diff options
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression_template.go')
-rw-r--r-- | vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression_template.go | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression_template.go b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression_template.go new file mode 100644 index 0000000..a1c4727 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression_template.go | |||
@@ -0,0 +1,192 @@ | |||
1 | package hclsyntax | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "fmt" | ||
6 | |||
7 | "github.com/hashicorp/hcl2/hcl" | ||
8 | "github.com/zclconf/go-cty/cty" | ||
9 | "github.com/zclconf/go-cty/cty/convert" | ||
10 | ) | ||
11 | |||
12 | type TemplateExpr struct { | ||
13 | Parts []Expression | ||
14 | |||
15 | SrcRange hcl.Range | ||
16 | } | ||
17 | |||
18 | func (e *TemplateExpr) walkChildNodes(w internalWalkFunc) { | ||
19 | for i, part := range e.Parts { | ||
20 | e.Parts[i] = w(part).(Expression) | ||
21 | } | ||
22 | } | ||
23 | |||
24 | func (e *TemplateExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { | ||
25 | buf := &bytes.Buffer{} | ||
26 | var diags hcl.Diagnostics | ||
27 | isKnown := true | ||
28 | |||
29 | for _, part := range e.Parts { | ||
30 | partVal, partDiags := part.Value(ctx) | ||
31 | diags = append(diags, partDiags...) | ||
32 | |||
33 | if partVal.IsNull() { | ||
34 | diags = append(diags, &hcl.Diagnostic{ | ||
35 | Severity: hcl.DiagError, | ||
36 | Summary: "Invalid template interpolation value", | ||
37 | Detail: fmt.Sprintf( | ||
38 | "The expression result is null. Cannot include a null value in a string template.", | ||
39 | ), | ||
40 | Subject: part.Range().Ptr(), | ||
41 | Context: &e.SrcRange, | ||
42 | }) | ||
43 | continue | ||
44 | } | ||
45 | |||
46 | if !partVal.IsKnown() { | ||
47 | // If any part is unknown then the result as a whole must be | ||
48 | // unknown too. We'll keep on processing the rest of the parts | ||
49 | // anyway, because we want to still emit any diagnostics resulting | ||
50 | // from evaluating those. | ||
51 | isKnown = false | ||
52 | continue | ||
53 | } | ||
54 | |||
55 | strVal, err := convert.Convert(partVal, cty.String) | ||
56 | if err != nil { | ||
57 | diags = append(diags, &hcl.Diagnostic{ | ||
58 | Severity: hcl.DiagError, | ||
59 | Summary: "Invalid template interpolation value", | ||
60 | Detail: fmt.Sprintf( | ||
61 | "Cannot include the given value in a string template: %s.", | ||
62 | err.Error(), | ||
63 | ), | ||
64 | Subject: part.Range().Ptr(), | ||
65 | Context: &e.SrcRange, | ||
66 | }) | ||
67 | continue | ||
68 | } | ||
69 | |||
70 | buf.WriteString(strVal.AsString()) | ||
71 | } | ||
72 | |||
73 | if !isKnown { | ||
74 | return cty.UnknownVal(cty.String), diags | ||
75 | } | ||
76 | |||
77 | return cty.StringVal(buf.String()), diags | ||
78 | } | ||
79 | |||
80 | func (e *TemplateExpr) Range() hcl.Range { | ||
81 | return e.SrcRange | ||
82 | } | ||
83 | |||
84 | func (e *TemplateExpr) StartRange() hcl.Range { | ||
85 | return e.Parts[0].StartRange() | ||
86 | } | ||
87 | |||
88 | // TemplateJoinExpr is used to convert tuples of strings produced by template | ||
89 | // constructs (i.e. for loops) into flat strings, by converting the values | ||
90 | // tos strings and joining them. This AST node is not used directly; it's | ||
91 | // produced as part of the AST of a "for" loop in a template. | ||
92 | type TemplateJoinExpr struct { | ||
93 | Tuple Expression | ||
94 | } | ||
95 | |||
96 | func (e *TemplateJoinExpr) walkChildNodes(w internalWalkFunc) { | ||
97 | e.Tuple = w(e.Tuple).(Expression) | ||
98 | } | ||
99 | |||
100 | func (e *TemplateJoinExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { | ||
101 | tuple, diags := e.Tuple.Value(ctx) | ||
102 | |||
103 | if tuple.IsNull() { | ||
104 | // This indicates a bug in the code that constructed the AST. | ||
105 | panic("TemplateJoinExpr got null tuple") | ||
106 | } | ||
107 | if tuple.Type() == cty.DynamicPseudoType { | ||
108 | return cty.UnknownVal(cty.String), diags | ||
109 | } | ||
110 | if !tuple.Type().IsTupleType() { | ||
111 | // This indicates a bug in the code that constructed the AST. | ||
112 | panic("TemplateJoinExpr got non-tuple tuple") | ||
113 | } | ||
114 | if !tuple.IsKnown() { | ||
115 | return cty.UnknownVal(cty.String), diags | ||
116 | } | ||
117 | |||
118 | buf := &bytes.Buffer{} | ||
119 | it := tuple.ElementIterator() | ||
120 | for it.Next() { | ||
121 | _, val := it.Element() | ||
122 | |||
123 | if val.IsNull() { | ||
124 | diags = append(diags, &hcl.Diagnostic{ | ||
125 | Severity: hcl.DiagError, | ||
126 | Summary: "Invalid template interpolation value", | ||
127 | Detail: fmt.Sprintf( | ||
128 | "An iteration result is null. Cannot include a null value in a string template.", | ||
129 | ), | ||
130 | Subject: e.Range().Ptr(), | ||
131 | }) | ||
132 | continue | ||
133 | } | ||
134 | if val.Type() == cty.DynamicPseudoType { | ||
135 | return cty.UnknownVal(cty.String), diags | ||
136 | } | ||
137 | strVal, err := convert.Convert(val, cty.String) | ||
138 | if err != nil { | ||
139 | diags = append(diags, &hcl.Diagnostic{ | ||
140 | Severity: hcl.DiagError, | ||
141 | Summary: "Invalid template interpolation value", | ||
142 | Detail: fmt.Sprintf( | ||
143 | "Cannot include one of the interpolation results into the string template: %s.", | ||
144 | err.Error(), | ||
145 | ), | ||
146 | Subject: e.Range().Ptr(), | ||
147 | }) | ||
148 | continue | ||
149 | } | ||
150 | if !val.IsKnown() { | ||
151 | return cty.UnknownVal(cty.String), diags | ||
152 | } | ||
153 | |||
154 | buf.WriteString(strVal.AsString()) | ||
155 | } | ||
156 | |||
157 | return cty.StringVal(buf.String()), diags | ||
158 | } | ||
159 | |||
160 | func (e *TemplateJoinExpr) Range() hcl.Range { | ||
161 | return e.Tuple.Range() | ||
162 | } | ||
163 | |||
164 | func (e *TemplateJoinExpr) StartRange() hcl.Range { | ||
165 | return e.Tuple.StartRange() | ||
166 | } | ||
167 | |||
168 | // TemplateWrapExpr is used instead of a TemplateExpr when a template | ||
169 | // consists _only_ of a single interpolation sequence. In that case, the | ||
170 | // template's result is the single interpolation's result, verbatim with | ||
171 | // no type conversions. | ||
172 | type TemplateWrapExpr struct { | ||
173 | Wrapped Expression | ||
174 | |||
175 | SrcRange hcl.Range | ||
176 | } | ||
177 | |||
178 | func (e *TemplateWrapExpr) walkChildNodes(w internalWalkFunc) { | ||
179 | e.Wrapped = w(e.Wrapped).(Expression) | ||
180 | } | ||
181 | |||
182 | func (e *TemplateWrapExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { | ||
183 | return e.Wrapped.Value(ctx) | ||
184 | } | ||
185 | |||
186 | func (e *TemplateWrapExpr) Range() hcl.Range { | ||
187 | return e.SrcRange | ||
188 | } | ||
189 | |||
190 | func (e *TemplateWrapExpr) StartRange() hcl.Range { | ||
191 | return e.SrcRange | ||
192 | } | ||