Skip to content

Commit f34318a

Browse files
committed
Support chained comparison
1 parent 6cc56e7 commit f34318a

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed

Diff for: expr_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,26 @@ func TestExpr(t *testing.T) {
12371237
`[nil, 3, 4]?.[0]?.[1]`,
12381238
nil,
12391239
},
1240+
{
1241+
`1 > 2 < 3`,
1242+
false,
1243+
},
1244+
{
1245+
`1 < 2 < 3`,
1246+
true,
1247+
},
1248+
{
1249+
`1 < 2 < 3 > 4`,
1250+
false,
1251+
},
1252+
{
1253+
`1 < 2 < 3 > 2`,
1254+
true,
1255+
},
1256+
{
1257+
`1 < 2 < 3 == true`,
1258+
true,
1259+
},
12401260
}
12411261

12421262
for _, tt := range tests {

Diff for: parser/operator/operator.go

+4
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,7 @@ var Binary = map[string]Operator{
5454
"^": {100, Right},
5555
"??": {500, Left},
5656
}
57+
58+
func IsComparison(op string) bool {
59+
return op == "<" || op == ">" || op == ">=" || op == "<="
60+
}

Diff for: parser/parser.go

+36
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ func (p *parser) parseExpression(precedence int) Node {
164164
break
165165
}
166166

167+
if operator.IsComparison(opToken.Value) {
168+
nodeLeft = p.parseComparison(nodeLeft, opToken, op.Precedence)
169+
goto next
170+
}
171+
167172
var nodeRight Node
168173
if op.Associativity == operator.Left {
169174
nodeRight = p.parseExpression(op.Precedence + 1)
@@ -685,3 +690,34 @@ func (p *parser) parsePostfixExpression(node Node) Node {
685690
}
686691
return node
687692
}
693+
694+
func (p *parser) parseComparison(left Node, token Token, precedence int) Node {
695+
var rootNode Node
696+
for {
697+
comparator := p.parseExpression(precedence + 1)
698+
cmpNode := &BinaryNode{
699+
Operator: token.Value,
700+
Left: left,
701+
Right: comparator,
702+
}
703+
cmpNode.SetLocation(token.Location)
704+
if rootNode == nil {
705+
rootNode = cmpNode
706+
} else {
707+
rootNode = &BinaryNode{
708+
Operator: "&&",
709+
Left: rootNode,
710+
Right: cmpNode,
711+
}
712+
rootNode.SetLocation(token.Location)
713+
}
714+
715+
left = comparator
716+
token = p.current
717+
if !(token.Is(Operator) && operator.IsComparison(token.Value) && p.err == nil) {
718+
break
719+
}
720+
p.next()
721+
}
722+
return rootNode
723+
}

Diff for: parser/parser_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,46 @@ world`},
531531
To: &IntegerNode{Value: 3},
532532
},
533533
},
534+
{
535+
`1 < 2 > 3`,
536+
&BinaryNode{
537+
Operator: "&&",
538+
Left: &BinaryNode{
539+
Operator: "<",
540+
Left: &IntegerNode{Value: 1},
541+
Right: &IntegerNode{Value: 2},
542+
},
543+
Right: &BinaryNode{
544+
Operator: ">",
545+
Left: &IntegerNode{Value: 2},
546+
Right: &IntegerNode{Value: 3},
547+
},
548+
},
549+
},
550+
{
551+
`1 < 2 < 3 < 4`,
552+
&BinaryNode{
553+
Operator: "&&",
554+
Left: &BinaryNode{
555+
Operator: "&&",
556+
Left: &BinaryNode{
557+
Operator: "<",
558+
Left: &IntegerNode{Value: 1},
559+
Right: &IntegerNode{Value: 2},
560+
},
561+
Right: &BinaryNode{
562+
Operator: "<",
563+
Left: &IntegerNode{Value: 2},
564+
Right: &IntegerNode{Value: 3},
565+
},
566+
},
567+
Right: &BinaryNode{
568+
Operator: "<",
569+
Left: &IntegerNode{Value: 3},
570+
Right: &IntegerNode{Value: 4},
571+
},
572+
},
573+
},
534574
}
535575
for _, test := range tests {
536576
t.Run(test.input, func(t *testing.T) {

0 commit comments

Comments
 (0)