aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression.go')
-rw-r--r--vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression.go1275
1 files changed, 1275 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression.go b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression.go
new file mode 100644
index 0000000..cfc7cd9
--- /dev/null
+++ b/vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression.go
@@ -0,0 +1,1275 @@
1package hclsyntax
2
3import (
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)
11
12// Expression is the abstract type for nodes that behave as HCL expressions.
13type Expression interface {
14 Node
15
16 // The hcl.Expression methods are duplicated here, rather than simply
17 // embedded, because both Node and hcl.Expression have a Range method
18 // and so they conflict.
19
20 Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics)
21 Variables() []hcl.Traversal
22 StartRange() hcl.Range
23}
24
25// Assert that Expression implements hcl.Expression
26var assertExprImplExpr hcl.Expression = Expression(nil)
27
28// LiteralValueExpr is an expression that just always returns a given value.
29type LiteralValueExpr struct {
30 Val cty.Value
31 SrcRange hcl.Range
32}
33
34func (e *LiteralValueExpr) walkChildNodes(w internalWalkFunc) {
35 // Literal values have no child nodes
36}
37
38func (e *LiteralValueExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
39 return e.Val, nil
40}
41
42func (e *LiteralValueExpr) Range() hcl.Range {
43 return e.SrcRange
44}
45
46func (e *LiteralValueExpr) StartRange() hcl.Range {
47 return e.SrcRange
48}
49
50// Implementation for hcl.AbsTraversalForExpr.
51func (e *LiteralValueExpr) AsTraversal() hcl.Traversal {
52 // This one's a little weird: the contract for AsTraversal is to interpret
53 // an expression as if it were traversal syntax, and traversal syntax
54 // doesn't have the special keywords "null", "true", and "false" so these
55 // are expected to be treated like variables in that case.
56 // Since our parser already turned them into LiteralValueExpr by the time
57 // we get here, we need to undo this and infer the name that would've
58 // originally led to our value.
59 // We don't do anything for any other values, since they don't overlap
60 // with traversal roots.
61
62 if e.Val.IsNull() {
63 // In practice the parser only generates null values of the dynamic
64 // pseudo-type for literals, so we can safely assume that any null
65 // was orignally the keyword "null".
66 return hcl.Traversal{
67 hcl.TraverseRoot{
68 Name: "null",
69 SrcRange: e.SrcRange,
70 },
71 }
72 }
73
74 switch e.Val {
75 case cty.True:
76 return hcl.Traversal{
77 hcl.TraverseRoot{
78 Name: "true",
79 SrcRange: e.SrcRange,
80 },
81 }
82 case cty.False:
83 return hcl.Traversal{
84 hcl.TraverseRoot{
85 Name: "false",
86 SrcRange: e.SrcRange,
87 },
88 }
89 default:
90 // No traversal is possible for any other value.
91 return nil
92 }
93}
94
95// ScopeTraversalExpr is an Expression that retrieves a value from the scope
96// using a traversal.
97type ScopeTraversalExpr struct {
98 Traversal hcl.Traversal
99 SrcRange hcl.Range
100}
101
102func (e *ScopeTraversalExpr) walkChildNodes(w internalWalkFunc) {
103 // Scope traversals have no child nodes
104}
105
106func (e *ScopeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
107 return e.Traversal.TraverseAbs(ctx)
108}
109
110func (e *ScopeTraversalExpr) Range() hcl.Range {
111 return e.SrcRange
112}
113
114func (e *ScopeTraversalExpr) StartRange() hcl.Range {
115 return e.SrcRange
116}
117
118// Implementation for hcl.AbsTraversalForExpr.
119func (e *ScopeTraversalExpr) AsTraversal() hcl.Traversal {
120 return e.Traversal
121}
122
123// RelativeTraversalExpr is an Expression that retrieves a value from another
124// value using a _relative_ traversal.
125type RelativeTraversalExpr struct {
126 Source Expression
127 Traversal hcl.Traversal
128 SrcRange hcl.Range
129}
130
131func (e *RelativeTraversalExpr) walkChildNodes(w internalWalkFunc) {
132 // Scope traversals have no child nodes
133}
134
135func (e *RelativeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
136 src, diags := e.Source.Value(ctx)
137 ret, travDiags := e.Traversal.TraverseRel(src)
138 diags = append(diags, travDiags...)
139 return ret, diags
140}
141
142func (e *RelativeTraversalExpr) Range() hcl.Range {
143 return e.SrcRange
144}
145
146func (e *RelativeTraversalExpr) StartRange() hcl.Range {
147 return e.SrcRange
148}
149
150// Implementation for hcl.AbsTraversalForExpr.
151func (e *RelativeTraversalExpr) AsTraversal() hcl.Traversal {
152 // We can produce a traversal only if our source can.
153 st, diags := hcl.AbsTraversalForExpr(e.Source)
154 if diags.HasErrors() {
155 return nil
156 }
157
158 ret := make(hcl.Traversal, len(st)+len(e.Traversal))
159 copy(ret, st)
160 copy(ret[len(st):], e.Traversal)
161 return ret
162}
163
164// FunctionCallExpr is an Expression that calls a function from the EvalContext
165// and returns its result.
166type FunctionCallExpr struct {
167 Name string
168 Args []Expression
169
170 // If true, the final argument should be a tuple, list or set which will
171 // expand to be one argument per element.
172 ExpandFinal bool
173
174 NameRange hcl.Range
175 OpenParenRange hcl.Range
176 CloseParenRange hcl.Range
177}
178
179func (e *FunctionCallExpr) walkChildNodes(w internalWalkFunc) {
180 for i, arg := range e.Args {
181 e.Args[i] = w(arg).(Expression)
182 }
183}
184
185func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
186 var diags hcl.Diagnostics
187
188 var f function.Function
189 exists := false
190 hasNonNilMap := false
191 thisCtx := ctx
192 for thisCtx != nil {
193 if thisCtx.Functions == nil {
194 thisCtx = thisCtx.Parent()
195 continue
196 }
197 hasNonNilMap = true
198 f, exists = thisCtx.Functions[e.Name]
199 if exists {
200 break
201 }
202 thisCtx = thisCtx.Parent()
203 }
204
205 if !exists {
206 if !hasNonNilMap {
207 return cty.DynamicVal, hcl.Diagnostics{
208 {
209 Severity: hcl.DiagError,
210 Summary: "Function calls not allowed",
211 Detail: "Functions may not be called here.",
212 Subject: e.Range().Ptr(),
213 },
214 }
215 }
216
217 avail := make([]string, 0, len(ctx.Functions))
218 for name := range ctx.Functions {
219 avail = append(avail, name)
220 }
221 suggestion := nameSuggestion(e.Name, avail)
222 if suggestion != "" {
223 suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
224 }
225
226 return cty.DynamicVal, hcl.Diagnostics{
227 {
228 Severity: hcl.DiagError,
229 Summary: "Call to unknown function",
230 Detail: fmt.Sprintf("There is no function named %q.%s", e.Name, suggestion),
231 Subject: &e.NameRange,
232 Context: e.Range().Ptr(),
233 },
234 }
235 }
236
237 params := f.Params()
238 varParam := f.VarParam()
239
240 args := e.Args
241 if e.ExpandFinal {
242 if len(args) < 1 {
243 // should never happen if the parser is behaving
244 panic("ExpandFinal set on function call with no arguments")
245 }
246 expandExpr := args[len(args)-1]
247 expandVal, expandDiags := expandExpr.Value(ctx)
248 diags = append(diags, expandDiags...)
249 if expandDiags.HasErrors() {
250 return cty.DynamicVal, diags
251 }
252
253 switch {
254 case expandVal.Type().IsTupleType() || expandVal.Type().IsListType() || expandVal.Type().IsSetType():
255 if expandVal.IsNull() {
256 diags = append(diags, &hcl.Diagnostic{
257 Severity: hcl.DiagError,
258 Summary: "Invalid expanding argument value",
259 Detail: "The expanding argument (indicated by ...) must not be null.",
260 Context: expandExpr.Range().Ptr(),
261 Subject: e.Range().Ptr(),
262 })
263 return cty.DynamicVal, diags
264 }
265 if !expandVal.IsKnown() {
266 return cty.DynamicVal, diags
267 }
268
269 newArgs := make([]Expression, 0, (len(args)-1)+expandVal.LengthInt())
270 newArgs = append(newArgs, args[:len(args)-1]...)
271 it := expandVal.ElementIterator()
272 for it.Next() {
273 _, val := it.Element()
274 newArgs = append(newArgs, &LiteralValueExpr{
275 Val: val,
276 SrcRange: expandExpr.Range(),
277 })
278 }
279 args = newArgs
280 default:
281 diags = append(diags, &hcl.Diagnostic{
282 Severity: hcl.DiagError,
283 Summary: "Invalid expanding argument value",
284 Detail: "The expanding argument (indicated by ...) must be of a tuple, list, or set type.",
285 Context: expandExpr.Range().Ptr(),
286 Subject: e.Range().Ptr(),
287 })
288 return cty.DynamicVal, diags
289 }
290 }
291
292 if len(args) < len(params) {
293 missing := params[len(args)]
294 qual := ""
295 if varParam != nil {
296 qual = " at least"
297 }
298 return cty.DynamicVal, hcl.Diagnostics{
299 {
300 Severity: hcl.DiagError,
301 Summary: "Not enough function arguments",
302 Detail: fmt.Sprintf(
303 "Function %q expects%s %d argument(s). Missing value for %q.",
304 e.Name, qual, len(params), missing.Name,
305 ),
306 Subject: &e.CloseParenRange,
307 Context: e.Range().Ptr(),
308 },
309 }
310 }
311
312 if varParam == nil && len(args) > len(params) {
313 return cty.DynamicVal, hcl.Diagnostics{
314 {
315 Severity: hcl.DiagError,
316 Summary: "Too many function arguments",
317 Detail: fmt.Sprintf(
318 "Function %q expects only %d argument(s).",
319 e.Name, len(params),
320 ),
321 Subject: args[len(params)].StartRange().Ptr(),
322 Context: e.Range().Ptr(),
323 },
324 }
325 }
326
327 argVals := make([]cty.Value, len(args))
328
329 for i, argExpr := range args {
330 var param *function.Parameter
331 if i < len(params) {
332 param = &params[i]
333 } else {
334 param = varParam
335 }
336
337 val, argDiags := argExpr.Value(ctx)
338 if len(argDiags) > 0 {
339 diags = append(diags, argDiags...)
340 }
341
342 // Try to convert our value to the parameter type
343 val, err := convert.Convert(val, param.Type)
344 if err != nil {
345 diags = append(diags, &hcl.Diagnostic{
346 Severity: hcl.DiagError,
347 Summary: "Invalid function argument",
348 Detail: fmt.Sprintf(
349 "Invalid value for %q parameter: %s.",
350 param.Name, err,
351 ),
352 Subject: argExpr.StartRange().Ptr(),
353 Context: e.Range().Ptr(),
354 })
355 }
356
357 argVals[i] = val
358 }
359
360 if diags.HasErrors() {
361 // Don't try to execute the function if we already have errors with
362 // the arguments, because the result will probably be a confusing
363 // error message.
364 return cty.DynamicVal, diags
365 }
366
367 resultVal, err := f.Call(argVals)
368 if err != nil {
369 switch terr := err.(type) {
370 case function.ArgError:
371 i := terr.Index
372 var param *function.Parameter
373 if i < len(params) {
374 param = &params[i]
375 } else {
376 param = varParam
377 }
378 argExpr := e.Args[i]
379
380 // TODO: we should also unpick a PathError here and show the
381 // path to the deep value where the error was detected.
382 diags = append(diags, &hcl.Diagnostic{
383 Severity: hcl.DiagError,
384 Summary: "Invalid function argument",
385 Detail: fmt.Sprintf(
386 "Invalid value for %q parameter: %s.",
387 param.Name, err,
388 ),
389 Subject: argExpr.StartRange().Ptr(),
390 Context: e.Range().Ptr(),
391 })
392
393 default:
394 diags = append(diags, &hcl.Diagnostic{
395 Severity: hcl.DiagError,
396 Summary: "Error in function call",
397 Detail: fmt.Sprintf(
398 "Call to function %q failed: %s.",
399 e.Name, err,
400 ),
401 Subject: e.StartRange().Ptr(),
402 Context: e.Range().Ptr(),
403 })
404 }
405
406 return cty.DynamicVal, diags
407 }
408
409 return resultVal, diags
410}
411
412func (e *FunctionCallExpr) Range() hcl.Range {
413 return hcl.RangeBetween(e.NameRange, e.CloseParenRange)
414}
415
416func (e *FunctionCallExpr) StartRange() hcl.Range {
417 return hcl.RangeBetween(e.NameRange, e.OpenParenRange)
418}
419
420// Implementation for hcl.ExprCall.
421func (e *FunctionCallExpr) ExprCall() *hcl.StaticCall {
422 ret := &hcl.StaticCall{
423 Name: e.Name,
424 NameRange: e.NameRange,
425 Arguments: make([]hcl.Expression, len(e.Args)),
426 ArgsRange: hcl.RangeBetween(e.OpenParenRange, e.CloseParenRange),
427 }
428 // Need to convert our own Expression objects into hcl.Expression.
429 for i, arg := range e.Args {
430 ret.Arguments[i] = arg
431 }
432 return ret
433}
434
435type ConditionalExpr struct {
436 Condition Expression
437 TrueResult Expression
438 FalseResult Expression
439
440 SrcRange hcl.Range
441}
442
443func (e *ConditionalExpr) walkChildNodes(w internalWalkFunc) {
444 e.Condition = w(e.Condition).(Expression)
445 e.TrueResult = w(e.TrueResult).(Expression)
446 e.FalseResult = w(e.FalseResult).(Expression)
447}
448
449func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
450 trueResult, trueDiags := e.TrueResult.Value(ctx)
451 falseResult, falseDiags := e.FalseResult.Value(ctx)
452 var diags hcl.Diagnostics
453
454 // Try to find a type that both results can be converted to.
455 resultType, convs := convert.UnifyUnsafe([]cty.Type{trueResult.Type(), falseResult.Type()})
456 if resultType == cty.NilType {
457 return cty.DynamicVal, hcl.Diagnostics{
458 {
459 Severity: hcl.DiagError,
460 Summary: "Inconsistent conditional result types",
461 Detail: fmt.Sprintf(
462 // FIXME: Need a helper function for showing natural-language type diffs,
463 // since this will generate some useless messages in some cases, like
464 // "These expressions are object and object respectively" if the
465 // object types don't exactly match.
466 "The true and false result expressions must have consistent types. The given expressions are %s and %s, respectively.",
467 trueResult.Type(), falseResult.Type(),
468 ),
469 Subject: hcl.RangeBetween(e.TrueResult.Range(), e.FalseResult.Range()).Ptr(),
470 Context: &e.SrcRange,
471 },
472 }
473 }
474
475 condResult, condDiags := e.Condition.Value(ctx)
476 diags = append(diags, condDiags...)
477 if condResult.IsNull() {
478 diags = append(diags, &hcl.Diagnostic{
479 Severity: hcl.DiagError,
480 Summary: "Null condition",
481 Detail: "The condition value is null. Conditions must either be true or false.",
482 Subject: e.Condition.Range().Ptr(),
483 Context: &e.SrcRange,
484 })
485 return cty.UnknownVal(resultType), diags
486 }
487 if !condResult.IsKnown() {
488 return cty.UnknownVal(resultType), diags
489 }
490 condResult, err := convert.Convert(condResult, cty.Bool)
491 if err != nil {
492 diags = append(diags, &hcl.Diagnostic{
493 Severity: hcl.DiagError,
494 Summary: "Incorrect condition type",
495 Detail: fmt.Sprintf("The condition expression must be of type bool."),
496 Subject: e.Condition.Range().Ptr(),
497 Context: &e.SrcRange,
498 })
499 return cty.UnknownVal(resultType), diags
500 }
501
502 if condResult.True() {
503 diags = append(diags, trueDiags...)
504 if convs[0] != nil {
505 var err error
506 trueResult, err = convs[0](trueResult)
507 if err != nil {
508 // Unsafe conversion failed with the concrete result value
509 diags = append(diags, &hcl.Diagnostic{
510 Severity: hcl.DiagError,
511 Summary: "Inconsistent conditional result types",
512 Detail: fmt.Sprintf(
513 "The true result value has the wrong type: %s.",
514 err.Error(),
515 ),
516 Subject: e.TrueResult.Range().Ptr(),
517 Context: &e.SrcRange,
518 })
519 trueResult = cty.UnknownVal(resultType)
520 }
521 }
522 return trueResult, diags
523 } else {
524 diags = append(diags, falseDiags...)
525 if convs[1] != nil {
526 var err error
527 falseResult, err = convs[1](falseResult)
528 if err != nil {
529 // Unsafe conversion failed with the concrete result value
530 diags = append(diags, &hcl.Diagnostic{
531 Severity: hcl.DiagError,
532 Summary: "Inconsistent conditional result types",
533 Detail: fmt.Sprintf(
534 "The false result value has the wrong type: %s.",
535 err.Error(),
536 ),
537 Subject: e.TrueResult.Range().Ptr(),
538 Context: &e.SrcRange,
539 })
540 falseResult = cty.UnknownVal(resultType)
541 }
542 }
543 return falseResult, diags
544 }
545}
546
547func (e *ConditionalExpr) Range() hcl.Range {
548 return e.SrcRange
549}
550
551func (e *ConditionalExpr) StartRange() hcl.Range {
552 return e.Condition.StartRange()
553}
554
555type IndexExpr struct {
556 Collection Expression
557 Key Expression
558
559 SrcRange hcl.Range
560 OpenRange hcl.Range
561}
562
563func (e *IndexExpr) walkChildNodes(w internalWalkFunc) {
564 e.Collection = w(e.Collection).(Expression)
565 e.Key = w(e.Key).(Expression)
566}
567
568func (e *IndexExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
569 var diags hcl.Diagnostics
570 coll, collDiags := e.Collection.Value(ctx)
571 key, keyDiags := e.Key.Value(ctx)
572 diags = append(diags, collDiags...)
573 diags = append(diags, keyDiags...)
574
575 return hcl.Index(coll, key, &e.SrcRange)
576}
577
578func (e *IndexExpr) Range() hcl.Range {
579 return e.SrcRange
580}
581
582func (e *IndexExpr) StartRange() hcl.Range {
583 return e.OpenRange
584}
585
586type TupleConsExpr struct {
587 Exprs []Expression
588
589 SrcRange hcl.Range
590 OpenRange hcl.Range
591}
592
593func (e *TupleConsExpr) walkChildNodes(w internalWalkFunc) {
594 for i, expr := range e.Exprs {
595 e.Exprs[i] = w(expr).(Expression)
596 }
597}
598
599func (e *TupleConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
600 var vals []cty.Value
601 var diags hcl.Diagnostics
602
603 vals = make([]cty.Value, len(e.Exprs))
604 for i, expr := range e.Exprs {
605 val, valDiags := expr.Value(ctx)
606 vals[i] = val
607 diags = append(diags, valDiags...)
608 }
609
610 return cty.TupleVal(vals), diags
611}
612
613func (e *TupleConsExpr) Range() hcl.Range {
614 return e.SrcRange
615}
616
617func (e *TupleConsExpr) StartRange() hcl.Range {
618 return e.OpenRange
619}
620
621// Implementation for hcl.ExprList
622func (e *TupleConsExpr) ExprList() []hcl.Expression {
623 ret := make([]hcl.Expression, len(e.Exprs))
624 for i, expr := range e.Exprs {
625 ret[i] = expr
626 }
627 return ret
628}
629
630type ObjectConsExpr struct {
631 Items []ObjectConsItem
632
633 SrcRange hcl.Range
634 OpenRange hcl.Range
635}
636
637type ObjectConsItem struct {
638 KeyExpr Expression
639 ValueExpr Expression
640}
641
642func (e *ObjectConsExpr) walkChildNodes(w internalWalkFunc) {
643 for i, item := range e.Items {
644 e.Items[i].KeyExpr = w(item.KeyExpr).(Expression)
645 e.Items[i].ValueExpr = w(item.ValueExpr).(Expression)
646 }
647}
648
649func (e *ObjectConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
650 var vals map[string]cty.Value
651 var diags hcl.Diagnostics
652
653 // This will get set to true if we fail to produce any of our keys,
654 // either because they are actually unknown or if the evaluation produces
655 // errors. In all of these case we must return DynamicPseudoType because
656 // we're unable to know the full set of keys our object has, and thus
657 // we can't produce a complete value of the intended type.
658 //
659 // We still evaluate all of the item keys and values to make sure that we
660 // get as complete as possible a set of diagnostics.
661 known := true
662
663 vals = make(map[string]cty.Value, len(e.Items))
664 for _, item := range e.Items {
665 key, keyDiags := item.KeyExpr.Value(ctx)
666 diags = append(diags, keyDiags...)
667
668 val, valDiags := item.ValueExpr.Value(ctx)
669 diags = append(diags, valDiags...)
670
671 if keyDiags.HasErrors() {
672 known = false
673 continue
674 }
675
676 if key.IsNull() {
677 diags = append(diags, &hcl.Diagnostic{
678 Severity: hcl.DiagError,
679 Summary: "Null value as key",
680 Detail: "Can't use a null value as a key.",
681 Subject: item.ValueExpr.Range().Ptr(),
682 })
683 known = false
684 continue
685 }
686
687 var err error
688 key, err = convert.Convert(key, cty.String)
689 if err != nil {
690 diags = append(diags, &hcl.Diagnostic{
691 Severity: hcl.DiagError,
692 Summary: "Incorrect key type",
693 Detail: fmt.Sprintf("Can't use this value as a key: %s.", err.Error()),
694 Subject: item.ValueExpr.Range().Ptr(),
695 })
696 known = false
697 continue
698 }
699
700 if !key.IsKnown() {
701 known = false
702 continue
703 }
704
705 keyStr := key.AsString()
706
707 vals[keyStr] = val
708 }
709
710 if !known {
711 return cty.DynamicVal, diags
712 }
713
714 return cty.ObjectVal(vals), diags
715}
716
717func (e *ObjectConsExpr) Range() hcl.Range {
718 return e.SrcRange
719}
720
721func (e *ObjectConsExpr) StartRange() hcl.Range {
722 return e.OpenRange
723}
724
725// Implementation for hcl.ExprMap
726func (e *ObjectConsExpr) ExprMap() []hcl.KeyValuePair {
727 ret := make([]hcl.KeyValuePair, len(e.Items))
728 for i, item := range e.Items {
729 ret[i] = hcl.KeyValuePair{
730 Key: item.KeyExpr,
731 Value: item.ValueExpr,
732 }
733 }
734 return ret
735}
736
737// ObjectConsKeyExpr is a special wrapper used only for ObjectConsExpr keys,
738// which deals with the special case that a naked identifier in that position
739// must be interpreted as a literal string rather than evaluated directly.
740type ObjectConsKeyExpr struct {
741 Wrapped Expression
742}
743
744func (e *ObjectConsKeyExpr) literalName() string {
745 // This is our logic for deciding whether to behave like a literal string.
746 // We lean on our AbsTraversalForExpr implementation here, which already
747 // deals with some awkward cases like the expression being the result
748 // of the keywords "null", "true" and "false" which we'd want to interpret
749 // as keys here too.
750 return hcl.ExprAsKeyword(e.Wrapped)
751}
752
753func (e *ObjectConsKeyExpr) walkChildNodes(w internalWalkFunc) {
754 // We only treat our wrapped expression as a real expression if we're
755 // not going to interpret it as a literal.
756 if e.literalName() == "" {
757 e.Wrapped = w(e.Wrapped).(Expression)
758 }
759}
760
761func (e *ObjectConsKeyExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
762 if ln := e.literalName(); ln != "" {
763 return cty.StringVal(ln), nil
764 }
765 return e.Wrapped.Value(ctx)
766}
767
768func (e *ObjectConsKeyExpr) Range() hcl.Range {
769 return e.Wrapped.Range()
770}
771
772func (e *ObjectConsKeyExpr) StartRange() hcl.Range {
773 return e.Wrapped.StartRange()
774}
775
776// Implementation for hcl.AbsTraversalForExpr.
777func (e *ObjectConsKeyExpr) AsTraversal() hcl.Traversal {
778 // We can produce a traversal only if our wrappee can.
779 st, diags := hcl.AbsTraversalForExpr(e.Wrapped)
780 if diags.HasErrors() {
781 return nil
782 }
783
784 return st
785}
786
787func (e *ObjectConsKeyExpr) UnwrapExpression() Expression {
788 return e.Wrapped
789}
790
791// ForExpr represents iteration constructs:
792//
793// tuple = [for i, v in list: upper(v) if i > 2]
794// object = {for k, v in map: k => upper(v)}
795// object_of_tuples = {for v in list: v.key: v...}
796type ForExpr struct {
797 KeyVar string // empty if ignoring the key
798 ValVar string
799
800 CollExpr Expression
801
802 KeyExpr Expression // nil when producing a tuple
803 ValExpr Expression
804 CondExpr Expression // null if no "if" clause is present
805
806 Group bool // set if the ellipsis is used on the value in an object for
807
808 SrcRange hcl.Range
809 OpenRange hcl.Range
810 CloseRange hcl.Range
811}
812
813func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
814 var diags hcl.Diagnostics
815
816 collVal, collDiags := e.CollExpr.Value(ctx)
817 diags = append(diags, collDiags...)
818
819 if collVal.IsNull() {
820 diags = append(diags, &hcl.Diagnostic{
821 Severity: hcl.DiagError,
822 Summary: "Iteration over null value",
823 Detail: "A null value cannot be used as the collection in a 'for' expression.",
824 Subject: e.CollExpr.Range().Ptr(),
825 Context: &e.SrcRange,
826 })
827 return cty.DynamicVal, diags
828 }
829 if collVal.Type() == cty.DynamicPseudoType {
830 return cty.DynamicVal, diags
831 }
832 if !collVal.CanIterateElements() {
833 diags = append(diags, &hcl.Diagnostic{
834 Severity: hcl.DiagError,
835 Summary: "Iteration over non-iterable value",
836 Detail: fmt.Sprintf(
837 "A value of type %s cannot be used as the collection in a 'for' expression.",
838 collVal.Type().FriendlyName(),
839 ),
840 Subject: e.CollExpr.Range().Ptr(),
841 Context: &e.SrcRange,
842 })
843 return cty.DynamicVal, diags
844 }
845 if !collVal.IsKnown() {
846 return cty.DynamicVal, diags
847 }
848
849 childCtx := ctx.NewChild()
850 childCtx.Variables = map[string]cty.Value{}
851
852 // Before we start we'll do an early check to see if any CondExpr we've
853 // been given is of the wrong type. This isn't 100% reliable (it may
854 // be DynamicVal until real values are given) but it should catch some
855 // straightforward cases and prevent a barrage of repeated errors.
856 if e.CondExpr != nil {
857 if e.KeyVar != "" {
858 childCtx.Variables[e.KeyVar] = cty.DynamicVal
859 }
860 childCtx.Variables[e.ValVar] = cty.DynamicVal
861
862 result, condDiags := e.CondExpr.Value(childCtx)
863 diags = append(diags, condDiags...)
864 if result.IsNull() {
865 diags = append(diags, &hcl.Diagnostic{
866 Severity: hcl.DiagError,
867 Summary: "Condition is null",
868 Detail: "The value of the 'if' clause must not be null.",
869 Subject: e.CondExpr.Range().Ptr(),
870 Context: &e.SrcRange,
871 })
872 return cty.DynamicVal, diags
873 }
874 _, err := convert.Convert(result, cty.Bool)
875 if err != nil {
876 diags = append(diags, &hcl.Diagnostic{
877 Severity: hcl.DiagError,
878 Summary: "Invalid 'for' condition",
879 Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
880 Subject: e.CondExpr.Range().Ptr(),
881 Context: &e.SrcRange,
882 })
883 return cty.DynamicVal, diags
884 }
885 if condDiags.HasErrors() {
886 return cty.DynamicVal, diags
887 }
888 }
889
890 if e.KeyExpr != nil {
891 // Producing an object
892 var vals map[string]cty.Value
893 var groupVals map[string][]cty.Value
894 if e.Group {
895 groupVals = map[string][]cty.Value{}
896 } else {
897 vals = map[string]cty.Value{}
898 }
899
900 it := collVal.ElementIterator()
901
902 known := true
903 for it.Next() {
904 k, v := it.Element()
905 if e.KeyVar != "" {
906 childCtx.Variables[e.KeyVar] = k
907 }
908 childCtx.Variables[e.ValVar] = v
909
910 if e.CondExpr != nil {
911 includeRaw, condDiags := e.CondExpr.Value(childCtx)
912 diags = append(diags, condDiags...)
913 if includeRaw.IsNull() {
914 if known {
915 diags = append(diags, &hcl.Diagnostic{
916 Severity: hcl.DiagError,
917 Summary: "Condition is null",
918 Detail: "The value of the 'if' clause must not be null.",
919 Subject: e.CondExpr.Range().Ptr(),
920 Context: &e.SrcRange,
921 })
922 }
923 known = false
924 continue
925 }
926 include, err := convert.Convert(includeRaw, cty.Bool)
927 if err != nil {
928 if known {
929 diags = append(diags, &hcl.Diagnostic{
930 Severity: hcl.DiagError,
931 Summary: "Invalid 'for' condition",
932 Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
933 Subject: e.CondExpr.Range().Ptr(),
934 Context: &e.SrcRange,
935 })
936 }
937 known = false
938 continue
939 }
940 if !include.IsKnown() {
941 known = false
942 continue
943 }
944
945 if include.False() {
946 // Skip this element
947 continue
948 }
949 }
950
951 keyRaw, keyDiags := e.KeyExpr.Value(childCtx)
952 diags = append(diags, keyDiags...)
953 if keyRaw.IsNull() {
954 if known {
955 diags = append(diags, &hcl.Diagnostic{
956 Severity: hcl.DiagError,
957 Summary: "Invalid object key",
958 Detail: "Key expression in 'for' expression must not produce a null value.",
959 Subject: e.KeyExpr.Range().Ptr(),
960 Context: &e.SrcRange,
961 })
962 }
963 known = false
964 continue
965 }
966 if !keyRaw.IsKnown() {
967 known = false
968 continue
969 }
970
971 key, err := convert.Convert(keyRaw, cty.String)
972 if err != nil {
973 if known {
974 diags = append(diags, &hcl.Diagnostic{
975 Severity: hcl.DiagError,
976 Summary: "Invalid object key",
977 Detail: fmt.Sprintf("The key expression produced an invalid result: %s.", err.Error()),
978 Subject: e.KeyExpr.Range().Ptr(),
979 Context: &e.SrcRange,
980 })
981 }
982 known = false
983 continue
984 }
985
986 val, valDiags := e.ValExpr.Value(childCtx)
987 diags = append(diags, valDiags...)
988
989 if e.Group {
990 k := key.AsString()
991 groupVals[k] = append(groupVals[k], val)
992 } else {
993 k := key.AsString()
994 if _, exists := vals[k]; exists {
995 diags = append(diags, &hcl.Diagnostic{
996 Severity: hcl.DiagError,
997 Summary: "Duplicate object key",
998 Detail: fmt.Sprintf(
999 "Two different items produced the key %q in this for expression. If duplicates are expected, use the ellipsis (...) after the value expression to enable grouping by key.",
1000 k,
1001 ),
1002 Subject: e.KeyExpr.Range().Ptr(),
1003 Context: &e.SrcRange,
1004 })
1005 } else {
1006 vals[key.AsString()] = val
1007 }
1008 }
1009 }
1010
1011 if !known {
1012 return cty.DynamicVal, diags
1013 }
1014
1015 if e.Group {
1016 vals = map[string]cty.Value{}
1017 for k, gvs := range groupVals {
1018 vals[k] = cty.TupleVal(gvs)
1019 }
1020 }
1021
1022 return cty.ObjectVal(vals), diags
1023
1024 } else {
1025 // Producing a tuple
1026 vals := []cty.Value{}
1027
1028 it := collVal.ElementIterator()
1029
1030 known := true
1031 for it.Next() {
1032 k, v := it.Element()
1033 if e.KeyVar != "" {
1034 childCtx.Variables[e.KeyVar] = k
1035 }
1036 childCtx.Variables[e.ValVar] = v
1037
1038 if e.CondExpr != nil {
1039 includeRaw, condDiags := e.CondExpr.Value(childCtx)
1040 diags = append(diags, condDiags...)
1041 if includeRaw.IsNull() {
1042 if known {
1043 diags = append(diags, &hcl.Diagnostic{
1044 Severity: hcl.DiagError,
1045 Summary: "Condition is null",
1046 Detail: "The value of the 'if' clause must not be null.",
1047 Subject: e.CondExpr.Range().Ptr(),
1048 Context: &e.SrcRange,
1049 })
1050 }
1051 known = false
1052 continue
1053 }
1054 if !includeRaw.IsKnown() {
1055 // We will eventually return DynamicVal, but we'll continue
1056 // iterating in case there are other diagnostics to gather
1057 // for later elements.
1058 known = false
1059 continue
1060 }
1061
1062 include, err := convert.Convert(includeRaw, cty.Bool)
1063 if err != nil {
1064 if known {
1065 diags = append(diags, &hcl.Diagnostic{
1066 Severity: hcl.DiagError,
1067 Summary: "Invalid 'for' condition",
1068 Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
1069 Subject: e.CondExpr.Range().Ptr(),
1070 Context: &e.SrcRange,
1071 })
1072 }
1073 known = false
1074 continue
1075 }
1076
1077 if include.False() {
1078 // Skip this element
1079 continue
1080 }
1081 }
1082
1083 val, valDiags := e.ValExpr.Value(childCtx)
1084 diags = append(diags, valDiags...)
1085 vals = append(vals, val)
1086 }
1087
1088 if !known {
1089 return cty.DynamicVal, diags
1090 }
1091
1092 return cty.TupleVal(vals), diags
1093 }
1094}
1095
1096func (e *ForExpr) walkChildNodes(w internalWalkFunc) {
1097 e.CollExpr = w(e.CollExpr).(Expression)
1098
1099 scopeNames := map[string]struct{}{}
1100 if e.KeyVar != "" {
1101 scopeNames[e.KeyVar] = struct{}{}
1102 }
1103 if e.ValVar != "" {
1104 scopeNames[e.ValVar] = struct{}{}
1105 }
1106
1107 if e.KeyExpr != nil {
1108 w(ChildScope{
1109 LocalNames: scopeNames,
1110 Expr: &e.KeyExpr,
1111 })
1112 }
1113 w(ChildScope{
1114 LocalNames: scopeNames,
1115 Expr: &e.ValExpr,
1116 })
1117 if e.CondExpr != nil {
1118 w(ChildScope{
1119 LocalNames: scopeNames,
1120 Expr: &e.CondExpr,
1121 })
1122 }
1123}
1124
1125func (e *ForExpr) Range() hcl.Range {
1126 return e.SrcRange
1127}
1128
1129func (e *ForExpr) StartRange() hcl.Range {
1130 return e.OpenRange
1131}
1132
1133type SplatExpr struct {
1134 Source Expression
1135 Each Expression
1136 Item *AnonSymbolExpr
1137
1138 SrcRange hcl.Range
1139 MarkerRange hcl.Range
1140}
1141
1142func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
1143 sourceVal, diags := e.Source.Value(ctx)
1144 if diags.HasErrors() {
1145 // We'll evaluate our "Each" expression here just to see if it
1146 // produces any more diagnostics we can report. Since we're not
1147 // assigning a value to our AnonSymbolExpr here it will return
1148 // DynamicVal, which should short-circuit any use of it.
1149 _, itemDiags := e.Item.Value(ctx)
1150 diags = append(diags, itemDiags...)
1151 return cty.DynamicVal, diags
1152 }
1153
1154 if sourceVal.IsNull() {
1155 diags = append(diags, &hcl.Diagnostic{
1156 Severity: hcl.DiagError,
1157 Summary: "Splat of null value",
1158 Detail: "Splat expressions (with the * symbol) cannot be applied to null values.",
1159 Subject: e.Source.Range().Ptr(),
1160 Context: hcl.RangeBetween(e.Source.Range(), e.MarkerRange).Ptr(),
1161 })
1162 return cty.DynamicVal, diags
1163 }
1164 if !sourceVal.IsKnown() {
1165 return cty.DynamicVal, diags
1166 }
1167
1168 // A "special power" of splat expressions is that they can be applied
1169 // both to tuples/lists and to other values, and in the latter case
1170 // the value will be treated as an implicit single-value list. We'll
1171 // deal with that here first.
1172 if !(sourceVal.Type().IsTupleType() || sourceVal.Type().IsListType()) {
1173 sourceVal = cty.ListVal([]cty.Value{sourceVal})
1174 }
1175
1176 vals := make([]cty.Value, 0, sourceVal.LengthInt())
1177 it := sourceVal.ElementIterator()
1178 if ctx == nil {
1179 // we need a context to use our AnonSymbolExpr, so we'll just
1180 // make an empty one here to use as a placeholder.
1181 ctx = ctx.NewChild()
1182 }
1183 isKnown := true
1184 for it.Next() {
1185 _, sourceItem := it.Element()
1186 e.Item.setValue(ctx, sourceItem)
1187 newItem, itemDiags := e.Each.Value(ctx)
1188 diags = append(diags, itemDiags...)
1189 if itemDiags.HasErrors() {
1190 isKnown = false
1191 }
1192 vals = append(vals, newItem)
1193 }
1194 e.Item.clearValue(ctx) // clean up our temporary value
1195
1196 if !isKnown {
1197 return cty.DynamicVal, diags
1198 }
1199
1200 return cty.TupleVal(vals), diags
1201}
1202
1203func (e *SplatExpr) walkChildNodes(w internalWalkFunc) {
1204 e.Source = w(e.Source).(Expression)
1205 e.Each = w(e.Each).(Expression)
1206}
1207
1208func (e *SplatExpr) Range() hcl.Range {
1209 return e.SrcRange
1210}
1211
1212func (e *SplatExpr) StartRange() hcl.Range {
1213 return e.MarkerRange
1214}
1215
1216// AnonSymbolExpr is used as a placeholder for a value in an expression that
1217// can be applied dynamically to any value at runtime.
1218//
1219// This is a rather odd, synthetic expression. It is used as part of the
1220// representation of splat expressions as a placeholder for the current item
1221// being visited in the splat evaluation.
1222//
1223// AnonSymbolExpr cannot be evaluated in isolation. If its Value is called
1224// directly then cty.DynamicVal will be returned. Instead, it is evaluated
1225// in terms of another node (i.e. a splat expression) which temporarily
1226// assigns it a value.
1227type AnonSymbolExpr struct {
1228 SrcRange hcl.Range
1229 values map[*hcl.EvalContext]cty.Value
1230}
1231
1232func (e *AnonSymbolExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
1233 if ctx == nil {
1234 return cty.DynamicVal, nil
1235 }
1236 val, exists := e.values[ctx]
1237 if !exists {
1238 return cty.DynamicVal, nil
1239 }
1240 return val, nil
1241}
1242
1243// setValue sets a temporary local value for the expression when evaluated
1244// in the given context, which must be non-nil.
1245func (e *AnonSymbolExpr) setValue(ctx *hcl.EvalContext, val cty.Value) {
1246 if e.values == nil {
1247 e.values = make(map[*hcl.EvalContext]cty.Value)
1248 }
1249 if ctx == nil {
1250 panic("can't setValue for a nil EvalContext")
1251 }
1252 e.values[ctx] = val
1253}
1254
1255func (e *AnonSymbolExpr) clearValue(ctx *hcl.EvalContext) {
1256 if e.values == nil {
1257 return
1258 }
1259 if ctx == nil {
1260 panic("can't clearValue for a nil EvalContext")
1261 }
1262 delete(e.values, ctx)
1263}
1264
1265func (e *AnonSymbolExpr) walkChildNodes(w internalWalkFunc) {
1266 // AnonSymbolExpr is a leaf node in the tree
1267}
1268
1269func (e *AnonSymbolExpr) Range() hcl.Range {
1270 return e.SrcRange
1271}
1272
1273func (e *AnonSymbolExpr) StartRange() hcl.Range {
1274 return e.SrcRange
1275}