vendor/github.com/pelletier/go-toml/keysparsing.go
changeset 251 1c52a0eeb952
parent 242 2a9ec03fe5a1
child 256 6d9efbef00a9
--- a/vendor/github.com/pelletier/go-toml/keysparsing.go	Wed Sep 18 19:17:42 2019 +0200
+++ b/vendor/github.com/pelletier/go-toml/keysparsing.go	Sun Feb 16 18:54:01 2020 +0100
@@ -3,79 +3,107 @@
 package toml
 
 import (
-	"bytes"
 	"errors"
 	"fmt"
 	"unicode"
 )
 
 // Convert the bare key group string to an array.
-// The input supports double quotation to allow "." inside the key name,
+// 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) {
-	groups := []string{}
-	var buffer bytes.Buffer
-	inQuotes := false
-	wasInQuotes := false
-	ignoreSpace := true
-	expectDot := false
+	runes := []rune(key)
+	var groups []string
+
+	if len(key) == 0 {
+		return nil, errors.New("empty key")
+	}
 
-	for _, char := range key {
-		if ignoreSpace {
-			if char == ' ' {
-				continue
-			}
-			ignoreSpace = false
+	idx := 0
+	for idx < len(runes) {
+		for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
+			// skip leading whitespace
+		}
+		if idx >= len(runes) {
+			break
 		}
-		switch char {
-		case '"':
-			if inQuotes {
-				groups = append(groups, buffer.String())
-				buffer.Reset()
-				wasInQuotes = true
+		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
 			}
-			inQuotes = !inQuotes
-			expectDot = false
-		case '.':
-			if inQuotes {
-				buffer.WriteRune(char)
-			} else {
-				if !wasInQuotes {
-					if buffer.Len() == 0 {
-						return nil, errors.New("empty table key")
-					}
-					groups = append(groups, buffer.String())
-					buffer.Reset()
+			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
 				}
-				ignoreSpace = true
-				expectDot = false
-				wasInQuotes = false
-			}
-		case ' ':
-			if inQuotes {
-				buffer.WriteRune(char)
-			} else {
-				expectDot = true
+				idx++
 			}
-		default:
-			if !inQuotes && !isValidBareChar(char) {
-				return nil, fmt.Errorf("invalid bare character: %c", char)
+		} 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++
 			}
-			if !inQuotes && expectDot {
-				return nil, errors.New("what?")
+		} else if r == '.' {
+			idx++
+			if idx >= len(runes) {
+				return nil, fmt.Errorf("unexpected end of key")
 			}
-			buffer.WriteRune(char)
-			expectDot = false
+			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 inQuotes {
-		return nil, errors.New("mismatched quotes")
-	}
-	if buffer.Len() > 0 {
-		groups = append(groups, buffer.String())
-	}
 	if len(groups) == 0 {
-		return nil, errors.New("empty key")
+		return nil, fmt.Errorf("empty key")
 	}
 	return groups, nil
 }