// 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) }