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:
parent
56d8fa97ed
commit
1d8e3f4f8b
3 changed files with 28 additions and 5 deletions
|
@ -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),
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
Loading…
Reference in a new issue