Skip to content

Commit

Permalink
function clock() call
Browse files Browse the repository at this point in the history
  • Loading branch information
cezaris13 committed Dec 8, 2024
1 parent 57ef2ec commit 1bb316f
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 38 deletions.
1 change: 0 additions & 1 deletion src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use std::rc::Rc;
#[path = "./tests/environment_tests.rs"]
mod tests;

#[derive(Debug)]
pub struct Environment {
pub values: HashMap<String, LiteralValue>,
pub enclosing: Option<Rc<RefCell<Environment>>>,
Expand Down
46 changes: 39 additions & 7 deletions src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub enum Expression {
Call {
callee: Box<Expression>,
paren: Token,
arguments: Vec<Box<Expression>>,
arguments: Vec<Expression>,
},
}

Expand Down Expand Up @@ -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::<Vec<String>>()
.join(",");

format!("({} [{}])", callee, comma_separated)
}
};
write!(f, "{}", str)
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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(&parameters))
}
_ => Err(format!("Cannot use {} as callable", callable.to_type())),
}
}
}
}
Expand Down
61 changes: 58 additions & 3 deletions src/expression_literal_value.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,70 @@
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),
StringValue(String),
True,
False,
Nil,
Callable {
name: String,
arity: usize,
fun: Rc<dyn Fn(&Vec<LiteralValue>) -> 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<Token> for LiteralValue {
Expand Down Expand Up @@ -58,6 +106,7 @@ impl From<&LiteralValue> for bool {
True => true,
False => false,
Nil => false,
Callable { .. } => todo!(),
}
}
}
Expand All @@ -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)
}
Expand All @@ -90,6 +144,7 @@ impl LiteralValue {
True | False => "Bool",
StringValue(_) => "String",
Nil => "Nil",
Callable { .. } => "Callable",
}
}

Expand Down
34 changes: 26 additions & 8 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand All @@ -14,10 +15,29 @@ pub struct Interpreter {
pub environment: Rc<RefCell<Environment>>,
}

fn clock_impl(_args: &Vec<LiteralValue>) -> 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)),
}
}

Expand All @@ -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 } => {
Expand Down
2 changes: 1 addition & 1 deletion src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 1bb316f

Please sign in to comment.