diff options
Diffstat (limited to 'vendor/github.com/zclconf/go-cty-yaml/decode.go')
-rw-r--r-- | vendor/github.com/zclconf/go-cty-yaml/decode.go | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/vendor/github.com/zclconf/go-cty-yaml/decode.go b/vendor/github.com/zclconf/go-cty-yaml/decode.go new file mode 100644 index 0000000..e369ff2 --- /dev/null +++ b/vendor/github.com/zclconf/go-cty-yaml/decode.go | |||
@@ -0,0 +1,261 @@ | |||
1 | package yaml | ||
2 | |||
3 | import ( | ||
4 | "errors" | ||
5 | "fmt" | ||
6 | |||
7 | "github.com/zclconf/go-cty/cty" | ||
8 | "github.com/zclconf/go-cty/cty/convert" | ||
9 | ) | ||
10 | |||
11 | func (c *Converter) unmarshal(src []byte, ty cty.Type) (cty.Value, error) { | ||
12 | p := &yaml_parser_t{} | ||
13 | if !yaml_parser_initialize(p) { | ||
14 | return cty.NilVal, errors.New("failed to initialize YAML parser") | ||
15 | } | ||
16 | if len(src) == 0 { | ||
17 | src = []byte{'\n'} | ||
18 | } | ||
19 | |||
20 | an := &valueAnalysis{ | ||
21 | anchorsPending: map[string]int{}, | ||
22 | anchorVals: map[string]cty.Value{}, | ||
23 | } | ||
24 | |||
25 | yaml_parser_set_input_string(p, src) | ||
26 | |||
27 | var evt yaml_event_t | ||
28 | if !yaml_parser_parse(p, &evt) { | ||
29 | return cty.NilVal, parserError(p) | ||
30 | } | ||
31 | if evt.typ != yaml_STREAM_START_EVENT { | ||
32 | return cty.NilVal, parseEventErrorf(&evt, "missing stream start token") | ||
33 | } | ||
34 | if !yaml_parser_parse(p, &evt) { | ||
35 | return cty.NilVal, parserError(p) | ||
36 | } | ||
37 | if evt.typ != yaml_DOCUMENT_START_EVENT { | ||
38 | return cty.NilVal, parseEventErrorf(&evt, "missing start of document") | ||
39 | } | ||
40 | |||
41 | v, err := c.unmarshalParse(an, p) | ||
42 | if err != nil { | ||
43 | return cty.NilVal, err | ||
44 | } | ||
45 | |||
46 | if !yaml_parser_parse(p, &evt) { | ||
47 | return cty.NilVal, parserError(p) | ||
48 | } | ||
49 | if evt.typ == yaml_DOCUMENT_START_EVENT { | ||
50 | return cty.NilVal, parseEventErrorf(&evt, "only a single document is allowed") | ||
51 | } | ||
52 | if evt.typ != yaml_DOCUMENT_END_EVENT { | ||
53 | return cty.NilVal, parseEventErrorf(&evt, "unexpected extra content (%s) after value", evt.typ.String()) | ||
54 | } | ||
55 | if !yaml_parser_parse(p, &evt) { | ||
56 | return cty.NilVal, parserError(p) | ||
57 | } | ||
58 | if evt.typ != yaml_STREAM_END_EVENT { | ||
59 | return cty.NilVal, parseEventErrorf(&evt, "unexpected extra content after value") | ||
60 | } | ||
61 | |||
62 | return convert.Convert(v, ty) | ||
63 | } | ||
64 | |||
65 | func (c *Converter) unmarshalParse(an *valueAnalysis, p *yaml_parser_t) (cty.Value, error) { | ||
66 | var evt yaml_event_t | ||
67 | if !yaml_parser_parse(p, &evt) { | ||
68 | return cty.NilVal, parserError(p) | ||
69 | } | ||
70 | return c.unmarshalParseRemainder(an, &evt, p) | ||
71 | } | ||
72 | |||
73 | func (c *Converter) unmarshalParseRemainder(an *valueAnalysis, evt *yaml_event_t, p *yaml_parser_t) (cty.Value, error) { | ||
74 | switch evt.typ { | ||
75 | case yaml_SCALAR_EVENT: | ||
76 | return c.unmarshalScalar(an, evt, p) | ||
77 | case yaml_ALIAS_EVENT: | ||
78 | return c.unmarshalAlias(an, evt, p) | ||
79 | case yaml_MAPPING_START_EVENT: | ||
80 | return c.unmarshalMapping(an, evt, p) | ||
81 | case yaml_SEQUENCE_START_EVENT: | ||
82 | return c.unmarshalSequence(an, evt, p) | ||
83 | case yaml_DOCUMENT_START_EVENT: | ||
84 | return cty.NilVal, parseEventErrorf(evt, "only a single document is allowed") | ||
85 | case yaml_STREAM_END_EVENT: | ||
86 | // Decoding an empty buffer, probably | ||
87 | return cty.NilVal, parseEventErrorf(evt, "expecting value but found end of stream") | ||
88 | default: | ||
89 | // Should never happen; the above should be comprehensive | ||
90 | return cty.NilVal, parseEventErrorf(evt, "unexpected parser event %s", evt.typ.String()) | ||
91 | } | ||
92 | } | ||
93 | |||
94 | func (c *Converter) unmarshalScalar(an *valueAnalysis, evt *yaml_event_t, p *yaml_parser_t) (cty.Value, error) { | ||
95 | src := evt.value | ||
96 | tag := string(evt.tag) | ||
97 | anchor := string(evt.anchor) | ||
98 | |||
99 | if len(anchor) > 0 { | ||
100 | an.beginAnchor(anchor) | ||
101 | } | ||
102 | |||
103 | val, err := c.resolveScalar(tag, string(src), yaml_scalar_style_t(evt.style)) | ||
104 | if err != nil { | ||
105 | return cty.NilVal, parseEventErrorWrap(evt, err) | ||
106 | } | ||
107 | |||
108 | if val.RawEquals(mergeMappingVal) { | ||
109 | // In any context other than a mapping key, this is just a plain string | ||
110 | val = cty.StringVal("<<") | ||
111 | } | ||
112 | |||
113 | if len(anchor) > 0 { | ||
114 | an.completeAnchor(anchor, val) | ||
115 | } | ||
116 | return val, nil | ||
117 | } | ||
118 | |||
119 | func (c *Converter) unmarshalMapping(an *valueAnalysis, evt *yaml_event_t, p *yaml_parser_t) (cty.Value, error) { | ||
120 | tag := string(evt.tag) | ||
121 | anchor := string(evt.anchor) | ||
122 | |||
123 | if tag != "" && tag != yaml_MAP_TAG { | ||
124 | return cty.NilVal, parseEventErrorf(evt, "can't interpret mapping as %s", tag) | ||
125 | } | ||
126 | |||
127 | if anchor != "" { | ||
128 | an.beginAnchor(anchor) | ||
129 | } | ||
130 | |||
131 | vals := make(map[string]cty.Value) | ||
132 | for { | ||
133 | var nextEvt yaml_event_t | ||
134 | if !yaml_parser_parse(p, &nextEvt) { | ||
135 | return cty.NilVal, parserError(p) | ||
136 | } | ||
137 | if nextEvt.typ == yaml_MAPPING_END_EVENT { | ||
138 | v := cty.ObjectVal(vals) | ||
139 | if anchor != "" { | ||
140 | an.completeAnchor(anchor, v) | ||
141 | } | ||
142 | return v, nil | ||
143 | } | ||
144 | |||
145 | if nextEvt.typ != yaml_SCALAR_EVENT { | ||
146 | return cty.NilVal, parseEventErrorf(&nextEvt, "only strings are allowed as mapping keys") | ||
147 | } | ||
148 | keyVal, err := c.resolveScalar(string(nextEvt.tag), string(nextEvt.value), yaml_scalar_style_t(nextEvt.style)) | ||
149 | if err != nil { | ||
150 | return cty.NilVal, err | ||
151 | } | ||
152 | if keyVal.RawEquals(mergeMappingVal) { | ||
153 | // Merging the value (which must be a mapping) into our mapping, | ||
154 | // then. | ||
155 | val, err := c.unmarshalParse(an, p) | ||
156 | if err != nil { | ||
157 | return cty.NilVal, err | ||
158 | } | ||
159 | ty := val.Type() | ||
160 | if !(ty.IsObjectType() || ty.IsMapType()) { | ||
161 | return cty.NilVal, parseEventErrorf(&nextEvt, "cannot merge %s into mapping", ty.FriendlyName()) | ||
162 | } | ||
163 | for it := val.ElementIterator(); it.Next(); { | ||
164 | k, v := it.Element() | ||
165 | vals[k.AsString()] = v | ||
166 | } | ||
167 | continue | ||
168 | } | ||
169 | if keyValStr, err := convert.Convert(keyVal, cty.String); err == nil { | ||
170 | keyVal = keyValStr | ||
171 | } else { | ||
172 | return cty.NilVal, parseEventErrorf(&nextEvt, "only strings are allowed as mapping keys") | ||
173 | } | ||
174 | if keyVal.IsNull() { | ||
175 | return cty.NilVal, parseEventErrorf(&nextEvt, "mapping key cannot be null") | ||
176 | } | ||
177 | if !keyVal.IsKnown() { | ||
178 | return cty.NilVal, parseEventErrorf(&nextEvt, "mapping key must be known") | ||
179 | } | ||
180 | val, err := c.unmarshalParse(an, p) | ||
181 | if err != nil { | ||
182 | return cty.NilVal, err | ||
183 | } | ||
184 | |||
185 | vals[keyVal.AsString()] = val | ||
186 | } | ||
187 | } | ||
188 | |||
189 | func (c *Converter) unmarshalSequence(an *valueAnalysis, evt *yaml_event_t, p *yaml_parser_t) (cty.Value, error) { | ||
190 | tag := string(evt.tag) | ||
191 | anchor := string(evt.anchor) | ||
192 | |||
193 | if tag != "" && tag != yaml_SEQ_TAG { | ||
194 | return cty.NilVal, parseEventErrorf(evt, "can't interpret sequence as %s", tag) | ||
195 | } | ||
196 | |||
197 | if anchor != "" { | ||
198 | an.beginAnchor(anchor) | ||
199 | } | ||
200 | |||
201 | var vals []cty.Value | ||
202 | for { | ||
203 | var nextEvt yaml_event_t | ||
204 | if !yaml_parser_parse(p, &nextEvt) { | ||
205 | return cty.NilVal, parserError(p) | ||
206 | } | ||
207 | if nextEvt.typ == yaml_SEQUENCE_END_EVENT { | ||
208 | ty := cty.TupleVal(vals) | ||
209 | if anchor != "" { | ||
210 | an.completeAnchor(anchor, ty) | ||
211 | } | ||
212 | return ty, nil | ||
213 | } | ||
214 | |||
215 | val, err := c.unmarshalParseRemainder(an, &nextEvt, p) | ||
216 | if err != nil { | ||
217 | return cty.NilVal, err | ||
218 | } | ||
219 | |||
220 | vals = append(vals, val) | ||
221 | } | ||
222 | } | ||
223 | |||
224 | func (c *Converter) unmarshalAlias(an *valueAnalysis, evt *yaml_event_t, p *yaml_parser_t) (cty.Value, error) { | ||
225 | v, err := an.anchorVal(string(evt.anchor)) | ||
226 | if err != nil { | ||
227 | err = parseEventErrorWrap(evt, err) | ||
228 | } | ||
229 | return v, err | ||
230 | } | ||
231 | |||
232 | type valueAnalysis struct { | ||
233 | anchorsPending map[string]int | ||
234 | anchorVals map[string]cty.Value | ||
235 | } | ||
236 | |||
237 | func (an *valueAnalysis) beginAnchor(name string) { | ||
238 | an.anchorsPending[name]++ | ||
239 | } | ||
240 | |||
241 | func (an *valueAnalysis) completeAnchor(name string, v cty.Value) { | ||
242 | an.anchorsPending[name]-- | ||
243 | if an.anchorsPending[name] == 0 { | ||
244 | delete(an.anchorsPending, name) | ||
245 | } | ||
246 | an.anchorVals[name] = v | ||
247 | } | ||
248 | |||
249 | func (an *valueAnalysis) anchorVal(name string) (cty.Value, error) { | ||
250 | if _, pending := an.anchorsPending[name]; pending { | ||
251 | // YAML normally allows self-referencing structures, but cty cannot | ||
252 | // represent them (it requires all structures to be finite) so we | ||
253 | // must fail here. | ||
254 | return cty.NilVal, fmt.Errorf("cannot refer to anchor %q from inside its own definition", name) | ||
255 | } | ||
256 | ty, ok := an.anchorVals[name] | ||
257 | if !ok { | ||
258 | return cty.NilVal, fmt.Errorf("reference to undefined anchor %q", name) | ||
259 | } | ||
260 | return ty, nil | ||
261 | } | ||