From 57f178f55bcddc5de3d15bdd3926c89350e66dd4 Mon Sep 17 00:00:00 2001 From: Zak Farmer Date: Sun, 22 Oct 2023 14:23:03 +0100 Subject: [PATCH] refactor: simplified $ identifier parsing --- src/evaluator.rs | 138 +++++++---- src/lexer.rs | 68 +++--- src/main.rs | 2 +- src/object/environment.rs | 28 ++- src/object/mod.rs | 14 +- src/parser.rs | 473 +++++++++++++++++--------------------- src/repl.rs | 12 +- 7 files changed, 376 insertions(+), 359 deletions(-) diff --git a/src/evaluator.rs b/src/evaluator.rs index 2caecda..5ab94ce 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -1,18 +1,12 @@ -use std::sync::Arc; +use std::{rc::Rc, cell::RefCell}; use anyhow::{Result, Ok, Error}; use lazy_static::lazy_static; -use crate::{ast::{Boolean, Expression, Literal, Node, Statement, IfExpression}, object::{Object, environment::Env}}; +use crate::{ast::{Boolean, Expression, Literal, Node, Statement, IfExpression, FunctionLiteral, CallExpression}, object::{Object, environment::{Env, Environment}}}; -lazy_static! { - static ref TRUE: Object = Object::Boolean(true); - static ref FALSE: Object = Object::Boolean(false); - static ref NULL: Object = Object::Null; -} - -pub fn eval(node: Node, env: &Env) -> Result> { +pub fn eval(node: Node, env: &Env) -> Result> { match node { Node::Expression(expression) => eval_expression(&expression, env), Node::Program(program) => eval_statements(&program.statements, env), @@ -21,8 +15,8 @@ pub fn eval(node: Node, env: &Env) -> Result> { } } -pub fn eval_statements(statements: &Vec, env: &Env) -> Result> { - let mut result: Arc = Arc::new(Object::Null); +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, env)?; @@ -36,6 +30,22 @@ pub fn eval_statements(statements: &Vec, env: &Env) -> Result, 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, @@ -44,13 +54,20 @@ fn is_truthy(object: &Object) -> bool { } } -fn eval_expression(expression: &Expression, env: &Env) -> Result> { +fn unwrap_return_value(object: Rc) -> Result> { + match &* object { + Object::Return(value) => Ok(Rc::clone(value)), + _ => Ok(object), + } +} + +fn eval_expression(expression: &Expression, env: &Env) -> Result> { match expression { Expression::Identifier(identifier_expression) => eval_identifier(identifier_expression.to_string(), env), Expression::Literal(literal) => eval_literal(&literal), Expression::Infix(infix_expression) => { - let left = eval_expression(&infix_expression.left, &Arc::clone(env))?; - let right = eval_expression(&infix_expression.right, &Arc::clone(env))?; + 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(), @@ -60,7 +77,7 @@ fn eval_expression(expression: &Expression, env: &Env) -> Result> { ) }, Expression::Prefix(prefix_expression) => { - let right = eval_expression(&prefix_expression.right, &Arc::clone(env))?; + let right = eval_expression(&prefix_expression.right, &Rc::clone(env))?; eval_prefix_expression( prefix_expression.operator.to_string(), @@ -69,11 +86,34 @@ fn eval_expression(expression: &Expression, env: &Env) -> Result> { ) }, 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_if_expression(expression: &Expression, env: &Env) -> Result> { +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_if_expression(expression: &Expression, env: &Env) -> Result> { if let Expression::If(IfExpression { condition, consequence, @@ -96,7 +136,7 @@ fn eval_if_expression(expression: &Expression, env: &Env) -> Result> } } -fn eval_infix_expression(operator: String, left: &Object, right: &Object, env: &Env) -> Result> { +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) @@ -114,7 +154,7 @@ fn eval_infix_expression(operator: String, left: &Object, right: &Object, env: & } } -fn eval_boolean_infix_expression(operator: String, left: bool, right: bool) -> Result> { +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), @@ -127,7 +167,7 @@ fn eval_boolean_infix_expression(operator: String, left: bool, right: bool) -> R Ok(result.into()) } -fn eval_integer_infix_expression(operator: String, left: i64, right: i64) -> Result> { +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), @@ -146,7 +186,7 @@ fn eval_integer_infix_expression(operator: String, left: i64, right: i64) -> Res Ok(result.into()) } -fn eval_string_infix_expression(operator: String, left: String, right: String) -> Result> { +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!( @@ -158,7 +198,7 @@ fn eval_string_infix_expression(operator: String, left: String, right: String) - Ok(result.into()) } -fn eval_prefix_expression(operator: String, right: &Object, env: &Env) -> Result> { +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), @@ -169,19 +209,19 @@ fn eval_prefix_expression(operator: String, right: &Object, env: &Env) -> Result } } -fn eval_bang_operator_expression(right: &Object) -> Result> { +fn eval_bang_operator_expression(right: &Object) -> Result> { let result = match *right { - Object::Null => Arc::new(Object::Boolean(true)), - Object::Boolean(boolean) => Arc::new(Object::Boolean(!boolean)), - _ => Arc::new(Object::Boolean(false)), + 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> { +fn eval_minus_prefix_operator_expression(right: &Object) -> Result> { let result = match *right { - Object::Integer(integer) => Arc::from(Object::Integer(-integer)), + Object::Integer(integer) => Rc::from(Object::Integer(-integer)), _ => return Err(Error::msg(format!( "Invalid use of minus operator: -{}", right @@ -191,12 +231,12 @@ fn eval_minus_prefix_operator_expression(right: &Object) -> Result> Ok(result.into()) } -fn eval_statement(statement: &Statement, env: &Env) -> Result> { +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 = Arc::clone(&value); + let object = Rc::clone(&value); env.borrow_mut().set(assignment.name.to_string(), object); @@ -205,20 +245,20 @@ fn eval_statement(statement: &Statement, env: &Env) -> Result> { Statement::Return(return_statement) => { let value = eval_expression(&return_statement.return_value, env)?; - Ok(Arc::new(Object::Return(value))) + Ok(Rc::new(Object::Return(value))) }, _ => Err(Error::msg(format!("Unknown statement type: {}", statement))), } } -fn eval_identifier(identifier: String, env: &Env) -> Result> { +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> { +fn eval_literal(literal: &Literal) -> Result> { let result = match literal { Literal::Integer(integer) => Object::Integer(integer.value), Literal::Boolean(Boolean { value, .. }) => Object::Boolean(*value), @@ -230,11 +270,7 @@ fn eval_literal(literal: &Literal) -> Result> { } fn native_bool_to_bool_object(input: bool) -> Object { - if input { - TRUE.clone() - } else { - FALSE.clone() - } + Object::Boolean(input) } #[cfg(test)] @@ -349,7 +385,7 @@ mod tests { if let Some(expected) = expected { assert_integer_object(evaluated, expected)?; } else { - assert_eq!(*evaluated, *NULL); + assert_eq!(*evaluated, Object::Null); } } @@ -375,13 +411,29 @@ mod tests { Ok(()) } - fn assert_eval(input: &str) -> Result, Error> { - let env = Arc::new(RefCell::new(Environment::new())); + #[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, 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(Node::Program(program), &env); @@ -389,7 +441,7 @@ mod tests { evaluated } - fn assert_boolean_literal_object(object: Arc, expected: bool) -> Result<(), Error> { + fn assert_boolean_literal_object(object: Rc, expected: bool) -> Result<(), Error> { if let Object::Boolean(boolean) = *object { assert_eq!(boolean, expected); } else { @@ -399,7 +451,7 @@ mod tests { Ok(()) } - fn assert_integer_object(object: Arc, expected: i64) -> Result<(), Error> { + fn assert_integer_object(object: Rc, expected: i64) -> Result<(), Error> { if let Object::Integer(integer) = *object { assert_eq!(integer, expected); } else { 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 d0ce23f..bcc89de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 index c12b0c2..36f2825 100644 --- a/src/object/environment.rs +++ b/src/object/environment.rs @@ -1,28 +1,44 @@ -use std::{collections::HashMap, sync::Arc, cell::RefCell}; +use std::{collections::HashMap, rc::Rc, cell::RefCell}; use super::Object; -pub type Env = Arc>; +pub type Env = Rc>; +#[derive(Debug)] pub struct Environment { - store: HashMap>, + 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 get(&self, name: &str) -> Option> { + 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(Arc::clone(value)), + Some(value) => Some(Rc::clone(value)), None => None, } } - pub fn set(&mut self, name: String, value: Arc) -> Option> { + 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/mod.rs b/src/object/mod.rs index 7243b05..dc76cb9 100644 --- a/src/object/mod.rs +++ b/src/object/mod.rs @@ -1,6 +1,8 @@ -use std::sync::Arc; +use std::rc::Rc; -use crate::ast::BlockStatement; +use crate::ast::{BlockStatement, Identifier}; + +use self::environment::Env; pub mod environment; @@ -9,8 +11,8 @@ pub enum Object { Integer(i64), Boolean(bool), String(String), - Function(Vec, BlockStatement), - Return(Arc), + Function(Vec, BlockStatement, Env), + Return(Rc), Null, } @@ -20,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(", "); diff --git a/src/parser.rs b/src/parser.rs index bdd2ebd..2cc1519 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; -use anyhow::Error; -use log::trace; +use anyhow::{Error, Result}; +use log::{trace, info}; use crate::{ ast::{ @@ -13,7 +13,7 @@ use crate::{ token::{Token, TokenType}, }; -type ParseResult = Option; +type ParseResult = Result; type PrefixParseFn = fn(&mut Parser) -> ParseResult; type InfixParseFn = fn(&mut Parser, Expression) -> ParseResult; @@ -169,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(); @@ -185,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; - } + fn parse_variable_reference_expression(&mut self) -> Result { + info!("parse_variable_reference_expression: Current token: {:?}", self.current_token); - self.next_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 { @@ -326,32 +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) if token.token_type == TokenType::Semicolon => { - let identifier = Identifier { - token: name_token.clone(), - value: name_token.literal.clone(), - }; - - Some(Statement::Expr(Expression::Identifier(identifier))) - } - 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 @@ -359,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 @@ -388,20 +374,19 @@ 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![]; @@ -411,97 +396,103 @@ impl<'a> Parser<'a> { 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); } - // 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); - } - - // 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); + self.next_token(); + + 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))); + } } - } + + if self.peek_token_is(&TokenType::Comma) { + self.next_token(); + self.next_token(); + } else if self.peek_token_is(&TokenType::RParen) { + self.next_token(); - // Expecting RParen to close the parameters list - if !self.expect_peek(TokenType::RParen) { - return vec![]; + break; + } else { + return Err(Error::msg("Expected ',' or ')' after identifier".to_string())); + } } - - identifiers + + Ok(identifiers) } + + + fn parse_grouped_expression(&mut self) -> Result { + info!("parse_grouped_expression: Current token: {:?}", self.current_token); - fn parse_grouped_expression(&mut self) -> Option { 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 { @@ -509,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 @@ -523,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) { @@ -554,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(); @@ -621,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(); @@ -644,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(); @@ -665,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(), })) @@ -704,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]; @@ -735,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()); @@ -776,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()); @@ -811,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()?; @@ -819,14 +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"); } @@ -849,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()?; @@ -857,14 +841,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"); } @@ -877,7 +861,7 @@ mod tests { 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"); } @@ -902,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()); @@ -921,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()); @@ -942,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()); @@ -998,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()); @@ -1007,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)]; @@ -1052,7 +999,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()); @@ -1123,18 +1070,18 @@ mod tests { 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"), } diff --git a/src/repl.rs b/src/repl.rs index fec6f53..10f0366 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -1,4 +1,4 @@ -use std::{sync::Arc, cell::RefCell}; +use std::{cell::RefCell, rc::Rc}; use anyhow::{Error, Result}; @@ -22,7 +22,7 @@ pub fn init_repl() -> Result<(), Error> { env!("CARGO_PKG_VERSION") ); - let env = Arc::new(RefCell::new(Environment::new())); + let env = Rc::new(RefCell::new(Environment::new())); loop { let readline = rl.readline(format!("{}", PROMPT).as_str()); @@ -34,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, &env); + let evaluated = evaluator::eval_statements(&program.statements, &env)?; - if let Ok(evaluated) = evaluation { - println!("{}", evaluated); - } + println!("{}", evaluated); } Err(ReadlineError::Interrupted) => { println!("CTRL-C");