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