simple while

This commit is contained in:
Greg 2024-10-07 21:06:23 +03:00
parent 8adfb71887
commit 6bb2408269
5 changed files with 54 additions and 5 deletions

View file

@ -117,3 +117,11 @@ func (as *AstStringer) visitIfStmt(i *IfStmt) {
func (as *AstStringer) visitEnvStmt(e *EnvStmt) { func (as *AstStringer) visitEnvStmt(e *EnvStmt) {
as.str.WriteString("(env)") as.str.WriteString("(env)")
} }
func (as *AstStringer) visitWhileStmt(w *WhileStmt) {
as.str.WriteString("(while ")
w.cond.accept(as)
as.str.WriteString(" ")
w.body.accept(as)
as.str.WriteString(")")
}

5
env.go
View file

@ -33,5 +33,10 @@ func (env *Environment) exists(key string) bool {
} }
func (env *Environment) set(key string, val any) { func (env *Environment) set(key string, val any) {
if env.parent != nil && env.parent.exists(key) {
env.parent.set(key, val)
}
env.values[key] = val env.values[key] = val
} }

View file

@ -210,7 +210,12 @@ func (i *Interpreter) visitEnvStmt(e *EnvStmt) {
fmt.Printf("%*s", ident, "") fmt.Printf("%*s", ident, "")
fmt.Printf("%+v\n", *e) fmt.Printf("%+v\n", *e)
} }
}
func (i *Interpreter) visitWhileStmt(w *WhileStmt) {
for isTruthy(i.evaluate(w.cond)) {
w.body.accept(i)
}
} }
func (i *Interpreter) panic(re *RuntimeError) { func (i *Interpreter) panic(re *RuntimeError) {

View file

@ -66,14 +66,20 @@ func (p *Parser) varDecl() Stmt {
return &VarStmt{name, initializer} return &VarStmt{name, initializer}
} }
// statement -> exprStmt | printStmt | block | ifStmt | env // statement -> exprStmt
//
// | whileStmt
// | printStmt
// | blockStmt
// | ifStmt
// | env
func (p *Parser) statement() Stmt { func (p *Parser) statement() Stmt {
if p.match(PRINT) { if p.match(PRINT) {
return p.printStmt() return p.printStmt()
} }
if p.match(LEFT_BRACE) { if p.match(LEFT_BRACE) {
return p.block() return p.blockStmt()
} }
if p.match(IF) { if p.match(IF) {
@ -84,6 +90,10 @@ func (p *Parser) statement() Stmt {
return p.envStmt() return p.envStmt()
} }
if p.match(WHILE) {
return p.whileStmt()
}
return p.exprStmt() return p.exprStmt()
} }
@ -111,8 +121,8 @@ func (p *Parser) printStmt() Stmt {
return &PrintStmt{expr} return &PrintStmt{expr}
} }
// block -> "{" statement* "}" // blockStmt -> "{" statement* "}"
func (p *Parser) block() Stmt { func (p *Parser) blockStmt() Stmt {
stmts := []Stmt{} stmts := []Stmt{}
for !p.check(RIGHT_BRACE) && !p.isAtEnd() { for !p.check(RIGHT_BRACE) && !p.isAtEnd() {
@ -140,6 +150,16 @@ func (p *Parser) ifStmt() Stmt {
return &IfStmt{name, expr, then, or} return &IfStmt{name, expr, then, or}
} }
// while -> "while" "(" expression ")" statement
func (p *Parser) whileStmt() Stmt {
p.consume(LEFT_PAREN, "Expect '(' after 'while'.")
cond := p.expression()
p.consume(RIGHT_PAREN, "Expect ')' after 'while' expression.")
body := p.statement()
return &WhileStmt{cond, body}
}
// env -> "env" ";" // env -> "env" ";"
func (p *Parser) envStmt() Stmt { func (p *Parser) envStmt() Stmt {
p.consume(SEMICOLON, "Expect ';' after 'env'.") p.consume(SEMICOLON, "Expect ';' after 'env'.")

13
stmt.go
View file

@ -7,6 +7,7 @@ type StmtVisitor interface {
visitPrintStmt(p *PrintStmt) visitPrintStmt(p *PrintStmt)
visitBlockStmt(b *BlockStmt) visitBlockStmt(b *BlockStmt)
visitEnvStmt(e *EnvStmt) visitEnvStmt(e *EnvStmt)
visitWhileStmt(w *WhileStmt)
} }
type Stmt interface { type Stmt interface {
@ -40,12 +41,18 @@ type IfStmt struct {
or Stmt or Stmt
} }
type WhileStmt struct {
cond Expr
body Stmt
}
func (i *IfStmt) stmt() {} func (i *IfStmt) stmt() {}
func (e *EnvStmt) stmt() {}
func (vs *VarStmt) stmt() {} func (vs *VarStmt) stmt() {}
func (es *ExprStmt) stmt() {} func (es *ExprStmt) stmt() {}
func (p *PrintStmt) stmt() {} func (p *PrintStmt) stmt() {}
func (b *BlockStmt) stmt() {} func (b *BlockStmt) stmt() {}
func (e *EnvStmt) stmt() {} func (w *WhileStmt) stmt() {}
func (p *PrintStmt) accept(v StmtVisitor) { func (p *PrintStmt) accept(v StmtVisitor) {
v.visitPrintStmt(p) v.visitPrintStmt(p)
@ -70,3 +77,7 @@ func (i *IfStmt) accept(v StmtVisitor) {
func (e *EnvStmt) accept(v StmtVisitor) { func (e *EnvStmt) accept(v StmtVisitor) {
v.visitEnvStmt(e) v.visitEnvStmt(e)
} }
func (w *WhileStmt) accept(v StmtVisitor) {
v.visitWhileStmt(w)
}