Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
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
113 lines
2.5 KiB
// 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) |
|
}
|
|
|