about summary refs log tree commit diff
path: root/users/tazjin/rlox
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-01-14T00·14+0300
committertazjin <mail@tazj.in>2021-01-14T00·31+0000
commit26544aa5f05021ed95eca77966738a84d8be902e (patch)
treee6a1b464d7006c40402cb7c3cb60d7e3a0aacaa2 /users/tazjin/rlox
parent090c96eae998fd399975e85321189a136a7dbddd (diff)
feat(tazjin/rlox): Implement function call evaluation r/2096
Change-Id: I6767c3a1a9654475b4066415f8c026b9c5b5907a
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2382
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
Diffstat (limited to 'users/tazjin/rlox')
-rw-r--r--users/tazjin/rlox/src/errors.rs1
-rw-r--r--users/tazjin/rlox/src/interpreter.rs35
2 files changed, 34 insertions, 2 deletions
diff --git a/users/tazjin/rlox/src/errors.rs b/users/tazjin/rlox/src/errors.rs
index 64dc7a92072f..484b06bdf6ab 100644
--- a/users/tazjin/rlox/src/errors.rs
+++ b/users/tazjin/rlox/src/errors.rs
@@ -12,6 +12,7 @@ pub enum ErrorKind {
     UndefinedVariable(String),
     InternalError(String),
     InvalidAssignmentTarget(String),
+    RuntimeError(String),
 }
 
 #[derive(Debug)]
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs
index 5e2eba02d460..2ddbab7e1f29 100644
--- a/users/tazjin/rlox/src/interpreter.rs
+++ b/users/tazjin/rlox/src/interpreter.rs
@@ -33,8 +33,9 @@ impl Callable {
 
 // Representation of an in-language value.
 #[derive(Clone, Debug)]
-enum Value {
+pub enum Value {
     Literal(Literal),
+    Callable(Callable),
 }
 
 impl From<Literal> for Value {
@@ -235,7 +236,7 @@ impl Interpreter {
             Expr::Binary(binary) => self.eval_binary(binary),
             Expr::Variable(var) => self.get_var(var),
             Expr::Logical(log) => self.eval_logical(log),
-            Expr::Call(_) => unimplemented!(),
+            Expr::Call(call) => self.eval_call(call),
         }
     }
 
@@ -321,6 +322,36 @@ impl Interpreter {
             }),
         }
     }
+
+    fn eval_call<'a>(&mut self, call: &parser::Call<'a>) -> Result<Value, Error> {
+        let callable = match self.eval(&call.callee)? {
+            Value::Callable(c) => c,
+            Value::Literal(v) => {
+                return Err(Error {
+                    line: call.paren.line,
+                    kind: ErrorKind::RuntimeError(format!("not callable: {:?}", v)),
+                })
+            }
+        };
+
+        let mut args = vec![];
+        for arg in &call.args {
+            args.push(self.eval(arg)?);
+        }
+
+        if callable.arity() != args.len() {
+            return Err(Error {
+                line: call.paren.line,
+                kind: ErrorKind::RuntimeError(format!(
+                    "Expected {} arguments, but got {}",
+                    callable.arity(),
+                    args.len(),
+                )),
+            });
+        }
+
+        callable.call(args)
+    }
 }
 
 // Interpreter functions not dependent on interpreter-state.