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) { | ||||
|  |  | |||
							
								
								
									
										16
									
								
								callable.go
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								callable.go
									
										
									
									
									
								
							|  | @ -6,8 +6,10 @@ type Callable interface { | |||
| } | ||||
| 
 | ||||
| type Function struct { | ||||
| 	definition *FunStmt | ||||
| 	closure    *Environment | ||||
| 	name    Token | ||||
| 	args    []Token | ||||
| 	body    *BlockStmt | ||||
| 	closure *Environment | ||||
| } | ||||
| 
 | ||||
| func (f *Function) call(i *Interpreter, args ...any) (ret any) { | ||||
|  | @ -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] | ||||
| } | ||||
|  |  | |||
|  | @ -58,4 +58,14 @@ fun makeCounter() { | |||
| var counter = makeCounter(); | ||||
| 
 | ||||
| counter(); | ||||
| 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…
	
	Add table
		
		Reference in a new issue