annotate vendor/gopkg.in/yaml.v3/decode.go @ 81:6ce24b93c8d0 draft

I keep inserting random bugs Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>
author yakumo.izuru
date Tue, 12 Dec 2023 14:27:29 +0000
parents d8727551f403
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
74
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
1 //
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
2 // Copyright (c) 2011-2019 Canonical Ltd
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
3 //
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
4 // Licensed under the Apache License, Version 2.0 (the "License");
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
5 // you may not use this file except in compliance with the License.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
6 // You may obtain a copy of the License at
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
7 //
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
8 // http://www.apache.org/licenses/LICENSE-2.0
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
9 //
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
10 // Unless required by applicable law or agreed to in writing, software
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
11 // distributed under the License is distributed on an "AS IS" BASIS,
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
13 // See the License for the specific language governing permissions and
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
14 // limitations under the License.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
15
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
16 package yaml
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
17
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
18 import (
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
19 "encoding"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
20 "encoding/base64"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
21 "fmt"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
22 "io"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
23 "math"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
24 "reflect"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
25 "strconv"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
26 "time"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
27 )
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
28
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
29 // ----------------------------------------------------------------------------
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
30 // Parser, produces a node tree out of a libyaml event stream.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
31
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
32 type parser struct {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
33 parser yaml_parser_t
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
34 event yaml_event_t
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
35 doc *Node
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
36 anchors map[string]*Node
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
37 doneInit bool
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
38 textless bool
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
39 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
40
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
41 func newParser(b []byte) *parser {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
42 p := parser{}
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
43 if !yaml_parser_initialize(&p.parser) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
44 panic("failed to initialize YAML emitter")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
45 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
46 if len(b) == 0 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
47 b = []byte{'\n'}
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
48 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
49 yaml_parser_set_input_string(&p.parser, b)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
50 return &p
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
51 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
52
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
53 func newParserFromReader(r io.Reader) *parser {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
54 p := parser{}
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
55 if !yaml_parser_initialize(&p.parser) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
56 panic("failed to initialize YAML emitter")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
57 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
58 yaml_parser_set_input_reader(&p.parser, r)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
59 return &p
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
60 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
61
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
62 func (p *parser) init() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
63 if p.doneInit {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
64 return
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
65 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
66 p.anchors = make(map[string]*Node)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
67 p.expect(yaml_STREAM_START_EVENT)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
68 p.doneInit = true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
69 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
70
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
71 func (p *parser) destroy() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
72 if p.event.typ != yaml_NO_EVENT {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
73 yaml_event_delete(&p.event)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
74 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
75 yaml_parser_delete(&p.parser)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
76 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
77
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
78 // expect consumes an event from the event stream and
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
79 // checks that it's of the expected type.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
80 func (p *parser) expect(e yaml_event_type_t) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
81 if p.event.typ == yaml_NO_EVENT {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
82 if !yaml_parser_parse(&p.parser, &p.event) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
83 p.fail()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
84 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
85 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
86 if p.event.typ == yaml_STREAM_END_EVENT {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
87 failf("attempted to go past the end of stream; corrupted value?")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
88 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
89 if p.event.typ != e {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
90 p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
91 p.fail()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
92 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
93 yaml_event_delete(&p.event)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
94 p.event.typ = yaml_NO_EVENT
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
95 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
96
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
97 // peek peeks at the next event in the event stream,
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
98 // puts the results into p.event and returns the event type.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
99 func (p *parser) peek() yaml_event_type_t {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
100 if p.event.typ != yaml_NO_EVENT {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
101 return p.event.typ
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
102 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
103 // It's curious choice from the underlying API to generally return a
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
104 // positive result on success, but on this case return true in an error
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
105 // scenario. This was the source of bugs in the past (issue #666).
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
106 if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
107 p.fail()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
108 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
109 return p.event.typ
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
110 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
111
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
112 func (p *parser) fail() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
113 var where string
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
114 var line int
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
115 if p.parser.context_mark.line != 0 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
116 line = p.parser.context_mark.line
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
117 // Scanner errors don't iterate line before returning error
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
118 if p.parser.error == yaml_SCANNER_ERROR {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
119 line++
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
120 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
121 } else if p.parser.problem_mark.line != 0 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
122 line = p.parser.problem_mark.line
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
123 // Scanner errors don't iterate line before returning error
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
124 if p.parser.error == yaml_SCANNER_ERROR {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
125 line++
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
126 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
127 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
128 if line != 0 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
129 where = "line " + strconv.Itoa(line) + ": "
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
130 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
131 var msg string
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
132 if len(p.parser.problem) > 0 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
133 msg = p.parser.problem
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
134 } else {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
135 msg = "unknown problem parsing YAML content"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
136 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
137 failf("%s%s", where, msg)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
138 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
139
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
140 func (p *parser) anchor(n *Node, anchor []byte) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
141 if anchor != nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
142 n.Anchor = string(anchor)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
143 p.anchors[n.Anchor] = n
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
144 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
145 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
146
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
147 func (p *parser) parse() *Node {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
148 p.init()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
149 switch p.peek() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
150 case yaml_SCALAR_EVENT:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
151 return p.scalar()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
152 case yaml_ALIAS_EVENT:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
153 return p.alias()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
154 case yaml_MAPPING_START_EVENT:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
155 return p.mapping()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
156 case yaml_SEQUENCE_START_EVENT:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
157 return p.sequence()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
158 case yaml_DOCUMENT_START_EVENT:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
159 return p.document()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
160 case yaml_STREAM_END_EVENT:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
161 // Happens when attempting to decode an empty buffer.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
162 return nil
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
163 case yaml_TAIL_COMMENT_EVENT:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
164 panic("internal error: unexpected tail comment event (please report)")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
165 default:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
166 panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String())
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
167 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
168 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
169
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
170 func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
171 var style Style
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
172 if tag != "" && tag != "!" {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
173 tag = shortTag(tag)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
174 style = TaggedStyle
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
175 } else if defaultTag != "" {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
176 tag = defaultTag
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
177 } else if kind == ScalarNode {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
178 tag, _ = resolve("", value)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
179 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
180 n := &Node{
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
181 Kind: kind,
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
182 Tag: tag,
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
183 Value: value,
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
184 Style: style,
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
185 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
186 if !p.textless {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
187 n.Line = p.event.start_mark.line + 1
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
188 n.Column = p.event.start_mark.column + 1
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
189 n.HeadComment = string(p.event.head_comment)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
190 n.LineComment = string(p.event.line_comment)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
191 n.FootComment = string(p.event.foot_comment)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
192 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
193 return n
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
194 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
195
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
196 func (p *parser) parseChild(parent *Node) *Node {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
197 child := p.parse()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
198 parent.Content = append(parent.Content, child)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
199 return child
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
200 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
201
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
202 func (p *parser) document() *Node {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
203 n := p.node(DocumentNode, "", "", "")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
204 p.doc = n
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
205 p.expect(yaml_DOCUMENT_START_EVENT)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
206 p.parseChild(n)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
207 if p.peek() == yaml_DOCUMENT_END_EVENT {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
208 n.FootComment = string(p.event.foot_comment)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
209 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
210 p.expect(yaml_DOCUMENT_END_EVENT)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
211 return n
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
212 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
213
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
214 func (p *parser) alias() *Node {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
215 n := p.node(AliasNode, "", "", string(p.event.anchor))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
216 n.Alias = p.anchors[n.Value]
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
217 if n.Alias == nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
218 failf("unknown anchor '%s' referenced", n.Value)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
219 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
220 p.expect(yaml_ALIAS_EVENT)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
221 return n
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
222 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
223
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
224 func (p *parser) scalar() *Node {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
225 var parsedStyle = p.event.scalar_style()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
226 var nodeStyle Style
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
227 switch {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
228 case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
229 nodeStyle = DoubleQuotedStyle
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
230 case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
231 nodeStyle = SingleQuotedStyle
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
232 case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
233 nodeStyle = LiteralStyle
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
234 case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
235 nodeStyle = FoldedStyle
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
236 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
237 var nodeValue = string(p.event.value)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
238 var nodeTag = string(p.event.tag)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
239 var defaultTag string
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
240 if nodeStyle == 0 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
241 if nodeValue == "<<" {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
242 defaultTag = mergeTag
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
243 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
244 } else {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
245 defaultTag = strTag
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
246 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
247 n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
248 n.Style |= nodeStyle
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
249 p.anchor(n, p.event.anchor)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
250 p.expect(yaml_SCALAR_EVENT)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
251 return n
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
252 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
253
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
254 func (p *parser) sequence() *Node {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
255 n := p.node(SequenceNode, seqTag, string(p.event.tag), "")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
256 if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
257 n.Style |= FlowStyle
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
258 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
259 p.anchor(n, p.event.anchor)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
260 p.expect(yaml_SEQUENCE_START_EVENT)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
261 for p.peek() != yaml_SEQUENCE_END_EVENT {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
262 p.parseChild(n)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
263 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
264 n.LineComment = string(p.event.line_comment)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
265 n.FootComment = string(p.event.foot_comment)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
266 p.expect(yaml_SEQUENCE_END_EVENT)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
267 return n
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
268 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
269
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
270 func (p *parser) mapping() *Node {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
271 n := p.node(MappingNode, mapTag, string(p.event.tag), "")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
272 block := true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
273 if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
274 block = false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
275 n.Style |= FlowStyle
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
276 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
277 p.anchor(n, p.event.anchor)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
278 p.expect(yaml_MAPPING_START_EVENT)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
279 for p.peek() != yaml_MAPPING_END_EVENT {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
280 k := p.parseChild(n)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
281 if block && k.FootComment != "" {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
282 // Must be a foot comment for the prior value when being dedented.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
283 if len(n.Content) > 2 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
284 n.Content[len(n.Content)-3].FootComment = k.FootComment
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
285 k.FootComment = ""
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
286 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
287 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
288 v := p.parseChild(n)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
289 if k.FootComment == "" && v.FootComment != "" {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
290 k.FootComment = v.FootComment
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
291 v.FootComment = ""
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
292 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
293 if p.peek() == yaml_TAIL_COMMENT_EVENT {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
294 if k.FootComment == "" {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
295 k.FootComment = string(p.event.foot_comment)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
296 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
297 p.expect(yaml_TAIL_COMMENT_EVENT)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
298 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
299 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
300 n.LineComment = string(p.event.line_comment)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
301 n.FootComment = string(p.event.foot_comment)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
302 if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
303 n.Content[len(n.Content)-2].FootComment = n.FootComment
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
304 n.FootComment = ""
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
305 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
306 p.expect(yaml_MAPPING_END_EVENT)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
307 return n
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
308 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
309
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
310 // ----------------------------------------------------------------------------
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
311 // Decoder, unmarshals a node into a provided value.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
312
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
313 type decoder struct {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
314 doc *Node
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
315 aliases map[*Node]bool
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
316 terrors []string
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
317
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
318 stringMapType reflect.Type
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
319 generalMapType reflect.Type
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
320
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
321 knownFields bool
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
322 uniqueKeys bool
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
323 decodeCount int
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
324 aliasCount int
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
325 aliasDepth int
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
326
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
327 mergedFields map[interface{}]bool
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
328 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
329
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
330 var (
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
331 nodeType = reflect.TypeOf(Node{})
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
332 durationType = reflect.TypeOf(time.Duration(0))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
333 stringMapType = reflect.TypeOf(map[string]interface{}{})
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
334 generalMapType = reflect.TypeOf(map[interface{}]interface{}{})
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
335 ifaceType = generalMapType.Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
336 timeType = reflect.TypeOf(time.Time{})
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
337 ptrTimeType = reflect.TypeOf(&time.Time{})
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
338 )
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
339
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
340 func newDecoder() *decoder {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
341 d := &decoder{
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
342 stringMapType: stringMapType,
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
343 generalMapType: generalMapType,
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
344 uniqueKeys: true,
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
345 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
346 d.aliases = make(map[*Node]bool)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
347 return d
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
348 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
349
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
350 func (d *decoder) terror(n *Node, tag string, out reflect.Value) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
351 if n.Tag != "" {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
352 tag = n.Tag
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
353 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
354 value := n.Value
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
355 if tag != seqTag && tag != mapTag {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
356 if len(value) > 10 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
357 value = " `" + value[:7] + "...`"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
358 } else {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
359 value = " `" + value + "`"
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
360 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
361 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
362 d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type()))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
363 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
364
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
365 func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
366 err := u.UnmarshalYAML(n)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
367 if e, ok := err.(*TypeError); ok {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
368 d.terrors = append(d.terrors, e.Errors...)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
369 return false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
370 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
371 if err != nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
372 fail(err)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
373 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
374 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
375 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
376
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
377 func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
378 terrlen := len(d.terrors)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
379 err := u.UnmarshalYAML(func(v interface{}) (err error) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
380 defer handleErr(&err)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
381 d.unmarshal(n, reflect.ValueOf(v))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
382 if len(d.terrors) > terrlen {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
383 issues := d.terrors[terrlen:]
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
384 d.terrors = d.terrors[:terrlen]
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
385 return &TypeError{issues}
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
386 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
387 return nil
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
388 })
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
389 if e, ok := err.(*TypeError); ok {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
390 d.terrors = append(d.terrors, e.Errors...)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
391 return false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
392 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
393 if err != nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
394 fail(err)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
395 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
396 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
397 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
398
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
399 // d.prepare initializes and dereferences pointers and calls UnmarshalYAML
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
400 // if a value is found to implement it.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
401 // It returns the initialized and dereferenced out value, whether
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
402 // unmarshalling was already done by UnmarshalYAML, and if so whether
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
403 // its types unmarshalled appropriately.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
404 //
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
405 // If n holds a null value, prepare returns before doing anything.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
406 func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
407 if n.ShortTag() == nullTag {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
408 return out, false, false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
409 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
410 again := true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
411 for again {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
412 again = false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
413 if out.Kind() == reflect.Ptr {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
414 if out.IsNil() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
415 out.Set(reflect.New(out.Type().Elem()))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
416 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
417 out = out.Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
418 again = true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
419 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
420 if out.CanAddr() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
421 outi := out.Addr().Interface()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
422 if u, ok := outi.(Unmarshaler); ok {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
423 good = d.callUnmarshaler(n, u)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
424 return out, true, good
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
425 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
426 if u, ok := outi.(obsoleteUnmarshaler); ok {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
427 good = d.callObsoleteUnmarshaler(n, u)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
428 return out, true, good
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
429 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
430 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
431 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
432 return out, false, false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
433 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
434
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
435 func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
436 if n.ShortTag() == nullTag {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
437 return reflect.Value{}
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
438 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
439 for _, num := range index {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
440 for {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
441 if v.Kind() == reflect.Ptr {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
442 if v.IsNil() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
443 v.Set(reflect.New(v.Type().Elem()))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
444 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
445 v = v.Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
446 continue
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
447 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
448 break
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
449 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
450 v = v.Field(num)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
451 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
452 return v
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
453 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
454
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
455 const (
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
456 // 400,000 decode operations is ~500kb of dense object declarations, or
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
457 // ~5kb of dense object declarations with 10000% alias expansion
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
458 alias_ratio_range_low = 400000
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
459
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
460 // 4,000,000 decode operations is ~5MB of dense object declarations, or
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
461 // ~4.5MB of dense object declarations with 10% alias expansion
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
462 alias_ratio_range_high = 4000000
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
463
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
464 // alias_ratio_range is the range over which we scale allowed alias ratios
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
465 alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
466 )
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
467
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
468 func allowedAliasRatio(decodeCount int) float64 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
469 switch {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
470 case decodeCount <= alias_ratio_range_low:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
471 // allow 99% to come from alias expansion for small-to-medium documents
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
472 return 0.99
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
473 case decodeCount >= alias_ratio_range_high:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
474 // allow 10% to come from alias expansion for very large documents
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
475 return 0.10
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
476 default:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
477 // scale smoothly from 99% down to 10% over the range.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
478 // this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
479 // 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
480 return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
481 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
482 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
483
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
484 func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
485 d.decodeCount++
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
486 if d.aliasDepth > 0 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
487 d.aliasCount++
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
488 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
489 if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
490 failf("document contains excessive aliasing")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
491 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
492 if out.Type() == nodeType {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
493 out.Set(reflect.ValueOf(n).Elem())
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
494 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
495 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
496 switch n.Kind {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
497 case DocumentNode:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
498 return d.document(n, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
499 case AliasNode:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
500 return d.alias(n, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
501 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
502 out, unmarshaled, good := d.prepare(n, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
503 if unmarshaled {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
504 return good
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
505 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
506 switch n.Kind {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
507 case ScalarNode:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
508 good = d.scalar(n, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
509 case MappingNode:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
510 good = d.mapping(n, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
511 case SequenceNode:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
512 good = d.sequence(n, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
513 case 0:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
514 if n.IsZero() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
515 return d.null(out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
516 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
517 fallthrough
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
518 default:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
519 failf("cannot decode node with unknown kind %d", n.Kind)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
520 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
521 return good
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
522 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
523
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
524 func (d *decoder) document(n *Node, out reflect.Value) (good bool) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
525 if len(n.Content) == 1 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
526 d.doc = n
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
527 d.unmarshal(n.Content[0], out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
528 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
529 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
530 return false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
531 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
532
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
533 func (d *decoder) alias(n *Node, out reflect.Value) (good bool) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
534 if d.aliases[n] {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
535 // TODO this could actually be allowed in some circumstances.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
536 failf("anchor '%s' value contains itself", n.Value)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
537 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
538 d.aliases[n] = true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
539 d.aliasDepth++
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
540 good = d.unmarshal(n.Alias, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
541 d.aliasDepth--
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
542 delete(d.aliases, n)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
543 return good
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
544 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
545
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
546 var zeroValue reflect.Value
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
547
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
548 func resetMap(out reflect.Value) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
549 for _, k := range out.MapKeys() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
550 out.SetMapIndex(k, zeroValue)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
551 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
552 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
553
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
554 func (d *decoder) null(out reflect.Value) bool {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
555 if out.CanAddr() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
556 switch out.Kind() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
557 case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
558 out.Set(reflect.Zero(out.Type()))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
559 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
560 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
561 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
562 return false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
563 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
564
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
565 func (d *decoder) scalar(n *Node, out reflect.Value) bool {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
566 var tag string
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
567 var resolved interface{}
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
568 if n.indicatedString() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
569 tag = strTag
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
570 resolved = n.Value
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
571 } else {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
572 tag, resolved = resolve(n.Tag, n.Value)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
573 if tag == binaryTag {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
574 data, err := base64.StdEncoding.DecodeString(resolved.(string))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
575 if err != nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
576 failf("!!binary value contains invalid base64 data")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
577 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
578 resolved = string(data)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
579 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
580 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
581 if resolved == nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
582 return d.null(out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
583 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
584 if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
585 // We've resolved to exactly the type we want, so use that.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
586 out.Set(resolvedv)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
587 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
588 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
589 // Perhaps we can use the value as a TextUnmarshaler to
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
590 // set its value.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
591 if out.CanAddr() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
592 u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
593 if ok {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
594 var text []byte
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
595 if tag == binaryTag {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
596 text = []byte(resolved.(string))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
597 } else {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
598 // We let any value be unmarshaled into TextUnmarshaler.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
599 // That might be more lax than we'd like, but the
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
600 // TextUnmarshaler itself should bowl out any dubious values.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
601 text = []byte(n.Value)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
602 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
603 err := u.UnmarshalText(text)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
604 if err != nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
605 fail(err)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
606 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
607 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
608 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
609 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
610 switch out.Kind() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
611 case reflect.String:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
612 if tag == binaryTag {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
613 out.SetString(resolved.(string))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
614 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
615 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
616 out.SetString(n.Value)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
617 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
618 case reflect.Interface:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
619 out.Set(reflect.ValueOf(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
620 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
621 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
622 // This used to work in v2, but it's very unfriendly.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
623 isDuration := out.Type() == durationType
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
624
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
625 switch resolved := resolved.(type) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
626 case int:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
627 if !isDuration && !out.OverflowInt(int64(resolved)) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
628 out.SetInt(int64(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
629 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
630 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
631 case int64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
632 if !isDuration && !out.OverflowInt(resolved) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
633 out.SetInt(resolved)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
634 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
635 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
636 case uint64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
637 if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
638 out.SetInt(int64(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
639 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
640 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
641 case float64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
642 if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
643 out.SetInt(int64(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
644 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
645 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
646 case string:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
647 if out.Type() == durationType {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
648 d, err := time.ParseDuration(resolved)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
649 if err == nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
650 out.SetInt(int64(d))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
651 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
652 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
653 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
654 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
655 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
656 switch resolved := resolved.(type) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
657 case int:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
658 if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
659 out.SetUint(uint64(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
660 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
661 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
662 case int64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
663 if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
664 out.SetUint(uint64(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
665 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
666 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
667 case uint64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
668 if !out.OverflowUint(uint64(resolved)) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
669 out.SetUint(uint64(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
670 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
671 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
672 case float64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
673 if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
674 out.SetUint(uint64(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
675 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
676 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
677 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
678 case reflect.Bool:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
679 switch resolved := resolved.(type) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
680 case bool:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
681 out.SetBool(resolved)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
682 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
683 case string:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
684 // This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html).
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
685 // It only works if explicitly attempting to unmarshal into a typed bool value.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
686 switch resolved {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
687 case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
688 out.SetBool(true)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
689 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
690 case "n", "N", "no", "No", "NO", "off", "Off", "OFF":
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
691 out.SetBool(false)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
692 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
693 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
694 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
695 case reflect.Float32, reflect.Float64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
696 switch resolved := resolved.(type) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
697 case int:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
698 out.SetFloat(float64(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
699 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
700 case int64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
701 out.SetFloat(float64(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
702 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
703 case uint64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
704 out.SetFloat(float64(resolved))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
705 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
706 case float64:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
707 out.SetFloat(resolved)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
708 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
709 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
710 case reflect.Struct:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
711 if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
712 out.Set(resolvedv)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
713 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
714 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
715 case reflect.Ptr:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
716 panic("yaml internal error: please report the issue")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
717 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
718 d.terror(n, tag, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
719 return false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
720 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
721
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
722 func settableValueOf(i interface{}) reflect.Value {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
723 v := reflect.ValueOf(i)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
724 sv := reflect.New(v.Type()).Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
725 sv.Set(v)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
726 return sv
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
727 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
728
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
729 func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
730 l := len(n.Content)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
731
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
732 var iface reflect.Value
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
733 switch out.Kind() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
734 case reflect.Slice:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
735 out.Set(reflect.MakeSlice(out.Type(), l, l))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
736 case reflect.Array:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
737 if l != out.Len() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
738 failf("invalid array: want %d elements but got %d", out.Len(), l)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
739 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
740 case reflect.Interface:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
741 // No type hints. Will have to use a generic sequence.
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
742 iface = out
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
743 out = settableValueOf(make([]interface{}, l))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
744 default:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
745 d.terror(n, seqTag, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
746 return false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
747 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
748 et := out.Type().Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
749
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
750 j := 0
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
751 for i := 0; i < l; i++ {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
752 e := reflect.New(et).Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
753 if ok := d.unmarshal(n.Content[i], e); ok {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
754 out.Index(j).Set(e)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
755 j++
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
756 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
757 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
758 if out.Kind() != reflect.Array {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
759 out.Set(out.Slice(0, j))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
760 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
761 if iface.IsValid() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
762 iface.Set(out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
763 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
764 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
765 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
766
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
767 func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
768 l := len(n.Content)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
769 if d.uniqueKeys {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
770 nerrs := len(d.terrors)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
771 for i := 0; i < l; i += 2 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
772 ni := n.Content[i]
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
773 for j := i + 2; j < l; j += 2 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
774 nj := n.Content[j]
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
775 if ni.Kind == nj.Kind && ni.Value == nj.Value {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
776 d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
777 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
778 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
779 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
780 if len(d.terrors) > nerrs {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
781 return false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
782 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
783 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
784 switch out.Kind() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
785 case reflect.Struct:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
786 return d.mappingStruct(n, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
787 case reflect.Map:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
788 // okay
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
789 case reflect.Interface:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
790 iface := out
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
791 if isStringMap(n) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
792 out = reflect.MakeMap(d.stringMapType)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
793 } else {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
794 out = reflect.MakeMap(d.generalMapType)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
795 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
796 iface.Set(out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
797 default:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
798 d.terror(n, mapTag, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
799 return false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
800 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
801
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
802 outt := out.Type()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
803 kt := outt.Key()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
804 et := outt.Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
805
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
806 stringMapType := d.stringMapType
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
807 generalMapType := d.generalMapType
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
808 if outt.Elem() == ifaceType {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
809 if outt.Key().Kind() == reflect.String {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
810 d.stringMapType = outt
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
811 } else if outt.Key() == ifaceType {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
812 d.generalMapType = outt
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
813 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
814 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
815
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
816 mergedFields := d.mergedFields
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
817 d.mergedFields = nil
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
818
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
819 var mergeNode *Node
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
820
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
821 mapIsNew := false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
822 if out.IsNil() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
823 out.Set(reflect.MakeMap(outt))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
824 mapIsNew = true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
825 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
826 for i := 0; i < l; i += 2 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
827 if isMerge(n.Content[i]) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
828 mergeNode = n.Content[i+1]
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
829 continue
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
830 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
831 k := reflect.New(kt).Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
832 if d.unmarshal(n.Content[i], k) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
833 if mergedFields != nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
834 ki := k.Interface()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
835 if mergedFields[ki] {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
836 continue
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
837 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
838 mergedFields[ki] = true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
839 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
840 kkind := k.Kind()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
841 if kkind == reflect.Interface {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
842 kkind = k.Elem().Kind()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
843 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
844 if kkind == reflect.Map || kkind == reflect.Slice {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
845 failf("invalid map key: %#v", k.Interface())
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
846 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
847 e := reflect.New(et).Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
848 if d.unmarshal(n.Content[i+1], e) || n.Content[i+1].ShortTag() == nullTag && (mapIsNew || !out.MapIndex(k).IsValid()) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
849 out.SetMapIndex(k, e)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
850 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
851 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
852 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
853
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
854 d.mergedFields = mergedFields
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
855 if mergeNode != nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
856 d.merge(n, mergeNode, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
857 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
858
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
859 d.stringMapType = stringMapType
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
860 d.generalMapType = generalMapType
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
861 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
862 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
863
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
864 func isStringMap(n *Node) bool {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
865 if n.Kind != MappingNode {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
866 return false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
867 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
868 l := len(n.Content)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
869 for i := 0; i < l; i += 2 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
870 shortTag := n.Content[i].ShortTag()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
871 if shortTag != strTag && shortTag != mergeTag {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
872 return false
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
873 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
874 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
875 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
876 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
877
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
878 func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
879 sinfo, err := getStructInfo(out.Type())
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
880 if err != nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
881 panic(err)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
882 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
883
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
884 var inlineMap reflect.Value
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
885 var elemType reflect.Type
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
886 if sinfo.InlineMap != -1 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
887 inlineMap = out.Field(sinfo.InlineMap)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
888 elemType = inlineMap.Type().Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
889 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
890
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
891 for _, index := range sinfo.InlineUnmarshalers {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
892 field := d.fieldByIndex(n, out, index)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
893 d.prepare(n, field)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
894 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
895
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
896 mergedFields := d.mergedFields
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
897 d.mergedFields = nil
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
898 var mergeNode *Node
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
899 var doneFields []bool
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
900 if d.uniqueKeys {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
901 doneFields = make([]bool, len(sinfo.FieldsList))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
902 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
903 name := settableValueOf("")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
904 l := len(n.Content)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
905 for i := 0; i < l; i += 2 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
906 ni := n.Content[i]
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
907 if isMerge(ni) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
908 mergeNode = n.Content[i+1]
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
909 continue
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
910 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
911 if !d.unmarshal(ni, name) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
912 continue
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
913 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
914 sname := name.String()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
915 if mergedFields != nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
916 if mergedFields[sname] {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
917 continue
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
918 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
919 mergedFields[sname] = true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
920 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
921 if info, ok := sinfo.FieldsMap[sname]; ok {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
922 if d.uniqueKeys {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
923 if doneFields[info.Id] {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
924 d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
925 continue
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
926 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
927 doneFields[info.Id] = true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
928 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
929 var field reflect.Value
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
930 if info.Inline == nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
931 field = out.Field(info.Num)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
932 } else {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
933 field = d.fieldByIndex(n, out, info.Inline)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
934 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
935 d.unmarshal(n.Content[i+1], field)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
936 } else if sinfo.InlineMap != -1 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
937 if inlineMap.IsNil() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
938 inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
939 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
940 value := reflect.New(elemType).Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
941 d.unmarshal(n.Content[i+1], value)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
942 inlineMap.SetMapIndex(name, value)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
943 } else if d.knownFields {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
944 d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
945 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
946 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
947
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
948 d.mergedFields = mergedFields
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
949 if mergeNode != nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
950 d.merge(n, mergeNode, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
951 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
952 return true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
953 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
954
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
955 func failWantMap() {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
956 failf("map merge requires map or sequence of maps as the value")
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
957 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
958
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
959 func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
960 mergedFields := d.mergedFields
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
961 if mergedFields == nil {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
962 d.mergedFields = make(map[interface{}]bool)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
963 for i := 0; i < len(parent.Content); i += 2 {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
964 k := reflect.New(ifaceType).Elem()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
965 if d.unmarshal(parent.Content[i], k) {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
966 d.mergedFields[k.Interface()] = true
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
967 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
968 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
969 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
970
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
971 switch merge.Kind {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
972 case MappingNode:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
973 d.unmarshal(merge, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
974 case AliasNode:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
975 if merge.Alias != nil && merge.Alias.Kind != MappingNode {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
976 failWantMap()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
977 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
978 d.unmarshal(merge, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
979 case SequenceNode:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
980 for i := 0; i < len(merge.Content); i++ {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
981 ni := merge.Content[i]
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
982 if ni.Kind == AliasNode {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
983 if ni.Alias != nil && ni.Alias.Kind != MappingNode {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
984 failWantMap()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
985 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
986 } else if ni.Kind != MappingNode {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
987 failWantMap()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
988 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
989 d.unmarshal(ni, out)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
990 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
991 default:
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
992 failWantMap()
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
993 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
994
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
995 d.mergedFields = mergedFields
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
996 }
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
997
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
998 func isMerge(n *Node) bool {
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
999 return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag)
d8727551f403 The Empress (III)
yakumo.izuru
parents:
diff changeset
1000 }