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