zclsyntax: parsing of attributes within bodies

This commit is contained in:
Martin Atkins 2017-06-02 08:12:33 -07:00
parent a1368a4d4d
commit 4d6dbdbb37
3 changed files with 85 additions and 2 deletions

View File

@ -151,7 +151,46 @@ func (p *parser) ParseBodyItem() (Node, zcl.Diagnostics) {
}
func (p *parser) finishParsingBodyAttribute(ident Token) (Node, zcl.Diagnostics) {
panic("attribute parsing not yet implemented")
eqTok := p.Read() // eat equals token
if eqTok.Type != TokenEqual {
// should never happen if caller behaves
panic("finishParsingBodyAttribute called with next not equals")
}
expr, diags := p.ParseExpression()
if p.recovery && diags.HasErrors() {
// recovery within expressions tends to be tricky, so we've probably
// landed somewhere weird. We'll try to reset to the start of a body
// item so parsing can continue.
p.recoverAfterBodyItem()
} else {
end := p.Peek()
if end.Type != TokenNewline && end.Type != TokenEOF {
if !p.recovery {
diags = append(diags, &zcl.Diagnostic{
Severity: zcl.DiagError,
Summary: "Missing newline in attribute definition",
Detail: "An attribute definition must end with a newline.",
Subject: &end.Range,
Context: zcl.RangeBetween(ident.Range, end.Range).Ptr(),
})
}
p.recoverAfterBodyItem()
} else {
p.Read() // eat newline
}
}
endRange := p.PrevRange()
return &Attribute{
Name: string(ident.Bytes),
Expr: expr,
SrcRange: zcl.RangeBetween(ident.Range, endRange),
NameRange: ident.Range,
EqualsRange: eqTok.Range,
}, diags
}
func (p *parser) finishParsingBodyBlock(ident Token) (Node, zcl.Diagnostics) {

View File

@ -5,6 +5,7 @@ import (
"testing"
"github.com/kylelemons/godebug/pretty"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-zcl/zcl"
)
@ -313,6 +314,48 @@ block "valid" {}
},
},
},
{
`a = 1`,
0,
&Body{
Attributes: Attributes{
"a": {
Name: "a",
Expr: &LiteralValueExpr{
Val: cty.NumberIntVal(1),
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 5, Byte: 4},
End: zcl.Pos{Line: 1, Column: 6, Byte: 5},
},
},
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 6, Byte: 5},
},
NameRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 2, Byte: 1},
},
EqualsRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 3, Byte: 2},
End: zcl.Pos{Line: 1, Column: 4, Byte: 3},
},
},
},
Blocks: Blocks{},
SrcRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 1, Byte: 0},
End: zcl.Pos{Line: 1, Column: 6, Byte: 5},
},
EndRange: zcl.Range{
Start: zcl.Pos{Line: 1, Column: 6, Byte: 5},
End: zcl.Pos{Line: 1, Column: 6, Byte: 5},
},
},
},
}
prettyConfig := &pretty.Config{

View File

@ -92,6 +92,7 @@ type Attribute struct {
Name string
Expr Expression
SrcRange zcl.Range
NameRange zcl.Range
EqualsRange zcl.Range
}
@ -101,7 +102,7 @@ func (a *Attribute) walkChildNodes(w internalWalkFunc) {
}
func (a *Attribute) Range() zcl.Range {
return zcl.RangeBetween(a.NameRange, a.Expr.Range())
return a.SrcRange
}
// Blocks is the list of nested blocks within a body.