Support chzained comparisonc1 < 2 < 3 (#581)

This commit is contained in:
Sergey
2024-02-27 14:23:49 +01:00
committed by GitHub
parent 2f8f25a68d
commit 26bfa591a9
4 changed files with 120 additions and 0 deletions
+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) {