From 28b6ce28447e0988f55491ea7c161190a05d87b0 Mon Sep 17 00:00:00 2001 From: Cedric <14017092+douyixuan@users.noreply.github.com> Date: Thu, 28 Nov 2024 00:54:16 +0800 Subject: [PATCH] fix: logic operator parsing --- compiler/lexer/lexer_test.go | 17 +++++++++++++++ compiler/parser/node.go | 8 +++++++ compiler/parser/parser.go | 17 +++++++++++++++ compiler/parser/parser_test.go | 38 ++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/compiler/lexer/lexer_test.go b/compiler/lexer/lexer_test.go index 5fb99d8..afb188f 100644 --- a/compiler/lexer/lexer_test.go +++ b/compiler/lexer/lexer_test.go @@ -185,3 +185,20 @@ func TestLexerPragma(t *testing.T) { assert.Equal(t, expected, r) } + +func TestCondition(t *testing.T) { + r := Lex(`a > b && b > c`) + + expected := []Item{ + {Type: IDENTIFIER, Val: "a", Line: 1}, + {Type: OPERATOR, Val: ">", Line: 1}, + {Type: IDENTIFIER, Val: "b", Line: 1}, + {Type: OPERATOR, Val: "&&", Line: 1}, + {Type: IDENTIFIER, Val: "b", Line: 1}, + {Type: OPERATOR, Val: ">", Line: 1}, + {Type: IDENTIFIER, Val: "c", Line: 1}, + {Type: EOL}, + {Type: EOF}, + } + assert.Equal(t, expected, r) +} \ No newline at end of file diff --git a/compiler/parser/node.go b/compiler/parser/node.go index 4a507e1..8ffdd95 100644 --- a/compiler/parser/node.go +++ b/compiler/parser/node.go @@ -117,6 +117,7 @@ const ( var opsCharToOp map[string]Operator var arithOperators map[Operator]struct{} +var cmpOperators map[Operator]struct{} func init() { opsCharToOp = make(map[string]Operator) @@ -136,6 +137,13 @@ func init() { } { arithOperators[op] = struct{}{} } + + cmpOperators = make(map[Operator]struct{}) + for _, op := range []Operator{ + OP_EQ, OP_GT, OP_GTEQ, OP_LT, OP_LTEQ, + } { + cmpOperators[op] = struct{}{} + } } func (on OperatorNode) String() string { diff --git a/compiler/parser/parser.go b/compiler/parser/parser.go index 289dcab..a222b1e 100644 --- a/compiler/parser/parser.go +++ b/compiler/parser/parser.go @@ -754,6 +754,7 @@ func (p *parser) parseOperation(input Node, withArithAhead bool) Node { // Handle "Operations" both arith and comparision operator := opsCharToOp[next.Val] _, isArithOp := arithOperators[operator] + _, isCmpOp := cmpOperators[operator] if !withArithAhead && isArithOp { return input @@ -764,11 +765,27 @@ func (p *parser) parseOperation(input Node, withArithAhead bool) Node { Operator: operator, Left: input, } + if operator == OP_LOGICAL_AND || operator == OP_LOGICAL_OR { + body, _ := p.parseUntilEither( + []lexer.Item{ + {Type: lexer.OPERATOR, Val: "{"}, + {Type: lexer.EOL}, + {Type: lexer.EOF}, + }, + ) + return &OperatorNode{ + Operator: operator, + Left: input, + Right: body[0], + } + } if isArithOp { res.Right = p.parseOneWithOptions(false, false, false) // Sort infix operations if necessary (eg: apply OP_MUL before OP_ADD) res = sortInfix(res) + } else if isCmpOp { + res.Right = p.parseOneWithOptions(false, false, false) } else { res.Right = p.parseOneWithOptions(true, true, true) } diff --git a/compiler/parser/parser_test.go b/compiler/parser/parser_test.go index e5004f2..1e0d9da 100644 --- a/compiler/parser/parser_test.go +++ b/compiler/parser/parser_test.go @@ -341,3 +341,41 @@ func TestFunction(t *testing.T) { assert.Equal(t, expected, Parse(input, &option.Options{Debug: false})) } + +func TestCondition(t *testing.T) { + input := []lexer.Item{ + {Type: lexer.IDENTIFIER, Val: "a", Line: 1}, + {Type: lexer.OPERATOR, Val: ">", Line: 1}, + {Type: lexer.IDENTIFIER, Val: "b", Line: 1}, + {Type: lexer.OPERATOR, Val: "&&", Line: 1}, + {Type: lexer.IDENTIFIER, Val: "b", Line: 1}, + {Type: lexer.OPERATOR, Val: ">", Line: 1}, + {Type: lexer.IDENTIFIER, Val: "c", Line: 1}, + {Type: lexer.EOL}, + {Type: lexer.EOF}, + } + + /* + a > b && b > c + */ + + expected := &FileNode{ + Instructions: []Node{ + &OperatorNode{ + Operator: "&&", + Left: &OperatorNode{ + Operator: ">", + Left: &NameNode{Name: "a"}, + Right: &NameNode{Name: "b"}, + }, + Right: &OperatorNode{ + Operator: ">", + Left: &NameNode{Name: "b"}, + Right: &NameNode{Name: "c"}, + }, + }, + }, + } + + assert.Equal(t, expected, Parse(input, &option.Options{Debug: false})) +}