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)
as.str.WriteString(")")
}
func (as *AstStringer) visitBreakStmt(b *BreakStmt) {
as.str.WriteString("(break)")
}

View file

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

View file

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

View file

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

View file

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

View file

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

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