simplify logical operators

This commit is contained in:
Greg 2024-10-06 17:15:50 +03:00
parent 5de730af97
commit 8adfb71887
7 changed files with 49 additions and 63 deletions

View file

@ -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)

40
expr.go
View file

@ -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)
}

View file

@ -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
}

View file

@ -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)
}

View file

@ -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) {

View file

@ -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

10
tests/if.lox Normal file
View file

@ -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";