From 1d8e3f4f8b4479a47e744b3d153fe0e624958817 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Thu, 14 Jan 2021 18:16:31 +0300 Subject: [PATCH] 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 Tested-by: BuildkiteCI --- users/tazjin/rlox/src/interpreter.rs | 11 +++++++++-- users/tazjin/rlox/src/interpreter/tests.rs | 15 +++++++++++++++ users/tazjin/rlox/src/parser.rs | 7 ++++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index ef188b797..f04d767dc 100644 --- a/users/tazjin/rlox/src/interpreter.rs +++ b/users/tazjin/rlox/src/interpreter.rs @@ -41,7 +41,7 @@ impl<'a> Callable<'a> { } 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::If(if_stmt) => return self.interpret_if(if_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) @@ -278,6 +278,13 @@ impl<'a> Interpreter<'a> { Ok(value) } + fn interpret_function(&mut self, stmt: Rc>) -> Result, 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, Error> { match expr { Expr::Assign(assign) => self.eval_assign(assign), diff --git a/users/tazjin/rlox/src/interpreter/tests.rs b/users/tazjin/rlox/src/interpreter/tests.rs index 93a025c5e..bf2cf61b0 100644 --- a/users/tazjin/rlox/src/interpreter/tests.rs +++ b/users/tazjin/rlox/src/interpreter/tests.rs @@ -70,3 +70,18 @@ fn test_binary_operators() { 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)); +} diff --git a/users/tazjin/rlox/src/parser.rs b/users/tazjin/rlox/src/parser.rs index 626eda641..78aaec105 100644 --- a/users/tazjin/rlox/src/parser.rs +++ b/users/tazjin/rlox/src/parser.rs @@ -7,6 +7,7 @@ // have real types. use crate::errors::{Error, ErrorKind}; use crate::scanner::{Token, TokenKind}; +use std::rc::Rc; // AST @@ -108,7 +109,7 @@ pub enum Statement<'a> { Block(Block<'a>), If(If<'a>), While(While<'a>), - Function(Function<'a>), + Function(Rc>), } // Parser @@ -221,11 +222,11 @@ impl<'a> Parser<'a> { ErrorKind::ExpectedToken("Expect '{' before function body."), )?; - Ok(Statement::Function(Function { + Ok(Statement::Function(Rc::new(Function { name, params, body: self.block_statement()?, - })) + }))) } fn var_declaration(&mut self) -> StmtResult<'a> {