aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/zclconf/go-cty-yaml/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/zclconf/go-cty-yaml/decode.go')
-rw-r--r--vendor/github.com/zclconf/go-cty-yaml/decode.go261
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 @@
1package yaml
2
3import (
4 "errors"
5 "fmt"
6
7 "github.com/zclconf/go-cty/cty"
8 "github.com/zclconf/go-cty/cty/convert"
9)
10
11func (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
65func (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
73func (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
94func (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
119func (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
189func (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
224func (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
232type valueAnalysis struct {
233 anchorsPending map[string]int
234 anchorVals map[string]cty.Value
235}
236
237func (an *valueAnalysis) beginAnchor(name string) {
238 an.anchorsPending[name]++
239}
240
241func (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
249func (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}