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 {
|
func (e *ConditionalExpr) StartRange() zcl.Range {
|
||||||
return e.Condition.StartRange()
|
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"),
|
cty.StringVal("FOO"),
|
||||||
0,
|
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 {
|
for _, test := range tests {
|
||||||
|
@ -31,6 +31,10 @@ func (e *TemplateExpr) Variables() []zcl.Traversal {
|
|||||||
return Variables(e)
|
return Variables(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *TupleConsExpr) Variables() []zcl.Traversal {
|
||||||
|
return Variables(e)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *UnaryOpExpr) Variables() []zcl.Traversal {
|
func (e *UnaryOpExpr) Variables() []zcl.Traversal {
|
||||||
return Variables(e)
|
return Variables(e)
|
||||||
}
|
}
|
||||||
|
@ -587,6 +587,9 @@ func (p *parser) parseExpressionTerm() (Expression, zcl.Diagnostics) {
|
|||||||
SymbolRange: tok.Range,
|
SymbolRange: tok.Range,
|
||||||
}, diags
|
}, diags
|
||||||
|
|
||||||
|
case TokenOBrack:
|
||||||
|
return p.parseTupleCons()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var diags zcl.Diagnostics
|
var diags zcl.Diagnostics
|
||||||
if !p.recovery {
|
if !p.recovery {
|
||||||
@ -683,6 +686,72 @@ Token:
|
|||||||
}, diags
|
}, 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) {
|
func (p *parser) ParseTemplate(end TokenType) (Expression, zcl.Diagnostics) {
|
||||||
var parts []Expression
|
var parts []Expression
|
||||||
var diags zcl.Diagnostics
|
var diags zcl.Diagnostics
|
||||||
@ -1061,7 +1130,7 @@ func (p *parser) setRecovery() {
|
|||||||
// the end of the _current_ instance of that bracketer, skipping over any
|
// the end of the _current_ instance of that bracketer, skipping over any
|
||||||
// nested instances. This is a best-effort operation and may have
|
// nested instances. This is a best-effort operation and may have
|
||||||
// unpredictable results on input with bad bracketer nesting.
|
// 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)
|
start := p.oppositeBracket(end)
|
||||||
p.recovery = true
|
p.recovery = true
|
||||||
|
|
||||||
@ -1082,12 +1151,12 @@ func (p *parser) recover(end TokenType) {
|
|||||||
nest++
|
nest++
|
||||||
case end:
|
case end:
|
||||||
if nest < 1 {
|
if nest < 1 {
|
||||||
return
|
return tok
|
||||||
}
|
}
|
||||||
|
|
||||||
nest--
|
nest--
|
||||||
case TokenEOF:
|
case TokenEOF:
|
||||||
return
|
return tok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user