Skip to content

Commit

Permalink
Add support for trailing comma in arrays and maps
Browse files Browse the repository at this point in the history
  • Loading branch information
antonmedv committed Mar 4, 2020
1 parent 3607640 commit b72131b
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 9 deletions.
35 changes: 26 additions & 9 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,22 @@ func (p *parser) parseClosure() Node {
}

func (p *parser) parseArrayExpression(token Token) Node {
nodes := p.parseList("[", "]")
nodes := make([]Node, 0)

p.expect(Bracket, "[")
for !p.current.Is(Bracket, "]") && p.err == nil {
if len(nodes) > 0 {
p.expect(Operator, ",")
if p.current.Is(Bracket, "]") {
goto end
}
}
node := p.parseExpression(0)
nodes = append(nodes, node)
}
end:
p.expect(Bracket, "]")

return &ArrayNode{Base: Loc(token.Location), Nodes: nodes}
}

Expand All @@ -384,6 +399,12 @@ func (p *parser) parseMapExpression(token Token) Node {
for !p.current.Is(Bracket, "}") && p.err == nil {
if len(nodes) > 0 {
p.expect(Operator, ",")
if p.current.Is(Bracket, "}") {
goto end
}
if p.current.Is(Operator, ",") {
p.error("unexpected token %v", p.current)
}
}

var key Node
Expand All @@ -407,6 +428,7 @@ func (p *parser) parseMapExpression(token Token) Node {
nodes = append(nodes, &PairNode{Base: Loc(token.Location), Key: key, Value: node})
}

end:
p.expect(Bracket, "}")

return &MapNode{Base: Loc(token.Location), Pairs: nodes}
Expand Down Expand Up @@ -526,21 +548,16 @@ func isAlphabetic(r rune) bool {
}

func (p *parser) parseArguments() []Node {
return p.parseList("(", ")")
}

func (p *parser) parseList(start, end string) []Node {
p.expect(Bracket, start)

p.expect(Bracket, "(")
nodes := make([]Node, 0)
for !p.current.Is(Bracket, end) && p.err == nil {
for !p.current.Is(Bracket, ")") && p.err == nil {
if len(nodes) > 0 {
p.expect(Operator, ",")
}
node := p.parseExpression(0)
nodes = append(nodes, node)
}
p.expect(Bracket, ")")

p.expect(Bracket, end)
return nodes
}
32 changes: 32 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ func TestParse(t *testing.T) {
"{foo:1, bar:2}",
&ast.MapNode{Pairs: []ast.Node{&ast.PairNode{Key: &ast.StringNode{Value: "foo"}, Value: &ast.IntegerNode{Value: 1}}, &ast.PairNode{Key: &ast.StringNode{Value: "bar"}, Value: &ast.IntegerNode{Value: 2}}}},
},
{
"{foo:1, bar:2, }",
&ast.MapNode{Pairs: []ast.Node{&ast.PairNode{Key: &ast.StringNode{Value: "foo"}, Value: &ast.IntegerNode{Value: 1}}, &ast.PairNode{Key: &ast.StringNode{Value: "bar"}, Value: &ast.IntegerNode{Value: 2}}}},
},
{
`{"a": 1, 'b': 2}`,
&ast.MapNode{Pairs: []ast.Node{&ast.PairNode{Key: &ast.StringNode{Value: "a"}, Value: &ast.IntegerNode{Value: 1}}, &ast.PairNode{Key: &ast.StringNode{Value: "b"}, Value: &ast.IntegerNode{Value: 2}}}},
Expand Down Expand Up @@ -214,6 +218,14 @@ func TestParse(t *testing.T) {
"array[:]",
&ast.SliceNode{Node: &ast.IdentifierNode{Value: "array"}},
},
{
"[]",
&ast.ArrayNode{},
},
{
"[1, 2, 3,]",
&ast.ArrayNode{Nodes: []ast.Node{&ast.IntegerNode{Value: 1}, &ast.IntegerNode{Value: 2}, &ast.IntegerNode{Value: 3}}},
},
}
for _, test := range parseTests {
actual, err := parser.Parse(test.input)
Expand Down Expand Up @@ -274,6 +286,26 @@ a map key must be a quoted string, a number, a identifier, or an expression encl
cannot use pointer accessor outside closure (1:1)
| .foo
| ^
[1, 2, 3,,]
unexpected token Operator(",") (1:10)
| [1, 2, 3,,]
| .........^
[,]
unexpected token Operator(",") (1:2)
| [,]
| .^
{,}
a map key must be a quoted string, a number, a identifier, or an expression enclosed in parentheses (unexpected token Operator(",")) (1:2)
| {,}
| .^
{foo:1, bar:2, ,}
unexpected token Operator(",") (1:16)
| {foo:1, bar:2, ,}
| ...............^
`

func TestParse_error(t *testing.T) {
Expand Down

0 comments on commit b72131b

Please sign in to comment.