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…
Reference in a new issue