OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / pelletier / go-toml / keysparsing.go
diff --git a/vendor/github.com/pelletier/go-toml/keysparsing.go b/vendor/github.com/pelletier/go-toml/keysparsing.go
new file mode 100644 (file)
index 0000000..9707c68
--- /dev/null
@@ -0,0 +1,161 @@
+// Parsing keys handling both bare and quoted keys.
+
+package toml
+
+import (
+       "bytes"
+       "errors"
+       "fmt"
+       "strconv"
+       "unicode"
+)
+
+var escapeSequenceMap = map[rune]rune{
+       'b':  '\b',
+       't':  '\t',
+       'n':  '\n',
+       'f':  '\f',
+       'r':  '\r',
+       '"':  '"',
+       '\\': '\\',
+}
+
+type parseKeyState int
+
+const (
+       BARE parseKeyState = iota
+       BASIC
+       LITERAL
+       ESC
+       UNICODE_4
+       UNICODE_8
+)
+
+func parseKey(key string) ([]string, error) {
+       groups := []string{}
+       var buffer bytes.Buffer
+       var hex bytes.Buffer
+       state := BARE
+       wasInQuotes := false
+       ignoreSpace := true
+       expectDot := false
+
+       for _, char := range key {
+               if ignoreSpace {
+                       if char == ' ' {
+                               continue
+                       }
+                       ignoreSpace = false
+               }
+
+               if state == ESC {
+                       if char == 'u' {
+                               state = UNICODE_4
+                               hex.Reset()
+                       } else if char == 'U' {
+                               state = UNICODE_8
+                               hex.Reset()
+                       } else if newChar, ok := escapeSequenceMap[char]; ok {
+                               buffer.WriteRune(newChar)
+                               state = BASIC
+                       } else {
+                               return nil, fmt.Errorf(`invalid escape sequence \%c`, char)
+                       }
+                       continue
+               }
+
+               if state == UNICODE_4 || state == UNICODE_8 {
+                       if isHexDigit(char) {
+                               hex.WriteRune(char)
+                       }
+                       if (state == UNICODE_4 && hex.Len() == 4) || (state == UNICODE_8 && hex.Len() == 8) {
+                               if value, err := strconv.ParseInt(hex.String(), 16, 32); err == nil {
+                                       buffer.WriteRune(rune(value))
+                               } else {
+                                       return nil, err
+                               }
+                               state = BASIC
+                       }
+                       continue
+               }
+
+               switch char {
+               case '\\':
+                       if state == BASIC {
+                               state = ESC
+                       } else if state == LITERAL {
+                               buffer.WriteRune(char)
+                       }
+               case '\'':
+                       if state == BARE {
+                               state = LITERAL
+                       } else if state == LITERAL {
+                               groups = append(groups, buffer.String())
+                               buffer.Reset()
+                               wasInQuotes = true
+                               state = BARE
+                       }
+                       expectDot = false
+               case '"':
+                       if state == BARE {
+                               state = BASIC
+                       } else if state == BASIC {
+                               groups = append(groups, buffer.String())
+                               buffer.Reset()
+                               state = BARE
+                               wasInQuotes = true
+                       }
+                       expectDot = false
+               case '.':
+                       if state != BARE {
+                               buffer.WriteRune(char)
+                       } else {
+                               if !wasInQuotes {
+                                       if buffer.Len() == 0 {
+                                               return nil, errors.New("empty table key")
+                                       }
+                                       groups = append(groups, buffer.String())
+                                       buffer.Reset()
+                               }
+                               ignoreSpace = true
+                               expectDot = false
+                               wasInQuotes = false
+                       }
+               case ' ':
+                       if state == BASIC {
+                               buffer.WriteRune(char)
+                       } else {
+                               expectDot = true
+                       }
+               default:
+                       if state == BARE {
+                               if !isValidBareChar(char) {
+                                       return nil, fmt.Errorf("invalid bare character: %c", char)
+                               } else if expectDot {
+                                       return nil, errors.New("what?")
+                               }
+                       }
+                       buffer.WriteRune(char)
+                       expectDot = false
+               }
+       }
+
+       // state must be BARE at the end
+       if state == ESC {
+               return nil, errors.New("unfinished escape sequence")
+       } else if state != BARE {
+               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 groups, nil
+}
+
+func isValidBareChar(r rune) bool {
+       return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r)
+}