diff options
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression_ops.go')
-rw-r--r-- | vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression_ops.go | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression_ops.go b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression_ops.go new file mode 100644 index 0000000..9a5da04 --- /dev/null +++ b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression_ops.go | |||
@@ -0,0 +1,258 @@ | |||
1 | package hclsyntax | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | |||
6 | "github.com/hashicorp/hcl2/hcl" | ||
7 | "github.com/zclconf/go-cty/cty" | ||
8 | "github.com/zclconf/go-cty/cty/convert" | ||
9 | "github.com/zclconf/go-cty/cty/function" | ||
10 | "github.com/zclconf/go-cty/cty/function/stdlib" | ||
11 | ) | ||
12 | |||
13 | type Operation struct { | ||
14 | Impl function.Function | ||
15 | Type cty.Type | ||
16 | } | ||
17 | |||
18 | var ( | ||
19 | OpLogicalOr = &Operation{ | ||
20 | Impl: stdlib.OrFunc, | ||
21 | Type: cty.Bool, | ||
22 | } | ||
23 | OpLogicalAnd = &Operation{ | ||
24 | Impl: stdlib.AndFunc, | ||
25 | Type: cty.Bool, | ||
26 | } | ||
27 | OpLogicalNot = &Operation{ | ||
28 | Impl: stdlib.NotFunc, | ||
29 | Type: cty.Bool, | ||
30 | } | ||
31 | |||
32 | OpEqual = &Operation{ | ||
33 | Impl: stdlib.EqualFunc, | ||
34 | Type: cty.Bool, | ||
35 | } | ||
36 | OpNotEqual = &Operation{ | ||
37 | Impl: stdlib.NotEqualFunc, | ||
38 | Type: cty.Bool, | ||
39 | } | ||
40 | |||
41 | OpGreaterThan = &Operation{ | ||
42 | Impl: stdlib.GreaterThanFunc, | ||
43 | Type: cty.Bool, | ||
44 | } | ||
45 | OpGreaterThanOrEqual = &Operation{ | ||
46 | Impl: stdlib.GreaterThanOrEqualToFunc, | ||
47 | Type: cty.Bool, | ||
48 | } | ||
49 | OpLessThan = &Operation{ | ||
50 | Impl: stdlib.LessThanFunc, | ||
51 | Type: cty.Bool, | ||
52 | } | ||
53 | OpLessThanOrEqual = &Operation{ | ||
54 | Impl: stdlib.LessThanOrEqualToFunc, | ||
55 | Type: cty.Bool, | ||
56 | } | ||
57 | |||
58 | OpAdd = &Operation{ | ||
59 | Impl: stdlib.AddFunc, | ||
60 | Type: cty.Number, | ||
61 | } | ||
62 | OpSubtract = &Operation{ | ||
63 | Impl: stdlib.SubtractFunc, | ||
64 | Type: cty.Number, | ||
65 | } | ||
66 | OpMultiply = &Operation{ | ||
67 | Impl: stdlib.MultiplyFunc, | ||
68 | Type: cty.Number, | ||
69 | } | ||
70 | OpDivide = &Operation{ | ||
71 | Impl: stdlib.DivideFunc, | ||
72 | Type: cty.Number, | ||
73 | } | ||
74 | OpModulo = &Operation{ | ||
75 | Impl: stdlib.ModuloFunc, | ||
76 | Type: cty.Number, | ||
77 | } | ||
78 | OpNegate = &Operation{ | ||
79 | Impl: stdlib.NegateFunc, | ||
80 | Type: cty.Number, | ||
81 | } | ||
82 | ) | ||
83 | |||
84 | var binaryOps []map[TokenType]*Operation | ||
85 | |||
86 | func init() { | ||
87 | // This operation table maps from the operator's token type | ||
88 | // to the AST operation type. All expressions produced from | ||
89 | // binary operators are BinaryOp nodes. | ||
90 | // | ||
91 | // Binary operator groups are listed in order of precedence, with | ||
92 | // the *lowest* precedence first. Operators within the same group | ||
93 | // have left-to-right associativity. | ||
94 | binaryOps = []map[TokenType]*Operation{ | ||
95 | { | ||
96 | TokenOr: OpLogicalOr, | ||
97 | }, | ||
98 | { | ||
99 | TokenAnd: OpLogicalAnd, | ||
100 | }, | ||
101 | { | ||
102 | TokenEqualOp: OpEqual, | ||
103 | TokenNotEqual: OpNotEqual, | ||
104 | }, | ||
105 | { | ||
106 | TokenGreaterThan: OpGreaterThan, | ||
107 | TokenGreaterThanEq: OpGreaterThanOrEqual, | ||
108 | TokenLessThan: OpLessThan, | ||
109 | TokenLessThanEq: OpLessThanOrEqual, | ||
110 | }, | ||
111 | { | ||
112 | TokenPlus: OpAdd, | ||
113 | TokenMinus: OpSubtract, | ||
114 | }, | ||
115 | { | ||
116 | TokenStar: OpMultiply, | ||
117 | TokenSlash: OpDivide, | ||
118 | TokenPercent: OpModulo, | ||
119 | }, | ||
120 | } | ||
121 | } | ||
122 | |||
123 | type BinaryOpExpr struct { | ||
124 | LHS Expression | ||
125 | Op *Operation | ||
126 | RHS Expression | ||
127 | |||
128 | SrcRange hcl.Range | ||
129 | } | ||
130 | |||
131 | func (e *BinaryOpExpr) walkChildNodes(w internalWalkFunc) { | ||
132 | e.LHS = w(e.LHS).(Expression) | ||
133 | e.RHS = w(e.RHS).(Expression) | ||
134 | } | ||
135 | |||
136 | func (e *BinaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { | ||
137 | impl := e.Op.Impl // assumed to be a function taking exactly two arguments | ||
138 | params := impl.Params() | ||
139 | lhsParam := params[0] | ||
140 | rhsParam := params[1] | ||
141 | |||
142 | var diags hcl.Diagnostics | ||
143 | |||
144 | givenLHSVal, lhsDiags := e.LHS.Value(ctx) | ||
145 | givenRHSVal, rhsDiags := e.RHS.Value(ctx) | ||
146 | diags = append(diags, lhsDiags...) | ||
147 | diags = append(diags, rhsDiags...) | ||
148 | |||
149 | lhsVal, err := convert.Convert(givenLHSVal, lhsParam.Type) | ||
150 | if err != nil { | ||
151 | diags = append(diags, &hcl.Diagnostic{ | ||
152 | Severity: hcl.DiagError, | ||
153 | Summary: "Invalid operand", | ||
154 | Detail: fmt.Sprintf("Unsuitable value for left operand: %s.", err), | ||
155 | Subject: e.LHS.Range().Ptr(), | ||
156 | Context: &e.SrcRange, | ||
157 | }) | ||
158 | } | ||
159 | rhsVal, err := convert.Convert(givenRHSVal, rhsParam.Type) | ||
160 | if err != nil { | ||
161 | diags = append(diags, &hcl.Diagnostic{ | ||
162 | Severity: hcl.DiagError, | ||
163 | Summary: "Invalid operand", | ||
164 | Detail: fmt.Sprintf("Unsuitable value for right operand: %s.", err), | ||
165 | Subject: e.RHS.Range().Ptr(), | ||
166 | Context: &e.SrcRange, | ||
167 | }) | ||
168 | } | ||
169 | |||
170 | if diags.HasErrors() { | ||
171 | // Don't actually try the call if we have errors already, since the | ||
172 | // this will probably just produce a confusing duplicative diagnostic. | ||
173 | return cty.UnknownVal(e.Op.Type), diags | ||
174 | } | ||
175 | |||
176 | args := []cty.Value{lhsVal, rhsVal} | ||
177 | result, err := impl.Call(args) | ||
178 | if err != nil { | ||
179 | diags = append(diags, &hcl.Diagnostic{ | ||
180 | // FIXME: This diagnostic is useless. | ||
181 | Severity: hcl.DiagError, | ||
182 | Summary: "Operation failed", | ||
183 | Detail: fmt.Sprintf("Error during operation: %s.", err), | ||
184 | Subject: &e.SrcRange, | ||
185 | }) | ||
186 | return cty.UnknownVal(e.Op.Type), diags | ||
187 | } | ||
188 | |||
189 | return result, diags | ||
190 | } | ||
191 | |||
192 | func (e *BinaryOpExpr) Range() hcl.Range { | ||
193 | return e.SrcRange | ||
194 | } | ||
195 | |||
196 | func (e *BinaryOpExpr) StartRange() hcl.Range { | ||
197 | return e.LHS.StartRange() | ||
198 | } | ||
199 | |||
200 | type UnaryOpExpr struct { | ||
201 | Op *Operation | ||
202 | Val Expression | ||
203 | |||
204 | SrcRange hcl.Range | ||
205 | SymbolRange hcl.Range | ||
206 | } | ||
207 | |||
208 | func (e *UnaryOpExpr) walkChildNodes(w internalWalkFunc) { | ||
209 | e.Val = w(e.Val).(Expression) | ||
210 | } | ||
211 | |||
212 | func (e *UnaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { | ||
213 | impl := e.Op.Impl // assumed to be a function taking exactly one argument | ||
214 | params := impl.Params() | ||
215 | param := params[0] | ||
216 | |||
217 | givenVal, diags := e.Val.Value(ctx) | ||
218 | |||
219 | val, err := convert.Convert(givenVal, param.Type) | ||
220 | if err != nil { | ||
221 | diags = append(diags, &hcl.Diagnostic{ | ||
222 | Severity: hcl.DiagError, | ||
223 | Summary: "Invalid operand", | ||
224 | Detail: fmt.Sprintf("Unsuitable value for unary operand: %s.", err), | ||
225 | Subject: e.Val.Range().Ptr(), | ||
226 | Context: &e.SrcRange, | ||
227 | }) | ||
228 | } | ||
229 | |||
230 | if diags.HasErrors() { | ||
231 | // Don't actually try the call if we have errors already, since the | ||
232 | // this will probably just produce a confusing duplicative diagnostic. | ||
233 | return cty.UnknownVal(e.Op.Type), diags | ||
234 | } | ||
235 | |||
236 | args := []cty.Value{val} | ||
237 | result, err := impl.Call(args) | ||
238 | if err != nil { | ||
239 | diags = append(diags, &hcl.Diagnostic{ | ||
240 | // FIXME: This diagnostic is useless. | ||
241 | Severity: hcl.DiagError, | ||
242 | Summary: "Operation failed", | ||
243 | Detail: fmt.Sprintf("Error during operation: %s.", err), | ||
244 | Subject: &e.SrcRange, | ||
245 | }) | ||
246 | return cty.UnknownVal(e.Op.Type), diags | ||
247 | } | ||
248 | |||
249 | return result, diags | ||
250 | } | ||
251 | |||
252 | func (e *UnaryOpExpr) Range() hcl.Range { | ||
253 | return e.SrcRange | ||
254 | } | ||
255 | |||
256 | func (e *UnaryOpExpr) StartRange() hcl.Range { | ||
257 | return e.SymbolRange | ||
258 | } | ||