diff --git a/expr_test.go b/expr_test.go index ea9213be..a4321c57 100644 --- a/expr_test.go +++ b/expr_test.go @@ -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 { diff --git a/parser/operator/operator.go b/parser/operator/operator.go index 8d804c7b..411a0e2b 100644 --- a/parser/operator/operator.go +++ b/parser/operator/operator.go @@ -54,3 +54,7 @@ var Binary = map[string]Operator{ "^": {100, Right}, "??": {500, Left}, } + +func IsComparison(op string) bool { + return op == "<" || op == ">" || op == ">=" || op == "<=" +} diff --git a/parser/parser.go b/parser/parser.go index 1eabdebe..9114bc0c 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -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 +} diff --git a/parser/parser_test.go b/parser/parser_test.go index b633bd52..9225e102 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -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) {