zclsyntax: parsing of the index operator
This can either be a traversal or a first-class node depending on whether the given expression is a literal. This exception is made to allow applications to conditionally populate only part of a potentially-large collection if the config is only requesting one or two distinct indices. In particular, it allows the following to be considered a single traversal from the scope: foo.bar[0].baz
This commit is contained in:
parent
8fc5bd5141
commit
bca573d3d0
@ -387,6 +387,31 @@ func (e *ConditionalExpr) StartRange() zcl.Range {
|
||||
return e.Condition.StartRange()
|
||||
}
|
||||
|
||||
type IndexExpr struct {
|
||||
Collection Expression
|
||||
Key Expression
|
||||
|
||||
SrcRange zcl.Range
|
||||
OpenRange zcl.Range
|
||||
}
|
||||
|
||||
func (e *IndexExpr) walkChildNodes(w internalWalkFunc) {
|
||||
e.Collection = w(e.Collection).(Expression)
|
||||
e.Key = w(e.Key).(Expression)
|
||||
}
|
||||
|
||||
func (e *IndexExpr) Value(ctx *zcl.EvalContext) (cty.Value, zcl.Diagnostics) {
|
||||
panic("IndexExpr.Value not yet implemented")
|
||||
}
|
||||
|
||||
func (e *IndexExpr) Range() zcl.Range {
|
||||
return e.SrcRange
|
||||
}
|
||||
|
||||
func (e *IndexExpr) StartRange() zcl.Range {
|
||||
return e.OpenRange
|
||||
}
|
||||
|
||||
type TupleConsExpr struct {
|
||||
Exprs []Expression
|
||||
|
||||
|
@ -19,6 +19,10 @@ func (e *FunctionCallExpr) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}
|
||||
|
||||
func (e *IndexExpr) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}
|
||||
|
||||
func (e *LiteralValueExpr) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}
|
||||
|
@ -461,10 +461,11 @@ Traversal:
|
||||
case TokenDot:
|
||||
// Attribute access or splat
|
||||
dot := p.Read()
|
||||
attrTok := p.Read()
|
||||
attrTok := p.Peek()
|
||||
|
||||
switch attrTok.Type {
|
||||
case TokenIdent:
|
||||
attrTok = p.Read() // eat token
|
||||
name := string(attrTok.Bytes)
|
||||
rng := zcl.RangeBetween(dot.Range, attrTok.Range)
|
||||
step := zcl.TraverseAttr{
|
||||
@ -491,7 +492,51 @@ Traversal:
|
||||
// in order to support autocomplete triggered by typing a
|
||||
// period.
|
||||
p.setRecovery()
|
||||
break Traversal
|
||||
}
|
||||
|
||||
case TokenOBrack:
|
||||
// Indexing of a collection.
|
||||
// This may or may not be a zcl.Traverser, depending on whether
|
||||
// the key value is something constant.
|
||||
|
||||
open := p.Read()
|
||||
var close Token
|
||||
p.PushIncludeNewlines(false) // arbitrary newlines allowed in brackets
|
||||
keyExpr, keyDiags := p.ParseExpression()
|
||||
diags = append(diags, keyDiags...)
|
||||
if p.recovery && keyDiags.HasErrors() {
|
||||
close = p.recover(TokenCBrack)
|
||||
} else {
|
||||
close = p.Read()
|
||||
if close.Type != TokenCBrack && !p.recovery {
|
||||
diags = append(diags, &zcl.Diagnostic{
|
||||
Severity: zcl.DiagError,
|
||||
Summary: "Missing close bracket on index",
|
||||
Detail: "The index operator must end with a closing bracket (\"]\").",
|
||||
Subject: &close.Range,
|
||||
})
|
||||
close = p.recover(TokenCBrack)
|
||||
}
|
||||
}
|
||||
p.PushIncludeNewlines(true)
|
||||
|
||||
if lit, isLit := keyExpr.(*LiteralValueExpr); isLit {
|
||||
litKey, _ := lit.Value(nil)
|
||||
rng := zcl.RangeBetween(open.Range, close.Range)
|
||||
step := &zcl.TraverseIndex{
|
||||
Key: litKey,
|
||||
SrcRange: rng,
|
||||
}
|
||||
ret = makeRelativeTraversal(ret, step, rng)
|
||||
} else {
|
||||
rng := zcl.RangeBetween(open.Range, close.Range)
|
||||
ret = &IndexExpr{
|
||||
Collection: ret,
|
||||
Key: keyExpr,
|
||||
|
||||
SrcRange: rng,
|
||||
OpenRange: open.Range,
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user