annotate vendor/gopkg.in/yaml.v2/decode.go @ 71:7819959ac6ca draft

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