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) {
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) {
if env.parent != nil && env.parent.exists(key) {
env.parent.set(key, val)
}
env.values[key] = val
}

View file

@ -210,7 +210,12 @@ func (i *Interpreter) visitEnvStmt(e *EnvStmt) {
fmt.Printf("%*s", ident, "")
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) {

View file

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

13
stmt.go
View file

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