diff --git a/src/ast.rs b/src/ast.rs index 5e6b758..7d80541 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -16,22 +16,24 @@ impl std::fmt::Display for Node { } } +#[derive(Clone, Debug, PartialEq)] pub enum Literal { Integer(Integer), Boolean(Boolean), - String(StringLiteral) + String(StringLiteral), } impl std::fmt::Display for Literal { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Literal::Integer(Integer { token, value }) => write!(f, "{}", value), - Literal::Boolean(Boolean { token, value }) => write!(f, "{}", value), - Literal::String(StringLiteral { token, value }) => write!(f, "{}", value), + Literal::Integer(Integer { token: _, value }) => write!(f, "{}", value), + Literal::Boolean(Boolean { token: _, value }) => write!(f, "{}", value), + Literal::String(StringLiteral { token: _, value }) => write!(f, "{}", value), } } } +#[derive(Clone, Debug, PartialEq)] pub enum Expression { Identifier(Identifier), Literal(Literal), @@ -48,39 +50,46 @@ impl std::fmt::Display for Expression { Expression::Identifier(identifier) => write!(f, "{}", identifier), Expression::Literal(literal) => write!(f, "{}", literal), Expression::Infix(InfixExpression { - token, + token: _, left, operator, right, }) => write!(f, "({} {} {})", left, operator, right), Expression::Prefix(PrefixExpression { - token, + token: _, operator, right, }) => write!(f, "({}{})", operator, right), Expression::If(IfExpression { - token, + token: _, condition, consequence, alternative, }) => { if let Some(alternative) = alternative { - write!(f, "if {} {{\n{}\n}} else {{\n{}\n}}", condition, consequence, alternative) + write!( + f, + "if {} {{\n{}\n}} else {{\n{}\n}}", + condition, consequence, alternative + ) } else { write!(f, "if {} {{\n{}\n}}", condition, consequence) } - }, + } Expression::Function(FunctionLiteral { - token, + token: _, parameters, body, }) => { - let params = parameters.iter().map(|p| p.to_string()).collect::>(); + let params = parameters + .iter() + .map(|p| p.to_string()) + .collect::>(); write!(f, "fn({}) {{\n{}\n}}", params.join(", "), body) - }, + } Expression::Call(CallExpression { - token, + token: _, function, arguments, }) => { @@ -100,6 +109,7 @@ impl std::fmt::Display for Expression { } } +#[derive(Clone, Debug, PartialEq)] pub enum Statement { Assign(Assignment), Expr(Expression), @@ -109,11 +119,9 @@ pub enum Statement { impl std::fmt::Display for Statement { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Statement::Assign(Assignment { - token, - name, - value, - }) => write!(f, "{} {} = {}", token, name, value), + Statement::Assign(Assignment { token, name, value }) => { + write!(f, "{} {} = {}", token, name, value) + } Statement::Expr(expression) => write!(f, "{}", expression), Statement::Return(ReturnStatement { token, @@ -123,6 +131,7 @@ impl std::fmt::Display for Statement { } } +#[derive(Clone, Debug, PartialEq)] pub struct Program { pub statements: Vec, } @@ -148,34 +157,40 @@ impl std::fmt::Display for Program { } // LITERALS +#[derive(Clone, Debug, PartialEq)] pub struct Boolean { pub token: Token, pub value: bool, } +#[derive(Clone, Debug, PartialEq)] pub struct Integer { pub token: Token, pub value: i64, } +#[derive(Clone, Debug, PartialEq)] pub struct StringLiteral { pub token: Token, pub value: String, } // EXPRESSIONS +#[derive(Clone, Debug, PartialEq)] pub struct FunctionLiteral { pub token: Token, pub parameters: Vec, pub body: BlockStatement, } +#[derive(Clone, Debug, PartialEq)] pub struct CallExpression { pub token: Token, pub function: Box, pub arguments: Vec, } +#[derive(Clone, Debug, PartialEq)] pub struct Identifier { pub token: Token, pub value: String, @@ -187,6 +202,7 @@ impl std::fmt::Display for Identifier { } } +#[derive(Clone, Debug, PartialEq)] pub struct IfExpression { pub token: Token, pub condition: Box, @@ -194,6 +210,7 @@ pub struct IfExpression { pub alternative: Option, } +#[derive(Clone, Debug, PartialEq)] pub struct InfixExpression { pub token: Token, pub left: Box, @@ -201,6 +218,7 @@ pub struct InfixExpression { pub right: Box, } +#[derive(Clone, Debug, PartialEq)] pub struct PrefixExpression { pub token: Token, pub operator: String, @@ -208,12 +226,14 @@ pub struct PrefixExpression { } // STATEMENTS +#[derive(Clone, Debug, PartialEq)] pub struct Assignment { pub token: Token, pub name: Identifier, pub value: Expression, } +#[derive(Clone, Debug, PartialEq)] pub struct BlockStatement { pub token: Token, pub statements: Vec, @@ -231,7 +251,8 @@ impl std::fmt::Display for BlockStatement { } } +#[derive(Clone, Debug, PartialEq)] pub struct ReturnStatement { pub token: Token, pub return_value: Expression, -} \ No newline at end of file +} diff --git a/src/evaluator.rs b/src/evaluator.rs index 2b69670..5ab94ce 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -1,87 +1,322 @@ -use anyhow::{Error, Result}; -use lazy_static::lazy_static; -use crate::{object::{Object, self}, ast::{Node, Program, Statement, Boolean, Expression, Literal}}; +use std::{rc::Rc, cell::RefCell}; -lazy_static! { - static ref TRUE: Object = Object::Boolean(true); - static ref FALSE: Object = Object::Boolean(false); -} +use anyhow::{Result, Ok, Error}; +use lazy_static::lazy_static; + +use crate::{ast::{Boolean, Expression, Literal, Node, Statement, IfExpression, FunctionLiteral, CallExpression}, object::{Object, environment::{Env, Environment}}}; -pub fn eval(node: Node) -> Option { +pub fn eval(node: Node, env: &Env) -> Result> { match node { - Node::Expression(expression) => eval_expression(&expression), - Node::Program(program) => eval_statements(&program.statements), - Node::Statement(statement) => eval_statement(&statement), - _ => None, + Node::Expression(expression) => eval_expression(&expression, env), + Node::Program(program) => eval_statements(&program.statements, env), + Node::Statement(statement) => eval_statement(&statement, env), + _ => Err(Error::msg(format!("Unknown node type: {}", node))), } } -pub fn eval_statements(statements: &Vec) -> Option { - let mut result = None; +pub fn eval_statements(statements: &Vec, env: &Env) -> Result> { + let mut result: Rc = Rc::new(Object::Null); for statement in statements { - let val = eval_statement(statement); + let val = eval_statement(statement, env)?; - match val { - Some(Object::Return(value)) => return Some(*value), - Some(_) => result = val, - None => return None, + match *val { + Object::Return(_) => return Ok(val), + _ => result = val, } } - result + Ok(result) +} + +fn apply_function(function: &Rc, args: &Vec>) -> Result> { + match &**function { + Object::Function(params, body, env) => { + let mut env = Environment::new_enclosed_environment(&env); + + params.iter().enumerate().for_each(|(i, param)| { + env.set(param.value.clone(), args[i].clone()); + }); + + let evaluated = eval_statements(&body.statements, &Rc::new(RefCell::new(env)))?; + return unwrap_return_value(evaluated); + } + f => Err(Error::msg(format!("expected {} to be a function", f))), + } +} + +fn is_truthy(object: &Object) -> bool { + match object { + Object::Null => false, + Object::Boolean(boolean) => *boolean, + _ => true, + } +} + +fn unwrap_return_value(object: Rc) -> Result> { + match &* object { + Object::Return(value) => Ok(Rc::clone(value)), + _ => Ok(object), + } } -fn eval_expression(expression: &Expression) -> Option { +fn eval_expression(expression: &Expression, env: &Env) -> Result> { match expression { - Expression::Identifier(identifier) => eval_identifier(identifier.to_string()), + Expression::Identifier(identifier_expression) => eval_identifier(identifier_expression.to_string(), env), Expression::Literal(literal) => eval_literal(&literal), - _ => None, + Expression::Infix(infix_expression) => { + let left = eval_expression(&infix_expression.left, &Rc::clone(env))?; + let right = eval_expression(&infix_expression.right, &Rc::clone(env))?; + + eval_infix_expression( + infix_expression.operator.to_string(), + &left, + &right, + env + ) + }, + Expression::Prefix(prefix_expression) => { + let right = eval_expression(&prefix_expression.right, &Rc::clone(env))?; + + eval_prefix_expression( + prefix_expression.operator.to_string(), + &right, + env + ) + }, + Expression::If(if_expression) => eval_if_expression(expression, env), + Expression::Call(CallExpression { function, token, arguments }) => { + let function = eval_expression(function, env)?; // This should give you a Function object. + let arguments = eval_expressions(arguments, env)?; + + apply_function(&function, &arguments) + }, + Expression::Function(FunctionLiteral { + parameters, + body, + .. + }) => { + Ok(Object::Function(parameters.clone(), body.clone(), Rc::clone(env)).into()) + }, + _ => Err(Error::msg(format!("Unknown expression type: {}", expression))), } } -fn eval_statement(statement: &Statement) -> Option { - match statement { - Statement::Expr(expression) => eval_expression(expression), - _ => None, +fn eval_expressions(exprs: &Vec, env: &Env) -> Result>> { + let mut list = Vec::new(); + for expr in exprs { + let val = eval_expression(expr, &Rc::clone(env))?; + list.push(val); } + + Ok(list) } -fn eval_identifier(identifier: String) -> Option { - unimplemented!("eval_identifier"); +fn eval_if_expression(expression: &Expression, env: &Env) -> Result> { + if let Expression::If(IfExpression { + condition, + consequence, + alternative, + .. + }) = expression + { + let condition = eval_expression(condition, env)?; + + if is_truthy(&condition) { + eval_statements(&consequence.statements, env) + } else { + match alternative { + Some(alternative) => eval_statements(&alternative.statements, env), + None => Ok(Object::Null.into()), + } + } + } else { + Err(Error::msg(format!("Unknown expression type: {}", expression))) + } } -fn eval_literal(literal: &Literal) -> Option { - match literal { - Literal::Integer(integer) => Some(Object::Integer(integer.value)), - Literal::Boolean(Boolean { value, .. }) => Some(Object::Boolean(*value)), - Literal::String(string) => Some(Object::String(string.value.clone())), - _ => None, +fn eval_infix_expression(operator: String, left: &Object, right: &Object, env: &Env) -> Result> { + match (left, right) { + (Object::Integer(left), Object::Integer(right)) => { + eval_integer_infix_expression(operator, *left, *right) + } + (Object::Boolean(left), Object::Boolean(right)) => { + eval_boolean_infix_expression(operator, *left, *right) + } + (Object::String(left), Object::String(right)) => { + eval_string_infix_expression(operator, left.to_string(), right.to_string()) + } + _ => Err(Error::msg(format!( + "Unknown operator: {}", + operator + ))), } } -fn native_bool_to_bool_object(input: bool) -> &'static Object { - if input { - &TRUE - } else { - &FALSE +fn eval_boolean_infix_expression(operator: String, left: bool, right: bool) -> Result> { + let result = match operator.as_str() { + "==" => native_bool_to_bool_object(left == right), + "!=" => native_bool_to_bool_object(left != right), + _ => return Err(Error::msg(format!( + "Unknown operator: {} {} {}", + left, operator, right + ))), + }; + + Ok(result.into()) +} + +fn eval_integer_infix_expression(operator: String, left: i64, right: i64) -> Result> { + let result = match operator.as_str() { + "+" => Object::Integer(left + right), + "-" => Object::Integer(left - right), + "*" => Object::Integer(left * right), + "/" => Object::Integer(left / right), + "<" => native_bool_to_bool_object(left < right), + ">" => native_bool_to_bool_object(left > right), + "==" => native_bool_to_bool_object(left == right), + "!=" => native_bool_to_bool_object(left != right), + _ => return Err(Error::msg(format!( + "Unknown operator: {} {} {}", + left, operator, right + ))), + }; + + Ok(result.into()) +} + +fn eval_string_infix_expression(operator: String, left: String, right: String) -> Result> { + let result = match operator.as_str() { + "+" => Object::String(format!("{}{}", left, right)), + _ => return Err(Error::msg(format!( + "Unknown operator: {} {} {}", + left, operator, right + ))), + }; + + Ok(result.into()) +} + +fn eval_prefix_expression(operator: String, right: &Object, env: &Env) -> Result> { + match operator.as_str() { + "-" => eval_minus_prefix_operator_expression(right), + "!" => eval_bang_operator_expression(right), + _ => return Err(Error::msg(format!( + "Unknown operator: {}{}", + operator, right + ))), + } +} + +fn eval_bang_operator_expression(right: &Object) -> Result> { + let result = match *right { + Object::Null => Rc::new(Object::Boolean(true)), + Object::Boolean(boolean) => Rc::new(Object::Boolean(!boolean)), + _ => Rc::new(Object::Boolean(false)), + }; + + Ok(result.into()) +} + +fn eval_minus_prefix_operator_expression(right: &Object) -> Result> { + let result = match *right { + Object::Integer(integer) => Rc::from(Object::Integer(-integer)), + _ => return Err(Error::msg(format!( + "Invalid use of minus operator: -{}", + right + ))), + }; + + Ok(result.into()) +} + +fn eval_statement(statement: &Statement, env: &Env) -> Result> { + match statement { + Statement::Expr(expression) => eval_expression(expression, env), + Statement::Assign(assignment) => { + let value = eval_expression(&assignment.value, env)?; + let object = Rc::clone(&value); + + env.borrow_mut().set(assignment.name.to_string(), object); + + Ok(value) + }, + Statement::Return(return_statement) => { + let value = eval_expression(&return_statement.return_value, env)?; + + Ok(Rc::new(Object::Return(value))) + }, + _ => Err(Error::msg(format!("Unknown statement type: {}", statement))), } } +fn eval_identifier(identifier: String, env: &Env) -> Result> { + match env.borrow().get(&identifier) { + Some(value) => Ok(value), + None => Err(Error::msg(format!("Identifier not found: {}", identifier))), + } +} + +fn eval_literal(literal: &Literal) -> Result> { + let result = match literal { + Literal::Integer(integer) => Object::Integer(integer.value), + Literal::Boolean(Boolean { value, .. }) => Object::Boolean(*value), + Literal::String(string) => Object::String(string.value.clone()), + _ => return Err(Error::msg(format!("Unknown literal type: {}", literal))), + }; + + Ok(result.into()) +} + +fn native_bool_to_bool_object(input: bool) -> Object { + Object::Boolean(input) +} + #[cfg(test)] mod tests { + use std::cell::RefCell; + use anyhow::Error; - use crate::{object::{Object}, lexer::Lexer, parser::Parser}; + use crate::{lexer::Lexer, object::{Object, environment::Environment}, parser::Parser}; use super::*; #[test] fn test_eval_boolean_literals() -> Result<(), Error> { + let tests = vec![("true", true), ("false", false)]; + + for (input, expected) in tests { + let evaluated = assert_eval(input)?; + assert_boolean_literal_object(evaluated, expected)?; + } + + Ok(()) + } + + #[test] + fn test_eval_boolean_expression() -> Result<(), Error> { let tests = vec![ ("true", true), ("false", false), + ("1 < 2", true), + ("1 > 2", false), + ("1 < 1", false), + ("1 > 1", false), + ("1 == 1", true), + ("1 != 1", false), + ("1 == 2", false), + ("1 != 2", true), + ("true == true", true), + ("false == false", true), + ("true == false", false), + ("true != false", true), + ("false != true", true), + ("(1 < 2) == true", true), + ("(1 < 2) == false", false), + ("(1 > 2) == true", false), + ("(1 > 2) == false", true), ]; for (input, expected) in tests { @@ -95,32 +330,119 @@ mod tests { #[test] fn test_eval_integer_expression() -> Result<(), Error> { let tests = vec![ - ("5", 5), + ("5", 5), ("10", 10), + ("-5", -5), + ("-10", -10), + ("5 + 5 + 5 + 5 - 10", 10), + ("2 * 2 * 2 * 2 * 2", 32), + ("-50 + 100 + -50", 0), + ("5 * 2 + 10", 20), + ("5 + 2 * 10", 25), + ("20 + 2 * -10", 0), + ("50 / 2 * 2 + 10", 60), + ("2 * (5 + 10)", 30), + ("3 * 3 * 3 + 10", 37), + ("3 * (3 * 3) + 10", 37), + ("(5 + 10 * 2 + 15 / 3) * 2 + -10", 50), + ]; + + for (input, expected) in tests { + let evaluated = assert_eval(input)?; + assert_integer_object(evaluated, expected)?; + } + + Ok(()) + } + + #[test] + fn test_eval_bang_operator() -> Result<(), Error> { + let tests = vec![("!true", false), ("!false", true), ("!5", false), ("!!true", true)]; + + for (input, expected) in tests { + let evaluated = assert_eval(input)?; + assert_boolean_literal_object(evaluated, expected)?; + } + + Ok(()) + } + + #[test] + fn test_eval_if_else_expressions() -> Result<(), Error> { + let tests = vec![ + ("if (true) { 10 }", Some(10)), + ("if (false) { 10 }", None), + ("if (1) { 10 }", Some(10)), + ("if (1 < 2) { 10 }", Some(10)), + ("if (1 > 2) { 10 }", None), + ("if (1 > 2) { 10 } else { 20 }", Some(20)), + ("if (1 < 2) { 10 } else { 20 }", Some(10)), + ]; + + for (input, expected) in tests { + let evaluated = assert_eval(input)?; + + if let Some(expected) = expected { + assert_integer_object(evaluated, expected)?; + } else { + assert_eq!(*evaluated, Object::Null); + } + } + + Ok(()) + } + + #[test] + fn test_eval_assertions() -> Result<(), Error> { + let tests = vec![ + ("$a = 5; $a;", 5), + ("$a = 5 * 5; $a;", 25), + ("$a = 5; $a;", 5), + ]; + + for (input, expected) in tests { + let evaluated = assert_eval(input)?; + + dbg!(&evaluated); + + assert_integer_object(evaluated, expected)?; + } + + Ok(()) + } + + #[test] + fn test_eval_functions() -> Result<(), Error> { + let tests = vec![ + ("function ($x) { $x + 2; }(2);", 4) ]; for (input, expected) in tests { let evaluated = assert_eval(input)?; + + dbg!(&evaluated); assert_integer_object(evaluated, expected)?; } Ok(()) } - fn assert_eval(input: &str) -> Result { + fn assert_eval(input: &str) -> Result, Error> { + let env = Rc::new(RefCell::new(Environment::new())); + let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; - let evaluated = eval_statements(&program.statements).ok_or_else(|| anyhow::anyhow!("eval returned None"))?; + let evaluated = eval(Node::Program(program), &env); - Ok(evaluated) + evaluated } - fn assert_boolean_literal_object(object: Object, expected: bool) -> Result<(), Error> { - if let Object::Boolean(boolean) = object { + fn assert_boolean_literal_object(object: Rc, expected: bool) -> Result<(), Error> { + if let Object::Boolean(boolean) = *object { assert_eq!(boolean, expected); } else { return Err(anyhow::anyhow!("Object is not a Boolean.")); @@ -129,8 +451,8 @@ mod tests { Ok(()) } - fn assert_integer_object(object: Object, expected: i64) -> Result<(), Error> { - if let Object::Integer(integer) = object { + fn assert_integer_object(object: Rc, expected: i64) -> Result<(), Error> { + if let Object::Integer(integer) = *object { assert_eq!(integer, expected); } else { return Err(anyhow::anyhow!("Object is not an Integer.")); @@ -138,4 +460,4 @@ mod tests { Ok(()) } -} \ No newline at end of file +} diff --git a/src/lexer.rs b/src/lexer.rs index ca89532..1abf93e 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -53,7 +53,25 @@ impl<'a> Lexer<'a> { Some('*') => (TokenType::Asterisk, "*".to_string()), Some('<') => (TokenType::Lt, "<".to_string()), Some('>') => (TokenType::Gt, ">".to_string()), - Some('$') => (TokenType::Dollar, "$".to_string()), + Some('$') => { + self.read_char(); + + if let Some(ch) = self.ch { + if ch.is_alphabetic() || ch == '_' { + let identifier = self.read_identifier(); + let var_name = format!("${}", identifier); + + return Token { + token_type: TokenType::Ident, + literal: var_name, + }; + } else { + (TokenType::Illegal, "$".to_string()) + } + } else { + (TokenType::Illegal, "$".to_string()) + } + } Some(ch) => { if ch.is_alphabetic() { let literal = self.read_identifier(); @@ -152,24 +170,20 @@ mod tests { let input = " $five = 5; - $ten = five + 5; + $ten = $five + 5; - $add = function (x, y) { - return x + y; + $add = function ($x, $y) { + return $x + $y; } - $result = add(five, ten); + $result = $add($five, $ten); " .to_string(); let expected_tokens = [ - Token { - token_type: TokenType::Dollar, - literal: "$".to_string(), - }, Token { token_type: TokenType::Ident, - literal: "five".to_string(), + literal: "$five".to_string(), }, Token { token_type: TokenType::Assign, @@ -183,13 +197,9 @@ mod tests { token_type: TokenType::Semicolon, literal: ";".to_string(), }, - Token { - token_type: TokenType::Dollar, - literal: "$".to_string(), - }, Token { token_type: TokenType::Ident, - literal: "ten".to_string(), + literal: "$ten".to_string(), }, Token { token_type: TokenType::Assign, @@ -197,7 +207,7 @@ mod tests { }, Token { token_type: TokenType::Ident, - literal: "five".to_string(), + literal: "$five".to_string(), }, Token { token_type: TokenType::Plus, @@ -211,13 +221,9 @@ mod tests { token_type: TokenType::Semicolon, literal: ";".to_string(), }, - Token { - token_type: TokenType::Dollar, - literal: "$".to_string(), - }, Token { token_type: TokenType::Ident, - literal: "add".to_string(), + literal: "$add".to_string(), }, Token { token_type: TokenType::Assign, @@ -233,7 +239,7 @@ mod tests { }, Token { token_type: TokenType::Ident, - literal: "x".to_string(), + literal: "$x".to_string(), }, Token { token_type: TokenType::Comma, @@ -241,7 +247,7 @@ mod tests { }, Token { token_type: TokenType::Ident, - literal: "y".to_string(), + literal: "$y".to_string(), }, Token { token_type: TokenType::RParen, @@ -257,7 +263,7 @@ mod tests { }, Token { token_type: TokenType::Ident, - literal: "x".to_string(), + literal: "$x".to_string(), }, Token { token_type: TokenType::Plus, @@ -265,7 +271,7 @@ mod tests { }, Token { token_type: TokenType::Ident, - literal: "y".to_string(), + literal: "$y".to_string(), }, Token { token_type: TokenType::Semicolon, @@ -275,13 +281,9 @@ mod tests { token_type: TokenType::RBrace, literal: "}".to_string(), }, - Token { - token_type: TokenType::Dollar, - literal: "$".to_string(), - }, Token { token_type: TokenType::Ident, - literal: "result".to_string(), + literal: "$result".to_string(), }, Token { token_type: TokenType::Assign, @@ -289,7 +291,7 @@ mod tests { }, Token { token_type: TokenType::Ident, - literal: "add".to_string(), + literal: "$add".to_string(), }, Token { token_type: TokenType::LParen, @@ -297,7 +299,7 @@ mod tests { }, Token { token_type: TokenType::Ident, - literal: "five".to_string(), + literal: "$five".to_string(), }, Token { token_type: TokenType::Comma, @@ -305,7 +307,7 @@ mod tests { }, Token { token_type: TokenType::Ident, - literal: "ten".to_string(), + literal: "$ten".to_string(), }, Token { token_type: TokenType::RParen, diff --git a/src/main.rs b/src/main.rs index b6eb0f5..bcc89de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,11 +6,11 @@ use repl::init_repl; mod ast; mod evaluator; mod lexer; +mod object; mod parser; mod repl; mod string; mod token; -mod object; pub const NAME: &str = env!("CARGO_PKG_NAME"); pub const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -38,7 +38,7 @@ fn main() -> Result<(), Error> { let lexer = lexer::Lexer::new(&file); let mut parser = parser::Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; diff --git a/src/object/environment.rs b/src/object/environment.rs new file mode 100644 index 0000000..36f2825 --- /dev/null +++ b/src/object/environment.rs @@ -0,0 +1,44 @@ +use std::{collections::HashMap, rc::Rc, cell::RefCell}; + +use super::Object; + +pub type Env = Rc>; + +#[derive(Debug)] +pub struct Environment { + store: HashMap>, + outer: Option, +} + +impl PartialEq for Environment { + fn eq(&self, other: &Self) -> bool { + self.store == other.store + } +} + +impl Environment { + pub fn new() -> Self { + Self { + store: HashMap::new(), + outer: None, + } + } + + pub fn new_enclosed_environment(outer: &Env) -> Self { + let mut env = Self::new(); + env.outer = Some(Rc::clone(outer)); + + env + } + + pub fn get(&self, name: &str) -> Option> { + match self.store.get(name) { + Some(value) => Some(Rc::clone(value)), + None => None, + } + } + + pub fn set(&mut self, name: String, value: Rc) -> Option> { + self.store.insert(name, value) + } +} \ No newline at end of file diff --git a/src/object.rs b/src/object/mod.rs similarity index 70% rename from src/object.rs rename to src/object/mod.rs index 0e038fd..dc76cb9 100644 --- a/src/object.rs +++ b/src/object/mod.rs @@ -1,11 +1,18 @@ -use crate::ast::BlockStatement; +use std::rc::Rc; +use crate::ast::{BlockStatement, Identifier}; + +use self::environment::Env; + +pub mod environment; + +#[derive(Clone, Debug, PartialEq)] pub enum Object { Integer(i64), Boolean(bool), String(String), - Function(Vec, BlockStatement), - Return(Box), + Function(Vec, BlockStatement, Env), + Return(Rc), Null, } @@ -15,11 +22,11 @@ impl std::fmt::Display for Object { Object::Integer(integer) => write!(f, "{}", integer), Object::Boolean(boolean) => write!(f, "{}", boolean), Object::String(string) => write!(f, "{}", string), - Object::Function(parameters, body) => { + Object::Function(parameters, body, _env) => { let mut parameters_string = String::new(); for (index, parameter) in parameters.iter().enumerate() { - parameters_string.push_str(parameter); + parameters_string.push_str(¶meter.to_string()); if index < parameters.len() - 1 { parameters_string.push_str(", "); @@ -27,9 +34,9 @@ impl std::fmt::Display for Object { } write!(f, "fn({}) {{\n{}\n}}", parameters_string, body) - }, + } Object::Return(value) => write!(f, "{}", value), Object::Null => write!(f, "null"), } } -} \ No newline at end of file +} diff --git a/src/parser.rs b/src/parser.rs index 0026fb0..2cc1519 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,18 +1,19 @@ use std::collections::HashMap; -use anyhow::Error; -use log::trace; +use anyhow::{Error, Result}; +use log::{trace, info}; use crate::{ ast::{ - Expression, Identifier, InfixExpression, - PrefixExpression, Program, ReturnStatement, Statement, Boolean, IfExpression, BlockStatement, FunctionLiteral, Node, Assignment, CallExpression, Literal, Integer, + Assignment, BlockStatement, Boolean, CallExpression, Expression, FunctionLiteral, + Identifier, IfExpression, InfixExpression, Integer, Literal, PrefixExpression, + Program, ReturnStatement, Statement, }, lexer::Lexer, token::{Token, TokenType}, }; -type ParseResult = Option; +type ParseResult = Result; type PrefixParseFn = fn(&mut Parser) -> ParseResult; type InfixParseFn = fn(&mut Parser, Expression) -> ParseResult; @@ -115,7 +116,9 @@ impl<'a> Parser<'a> { parser.register_prefix(TokenType::If, |p| Parser::parse_if_expression(p)); parser.register_prefix(TokenType::Bang, |p| Parser::parse_prefix_expression(p)); parser.register_prefix(TokenType::Minus, |p| Parser::parse_prefix_expression(p)); - parser.register_prefix(TokenType::Dollar, |p| Parser::parse_variable_reference_expression(p)); + parser.register_prefix(TokenType::Dollar, |p| { + Parser::parse_variable_reference_expression(p) + }); parser.register_infix(TokenType::LParen, |p, left| { Parser::parse_call_expression(p, left) @@ -166,6 +169,15 @@ impl<'a> Parser<'a> { } } + fn expect_current(&mut self, t: TokenType) -> bool { + if self.current_token.is_some() && self.current_token.as_ref().unwrap().token_type == t { + true + } else { + self.errors.push(format!("Expected {:?}, got {:?}", t, self.current_token)); + false + } + } + pub fn expect_peek(&mut self, token_type: TokenType) -> bool { if self.peek_token_is(&token_type) { self.next_token(); @@ -182,138 +194,118 @@ impl<'a> Parser<'a> { self.peek_token.as_ref().unwrap().token_type == token_type.to_owned() } - fn parse_boolean(&mut self) -> Option { + fn parse_boolean(&mut self) -> Result { let current_token = self.current_token.clone().unwrap(); let value = match self.current_token.as_ref().unwrap().token_type { TokenType::True => true, TokenType::False => false, _ => { - self.errors.push(format!( + return Err(Error::msg(format!( "Expected true or false, got {:?}", self.current_token.as_ref().unwrap().token_type - )); - return None; + ))); } }; - Some(Expression::Literal(Literal::Boolean( Boolean { + Ok(Expression::Literal(Literal::Boolean(Boolean { token: current_token, value, }))) } - pub fn parse_program(&mut self) -> Program { + pub fn parse_program(&mut self) -> Result { let mut program = Program::default(); - while self.current_token.as_ref().unwrap().token_type != TokenType::Eof { - let statement = self.parse_statement(); - - if let Some(statement) = statement { - program.statements.push(statement); + while !self.current_token_is(TokenType::Eof) { + match self.parse_statement() { + Ok(stmt) => program.statements.push(stmt), + Err(e) => self.errors.push(e.to_string()), } - self.next_token(); } - program + if self.errors.is_empty() { + Ok(program) + } else { + Err(Error::msg(format!( + "Parser has errors: {}", + self.errors.join(", ") + ))) + } } - pub fn parse_statement(&mut self) -> Option { + pub fn parse_statement(&mut self) -> Result { if let Some(token) = &self.current_token { - match token.token_type { + match &token.token_type { TokenType::Return => self.parse_return_statement(), - TokenType::Dollar => self.parse_assignment_statement(), + TokenType::Ident if token.literal.starts_with('$') => { + if self.peek_token_is(&TokenType::Assign) { + self.parse_assignment_statement() + } else { + self.parse_expression_statement() + } + }, _ => self.parse_expression_statement(), } } else { - None + Err(Error::msg("Unexpected end of input")) } } - fn parse_variable_reference_expression(&mut self) -> Option { - if let Some(token) = &self.current_token { - if token.token_type != TokenType::Dollar { - self.errors.push(format!("Expected $, got {:?}", token)); - return None; - } - } else { - self.errors.push("Expected $, got None".to_string()); - return None; - } - - self.next_token(); + fn parse_variable_reference_expression(&mut self) -> Result { + info!("parse_variable_reference_expression: Current token: {:?}", self.current_token); - // Ensure the variable name is an identifier. - let name_token = if let Some(token) = &self.current_token { + // Expect the next token to be an identifier + if let Some(token) = &self.current_token { if token.token_type == TokenType::Ident { - token.clone() + let identifier = Identifier { + token: token.clone(), + value: token.literal.clone(), + }; + + self.next_token(); + + return Ok(Expression::Identifier(identifier)); } else { - self.errors - .push(format!("Expected identifier, got {:?}", token)); - return None; + return Err(Error::msg(format!( + "Expected identifier after $, got {:?}", + token + ))); } } else { - self.errors - .push("Expected identifier, got None".to_string()); - return None; - }; - - // Parse as reference - let identifier = Identifier { - token: name_token.clone(), - value: name_token.literal.clone(), - }; - - Some(Expression::Identifier(identifier)) - } - - fn parse_assignment_statement(&mut self) -> Option { - trace!("Current token: {:?}", self.current_token); - // Ensure the current token is a Dollar sign. - if let Some(token) = &self.current_token { - if token.token_type != TokenType::Dollar { - self.errors.push(format!("Expected $, got {:?}", token)); - return None; - } - } else { - self.errors.push("Expected $, got None".to_string()); - return None; + return Err(Error::msg("Unexpected end of input")); } + } - // Move to the variable name. - self.next_token(); + fn parse_assignment_statement(&mut self) -> Result { + info!("parse_assignment_statement: Current token: {:?}", self.current_token); // Ensure the variable name is an identifier. let name_token = if let Some(token) = &self.current_token { if token.token_type == TokenType::Ident { token.clone() } else { - self.errors - .push(format!("Expected identifier, got {:?}", token)); - return None; + self.errors.push(format!("Expected identifier, got {:?}", token)); + return Err(Error::msg(format!("Expected identifier, got {:?}", token))); } } else { - self.errors - .push("Expected identifier, got None".to_string()); - return None; + self.errors.push("Expected identifier, got None".to_string()); + return Err(Error::msg("Expected identifier, got None")); }; - - // Move to the next token and check if it's an assignment or a reference. + + // Move to the next token and check if it's an assignment. self.next_token(); - - match &self.current_token { - Some(token) if token.token_type == TokenType::Assign => { + + if let Some(token) = &self.current_token { + if token.token_type == TokenType::Assign { // Parse as assignment self.next_token(); - let value_expression = self.parse_expression(Precedence::Lowest); - - if let Some(value_expression) = value_expression { - // Ensure the semicolon is present. - if !self.expect_peek(TokenType::Semicolon) { - return None; - } + info!("parse_assignment_statement: Next token: {:?}", self.current_token); + let value_expression = self.parse_expression(Precedence::Lowest); + + if let Ok(value_expression) = value_expression { let variable_assignment = Assignment { token: name_token.clone(), name: Identifier { @@ -323,24 +315,31 @@ impl<'a> Parser<'a> { value: value_expression, }; - Some(Statement::Assign(variable_assignment)) + if self.peek_token_is(&TokenType::Semicolon) { + self.next_token(); + } + + return Ok(Statement::Assign(variable_assignment)); } else { - None + self.errors.push("Expected an expression after =".to_string()); + return Err(Error::msg("Expected an expression after =")); } + } else { + // If it's not an assignment, then it's not an assignment statement. + return Err(Error::msg(format!( + "Expected assignment, got {:?}", + token.token_type + ))); } - Some(token) => { - self.errors - .push(format!("Expected = or ;, got {:?}", token)); - None - } - None => { - self.errors.push("Expected = or ;, got None".to_string()); - None - } + } else { + self.errors.push("Unexpected end of input".to_string()); + return Err(Error::msg("Unexpected end of input")); } - } + } + + fn parse_expression(&mut self, precedence: Precedence) -> Result { + info!("parse_expression: Current token: {:?}", self.current_token); - fn parse_expression(&mut self, precedence: Precedence) -> Option { // Get prefix parse function (if it exists) let prefix_fn = self .prefix_parse_fns @@ -348,12 +347,10 @@ impl<'a> Parser<'a> { .map(|x| *x); if prefix_fn.is_none() { - self.errors.push(format!( + return Err(Error::msg(format!( "No prefix parse function for {:?}", self.current_token.as_ref().unwrap().token_type - )); - - return None; + ))); } // Call the prefix parse function @@ -377,123 +374,125 @@ impl<'a> Parser<'a> { left } - fn parse_expression_statement(&mut self) -> Option { - let current_token = self.current_token.clone().unwrap(); - - let expression = self.parse_expression(Precedence::Lowest); - - // Move to the next token if it's a semicolon + fn parse_expression_statement(&mut self) -> Result { + info!("parse_expression_statement: Current token: {:?}", self.current_token); + let expr = self.parse_expression(Precedence::Lowest)?; if self.peek_token_is(&TokenType::Semicolon) { self.next_token(); } - Some(Statement::Expr(expression.unwrap())) + Ok(Statement::Expr(expr)) } - fn parse_block_statement(&mut self) -> Option { + fn parse_block_statement(&mut self) -> Result { + info!("parse_block_statement: Current token: {:?}", self.current_token); + let current_token = self.current_token.clone().unwrap(); let mut statements = vec![]; self.next_token(); - while !self.current_token_is(TokenType::RBrace) - && !self.current_token_is(TokenType::Eof) - { + while !self.current_token_is(TokenType::RBrace) && !self.current_token_is(TokenType::Eof) { let statement = self.parse_statement(); - if let Some(statement) = statement { + if let Ok(statement) = statement { statements.push(statement); } self.next_token(); } - Some(BlockStatement { + Ok(BlockStatement { token: current_token, statements, }) } - fn parse_function_literal(&mut self) -> Option { + fn parse_function_literal(&mut self) -> Result { + info!("parse_function_literal: Current token: {:?}", self.current_token); + let current_token = self.current_token.clone().unwrap(); - + if !self.expect_peek(TokenType::LParen) { - return None; + return Err(Error::msg("Expected LParen")); } - - let parameters = self.parse_function_parameters(); - + + let parameters = self.parse_function_parameters()?; + if !self.expect_peek(TokenType::LBrace) { - return None; + return Err(Error::msg("Expected LBrace")); } - + let body = self.parse_block_statement(); - - if let Some(body) = body { - Some(Expression::Function(FunctionLiteral { + + if let Ok(body) = body { + Ok(Expression::Function(FunctionLiteral { token: current_token, parameters, body: body, })) } else { - None + Err(Error::msg("Expected a block statement")) } } - - fn parse_function_parameters(&mut self) -> Vec { + fn parse_function_parameters(&mut self) -> Result> { + info!("parse_function_parameters: Current token: {:?}", self.current_token); let mut identifiers = vec![]; if self.peek_token_is(&TokenType::RParen) { self.next_token(); // Consume the RParen and exit - return identifiers; + return Ok(identifiers); } + + self.next_token(); - // Expecting a Dollar sign and identifier (variable name) - if self.expect_peek(TokenType::Dollar) { - self.next_token(); // Consume Dollar - let identifier = Identifier { - token: self.current_token.clone().unwrap(), - value: self.current_token.as_ref().unwrap().to_string(), - }; - identifiers.push(identifier); - } + loop { + if let Some(token) = &self.current_token { + if token.token_type == TokenType::Ident && token.literal.starts_with('$') { + let identifier = Identifier { + token: token.clone(), + value: token.literal.clone(), + }; + identifiers.push(identifier); + } else { + return Err(Error::msg(format!("Expected identifier starting with '$', got {:?}", token))); + } + } - // Expecting comma-separated identifiers - while self.peek_token_is(&TokenType::Comma) { - self.next_token(); // Consume Comma - if self.expect_peek(TokenType::Dollar) { - self.next_token(); // Consume Dollar - let identifier = Identifier { - token: self.current_token.clone().unwrap(), - value: self.current_token.as_ref().unwrap().to_string(), - }; - identifiers.push(identifier); + if self.peek_token_is(&TokenType::Comma) { + self.next_token(); + self.next_token(); + } else if self.peek_token_is(&TokenType::RParen) { + self.next_token(); + + break; + } else { + return Err(Error::msg("Expected ',' or ')' after identifier".to_string())); } } - // Expecting RParen to close the parameters list - if !self.expect_peek(TokenType::RParen) { - return vec![]; - } + Ok(identifiers) + } - identifiers - } - fn parse_grouped_expression(&mut self) -> Option { + fn parse_grouped_expression(&mut self) -> Result { + info!("parse_grouped_expression: Current token: {:?}", self.current_token); + self.next_token(); let expression = self.parse_expression(Precedence::Lowest); if !self.expect_peek(TokenType::RParen) { - return None; + return Err(Error::msg("Expected RParen")); } expression } - fn parse_identifier(&mut self) -> Option { + fn parse_identifier(&mut self) -> Result { + info!("parse_identifier: Current token: {:?}", self.current_token); let current_token = self.current_token.clone().unwrap(); let identifier = Identifier { @@ -501,10 +500,12 @@ impl<'a> Parser<'a> { value: self.current_token.as_ref().unwrap().to_string(), }; - Some(Expression::Identifier(identifier)) + Ok(Expression::Identifier(identifier)) } - fn parse_integer_literal(&mut self) -> Option { + fn parse_integer_literal(&mut self) -> Result { + info!("parse_integer_literal: Current token: {:?}", self.current_token); + let current_token = self.current_token.clone().unwrap(); let value = self @@ -515,13 +516,15 @@ impl<'a> Parser<'a> { .parse::() .unwrap(); - Some(Expression::Literal(Literal::Integer(Integer { + Ok(Expression::Literal(Literal::Integer(Integer { token: current_token, value, }))) } fn parse_call_arguments(&mut self) -> Vec { + info!("parse_call_arguments: Current token: {:?}", self.current_token); + let mut arguments = vec![]; if self.peek_token_is(&TokenType::RParen) { @@ -546,64 +549,50 @@ impl<'a> Parser<'a> { arguments } - fn parse_call_expression(&mut self, function: Expression) -> Option { + fn parse_call_expression(&mut self, function: Expression) -> Result { + info!("parse_call_expression: Current token: {:?}", self.current_token); let current_token = self.current_token.clone().unwrap(); let arguments = self.parse_call_arguments(); - Some(Expression::Call(CallExpression { + Ok(Expression::Call(CallExpression { token: current_token, function: Box::new(function), arguments, })) } - fn parse_if_expression(&mut self) -> Option { - let current_token = self.current_token.clone().unwrap(); - - if !self.expect_peek(TokenType::LParen) { - return None; - } + fn parse_if_expression(&mut self) -> Result { + info!("parse_if_expression: Current token: {:?}", self.current_token); + self.expect_peek(TokenType::LParen); self.next_token(); - let condition = self.parse_expression(Precedence::Lowest); + let condition = self.parse_expression(Precedence::Lowest)?; + self.expect_peek(TokenType::RParen); + self.expect_peek(TokenType::LBrace); - if let None = condition { - return None; - } - - if !self.expect_peek(TokenType::RParen) { - return None; - } - - if !self.expect_peek(TokenType::LBrace) { - return None; - } - - let consequence = self.parse_block_statement(); + let consequence = self.parse_block_statement()?; let alternative = if self.peek_token_is(&TokenType::Else) { self.next_token(); - - if !self.expect_peek(TokenType::LBrace) { - return None; - } - - self.parse_block_statement() + self.expect_peek(TokenType::LBrace); + Some(self.parse_block_statement()?) } else { None }; - Some(Expression::If(IfExpression { - token: current_token, - condition: Box::new(condition.unwrap()), - consequence: consequence.unwrap(), - alternative: alternative, - })) + return Ok(Expression::If(IfExpression { + condition: Box::new(condition), + token: self.current_token.clone().unwrap(), + consequence, + alternative, + })); } - fn parse_infix_expression(&mut self, left: Expression) -> Option { + fn parse_infix_expression(&mut self, left: Expression) -> Result { + info!("parse_infix_expression: Current token: {:?}", self.current_token); + let current_token = self.current_token.clone().unwrap(); let operator = self.current_token.as_ref().unwrap().to_string(); @@ -613,21 +602,23 @@ impl<'a> Parser<'a> { self.next_token(); match self.parse_expression(precedence) { - Some(right) => Some(Expression::Infix(InfixExpression { + Ok(right) => Ok(Expression::Infix(InfixExpression { token: current_token, operator, left: Box::new(left), right: Box::new(right), })), - None => { + Err(e) => { self.errors .push("Expected an expression, but found none.".to_string()); - return None; + return Err(Error::msg(e.to_string())); } } } - fn parse_prefix_expression(&mut self) -> Option { + fn parse_prefix_expression(&mut self) -> Result { + info!("parse_prefix_expression: Current token: {:?}", self.current_token); + let current_token = self.current_token.clone().unwrap(); let operator = self.current_token.as_ref().unwrap().to_string(); @@ -636,20 +627,21 @@ impl<'a> Parser<'a> { let right = self.parse_expression(Precedence::Prefix).unwrap(); - Some(Expression::Prefix(PrefixExpression { + Ok(Expression::Prefix(PrefixExpression { token: current_token, operator, right: Box::new(right), })) } - fn parse_return_statement(&mut self) -> Option { + fn parse_return_statement(&mut self) -> Result { let current_token = self.current_token.clone().unwrap(); if !matches!(current_token.token_type, TokenType::Return) { - self.errors - .push(format!("Expected 'return', got {:?}", current_token)); - return None; + return Err(Error::msg(format!( + "Expected 'return', got {:?}", + current_token + ))); } self.next_token(); @@ -657,10 +649,10 @@ impl<'a> Parser<'a> { let return_value = self.parse_expression(Precedence::Lowest); if !self.expect_peek(TokenType::Semicolon) { - return None; + return Err(Error::msg("Expected Semicolon")); } - Some(Statement::Return(ReturnStatement { + Ok(Statement::Return(ReturnStatement { token: current_token, return_value: return_value.unwrap(), })) @@ -681,7 +673,9 @@ mod tests { use anyhow::{Error, Result}; - use crate::ast::{InfixExpression, PrefixExpression, Statement, IfExpression, FunctionLiteral, CallExpression}; + use crate::ast::{ + Statement, + }; #[test] fn test_assignment_statements() -> Result<(), Error> { @@ -694,12 +688,12 @@ mod tests { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; assert_eq!(3, program.statements.len()); - let expected_identifiers = ["x", "y", "foobar"]; + let expected_identifiers = ["$x", "$y", "$foobar"]; for i in 0..expected_identifiers.len() { let statement = &program.statements[i]; @@ -725,7 +719,7 @@ mod tests { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; assert_eq!(4, program.statements.len()); @@ -742,7 +736,9 @@ mod tests { } } Statement::Assign(variable_assignment) => { - if let Expression::Literal(Literal::Boolean(boolean)) = &variable_assignment.value { + if let Expression::Literal(Literal::Boolean(boolean)) = + &variable_assignment.value + { assert_eq!(expected_values[i], boolean.value); } else { assert!(false, "Expected Boolean expression"); @@ -764,7 +760,7 @@ mod tests { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; assert_eq!(1, program.statements.len()); @@ -775,24 +771,11 @@ mod tests { assert_eq!(3, call_expression.arguments.len()); - assert_literal_expression( - &call_expression.arguments[0], - "1", - )?; - - assert_infix_expression( - &call_expression.arguments[1], - "2", - "*", - "3", - )?; - - assert_infix_expression( - &call_expression.arguments[2], - "4", - "+", - "5", - )?; + assert_literal_expression(&call_expression.arguments[0], "1")?; + + assert_infix_expression(&call_expression.arguments[1], "2", "*", "3")?; + + assert_infix_expression(&call_expression.arguments[2], "4", "+", "5")?; } else { assert!(false, "Expected CallExpression"); } @@ -812,7 +795,7 @@ mod tests { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; @@ -820,19 +803,14 @@ mod tests { if let Statement::Expr(expression) = &program.statements[0] { if let Expression::If(if_expression) = &expression { - assert_infix_expression( - &if_expression.condition, - "x", - "<", - "y", - )?; + assert_infix_expression(&if_expression.condition, "$x", "<", "$y")?; assert_eq!(1, if_expression.consequence.statements.len()); if let Statement::Return(return_statement) = &if_expression.consequence.statements[0] { - assert_identifier(&return_statement.return_value, "x")?; + assert_identifier(&return_statement.return_value, "$x")?; } else { assert!(false, "Expected ReturnStatement"); } @@ -855,7 +833,7 @@ mod tests { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; @@ -863,29 +841,27 @@ mod tests { if let Statement::Expr(expression) = &program.statements[0] { if let Expression::If(if_expression) = &expression { - assert_infix_expression( - &if_expression.condition, - "x", - "<", - "y", - )?; + assert_infix_expression(&if_expression.condition, "$x", "<", "$y")?; assert_eq!(1, if_expression.consequence.statements.len()); if let Statement::Return(return_statement) = &if_expression.consequence.statements[0] { - assert_identifier(&return_statement.return_value, "x")?; + assert_identifier(&return_statement.return_value, "$x")?; } else { assert!(false, "Expected ReturnStatement"); } - assert_eq!(1, if_expression.alternative.as_ref().unwrap().statements.len()); + assert_eq!( + 1, + if_expression.alternative.as_ref().unwrap().statements.len() + ); if let Statement::Return(return_statement) = &if_expression.alternative.as_ref().unwrap().statements[0] { - assert_identifier(&return_statement.return_value, "y")?; + assert_identifier(&return_statement.return_value, "$y")?; } else { assert!(false, "Expected ReturnStatement"); } @@ -910,7 +886,7 @@ mod tests { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; assert_eq!(3, program.statements.len()); @@ -929,7 +905,7 @@ mod tests { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; assert_eq!(1, program.statements.len()); @@ -950,7 +926,7 @@ mod tests { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; assert_eq!(1, program.statements.len()); @@ -1006,7 +982,7 @@ mod tests { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; assert_eq!(*expected, program.to_string()); @@ -1015,43 +991,6 @@ mod tests { Ok(()) } - // #[test] - // fn test_parsing_infix_expressions() -> Result<(), Error> { - // let infix_tests: [(&str, i64, &str, i64); 8] = [ - // ("5 + 5;", 5, "+", 5), - // ("5 - 5;", 5, "-", 5), - // ("5 * 5;", 5, "*", 5), - // ("5 / 5;", 5, "/", 5), - // ("5 > 5;", 5, ">", 5), - // ("5 < 5;", 5, "<", 5), - // ("5 == 5;", 5, "==", 5), - // ("5 != 5;", 5, "!=", 5), - // ]; - - // for (input, left_value, operator, right_value) in infix_tests.iter() { - // let lexer = Lexer::new(input); - // let mut parser = Parser::new(lexer); - - // let program = parser.parse_program(); - // parser.check_errors()?; - - // assert_eq!(1, program.statements.len()); - - // if let Statement::Expr(expression) = &program.statements[0] { - // assert_infix_expression( - // &expression, - // *left_value, - // *operator, - // *right_value, - // )?; - // } else { - // assert!(false, "Expected ExpressionStatement"); - // } - // } - - // Ok(()) - // } - #[test] fn test_parsing_prefix_expressions() -> Result<(), Error> { let prefix_tests: [(&str, &str, i64); 2] = [("!5;", "!", 5), ("-15;", "-", 15)]; @@ -1060,17 +999,13 @@ mod tests { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; assert_eq!(1, program.statements.len()); if let Statement::Expr(expression) = &program.statements[0] { - assert_prefix_expression( - &expression, - *_operator, - *value, - )?; + assert_prefix_expression(&expression, *_operator, *value)?; } else { assert!(false, "Expected ExpressionStatement"); } @@ -1134,29 +1069,19 @@ mod tests { fn assert_function_literal(expression: &Expression) -> Result<(), Error> { if let Expression::Function(function_literal) = expression { assert_eq!(2, function_literal.parameters.len()); - - assert_eq!("x", function_literal.parameters[0].value); - assert_eq!("y", function_literal.parameters[1].value); - + + assert_eq!("$x", function_literal.parameters[0].value); + assert_eq!("$y", function_literal.parameters[1].value); + if let BlockStatement { statements, .. } = &function_literal.body { assert_eq!(1, statements.len()); - + match &statements[0] { Statement::Return(return_statement) => { - assert_infix_expression( - &return_statement.return_value, - "x", - "+", - "y", - )?; + assert_infix_expression(&return_statement.return_value, "$x", "+", "$y")?; } Statement::Expr(expression) => { - assert_infix_expression( - expression, - "x", - "+", - "y", - )?; + assert_infix_expression(expression, "$x", "+", "$y")?; } _ => assert!(false, "Expected ReturnStatement or ExpressionStatement"), } @@ -1166,32 +1091,19 @@ mod tests { } else { assert!(false, "Expected FunctionLiteral"); } - + Ok(()) - } + } fn assert_call_expression(expression: &Expression) -> Result<(), Error> { if let Expression::Call(call_expression) = expression { assert_eq!(3, call_expression.arguments.len()); - assert_literal_expression( - &call_expression.arguments[0], - "1", - )?; - - assert_infix_expression( - &call_expression.arguments[1], - "2", - "*", - "3", - )?; - - assert_infix_expression( - &call_expression.arguments[2], - "4", - "+", - "5", - )?; + assert_literal_expression(&call_expression.arguments[0], "1")?; + + assert_infix_expression(&call_expression.arguments[1], "2", "*", "3")?; + + assert_infix_expression(&call_expression.arguments[2], "4", "+", "5")?; } else { assert!(false, "Expected CallExpression"); } @@ -1237,10 +1149,7 @@ mod tests { Ok(()) } - fn assert_literal_expression( - expression: &Expression, - expected: &str, - ) -> Result { + fn assert_literal_expression(expression: &Expression, expected: &str) -> Result { match expression { Expression::Literal(Literal::Integer(integer_literal)) => { assert_eq!(expected, integer_literal.value.to_string()); diff --git a/src/repl.rs b/src/repl.rs index de1bf13..10f0366 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -1,8 +1,10 @@ +use std::{cell::RefCell, rc::Rc}; + use anyhow::{Error, Result}; use rustyline::error::ReadlineError; -use crate::{lexer::Lexer, parser::Parser, evaluator}; +use crate::{evaluator, lexer::Lexer, parser::Parser, object::environment::Environment}; const PROMPT: &str = ">> "; @@ -20,6 +22,8 @@ pub fn init_repl() -> Result<(), Error> { env!("CARGO_PKG_VERSION") ); + let env = Rc::new(RefCell::new(Environment::new())); + loop { let readline = rl.readline(format!("{}", PROMPT).as_str()); @@ -30,14 +34,12 @@ pub fn init_repl() -> Result<(), Error> { let lexer = Lexer::new(&line); let mut parser = Parser::new(lexer); - let program = parser.parse_program(); + let program = parser.parse_program()?; parser.check_errors()?; - let evaluation = evaluator::eval_statements(&program.statements); + let evaluated = evaluator::eval_statements(&program.statements, &env)?; - if let Some(evaluated) = evaluation { - println!("{}", evaluated); - } + println!("{}", evaluated); } Err(ReadlineError::Interrupted) => { println!("CTRL-C"); @@ -55,4 +57,4 @@ pub fn init_repl() -> Result<(), Error> { } Ok(()) -} \ No newline at end of file +}