1
15
16 package strvals
17
18 import (
19 "bytes"
20 "fmt"
21 "io"
22 "strconv"
23
24 "github.com/pkg/errors"
25 )
26
27
28
29
30 func ParseLiteral(s string) (map[string]interface{}, error) {
31 vals := map[string]interface{}{}
32 scanner := bytes.NewBufferString(s)
33 t := newLiteralParser(scanner, vals)
34 err := t.parse()
35 return vals, err
36 }
37
38
39
40
41
42
43 func ParseLiteralInto(s string, dest map[string]interface{}) error {
44 scanner := bytes.NewBufferString(s)
45 t := newLiteralParser(scanner, dest)
46 return t.parse()
47 }
48
49
50
51
52
53
54
55
56 type literalParser struct {
57 sc *bytes.Buffer
58 data map[string]interface{}
59 }
60
61 func newLiteralParser(sc *bytes.Buffer, data map[string]interface{}) *literalParser {
62 return &literalParser{sc: sc, data: data}
63 }
64
65 func (t *literalParser) parse() error {
66 for {
67 err := t.key(t.data, 0)
68 if err == nil {
69 continue
70 }
71 if err == io.EOF {
72 return nil
73 }
74 return err
75 }
76 }
77
78 func runesUntilLiteral(in io.RuneReader, stop map[rune]bool) ([]rune, rune, error) {
79 v := []rune{}
80 for {
81 switch r, _, e := in.ReadRune(); {
82 case e != nil:
83 return v, r, e
84 case inMap(r, stop):
85 return v, r, nil
86 default:
87 v = append(v, r)
88 }
89 }
90 }
91
92 func (t *literalParser) key(data map[string]interface{}, nestedNameLevel int) (reterr error) {
93 defer func() {
94 if r := recover(); r != nil {
95 reterr = fmt.Errorf("unable to parse key: %s", r)
96 }
97 }()
98 stop := runeSet([]rune{'=', '[', '.'})
99 for {
100 switch key, lastRune, err := runesUntilLiteral(t.sc, stop); {
101 case err != nil:
102 if len(key) == 0 {
103 return err
104 }
105 return errors.Errorf("key %q has no value", string(key))
106
107 case lastRune == '=':
108
109 value, err := t.val()
110 if err == nil && err != io.EOF {
111 return err
112 }
113 set(data, string(key), string(value))
114 return nil
115
116 case lastRune == '.':
117
118 nestedNameLevel++
119 if nestedNameLevel > MaxNestedNameLevel {
120 return fmt.Errorf("value name nested level is greater than maximum supported nested level of %d", MaxNestedNameLevel)
121 }
122
123
124 inner := map[string]interface{}{}
125 if _, ok := data[string(key)]; ok {
126 inner = data[string(key)].(map[string]interface{})
127 }
128
129
130 err := t.key(inner, nestedNameLevel)
131 if err == nil && len(inner) == 0 {
132 return errors.Errorf("key map %q has no value", string(key))
133 }
134 if len(inner) != 0 {
135 set(data, string(key), inner)
136 }
137 return err
138
139 case lastRune == '[':
140
141 i, err := t.keyIndex()
142 if err != nil {
143 return errors.Wrap(err, "error parsing index")
144 }
145 kk := string(key)
146
147
148 list := []interface{}{}
149 if _, ok := data[kk]; ok {
150 list = data[kk].([]interface{})
151 }
152
153
154 list, err = t.listItem(list, i, nestedNameLevel)
155 set(data, kk, list)
156 return err
157 }
158 }
159 }
160
161 func (t *literalParser) keyIndex() (int, error) {
162
163 stop := runeSet([]rune{']'})
164 v, _, err := runesUntilLiteral(t.sc, stop)
165 if err != nil {
166 return 0, err
167 }
168
169
170 return strconv.Atoi(string(v))
171 }
172
173 func (t *literalParser) listItem(list []interface{}, i, nestedNameLevel int) ([]interface{}, error) {
174 if i < 0 {
175 return list, fmt.Errorf("negative %d index not allowed", i)
176 }
177 stop := runeSet([]rune{'[', '.', '='})
178
179 switch key, lastRune, err := runesUntilLiteral(t.sc, stop); {
180 case len(key) > 0:
181 return list, errors.Errorf("unexpected data at end of array index: %q", key)
182
183 case err != nil:
184 return list, err
185
186 case lastRune == '=':
187 value, err := t.val()
188 if err != nil && err != io.EOF {
189 return list, err
190 }
191 return setIndex(list, i, string(value))
192
193 case lastRune == '.':
194
195 inner := map[string]interface{}{}
196 if len(list) > i {
197 var ok bool
198 inner, ok = list[i].(map[string]interface{})
199 if !ok {
200
201 list[i] = map[string]interface{}{}
202 inner = list[i].(map[string]interface{})
203 }
204 }
205
206
207 err := t.key(inner, nestedNameLevel)
208 if err != nil {
209 return list, err
210 }
211 return setIndex(list, i, inner)
212
213 case lastRune == '[':
214
215 nextI, err := t.keyIndex()
216 if err != nil {
217 return list, errors.Wrap(err, "error parsing index")
218 }
219 var crtList []interface{}
220 if len(list) > i {
221
222 existed := list[i]
223 if existed != nil {
224 crtList = list[i].([]interface{})
225 }
226 }
227
228
229 list2, err := t.listItem(crtList, nextI, nestedNameLevel)
230 if err != nil {
231 return list, err
232 }
233 return setIndex(list, i, list2)
234
235 default:
236 return nil, errors.Errorf("parse error: unexpected token %v", lastRune)
237 }
238 }
239
240 func (t *literalParser) val() ([]rune, error) {
241 stop := runeSet([]rune{})
242 v, _, err := runesUntilLiteral(t.sc, stop)
243 return v, err
244 }
245
View as plain text