feat(tazjin/rlox): Implement function definitions

... with this, functions now work.

Note that this bubbled up another weird code structure nit: The
parser::Function type should probably not carry its name directly.

However this doesn't matter much and I don't care right now.

Change-Id: If8e3b23f07033260433b9acd45f37c0e61fd2ff8
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2393
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2021-01-14 18:16:31 +03:00 committed by tazjin
parent 56d8fa97ed
commit 1d8e3f4f8b
3 changed files with 28 additions and 5 deletions

View file

@ -41,7 +41,7 @@ impl<'a> Callable<'a> {
} }
lox.interpret_block(Rc::new(RwLock::new(fn_env)), &func.body) lox.interpret_block(Rc::new(RwLock::new(fn_env)), &func.body)
}, }
} }
} }
} }
@ -220,7 +220,7 @@ impl<'a> Interpreter<'a> {
Statement::Block(block) => return self.interpret_block(Default::default(), block), Statement::Block(block) => return self.interpret_block(Default::default(), block),
Statement::If(if_stmt) => return self.interpret_if(if_stmt), Statement::If(if_stmt) => return self.interpret_if(if_stmt),
Statement::While(while_stmt) => return self.interpret_while(while_stmt), Statement::While(while_stmt) => return self.interpret_while(while_stmt),
Statement::Function(_) => unimplemented!(), Statement::Function(func) => return self.interpret_function(func.clone()),
}; };
Ok(value) Ok(value)
@ -278,6 +278,13 @@ impl<'a> Interpreter<'a> {
Ok(value) Ok(value)
} }
fn interpret_function(&mut self, stmt: Rc<parser::Function<'a>>) -> Result<Value<'a>, Error> {
let name = stmt.name.clone();
let value = Value::Callable(Callable::Function(stmt));
self.define_var(&name, value.clone())?;
Ok(value)
}
fn eval(&mut self, expr: &Expr<'a>) -> Result<Value<'a>, Error> { fn eval(&mut self, expr: &Expr<'a>) -> Result<Value<'a>, Error> {
match expr { match expr {
Expr::Assign(assign) => self.eval_assign(assign), Expr::Assign(assign) => self.eval_assign(assign),

View file

@ -70,3 +70,18 @@ fn test_binary_operators() {
parse_eval(&code("\"foo\" + \"bar\";")) parse_eval(&code("\"foo\" + \"bar\";"))
); );
} }
#[test]
fn test_functions() {
let code = code(
r#"
fun add(a, b, c) {
a + b + c;
}
add(1, 2, 3);
"#,
);
assert_eq!(Value::Literal(Literal::Number(6.0)), parse_eval(&code));
}

View file

@ -7,6 +7,7 @@
// have real types. // have real types.
use crate::errors::{Error, ErrorKind}; use crate::errors::{Error, ErrorKind};
use crate::scanner::{Token, TokenKind}; use crate::scanner::{Token, TokenKind};
use std::rc::Rc;
// AST // AST
@ -108,7 +109,7 @@ pub enum Statement<'a> {
Block(Block<'a>), Block(Block<'a>),
If(If<'a>), If(If<'a>),
While(While<'a>), While(While<'a>),
Function(Function<'a>), Function(Rc<Function<'a>>),
} }
// Parser // Parser
@ -221,11 +222,11 @@ impl<'a> Parser<'a> {
ErrorKind::ExpectedToken("Expect '{' before function body."), ErrorKind::ExpectedToken("Expect '{' before function body."),
)?; )?;
Ok(Statement::Function(Function { Ok(Statement::Function(Rc::new(Function {
name, name,
params, params,
body: self.block_statement()?, body: self.block_statement()?,
})) })))
} }
fn var_declaration(&mut self) -> StmtResult<'a> { fn var_declaration(&mut self) -> StmtResult<'a> {