66
|
1 package yaml
|
|
2
|
|
3 import (
|
|
4 "encoding"
|
|
5 "encoding/base64"
|
|
6 "fmt"
|
|
7 "io"
|
|
8 "math"
|
|
9 "reflect"
|
|
10 "strconv"
|
|
11 "time"
|
|
12 )
|
|
13
|
|
14 const (
|
|
15 documentNode = 1 << iota
|
|
16 mappingNode
|
|
17 sequenceNode
|
|
18 scalarNode
|
|
19 aliasNode
|
|
20 )
|
|
21
|
|
22 type node struct {
|
|
23 kind int
|
|
24 line, column int
|
|
25 tag string
|
|
26 // For an alias node, alias holds the resolved alias.
|
|
27 alias *node
|
|
28 value string
|
|
29 implicit bool
|
|
30 children []*node
|
|
31 anchors map[string]*node
|
|
32 }
|
|
33
|
|
34 // ----------------------------------------------------------------------------
|
|
35 // Parser, produces a node tree out of a libyaml event stream.
|
|
36
|
|
37 type parser struct {
|
|
38 parser yaml_parser_t
|
|
39 event yaml_event_t
|
|
40 doc *node
|
|
41 doneInit bool
|
|
42 }
|
|
43
|
|
44 func newParser(b []byte) *parser {
|
|
45 p := parser{}
|
|
46 if !yaml_parser_initialize(&p.parser) {
|
|
47 panic("failed to initialize YAML emitter")
|
|
48 }
|
|
49 if len(b) == 0 {
|
|
50 b = []byte{'\n'}
|
|
51 }
|
|
52 yaml_parser_set_input_string(&p.parser, b)
|
|
53 return &p
|
|
54 }
|
|
55
|
|
56 func newParserFromReader(r io.Reader) *parser {
|
|
57 p := parser{}
|
|
58 if !yaml_parser_initialize(&p.parser) {
|
|
59 panic("failed to initialize YAML emitter")
|
|
60 }
|
|
61 yaml_parser_set_input_reader(&p.parser, r)
|
|
62 return &p
|
|
63 }
|
|
64
|
|
65 func (p *parser) init() {
|
|
66 if p.doneInit {
|
|
67 return
|
|
68 }
|
|
69 p.expect(yaml_STREAM_START_EVENT)
|
|
70 p.doneInit = true
|
|
71 }
|
|
72
|
|
73 func (p *parser) destroy() {
|
|
74 if p.event.typ != yaml_NO_EVENT {
|
|
75 yaml_event_delete(&p.event)
|
|
76 }
|
|
77 yaml_parser_delete(&p.parser)
|
|
78 }
|
|
79
|
|
80 // expect consumes an event from the event stream and
|
|
81 // checks that it's of the expected type.
|
|
82 func (p *parser) expect(e yaml_event_type_t) {
|
|
83 if p.event.typ == yaml_NO_EVENT {
|
|
84 if !yaml_parser_parse(&p.parser, &p.event) {
|
|
85 p.fail()
|
|
86 }
|
|
87 }
|
|
88 if p.event.typ == yaml_STREAM_END_EVENT {
|
|
89 failf("attempted to go past the end of stream; corrupted value?")
|
|
90 }
|
|
91 if p.event.typ != e {
|
|
92 p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
|
|
93 p.fail()
|
|
94 }
|
|
95 yaml_event_delete(&p.event)
|
|
96 p.event.typ = yaml_NO_EVENT
|
|
97 }
|
|
98
|
|
99 // peek peeks at the next event in the event stream,
|
|
100 // puts the results into p.event and returns the event type.
|
|
101 func (p *parser) peek() yaml_event_type_t {
|
|
102 if p.event.typ != yaml_NO_EVENT {
|
|
103 return p.event.typ
|
|
104 }
|
|
105 if !yaml_parser_parse(&p.parser, &p.event) {
|
|
106 p.fail()
|
|
107 }
|
|
108 return p.event.typ
|
|
109 }
|
|
110
|
|
111 func (p *parser) fail() {
|
|
112 var where string
|
|
113 var line int
|
|
114 if p.parser.problem_mark.line != 0 {
|
|
115 line = p.parser.problem_mark.line
|
|
116 // Scanner errors don't iterate line before returning error
|
|
117 if p.parser.error == yaml_SCANNER_ERROR {
|
|
118 line++
|
|
119 }
|
|
120 } else if p.parser.context_mark.line != 0 {
|
|
121 line = p.parser.context_mark.line
|
|
122 }
|
|
123 if line != 0 {
|
|
124 where = "line " + strconv.Itoa(line) + ": "
|
|
125 }
|
|
126 var msg string
|
|
127 if len(p.parser.problem) > 0 {
|
|
128 msg = p.parser.problem
|
|
129 } else {
|
|
130 msg = "unknown problem parsing YAML content"
|
|
131 }
|
|
132 failf("%s%s", where, msg)
|
|
133 }
|
|
134
|
|
135 func (p *parser) anchor(n *node, anchor []byte) {
|
|
136 if anchor != nil {
|
|
137 p.doc.anchors[string(anchor)] = n
|
|
138 }
|
|
139 }
|
|
140
|
|
141 func (p *parser) parse() *node {
|
|
142 p.init()
|
|
143 switch p.peek() {
|
|
144 case yaml_SCALAR_EVENT:
|
|
145 return p.scalar()
|
|
146 case yaml_ALIAS_EVENT:
|
|
147 return p.alias()
|
|
148 case yaml_MAPPING_START_EVENT:
|
|
149 return p.mapping()
|
|
150 case yaml_SEQUENCE_START_EVENT:
|
|
151 return p.sequence()
|
|
152 case yaml_DOCUMENT_START_EVENT:
|
|
153 return p.document()
|
|
154 case yaml_STREAM_END_EVENT:
|
|
155 // Happens when attempting to decode an empty buffer.
|
|
156 return nil
|
|
157 default:
|
|
158 panic("attempted to parse unknown event: " + p.event.typ.String())
|
|
159 }
|
|
160 }
|
|
161
|
|
162 func (p *parser) node(kind int) *node {
|
|
163 return &node{
|
|
164 kind: kind,
|
|
165 line: p.event.start_mark.line,
|
|
166 column: p.event.start_mark.column,
|
|
167 }
|
|
168 }
|
|
169
|
|
170 func (p *parser) document() *node {
|
|
171 n := p.node(documentNode)
|
|
172 n.anchors = make(map[string]*node)
|
|
173 p.doc = n
|
|
174 p.expect(yaml_DOCUMENT_START_EVENT)
|
|
175 n.children = append(n.children, p.parse())
|
|
176 p.expect(yaml_DOCUMENT_END_EVENT)
|
|
177 return n
|
|
178 }
|
|
179
|
|
180 func (p *parser) alias() *node {
|
|
181 n := p.node(aliasNode)
|
|
182 n.value = string(p.event.anchor)
|
|
183 n.alias = p.doc.anchors[n.value]
|
|
184 if n.alias == nil {
|
|
185 failf("unknown anchor '%s' referenced", n.value)
|
|
186 }
|
|
187 p.expect(yaml_ALIAS_EVENT)
|
|
188 return n
|
|
189 }
|
|
190
|
|
191 func (p *parser) scalar() *node {
|
|
192 n := p.node(scalarNode)
|
|
193 n.value = string(p.event.value)
|
|
194 n.tag = string(p.event.tag)
|
|
195 n.implicit = p.event.implicit
|
|
196 p.anchor(n, p.event.anchor)
|
|
197 p.expect(yaml_SCALAR_EVENT)
|
|
198 return n
|
|
199 }
|
|
200
|
|
201 func (p *parser) sequence() *node {
|
|
202 n := p.node(sequenceNode)
|
|
203 p.anchor(n, p.event.anchor)
|
|
204 p.expect(yaml_SEQUENCE_START_EVENT)
|
|
205 for p.peek() != yaml_SEQUENCE_END_EVENT {
|
|
206 n.children = append(n.children, p.parse())
|
|
207 }
|
|
208 p.expect(yaml_SEQUENCE_END_EVENT)
|
|
209 return n
|
|
210 }
|
|
211
|
|
212 func (p *parser) mapping() *node {
|
|
213 n := p.node(mappingNode)
|
|
214 p.anchor(n, p.event.anchor)
|
|
215 p.expect(yaml_MAPPING_START_EVENT)
|
|
216 for p.peek() != yaml_MAPPING_END_EVENT {
|
|
217 n.children = append(n.children, p.parse(), p.parse())
|
|
218 }
|
|
219 p.expect(yaml_MAPPING_END_EVENT)
|
|
220 return n
|
|
221 }
|
|
222
|
|
223 // ----------------------------------------------------------------------------
|
|
224 // Decoder, unmarshals a node into a provided value.
|
|
225
|
|
226 type decoder struct {
|
|
227 doc *node
|
|
228 aliases map[*node]bool
|
|
229 mapType reflect.Type
|
|
230 terrors []string
|
|
231 strict bool
|
|
232
|
|
233 decodeCount int
|
|
234 aliasCount int
|
|
235 aliasDepth int
|
|
236 }
|
|
237
|
|
238 var (
|
|
239 mapItemType = reflect.TypeOf(MapItem{})
|
|
240 durationType = reflect.TypeOf(time.Duration(0))
|
|
241 defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
|
|
242 ifaceType = defaultMapType.Elem()
|
|
243 timeType = reflect.TypeOf(time.Time{})
|
|
244 ptrTimeType = reflect.TypeOf(&time.Time{})
|
|
245 )
|
|
246
|
|
247 func newDecoder(strict bool) *decoder {
|
|
248 d := &decoder{mapType: defaultMapType, strict: strict}
|
|
249 d.aliases = make(map[*node]bool)
|
|
250 return d
|
|
251 }
|
|
252
|
|
253 func (d *decoder) terror(n *node, tag string, out reflect.Value) {
|
|
254 if n.tag != "" {
|
|
255 tag = n.tag
|
|
256 }
|
|
257 value := n.value
|
|
258 if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG {
|
|
259 if len(value) > 10 {
|
|
260 value = " `" + value[:7] + "...`"
|
|
261 } else {
|
|
262 value = " `" + value + "`"
|
|
263 }
|
|
264 }
|
|
265 d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type()))
|
|
266 }
|
|
267
|
|
268 func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
|
|
269 terrlen := len(d.terrors)
|
|
270 err := u.UnmarshalYAML(func(v interface{}) (err error) {
|
|
271 defer handleErr(&err)
|
|
272 d.unmarshal(n, reflect.ValueOf(v))
|
|
273 if len(d.terrors) > terrlen {
|
|
274 issues := d.terrors[terrlen:]
|
|
275 d.terrors = d.terrors[:terrlen]
|
|
276 return &TypeError{issues}
|
|
277 }
|
|
278 return nil
|
|
279 })
|
|
280 if e, ok := err.(*TypeError); ok {
|
|
281 d.terrors = append(d.terrors, e.Errors...)
|
|
282 return false
|
|
283 }
|
|
284 if err != nil {
|
|
285 fail(err)
|
|
286 }
|
|
287 return true
|
|
288 }
|
|
289
|
|
290 // d.prepare initializes and dereferences pointers and calls UnmarshalYAML
|
|
291 // if a value is found to implement it.
|
|
292 // It returns the initialized and dereferenced out value, whether
|
|
293 // unmarshalling was already done by UnmarshalYAML, and if so whether
|
|
294 // its types unmarshalled appropriately.
|
|
295 //
|
|
296 // If n holds a null value, prepare returns before doing anything.
|
|
297 func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
|
|
298 if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) {
|
|
299 return out, false, false
|
|
300 }
|
|
301 again := true
|
|
302 for again {
|
|
303 again = false
|
|
304 if out.Kind() == reflect.Ptr {
|
|
305 if out.IsNil() {
|
|
306 out.Set(reflect.New(out.Type().Elem()))
|
|
307 }
|
|
308 out = out.Elem()
|
|
309 again = true
|
|
310 }
|
|
311 if out.CanAddr() {
|
|
312 if u, ok := out.Addr().Interface().(Unmarshaler); ok {
|
|
313 good = d.callUnmarshaler(n, u)
|
|
314 return out, true, good
|
|
315 }
|
|
316 }
|
|
317 }
|
|
318 return out, false, false
|
|
319 }
|
|
320
|
|
321 const (
|
|
322 // 400,000 decode operations is ~500kb of dense object declarations, or
|
|
323 // ~5kb of dense object declarations with 10000% alias expansion
|
|
324 alias_ratio_range_low = 400000
|
|
325
|
|
326 // 4,000,000 decode operations is ~5MB of dense object declarations, or
|
|
327 // ~4.5MB of dense object declarations with 10% alias expansion
|
|
328 alias_ratio_range_high = 4000000
|
|
329
|
|
330 // alias_ratio_range is the range over which we scale allowed alias ratios
|
|
331 alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
|
|
332 )
|
|
333
|
|
334 func allowedAliasRatio(decodeCount int) float64 {
|
|
335 switch {
|
|
336 case decodeCount <= alias_ratio_range_low:
|
|
337 // allow 99% to come from alias expansion for small-to-medium documents
|
|
338 return 0.99
|
|
339 case decodeCount >= alias_ratio_range_high:
|
|
340 // allow 10% to come from alias expansion for very large documents
|
|
341 return 0.10
|
|
342 default:
|
|
343 // scale smoothly from 99% down to 10% over the range.
|
|
344 // this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
|
|
345 // 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
|
|
346 return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
|
|
347 }
|
|
348 }
|
|
349
|
|
350 func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
|
|
351 d.decodeCount++
|
|
352 if d.aliasDepth > 0 {
|
|
353 d.aliasCount++
|
|
354 }
|
|
355 if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
|
|
356 failf("document contains excessive aliasing")
|
|
357 }
|
|
358 switch n.kind {
|
|
359 case documentNode:
|
|
360 return d.document(n, out)
|
|
361 case aliasNode:
|
|
362 return d.alias(n, out)
|
|
363 }
|
|
364 out, unmarshaled, good := d.prepare(n, out)
|
|
365 if unmarshaled {
|
|
366 return good
|
|
367 }
|
|
368 switch n.kind {
|
|
369 case scalarNode:
|
|
370 good = d.scalar(n, out)
|
|
371 case mappingNode:
|
|
372 good = d.mapping(n, out)
|
|
373 case sequenceNode:
|
|
374 good = d.sequence(n, out)
|
|
375 default:
|
|
376 panic("internal error: unknown node kind: " + strconv.Itoa(n.kind))
|
|
377 }
|
|
378 return good
|
|
379 }
|
|
380
|
|
381 func (d *decoder) document(n *node, out reflect.Value) (good bool) {
|
|
382 if len(n.children) == 1 {
|
|
383 d.doc = n
|
|
384 d.unmarshal(n.children[0], out)
|
|
385 return true
|
|
386 }
|
|
387 return false
|
|
388 }
|
|
389
|
|
390 func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
|
|
391 if d.aliases[n] {
|
|
392 // TODO this could actually be allowed in some circumstances.
|
|
393 failf("anchor '%s' value contains itself", n.value)
|
|
394 }
|
|
395 d.aliases[n] = true
|
|
396 d.aliasDepth++
|
|
397 good = d.unmarshal(n.alias, out)
|
|
398 d.aliasDepth--
|
|
399 delete(d.aliases, n)
|
|
400 return good
|
|
401 }
|
|
402
|
|
403 var zeroValue reflect.Value
|
|
404
|
|
405 func resetMap(out reflect.Value) {
|
|
406 for _, k := range out.MapKeys() {
|
|
407 out.SetMapIndex(k, zeroValue)
|
|
408 }
|
|
409 }
|
|
410
|
|
411 func (d *decoder) scalar(n *node, out reflect.Value) bool {
|
|
412 var tag string
|
|
413 var resolved interface{}
|
|
414 if n.tag == "" && !n.implicit {
|
|
415 tag = yaml_STR_TAG
|
|
416 resolved = n.value
|
|
417 } else {
|
|
418 tag, resolved = resolve(n.tag, n.value)
|
|
419 if tag == yaml_BINARY_TAG {
|
|
420 data, err := base64.StdEncoding.DecodeString(resolved.(string))
|
|
421 if err != nil {
|
|
422 failf("!!binary value contains invalid base64 data")
|
|
423 }
|
|
424 resolved = string(data)
|
|
425 }
|
|
426 }
|
|
427 if resolved == nil {
|
|
428 if out.Kind() == reflect.Map && !out.CanAddr() {
|
|
429 resetMap(out)
|
|
430 } else {
|
|
431 out.Set(reflect.Zero(out.Type()))
|
|
432 }
|
|
433 return true
|
|
434 }
|
|
435 if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
|
|
436 // We've resolved to exactly the type we want, so use that.
|
|
437 out.Set(resolvedv)
|
|
438 return true
|
|
439 }
|
|
440 // Perhaps we can use the value as a TextUnmarshaler to
|
|
441 // set its value.
|
|
442 if out.CanAddr() {
|
|
443 u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
|
|
444 if ok {
|
|
445 var text []byte
|
|
446 if tag == yaml_BINARY_TAG {
|
|
447 text = []byte(resolved.(string))
|
|
448 } else {
|
|
449 // We let any value be unmarshaled into TextUnmarshaler.
|
|
450 // That might be more lax than we'd like, but the
|
|
451 // TextUnmarshaler itself should bowl out any dubious values.
|
|
452 text = []byte(n.value)
|
|
453 }
|
|
454 err := u.UnmarshalText(text)
|
|
455 if err != nil {
|
|
456 fail(err)
|
|
457 }
|
|
458 return true
|
|
459 }
|
|
460 }
|
|
461 switch out.Kind() {
|
|
462 case reflect.String:
|
|
463 if tag == yaml_BINARY_TAG {
|
|
464 out.SetString(resolved.(string))
|
|
465 return true
|
|
466 }
|
|
467 if resolved != nil {
|
|
468 out.SetString(n.value)
|
|
469 return true
|
|
470 }
|
|
471 case reflect.Interface:
|
|
472 if resolved == nil {
|
|
473 out.Set(reflect.Zero(out.Type()))
|
|
474 } else if tag == yaml_TIMESTAMP_TAG {
|
|
475 // It looks like a timestamp but for backward compatibility
|
|
476 // reasons we set it as a string, so that code that unmarshals
|
|
477 // timestamp-like values into interface{} will continue to
|
|
478 // see a string and not a time.Time.
|
|
479 // TODO(v3) Drop this.
|
|
480 out.Set(reflect.ValueOf(n.value))
|
|
481 } else {
|
|
482 out.Set(reflect.ValueOf(resolved))
|
|
483 }
|
|
484 return true
|
|
485 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
486 switch resolved := resolved.(type) {
|
|
487 case int:
|
|
488 if !out.OverflowInt(int64(resolved)) {
|
|
489 out.SetInt(int64(resolved))
|
|
490 return true
|
|
491 }
|
|
492 case int64:
|
|
493 if !out.OverflowInt(resolved) {
|
|
494 out.SetInt(resolved)
|
|
495 return true
|
|
496 }
|
|
497 case uint64:
|
|
498 if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
|
|
499 out.SetInt(int64(resolved))
|
|
500 return true
|
|
501 }
|
|
502 case float64:
|
|
503 if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
|
|
504 out.SetInt(int64(resolved))
|
|
505 return true
|
|
506 }
|
|
507 case string:
|
|
508 if out.Type() == durationType {
|
|
509 d, err := time.ParseDuration(resolved)
|
|
510 if err == nil {
|
|
511 out.SetInt(int64(d))
|
|
512 return true
|
|
513 }
|
|
514 }
|
|
515 }
|
|
516 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
517 switch resolved := resolved.(type) {
|
|
518 case int:
|
|
519 if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
|
|
520 out.SetUint(uint64(resolved))
|
|
521 return true
|
|
522 }
|
|
523 case int64:
|
|
524 if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
|
|
525 out.SetUint(uint64(resolved))
|
|
526 return true
|
|
527 }
|
|
528 case uint64:
|
|
529 if !out.OverflowUint(uint64(resolved)) {
|
|
530 out.SetUint(uint64(resolved))
|
|
531 return true
|
|
532 }
|
|
533 case float64:
|
|
534 if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
|
|
535 out.SetUint(uint64(resolved))
|
|
536 return true
|
|
537 }
|
|
538 }
|
|
539 case reflect.Bool:
|
|
540 switch resolved := resolved.(type) {
|
|
541 case bool:
|
|
542 out.SetBool(resolved)
|
|
543 return true
|
|
544 }
|
|
545 case reflect.Float32, reflect.Float64:
|
|
546 switch resolved := resolved.(type) {
|
|
547 case int:
|
|
548 out.SetFloat(float64(resolved))
|
|
549 return true
|
|
550 case int64:
|
|
551 out.SetFloat(float64(resolved))
|
|
552 return true
|
|
553 case uint64:
|
|
554 out.SetFloat(float64(resolved))
|
|
555 return true
|
|
556 case float64:
|
|
557 out.SetFloat(resolved)
|
|
558 return true
|
|
559 }
|
|
560 case reflect.Struct:
|
|
561 if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
|
|
562 out.Set(resolvedv)
|
|
563 return true
|
|
564 }
|
|
565 case reflect.Ptr:
|
|
566 if out.Type().Elem() == reflect.TypeOf(resolved) {
|
|
567 // TODO DOes this make sense? When is out a Ptr except when decoding a nil value?
|
|
568 elem := reflect.New(out.Type().Elem())
|
|
569 elem.Elem().Set(reflect.ValueOf(resolved))
|
|
570 out.Set(elem)
|
|
571 return true
|
|
572 }
|
|
573 }
|
|
574 d.terror(n, tag, out)
|
|
575 return false
|
|
576 }
|
|
577
|
|
578 func settableValueOf(i interface{}) reflect.Value {
|
|
579 v := reflect.ValueOf(i)
|
|
580 sv := reflect.New(v.Type()).Elem()
|
|
581 sv.Set(v)
|
|
582 return sv
|
|
583 }
|
|
584
|
|
585 func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
|
|
586 l := len(n.children)
|
|
587
|
|
588 var iface reflect.Value
|
|
589 switch out.Kind() {
|
|
590 case reflect.Slice:
|
|
591 out.Set(reflect.MakeSlice(out.Type(), l, l))
|
|
592 case reflect.Array:
|
|
593 if l != out.Len() {
|
|
594 failf("invalid array: want %d elements but got %d", out.Len(), l)
|
|
595 }
|
|
596 case reflect.Interface:
|
|
597 // No type hints. Will have to use a generic sequence.
|
|
598 iface = out
|
|
599 out = settableValueOf(make([]interface{}, l))
|
|
600 default:
|
|
601 d.terror(n, yaml_SEQ_TAG, out)
|
|
602 return false
|
|
603 }
|
|
604 et := out.Type().Elem()
|
|
605
|
|
606 j := 0
|
|
607 for i := 0; i < l; i++ {
|
|
608 e := reflect.New(et).Elem()
|
|
609 if ok := d.unmarshal(n.children[i], e); ok {
|
|
610 out.Index(j).Set(e)
|
|
611 j++
|
|
612 }
|
|
613 }
|
|
614 if out.Kind() != reflect.Array {
|
|
615 out.Set(out.Slice(0, j))
|
|
616 }
|
|
617 if iface.IsValid() {
|
|
618 iface.Set(out)
|
|
619 }
|
|
620 return true
|
|
621 }
|
|
622
|
|
623 func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
|
|
624 switch out.Kind() {
|
|
625 case reflect.Struct:
|
|
626 return d.mappingStruct(n, out)
|
|
627 case reflect.Slice:
|
|
628 return d.mappingSlice(n, out)
|
|
629 case reflect.Map:
|
|
630 // okay
|
|
631 case reflect.Interface:
|
|
632 if d.mapType.Kind() == reflect.Map {
|
|
633 iface := out
|
|
634 out = reflect.MakeMap(d.mapType)
|
|
635 iface.Set(out)
|
|
636 } else {
|
|
637 slicev := reflect.New(d.mapType).Elem()
|
|
638 if !d.mappingSlice(n, slicev) {
|
|
639 return false
|
|
640 }
|
|
641 out.Set(slicev)
|
|
642 return true
|
|
643 }
|
|
644 default:
|
|
645 d.terror(n, yaml_MAP_TAG, out)
|
|
646 return false
|
|
647 }
|
|
648 outt := out.Type()
|
|
649 kt := outt.Key()
|
|
650 et := outt.Elem()
|
|
651
|
|
652 mapType := d.mapType
|
|
653 if outt.Key() == ifaceType && outt.Elem() == ifaceType {
|
|
654 d.mapType = outt
|
|
655 }
|
|
656
|
|
657 if out.IsNil() {
|
|
658 out.Set(reflect.MakeMap(outt))
|
|
659 }
|
|
660 l := len(n.children)
|
|
661 for i := 0; i < l; i += 2 {
|
|
662 if isMerge(n.children[i]) {
|
|
663 d.merge(n.children[i+1], out)
|
|
664 continue
|
|
665 }
|
|
666 k := reflect.New(kt).Elem()
|
|
667 if d.unmarshal(n.children[i], k) {
|
|
668 kkind := k.Kind()
|
|
669 if kkind == reflect.Interface {
|
|
670 kkind = k.Elem().Kind()
|
|
671 }
|
|
672 if kkind == reflect.Map || kkind == reflect.Slice {
|
|
673 failf("invalid map key: %#v", k.Interface())
|
|
674 }
|
|
675 e := reflect.New(et).Elem()
|
|
676 if d.unmarshal(n.children[i+1], e) {
|
|
677 d.setMapIndex(n.children[i+1], out, k, e)
|
|
678 }
|
|
679 }
|
|
680 }
|
|
681 d.mapType = mapType
|
|
682 return true
|
|
683 }
|
|
684
|
|
685 func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) {
|
|
686 if d.strict && out.MapIndex(k) != zeroValue {
|
|
687 d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface()))
|
|
688 return
|
|
689 }
|
|
690 out.SetMapIndex(k, v)
|
|
691 }
|
|
692
|
|
693 func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
|
|
694 outt := out.Type()
|
|
695 if outt.Elem() != mapItemType {
|
|
696 d.terror(n, yaml_MAP_TAG, out)
|
|
697 return false
|
|
698 }
|
|
699
|
|
700 mapType := d.mapType
|
|
701 d.mapType = outt
|
|
702
|
|
703 var slice []MapItem
|
|
704 var l = len(n.children)
|
|
705 for i := 0; i < l; i += 2 {
|
|
706 if isMerge(n.children[i]) {
|
|
707 d.merge(n.children[i+1], out)
|
|
708 continue
|
|
709 }
|
|
710 item := MapItem{}
|
|
711 k := reflect.ValueOf(&item.Key).Elem()
|
|
712 if d.unmarshal(n.children[i], k) {
|
|
713 v := reflect.ValueOf(&item.Value).Elem()
|
|
714 if d.unmarshal(n.children[i+1], v) {
|
|
715 slice = append(slice, item)
|
|
716 }
|
|
717 }
|
|
718 }
|
|
719 out.Set(reflect.ValueOf(slice))
|
|
720 d.mapType = mapType
|
|
721 return true
|
|
722 }
|
|
723
|
|
724 func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
|
|
725 sinfo, err := getStructInfo(out.Type())
|
|
726 if err != nil {
|
|
727 panic(err)
|
|
728 }
|
|
729 name := settableValueOf("")
|
|
730 l := len(n.children)
|
|
731
|
|
732 var inlineMap reflect.Value
|
|
733 var elemType reflect.Type
|
|
734 if sinfo.InlineMap != -1 {
|
|
735 inlineMap = out.Field(sinfo.InlineMap)
|
|
736 inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
|
|
737 elemType = inlineMap.Type().Elem()
|
|
738 }
|
|
739
|
|
740 var doneFields []bool
|
|
741 if d.strict {
|
|
742 doneFields = make([]bool, len(sinfo.FieldsList))
|
|
743 }
|
|
744 for i := 0; i < l; i += 2 {
|
|
745 ni := n.children[i]
|
|
746 if isMerge(ni) {
|
|
747 d.merge(n.children[i+1], out)
|
|
748 continue
|
|
749 }
|
|
750 if !d.unmarshal(ni, name) {
|
|
751 continue
|
|
752 }
|
|
753 if info, ok := sinfo.FieldsMap[name.String()]; ok {
|
|
754 if d.strict {
|
|
755 if doneFields[info.Id] {
|
|
756 d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type()))
|
|
757 continue
|
|
758 }
|
|
759 doneFields[info.Id] = true
|
|
760 }
|
|
761 var field reflect.Value
|
|
762 if info.Inline == nil {
|
|
763 field = out.Field(info.Num)
|
|
764 } else {
|
|
765 field = out.FieldByIndex(info.Inline)
|
|
766 }
|
|
767 d.unmarshal(n.children[i+1], field)
|
|
768 } else if sinfo.InlineMap != -1 {
|
|
769 if inlineMap.IsNil() {
|
|
770 inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
|
|
771 }
|
|
772 value := reflect.New(elemType).Elem()
|
|
773 d.unmarshal(n.children[i+1], value)
|
|
774 d.setMapIndex(n.children[i+1], inlineMap, name, value)
|
|
775 } else if d.strict {
|
|
776 d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type()))
|
|
777 }
|
|
778 }
|
|
779 return true
|
|
780 }
|
|
781
|
|
782 func failWantMap() {
|
|
783 failf("map merge requires map or sequence of maps as the value")
|
|
784 }
|
|
785
|
|
786 func (d *decoder) merge(n *node, out reflect.Value) {
|
|
787 switch n.kind {
|
|
788 case mappingNode:
|
|
789 d.unmarshal(n, out)
|
|
790 case aliasNode:
|
|
791 if n.alias != nil && n.alias.kind != mappingNode {
|
|
792 failWantMap()
|
|
793 }
|
|
794 d.unmarshal(n, out)
|
|
795 case sequenceNode:
|
|
796 // Step backwards as earlier nodes take precedence.
|
|
797 for i := len(n.children) - 1; i >= 0; i-- {
|
|
798 ni := n.children[i]
|
|
799 if ni.kind == aliasNode {
|
|
800 if ni.alias != nil && ni.alias.kind != mappingNode {
|
|
801 failWantMap()
|
|
802 }
|
|
803 } else if ni.kind != mappingNode {
|
|
804 failWantMap()
|
|
805 }
|
|
806 d.unmarshal(ni, out)
|
|
807 }
|
|
808 default:
|
|
809 failWantMap()
|
|
810 }
|
|
811 }
|
|
812
|
|
813 func isMerge(n *node) bool {
|
|
814 return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG)
|
|
815 }
|