|
- // Parsing keys handling both bare and quoted keys.
-
- package toml
-
- import (
- "errors"
- "fmt"
- "unicode"
- )
-
- // Convert the bare key group string to an array.
- // The input supports double quotation and single quotation,
- // but escape sequences are not supported. Lexers must unescape them beforehand.
- func parseKey(key string) ([]string, error) {
- runes := []rune(key)
- var groups []string
-
- if len(key) == 0 {
- return nil, errors.New("empty key")
- }
-
- idx := 0
- for idx < len(runes) {
- for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
- // skip leading whitespace
- }
- if idx >= len(runes) {
- break
- }
- r := runes[idx]
- if isValidBareChar(r) {
- // parse bare key
- startIdx := idx
- endIdx := -1
- idx++
- for idx < len(runes) {
- r = runes[idx]
- if isValidBareChar(r) {
- idx++
- } else if r == '.' {
- endIdx = idx
- break
- } else if isSpace(r) {
- endIdx = idx
- for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
- // skip trailing whitespace
- }
- if idx < len(runes) && runes[idx] != '.' {
- return nil, fmt.Errorf("invalid key character after whitespace: %c", runes[idx])
- }
- break
- } else {
- return nil, fmt.Errorf("invalid bare key character: %c", r)
- }
- }
- if endIdx == -1 {
- endIdx = idx
- }
- groups = append(groups, string(runes[startIdx:endIdx]))
- } else if r == '\'' {
- // parse single quoted key
- idx++
- startIdx := idx
- for {
- if idx >= len(runes) {
- return nil, fmt.Errorf("unclosed single-quoted key")
- }
- r = runes[idx]
- if r == '\'' {
- groups = append(groups, string(runes[startIdx:idx]))
- idx++
- break
- }
- idx++
- }
- } else if r == '"' {
- // parse double quoted key
- idx++
- startIdx := idx
- for {
- if idx >= len(runes) {
- return nil, fmt.Errorf("unclosed double-quoted key")
- }
- r = runes[idx]
- if r == '"' {
- groups = append(groups, string(runes[startIdx:idx]))
- idx++
- break
- }
- idx++
- }
- } else if r == '.' {
- idx++
- if idx >= len(runes) {
- return nil, fmt.Errorf("unexpected end of key")
- }
- r = runes[idx]
- if !isValidBareChar(r) && r != '\'' && r != '"' && r != ' ' {
- return nil, fmt.Errorf("expecting key part after dot")
- }
- } else {
- return nil, fmt.Errorf("invalid key character: %c", r)
- }
- }
- if len(groups) == 0 {
- return nil, fmt.Errorf("empty key")
- }
- return groups, nil
- }
-
- func isValidBareChar(r rune) bool {
- return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r)
- }
|