diff --git a/src/interpreter.rs b/src/interpreter.rs index 7a3e2a2..d734468 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -2,15 +2,15 @@ use std::mem; use crate::lexer::TokenKind; use crate::parser::{Expr, Stmt, Unit}; -use crate::prelude::{self}; -use crate::{symbol_table::SymbolTable, visitor::Visitor}; +use crate::prelude; +use crate::symbol_table::SymbolTable; -pub struct Interpreter<'a> { +pub struct Context<'a> { symbol_table: &'a mut SymbolTable, angle_unit: Unit, } -impl<'a> Interpreter<'a> { +impl<'a> Context<'a> { pub fn new(angle_unit: Unit, symbol_table: &'a mut SymbolTable) -> Self { for constant in prelude::CONSTANTS { symbol_table.insert( @@ -22,33 +22,33 @@ impl<'a> Interpreter<'a> { ); } - Interpreter { + Context { angle_unit: angle_unit.clone(), symbol_table, } } - pub fn interpret(&mut self, statements: Vec) -> Option { + pub fn interpret(&mut self, statements: Vec) -> Result, String> { for (i, stmt) in statements.iter().enumerate() { - let value = self.visit_stmt(stmt); + let value = eval_stmt(self, stmt); if i == statements.len() - 1 { if let Stmt::Expr(_) = stmt { - return Some(value); + return Ok(Some(value?)); } } } - return None; + Ok(None) } } impl TokenKind { - fn to_unit(&self) -> Unit { + fn to_unit(&self) -> Result { match self { - TokenKind::Deg => Unit::Degrees, - TokenKind::Rad => Unit::Radians, - _ => panic!("Invalid unit."), + TokenKind::Deg => Ok(Unit::Degrees), + TokenKind::Rad => Ok(Unit::Radians), + _ => Err(String::from("Invalid unit.")), } } } @@ -60,142 +60,145 @@ impl Unit { } } -impl<'a> Visitor for Interpreter<'a> { - fn visit_stmt(&mut self, stmt: &Stmt) -> f64 { - match stmt { - Stmt::VarDecl(identifier, _) => self.eval_var_decl_stmt(stmt, identifier), - Stmt::FnDecl(_, _, _) => self.eval_fn_decl_stmt(), - Stmt::Expr(expr) => self.eval_expr_stmt(&expr), - } +fn eval_stmt(context: &mut Context, stmt: &Stmt) -> Result { + match stmt { + Stmt::VarDecl(identifier, _) => eval_var_decl_stmt(context, stmt, identifier), + Stmt::FnDecl(_, _, _) => eval_fn_decl_stmt(context), + Stmt::Expr(expr) => eval_expr_stmt(context, &expr), } +} - fn visit_expr(&mut self, expr: &Expr) -> f64 { - match expr { - Expr::Binary(left, op, right) => self.eval_binary_expr(&left, op, &right), - Expr::Unary(_, expr) => self.eval_unary_expr(expr), - Expr::Unit(expr, kind) => self.eval_unit_expr(expr, kind), - Expr::Var(identifier) => self.eval_var_expr(identifier), - Expr::Literal(value) => self.eval_literal_expr(value), - Expr::Group(expr) => self.eval_group_expr(&expr), - Expr::FnCall(identifier, expressions) => { - self.eval_fn_call_expr(identifier, expressions) - } +fn eval_var_decl_stmt(context: &mut Context, stmt: &Stmt, identifier: &str) -> Result { + context.symbol_table.insert(&identifier, stmt.clone()); + Ok(0f64) +} + +fn eval_fn_decl_stmt(_: &mut Context) -> Result { + Ok(0f64) // Nothing needs to happen here, since the parser will already have added the FnDecl's to the symbol table. +} + +fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result { + eval_expr(context, &expr) +} + +fn eval_expr(context: &mut Context, expr: &Expr) -> Result { + match expr { + Expr::Binary(left, op, right) => eval_binary_expr(context, &left, op, &right), + Expr::Unary(_, expr) => eval_unary_expr(context, expr), + Expr::Unit(expr, kind) => eval_unit_expr(context, expr, kind), + Expr::Var(identifier) => eval_var_expr(context, identifier), + Expr::Literal(value) => eval_literal_expr(context, value), + Expr::Group(expr) => eval_group_expr(context, &expr), + Expr::FnCall(identifier, expressions) => { + eval_fn_call_expr(context, identifier, expressions) } } } -impl<'a> Interpreter<'a> { - fn eval_var_decl_stmt(&mut self, stmt: &Stmt, identifier: &str) -> f64 { - self.symbol_table.insert(&identifier, stmt.clone()); - 0f64 +fn eval_binary_expr( + context: &mut Context, + left: &Expr, + op: &TokenKind, + right: &Expr, +) -> Result { + let left = eval_expr(context, &left)?; + let right = eval_expr(context, &right)?; + + Ok(match op { + TokenKind::Plus => left + right, + TokenKind::Minus => left - right, + TokenKind::Star => left * right, + TokenKind::Slash => left / right, + TokenKind::Power => left.powf(right), + _ => 0f64, + }) +} + +fn eval_unary_expr(context: &mut Context, expr: &Expr) -> Result { + eval_expr(context, &expr).clone() +} + +fn eval_unit_expr(context: &mut Context, expr: &Expr, kind: &TokenKind) -> Result { + let x = eval_expr(context, &expr); + let unit = kind.to_unit()?; + + // Don't do any angle conversions if the defauly angle unit is the same as the unit kind + match unit { + Unit::Degrees | Unit::Radians => { + if context.angle_unit.compare(&unit) { + return x; + } + } } - fn eval_fn_decl_stmt(&mut self) -> f64 { - 0f64 // Nothing needs to happen here, since the parser will already have added the FnDecl's to the symbol table. - } - - fn eval_expr_stmt(&mut self, expr: &Expr) -> f64 { - self.visit_expr(&expr) + match unit { + Unit::Degrees => Ok(x?.to_radians()), + Unit::Radians => Ok(x?.to_degrees()), } } -impl<'a> Interpreter<'a> { - fn eval_binary_expr(&mut self, left: &Expr, op: &TokenKind, right: &Expr) -> f64 { - let left = self.visit_expr(&left); - let right = self.visit_expr(&right); +fn eval_var_expr(context: &mut Context, identifier: &str) -> Result { + let var_decl = context.symbol_table.get(identifier).cloned(); + match var_decl { + Some(Stmt::VarDecl(_, expr)) => eval_expr(context, &expr), + _ => Err(String::from("Undefined variable.")), + } +} - match op { - TokenKind::Plus => left + right, - TokenKind::Minus => left - right, - TokenKind::Star => left * right, - TokenKind::Slash => left / right, - TokenKind::Power => left.powf(right), - _ => 0f64, +fn eval_literal_expr(_: &mut Context, value: &str) -> Result { + match value.parse() { + Ok(parsed_value) => Ok(parsed_value), + Err(_) => Err(String::from("Invalid number literal.")), + } +} + +fn eval_group_expr(context: &mut Context, expr: &Expr) -> Result { + eval_expr(context, expr) +} + +fn eval_fn_call_expr( + context: &mut Context, + identifier: &str, + expressions: &Vec, +) -> Result { + let prelude_func = match expressions.len() { + 1 => { + let x = eval_expr(context, &expressions[0])?; + prelude::call_unary_func(identifier, x, &context.angle_unit) } - } - - fn eval_unary_expr(&mut self, expr: &Expr) -> f64 { - self.visit_expr(&expr).clone() - } - - fn eval_unit_expr(&mut self, expr: &Expr, kind: &TokenKind) -> f64 { - let x = self.visit_expr(&expr); - - // Don't do any angle conversions if the defauly angle unit is the same as the unit kind - if (kind.compare(&TokenKind::Deg) || kind.compare(&TokenKind::Rad)) - && self.angle_unit.compare(&kind.to_unit()) - { - return x; + 2 => { + let x = eval_expr(context, &expressions[0])?; + let y = eval_expr(context, &expressions[1])?; + prelude::call_binary_func(identifier, x, y, &context.angle_unit) } + _ => None, + }; - match kind { - TokenKind::Deg => x.to_radians(), - TokenKind::Rad => x.to_degrees(), - _ => panic!("Invalid unit."), - } + if let Some(result) = prelude_func { + return Ok(result); } - fn eval_var_expr(&mut self, identifier: &str) -> f64 { - let value = self - .symbol_table - .get(identifier) - .expect("Undefined variable.") - .clone(); - if let Stmt::VarDecl(_, expr) = value { - return self.visit_expr(&expr); - } + let stmt_definition = context + .symbol_table + .get(&format!("{}()", identifier)) + .cloned(); - panic!("Unknown error."); - } - - fn eval_literal_expr(&mut self, value: &str) -> f64 { - value.parse().unwrap() - } - - fn eval_group_expr(&mut self, expr: &Expr) -> f64 { - self.visit_expr(expr) - } - - fn eval_fn_call_expr(&mut self, identifier: &str, expressions: &Vec) -> f64 { - let prelude_func = match expressions.len() { - 1 => { - let x = self.visit_expr(&expressions[0]); - prelude::call_unary_func(identifier, x, &self.angle_unit) - } - 2 => { - let x = self.visit_expr(&expressions[0]); - let y = self.visit_expr(&expressions[1]); - prelude::call_binary_func(identifier, x, y, &self.angle_unit) - } - _ => None, - }; - - if let Some(result) = prelude_func { - return result; - } - - let stmt = self - .symbol_table - .get(&format!("{}()", identifier)) - .expect("Undefined function") - .clone(); - - if let Stmt::FnDecl(_, arguments, fn_body) = stmt { + match stmt_definition { + Some(Stmt::FnDecl(_, arguments, fn_body)) => { if arguments.len() != expressions.len() { - panic!("Incorrect amount of arguments."); + return Err(String::from("Incorrect amount of arguments.")); } // Initialise the arguments as their own variables. for (i, argument) in arguments.iter().enumerate() { - self.visit_stmt(&Stmt::VarDecl( - argument.clone(), - Box::new(expressions[i].clone()), - )); + eval_stmt( + context, + &Stmt::VarDecl(argument.clone(), Box::new(expressions[i].clone())), + )?; } - return self.visit_expr(&*fn_body); + return eval_expr(context, &*fn_body); } - - panic!("Unexpected error."); + _ => Err(String::from("Undefined function.")), } } diff --git a/src/main.rs b/src/main.rs index 70885c9..bf0c60d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,14 +5,13 @@ mod lexer; mod parser; mod prelude; mod symbol_table; -mod visitor; -use parser::{ParserContext, Unit}; +use parser::Unit; use rustyline::error::ReadlineError; use rustyline::Editor; fn main() { - let mut parser = ParserContext::new(); + let mut parser = parser::Context::new(); // Command line argument input, execute it and exit. if let Some(expr) = env::args().skip(1).next() { @@ -37,7 +36,7 @@ fn main() { } } -fn eval_repl(parser: &mut ParserContext, input: &str) { +fn eval_repl(parser: &mut parser::Context, input: &str) { match input { "" => eprint!(""), "clear" => print!("\x1B[2J"), @@ -46,10 +45,11 @@ fn eval_repl(parser: &mut ParserContext, input: &str) { } } -fn eval(parser: &mut ParserContext, input: &str) { +fn eval(parser: &mut parser::Context, input: &str) { match parser::parse(parser, input, get_angle_unit()) { - Ok(result) => println!("{}", result), - Err(_) => println!("Invalid expression"), + Ok(Some(result)) => println!("{}", result), + Ok(None) => print!(""), + Err(err) => println!("{}", err), } } diff --git a/src/parser.rs b/src/parser.rs index 4f4513d..fa723a4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ use std::mem; use crate::{ - interpreter::Interpreter, + interpreter, lexer::{Lexer, Token, TokenKind}, symbol_table::SymbolTable, }; @@ -30,7 +30,7 @@ pub enum Unit { Degrees, } -pub struct ParserContext { +pub struct Context { //angle_unit: Unit, tokens: Vec, pos: usize, @@ -50,9 +50,9 @@ impl TokenKind { } } -impl ParserContext { +impl Context { pub fn new() -> Self { - ParserContext { + Context { tokens: Vec::new(), pos: 0, symbol_table: SymbolTable::new(), @@ -60,19 +60,20 @@ impl ParserContext { } } -pub fn parse(context: &mut ParserContext, input: &str, angle_unit: Unit) -> Result { +pub fn parse(context: &mut Context, input: &str, angle_unit: Unit) -> Result, String> { context.tokens = Lexer::lex(input); + context.pos = 0; let mut statements: Vec = Vec::new(); while !is_at_end(context) { statements.push(parse_stmt(context)?); } - let mut interpreter = Interpreter::new(angle_unit, &mut context.symbol_table); - Ok(interpreter.interpret(statements).unwrap()) + let mut interpreter = interpreter::Context::new(angle_unit, &mut context.symbol_table); + interpreter.interpret(statements) } -fn parse_stmt(context: &mut ParserContext) -> Result { +fn parse_stmt(context: &mut Context) -> Result { if match_token(context, TokenKind::Identifier) { return Ok(match peek_next(context).kind { TokenKind::Equals => parse_var_decl_stmt(context)?, @@ -84,7 +85,7 @@ fn parse_stmt(context: &mut ParserContext) -> Result { Ok(Stmt::Expr(Box::new(parse_expr(context)?))) } -fn parse_identifier_stmt(context: &mut ParserContext) -> Result { +fn parse_identifier_stmt(context: &mut Context) -> Result { let began_at = context.pos; let primary = parse_primary(context)?; // Since function declarations and function calls look the same at first, simply parse a "function call", and re-use the data. @@ -126,7 +127,7 @@ fn parse_identifier_stmt(context: &mut ParserContext) -> Result { } } -fn parse_var_decl_stmt(context: &mut ParserContext) -> Result { +fn parse_var_decl_stmt(context: &mut Context) -> Result { let identifier = advance(context).clone(); advance(context); // Equal sign let expr = parse_expr(context)?; @@ -134,11 +135,11 @@ fn parse_var_decl_stmt(context: &mut ParserContext) -> Result { Ok(Stmt::VarDecl(identifier.value, Box::new(expr))) } -fn parse_expr(context: &mut ParserContext) -> Result { +fn parse_expr(context: &mut Context) -> Result { Ok(parse_sum(context)?) } -fn parse_sum(context: &mut ParserContext) -> Result { +fn parse_sum(context: &mut Context) -> Result { let mut left = parse_factor(context)?; while match_token(context, TokenKind::Plus) || match_token(context, TokenKind::Minus) { @@ -152,7 +153,7 @@ fn parse_sum(context: &mut ParserContext) -> Result { Ok(left) } -fn parse_factor(context: &mut ParserContext) -> Result { +fn parse_factor(context: &mut Context) -> Result { let mut left = parse_unary(context)?; while match_token(context, TokenKind::Star) @@ -175,7 +176,7 @@ fn parse_factor(context: &mut ParserContext) -> Result { Ok(left) } -fn parse_unary(context: &mut ParserContext) -> Result { +fn parse_unary(context: &mut Context) -> Result { if match_token(context, TokenKind::Minus) { let op = advance(context).kind.clone(); let expr = Box::new(parse_unary(context)?); @@ -185,7 +186,7 @@ fn parse_unary(context: &mut ParserContext) -> Result { Ok(parse_exponent(context)?) } -fn parse_exponent(context: &mut ParserContext) -> Result { +fn parse_exponent(context: &mut Context) -> Result { let left = parse_primary(context)?; if match_token(context, TokenKind::Power) { @@ -197,7 +198,7 @@ fn parse_exponent(context: &mut ParserContext) -> Result { Ok(left) } -fn parse_primary(context: &mut ParserContext) -> Result { +fn parse_primary(context: &mut Context) -> Result { let expr = match peek(context).kind { TokenKind::OpenParenthesis => parse_group(context)?, TokenKind::Pipe => parse_abs(context)?, @@ -212,7 +213,7 @@ fn parse_primary(context: &mut ParserContext) -> Result { } } -fn parse_group(context: &mut ParserContext) -> Result { +fn parse_group(context: &mut Context) -> Result { advance(context); let group_expr = Expr::Group(Box::new(parse_expr(context)?)); consume(context, TokenKind::ClosedParenthesis)?; @@ -220,7 +221,7 @@ fn parse_group(context: &mut ParserContext) -> Result { Ok(group_expr) } -fn parse_abs(context: &mut ParserContext) -> Result { +fn parse_abs(context: &mut Context) -> Result { advance(context); let group_expr = Expr::Group(Box::new(parse_expr(context)?)); consume(context, TokenKind::Pipe)?; @@ -228,7 +229,7 @@ fn parse_abs(context: &mut ParserContext) -> Result { Ok(Expr::FnCall(String::from("abs"), vec![group_expr])) } -fn parse_identifier(context: &mut ParserContext) -> Result { +fn parse_identifier(context: &mut Context) -> Result { let identifier = advance(context).clone(); // Eg. sqrt64 @@ -261,19 +262,19 @@ fn parse_identifier(context: &mut ParserContext) -> Result { Ok(Expr::Var(identifier.value)) } -fn peek<'a>(context: &'a mut ParserContext) -> &'a Token { +fn peek<'a>(context: &'a mut Context) -> &'a Token { &context.tokens[context.pos] } -fn peek_next<'a>(context: &'a mut ParserContext) -> &'a Token { +fn peek_next<'a>(context: &'a mut Context) -> &'a Token { &context.tokens[context.pos + 1] } -fn previous<'a>(context: &'a mut ParserContext) -> &'a Token { +fn previous<'a>(context: &'a mut Context) -> &'a Token { &context.tokens[context.pos - 1] } -fn match_token(context: &mut ParserContext, kind: TokenKind) -> bool { +fn match_token(context: &mut Context, kind: TokenKind) -> bool { if is_at_end(context) { return false; } @@ -281,12 +282,12 @@ fn match_token(context: &mut ParserContext, kind: TokenKind) -> bool { peek(context).kind.compare(&kind) } -fn advance<'a>(context: &'a mut ParserContext) -> &'a Token { +fn advance<'a>(context: &'a mut Context) -> &'a Token { context.pos += 1; previous(context) } -fn consume<'a>(context: &'a mut ParserContext, kind: TokenKind) -> Result<&'a Token, String> { +fn consume<'a>(context: &'a mut Context, kind: TokenKind) -> Result<&'a Token, String> { if match_token(context, kind) { return Ok(advance(context)); } @@ -294,6 +295,6 @@ fn consume<'a>(context: &'a mut ParserContext, kind: TokenKind) -> Result<&'a To Err("Unexpected token".into()) } -fn is_at_end(context: &mut ParserContext) -> bool { +fn is_at_end(context: &mut Context) -> bool { context.pos >= context.tokens.len() || peek(context).kind.compare(&TokenKind::EOF) } diff --git a/src/visitor.rs b/src/visitor.rs deleted file mode 100644 index 25fe8c5..0000000 --- a/src/visitor.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::parser::{Expr, Stmt}; - -pub trait Visitor { - fn visit_stmt(&mut self, stmt: &Stmt) -> T; - fn visit_expr(&mut self, expr: &Expr) -> U; -}