1// Parsing keys handling both bare and quoted keys. 2 3package toml 4 5import ( 6 "bytes" 7 "errors" 8 "fmt" 9 "unicode" 10) 11 12// Convert the bare key group string to an array. 13// The input supports double quotation to allow "." inside the key name, 14// but escape sequences are not supported. Lexers must unescape them beforehand. 15func parseKey(key string) ([]string, error) { 16 groups := []string{} 17 var buffer bytes.Buffer 18 inQuotes := false 19 wasInQuotes := false 20 ignoreSpace := true 21 expectDot := false 22 23 for _, char := range key { 24 if ignoreSpace { 25 if char == ' ' { 26 continue 27 } 28 ignoreSpace = false 29 } 30 switch char { 31 case '"': 32 if inQuotes { 33 groups = append(groups, buffer.String()) 34 buffer.Reset() 35 wasInQuotes = true 36 } 37 inQuotes = !inQuotes 38 expectDot = false 39 case '.': 40 if inQuotes { 41 buffer.WriteRune(char) 42 } else { 43 if !wasInQuotes { 44 if buffer.Len() == 0 { 45 return nil, errors.New("empty table key") 46 } 47 groups = append(groups, buffer.String()) 48 buffer.Reset() 49 } 50 ignoreSpace = true 51 expectDot = false 52 wasInQuotes = false 53 } 54 case ' ': 55 if inQuotes { 56 buffer.WriteRune(char) 57 } else { 58 expectDot = true 59 } 60 default: 61 if !inQuotes && !isValidBareChar(char) { 62 return nil, fmt.Errorf("invalid bare character: %c", char) 63 } 64 if !inQuotes && expectDot { 65 return nil, errors.New("what?") 66 } 67 buffer.WriteRune(char) 68 expectDot = false 69 } 70 } 71 if inQuotes { 72 return nil, errors.New("mismatched quotes") 73 } 74 if buffer.Len() > 0 { 75 groups = append(groups, buffer.String()) 76 } 77 if len(groups) == 0 { 78 return nil, errors.New("empty key") 79 } 80 return groups, nil 81} 82 83func isValidBareChar(r rune) bool { 84 return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r) 85} 86