Support chzained comparisonc1 < 2 < 3 (#581)

This commit is contained in:
Sergey
2024-04-13 10:08:10 +02:00
committed by Anton Medvedev
parent db5a6defcb
commit 2be09b2554
4 changed files with 120 additions and 0 deletions
+20
View File
@@ -1253,6 +1253,26 @@ func TestExpr(t *testing.T) {
`[nil, 3, 4]?.[0]?.[1]`,
nil,
},
{
`1 > 2 < 3`,
false,
},
{
`1 < 2 < 3`,
true,
},
{
`1 < 2 < 3 > 4`,
false,
},
{
`1 < 2 < 3 > 2`,
true,
},
{
`1 < 2 < 3 == true`,
true,
},
}
for _, tt := range tests {
+4
View File
@@ -54,3 +54,7 @@ var Binary = map[string]Operator{
"^": {100, Right},
"??": {500, Left},
}
func IsComparison(op string) bool {
return op == "<" || op == ">" || op == ">=" || op == "<="
}
+36
View File
@@ -164,6 +164,11 @@ func (p *parser) parseExpression(precedence int) Node {
break
}
if operator.IsComparison(opToken.Value) {
nodeLeft = p.parseComparison(nodeLeft, opToken, op.Precedence)
goto next
}
var nodeRight Node
if op.Associativity == operator.Left {
nodeRight = p.parseExpression(op.Precedence + 1)
@@ -685,3 +690,34 @@ func (p *parser) parsePostfixExpression(node Node) Node {
}
return node
}
func (p *parser) parseComparison(left Node, token Token, precedence int) Node {
var rootNode Node
for {
comparator := p.parseExpression(precedence + 1)
cmpNode := &BinaryNode{
Operator: token.Value,
Left: left,
Right: comparator,
}
cmpNode.SetLocation(token.Location)
if rootNode == nil {
rootNode = cmpNode
} else {
rootNode = &BinaryNode{
Operator: "&&",
Left: rootNode,
Right: cmpNode,
}
rootNode.SetLocation(token.Location)
}
left = comparator
token = p.current
if !(token.Is(Operator) && operator.IsComparison(token.Value) && p.err == nil) {
break
}
p.next()
}
return rootNode
}
+60
View File
@@ -531,6 +531,66 @@ world`},
To: &IntegerNode{Value: 3},
},
},
{
`1 < 2 > 3`,
&BinaryNode{
Operator: "&&",
Left: &BinaryNode{
Operator: "<",
Left: &IntegerNode{Value: 1},
Right: &IntegerNode{Value: 2},
},
Right: &BinaryNode{
Operator: ">",
Left: &IntegerNode{Value: 2},
Right: &IntegerNode{Value: 3},
},
},
},
{
`1 < 2 < 3 < 4`,
&BinaryNode{
Operator: "&&",
Left: &BinaryNode{
Operator: "&&",
Left: &BinaryNode{
Operator: "<",
Left: &IntegerNode{Value: 1},
Right: &IntegerNode{Value: 2},
},
Right: &BinaryNode{
Operator: "<",
Left: &IntegerNode{Value: 2},
Right: &IntegerNode{Value: 3},
},
},
Right: &BinaryNode{
Operator: "<",
Left: &IntegerNode{Value: 3},
Right: &IntegerNode{Value: 4},
},
},
},
{
`1 < 2 < 3 == true`,
&BinaryNode{
Operator: "==",
Left: &BinaryNode{
Operator: "&&",
Left: &BinaryNode{
Operator: "<",
Left: &IntegerNode{Value: 1},
Right: &IntegerNode{Value: 2},
},
Right: &BinaryNode{
Operator: "<",
Left: &IntegerNode{Value: 2},
Right: &IntegerNode{Value: 3},
},
},
Right: &BoolNode{Value: true},
},
},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {