zclsyntax: parsing and evaluation of tuple constructors
This commit is contained in:
parent
4488df0cd8
commit
c3f4694e06
@ -362,3 +362,38 @@ func (e *ConditionalExpr) Range() zcl.Range {
|
||||
func (e *ConditionalExpr) StartRange() zcl.Range {
|
||||
return e.Condition.StartRange()
|
||||
}
|
||||
|
||||
type TupleConsExpr struct {
|
||||
Exprs []Expression
|
||||
|
||||
SrcRange zcl.Range
|
||||
OpenRange zcl.Range
|
||||
}
|
||||
|
||||
func (e *TupleConsExpr) walkChildNodes(w internalWalkFunc) {
|
||||
for i, expr := range e.Exprs {
|
||||
e.Exprs[i] = w(expr).(Expression)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *TupleConsExpr) Value(ctx *zcl.EvalContext) (cty.Value, zcl.Diagnostics) {
|
||||
var vals []cty.Value
|
||||
var diags zcl.Diagnostics
|
||||
|
||||
vals = make([]cty.Value, len(e.Exprs))
|
||||
for i, expr := range e.Exprs {
|
||||
val, valDiags := expr.Value(ctx)
|
||||
vals[i] = val
|
||||
diags = append(diags, valDiags...)
|
||||
}
|
||||
|
||||
return cty.TupleVal(vals), diags
|
||||
}
|
||||
|
||||
func (e *TupleConsExpr) Range() zcl.Range {
|
||||
return e.SrcRange
|
||||
}
|
||||
|
||||
func (e *TupleConsExpr) StartRange() zcl.Range {
|
||||
return e.OpenRange
|
||||
}
|
||||
|
@ -146,6 +146,39 @@ upper(
|
||||
cty.StringVal("FOO"),
|
||||
0,
|
||||
},
|
||||
{
|
||||
`[]`,
|
||||
nil,
|
||||
cty.EmptyTupleVal,
|
||||
0,
|
||||
},
|
||||
{
|
||||
`[1]`,
|
||||
nil,
|
||||
cty.TupleVal([]cty.Value{cty.NumberIntVal(1)}),
|
||||
0,
|
||||
},
|
||||
{
|
||||
`[1,]`,
|
||||
nil,
|
||||
cty.TupleVal([]cty.Value{cty.NumberIntVal(1)}),
|
||||
0,
|
||||
},
|
||||
{
|
||||
`[1,true]`,
|
||||
nil,
|
||||
cty.TupleVal([]cty.Value{cty.NumberIntVal(1), cty.True}),
|
||||
0,
|
||||
},
|
||||
{
|
||||
`[
|
||||
1,
|
||||
true
|
||||
]`,
|
||||
nil,
|
||||
cty.TupleVal([]cty.Value{cty.NumberIntVal(1), cty.True}),
|
||||
0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
@ -31,6 +31,10 @@ func (e *TemplateExpr) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}
|
||||
|
||||
func (e *TupleConsExpr) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}
|
||||
|
||||
func (e *UnaryOpExpr) Variables() []zcl.Traversal {
|
||||
return Variables(e)
|
||||
}
|
||||
|
@ -587,6 +587,9 @@ func (p *parser) parseExpressionTerm() (Expression, zcl.Diagnostics) {
|
||||
SymbolRange: tok.Range,
|
||||
}, diags
|
||||
|
||||
case TokenOBrack:
|
||||
return p.parseTupleCons()
|
||||
|
||||
default:
|
||||
var diags zcl.Diagnostics
|
||||
if !p.recovery {
|
||||
@ -683,6 +686,72 @@ Token:
|
||||
}, diags
|
||||
}
|
||||
|
||||
func (p *parser) parseTupleCons() (Expression, zcl.Diagnostics) {
|
||||
open := p.Read()
|
||||
if open.Type != TokenOBrack {
|
||||
// Should never happen if callers are behaving
|
||||
panic("parseTupleCons called without peeker pointing to open bracket")
|
||||
}
|
||||
|
||||
var close Token
|
||||
|
||||
p.PushIncludeNewlines(false)
|
||||
defer p.PopIncludeNewlines()
|
||||
|
||||
var diags zcl.Diagnostics
|
||||
var exprs []Expression
|
||||
|
||||
for {
|
||||
next := p.Peek()
|
||||
if next.Type == TokenCBrack {
|
||||
close = p.Read() // eat closer
|
||||
break
|
||||
}
|
||||
|
||||
expr, exprDiags := p.ParseExpression()
|
||||
exprs = append(exprs, expr)
|
||||
diags = append(diags, exprDiags...)
|
||||
|
||||
if p.recovery && exprDiags.HasErrors() {
|
||||
// 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
|
||||
// to after our closing bracket to allow parsing to continue.
|
||||
close = p.recover(TokenCBrack)
|
||||
break
|
||||
}
|
||||
|
||||
next = p.Peek()
|
||||
if next.Type == TokenCBrack {
|
||||
close = p.Read() // eat closer
|
||||
break
|
||||
}
|
||||
|
||||
if next.Type != TokenComma {
|
||||
if !p.recovery {
|
||||
diags = append(diags, &zcl.Diagnostic{
|
||||
Severity: zcl.DiagError,
|
||||
Summary: "Missing item separator",
|
||||
Detail: "Expected a comma to mark the beginning of the next item.",
|
||||
Subject: &next.Range,
|
||||
Context: zcl.RangeBetween(open.Range, next.Range).Ptr(),
|
||||
})
|
||||
}
|
||||
close = p.recover(TokenCBrack)
|
||||
break
|
||||
}
|
||||
|
||||
p.Read() // eat comma
|
||||
|
||||
}
|
||||
|
||||
return &TupleConsExpr{
|
||||
Exprs: exprs,
|
||||
|
||||
SrcRange: zcl.RangeBetween(open.Range, close.Range),
|
||||
OpenRange: open.Range,
|
||||
}, diags
|
||||
}
|
||||
|
||||
func (p *parser) ParseTemplate(end TokenType) (Expression, zcl.Diagnostics) {
|
||||
var parts []Expression
|
||||
var diags zcl.Diagnostics
|
||||
@ -1061,7 +1130,7 @@ func (p *parser) setRecovery() {
|
||||
// the end of the _current_ instance of that bracketer, skipping over any
|
||||
// nested instances. This is a best-effort operation and may have
|
||||
// unpredictable results on input with bad bracketer nesting.
|
||||
func (p *parser) recover(end TokenType) {
|
||||
func (p *parser) recover(end TokenType) Token {
|
||||
start := p.oppositeBracket(end)
|
||||
p.recovery = true
|
||||
|
||||
@ -1082,12 +1151,12 @@ func (p *parser) recover(end TokenType) {
|
||||
nest++
|
||||
case end:
|
||||
if nest < 1 {
|
||||
return
|
||||
return tok
|
||||
}
|
||||
|
||||
nest--
|
||||
case TokenEOF:
|
||||
return
|
||||
return tok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user