break
This commit is contained in:
		
							parent
							
								
									6bb2408269
								
							
						
					
					
						commit
						69042ccf99
					
				
					 8 changed files with 94 additions and 22 deletions
				
			
		|  | @ -125,3 +125,7 @@ func (as *AstStringer) visitWhileStmt(w *WhileStmt) { | ||||||
| 	w.body.accept(as) | 	w.body.accept(as) | ||||||
| 	as.str.WriteString(")") | 	as.str.WriteString(")") | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (as *AstStringer) visitBreakStmt(b *BreakStmt) { | ||||||
|  | 	as.str.WriteString("(break)") | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								glox.go
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								glox.go
									
										
									
									
									
								
							|  | @ -2,6 +2,7 @@ package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
|  | 	"fmt" | ||||||
| 	"log" | 	"log" | ||||||
| 	"os" | 	"os" | ||||||
| ) | ) | ||||||
|  | @ -51,7 +52,7 @@ func (gl *Glox) run(source []byte) { | ||||||
| 
 | 
 | ||||||
| 	stmts, _ := newParser(tokens).parse() | 	stmts, _ := newParser(tokens).parse() | ||||||
| 
 | 
 | ||||||
| 	// fmt.Println(AstStringer{stmts: stmts}) | 	fmt.Println(AstStringer{stmts: stmts}) | ||||||
| 
 | 
 | ||||||
| 	gl.Interpreter.interpret(stmts) | 	gl.Interpreter.interpret(stmts) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ import ( | ||||||
| type Interpreter struct { | type Interpreter struct { | ||||||
| 	env    *Environment | 	env    *Environment | ||||||
| 	errors []error | 	errors []error | ||||||
|  | 	brk    bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type RuntimeError struct { | type RuntimeError struct { | ||||||
|  | @ -22,7 +23,7 @@ func (re *RuntimeError) Error() string { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func newInterpreter() *Interpreter { | func newInterpreter() *Interpreter { | ||||||
| 	return &Interpreter{env: newEnvironment(nil)} | 	return &Interpreter{env: newEnvironment(nil), errors: []error{}, brk: false} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (i *Interpreter) interpret(stmts []Stmt) []error { | func (i *Interpreter) interpret(stmts []Stmt) []error { | ||||||
|  | @ -180,12 +181,21 @@ func (i *Interpreter) visitBlockStmt(b *BlockStmt) { | ||||||
| 	i.env = newEnvironment(parentEnv) | 	i.env = newEnvironment(parentEnv) | ||||||
| 
 | 
 | ||||||
| 	for _, stmt := range b.stmts { | 	for _, stmt := range b.stmts { | ||||||
|  | 
 | ||||||
|  | 		if i.brk { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		stmt.accept(i) | 		stmt.accept(i) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	i.env = parentEnv | 	i.env = parentEnv | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (i *Interpreter) visitBreakStmt(b *BreakStmt) { | ||||||
|  | 	i.brk = true | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (i *Interpreter) visitIfStmt(iff *IfStmt) { | func (i *Interpreter) visitIfStmt(iff *IfStmt) { | ||||||
| 	if isTruthy(i.evaluate(iff.expr)) { | 	if isTruthy(i.evaluate(iff.expr)) { | ||||||
| 		iff.then.accept(i) | 		iff.then.accept(i) | ||||||
|  | @ -214,7 +224,14 @@ func (i *Interpreter) visitEnvStmt(e *EnvStmt) { | ||||||
| 
 | 
 | ||||||
| func (i *Interpreter) visitWhileStmt(w *WhileStmt) { | func (i *Interpreter) visitWhileStmt(w *WhileStmt) { | ||||||
| 	for isTruthy(i.evaluate(w.cond)) { | 	for isTruthy(i.evaluate(w.cond)) { | ||||||
|  | 
 | ||||||
|  | 		if i.brk { | ||||||
|  | 			i.brk = false | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		w.body.accept(i) | 		w.body.accept(i) | ||||||
|  | 
 | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								parser.go
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								parser.go
									
										
									
									
									
								
							|  | @ -71,6 +71,7 @@ func (p *Parser) varDecl() Stmt { | ||||||
| //	| whileStmt | //	| whileStmt | ||||||
| //	| printStmt | //	| printStmt | ||||||
| //	| blockStmt | //	| blockStmt | ||||||
|  | //	| breakStmt | ||||||
| //	| ifStmt | //	| ifStmt | ||||||
| //	| env | //	| env | ||||||
| func (p *Parser) statement() Stmt { | func (p *Parser) statement() Stmt { | ||||||
|  | @ -94,6 +95,10 @@ func (p *Parser) statement() Stmt { | ||||||
| 		return p.whileStmt() | 		return p.whileStmt() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if p.match(BREAK) { | ||||||
|  | 		return p.breakStmt() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return p.exprStmt() | 	return p.exprStmt() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -134,6 +139,12 @@ func (p *Parser) blockStmt() Stmt { | ||||||
| 	return &BlockStmt{stmts} | 	return &BlockStmt{stmts} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // breakStmt -> break ";" | ||||||
|  | func (p *Parser) breakStmt() Stmt { | ||||||
|  | 	p.consume(SEMICOLON, "Expect ';' after break.") | ||||||
|  | 	return &BreakStmt{} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // if -> "if" "(" expression ")" statement ("else" statement)? | // if -> "if" "(" expression ")" statement ("else" statement)? | ||||||
| func (p *Parser) ifStmt() Stmt { | func (p *Parser) ifStmt() Stmt { | ||||||
| 	name := p.previous() | 	name := p.previous() | ||||||
|  | @ -304,7 +315,7 @@ func (p *Parser) primary() Expr { | ||||||
| 		return &Grouping{expr} | 		return &Grouping{expr} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// p.panic(&ParseError{p.peek(), "Expect expression"}) | 	p.panic(&ParseError{p.peek(), "Expect expression"}) | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -43,6 +43,7 @@ const ( | ||||||
| 
 | 
 | ||||||
| 	// keywords | 	// keywords | ||||||
| 	AND | 	AND | ||||||
|  | 	BREAK | ||||||
| 	CLASS | 	CLASS | ||||||
| 	ENV | 	ENV | ||||||
| 	ELSE | 	ELSE | ||||||
|  | @ -65,6 +66,7 @@ const ( | ||||||
| 
 | 
 | ||||||
| var keywords = map[string]TokenType{ | var keywords = map[string]TokenType{ | ||||||
| 	"and":    AND, | 	"and":    AND, | ||||||
|  | 	"break":  BREAK, | ||||||
| 	"class":  CLASS, | 	"class":  CLASS, | ||||||
| 	"else":   ELSE, | 	"else":   ELSE, | ||||||
| 	"false":  FALSE, | 	"false":  FALSE, | ||||||
|  |  | ||||||
							
								
								
									
										8
									
								
								stmt.go
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								stmt.go
									
										
									
									
									
								
							|  | @ -8,6 +8,7 @@ type StmtVisitor interface { | ||||||
| 	visitBlockStmt(b *BlockStmt) | 	visitBlockStmt(b *BlockStmt) | ||||||
| 	visitEnvStmt(e *EnvStmt) | 	visitEnvStmt(e *EnvStmt) | ||||||
| 	visitWhileStmt(w *WhileStmt) | 	visitWhileStmt(w *WhileStmt) | ||||||
|  | 	visitBreakStmt(b *BreakStmt) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type Stmt interface { | type Stmt interface { | ||||||
|  | @ -46,6 +47,8 @@ type WhileStmt struct { | ||||||
| 	body Stmt | 	body Stmt | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | type BreakStmt struct{} | ||||||
|  | 
 | ||||||
| func (i *IfStmt) stmt()    {} | func (i *IfStmt) stmt()    {} | ||||||
| func (e *EnvStmt) stmt()   {} | func (e *EnvStmt) stmt()   {} | ||||||
| func (vs *VarStmt) stmt()  {} | func (vs *VarStmt) stmt()  {} | ||||||
|  | @ -53,6 +56,7 @@ func (es *ExprStmt) stmt() {} | ||||||
| func (p *PrintStmt) stmt() {} | func (p *PrintStmt) stmt() {} | ||||||
| func (b *BlockStmt) stmt() {} | func (b *BlockStmt) stmt() {} | ||||||
| func (w *WhileStmt) stmt() {} | func (w *WhileStmt) stmt() {} | ||||||
|  | func (b *BreakStmt) stmt() {} | ||||||
| 
 | 
 | ||||||
| func (p *PrintStmt) accept(v StmtVisitor) { | func (p *PrintStmt) accept(v StmtVisitor) { | ||||||
| 	v.visitPrintStmt(p) | 	v.visitPrintStmt(p) | ||||||
|  | @ -81,3 +85,7 @@ func (e *EnvStmt) accept(v StmtVisitor) { | ||||||
| func (w *WhileStmt) accept(v StmtVisitor) { | func (w *WhileStmt) accept(v StmtVisitor) { | ||||||
| 	v.visitWhileStmt(w) | 	v.visitWhileStmt(w) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (b *BreakStmt) accept(v StmtVisitor) { | ||||||
|  | 	v.visitBreakStmt(b) | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										28
									
								
								tests/while.lox
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tests/while.lox
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | var iterator = 100; | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     while (iterator > 0) { | ||||||
|  |        { | ||||||
|  |          print iterator; | ||||||
|  |         iterator = iterator - 2; | ||||||
|  |        } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     while (iterator < 100) { | ||||||
|  |         { | ||||||
|  |             print iterator; | ||||||
|  |             iterator = iterator + 2; | ||||||
|  | 
 | ||||||
|  |             if (iterator > 50) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             print "shoud not be printed after 50"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | print iterator; | ||||||
|  | @ -31,28 +31,29 @@ func _() { | ||||||
| 	_ = x[STRING-20] | 	_ = x[STRING-20] | ||||||
| 	_ = x[NUMBER-21] | 	_ = x[NUMBER-21] | ||||||
| 	_ = x[AND-22] | 	_ = x[AND-22] | ||||||
| 	_ = x[CLASS-23] | 	_ = x[BREAK-23] | ||||||
| 	_ = x[ENV-24] | 	_ = x[CLASS-24] | ||||||
| 	_ = x[ELSE-25] | 	_ = x[ENV-25] | ||||||
| 	_ = x[FALSE-26] | 	_ = x[ELSE-26] | ||||||
| 	_ = x[FUN-27] | 	_ = x[FALSE-27] | ||||||
| 	_ = x[FOR-28] | 	_ = x[FUN-28] | ||||||
| 	_ = x[IF-29] | 	_ = x[FOR-29] | ||||||
| 	_ = x[NIL-30] | 	_ = x[IF-30] | ||||||
| 	_ = x[OR-31] | 	_ = x[NIL-31] | ||||||
| 	_ = x[PRINT-32] | 	_ = x[OR-32] | ||||||
| 	_ = x[RETURN-33] | 	_ = x[PRINT-33] | ||||||
| 	_ = x[SUPER-34] | 	_ = x[RETURN-34] | ||||||
| 	_ = x[THIS-35] | 	_ = x[SUPER-35] | ||||||
| 	_ = x[TRUE-36] | 	_ = x[THIS-36] | ||||||
| 	_ = x[VAR-37] | 	_ = x[TRUE-37] | ||||||
| 	_ = x[WHILE-38] | 	_ = x[VAR-38] | ||||||
| 	_ = x[EOF-39] | 	_ = x[WHILE-39] | ||||||
|  | 	_ = x[EOF-40] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const _TokenType_name = "LEFT_PARENRIGHT_PARENLEFT_BRACERIGHT_BRACECOMMADOTMINUSPLUSSEMICOLONSLASHSTARBANGBANG_EQUALEQUALEQUAL_EQUALGREATERGREATER_EQUALLESSLESS_EQUALIDENTIFIERSTRINGNUMBERANDCLASSENVELSEFALSEFUNFORIFNILORPRINTRETURNSUPERTHISTRUEVARWHILEEOF" | const _TokenType_name = "LEFT_PARENRIGHT_PARENLEFT_BRACERIGHT_BRACECOMMADOTMINUSPLUSSEMICOLONSLASHSTARBANGBANG_EQUALEQUALEQUAL_EQUALGREATERGREATER_EQUALLESSLESS_EQUALIDENTIFIERSTRINGNUMBERANDBREAKCLASSENVELSEFALSEFUNFORIFNILORPRINTRETURNSUPERTHISTRUEVARWHILEEOF" | ||||||
| 
 | 
 | ||||||
| var _TokenType_index = [...]uint8{0, 10, 21, 31, 42, 47, 50, 55, 59, 68, 73, 77, 81, 91, 96, 107, 114, 127, 131, 141, 151, 157, 163, 166, 171, 174, 178, 183, 186, 189, 191, 194, 196, 201, 207, 212, 216, 220, 223, 228, 231} | var _TokenType_index = [...]uint8{0, 10, 21, 31, 42, 47, 50, 55, 59, 68, 73, 77, 81, 91, 96, 107, 114, 127, 131, 141, 151, 157, 163, 166, 171, 176, 179, 183, 188, 191, 194, 196, 199, 201, 206, 212, 217, 221, 225, 228, 233, 236} | ||||||
| 
 | 
 | ||||||
| func (i TokenType) String() string { | func (i TokenType) String() string { | ||||||
| 	if i < 0 || i >= TokenType(len(_TokenType_index)-1) { | 	if i < 0 || i >= TokenType(len(_TokenType_index)-1) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue