From 8adfb7188725340b77ac291e2a09d546c70d6ec9 Mon Sep 17 00:00:00 2001 From: Greg Date: Sun, 6 Oct 2024 17:15:50 +0300 Subject: [PATCH] simplify logical operators --- ast_string.go | 13 ++----------- expr.go | 40 ++++++++++++++-------------------------- expr_rpn.go | 9 +-------- glox.go | 3 +-- interpreter.go | 16 +++++++++++----- parser.go | 21 ++++++++++----------- tests/if.lox | 10 ++++++++++ 7 files changed, 49 insertions(+), 63 deletions(-) create mode 100644 tests/if.lox diff --git a/ast_string.go b/ast_string.go index 5f3b976..de5f9f8 100644 --- a/ast_string.go +++ b/ast_string.go @@ -62,17 +62,8 @@ func (as *AstStringer) visitAssignment(a *Assign) any { return nil } -func (as *AstStringer) visitLogicalOr(l *LogicalOr) any { - as.str.WriteString("(or ") - l.left.accept(as) - as.str.WriteString(" ") - l.right.accept(as) - as.str.WriteString(")") - return nil -} - -func (as *AstStringer) visitLogicalAnd(l *LogicalAnd) any { - as.str.WriteString("(and ") +func (as *AstStringer) visitLogical(l *Logical) any { + as.str.WriteString(fmt.Sprintf("(%s ", l.operator.lexeme)) l.left.accept(as) as.str.WriteString(" ") l.right.accept(as) diff --git a/expr.go b/expr.go index 0f05096..4615b77 100644 --- a/expr.go +++ b/expr.go @@ -6,9 +6,8 @@ type ExprVisitor interface { visitLiteral(l *Literal) any visitGrouping(g *Grouping) any visitVariable(v *Variable) any - visitLogicalOr(l *LogicalOr) any + visitLogical(l *Logical) any visitAssignment(a *Assign) any - visitLogicalAnd(l *LogicalAnd) any } type Expr interface { @@ -44,26 +43,19 @@ type Assign struct { value Expr } -type LogicalOr struct { - left Expr - or Token - right Expr +type Logical struct { + left Expr + operator Token + right Expr } -type LogicalAnd struct { - left Expr - and Token - right Expr -} - -func (u *Unary) expr() {} -func (a *Assign) expr() {} -func (b *Binary) expr() {} -func (l *Literal) expr() {} -func (g *Grouping) expr() {} -func (v *Variable) expr() {} -func (l *LogicalOr) expr() {} -func (l *LogicalAnd) expr() {} +func (u *Unary) expr() {} +func (a *Assign) expr() {} +func (b *Binary) expr() {} +func (l *Literal) expr() {} +func (g *Grouping) expr() {} +func (v *Variable) expr() {} +func (l *Logical) expr() {} func (u *Unary) accept(v ExprVisitor) any { return v.visitUnary(u) @@ -89,10 +81,6 @@ func (a *Assign) accept(v ExprVisitor) any { return v.visitAssignment(a) } -func (l *LogicalOr) accept(v ExprVisitor) any { - return v.visitLogicalOr(l) -} - -func (l *LogicalAnd) accept(v ExprVisitor) any { - return v.visitLogicalAnd(l) +func (l *Logical) accept(v ExprVisitor) any { + return v.visitLogical(l) } diff --git a/expr_rpn.go b/expr_rpn.go index 3f3be95..1ef4679 100644 --- a/expr_rpn.go +++ b/expr_rpn.go @@ -55,16 +55,9 @@ func (as *ExprToRPN) visitAssignment(a *Assign) any { return nil } -func (as *ExprToRPN) visitLogicalOr(lo *LogicalOr) any { +func (as *ExprToRPN) visitLogical(lo *Logical) any { lo.left.accept(as) lo.right.accept(as) as.str.WriteString(" or") return nil } - -func (as *ExprToRPN) visitLogicalAnd(la *LogicalAnd) any { - la.left.accept(as) - la.right.accept(as) - as.str.WriteString(" and") - return nil -} diff --git a/glox.go b/glox.go index e25252f..bb8a353 100644 --- a/glox.go +++ b/glox.go @@ -2,7 +2,6 @@ package main import ( "bufio" - "fmt" "log" "os" ) @@ -52,7 +51,7 @@ func (gl *Glox) run(source []byte) { stmts, _ := newParser(tokens).parse() - fmt.Println(AstStringer{stmts: stmts}) + // fmt.Println(AstStringer{stmts: stmts}) gl.Interpreter.interpret(stmts) } diff --git a/interpreter.go b/interpreter.go index 24ddef4..afc6f9b 100644 --- a/interpreter.go +++ b/interpreter.go @@ -141,12 +141,18 @@ func (i *Interpreter) visitAssignment(a *Assign) any { return val } -func (i *Interpreter) visitLogicalOr(lo *LogicalOr) any { - return isTruthy(i.evaluate(lo.left)) || isTruthy(i.evaluate(lo.right)) -} +func (i *Interpreter) visitLogical(lo *Logical) any { -func (i *Interpreter) visitLogicalAnd(la *LogicalAnd) any { - return isTruthy(i.evaluate(la.left)) && isTruthy(i.evaluate(la.right)) + left := i.evaluate(lo.left) + + shortOr := lo.operator.typ == OR && isTruthy(left) + shortAnd := lo.operator.typ == AND && !isTruthy(left) + + if shortOr || shortAnd { + return left + } + + return i.evaluate(lo.right) } func (i *Interpreter) visitPrintStmt(p *PrintStmt) { diff --git a/parser.go b/parser.go index 9129804..d40e8d8 100644 --- a/parser.go +++ b/parser.go @@ -151,9 +151,9 @@ func (p *Parser) expression() Expr { return p.assignment() } -// assignment -> IDENTIFIER "=" assignment | logicalOr +// assignment -> IDENTIFIER "=" assignment | or func (p *Parser) assignment() Expr { - expr := p.logicalOr() + expr := p.or() if p.match(EQUAL) { eq := p.previous() @@ -169,29 +169,28 @@ func (p *Parser) assignment() Expr { return expr } -// logicalOr -> logicalAnd ( "or" logicalAnd )* -func (p *Parser) logicalOr() Expr { - left := p.logicalAnd() +// or -> and ( "or" and )* +func (p *Parser) or() Expr { + left := p.and() for p.match(OR) { or := p.previous() - right := p.logicalAnd() - - left = &LogicalOr{left, or, right} + right := p.and() + left = &Logical{left, or, right} } return left } -// logicalAnd -> equality ( "and" equality )* -func (p *Parser) logicalAnd() Expr { +// and -> equality ( "and" equality )* +func (p *Parser) and() Expr { left := p.equality() for p.match(AND) { or := p.previous() right := p.equality() - left = &LogicalAnd{left, or, right} + left = &Logical{left, or, right} } return left diff --git a/tests/if.lox b/tests/if.lox new file mode 100644 index 0000000..c932130 --- /dev/null +++ b/tests/if.lox @@ -0,0 +1,10 @@ +var a = 1; +var b = 2; + +if (a == b or b - a > 0) print a + b; + +if ( 1 and 2 ) print "and"; + +if ( 1 and 2 and 3 and false ) else print "else"; + +print nil or "yes"; \ No newline at end of file