diff --git a/zclwrite/ast.go b/zclwrite/ast.go index 3a079f5..3edc7cb 100644 --- a/zclwrite/ast.go +++ b/zclwrite/ast.go @@ -77,13 +77,17 @@ type Attribute struct { LeadCommentTokens *TokenSeq NameTokens *TokenSeq EqualsTokens *TokenSeq - Value *Expression + Expr *Expression LineCommentTokens *TokenSeq EOLTokens *TokenSeq } func (a *Attribute) walkChildNodes(w internalWalkFunc) { - w(a.Value) + w(a.Expr) +} + +func (n *Attribute) Tokens() *TokenSeq { + return n.AllTokens } type Block struct { diff --git a/zclwrite/parser.go b/zclwrite/parser.go index 6ae70f3..6e4210e 100644 --- a/zclwrite/parser.go +++ b/zclwrite/parser.go @@ -146,12 +146,11 @@ func parseBodyItem(nativeItem zclsyntax.Node, from inputTokens) (inputTokens, No var item Node - switch nativeItem.(type) { + switch tItem := nativeItem.(type) { case *zclsyntax.Attribute: - // TODO: actually deconstruct the attribute parts - item = &Unstructured{ - AllTokens: within.Seq(), - } + item = parseAttribute(tItem, within) + // TODO: Grab the newline and any line comment from "after" and + // write them into the attribute object. case *zclsyntax.Block: // TODO: actually deconstruct the block parts item = &Unstructured{ @@ -165,6 +164,50 @@ func parseBodyItem(nativeItem zclsyntax.Node, from inputTokens) (inputTokens, No return before, item, after } +func parseAttribute(nativeAttr *zclsyntax.Attribute, from inputTokens) *Attribute { + var allTokens TokenSeq + attr := &Attribute{} + + before, nameTokens, from := from.Partition(nativeAttr.NameRange) + if before.Len() > 0 { + allTokens = append(allTokens, before.Seq()) + } + attr.NameTokens = nameTokens.Seq() + allTokens = append(allTokens, attr.NameTokens) + + before, equalsTokens, from := from.Partition(nativeAttr.EqualsRange) + if before.Len() > 0 { + allTokens = append(allTokens, before.Seq()) + } + attr.EqualsTokens = equalsTokens.Seq() + allTokens = append(allTokens, attr.EqualsTokens) + + before, exprTokens, from := from.Partition(nativeAttr.Expr.Range()) + if before.Len() > 0 { + allTokens = append(allTokens, before.Seq()) + } + attr.Expr = parseExpression(nativeAttr.Expr, exprTokens) + allTokens = append(allTokens, attr.Expr.AllTokens) + + // Collect any stragglers, although we shouldn't generally have any since + // the newline and any line comments don't get included in the attribute's + // range. + if from.Len() > 0 { + allTokens = append(allTokens, from.Seq()) + } + + attr.AllTokens = &allTokens + + return attr +} + +func parseExpression(nativeExpr zclsyntax.Expression, from inputTokens) *Expression { + // TODO: Populate VarRefs by analyzing the result of nativeExpr.Variables() + return &Expression{ + AllTokens: from.Seq(), + } +} + // writerTokens takes a sequence of tokens as produced by the main zclsyntax // package and transforms it into an equivalent sequence of tokens using // this package's own token model. diff --git a/zclwrite/parser_test.go b/zclwrite/parser_test.go index 26fd979..802d3a4 100644 --- a/zclwrite/parser_test.go +++ b/zclwrite/parser_test.go @@ -27,43 +27,88 @@ func TestParse(t *testing.T) { "a = 1", &Body{ Items: []Node{ - &Unstructured{ - AllTokens: &TokenSeq{Tokens{ + &Attribute{ + AllTokens: &TokenSeq{ + &TokenSeq{ + Tokens{ + { + Type: zclsyntax.TokenIdent, + Bytes: []byte(`a`), + SpacesBefore: 0, + }, + }, + }, + &TokenSeq{ + Tokens{ + { + Type: zclsyntax.TokenEqual, + Bytes: []byte(`=`), + SpacesBefore: 1, + }, + }, + }, + &TokenSeq{ + Tokens{ + { + Type: zclsyntax.TokenNumberLit, + Bytes: []byte(`1`), + SpacesBefore: 1, + }, + }, + }, + }, + NameTokens: &TokenSeq{Tokens{ { Type: zclsyntax.TokenIdent, Bytes: []byte(`a`), SpacesBefore: 0, }, + }}, + EqualsTokens: &TokenSeq{Tokens{ { Type: zclsyntax.TokenEqual, Bytes: []byte(`=`), SpacesBefore: 1, }, - { - Type: zclsyntax.TokenNumberLit, - Bytes: []byte(`1`), - SpacesBefore: 1, - }, }}, + Expr: &Expression{ + AllTokens: &TokenSeq{Tokens{ + { + Type: zclsyntax.TokenNumberLit, + Bytes: []byte(`1`), + SpacesBefore: 1, + }, + }}, + }, }, }, AllTokens: &TokenSeq{ &TokenSeq{ - Tokens{ - { - Type: zclsyntax.TokenIdent, - Bytes: []byte(`a`), - SpacesBefore: 0, + &TokenSeq{ + Tokens{ + { + Type: zclsyntax.TokenIdent, + Bytes: []byte(`a`), + SpacesBefore: 0, + }, }, - { - Type: zclsyntax.TokenEqual, - Bytes: []byte(`=`), - SpacesBefore: 1, + }, + &TokenSeq{ + Tokens{ + { + Type: zclsyntax.TokenEqual, + Bytes: []byte(`=`), + SpacesBefore: 1, + }, }, - { - Type: zclsyntax.TokenNumberLit, - Bytes: []byte(`1`), - SpacesBefore: 1, + }, + &TokenSeq{ + Tokens{ + { + Type: zclsyntax.TokenNumberLit, + Bytes: []byte(`1`), + SpacesBefore: 1, + }, }, }, },