about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-01-14T15·16+0300
committertazjin <mail@tazj.in>2021-01-14T15·19+0000
commit1d8e3f4f8b4479a47e744b3d153fe0e624958817 (patch)
tree06d2747cf725fe6e2606c90355c8c1af25305e9c
parent56d8fa97ed936aacb66b13bb4a8c849a9797db93 (diff)
feat(tazjin/rlox): Implement function definitions r/2106
... 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
-rw-r--r--users/tazjin/rlox/src/interpreter.rs11
-rw-r--r--users/tazjin/rlox/src/interpreter/tests.rs15
-rw-r--r--users/tazjin/rlox/src/parser.rs7
3 files changed, 28 insertions, 5 deletions
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs
index ef188b797fa8..f04d767dc5a9 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<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> {
         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 93a025c5e832..bf2cf61b0a76 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 626eda641c03..78aaec105e32 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<Function<'a>>),
 }
 
 // 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> {