OSDN Git Service

versoin1.1.9 (#594)
[bytom/vapor.git] / vendor / github.com / pelletier / go-toml / keysparsing.go
1 // Parsing keys handling both bare and quoted keys.
2
3 package toml
4
5 import (
6         "bytes"
7         "errors"
8         "fmt"
9         "strconv"
10         "unicode"
11 )
12
13 var escapeSequenceMap = map[rune]rune{
14         'b':  '\b',
15         't':  '\t',
16         'n':  '\n',
17         'f':  '\f',
18         'r':  '\r',
19         '"':  '"',
20         '\\': '\\',
21 }
22
23 type parseKeyState int
24
25 const (
26         BARE parseKeyState = iota
27         BASIC
28         LITERAL
29         ESC
30         UNICODE_4
31         UNICODE_8
32 )
33
34 func parseKey(key string) ([]string, error) {
35         groups := []string{}
36         var buffer bytes.Buffer
37         var hex bytes.Buffer
38         state := BARE
39         wasInQuotes := false
40         ignoreSpace := true
41         expectDot := false
42
43         for _, char := range key {
44                 if ignoreSpace {
45                         if char == ' ' {
46                                 continue
47                         }
48                         ignoreSpace = false
49                 }
50
51                 if state == ESC {
52                         if char == 'u' {
53                                 state = UNICODE_4
54                                 hex.Reset()
55                         } else if char == 'U' {
56                                 state = UNICODE_8
57                                 hex.Reset()
58                         } else if newChar, ok := escapeSequenceMap[char]; ok {
59                                 buffer.WriteRune(newChar)
60                                 state = BASIC
61                         } else {
62                                 return nil, fmt.Errorf(`invalid escape sequence \%c`, char)
63                         }
64                         continue
65                 }
66
67                 if state == UNICODE_4 || state == UNICODE_8 {
68                         if isHexDigit(char) {
69                                 hex.WriteRune(char)
70                         }
71                         if (state == UNICODE_4 && hex.Len() == 4) || (state == UNICODE_8 && hex.Len() == 8) {
72                                 if value, err := strconv.ParseInt(hex.String(), 16, 32); err == nil {
73                                         buffer.WriteRune(rune(value))
74                                 } else {
75                                         return nil, err
76                                 }
77                                 state = BASIC
78                         }
79                         continue
80                 }
81
82                 switch char {
83                 case '\\':
84                         if state == BASIC {
85                                 state = ESC
86                         } else if state == LITERAL {
87                                 buffer.WriteRune(char)
88                         }
89                 case '\'':
90                         if state == BARE {
91                                 state = LITERAL
92                         } else if state == LITERAL {
93                                 groups = append(groups, buffer.String())
94                                 buffer.Reset()
95                                 wasInQuotes = true
96                                 state = BARE
97                         }
98                         expectDot = false
99                 case '"':
100                         if state == BARE {
101                                 state = BASIC
102                         } else if state == BASIC {
103                                 groups = append(groups, buffer.String())
104                                 buffer.Reset()
105                                 state = BARE
106                                 wasInQuotes = true
107                         }
108                         expectDot = false
109                 case '.':
110                         if state != BARE {
111                                 buffer.WriteRune(char)
112                         } else {
113                                 if !wasInQuotes {
114                                         if buffer.Len() == 0 {
115                                                 return nil, errors.New("empty table key")
116                                         }
117                                         groups = append(groups, buffer.String())
118                                         buffer.Reset()
119                                 }
120                                 ignoreSpace = true
121                                 expectDot = false
122                                 wasInQuotes = false
123                         }
124                 case ' ':
125                         if state == BASIC {
126                                 buffer.WriteRune(char)
127                         } else {
128                                 expectDot = true
129                         }
130                 default:
131                         if state == BARE {
132                                 if !isValidBareChar(char) {
133                                         return nil, fmt.Errorf("invalid bare character: %c", char)
134                                 } else if expectDot {
135                                         return nil, errors.New("what?")
136                                 }
137                         }
138                         buffer.WriteRune(char)
139                         expectDot = false
140                 }
141         }
142
143         // state must be BARE at the end
144         if state == ESC {
145                 return nil, errors.New("unfinished escape sequence")
146         } else if state != BARE {
147                 return nil, errors.New("mismatched quotes")
148         }
149
150         if buffer.Len() > 0 {
151                 groups = append(groups, buffer.String())
152         }
153         if len(groups) == 0 {
154                 return nil, errors.New("empty key")
155         }
156         return groups, nil
157 }
158
159 func isValidBareChar(r rune) bool {
160         return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r)
161 }