vendor: github.com/hashicorp/hcl/v2 v2.23.0

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2025-01-13 17:58:59 +01:00
parent 807d15ff9d
commit d3830e0a6e
10 changed files with 189 additions and 54 deletions

2
go.mod
View File

@ -25,7 +25,7 @@ require (
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992 github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992
github.com/hashicorp/hcl/v2 v2.20.1 github.com/hashicorp/hcl/v2 v2.23.0
github.com/in-toto/in-toto-golang v0.5.0 github.com/in-toto/in-toto-golang v0.5.0
github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/moby/buildkit v0.18.0 github.com/moby/buildkit v0.18.0

8
go.sum
View File

@ -239,8 +239,8 @@ github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992 h1:fYOrSfO5
github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA= github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/hcl/v2 v2.20.1 h1:M6hgdyz7HYt1UN9e61j+qKJBqR3orTWbI1HKBJEdxtc= github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
github.com/hashicorp/hcl/v2 v2.20.1/go.mod h1:TZDqQ4kNKCbh1iJp99FdPiUaVDDUPivbqxZulxDYqL4= github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
@ -464,8 +464,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ= github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ=
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE=

View File

@ -1,5 +1,22 @@
# HCL Changelog # HCL Changelog
## v2.22.0 (August 26, 2024)
### Enhancements
* feat: return an ExprSyntaxError for invalid references that end in a dot ([#692](https://github.com/hashicorp/hcl/pull/692))
## v2.21.0 (June 19, 2024)
### Enhancements
* Introduce `ParseTraversalPartial`, which allows traversals that include the splat (`[*]`) index operator. ([#673](https://github.com/hashicorp/hcl/pull/673))
* ext/dynblock: Now accepts marked values in `for_each`, and will transfer those marks (as much as technically possible) to values in the generated blocks. ([#679](https://github.com/hashicorp/hcl/pull/679))
### Bugs Fixed
* Expression evaluation will no longer panic if the splat operator is applied to an unknown value that has cty marks. ([#678](https://github.com/hashicorp/hcl/pull/678))
## v2.20.1 (March 26, 2024) ## v2.20.1 (March 26, 2024)
### Bugs Fixed ### Bugs Fixed

View File

@ -788,21 +788,24 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
}) })
return cty.UnknownVal(resultType), diags return cty.UnknownVal(resultType), diags
} }
// Now that we have all three values, collect all the marks for the result.
// Since it's possible that a condition value could be unknown, and the
// consumer needs to deal with any marks from either branch anyway, we must
// always combine them for consistent results.
condResult, condResultMarks := condResult.Unmark()
trueResult, trueResultMarks := trueResult.Unmark()
falseResult, falseResultMarks := falseResult.Unmark()
var resMarks []cty.ValueMarks
resMarks = append(resMarks, condResultMarks, trueResultMarks, falseResultMarks)
if !condResult.IsKnown() { if !condResult.IsKnown() {
// we use the unmarked values throughout the unknown branch
_, condResultMarks := condResult.Unmark()
trueResult, trueResultMarks := trueResult.Unmark()
falseResult, falseResultMarks := falseResult.Unmark()
// use a value to merge marks
_, resMarks := cty.DynamicVal.WithMarks(condResultMarks, trueResultMarks, falseResultMarks).Unmark()
trueRange := trueResult.Range() trueRange := trueResult.Range()
falseRange := falseResult.Range() falseRange := falseResult.Range()
// if both branches are known to be null, then the result must still be null // if both branches are known to be null, then the result must still be null
if trueResult.IsNull() && falseResult.IsNull() { if trueResult.IsNull() && falseResult.IsNull() {
return cty.NullVal(resultType).WithMarks(resMarks), diags return cty.NullVal(resultType).WithMarks(resMarks...), diags
} }
// We might be able to offer a refined range for the result based on // We might be able to offer a refined range for the result based on
@ -841,7 +844,7 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
ref = ref.NumberRangeUpperBound(hi, hiInc) ref = ref.NumberRangeUpperBound(hi, hiInc)
} }
return ref.NewValue().WithMarks(resMarks), diags return ref.NewValue().WithMarks(resMarks...), diags
} }
if trueResult.Type().IsCollectionType() && falseResult.Type().IsCollectionType() { if trueResult.Type().IsCollectionType() && falseResult.Type().IsCollectionType() {
@ -867,7 +870,7 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
} }
ref = ref.CollectionLengthLowerBound(lo).CollectionLengthUpperBound(hi) ref = ref.CollectionLengthLowerBound(lo).CollectionLengthUpperBound(hi)
return ref.NewValue().WithMarks(resMarks), diags return ref.NewValue().WithMarks(resMarks...), diags
} }
} }
@ -875,7 +878,7 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
if trueRange.DefinitelyNotNull() && falseRange.DefinitelyNotNull() { if trueRange.DefinitelyNotNull() && falseRange.DefinitelyNotNull() {
ret = ret.RefineNotNull() ret = ret.RefineNotNull()
} }
return ret.WithMarks(resMarks), diags return ret.WithMarks(resMarks...), diags
} }
condResult, err := convert.Convert(condResult, cty.Bool) condResult, err := convert.Convert(condResult, cty.Bool)
@ -892,8 +895,6 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
return cty.UnknownVal(resultType), diags return cty.UnknownVal(resultType), diags
} }
// Unmark result before testing for truthiness
condResult, _ = condResult.UnmarkDeep()
if condResult.True() { if condResult.True() {
diags = append(diags, trueDiags...) diags = append(diags, trueDiags...)
if convs[0] != nil { if convs[0] != nil {
@ -916,7 +917,7 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
trueResult = cty.UnknownVal(resultType) trueResult = cty.UnknownVal(resultType)
} }
} }
return trueResult, diags return trueResult.WithMarks(resMarks...), diags
} else { } else {
diags = append(diags, falseDiags...) diags = append(diags, falseDiags...)
if convs[1] != nil { if convs[1] != nil {
@ -939,7 +940,7 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
falseResult = cty.UnknownVal(resultType) falseResult = cty.UnknownVal(resultType)
} }
} }
return falseResult, diags return falseResult.WithMarks(resMarks...), diags
} }
} }
@ -1429,9 +1430,9 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
}) })
return cty.DynamicVal, diags return cty.DynamicVal, diags
} }
if !collVal.IsKnown() {
return cty.DynamicVal, diags // Grab the CondExpr marks when we're returning early with an unknown
} var condMarks cty.ValueMarks
// Before we start we'll do an early check to see if any CondExpr we've // Before we start we'll do an early check to see if any CondExpr we've
// been given is of the wrong type. This isn't 100% reliable (it may // been given is of the wrong type. This isn't 100% reliable (it may
@ -1459,6 +1460,9 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
}) })
return cty.DynamicVal, diags return cty.DynamicVal, diags
} }
_, condMarks = result.Unmark()
_, err := convert.Convert(result, cty.Bool) _, err := convert.Convert(result, cty.Bool)
if err != nil { if err != nil {
diags = append(diags, &hcl.Diagnostic{ diags = append(diags, &hcl.Diagnostic{
@ -1477,6 +1481,10 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
} }
} }
if !collVal.IsKnown() {
return cty.DynamicVal.WithMarks(append(marks, condMarks)...), diags
}
if e.KeyExpr != nil { if e.KeyExpr != nil {
// Producing an object // Producing an object
var vals map[string]cty.Value var vals map[string]cty.Value
@ -1517,6 +1525,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
known = false known = false
continue continue
} }
// Extract and merge marks from the include expression into the
// main set of marks
_, includeMarks := includeRaw.Unmark()
marks = append(marks, includeMarks)
include, err := convert.Convert(includeRaw, cty.Bool) include, err := convert.Convert(includeRaw, cty.Bool)
if err != nil { if err != nil {
if known { if known {
@ -1540,7 +1554,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
// Extract and merge marks from the include expression into the // Extract and merge marks from the include expression into the
// main set of marks // main set of marks
includeUnmarked, includeMarks := include.Unmark() includeUnmarked, _ := include.Unmark()
marks = append(marks, includeMarks) marks = append(marks, includeMarks)
if includeUnmarked.False() { if includeUnmarked.False() {
// Skip this element // Skip this element
@ -1565,6 +1579,10 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
known = false known = false
continue continue
} }
_, keyMarks := keyRaw.Unmark()
marks = append(marks, keyMarks)
if !keyRaw.IsKnown() { if !keyRaw.IsKnown() {
known = false known = false
continue continue
@ -1587,8 +1605,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
continue continue
} }
key, keyMarks := key.Unmark() key, _ = key.Unmark()
marks = append(marks, keyMarks)
val, valDiags := e.ValExpr.Value(childCtx) val, valDiags := e.ValExpr.Value(childCtx)
diags = append(diags, valDiags...) diags = append(diags, valDiags...)
@ -1618,7 +1635,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
} }
if !known { if !known {
return cty.DynamicVal, diags return cty.DynamicVal.WithMarks(marks...), diags
} }
if e.Group { if e.Group {
@ -1664,6 +1681,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
known = false known = false
continue continue
} }
// Extract and merge marks from the include expression into the
// main set of marks
_, includeMarks := includeRaw.Unmark()
marks = append(marks, includeMarks)
if !includeRaw.IsKnown() { if !includeRaw.IsKnown() {
// We will eventually return DynamicVal, but we'll continue // We will eventually return DynamicVal, but we'll continue
// iterating in case there are other diagnostics to gather // iterating in case there are other diagnostics to gather
@ -1689,10 +1712,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
continue continue
} }
// Extract and merge marks from the include expression into the includeUnmarked, _ := include.Unmark()
// main set of marks
includeUnmarked, includeMarks := include.Unmark()
marks = append(marks, includeMarks)
if includeUnmarked.False() { if includeUnmarked.False() {
// Skip this element // Skip this element
continue continue
@ -1705,7 +1725,7 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
} }
if !known { if !known {
return cty.DynamicVal, diags return cty.DynamicVal.WithMarks(marks...), diags
} }
return cty.TupleVal(vals).WithMarks(marks...), diags return cty.TupleVal(vals).WithMarks(marks...), diags
@ -1780,7 +1800,7 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
if sourceVal.IsNull() { if sourceVal.IsNull() {
if autoUpgrade { if autoUpgrade {
return cty.EmptyTupleVal, diags return cty.EmptyTupleVal.WithSameMarks(sourceVal), diags
} }
diags = append(diags, &hcl.Diagnostic{ diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError, Severity: hcl.DiagError,
@ -1798,7 +1818,7 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
// If we don't even know the _type_ of our source value yet then // If we don't even know the _type_ of our source value yet then
// we'll need to defer all processing, since we can't decide our // we'll need to defer all processing, since we can't decide our
// result type either. // result type either.
return cty.DynamicVal, diags return cty.DynamicVal.WithSameMarks(sourceVal), diags
} }
upgradedUnknown := false upgradedUnknown := false
@ -1813,13 +1833,14 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
// list of a single attribute, but we still need to check if that // list of a single attribute, but we still need to check if that
// attribute actually exists. // attribute actually exists.
if !sourceVal.IsKnown() { if !sourceVal.IsKnown() {
sourceRng := sourceVal.Range() unmarkedVal, _ := sourceVal.Unmark()
sourceRng := unmarkedVal.Range()
if sourceRng.CouldBeNull() { if sourceRng.CouldBeNull() {
upgradedUnknown = true upgradedUnknown = true
} }
} }
sourceVal = cty.TupleVal([]cty.Value{sourceVal}) sourceVal = cty.TupleVal([]cty.Value{sourceVal}).WithSameMarks(sourceVal)
sourceTy = sourceVal.Type() sourceTy = sourceVal.Type()
} }
@ -1900,14 +1921,14 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
e.Item.clearValue(ctx) // clean up our temporary value e.Item.clearValue(ctx) // clean up our temporary value
if upgradedUnknown { if upgradedUnknown {
return cty.DynamicVal, diags return cty.DynamicVal.WithMarks(marks), diags
} }
if !isKnown { if !isKnown {
// We'll ingore the resultTy diagnostics in this case since they // We'll ingore the resultTy diagnostics in this case since they
// will just be the same errors we saw while iterating above. // will just be the same errors we saw while iterating above.
ty, _ := resultTy() ty, _ := resultTy()
return cty.UnknownVal(ty), diags return cty.UnknownVal(ty).WithMarks(marks), diags
} }
switch { switch {
@ -1915,7 +1936,7 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
if len(vals) == 0 { if len(vals) == 0 {
ty, tyDiags := resultTy() ty, tyDiags := resultTy()
diags = append(diags, tyDiags...) diags = append(diags, tyDiags...)
return cty.ListValEmpty(ty.ElementType()), diags return cty.ListValEmpty(ty.ElementType()).WithMarks(marks), diags
} }
return cty.ListVal(vals).WithMarks(marks), diags return cty.ListVal(vals).WithMarks(marks), diags
default: default:

View File

@ -811,9 +811,16 @@ Traversal:
// will probably be misparsed until we hit something that // will probably be misparsed until we hit something that
// allows us to re-sync. // allows us to re-sync.
// //
// We will probably need to do something better here eventually // Returning an ExprSyntaxError allows us to pass more information
// in order to support autocomplete triggered by typing a // about the invalid expression to the caller, which can then
// period. // use this for example for completions that happen after typing
// a dot in an editor.
ret = &ExprSyntaxError{
Placeholder: cty.DynamicVal,
ParseDiags: diags,
SrcRange: hcl.RangeBetween(from.Range(), dot.Range),
}
p.setRecovery() p.setRecovery()
} }
@ -1516,6 +1523,16 @@ func (p *parser) parseObjectCons() (Expression, hcl.Diagnostics) {
diags = append(diags, valueDiags...) diags = append(diags, valueDiags...)
if p.recovery && valueDiags.HasErrors() { if p.recovery && valueDiags.HasErrors() {
// If the value is an ExprSyntaxError, we can add an item with it, even though we will recover afterwards
// This allows downstream consumers to still retrieve this first invalid item, even though following items
// won't be parsed. This is useful for supplying completions.
if exprSyntaxError, ok := value.(*ExprSyntaxError); ok {
items = append(items, ObjectConsItem{
KeyExpr: key,
ValueExpr: exprSyntaxError,
})
}
// If expression parsing failed then we are probably in a strange // If expression parsing failed then we are probably in a strange
// place in the token stream, so we'll bail out and try to reset // place in the token stream, so we'll bail out and try to reset
// to after our closing brace to allow parsing to continue. // to after our closing brace to allow parsing to continue.

View File

@ -4,8 +4,9 @@
package hclsyntax package hclsyntax
import ( import (
"github.com/hashicorp/hcl/v2"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
"github.com/hashicorp/hcl/v2"
) )
// ParseTraversalAbs parses an absolute traversal that is assumed to consume // ParseTraversalAbs parses an absolute traversal that is assumed to consume
@ -13,6 +14,26 @@ import (
// behavior is not supported here because traversals are not expected to // behavior is not supported here because traversals are not expected to
// be parsed as part of a larger program. // be parsed as part of a larger program.
func (p *parser) ParseTraversalAbs() (hcl.Traversal, hcl.Diagnostics) { func (p *parser) ParseTraversalAbs() (hcl.Traversal, hcl.Diagnostics) {
return p.parseTraversal(false)
}
// ParseTraversalPartial parses an absolute traversal that is permitted
// to contain splat ([*]) expressions. Only splat expressions within square
// brackets are permitted ([*]); splat expressions within attribute names are
// not permitted (.*).
//
// The meaning of partial here is that the traversal may be incomplete, in that
// any splat expression indicates reference to a potentially unknown number of
// elements.
//
// Traversals that include splats cannot be automatically traversed by HCL using
// the TraversalAbs or TraversalRel methods. Instead, the caller must handle
// the traversals manually.
func (p *parser) ParseTraversalPartial() (hcl.Traversal, hcl.Diagnostics) {
return p.parseTraversal(true)
}
func (p *parser) parseTraversal(allowSplats bool) (hcl.Traversal, hcl.Diagnostics) {
var ret hcl.Traversal var ret hcl.Traversal
var diags hcl.Diagnostics var diags hcl.Diagnostics
@ -127,6 +148,34 @@ func (p *parser) ParseTraversalAbs() (hcl.Traversal, hcl.Diagnostics) {
return ret, diags return ret, diags
} }
case TokenStar:
if allowSplats {
p.Read() // Eat the star.
close := p.Read()
if close.Type != TokenCBrack {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Unclosed index brackets",
Detail: "Index key must be followed by a closing bracket.",
Subject: &close.Range,
Context: hcl.RangeBetween(open.Range, close.Range).Ptr(),
})
}
ret = append(ret, hcl.TraverseSplat{
SrcRange: hcl.RangeBetween(open.Range, close.Range),
})
if diags.HasErrors() {
return ret, diags
}
continue
}
// Otherwise, return the error below for the star.
fallthrough
default: default:
if next.Type == TokenStar { if next.Type == TokenStar {
diags = append(diags, &hcl.Diagnostic{ diags = append(diags, &hcl.Diagnostic{

View File

@ -118,6 +118,37 @@ func ParseTraversalAbs(src []byte, filename string, start hcl.Pos) (hcl.Traversa
return expr, diags return expr, diags
} }
// ParseTraversalPartial matches the behavior of ParseTraversalAbs except
// that it allows splat expressions ([*]) to appear in the traversal.
//
// The returned traversals are "partial" in that the splat expression indicates
// an unknown value for the index.
//
// Traversals that include splats cannot be automatically traversed by HCL using
// the TraversalAbs or TraversalRel methods. Instead, the caller must handle
// the traversals manually.
func ParseTraversalPartial(src []byte, filename string, start hcl.Pos) (hcl.Traversal, hcl.Diagnostics) {
tokens, diags := LexExpression(src, filename, start)
peeker := newPeeker(tokens, false)
parser := &parser{peeker: peeker}
// Bare traverals are always parsed in "ignore newlines" mode, as if
// they were wrapped in parentheses.
parser.PushIncludeNewlines(false)
expr, parseDiags := parser.ParseTraversalPartial()
diags = append(diags, parseDiags...)
parser.PopIncludeNewlines()
// Panic if the parser uses incorrect stack discipline with the peeker's
// newlines stack, since otherwise it will produce confusing downstream
// errors.
peeker.AssertEmptyIncludeNewlinesStack()
return expr, diags
}
// LexConfig performs lexical analysis on the given buffer, treating it as a // LexConfig performs lexical analysis on the given buffer, treating it as a
// whole HCL config file, and returns the resulting tokens. // whole HCL config file, and returns the resulting tokens.
// //

View File

@ -49,7 +49,7 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
ty := collection.Type() ty := collection.Type()
kty := key.Type() kty := key.Type()
if kty == cty.DynamicPseudoType || ty == cty.DynamicPseudoType { if kty == cty.DynamicPseudoType || ty == cty.DynamicPseudoType {
return cty.DynamicVal, nil return cty.DynamicVal.WithSameMarks(collection), nil
} }
switch { switch {
@ -87,9 +87,9 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
has, _ := collection.HasIndex(key).Unmark() has, _ := collection.HasIndex(key).Unmark()
if !has.IsKnown() { if !has.IsKnown() {
if ty.IsTupleType() { if ty.IsTupleType() {
return cty.DynamicVal, nil return cty.DynamicVal.WithSameMarks(collection), nil
} else { } else {
return cty.UnknownVal(ty.ElementType()), nil return cty.UnknownVal(ty.ElementType()).WithSameMarks(collection), nil
} }
} }
if has.False() { if has.False() {
@ -196,10 +196,10 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
} }
} }
if !collection.IsKnown() { if !collection.IsKnown() {
return cty.DynamicVal, nil return cty.DynamicVal.WithSameMarks(collection), nil
} }
if !key.IsKnown() { if !key.IsKnown() {
return cty.DynamicVal, nil return cty.DynamicVal.WithSameMarks(collection), nil
} }
key, _ = key.Unmark() key, _ = key.Unmark()
@ -291,13 +291,13 @@ func GetAttr(obj cty.Value, attrName string, srcRange *Range) (cty.Value, Diagno
} }
if !obj.IsKnown() { if !obj.IsKnown() {
return cty.UnknownVal(ty.AttributeType(attrName)), nil return cty.UnknownVal(ty.AttributeType(attrName)).WithSameMarks(obj), nil
} }
return obj.GetAttr(attrName), nil return obj.GetAttr(attrName), nil
case ty.IsMapType(): case ty.IsMapType():
if !obj.IsKnown() { if !obj.IsKnown() {
return cty.UnknownVal(ty.ElementType()), nil return cty.UnknownVal(ty.ElementType()).WithSameMarks(obj), nil
} }
idx := cty.StringVal(attrName) idx := cty.StringVal(attrName)
@ -319,7 +319,7 @@ func GetAttr(obj cty.Value, attrName string, srcRange *Range) (cty.Value, Diagno
return obj.Index(idx), nil return obj.Index(idx), nil
case ty == cty.DynamicPseudoType: case ty == cty.DynamicPseudoType:
return cty.DynamicVal, nil return cty.DynamicVal.WithSameMarks(obj), nil
case ty.IsListType() && ty.ElementType().IsObjectType(): case ty.IsListType() && ty.ElementType().IsObjectType():
// It seems a common mistake to try to access attributes on a whole // It seems a common mistake to try to access attributes on a whole
// list of objects rather than on a specific individual element, so // list of objects rather than on a specific individual element, so

View File

@ -96,7 +96,7 @@ of the implementation language.
### _Dynamic Attributes_ Processing ### _Dynamic Attributes_ Processing
The _schema-driven_ processing model is useful when the expected structure The _schema-driven_ processing model is useful when the expected structure
of a body is known a priori by the calling application. Some blocks are of a body is known by the calling application. Some blocks are
instead more free-form, such as a user-provided set of arbitrary key/value instead more free-form, such as a user-provided set of arbitrary key/value
pairs. pairs.

2
vendor/modules.txt vendored
View File

@ -423,7 +423,7 @@ github.com/hashicorp/go-cty-funcs/uuid
# github.com/hashicorp/go-multierror v1.1.1 # github.com/hashicorp/go-multierror v1.1.1
## explicit; go 1.13 ## explicit; go 1.13
github.com/hashicorp/go-multierror github.com/hashicorp/go-multierror
# github.com/hashicorp/hcl/v2 v2.20.1 # github.com/hashicorp/hcl/v2 v2.23.0
## explicit; go 1.18 ## explicit; go 1.18
github.com/hashicorp/hcl/v2 github.com/hashicorp/hcl/v2
github.com/hashicorp/hcl/v2/ext/customdecode github.com/hashicorp/hcl/v2/ext/customdecode