diff options
Diffstat (limited to 'vendor/github.com/hashicorp/hcl/decoder.go')
-rw-r--r-- | vendor/github.com/hashicorp/hcl/decoder.go | 724 |
1 files changed, 724 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hcl/decoder.go b/vendor/github.com/hashicorp/hcl/decoder.go new file mode 100644 index 0000000..0b39c1b --- /dev/null +++ b/vendor/github.com/hashicorp/hcl/decoder.go | |||
@@ -0,0 +1,724 @@ | |||
1 | package hcl | ||
2 | |||
3 | import ( | ||
4 | "errors" | ||
5 | "fmt" | ||
6 | "reflect" | ||
7 | "sort" | ||
8 | "strconv" | ||
9 | "strings" | ||
10 | |||
11 | "github.com/hashicorp/hcl/hcl/ast" | ||
12 | "github.com/hashicorp/hcl/hcl/parser" | ||
13 | "github.com/hashicorp/hcl/hcl/token" | ||
14 | ) | ||
15 | |||
16 | // This is the tag to use with structures to have settings for HCL | ||
17 | const tagName = "hcl" | ||
18 | |||
19 | var ( | ||
20 | // nodeType holds a reference to the type of ast.Node | ||
21 | nodeType reflect.Type = findNodeType() | ||
22 | ) | ||
23 | |||
24 | // Unmarshal accepts a byte slice as input and writes the | ||
25 | // data to the value pointed to by v. | ||
26 | func Unmarshal(bs []byte, v interface{}) error { | ||
27 | root, err := parse(bs) | ||
28 | if err != nil { | ||
29 | return err | ||
30 | } | ||
31 | |||
32 | return DecodeObject(v, root) | ||
33 | } | ||
34 | |||
35 | // Decode reads the given input and decodes it into the structure | ||
36 | // given by `out`. | ||
37 | func Decode(out interface{}, in string) error { | ||
38 | obj, err := Parse(in) | ||
39 | if err != nil { | ||
40 | return err | ||
41 | } | ||
42 | |||
43 | return DecodeObject(out, obj) | ||
44 | } | ||
45 | |||
46 | // DecodeObject is a lower-level version of Decode. It decodes a | ||
47 | // raw Object into the given output. | ||
48 | func DecodeObject(out interface{}, n ast.Node) error { | ||
49 | val := reflect.ValueOf(out) | ||
50 | if val.Kind() != reflect.Ptr { | ||
51 | return errors.New("result must be a pointer") | ||
52 | } | ||
53 | |||
54 | // If we have the file, we really decode the root node | ||
55 | if f, ok := n.(*ast.File); ok { | ||
56 | n = f.Node | ||
57 | } | ||
58 | |||
59 | var d decoder | ||
60 | return d.decode("root", n, val.Elem()) | ||
61 | } | ||
62 | |||
63 | type decoder struct { | ||
64 | stack []reflect.Kind | ||
65 | } | ||
66 | |||
67 | func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error { | ||
68 | k := result | ||
69 | |||
70 | // If we have an interface with a valid value, we use that | ||
71 | // for the check. | ||
72 | if result.Kind() == reflect.Interface { | ||
73 | elem := result.Elem() | ||
74 | if elem.IsValid() { | ||
75 | k = elem | ||
76 | } | ||
77 | } | ||
78 | |||
79 | // Push current onto stack unless it is an interface. | ||
80 | if k.Kind() != reflect.Interface { | ||
81 | d.stack = append(d.stack, k.Kind()) | ||
82 | |||
83 | // Schedule a pop | ||
84 | defer func() { | ||
85 | d.stack = d.stack[:len(d.stack)-1] | ||
86 | }() | ||
87 | } | ||
88 | |||
89 | switch k.Kind() { | ||
90 | case reflect.Bool: | ||
91 | return d.decodeBool(name, node, result) | ||
92 | case reflect.Float64: | ||
93 | return d.decodeFloat(name, node, result) | ||
94 | case reflect.Int, reflect.Int32, reflect.Int64: | ||
95 | return d.decodeInt(name, node, result) | ||
96 | case reflect.Interface: | ||
97 | // When we see an interface, we make our own thing | ||
98 | return d.decodeInterface(name, node, result) | ||
99 | case reflect.Map: | ||
100 | return d.decodeMap(name, node, result) | ||
101 | case reflect.Ptr: | ||
102 | return d.decodePtr(name, node, result) | ||
103 | case reflect.Slice: | ||
104 | return d.decodeSlice(name, node, result) | ||
105 | case reflect.String: | ||
106 | return d.decodeString(name, node, result) | ||
107 | case reflect.Struct: | ||
108 | return d.decodeStruct(name, node, result) | ||
109 | default: | ||
110 | return &parser.PosError{ | ||
111 | Pos: node.Pos(), | ||
112 | Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()), | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | |||
117 | func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error { | ||
118 | switch n := node.(type) { | ||
119 | case *ast.LiteralType: | ||
120 | if n.Token.Type == token.BOOL { | ||
121 | v, err := strconv.ParseBool(n.Token.Text) | ||
122 | if err != nil { | ||
123 | return err | ||
124 | } | ||
125 | |||
126 | result.Set(reflect.ValueOf(v)) | ||
127 | return nil | ||
128 | } | ||
129 | } | ||
130 | |||
131 | return &parser.PosError{ | ||
132 | Pos: node.Pos(), | ||
133 | Err: fmt.Errorf("%s: unknown type %T", name, node), | ||
134 | } | ||
135 | } | ||
136 | |||
137 | func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error { | ||
138 | switch n := node.(type) { | ||
139 | case *ast.LiteralType: | ||
140 | if n.Token.Type == token.FLOAT { | ||
141 | v, err := strconv.ParseFloat(n.Token.Text, 64) | ||
142 | if err != nil { | ||
143 | return err | ||
144 | } | ||
145 | |||
146 | result.Set(reflect.ValueOf(v)) | ||
147 | return nil | ||
148 | } | ||
149 | } | ||
150 | |||
151 | return &parser.PosError{ | ||
152 | Pos: node.Pos(), | ||
153 | Err: fmt.Errorf("%s: unknown type %T", name, node), | ||
154 | } | ||
155 | } | ||
156 | |||
157 | func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error { | ||
158 | switch n := node.(type) { | ||
159 | case *ast.LiteralType: | ||
160 | switch n.Token.Type { | ||
161 | case token.NUMBER: | ||
162 | v, err := strconv.ParseInt(n.Token.Text, 0, 0) | ||
163 | if err != nil { | ||
164 | return err | ||
165 | } | ||
166 | |||
167 | if result.Kind() == reflect.Interface { | ||
168 | result.Set(reflect.ValueOf(int(v))) | ||
169 | } else { | ||
170 | result.SetInt(v) | ||
171 | } | ||
172 | return nil | ||
173 | case token.STRING: | ||
174 | v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0) | ||
175 | if err != nil { | ||
176 | return err | ||
177 | } | ||
178 | |||
179 | if result.Kind() == reflect.Interface { | ||
180 | result.Set(reflect.ValueOf(int(v))) | ||
181 | } else { | ||
182 | result.SetInt(v) | ||
183 | } | ||
184 | return nil | ||
185 | } | ||
186 | } | ||
187 | |||
188 | return &parser.PosError{ | ||
189 | Pos: node.Pos(), | ||
190 | Err: fmt.Errorf("%s: unknown type %T", name, node), | ||
191 | } | ||
192 | } | ||
193 | |||
194 | func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error { | ||
195 | // When we see an ast.Node, we retain the value to enable deferred decoding. | ||
196 | // Very useful in situations where we want to preserve ast.Node information | ||
197 | // like Pos | ||
198 | if result.Type() == nodeType && result.CanSet() { | ||
199 | result.Set(reflect.ValueOf(node)) | ||
200 | return nil | ||
201 | } | ||
202 | |||
203 | var set reflect.Value | ||
204 | redecode := true | ||
205 | |||
206 | // For testing types, ObjectType should just be treated as a list. We | ||
207 | // set this to a temporary var because we want to pass in the real node. | ||
208 | testNode := node | ||
209 | if ot, ok := node.(*ast.ObjectType); ok { | ||
210 | testNode = ot.List | ||
211 | } | ||
212 | |||
213 | switch n := testNode.(type) { | ||
214 | case *ast.ObjectList: | ||
215 | // If we're at the root or we're directly within a slice, then we | ||
216 | // decode objects into map[string]interface{}, otherwise we decode | ||
217 | // them into lists. | ||
218 | if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { | ||
219 | var temp map[string]interface{} | ||
220 | tempVal := reflect.ValueOf(temp) | ||
221 | result := reflect.MakeMap( | ||
222 | reflect.MapOf( | ||
223 | reflect.TypeOf(""), | ||
224 | tempVal.Type().Elem())) | ||
225 | |||
226 | set = result | ||
227 | } else { | ||
228 | var temp []map[string]interface{} | ||
229 | tempVal := reflect.ValueOf(temp) | ||
230 | result := reflect.MakeSlice( | ||
231 | reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items)) | ||
232 | set = result | ||
233 | } | ||
234 | case *ast.ObjectType: | ||
235 | // If we're at the root or we're directly within a slice, then we | ||
236 | // decode objects into map[string]interface{}, otherwise we decode | ||
237 | // them into lists. | ||
238 | if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { | ||
239 | var temp map[string]interface{} | ||
240 | tempVal := reflect.ValueOf(temp) | ||
241 | result := reflect.MakeMap( | ||
242 | reflect.MapOf( | ||
243 | reflect.TypeOf(""), | ||
244 | tempVal.Type().Elem())) | ||
245 | |||
246 | set = result | ||
247 | } else { | ||
248 | var temp []map[string]interface{} | ||
249 | tempVal := reflect.ValueOf(temp) | ||
250 | result := reflect.MakeSlice( | ||
251 | reflect.SliceOf(tempVal.Type().Elem()), 0, 1) | ||
252 | set = result | ||
253 | } | ||
254 | case *ast.ListType: | ||
255 | var temp []interface{} | ||
256 | tempVal := reflect.ValueOf(temp) | ||
257 | result := reflect.MakeSlice( | ||
258 | reflect.SliceOf(tempVal.Type().Elem()), 0, 0) | ||
259 | set = result | ||
260 | case *ast.LiteralType: | ||
261 | switch n.Token.Type { | ||
262 | case token.BOOL: | ||
263 | var result bool | ||
264 | set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) | ||
265 | case token.FLOAT: | ||
266 | var result float64 | ||
267 | set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) | ||
268 | case token.NUMBER: | ||
269 | var result int | ||
270 | set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) | ||
271 | case token.STRING, token.HEREDOC: | ||
272 | set = reflect.Indirect(reflect.New(reflect.TypeOf(""))) | ||
273 | default: | ||
274 | return &parser.PosError{ | ||
275 | Pos: node.Pos(), | ||
276 | Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node), | ||
277 | } | ||
278 | } | ||
279 | default: | ||
280 | return fmt.Errorf( | ||
281 | "%s: cannot decode into interface: %T", | ||
282 | name, node) | ||
283 | } | ||
284 | |||
285 | // Set the result to what its supposed to be, then reset | ||
286 | // result so we don't reflect into this method anymore. | ||
287 | result.Set(set) | ||
288 | |||
289 | if redecode { | ||
290 | // Revisit the node so that we can use the newly instantiated | ||
291 | // thing and populate it. | ||
292 | if err := d.decode(name, node, result); err != nil { | ||
293 | return err | ||
294 | } | ||
295 | } | ||
296 | |||
297 | return nil | ||
298 | } | ||
299 | |||
300 | func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error { | ||
301 | if item, ok := node.(*ast.ObjectItem); ok { | ||
302 | node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} | ||
303 | } | ||
304 | |||
305 | if ot, ok := node.(*ast.ObjectType); ok { | ||
306 | node = ot.List | ||
307 | } | ||
308 | |||
309 | n, ok := node.(*ast.ObjectList) | ||
310 | if !ok { | ||
311 | return &parser.PosError{ | ||
312 | Pos: node.Pos(), | ||
313 | Err: fmt.Errorf("%s: not an object type for map (%T)", name, node), | ||
314 | } | ||
315 | } | ||
316 | |||
317 | // If we have an interface, then we can address the interface, | ||
318 | // but not the slice itself, so get the element but set the interface | ||
319 | set := result | ||
320 | if result.Kind() == reflect.Interface { | ||
321 | result = result.Elem() | ||
322 | } | ||
323 | |||
324 | resultType := result.Type() | ||
325 | resultElemType := resultType.Elem() | ||
326 | resultKeyType := resultType.Key() | ||
327 | if resultKeyType.Kind() != reflect.String { | ||
328 | return &parser.PosError{ | ||
329 | Pos: node.Pos(), | ||
330 | Err: fmt.Errorf("%s: map must have string keys", name), | ||
331 | } | ||
332 | } | ||
333 | |||
334 | // Make a map if it is nil | ||
335 | resultMap := result | ||
336 | if result.IsNil() { | ||
337 | resultMap = reflect.MakeMap( | ||
338 | reflect.MapOf(resultKeyType, resultElemType)) | ||
339 | } | ||
340 | |||
341 | // Go through each element and decode it. | ||
342 | done := make(map[string]struct{}) | ||
343 | for _, item := range n.Items { | ||
344 | if item.Val == nil { | ||
345 | continue | ||
346 | } | ||
347 | |||
348 | // github.com/hashicorp/terraform/issue/5740 | ||
349 | if len(item.Keys) == 0 { | ||
350 | return &parser.PosError{ | ||
351 | Pos: node.Pos(), | ||
352 | Err: fmt.Errorf("%s: map must have string keys", name), | ||
353 | } | ||
354 | } | ||
355 | |||
356 | // Get the key we're dealing with, which is the first item | ||
357 | keyStr := item.Keys[0].Token.Value().(string) | ||
358 | |||
359 | // If we've already processed this key, then ignore it | ||
360 | if _, ok := done[keyStr]; ok { | ||
361 | continue | ||
362 | } | ||
363 | |||
364 | // Determine the value. If we have more than one key, then we | ||
365 | // get the objectlist of only these keys. | ||
366 | itemVal := item.Val | ||
367 | if len(item.Keys) > 1 { | ||
368 | itemVal = n.Filter(keyStr) | ||
369 | done[keyStr] = struct{}{} | ||
370 | } | ||
371 | |||
372 | // Make the field name | ||
373 | fieldName := fmt.Sprintf("%s.%s", name, keyStr) | ||
374 | |||
375 | // Get the key/value as reflection values | ||
376 | key := reflect.ValueOf(keyStr) | ||
377 | val := reflect.Indirect(reflect.New(resultElemType)) | ||
378 | |||
379 | // If we have a pre-existing value in the map, use that | ||
380 | oldVal := resultMap.MapIndex(key) | ||
381 | if oldVal.IsValid() { | ||
382 | val.Set(oldVal) | ||
383 | } | ||
384 | |||
385 | // Decode! | ||
386 | if err := d.decode(fieldName, itemVal, val); err != nil { | ||
387 | return err | ||
388 | } | ||
389 | |||
390 | // Set the value on the map | ||
391 | resultMap.SetMapIndex(key, val) | ||
392 | } | ||
393 | |||
394 | // Set the final map if we can | ||
395 | set.Set(resultMap) | ||
396 | return nil | ||
397 | } | ||
398 | |||
399 | func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error { | ||
400 | // Create an element of the concrete (non pointer) type and decode | ||
401 | // into that. Then set the value of the pointer to this type. | ||
402 | resultType := result.Type() | ||
403 | resultElemType := resultType.Elem() | ||
404 | val := reflect.New(resultElemType) | ||
405 | if err := d.decode(name, node, reflect.Indirect(val)); err != nil { | ||
406 | return err | ||
407 | } | ||
408 | |||
409 | result.Set(val) | ||
410 | return nil | ||
411 | } | ||
412 | |||
413 | func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error { | ||
414 | // If we have an interface, then we can address the interface, | ||
415 | // but not the slice itself, so get the element but set the interface | ||
416 | set := result | ||
417 | if result.Kind() == reflect.Interface { | ||
418 | result = result.Elem() | ||
419 | } | ||
420 | // Create the slice if it isn't nil | ||
421 | resultType := result.Type() | ||
422 | resultElemType := resultType.Elem() | ||
423 | if result.IsNil() { | ||
424 | resultSliceType := reflect.SliceOf(resultElemType) | ||
425 | result = reflect.MakeSlice( | ||
426 | resultSliceType, 0, 0) | ||
427 | } | ||
428 | |||
429 | // Figure out the items we'll be copying into the slice | ||
430 | var items []ast.Node | ||
431 | switch n := node.(type) { | ||
432 | case *ast.ObjectList: | ||
433 | items = make([]ast.Node, len(n.Items)) | ||
434 | for i, item := range n.Items { | ||
435 | items[i] = item | ||
436 | } | ||
437 | case *ast.ObjectType: | ||
438 | items = []ast.Node{n} | ||
439 | case *ast.ListType: | ||
440 | items = n.List | ||
441 | default: | ||
442 | return &parser.PosError{ | ||
443 | Pos: node.Pos(), | ||
444 | Err: fmt.Errorf("unknown slice type: %T", node), | ||
445 | } | ||
446 | } | ||
447 | |||
448 | for i, item := range items { | ||
449 | fieldName := fmt.Sprintf("%s[%d]", name, i) | ||
450 | |||
451 | // Decode | ||
452 | val := reflect.Indirect(reflect.New(resultElemType)) | ||
453 | |||
454 | // if item is an object that was decoded from ambiguous JSON and | ||
455 | // flattened, make sure it's expanded if it needs to decode into a | ||
456 | // defined structure. | ||
457 | item := expandObject(item, val) | ||
458 | |||
459 | if err := d.decode(fieldName, item, val); err != nil { | ||
460 | return err | ||
461 | } | ||
462 | |||
463 | // Append it onto the slice | ||
464 | result = reflect.Append(result, val) | ||
465 | } | ||
466 | |||
467 | set.Set(result) | ||
468 | return nil | ||
469 | } | ||
470 | |||
471 | // expandObject detects if an ambiguous JSON object was flattened to a List which | ||
472 | // should be decoded into a struct, and expands the ast to properly deocode. | ||
473 | func expandObject(node ast.Node, result reflect.Value) ast.Node { | ||
474 | item, ok := node.(*ast.ObjectItem) | ||
475 | if !ok { | ||
476 | return node | ||
477 | } | ||
478 | |||
479 | elemType := result.Type() | ||
480 | |||
481 | // our target type must be a struct | ||
482 | switch elemType.Kind() { | ||
483 | case reflect.Ptr: | ||
484 | switch elemType.Elem().Kind() { | ||
485 | case reflect.Struct: | ||
486 | //OK | ||
487 | default: | ||
488 | return node | ||
489 | } | ||
490 | case reflect.Struct: | ||
491 | //OK | ||
492 | default: | ||
493 | return node | ||
494 | } | ||
495 | |||
496 | // A list value will have a key and field name. If it had more fields, | ||
497 | // it wouldn't have been flattened. | ||
498 | if len(item.Keys) != 2 { | ||
499 | return node | ||
500 | } | ||
501 | |||
502 | keyToken := item.Keys[0].Token | ||
503 | item.Keys = item.Keys[1:] | ||
504 | |||
505 | // we need to un-flatten the ast enough to decode | ||
506 | newNode := &ast.ObjectItem{ | ||
507 | Keys: []*ast.ObjectKey{ | ||
508 | &ast.ObjectKey{ | ||
509 | Token: keyToken, | ||
510 | }, | ||
511 | }, | ||
512 | Val: &ast.ObjectType{ | ||
513 | List: &ast.ObjectList{ | ||
514 | Items: []*ast.ObjectItem{item}, | ||
515 | }, | ||
516 | }, | ||
517 | } | ||
518 | |||
519 | return newNode | ||
520 | } | ||
521 | |||
522 | func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error { | ||
523 | switch n := node.(type) { | ||
524 | case *ast.LiteralType: | ||
525 | switch n.Token.Type { | ||
526 | case token.NUMBER: | ||
527 | result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type())) | ||
528 | return nil | ||
529 | case token.STRING, token.HEREDOC: | ||
530 | result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type())) | ||
531 | return nil | ||
532 | } | ||
533 | } | ||
534 | |||
535 | return &parser.PosError{ | ||
536 | Pos: node.Pos(), | ||
537 | Err: fmt.Errorf("%s: unknown type for string %T", name, node), | ||
538 | } | ||
539 | } | ||
540 | |||
541 | func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error { | ||
542 | var item *ast.ObjectItem | ||
543 | if it, ok := node.(*ast.ObjectItem); ok { | ||
544 | item = it | ||
545 | node = it.Val | ||
546 | } | ||
547 | |||
548 | if ot, ok := node.(*ast.ObjectType); ok { | ||
549 | node = ot.List | ||
550 | } | ||
551 | |||
552 | // Handle the special case where the object itself is a literal. Previously | ||
553 | // the yacc parser would always ensure top-level elements were arrays. The new | ||
554 | // parser does not make the same guarantees, thus we need to convert any | ||
555 | // top-level literal elements into a list. | ||
556 | if _, ok := node.(*ast.LiteralType); ok && item != nil { | ||
557 | node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} | ||
558 | } | ||
559 | |||
560 | list, ok := node.(*ast.ObjectList) | ||
561 | if !ok { | ||
562 | return &parser.PosError{ | ||
563 | Pos: node.Pos(), | ||
564 | Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node), | ||
565 | } | ||
566 | } | ||
567 | |||
568 | // This slice will keep track of all the structs we'll be decoding. | ||
569 | // There can be more than one struct if there are embedded structs | ||
570 | // that are squashed. | ||
571 | structs := make([]reflect.Value, 1, 5) | ||
572 | structs[0] = result | ||
573 | |||
574 | // Compile the list of all the fields that we're going to be decoding | ||
575 | // from all the structs. | ||
576 | fields := make(map[*reflect.StructField]reflect.Value) | ||
577 | for len(structs) > 0 { | ||
578 | structVal := structs[0] | ||
579 | structs = structs[1:] | ||
580 | |||
581 | structType := structVal.Type() | ||
582 | for i := 0; i < structType.NumField(); i++ { | ||
583 | fieldType := structType.Field(i) | ||
584 | tagParts := strings.Split(fieldType.Tag.Get(tagName), ",") | ||
585 | |||
586 | // Ignore fields with tag name "-" | ||
587 | if tagParts[0] == "-" { | ||
588 | continue | ||
589 | } | ||
590 | |||
591 | if fieldType.Anonymous { | ||
592 | fieldKind := fieldType.Type.Kind() | ||
593 | if fieldKind != reflect.Struct { | ||
594 | return &parser.PosError{ | ||
595 | Pos: node.Pos(), | ||
596 | Err: fmt.Errorf("%s: unsupported type to struct: %s", | ||
597 | fieldType.Name, fieldKind), | ||
598 | } | ||
599 | } | ||
600 | |||
601 | // We have an embedded field. We "squash" the fields down | ||
602 | // if specified in the tag. | ||
603 | squash := false | ||
604 | for _, tag := range tagParts[1:] { | ||
605 | if tag == "squash" { | ||
606 | squash = true | ||
607 | break | ||
608 | } | ||
609 | } | ||
610 | |||
611 | if squash { | ||
612 | structs = append( | ||
613 | structs, result.FieldByName(fieldType.Name)) | ||
614 | continue | ||
615 | } | ||
616 | } | ||
617 | |||
618 | // Normal struct field, store it away | ||
619 | fields[&fieldType] = structVal.Field(i) | ||
620 | } | ||
621 | } | ||
622 | |||
623 | usedKeys := make(map[string]struct{}) | ||
624 | decodedFields := make([]string, 0, len(fields)) | ||
625 | decodedFieldsVal := make([]reflect.Value, 0) | ||
626 | unusedKeysVal := make([]reflect.Value, 0) | ||
627 | for fieldType, field := range fields { | ||
628 | if !field.IsValid() { | ||
629 | // This should never happen | ||
630 | panic("field is not valid") | ||
631 | } | ||
632 | |||
633 | // If we can't set the field, then it is unexported or something, | ||
634 | // and we just continue onwards. | ||
635 | if !field.CanSet() { | ||
636 | continue | ||
637 | } | ||
638 | |||
639 | fieldName := fieldType.Name | ||
640 | |||
641 | tagValue := fieldType.Tag.Get(tagName) | ||
642 | tagParts := strings.SplitN(tagValue, ",", 2) | ||
643 | if len(tagParts) >= 2 { | ||
644 | switch tagParts[1] { | ||
645 | case "decodedFields": | ||
646 | decodedFieldsVal = append(decodedFieldsVal, field) | ||
647 | continue | ||
648 | case "key": | ||
649 | if item == nil { | ||
650 | return &parser.PosError{ | ||
651 | Pos: node.Pos(), | ||
652 | Err: fmt.Errorf("%s: %s asked for 'key', impossible", | ||
653 | name, fieldName), | ||
654 | } | ||
655 | } | ||
656 | |||
657 | field.SetString(item.Keys[0].Token.Value().(string)) | ||
658 | continue | ||
659 | case "unusedKeys": | ||
660 | unusedKeysVal = append(unusedKeysVal, field) | ||
661 | continue | ||
662 | } | ||
663 | } | ||
664 | |||
665 | if tagParts[0] != "" { | ||
666 | fieldName = tagParts[0] | ||
667 | } | ||
668 | |||
669 | // Determine the element we'll use to decode. If it is a single | ||
670 | // match (only object with the field), then we decode it exactly. | ||
671 | // If it is a prefix match, then we decode the matches. | ||
672 | filter := list.Filter(fieldName) | ||
673 | |||
674 | prefixMatches := filter.Children() | ||
675 | matches := filter.Elem() | ||
676 | if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 { | ||
677 | continue | ||
678 | } | ||
679 | |||
680 | // Track the used key | ||
681 | usedKeys[fieldName] = struct{}{} | ||
682 | |||
683 | // Create the field name and decode. We range over the elements | ||
684 | // because we actually want the value. | ||
685 | fieldName = fmt.Sprintf("%s.%s", name, fieldName) | ||
686 | if len(prefixMatches.Items) > 0 { | ||
687 | if err := d.decode(fieldName, prefixMatches, field); err != nil { | ||
688 | return err | ||
689 | } | ||
690 | } | ||
691 | for _, match := range matches.Items { | ||
692 | var decodeNode ast.Node = match.Val | ||
693 | if ot, ok := decodeNode.(*ast.ObjectType); ok { | ||
694 | decodeNode = &ast.ObjectList{Items: ot.List.Items} | ||
695 | } | ||
696 | |||
697 | if err := d.decode(fieldName, decodeNode, field); err != nil { | ||
698 | return err | ||
699 | } | ||
700 | } | ||
701 | |||
702 | decodedFields = append(decodedFields, fieldType.Name) | ||
703 | } | ||
704 | |||
705 | if len(decodedFieldsVal) > 0 { | ||
706 | // Sort it so that it is deterministic | ||
707 | sort.Strings(decodedFields) | ||
708 | |||
709 | for _, v := range decodedFieldsVal { | ||
710 | v.Set(reflect.ValueOf(decodedFields)) | ||
711 | } | ||
712 | } | ||
713 | |||
714 | return nil | ||
715 | } | ||
716 | |||
717 | // findNodeType returns the type of ast.Node | ||
718 | func findNodeType() reflect.Type { | ||
719 | var nodeContainer struct { | ||
720 | Node ast.Node | ||
721 | } | ||
722 | value := reflect.ValueOf(nodeContainer).FieldByName("Node") | ||
723 | return value.Type() | ||
724 | } | ||