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"
13 type Operation struct {
14 Impl function.Function
19 OpLogicalOr = &Operation{
23 OpLogicalAnd = &Operation{
27 OpLogicalNot = &Operation{
33 Impl: stdlib.EqualFunc,
36 OpNotEqual = &Operation{
37 Impl: stdlib.NotEqualFunc,
41 OpGreaterThan = &Operation{
42 Impl: stdlib.GreaterThanFunc,
45 OpGreaterThanOrEqual = &Operation{
46 Impl: stdlib.GreaterThanOrEqualToFunc,
49 OpLessThan = &Operation{
50 Impl: stdlib.LessThanFunc,
53 OpLessThanOrEqual = &Operation{
54 Impl: stdlib.LessThanOrEqualToFunc,
62 OpSubtract = &Operation{
63 Impl: stdlib.SubtractFunc,
66 OpMultiply = &Operation{
67 Impl: stdlib.MultiplyFunc,
70 OpDivide = &Operation{
71 Impl: stdlib.DivideFunc,
74 OpModulo = &Operation{
75 Impl: stdlib.ModuloFunc,
78 OpNegate = &Operation{
79 Impl: stdlib.NegateFunc,
84 var binaryOps []map[TokenType]*Operation
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.
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{
99 TokenAnd: OpLogicalAnd,
102 TokenEqualOp: OpEqual,
103 TokenNotEqual: OpNotEqual,
106 TokenGreaterThan: OpGreaterThan,
107 TokenGreaterThanEq: OpGreaterThanOrEqual,
108 TokenLessThan: OpLessThan,
109 TokenLessThanEq: OpLessThanOrEqual,
113 TokenMinus: OpSubtract,
116 TokenStar: OpMultiply,
117 TokenSlash: OpDivide,
118 TokenPercent: OpModulo,
123 type BinaryOpExpr struct {
131 func (e *BinaryOpExpr) walkChildNodes(w internalWalkFunc) {
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]
142 var diags hcl.Diagnostics
144 givenLHSVal, lhsDiags := e.LHS.Value(ctx)
145 givenRHSVal, rhsDiags := e.RHS.Value(ctx)
146 diags = append(diags, lhsDiags...)
147 diags = append(diags, rhsDiags...)
149 lhsVal, err := convert.Convert(givenLHSVal, lhsParam.Type)
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,
161 rhsVal, err := convert.Convert(givenRHSVal, rhsParam.Type)
163 diags = append(diags, &hcl.Diagnostic{
164 Severity: hcl.DiagError,
165 Summary: "Invalid operand",
166 Detail: fmt.Sprintf("Unsuitable value for right operand: %s.", err),
167 Subject: e.RHS.Range().Ptr(),
168 Context: &e.SrcRange,
174 if diags.HasErrors() {
175 // Don't actually try the call if we have errors already, since the
176 // this will probably just produce a confusing duplicative diagnostic.
177 return cty.UnknownVal(e.Op.Type), diags
180 args := []cty.Value{lhsVal, rhsVal}
181 result, err := impl.Call(args)
183 diags = append(diags, &hcl.Diagnostic{
184 // FIXME: This diagnostic is useless.
185 Severity: hcl.DiagError,
186 Summary: "Operation failed",
187 Detail: fmt.Sprintf("Error during operation: %s.", err),
188 Subject: &e.SrcRange,
192 return cty.UnknownVal(e.Op.Type), diags
198 func (e *BinaryOpExpr) Range() hcl.Range {
202 func (e *BinaryOpExpr) StartRange() hcl.Range {
203 return e.LHS.StartRange()
206 type UnaryOpExpr struct {
211 SymbolRange hcl.Range
214 func (e *UnaryOpExpr) walkChildNodes(w internalWalkFunc) {
218 func (e *UnaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
219 impl := e.Op.Impl // assumed to be a function taking exactly one argument
220 params := impl.Params()
223 givenVal, diags := e.Val.Value(ctx)
225 val, err := convert.Convert(givenVal, param.Type)
227 diags = append(diags, &hcl.Diagnostic{
228 Severity: hcl.DiagError,
229 Summary: "Invalid operand",
230 Detail: fmt.Sprintf("Unsuitable value for unary operand: %s.", err),
231 Subject: e.Val.Range().Ptr(),
232 Context: &e.SrcRange,
238 if diags.HasErrors() {
239 // Don't actually try the call if we have errors already, since the
240 // this will probably just produce a confusing duplicative diagnostic.
241 return cty.UnknownVal(e.Op.Type), diags
244 args := []cty.Value{val}
245 result, err := impl.Call(args)
247 diags = append(diags, &hcl.Diagnostic{
248 // FIXME: This diagnostic is useless.
249 Severity: hcl.DiagError,
250 Summary: "Operation failed",
251 Detail: fmt.Sprintf("Error during operation: %s.", err),
252 Subject: &e.SrcRange,
256 return cty.UnknownVal(e.Op.Type), diags
262 func (e *UnaryOpExpr) Range() hcl.Range {
266 func (e *UnaryOpExpr) StartRange() hcl.Range {