You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
2.5 KiB

  1. // Parsing keys handling both bare and quoted keys.
  2. package toml
  3. import (
  4. "errors"
  5. "fmt"
  6. "unicode"
  7. )
  8. // Convert the bare key group string to an array.
  9. // The input supports double quotation and single quotation,
  10. // but escape sequences are not supported. Lexers must unescape them beforehand.
  11. func parseKey(key string) ([]string, error) {
  12. runes := []rune(key)
  13. var groups []string
  14. if len(key) == 0 {
  15. return nil, errors.New("empty key")
  16. }
  17. idx := 0
  18. for idx < len(runes) {
  19. for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
  20. // skip leading whitespace
  21. }
  22. if idx >= len(runes) {
  23. break
  24. }
  25. r := runes[idx]
  26. if isValidBareChar(r) {
  27. // parse bare key
  28. startIdx := idx
  29. endIdx := -1
  30. idx++
  31. for idx < len(runes) {
  32. r = runes[idx]
  33. if isValidBareChar(r) {
  34. idx++
  35. } else if r == '.' {
  36. endIdx = idx
  37. break
  38. } else if isSpace(r) {
  39. endIdx = idx
  40. for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
  41. // skip trailing whitespace
  42. }
  43. if idx < len(runes) && runes[idx] != '.' {
  44. return nil, fmt.Errorf("invalid key character after whitespace: %c", runes[idx])
  45. }
  46. break
  47. } else {
  48. return nil, fmt.Errorf("invalid bare key character: %c", r)
  49. }
  50. }
  51. if endIdx == -1 {
  52. endIdx = idx
  53. }
  54. groups = append(groups, string(runes[startIdx:endIdx]))
  55. } else if r == '\'' {
  56. // parse single quoted key
  57. idx++
  58. startIdx := idx
  59. for {
  60. if idx >= len(runes) {
  61. return nil, fmt.Errorf("unclosed single-quoted key")
  62. }
  63. r = runes[idx]
  64. if r == '\'' {
  65. groups = append(groups, string(runes[startIdx:idx]))
  66. idx++
  67. break
  68. }
  69. idx++
  70. }
  71. } else if r == '"' {
  72. // parse double quoted key
  73. idx++
  74. startIdx := idx
  75. for {
  76. if idx >= len(runes) {
  77. return nil, fmt.Errorf("unclosed double-quoted key")
  78. }
  79. r = runes[idx]
  80. if r == '"' {
  81. groups = append(groups, string(runes[startIdx:idx]))
  82. idx++
  83. break
  84. }
  85. idx++
  86. }
  87. } else if r == '.' {
  88. idx++
  89. if idx >= len(runes) {
  90. return nil, fmt.Errorf("unexpected end of key")
  91. }
  92. r = runes[idx]
  93. if !isValidBareChar(r) && r != '\'' && r != '"' && r != ' ' {
  94. return nil, fmt.Errorf("expecting key part after dot")
  95. }
  96. } else {
  97. return nil, fmt.Errorf("invalid key character: %c", r)
  98. }
  99. }
  100. if len(groups) == 0 {
  101. return nil, fmt.Errorf("empty key")
  102. }
  103. return groups, nil
  104. }
  105. func isValidBareChar(r rune) bool {
  106. return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r)
  107. }