simplify logical operators
This commit is contained in:
		
							parent
							
								
									5de730af97
								
							
						
					
					
						commit
						8adfb71887
					
				
					 7 changed files with 49 additions and 63 deletions
				
			
		|  | @ -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
									
										
									
									
									
								
							
							
						
						
									
										40
									
								
								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) | ||||
| } | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  |  | |||
							
								
								
									
										3
									
								
								glox.go
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								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) | ||||
| } | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
							
								
								
									
										21
									
								
								parser.go
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								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 | ||||
|  |  | |||
							
								
								
									
										10
									
								
								tests/if.lox
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tests/if.lox
									
										
									
									
									
										Normal 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"; | ||||
		Loading…
	
	Add table
		
		Reference in a new issue