lambda
This commit is contained in:
parent
1117f2c104
commit
a24586e601
6 changed files with 96 additions and 11 deletions
|
@ -86,6 +86,24 @@ func (as *AstStringer) visitCall(c *Call) any {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (as *AstStringer) visitLambda(l *Lambda) any {
|
||||
as.str.WriteString("(lambda ")
|
||||
if len(l.args) != 0 {
|
||||
as.str.WriteString("(")
|
||||
for i, arg := range l.args {
|
||||
as.str.WriteString(arg.lexeme)
|
||||
if i < len(l.args)-1 {
|
||||
as.str.WriteString(" ")
|
||||
}
|
||||
}
|
||||
as.str.WriteString(")")
|
||||
}
|
||||
l.body.accept(as)
|
||||
as.str.WriteString(")")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (as *AstStringer) visitPrintStmt(p *PrintStmt) {
|
||||
as.str.WriteString("(print ")
|
||||
p.val.accept(as)
|
||||
|
@ -159,7 +177,6 @@ func (as *AstStringer) visitFunStmt(f *FunStmt) {
|
|||
}
|
||||
f.body.accept(as)
|
||||
as.str.WriteString(")")
|
||||
|
||||
}
|
||||
|
||||
func (as *AstStringer) visitReturnStmt(r *ReturnStmt) {
|
||||
|
|
14
callable.go
14
callable.go
|
@ -6,7 +6,9 @@ type Callable interface {
|
|||
}
|
||||
|
||||
type Function struct {
|
||||
definition *FunStmt
|
||||
name Token
|
||||
args []Token
|
||||
body *BlockStmt
|
||||
closure *Environment
|
||||
}
|
||||
|
||||
|
@ -26,19 +28,19 @@ func (f *Function) call(i *Interpreter, args ...any) (ret any) {
|
|||
|
||||
env := newEnvironment(f.closure)
|
||||
|
||||
for idx, arg := range f.definition.args {
|
||||
for idx, arg := range f.args {
|
||||
env.define(arg.lexeme, args[idx])
|
||||
}
|
||||
|
||||
i.executeBlock(f.definition.body, env)
|
||||
i.executeBlock(f.body, env)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Function) arity() int {
|
||||
return len(f.definition.args)
|
||||
return len(f.args)
|
||||
}
|
||||
|
||||
func newFunction(fun *FunStmt, env *Environment) Callable {
|
||||
return &Function{fun, env}
|
||||
func newFunction(name Token, args []Token, body *BlockStmt, env *Environment) Callable {
|
||||
return &Function{name, args, body, env}
|
||||
}
|
||||
|
|
12
expr.go
12
expr.go
|
@ -3,6 +3,7 @@ package main
|
|||
type ExprVisitor interface {
|
||||
visitCall(c *Call) any
|
||||
visitUnary(u *Unary) any
|
||||
visitLambda(l *Lambda) any
|
||||
visitBinary(b *Binary) any
|
||||
visitLiteral(l *Literal) any
|
||||
visitGrouping(g *Grouping) any
|
||||
|
@ -56,10 +57,17 @@ type Call struct {
|
|||
args []Expr
|
||||
}
|
||||
|
||||
type Lambda struct {
|
||||
name Token
|
||||
args []Token
|
||||
body *BlockStmt
|
||||
}
|
||||
|
||||
func (c *Call) expr() {}
|
||||
func (u *Unary) expr() {}
|
||||
func (a *Assign) expr() {}
|
||||
func (b *Binary) expr() {}
|
||||
func (l *Lambda) expr() {}
|
||||
func (l *Literal) expr() {}
|
||||
func (g *Grouping) expr() {}
|
||||
func (v *Variable) expr() {}
|
||||
|
@ -96,3 +104,7 @@ func (l *Logical) accept(v ExprVisitor) any {
|
|||
func (c *Call) accept(v ExprVisitor) any {
|
||||
return v.visitCall(c)
|
||||
}
|
||||
|
||||
func (l *Lambda) accept(v ExprVisitor) any {
|
||||
return v.visitLambda(l)
|
||||
}
|
||||
|
|
|
@ -192,7 +192,11 @@ func (i *Interpreter) visitCall(c *Call) any {
|
|||
}
|
||||
|
||||
func (i *Interpreter) visitFunStmt(f *FunStmt) {
|
||||
i.env.define(f.name.lexeme, newFunction(f, i.env))
|
||||
i.env.define(f.name.lexeme, newFunction(f.name, f.args, f.body, i.env))
|
||||
}
|
||||
|
||||
func (i *Interpreter) visitLambda(l *Lambda) any {
|
||||
return newFunction(l.name, l.args, l.body, i.env)
|
||||
}
|
||||
|
||||
func (i *Interpreter) visitReturnStmt(r *ReturnStmt) {
|
||||
|
|
42
parser.go
42
parser.go
|
@ -431,7 +431,15 @@ func (p *Parser) arguments(callee Expr) Expr {
|
|||
return &Call{callee, paren, arguments}
|
||||
}
|
||||
|
||||
// primary -> NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" | IDENTIFIER
|
||||
// primary -> IDENTIFIER
|
||||
//
|
||||
// | NUMBER
|
||||
// | STRING
|
||||
// | "true"
|
||||
// | "false"
|
||||
// | "nil"
|
||||
// | "(" expression ")"
|
||||
// | lambda
|
||||
func (p *Parser) primary() Expr {
|
||||
switch {
|
||||
case p.match(FALSE):
|
||||
|
@ -442,6 +450,10 @@ func (p *Parser) primary() Expr {
|
|||
return &Literal{nil}
|
||||
}
|
||||
|
||||
if p.match(FUN) {
|
||||
return p.lambda()
|
||||
}
|
||||
|
||||
if p.match(NUMBER, STRING) {
|
||||
return &Literal{p.previous().literal}
|
||||
}
|
||||
|
@ -461,6 +473,34 @@ func (p *Parser) primary() Expr {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) lambda() Expr {
|
||||
name := p.previous()
|
||||
|
||||
p.consume(LEFT_PAREN, "Expect '(' before lambda arguments.")
|
||||
|
||||
args := []Token{}
|
||||
for !p.check(RIGHT_PAREN) {
|
||||
args = append(
|
||||
args,
|
||||
p.consume(
|
||||
IDENTIFIER,
|
||||
"Expect lambda argument.",
|
||||
),
|
||||
)
|
||||
|
||||
if p.check(COMMA) {
|
||||
p.advance()
|
||||
}
|
||||
}
|
||||
|
||||
p.consume(RIGHT_PAREN, "Expect ')' after lambda arguments.")
|
||||
p.consume(LEFT_BRACE, "Expect '{' before lambda body.")
|
||||
|
||||
body := p.blockStmt()
|
||||
|
||||
return &Lambda{name, args, body}
|
||||
}
|
||||
|
||||
func (p *Parser) previous() Token {
|
||||
return p.tokens[p.current-1]
|
||||
}
|
||||
|
|
|
@ -59,3 +59,13 @@ var counter = makeCounter();
|
|||
|
||||
counter();
|
||||
counter();
|
||||
|
||||
fun thrice(fn) {
|
||||
for (var i = 1; i <= 3; i = i + 1) {
|
||||
fn(i);
|
||||
}
|
||||
}
|
||||
|
||||
thrice(fun (a) { print a; });
|
||||
|
||||
print fun () { return "hello, "; }() + "world";
|
Loading…
Reference in a new issue