From 69042ccf99d4fc6fd2c2df3e0c0bd1594b394339 Mon Sep 17 00:00:00 2001 From: Greg Date: Mon, 7 Oct 2024 21:47:55 +0300 Subject: [PATCH] break --- ast_string.go | 4 ++++ glox.go | 3 ++- interpreter.go | 19 ++++++++++++++++++- parser.go | 13 ++++++++++++- scanner.go | 2 ++ stmt.go | 8 ++++++++ tests/while.lox | 28 ++++++++++++++++++++++++++++ tokentype_string.go | 39 ++++++++++++++++++++------------------- 8 files changed, 94 insertions(+), 22 deletions(-) create mode 100644 tests/while.lox diff --git a/ast_string.go b/ast_string.go index be86ec0..9840c49 100644 --- a/ast_string.go +++ b/ast_string.go @@ -125,3 +125,7 @@ func (as *AstStringer) visitWhileStmt(w *WhileStmt) { w.body.accept(as) as.str.WriteString(")") } + +func (as *AstStringer) visitBreakStmt(b *BreakStmt) { + as.str.WriteString("(break)") +} diff --git a/glox.go b/glox.go index bb8a353..e25252f 100644 --- a/glox.go +++ b/glox.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "fmt" "log" "os" ) @@ -51,7 +52,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 bf51d06..e13b78a 100644 --- a/interpreter.go +++ b/interpreter.go @@ -10,6 +10,7 @@ import ( type Interpreter struct { env *Environment errors []error + brk bool } type RuntimeError struct { @@ -22,7 +23,7 @@ func (re *RuntimeError) Error() string { } func newInterpreter() *Interpreter { - return &Interpreter{env: newEnvironment(nil)} + return &Interpreter{env: newEnvironment(nil), errors: []error{}, brk: false} } func (i *Interpreter) interpret(stmts []Stmt) []error { @@ -180,12 +181,21 @@ func (i *Interpreter) visitBlockStmt(b *BlockStmt) { i.env = newEnvironment(parentEnv) for _, stmt := range b.stmts { + + if i.brk { + break + } + stmt.accept(i) } i.env = parentEnv } +func (i *Interpreter) visitBreakStmt(b *BreakStmt) { + i.brk = true +} + func (i *Interpreter) visitIfStmt(iff *IfStmt) { if isTruthy(i.evaluate(iff.expr)) { iff.then.accept(i) @@ -214,7 +224,14 @@ func (i *Interpreter) visitEnvStmt(e *EnvStmt) { func (i *Interpreter) visitWhileStmt(w *WhileStmt) { for isTruthy(i.evaluate(w.cond)) { + + if i.brk { + i.brk = false + break + } + w.body.accept(i) + } } diff --git a/parser.go b/parser.go index 6049e17..ddfb879 100644 --- a/parser.go +++ b/parser.go @@ -71,6 +71,7 @@ func (p *Parser) varDecl() Stmt { // | whileStmt // | printStmt // | blockStmt +// | breakStmt // | ifStmt // | env func (p *Parser) statement() Stmt { @@ -94,6 +95,10 @@ func (p *Parser) statement() Stmt { return p.whileStmt() } + if p.match(BREAK) { + return p.breakStmt() + } + return p.exprStmt() } @@ -134,6 +139,12 @@ func (p *Parser) blockStmt() Stmt { return &BlockStmt{stmts} } +// breakStmt -> break ";" +func (p *Parser) breakStmt() Stmt { + p.consume(SEMICOLON, "Expect ';' after break.") + return &BreakStmt{} +} + // if -> "if" "(" expression ")" statement ("else" statement)? func (p *Parser) ifStmt() Stmt { name := p.previous() @@ -304,7 +315,7 @@ func (p *Parser) primary() Expr { return &Grouping{expr} } - // p.panic(&ParseError{p.peek(), "Expect expression"}) + p.panic(&ParseError{p.peek(), "Expect expression"}) return nil } diff --git a/scanner.go b/scanner.go index 698a6de..dc04275 100644 --- a/scanner.go +++ b/scanner.go @@ -43,6 +43,7 @@ const ( // keywords AND + BREAK CLASS ENV ELSE @@ -65,6 +66,7 @@ const ( var keywords = map[string]TokenType{ "and": AND, + "break": BREAK, "class": CLASS, "else": ELSE, "false": FALSE, diff --git a/stmt.go b/stmt.go index 429c97b..c4cfe5c 100644 --- a/stmt.go +++ b/stmt.go @@ -8,6 +8,7 @@ type StmtVisitor interface { visitBlockStmt(b *BlockStmt) visitEnvStmt(e *EnvStmt) visitWhileStmt(w *WhileStmt) + visitBreakStmt(b *BreakStmt) } type Stmt interface { @@ -46,6 +47,8 @@ type WhileStmt struct { body Stmt } +type BreakStmt struct{} + func (i *IfStmt) stmt() {} func (e *EnvStmt) stmt() {} func (vs *VarStmt) stmt() {} @@ -53,6 +56,7 @@ func (es *ExprStmt) stmt() {} func (p *PrintStmt) stmt() {} func (b *BlockStmt) stmt() {} func (w *WhileStmt) stmt() {} +func (b *BreakStmt) stmt() {} func (p *PrintStmt) accept(v StmtVisitor) { v.visitPrintStmt(p) @@ -81,3 +85,7 @@ func (e *EnvStmt) accept(v StmtVisitor) { func (w *WhileStmt) accept(v StmtVisitor) { v.visitWhileStmt(w) } + +func (b *BreakStmt) accept(v StmtVisitor) { + v.visitBreakStmt(b) +} diff --git a/tests/while.lox b/tests/while.lox new file mode 100644 index 0000000..232e666 --- /dev/null +++ b/tests/while.lox @@ -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; \ No newline at end of file diff --git a/tokentype_string.go b/tokentype_string.go index 130f89a..e2199a2 100644 --- a/tokentype_string.go +++ b/tokentype_string.go @@ -31,28 +31,29 @@ func _() { _ = x[STRING-20] _ = x[NUMBER-21] _ = x[AND-22] - _ = x[CLASS-23] - _ = x[ENV-24] - _ = x[ELSE-25] - _ = x[FALSE-26] - _ = x[FUN-27] - _ = x[FOR-28] - _ = x[IF-29] - _ = x[NIL-30] - _ = x[OR-31] - _ = x[PRINT-32] - _ = x[RETURN-33] - _ = x[SUPER-34] - _ = x[THIS-35] - _ = x[TRUE-36] - _ = x[VAR-37] - _ = x[WHILE-38] - _ = x[EOF-39] + _ = x[BREAK-23] + _ = x[CLASS-24] + _ = x[ENV-25] + _ = x[ELSE-26] + _ = x[FALSE-27] + _ = x[FUN-28] + _ = x[FOR-29] + _ = x[IF-30] + _ = x[NIL-31] + _ = x[OR-32] + _ = x[PRINT-33] + _ = x[RETURN-34] + _ = x[SUPER-35] + _ = x[THIS-36] + _ = x[TRUE-37] + _ = x[VAR-38] + _ = 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 { if i < 0 || i >= TokenType(len(_TokenType_index)-1) {