This commit is contained in:
Greg 2024-10-07 21:47:55 +03:00
parent 6bb2408269
commit 69042ccf99
8 changed files with 94 additions and 22 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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