Skip to content

Commit 4023ef3

Browse files
bizywizyantonmedv
authored andcommitted
Support chzained comparisonc1 < 2 < 3 (#581)
1 parent ef57900 commit 4023ef3

File tree

4 files changed

+120
-0
lines changed

4 files changed

+120
-0
lines changed

Diff for: expr_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,26 @@ func TestExpr(t *testing.T) {
12531253
`[nil, 3, 4]?.[0]?.[1]`,
12541254
nil,
12551255
},
1256+
{
1257+
`1 > 2 < 3`,
1258+
false,
1259+
},
1260+
{
1261+
`1 < 2 < 3`,
1262+
true,
1263+
},
1264+
{
1265+
`1 < 2 < 3 > 4`,
1266+
false,
1267+
},
1268+
{
1269+
`1 < 2 < 3 > 2`,
1270+
true,
1271+
},
1272+
{
1273+
`1 < 2 < 3 == true`,
1274+
true,
1275+
},
12561276
}
12571277

12581278
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

+60
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,66 @@ 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+
},
574+
{
575+
`1 < 2 < 3 == true`,
576+
&BinaryNode{
577+
Operator: "==",
578+
Left: &BinaryNode{
579+
Operator: "&&",
580+
Left: &BinaryNode{
581+
Operator: "<",
582+
Left: &IntegerNode{Value: 1},
583+
Right: &IntegerNode{Value: 2},
584+
},
585+
Right: &BinaryNode{
586+
Operator: "<",
587+
Left: &IntegerNode{Value: 2},
588+
Right: &IntegerNode{Value: 3},
589+
},
590+
},
591+
Right: &BoolNode{Value: true},
592+
},
593+
},
534594
}
535595
for _, test := range tests {
536596
t.Run(test.input, func(t *testing.T) {

0 commit comments

Comments
 (0)