From 1bb316f54c98f7862c42af96054ec43f80a43319 Mon Sep 17 00:00:00 2001 From: Pijus Date: Mon, 9 Dec 2024 00:44:56 +0200 Subject: [PATCH] function clock() call --- src/environment.rs | 1 - src/expression.rs | 46 ++++++++++++++++++++---- src/expression_literal_value.rs | 61 +++++++++++++++++++++++++++++-- src/interpreter.rs | 34 +++++++++++++----- src/parser.rs | 2 +- src/tests/interpreter_tests.rs | 63 +++++++++++++++++++++++---------- 6 files changed, 169 insertions(+), 38 deletions(-) diff --git a/src/environment.rs b/src/environment.rs index fd5a354..e411578 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -8,7 +8,6 @@ use std::rc::Rc; #[path = "./tests/environment_tests.rs"] mod tests; -#[derive(Debug)] pub struct Environment { pub values: HashMap, pub enclosing: Option>>, diff --git a/src/expression.rs b/src/expression.rs index ce95166..ce15539 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -42,7 +42,7 @@ pub enum Expression { Call { callee: Box, paren: Token, - arguments: Vec>, + arguments: Vec, }, } @@ -96,7 +96,15 @@ impl Display for Expression { callee, paren: _, arguments, - } => format!("({} {:?})", callee, arguments), + } => { + let comma_separated = arguments + .iter() + .map(|val| val.to_string()) + .collect::>() + .join(","); + + format!("({} [{}])", callee, comma_separated) + } }; write!(f, "{}", str) } @@ -139,8 +147,8 @@ impl Expression { GreaterEqual => compare_values!(>=, left, right), Less => compare_values!(<, left, right), LessEqual => compare_values!(<=, left, right), - BangEqual => Ok(LiteralValue::from(left != right)), - EqualEqual => Ok(LiteralValue::from(left == right)), + BangEqual => compare_values!(!=, left, right), + EqualEqual => compare_values!(==, left, right), _ => LiteralValue::not_implemented_error( &stringify!(operator.token_type), &left, @@ -175,11 +183,35 @@ impl Expression { } Self::Call { callee, - paren, + paren: _, arguments, } => { - println!("{:?} {:?} {:?}", callee, paren, arguments); - todo!() + let callable = (*callee).evaluate(environment)?; + match callable { + Callable { name, arity, fun } => { + if arity != arguments.len() { + return Err(format!( + "Expected {} arguments but got {}.", + arity, + arguments.len() + )); + } + + let mut parameters = vec![]; + for argument in arguments { + let literal = argument.evaluate(environment)?; + parameters.push(literal); + } + + // figure out if the variable can be the same name as the function?? + if let Err(_) = environment.get(&name) { + return Err(format!("undefined function {}", name)); + } + + Ok(fun(¶meters)) + } + _ => Err(format!("Cannot use {} as callable", callable.to_type())), + } } } } diff --git a/src/expression_literal_value.rs b/src/expression_literal_value.rs index 311b2c9..aff3163 100644 --- a/src/expression_literal_value.rs +++ b/src/expression_literal_value.rs @@ -1,15 +1,16 @@ use crate::expression_literal_value::LiteralValue::*; use crate::token::{LiteralValue as TokenLiteralValue, Token, TokenType}; -use std::fmt::{Display, Formatter}; -use std::ops::{Add, Sub, Mul, Div}; +use std::fmt::{self, Display, Formatter}; +use std::ops::{Add, Div, Mul, Sub}; +use std::rc::Rc; use std::string::String; #[cfg(test)] #[path = "./tests/expression_literal_value_tests.rs"] mod tests; -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone)] pub enum LiteralValue { IntValue(i64), FValue(f64), @@ -17,6 +18,53 @@ pub enum LiteralValue { True, False, Nil, + Callable { + name: String, + arity: usize, + fun: Rc) -> LiteralValue>, + }, +} + +impl PartialEq for LiteralValue { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::IntValue(a), Self::IntValue(b)) => a == b, + (Self::FValue(a), Self::FValue(b)) => (a - b).abs() < f64::EPSILON, + (Self::StringValue(a), Self::StringValue(b)) => a == b, + (Self::True, Self::True) => true, + (Self::False, Self::False) => true, + (Self::Nil, Self::Nil) => true, + ( + Self::Callable { + name: a_name, + arity: a_arity, + fun: _, + }, + Self::Callable { + name: b_name, + arity: b_arity, + fun: _, + }, + ) => a_name == b_name && a_arity == b_arity, + _ => false, + } + } +} + +impl fmt::Debug for LiteralValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::IntValue(i) => write!(f, "{}", i), + Self::FValue(fl) => write!(f, "{}", fl), + Self::StringValue(s) => write!(f, "\"{}\"", s), + Self::True => write!(f, "true"), + Self::False => write!(f, "false"), + Self::Nil => write!(f, "nil"), + Self::Callable { name, arity, .. } => { + write!(f, "Callable {{ name: {}, arity: {} }}", name, arity) + } + } + } } impl From for LiteralValue { @@ -58,6 +106,7 @@ impl From<&LiteralValue> for bool { True => true, False => false, Nil => false, + Callable { .. } => todo!(), } } } @@ -77,6 +126,11 @@ impl Display for LiteralValue { True => String::from("true"), False => String::from("false"), Nil => String::from("nil"), + Callable { + name, + arity, + fun: _, + } => format!("Callable: {} {}", name, arity), }; write!(f, "{}", str) } @@ -90,6 +144,7 @@ impl LiteralValue { True | False => "Bool", StringValue(_) => "String", Nil => "Nil", + Callable { .. } => "Callable", } } diff --git a/src/interpreter.rs b/src/interpreter.rs index ff349b0..4d375d0 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -5,6 +5,7 @@ use crate::statement::Statement; use std::cell::RefCell; use std::rc::Rc; +use std::time::SystemTime; #[cfg(test)] #[path = "./tests/interpreter_tests.rs"] @@ -14,10 +15,29 @@ pub struct Interpreter { pub environment: Rc>, } +fn clock_impl(_args: &Vec) -> LiteralValue { + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("Could not get time") + .as_secs(); + + LiteralValue::IntValue(now as i64) +} + impl Interpreter { pub fn new() -> Self { + let mut environment = Environment::new(); + environment.define( + String::from("clock"), + LiteralValue::Callable { + name: String::from("clock"), + arity: 0, + fun: Rc::new(clock_impl), + }, + ); + Self { - environment: Rc::new(RefCell::new(Environment::new())), + environment: Rc::new(RefCell::new(environment)), } } @@ -32,15 +52,13 @@ impl Interpreter { println!("{}", result); } Statement::Variable { token, initializer } => { - let nil = Expression::Literal { - value: LiteralValue::Nil, + let value = match initializer { + Expression::Literal { + value: LiteralValue::Nil, + } => LiteralValue::Nil, + _ => initializer.evaluate(&mut self.environment.borrow_mut())?, }; - let value = if initializer != nil { - initializer.evaluate(&mut self.environment.borrow_mut())? - } else { - LiteralValue::Nil - }; self.environment.borrow_mut().define(token.lexeme, value); } Statement::Block { statements } => { diff --git a/src/parser.rs b/src/parser.rs index d91eba8..94808ce 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -389,7 +389,7 @@ impl Parser { return Err(format!("Cant't have more than 255 arguments")); } - arguments.push(Box::new(self.expression()?)); + arguments.push(self.expression()?); if !self.match_tokens(vec![Comma]) { break; diff --git a/src/tests/interpreter_tests.rs b/src/tests/interpreter_tests.rs index 428f9fd..6dddcb7 100644 --- a/src/tests/interpreter_tests.rs +++ b/src/tests/interpreter_tests.rs @@ -16,10 +16,14 @@ mod tests { let statements = parser.parse().unwrap(); let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); let result = interpreter.interpret_statements(statements); assert!(result.is_ok()); - assert!(interpreter.environment.borrow().values.is_empty()); + assert_eq!( + variable_count, + interpreter.environment.borrow().values.len() + ); } #[test] @@ -33,11 +37,14 @@ mod tests { let statements = parser.parse().unwrap(); let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); let result = interpreter.interpret_statements(statements); assert!(result.is_ok()); - assert_eq!(interpreter.environment.borrow().values.is_empty(), false); - assert_eq!(interpreter.environment.borrow().values.len(), 1); + assert_eq!( + interpreter.environment.borrow().values.len(), + variable_count + 1 + ); assert_eq!( interpreter.environment.borrow().get("a"), Ok(LiteralValue::IntValue(12)) @@ -55,12 +62,15 @@ mod tests { let statements = parser.parse().unwrap(); let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); let result = interpreter.interpret_statements(statements); assert!(result.is_ok()); - assert_eq!(interpreter.environment.borrow().values.is_empty(), false); - assert_eq!(interpreter.environment.borrow().values.len(), 1); + assert_eq!( + interpreter.environment.borrow().values.len(), + variable_count + 1 + ); assert_eq!( interpreter.environment.borrow().get("a"), Ok(LiteralValue::Nil) @@ -97,12 +107,15 @@ mod tests { let statements = parser.parse().unwrap(); let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); let result = interpreter.interpret_statements(statements); assert!(result.is_ok()); - assert_eq!(interpreter.environment.borrow().values.is_empty(), false); - assert_eq!(interpreter.environment.borrow().values.len(), 3); + assert_eq!( + interpreter.environment.borrow().values.len(), + variable_count + 3 + ); assert_eq!( interpreter.environment.borrow().get("a"), Ok(LiteralValue::StringValue(String::from("global a"))) @@ -141,12 +154,15 @@ mod tests { let statements = parser.parse().unwrap(); let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); let result = interpreter.interpret_statements(statements); assert!(result.is_ok()); - assert_eq!(interpreter.environment.borrow().values.is_empty(), false); - assert_eq!(interpreter.environment.borrow().values.len(), 3); + assert_eq!( + interpreter.environment.borrow().values.len(), + variable_count + 3 + ); assert_eq!( interpreter.environment.borrow().get("a"), Ok(LiteralValue::IntValue(5)) @@ -176,12 +192,14 @@ mod tests { let statements = parser.parse().unwrap(); let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); let result = interpreter.interpret_statements(statements); assert!(result.is_ok()); - - assert_eq!(interpreter.environment.borrow().values.is_empty(), false); - assert_eq!(interpreter.environment.borrow().values.len(), 1); + assert_eq!( + interpreter.environment.borrow().values.len(), + variable_count + 1 + ); assert_eq!( interpreter.environment.borrow().get("a"), Ok(LiteralValue::IntValue(12)) @@ -203,12 +221,15 @@ mod tests { let statements = parser.parse().unwrap(); let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); let result = interpreter.interpret_statements(statements); assert!(result.is_ok()); - assert_eq!(interpreter.environment.borrow().values.is_empty(), false); - assert_eq!(interpreter.environment.borrow().values.len(), 1); + assert_eq!( + interpreter.environment.borrow().values.len(), + variable_count + 1 + ); assert_eq!( interpreter.environment.borrow().get("i"), Ok(LiteralValue::IntValue(10)) @@ -230,12 +251,15 @@ mod tests { let statements = parser.parse().unwrap(); let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); let result = interpreter.interpret_statements(statements); assert!(result.is_ok()); - assert_eq!(interpreter.environment.borrow().values.is_empty(), false); - assert_eq!(interpreter.environment.borrow().values.len(), 1); + assert_eq!( + interpreter.environment.borrow().values.len(), + variable_count + 1 + ); assert_eq!( interpreter.environment.borrow().get("i"), Ok(LiteralValue::IntValue(10)) @@ -257,12 +281,15 @@ mod tests { let statements = parser.parse().unwrap(); let mut interpreter: Interpreter = Interpreter::new(); + let variable_count = interpreter.environment.borrow().values.len(); let result = interpreter.interpret_statements(statements); assert!(result.is_ok()); - assert_eq!(interpreter.environment.borrow().values.is_empty(), false); - assert_eq!(interpreter.environment.borrow().values.len(), 1); + assert_eq!( + interpreter.environment.borrow().values.len(), + variable_count + 1 + ); assert_eq!( interpreter.environment.borrow().get("a"), Ok(LiteralValue::IntValue(20))