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…
	
	Add table
		
		Reference in a new issue