Skip to content

Commit

Permalink
Support chained comparison
Browse files Browse the repository at this point in the history
  • Loading branch information
bizywizy committed Feb 27, 2024
1 parent 6cc56e7 commit f34318a
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 0 deletions.
20 changes: 20 additions & 0 deletions expr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,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 {
Expand Down
4 changes: 4 additions & 0 deletions parser/operator/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@ var Binary = map[string]Operator{
"^": {100, Right},
"??": {500, Left},
}

func IsComparison(op string) bool {
return op == "<" || op == ">" || op == ">=" || op == "<="
}
36 changes: 36 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
40 changes: 40 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,46 @@ 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},
},
},
},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
Expand Down

0 comments on commit f34318a

Please sign in to comment.