zclsyntax: parsing of "attribute-only" splat expressions
Attribute-only splat expressions, indicated by using the star symbol as if it were an attribute, are inherited from HIL and are a limited sort of splat that only works for walking through attributes in each item of its source. Later zcl will also get full splat expressions, whose syntax is using the star symbol as if it were an _index_, which will generalize to supporting _all_ postfix traversal operations, including indexing and nested splats.
This commit is contained in:
parent
78db663590
commit
22bc5ce5c6
@ -486,6 +486,50 @@ upper(
|
||||
0,
|
||||
},
|
||||
|
||||
{
|
||||
`[{name: "Steve"}, {name: "Ermintrude"}].*.name`,
|
||||
nil,
|
||||
cty.TupleVal([]cty.Value{
|
||||
cty.StringVal("Steve"),
|
||||
cty.StringVal("Ermintrude"),
|
||||
}),
|
||||
0,
|
||||
},
|
||||
{
|
||||
`{name: "Steve"}.*.name`,
|
||||
nil,
|
||||
cty.TupleVal([]cty.Value{
|
||||
cty.StringVal("Steve"),
|
||||
}),
|
||||
0,
|
||||
},
|
||||
{
|
||||
`["hello", "goodbye"].*`,
|
||||
nil,
|
||||
cty.TupleVal([]cty.Value{
|
||||
cty.StringVal("hello"),
|
||||
cty.StringVal("goodbye"),
|
||||
}),
|
||||
0,
|
||||
},
|
||||
{
|
||||
`"hello".*`,
|
||||
nil,
|
||||
cty.TupleVal([]cty.Value{
|
||||
cty.StringVal("hello"),
|
||||
}),
|
||||
0,
|
||||
},
|
||||
{
|
||||
// For an "attribute-only" splat, an index operator applies to
|
||||
// the splat result as a whole, rather than being incorporated
|
||||
// into the splat traversal itself.
|
||||
`[{name: "Steve"}, {name: "Ermintrude"}].*.name[0]`,
|
||||
nil,
|
||||
cty.StringVal("Steve"),
|
||||
0,
|
||||
},
|
||||
|
||||
{
|
||||
`["hello"][0]`,
|
||||
nil,
|
||||
|
@ -498,7 +498,61 @@ Traversal:
|
||||
|
||||
ret = makeRelativeTraversal(ret, step, rng)
|
||||
|
||||
// TODO: TokenStar, for splats
|
||||
case TokenStar:
|
||||
// "Attribute-only" splat expression.
|
||||
// (This is a kinda weird construct inherited from HIL, which
|
||||
// behaves a bit like a [*] splat except that it is only able
|
||||
// to do attribute traversals into each of its elements,
|
||||
// whereas foo[*] can support _any_ traversal.
|
||||
marker := p.Read() // eat star
|
||||
trav := make(zcl.Traversal, 0, 1)
|
||||
var firstRange, lastRange zcl.Range
|
||||
firstRange = p.NextRange()
|
||||
for p.Peek().Type == TokenDot {
|
||||
dot := p.Read()
|
||||
if p.Peek().Type != TokenIdent {
|
||||
if !p.recovery {
|
||||
diags = append(diags, &zcl.Diagnostic{
|
||||
Severity: zcl.DiagError,
|
||||
Summary: "Invalid attribute name",
|
||||
Detail: "An attribute name is required after a dot.",
|
||||
Subject: &attrTok.Range,
|
||||
})
|
||||
}
|
||||
p.setRecovery()
|
||||
continue Traversal
|
||||
}
|
||||
|
||||
attrTok := p.Read()
|
||||
trav = append(trav, zcl.TraverseAttr{
|
||||
Name: string(attrTok.Bytes),
|
||||
SrcRange: zcl.RangeBetween(dot.Range, attrTok.Range),
|
||||
})
|
||||
lastRange = attrTok.Range
|
||||
}
|
||||
|
||||
itemExpr := &AnonSymbolExpr{
|
||||
SrcRange: zcl.RangeBetween(dot.Range, marker.Range),
|
||||
}
|
||||
var travExpr Expression
|
||||
if len(trav) == 0 {
|
||||
travExpr = itemExpr
|
||||
} else {
|
||||
travExpr = &RelativeTraversalExpr{
|
||||
Source: itemExpr,
|
||||
Traversal: trav,
|
||||
SrcRange: zcl.RangeBetween(firstRange, lastRange),
|
||||
}
|
||||
}
|
||||
|
||||
ret = &SplatExpr{
|
||||
Source: ret,
|
||||
Each: travExpr,
|
||||
Item: itemExpr,
|
||||
|
||||
SrcRange: zcl.RangeBetween(dot.Range, lastRange),
|
||||
MarkerRange: zcl.RangeBetween(dot.Range, marker.Range),
|
||||
}
|
||||
|
||||
default:
|
||||
diags = append(diags, &zcl.Diagnostic{
|
||||
@ -523,6 +577,8 @@ Traversal:
|
||||
// the key value is something constant.
|
||||
|
||||
open := p.Read()
|
||||
// TODO: If we have a TokenStar inside our brackets, parse as
|
||||
// a Splat expression: foo[*].baz[0].
|
||||
var close Token
|
||||
p.PushIncludeNewlines(false) // arbitrary newlines allowed in brackets
|
||||
keyExpr, keyDiags := p.ParseExpression()
|
||||
|
Loading…
Reference in New Issue
Block a user