zclwrite: parsing of blocks

There's something a little off here, as illustrated by the failing
round trip test. Will figure that out later.
This commit is contained in:
Martin Atkins 2017-06-10 17:16:19 -07:00
parent 948b2e0b7b
commit cb768a591a
3 changed files with 552 additions and 5 deletions

View File

@ -195,8 +195,7 @@ func parseBodyItem(nativeItem zclsyntax.Node, from inputTokens) (inputTokens, No
case *zclsyntax.Attribute:
item = parseAttribute(tItem, within, leadComments, lineComments, newline)
case *zclsyntax.Block:
// TODO: implement this
panic("block parsing not yet implemented")
item = parseBlock(tItem, within, leadComments, lineComments, newline)
default:
// should never happen if caller is behaving
panic("unsupported native item type")
@ -255,6 +254,78 @@ func parseAttribute(nativeAttr *zclsyntax.Attribute, from, leadComments, lineCom
return attr
}
func parseBlock(nativeBlock *zclsyntax.Block, from, leadComments, lineComments, newline inputTokens) *Block {
var allTokens TokenSeq
block := &Block{}
if leadComments.Len() > 0 {
block.LeadCommentTokens = leadComments.Seq()
allTokens = append(allTokens, block.LeadCommentTokens)
}
before, typeTokens, from := from.Partition(nativeBlock.TypeRange)
if before.Len() > 0 {
allTokens = append(allTokens, before.Seq())
}
block.TypeTokens = typeTokens.Seq()
allTokens = append(allTokens, block.TypeTokens)
for _, rng := range nativeBlock.LabelRanges {
var labelTokens inputTokens
before, labelTokens, from = from.Partition(rng)
if before.Len() > 0 {
allTokens = append(allTokens, before.Seq())
}
seq := labelTokens.Seq()
block.LabelTokens = append(block.LabelTokens, seq)
*(block.LabelTokensFlat) = append(*(block.LabelTokensFlat), seq)
allTokens = append(allTokens, seq)
}
before, oBrace, from := from.Partition(nativeBlock.OpenBraceRange)
if before.Len() > 0 {
allTokens = append(allTokens, before.Seq())
}
block.OBraceTokens = oBrace.Seq()
allTokens = append(allTokens, block.OBraceTokens)
// We go a bit out of order here: we go hunting for the closing brace
// so that we have a delimited body, but then we'll deal with the body
// before we actually append the closing brace and any straggling tokens
// that appear after it.
bodyTokens, cBrace, from := from.Partition(nativeBlock.CloseBraceRange)
before, body, after := parseBody(nativeBlock.Body, bodyTokens)
if before.Len() > 0 {
allTokens = append(allTokens, before.Seq())
}
block.Body = body
allTokens = append(allTokens, body.AllTokens)
if after.Len() > 0 {
allTokens = append(allTokens, after.Seq())
}
block.CBraceTokens = cBrace.Seq()
allTokens = append(allTokens, block.CBraceTokens)
// stragglers
if after.Len() > 0 {
allTokens = append(allTokens, from.Seq())
}
if lineComments.Len() > 0 {
// blocks don't actually have line comments, so we'll just treat
// them as extra stragglers
allTokens = append(allTokens, lineComments.Seq())
}
if newline.Len() > 0 {
block.EOLTokens = newline.Seq()
allTokens = append(allTokens, block.EOLTokens)
}
block.AllTokens = &allTokens
return block
}
func parseExpression(nativeExpr zclsyntax.Expression, from inputTokens) *Expression {
// TODO: Populate VarRefs by analyzing the result of nativeExpr.Variables()
return &Expression{
@ -336,7 +407,7 @@ func partitionTokens(toks zclsyntax.Tokens, rng zcl.Range) (start, end int) {
return len(toks), len(toks)
}
if toks[i].Range.ContainsOffset(rng.Start.Byte) {
if toks[i].Range.Start.Byte >= rng.Start.Byte {
start = i
break
}
@ -348,8 +419,8 @@ func partitionTokens(toks zclsyntax.Tokens, rng zcl.Range) (start, end int) {
return start, len(toks)
}
if toks[i].Range.End.Byte >= rng.End.Byte {
end = i + 1 // end marker is exclusive
if toks[i].Range.Start.Byte >= rng.End.Byte {
end = i // end marker is exclusive
break
}
}

View File

@ -530,6 +530,468 @@ func TestParse(t *testing.T) {
},
},
},
{
"b {}\n",
&Body{
Items: []Node{
&Block{
AllTokens: &TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`b`),
SpacesBefore: 0,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenOBrace,
Bytes: []byte(`{`),
SpacesBefore: 1,
},
},
},
(*TokenSeq)(nil), // the empty body
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenCBrace,
Bytes: []byte(`}`),
SpacesBefore: 0,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
},
TypeTokens: &TokenSeq{Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`b`),
SpacesBefore: 0,
},
}},
OBraceTokens: &TokenSeq{Tokens{
{
Type: zclsyntax.TokenOBrace,
Bytes: []byte(`{`),
SpacesBefore: 1,
},
}},
Body: &Body{},
CBraceTokens: &TokenSeq{Tokens{
{
Type: zclsyntax.TokenCBrace,
Bytes: []byte(`}`),
SpacesBefore: 0,
},
}},
EOLTokens: &TokenSeq{Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
}},
},
},
AllTokens: &TokenSeq{
&TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`b`),
SpacesBefore: 0,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenOBrace,
Bytes: []byte(`{`),
SpacesBefore: 1,
},
},
},
(*TokenSeq)(nil), // the empty body
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenCBrace,
Bytes: []byte(`}`),
SpacesBefore: 0,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
},
},
},
},
{
"b {\n a = 1\n}\n",
&Body{
Items: []Node{
&Block{
AllTokens: &TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`b`),
SpacesBefore: 0,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenOBrace,
Bytes: []byte(`{`),
SpacesBefore: 1,
},
},
},
&TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
&TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`a`),
SpacesBefore: 2,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenEqual,
Bytes: []byte(`=`),
SpacesBefore: 1,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNumberLit,
Bytes: []byte(`1`),
SpacesBefore: 1,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenCBrace,
Bytes: []byte(`}`),
SpacesBefore: 0,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
},
TypeTokens: &TokenSeq{Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`b`),
SpacesBefore: 0,
},
}},
OBraceTokens: &TokenSeq{Tokens{
{
Type: zclsyntax.TokenOBrace,
Bytes: []byte(`{`),
SpacesBefore: 1,
},
}},
Body: &Body{
Items: []Node{
&Attribute{
AllTokens: &TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`a`),
SpacesBefore: 2,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenEqual,
Bytes: []byte(`=`),
SpacesBefore: 1,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNumberLit,
Bytes: []byte(`1`),
SpacesBefore: 1,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
},
NameTokens: &TokenSeq{
Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`a`),
SpacesBefore: 2,
},
},
},
EqualsTokens: &TokenSeq{
Tokens{
{
Type: zclsyntax.TokenEqual,
Bytes: []byte(`=`),
SpacesBefore: 1,
},
},
},
Expr: &Expression{
AllTokens: &TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNumberLit,
Bytes: []byte(`1`),
SpacesBefore: 1,
},
},
},
},
EOLTokens: &TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
},
},
AllTokens: &TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
&TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`a`),
SpacesBefore: 2,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenEqual,
Bytes: []byte(`=`),
SpacesBefore: 1,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNumberLit,
Bytes: []byte(`1`),
SpacesBefore: 1,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
},
},
},
CBraceTokens: &TokenSeq{Tokens{
{
Type: zclsyntax.TokenCBrace,
Bytes: []byte(`}`),
SpacesBefore: 0,
},
}},
EOLTokens: &TokenSeq{Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
}},
},
},
AllTokens: &TokenSeq{
&TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`b`),
SpacesBefore: 0,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenOBrace,
Bytes: []byte(`{`),
SpacesBefore: 1,
},
},
},
&TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
&TokenSeq{
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenIdent,
Bytes: []byte(`a`),
SpacesBefore: 2,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenEqual,
Bytes: []byte(`=`),
SpacesBefore: 1,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNumberLit,
Bytes: []byte(`1`),
SpacesBefore: 1,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenCBrace,
Bytes: []byte(`}`),
SpacesBefore: 0,
},
},
},
&TokenSeq{
Tokens{
{
Type: zclsyntax.TokenNewline,
Bytes: []byte{'\n'},
SpacesBefore: 0,
},
},
},
},
},
},
},
}
prettyConfig := &pretty.Config{

View File

@ -27,6 +27,20 @@ baz = 1
foobar = 1
baz = 1
block {
a = "a"
b = "b"
c = "c"
d = "d"
subblock {
}
subblock {
e = "e"
}
}
# and they all lived happily ever after
`,
}