fun declaration
This commit is contained in:
parent
a6e0673c3b
commit
ce0492c489
6 changed files with 115 additions and 7 deletions
|
@ -140,3 +140,16 @@ func (as *AstStringer) visitWhileStmt(w *WhileStmt) {
|
||||||
func (as *AstStringer) visitBreakStmt(b *BreakStmt) {
|
func (as *AstStringer) visitBreakStmt(b *BreakStmt) {
|
||||||
as.str.WriteString("(break)")
|
as.str.WriteString("(break)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (as *AstStringer) visitFunStmt(f *FunStmt) {
|
||||||
|
as.str.WriteString(fmt.Sprintf("(fun %s", f.name.lexeme))
|
||||||
|
if len(f.args) != 0 {
|
||||||
|
as.str.WriteString("(")
|
||||||
|
for _, arg := range f.args {
|
||||||
|
as.str.WriteString(arg.lexeme)
|
||||||
|
}
|
||||||
|
as.str.WriteString(")")
|
||||||
|
}
|
||||||
|
as.str.WriteString(")")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
17
callable.go
17
callable.go
|
@ -4,3 +4,20 @@ type Callable struct {
|
||||||
arity int
|
arity int
|
||||||
call func(*Interpreter, ...any) any
|
call func(*Interpreter, ...any) any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newCallable(f *FunStmt) *Callable {
|
||||||
|
return &Callable{
|
||||||
|
arity: len(f.args),
|
||||||
|
call: func(i *Interpreter, args ...any) any {
|
||||||
|
env := newEnvironment(i.globals)
|
||||||
|
|
||||||
|
for idx, arg := range f.args {
|
||||||
|
env.set(arg.lexeme, args[idx])
|
||||||
|
}
|
||||||
|
|
||||||
|
i.executeBlock(f.body, env)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -197,6 +197,10 @@ func (i *Interpreter) visitCall(c *Call) any {
|
||||||
return callable.call(i, args...)
|
return callable.call(i, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Interpreter) visitFunStmt(f *FunStmt) {
|
||||||
|
i.env.set(f.name.lexeme, newCallable(f))
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Interpreter) visitPrintStmt(p *PrintStmt) {
|
func (i *Interpreter) visitPrintStmt(p *PrintStmt) {
|
||||||
fmt.Printf("%v\n", i.evaluate(p.val))
|
fmt.Printf("%v\n", i.evaluate(p.val))
|
||||||
}
|
}
|
||||||
|
@ -217,9 +221,13 @@ func (i *Interpreter) visitVarStmt(v *VarStmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Interpreter) visitBlockStmt(b *BlockStmt) {
|
func (i *Interpreter) visitBlockStmt(b *BlockStmt) {
|
||||||
|
i.executeBlock(b, newEnvironment(i.env))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Interpreter) executeBlock(b *BlockStmt, current *Environment) {
|
||||||
|
|
||||||
parentEnv := i.env
|
parentEnv := i.env
|
||||||
i.env = newEnvironment(parentEnv)
|
i.env = current
|
||||||
|
|
||||||
for _, stmt := range b.stmts {
|
for _, stmt := range b.stmts {
|
||||||
|
|
||||||
|
|
42
parser.go
42
parser.go
|
@ -43,18 +43,23 @@ func (p *Parser) parse() ([]Stmt, []error) {
|
||||||
return stmts, p.errors
|
return stmts, p.errors
|
||||||
}
|
}
|
||||||
|
|
||||||
// declaration -> varDecl | statement
|
// declaration -> varDecl | funDecl | statement
|
||||||
func (p *Parser) declaration() Stmt {
|
func (p *Parser) declaration() Stmt {
|
||||||
defer p.synchronize()
|
defer p.synchronize()
|
||||||
if p.match(VAR) {
|
if p.match(VAR) {
|
||||||
return p.varDecl()
|
return p.varDecl()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.match(FUN) {
|
||||||
|
return p.function("function")
|
||||||
|
}
|
||||||
|
|
||||||
return p.statement()
|
return p.statement()
|
||||||
}
|
}
|
||||||
|
|
||||||
// varDecl -> "var" IDENTIFIER ("=" expression)? ";"
|
// varDecl -> "var" IDENTIFIER ("=" expression)? ";"
|
||||||
func (p *Parser) varDecl() Stmt {
|
func (p *Parser) varDecl() Stmt {
|
||||||
name := p.consume(IDENTIFIER, "expect identifier for variable")
|
name := p.consume(IDENTIFIER, "Expect identifier for variable")
|
||||||
|
|
||||||
var initializer Expr = nil
|
var initializer Expr = nil
|
||||||
if p.match(EQUAL) {
|
if p.match(EQUAL) {
|
||||||
|
@ -66,6 +71,37 @@ func (p *Parser) varDecl() Stmt {
|
||||||
return &VarStmt{name, initializer}
|
return &VarStmt{name, initializer}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// funDecl -> "fun" function
|
||||||
|
// function -> IDENTIFIER "(" parameters? ")" blockStmt
|
||||||
|
// parameters -> IDENTIFIER ( "," IDENTIFIER )*
|
||||||
|
func (p *Parser) function(kind string) Stmt {
|
||||||
|
name := p.consume(IDENTIFIER, fmt.Sprintf("Expect %s name.", kind))
|
||||||
|
|
||||||
|
p.consume(LEFT_PAREN, fmt.Sprintf("Expect '(' after %s name.", kind))
|
||||||
|
|
||||||
|
args := []Token{}
|
||||||
|
for !p.check(RIGHT_PAREN) {
|
||||||
|
args = append(
|
||||||
|
args,
|
||||||
|
p.consume(
|
||||||
|
IDENTIFIER,
|
||||||
|
fmt.Sprintf("Expect %s argument.", kind),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
if p.check(COMMA) {
|
||||||
|
p.advance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.consume(RIGHT_PAREN, fmt.Sprintf("Expect ')' after %s name.", kind))
|
||||||
|
p.consume(LEFT_BRACE, fmt.Sprintf("Expect '{' after %s arguments.", kind))
|
||||||
|
|
||||||
|
body := p.blockStmt()
|
||||||
|
|
||||||
|
return &FunStmt{name, args, body}
|
||||||
|
}
|
||||||
|
|
||||||
// statement -> exprStmt
|
// statement -> exprStmt
|
||||||
//
|
//
|
||||||
// | whileStmt
|
// | whileStmt
|
||||||
|
@ -132,7 +168,7 @@ func (p *Parser) printStmt() Stmt {
|
||||||
}
|
}
|
||||||
|
|
||||||
// blockStmt -> "{" statement* "}"
|
// blockStmt -> "{" statement* "}"
|
||||||
func (p *Parser) blockStmt() Stmt {
|
func (p *Parser) blockStmt() *BlockStmt {
|
||||||
|
|
||||||
stmts := []Stmt{}
|
stmts := []Stmt{}
|
||||||
for !p.check(RIGHT_BRACE) && !p.isAtEnd() {
|
for !p.check(RIGHT_BRACE) && !p.isAtEnd() {
|
||||||
|
|
14
stmt.go
14
stmt.go
|
@ -3,10 +3,11 @@ package main
|
||||||
type StmtVisitor interface {
|
type StmtVisitor interface {
|
||||||
visitIfStmt(i *IfStmt)
|
visitIfStmt(i *IfStmt)
|
||||||
visitVarStmt(v *VarStmt)
|
visitVarStmt(v *VarStmt)
|
||||||
|
visitEnvStmt(e *EnvStmt)
|
||||||
|
visitFunStmt(f *FunStmt)
|
||||||
visitExprStmt(es *ExprStmt)
|
visitExprStmt(es *ExprStmt)
|
||||||
visitPrintStmt(p *PrintStmt)
|
visitPrintStmt(p *PrintStmt)
|
||||||
visitBlockStmt(b *BlockStmt)
|
visitBlockStmt(b *BlockStmt)
|
||||||
visitEnvStmt(e *EnvStmt)
|
|
||||||
visitWhileStmt(w *WhileStmt)
|
visitWhileStmt(w *WhileStmt)
|
||||||
visitBreakStmt(b *BreakStmt)
|
visitBreakStmt(b *BreakStmt)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +50,14 @@ type WhileStmt struct {
|
||||||
|
|
||||||
type BreakStmt struct{}
|
type BreakStmt struct{}
|
||||||
|
|
||||||
|
type FunStmt struct {
|
||||||
|
name Token
|
||||||
|
args []Token
|
||||||
|
body *BlockStmt
|
||||||
|
}
|
||||||
|
|
||||||
func (i *IfStmt) stmt() {}
|
func (i *IfStmt) stmt() {}
|
||||||
|
func (f *FunStmt) stmt() {}
|
||||||
func (e *EnvStmt) stmt() {}
|
func (e *EnvStmt) stmt() {}
|
||||||
func (vs *VarStmt) stmt() {}
|
func (vs *VarStmt) stmt() {}
|
||||||
func (es *ExprStmt) stmt() {}
|
func (es *ExprStmt) stmt() {}
|
||||||
|
@ -89,3 +97,7 @@ func (w *WhileStmt) accept(v StmtVisitor) {
|
||||||
func (b *BreakStmt) accept(v StmtVisitor) {
|
func (b *BreakStmt) accept(v StmtVisitor) {
|
||||||
v.visitBreakStmt(b)
|
v.visitBreakStmt(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FunStmt) accept(v StmtVisitor) {
|
||||||
|
v.visitFunStmt(f)
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,26 @@
|
||||||
|
|
||||||
print "functions test";
|
print "native function";
|
||||||
|
|
||||||
print clock();
|
print clock();
|
||||||
|
|
||||||
|
fun count(n) {
|
||||||
|
if (n > 1) count(n - 1);
|
||||||
|
print n;
|
||||||
|
}
|
||||||
|
|
||||||
|
count(10);
|
||||||
|
|
||||||
|
fun hi(name, surname) {
|
||||||
|
print "hello, " + name + " " + surname + "!";
|
||||||
|
}
|
||||||
|
|
||||||
|
hi("John", "Doe");
|
||||||
|
|
||||||
|
|
||||||
|
fun re(turn) {
|
||||||
|
print "before retrun";
|
||||||
|
return turn;
|
||||||
|
print "should not be printed";
|
||||||
|
}
|
||||||
|
|
||||||
|
print re("print");
|
Loading…
Reference in a new issue