Skip to content

Commit e750878

Browse files
committed
Add SequenceNode
Fixes #717
1 parent 8bb9ab7 commit e750878

File tree

5 files changed

+99
-13
lines changed

5 files changed

+99
-13
lines changed

ast/node.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@ type VariableDeclaratorNode struct {
216216
Expr Node // Expression of the variable. Like "foo + 1" in "let foo = 1; foo + 1".
217217
}
218218

219+
// SequenceNode represents a sequence of nodes separated by semicolons.
220+
// All nodes are executed, only the last node will be returned.
221+
type SequenceNode struct {
222+
base
223+
Nodes []Node
224+
}
225+
219226
// ArrayNode represents an array.
220227
type ArrayNode struct {
221228
base

ast/print.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ func (n *BinaryNode) String() string {
8383
if operator.Less(lb.Operator, n.Operator) {
8484
lwrap = true
8585
}
86-
if operator.Binary[lb.Operator].Precedence ==
87-
operator.Binary[n.Operator].Precedence &&
86+
if operator.Binary[lb.Operator].Precedence ==
87+
operator.Binary[n.Operator].Precedence &&
8888
operator.Binary[n.Operator].Associativity == operator.Right {
8989
lwrap = true
9090
}
@@ -99,8 +99,8 @@ func (n *BinaryNode) String() string {
9999
if operator.Less(rb.Operator, n.Operator) {
100100
rwrap = true
101101
}
102-
if operator.Binary[rb.Operator].Precedence ==
103-
operator.Binary[n.Operator].Precedence &&
102+
if operator.Binary[rb.Operator].Precedence ==
103+
operator.Binary[n.Operator].Precedence &&
104104
operator.Binary[n.Operator].Associativity == operator.Left {
105105
rwrap = true
106106
}
@@ -198,6 +198,14 @@ func (n *VariableDeclaratorNode) String() string {
198198
return fmt.Sprintf("let %s = %s; %s", n.Name, n.Value.String(), n.Expr.String())
199199
}
200200

201+
func (n *SequenceNode) String() string {
202+
nodes := make([]string, len(n.Nodes))
203+
for i, node := range n.Nodes {
204+
nodes[i] = node.String()
205+
}
206+
return strings.Join(nodes, "; ")
207+
}
208+
201209
func (n *ConditionalNode) String() string {
202210
var cond, exp1, exp2 string
203211
if _, ok := n.Cond.(*ConditionalNode); ok {

ast/visitor.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ func Walk(node *Node, v Visitor) {
5151
case *VariableDeclaratorNode:
5252
Walk(&n.Value, v)
5353
Walk(&n.Expr, v)
54+
case *SequenceNode:
55+
for i := range n.Nodes {
56+
Walk(&n.Nodes[i], v)
57+
}
5458
case *ConditionalNode:
5559
Walk(&n.Cond, v)
5660
Walk(&n.Exp1, v)

parser/parser.go

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,11 @@ type parser struct {
4949
current Token
5050
pos int
5151
err *file.Error
52-
depth int // predicate call depth
5352
config *conf.Config
53+
depth int // predicate call depth
5454
nodeCount uint // tracks number of AST nodes created
5555
}
5656

57-
// checkNodeLimit verifies that adding a new node won't exceed configured limits
5857
func (p *parser) checkNodeLimit() error {
5958
p.nodeCount++
6059
if p.config.MaxNodes > 0 && p.nodeCount > p.config.MaxNodes {
@@ -64,7 +63,6 @@ func (p *parser) checkNodeLimit() error {
6463
return nil
6564
}
6665

67-
// createNode handles creation of regular nodes
6866
func (p *parser) createNode(n Node, loc file.Location) Node {
6967
if err := p.checkNodeLimit(); err != nil {
7068
return nil
@@ -76,7 +74,6 @@ func (p *parser) createNode(n Node, loc file.Location) Node {
7674
return n
7775
}
7876

79-
// createMemberNode handles creation of member nodes
8077
func (p *parser) createMemberNode(n *MemberNode, loc file.Location) *MemberNode {
8178
if err := p.checkNodeLimit(); err != nil {
8279
return nil
@@ -163,6 +160,27 @@ func (p *parser) expect(kind Kind, values ...string) {
163160

164161
// parse functions
165162

163+
func (p *parser) parseSequenceExpression() Node {
164+
nodes := []Node{p.parseExpression(0)}
165+
166+
for p.current.Is(Operator, ";") && p.err == nil {
167+
p.next()
168+
// If a trailing semicolon is present, break out.
169+
if p.current.Is(EOF) {
170+
break
171+
}
172+
nodes = append(nodes, p.parseExpression(0))
173+
}
174+
175+
if len(nodes) == 1 {
176+
return nodes[0]
177+
}
178+
179+
return p.createNode(&SequenceNode{
180+
Nodes: nodes,
181+
}, nodes[0].Location())
182+
}
183+
166184
func (p *parser) parseExpression(precedence int) Node {
167185
if p.err != nil {
168186
return nil
@@ -171,6 +189,7 @@ func (p *parser) parseExpression(precedence int) Node {
171189
if precedence == 0 && p.current.Is(Operator, "let") {
172190
return p.parseVariableDeclaration()
173191
}
192+
174193
if p.current.Is(Operator, "if") {
175194
return p.parseConditionalIf()
176195
}
@@ -283,11 +302,11 @@ func (p *parser) parseConditionalIf() Node {
283302
p.next()
284303
nodeCondition := p.parseExpression(0)
285304
p.expect(Bracket, "{")
286-
expr1 := p.parseExpression(0)
305+
expr1 := p.parseSequenceExpression()
287306
p.expect(Bracket, "}")
288307
p.expect(Operator, "else")
289308
p.expect(Bracket, "{")
290-
expr2 := p.parseExpression(0)
309+
expr2 := p.parseSequenceExpression()
291310
p.expect(Bracket, "}")
292311

293312
return &ConditionalNode{
@@ -304,13 +323,13 @@ func (p *parser) parseConditional(node Node) Node {
304323
p.next()
305324

306325
if !p.current.Is(Operator, ":") {
307-
expr1 = p.parseExpression(0)
326+
expr1 = p.parseSequenceExpression()
308327
p.expect(Operator, ":")
309-
expr2 = p.parseExpression(0)
328+
expr2 = p.parseSequenceExpression()
310329
} else {
311330
p.next()
312331
expr1 = node
313-
expr2 = p.parseExpression(0)
332+
expr2 = p.parseSequenceExpression()
314333
}
315334

316335
node = p.createNode(&ConditionalNode{

parser/parser_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,54 @@ world`},
659659
Exp1: &BoolNode{Value: true},
660660
Exp2: &IdentifierNode{Value: "x"}},
661661
},
662+
{
663+
"true ? 1; 2; 3 : 4",
664+
&ConditionalNode{
665+
Cond: &BoolNode{Value: true},
666+
Exp1: &SequenceNode{
667+
Nodes: []Node{
668+
&IntegerNode{Value: 1},
669+
&IntegerNode{Value: 2},
670+
&IntegerNode{Value: 3}}},
671+
Exp2: &IntegerNode{Value: 4}},
672+
},
673+
{
674+
"true ? 1 : 2; 3 ; 4",
675+
&ConditionalNode{
676+
Cond: &BoolNode{Value: true},
677+
Exp1: &IntegerNode{Value: 1},
678+
Exp2: &SequenceNode{
679+
Nodes: []Node{
680+
&IntegerNode{Value: 2},
681+
&IntegerNode{Value: 3},
682+
&IntegerNode{Value: 4}}}},
683+
},
684+
{
685+
"true ?: 1; 2; 3",
686+
&ConditionalNode{
687+
Cond: &BoolNode{Value: true},
688+
Exp1: &BoolNode{Value: true},
689+
Exp2: &SequenceNode{
690+
Nodes: []Node{
691+
&IntegerNode{Value: 1},
692+
&IntegerNode{Value: 2},
693+
&IntegerNode{Value: 3}}}},
694+
},
695+
{
696+
"if true { 1; 2; 3 } else { 4; 5; 6 }",
697+
&ConditionalNode{
698+
Cond: &BoolNode{Value: true},
699+
Exp1: &SequenceNode{
700+
Nodes: []Node{
701+
&IntegerNode{Value: 1},
702+
&IntegerNode{Value: 2},
703+
&IntegerNode{Value: 3}}},
704+
Exp2: &SequenceNode{
705+
Nodes: []Node{
706+
&IntegerNode{Value: 4},
707+
&IntegerNode{Value: 5},
708+
&IntegerNode{Value: 6}}}},
709+
},
662710
}
663711
for _, test := range tests {
664712
t.Run(test.input, func(t *testing.T) {

0 commit comments

Comments
 (0)