Implemented somewhat proper error handling for the interpreter. This involved removing the visitor.

This commit is contained in:
PaddiM8 2020-05-30 15:16:13 +02:00
parent 1a56ddac45
commit 41a41629a5
4 changed files with 161 additions and 163 deletions

View File

@ -2,15 +2,15 @@ use std::mem;
use crate::lexer::TokenKind; use crate::lexer::TokenKind;
use crate::parser::{Expr, Stmt, Unit}; use crate::parser::{Expr, Stmt, Unit};
use crate::prelude::{self}; use crate::prelude;
use crate::{symbol_table::SymbolTable, visitor::Visitor}; use crate::symbol_table::SymbolTable;
pub struct Interpreter<'a> { pub struct Context<'a> {
symbol_table: &'a mut SymbolTable, symbol_table: &'a mut SymbolTable,
angle_unit: Unit, angle_unit: Unit,
} }
impl<'a> Interpreter<'a> { impl<'a> Context<'a> {
pub fn new(angle_unit: Unit, symbol_table: &'a mut SymbolTable) -> Self { pub fn new(angle_unit: Unit, symbol_table: &'a mut SymbolTable) -> Self {
for constant in prelude::CONSTANTS { for constant in prelude::CONSTANTS {
symbol_table.insert( symbol_table.insert(
@ -22,33 +22,33 @@ impl<'a> Interpreter<'a> {
); );
} }
Interpreter { Context {
angle_unit: angle_unit.clone(), angle_unit: angle_unit.clone(),
symbol_table, symbol_table,
} }
} }
pub fn interpret(&mut self, statements: Vec<Stmt>) -> Option<f64> { pub fn interpret(&mut self, statements: Vec<Stmt>) -> Result<Option<f64>, String> {
for (i, stmt) in statements.iter().enumerate() { 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 i == statements.len() - 1 {
if let Stmt::Expr(_) = stmt { if let Stmt::Expr(_) = stmt {
return Some(value); return Ok(Some(value?));
} }
} }
} }
return None; Ok(None)
} }
} }
impl TokenKind { impl TokenKind {
fn to_unit(&self) -> Unit { fn to_unit(&self) -> Result<Unit, String> {
match self { match self {
TokenKind::Deg => Unit::Degrees, TokenKind::Deg => Ok(Unit::Degrees),
TokenKind::Rad => Unit::Radians, TokenKind::Rad => Ok(Unit::Radians),
_ => panic!("Invalid unit."), _ => Err(String::from("Invalid unit.")),
} }
} }
} }
@ -60,142 +60,145 @@ impl Unit {
} }
} }
impl<'a> Visitor<f64, f64> for Interpreter<'a> { fn eval_stmt(context: &mut Context, stmt: &Stmt) -> Result<f64, String> {
fn visit_stmt(&mut self, stmt: &Stmt) -> f64 { match stmt {
match stmt { Stmt::VarDecl(identifier, _) => eval_var_decl_stmt(context, stmt, identifier),
Stmt::VarDecl(identifier, _) => self.eval_var_decl_stmt(stmt, identifier), Stmt::FnDecl(_, _, _) => eval_fn_decl_stmt(context),
Stmt::FnDecl(_, _, _) => self.eval_fn_decl_stmt(), Stmt::Expr(expr) => eval_expr_stmt(context, &expr),
Stmt::Expr(expr) => self.eval_expr_stmt(&expr),
}
} }
}
fn visit_expr(&mut self, expr: &Expr) -> f64 { fn eval_var_decl_stmt(context: &mut Context, stmt: &Stmt, identifier: &str) -> Result<f64, String> {
match expr { context.symbol_table.insert(&identifier, stmt.clone());
Expr::Binary(left, op, right) => self.eval_binary_expr(&left, op, &right), Ok(0f64)
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), fn eval_fn_decl_stmt(_: &mut Context) -> Result<f64, String> {
Expr::Literal(value) => self.eval_literal_expr(value), Ok(0f64) // Nothing needs to happen here, since the parser will already have added the FnDecl's to the symbol table.
Expr::Group(expr) => self.eval_group_expr(&expr), }
Expr::FnCall(identifier, expressions) => {
self.eval_fn_call_expr(identifier, expressions) fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result<f64, String> {
} eval_expr(context, &expr)
}
fn eval_expr(context: &mut Context, expr: &Expr) -> Result<f64, String> {
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_binary_expr(
fn eval_var_decl_stmt(&mut self, stmt: &Stmt, identifier: &str) -> f64 { context: &mut Context,
self.symbol_table.insert(&identifier, stmt.clone()); left: &Expr,
0f64 op: &TokenKind,
right: &Expr,
) -> Result<f64, String> {
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<f64, String> {
eval_expr(context, &expr).clone()
}
fn eval_unit_expr(context: &mut Context, expr: &Expr, kind: &TokenKind) -> Result<f64, String> {
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 { match unit {
0f64 // Nothing needs to happen here, since the parser will already have added the FnDecl's to the symbol table. Unit::Degrees => Ok(x?.to_radians()),
} Unit::Radians => Ok(x?.to_degrees()),
fn eval_expr_stmt(&mut self, expr: &Expr) -> f64 {
self.visit_expr(&expr)
} }
} }
impl<'a> Interpreter<'a> { fn eval_var_expr(context: &mut Context, identifier: &str) -> Result<f64, String> {
fn eval_binary_expr(&mut self, left: &Expr, op: &TokenKind, right: &Expr) -> f64 { let var_decl = context.symbol_table.get(identifier).cloned();
let left = self.visit_expr(&left); match var_decl {
let right = self.visit_expr(&right); Some(Stmt::VarDecl(_, expr)) => eval_expr(context, &expr),
_ => Err(String::from("Undefined variable.")),
}
}
match op { fn eval_literal_expr(_: &mut Context, value: &str) -> Result<f64, String> {
TokenKind::Plus => left + right, match value.parse() {
TokenKind::Minus => left - right, Ok(parsed_value) => Ok(parsed_value),
TokenKind::Star => left * right, Err(_) => Err(String::from("Invalid number literal.")),
TokenKind::Slash => left / right, }
TokenKind::Power => left.powf(right), }
_ => 0f64,
fn eval_group_expr(context: &mut Context, expr: &Expr) -> Result<f64, String> {
eval_expr(context, expr)
}
fn eval_fn_call_expr(
context: &mut Context,
identifier: &str,
expressions: &Vec<Expr>,
) -> Result<f64, String> {
let prelude_func = match expressions.len() {
1 => {
let x = eval_expr(context, &expressions[0])?;
prelude::call_unary_func(identifier, x, &context.angle_unit)
} }
} 2 => {
let x = eval_expr(context, &expressions[0])?;
fn eval_unary_expr(&mut self, expr: &Expr) -> f64 { let y = eval_expr(context, &expressions[1])?;
self.visit_expr(&expr).clone() prelude::call_binary_func(identifier, x, y, &context.angle_unit)
}
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;
} }
_ => None,
};
match kind { if let Some(result) = prelude_func {
TokenKind::Deg => x.to_radians(), return Ok(result);
TokenKind::Rad => x.to_degrees(),
_ => panic!("Invalid unit."),
}
} }
fn eval_var_expr(&mut self, identifier: &str) -> f64 { let stmt_definition = context
let value = self .symbol_table
.symbol_table .get(&format!("{}()", identifier))
.get(identifier) .cloned();
.expect("Undefined variable.")
.clone();
if let Stmt::VarDecl(_, expr) = value {
return self.visit_expr(&expr);
}
panic!("Unknown error."); match stmt_definition {
} Some(Stmt::FnDecl(_, arguments, fn_body)) => {
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<Expr>) -> 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 {
if arguments.len() != expressions.len() { 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. // Initialise the arguments as their own variables.
for (i, argument) in arguments.iter().enumerate() { for (i, argument) in arguments.iter().enumerate() {
self.visit_stmt(&Stmt::VarDecl( eval_stmt(
argument.clone(), context,
Box::new(expressions[i].clone()), &Stmt::VarDecl(argument.clone(), Box::new(expressions[i].clone())),
)); )?;
} }
return self.visit_expr(&*fn_body); return eval_expr(context, &*fn_body);
} }
_ => Err(String::from("Undefined function.")),
panic!("Unexpected error.");
} }
} }

View File

@ -5,14 +5,13 @@ mod lexer;
mod parser; mod parser;
mod prelude; mod prelude;
mod symbol_table; mod symbol_table;
mod visitor; use parser::Unit;
use parser::{ParserContext, Unit};
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
use rustyline::Editor; use rustyline::Editor;
fn main() { fn main() {
let mut parser = ParserContext::new(); let mut parser = parser::Context::new();
// Command line argument input, execute it and exit. // Command line argument input, execute it and exit.
if let Some(expr) = env::args().skip(1).next() { 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 { match input {
"" => eprint!(""), "" => eprint!(""),
"clear" => print!("\x1B[2J"), "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()) { match parser::parse(parser, input, get_angle_unit()) {
Ok(result) => println!("{}", result), Ok(Some(result)) => println!("{}", result),
Err(_) => println!("Invalid expression"), Ok(None) => print!(""),
Err(err) => println!("{}", err),
} }
} }

View File

@ -1,7 +1,7 @@
use std::mem; use std::mem;
use crate::{ use crate::{
interpreter::Interpreter, interpreter,
lexer::{Lexer, Token, TokenKind}, lexer::{Lexer, Token, TokenKind},
symbol_table::SymbolTable, symbol_table::SymbolTable,
}; };
@ -30,7 +30,7 @@ pub enum Unit {
Degrees, Degrees,
} }
pub struct ParserContext { pub struct Context {
//angle_unit: Unit, //angle_unit: Unit,
tokens: Vec<Token>, tokens: Vec<Token>,
pos: usize, pos: usize,
@ -50,9 +50,9 @@ impl TokenKind {
} }
} }
impl ParserContext { impl Context {
pub fn new() -> Self { pub fn new() -> Self {
ParserContext { Context {
tokens: Vec::new(), tokens: Vec::new(),
pos: 0, pos: 0,
symbol_table: SymbolTable::new(), symbol_table: SymbolTable::new(),
@ -60,19 +60,20 @@ impl ParserContext {
} }
} }
pub fn parse(context: &mut ParserContext, input: &str, angle_unit: Unit) -> Result<f64, String> { pub fn parse(context: &mut Context, input: &str, angle_unit: Unit) -> Result<Option<f64>, String> {
context.tokens = Lexer::lex(input); context.tokens = Lexer::lex(input);
context.pos = 0;
let mut statements: Vec<Stmt> = Vec::new(); let mut statements: Vec<Stmt> = Vec::new();
while !is_at_end(context) { while !is_at_end(context) {
statements.push(parse_stmt(context)?); statements.push(parse_stmt(context)?);
} }
let mut interpreter = Interpreter::new(angle_unit, &mut context.symbol_table); let mut interpreter = interpreter::Context::new(angle_unit, &mut context.symbol_table);
Ok(interpreter.interpret(statements).unwrap()) interpreter.interpret(statements)
} }
fn parse_stmt(context: &mut ParserContext) -> Result<Stmt, String> { fn parse_stmt(context: &mut Context) -> Result<Stmt, String> {
if match_token(context, TokenKind::Identifier) { if match_token(context, TokenKind::Identifier) {
return Ok(match peek_next(context).kind { return Ok(match peek_next(context).kind {
TokenKind::Equals => parse_var_decl_stmt(context)?, TokenKind::Equals => parse_var_decl_stmt(context)?,
@ -84,7 +85,7 @@ fn parse_stmt(context: &mut ParserContext) -> Result<Stmt, String> {
Ok(Stmt::Expr(Box::new(parse_expr(context)?))) Ok(Stmt::Expr(Box::new(parse_expr(context)?)))
} }
fn parse_identifier_stmt(context: &mut ParserContext) -> Result<Stmt, String> { fn parse_identifier_stmt(context: &mut Context) -> Result<Stmt, String> {
let began_at = context.pos; 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. 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<Stmt, String> {
} }
} }
fn parse_var_decl_stmt(context: &mut ParserContext) -> Result<Stmt, String> { fn parse_var_decl_stmt(context: &mut Context) -> Result<Stmt, String> {
let identifier = advance(context).clone(); let identifier = advance(context).clone();
advance(context); // Equal sign advance(context); // Equal sign
let expr = parse_expr(context)?; let expr = parse_expr(context)?;
@ -134,11 +135,11 @@ fn parse_var_decl_stmt(context: &mut ParserContext) -> Result<Stmt, String> {
Ok(Stmt::VarDecl(identifier.value, Box::new(expr))) Ok(Stmt::VarDecl(identifier.value, Box::new(expr)))
} }
fn parse_expr(context: &mut ParserContext) -> Result<Expr, String> { fn parse_expr(context: &mut Context) -> Result<Expr, String> {
Ok(parse_sum(context)?) Ok(parse_sum(context)?)
} }
fn parse_sum(context: &mut ParserContext) -> Result<Expr, String> { fn parse_sum(context: &mut Context) -> Result<Expr, String> {
let mut left = parse_factor(context)?; let mut left = parse_factor(context)?;
while match_token(context, TokenKind::Plus) || match_token(context, TokenKind::Minus) { while match_token(context, TokenKind::Plus) || match_token(context, TokenKind::Minus) {
@ -152,7 +153,7 @@ fn parse_sum(context: &mut ParserContext) -> Result<Expr, String> {
Ok(left) Ok(left)
} }
fn parse_factor(context: &mut ParserContext) -> Result<Expr, String> { fn parse_factor(context: &mut Context) -> Result<Expr, String> {
let mut left = parse_unary(context)?; let mut left = parse_unary(context)?;
while match_token(context, TokenKind::Star) while match_token(context, TokenKind::Star)
@ -175,7 +176,7 @@ fn parse_factor(context: &mut ParserContext) -> Result<Expr, String> {
Ok(left) Ok(left)
} }
fn parse_unary(context: &mut ParserContext) -> Result<Expr, String> { fn parse_unary(context: &mut Context) -> Result<Expr, String> {
if match_token(context, TokenKind::Minus) { if match_token(context, TokenKind::Minus) {
let op = advance(context).kind.clone(); let op = advance(context).kind.clone();
let expr = Box::new(parse_unary(context)?); let expr = Box::new(parse_unary(context)?);
@ -185,7 +186,7 @@ fn parse_unary(context: &mut ParserContext) -> Result<Expr, String> {
Ok(parse_exponent(context)?) Ok(parse_exponent(context)?)
} }
fn parse_exponent(context: &mut ParserContext) -> Result<Expr, String> { fn parse_exponent(context: &mut Context) -> Result<Expr, String> {
let left = parse_primary(context)?; let left = parse_primary(context)?;
if match_token(context, TokenKind::Power) { if match_token(context, TokenKind::Power) {
@ -197,7 +198,7 @@ fn parse_exponent(context: &mut ParserContext) -> Result<Expr, String> {
Ok(left) Ok(left)
} }
fn parse_primary(context: &mut ParserContext) -> Result<Expr, String> { fn parse_primary(context: &mut Context) -> Result<Expr, String> {
let expr = match peek(context).kind { let expr = match peek(context).kind {
TokenKind::OpenParenthesis => parse_group(context)?, TokenKind::OpenParenthesis => parse_group(context)?,
TokenKind::Pipe => parse_abs(context)?, TokenKind::Pipe => parse_abs(context)?,
@ -212,7 +213,7 @@ fn parse_primary(context: &mut ParserContext) -> Result<Expr, String> {
} }
} }
fn parse_group(context: &mut ParserContext) -> Result<Expr, String> { fn parse_group(context: &mut Context) -> Result<Expr, String> {
advance(context); advance(context);
let group_expr = Expr::Group(Box::new(parse_expr(context)?)); let group_expr = Expr::Group(Box::new(parse_expr(context)?));
consume(context, TokenKind::ClosedParenthesis)?; consume(context, TokenKind::ClosedParenthesis)?;
@ -220,7 +221,7 @@ fn parse_group(context: &mut ParserContext) -> Result<Expr, String> {
Ok(group_expr) Ok(group_expr)
} }
fn parse_abs(context: &mut ParserContext) -> Result<Expr, String> { fn parse_abs(context: &mut Context) -> Result<Expr, String> {
advance(context); advance(context);
let group_expr = Expr::Group(Box::new(parse_expr(context)?)); let group_expr = Expr::Group(Box::new(parse_expr(context)?));
consume(context, TokenKind::Pipe)?; consume(context, TokenKind::Pipe)?;
@ -228,7 +229,7 @@ fn parse_abs(context: &mut ParserContext) -> Result<Expr, String> {
Ok(Expr::FnCall(String::from("abs"), vec![group_expr])) Ok(Expr::FnCall(String::from("abs"), vec![group_expr]))
} }
fn parse_identifier(context: &mut ParserContext) -> Result<Expr, String> { fn parse_identifier(context: &mut Context) -> Result<Expr, String> {
let identifier = advance(context).clone(); let identifier = advance(context).clone();
// Eg. sqrt64 // Eg. sqrt64
@ -261,19 +262,19 @@ fn parse_identifier(context: &mut ParserContext) -> Result<Expr, String> {
Ok(Expr::Var(identifier.value)) 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] &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] &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] &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) { if is_at_end(context) {
return false; return false;
} }
@ -281,12 +282,12 @@ fn match_token(context: &mut ParserContext, kind: TokenKind) -> bool {
peek(context).kind.compare(&kind) 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; context.pos += 1;
previous(context) 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) { if match_token(context, kind) {
return Ok(advance(context)); return Ok(advance(context));
} }
@ -294,6 +295,6 @@ fn consume<'a>(context: &'a mut ParserContext, kind: TokenKind) -> Result<&'a To
Err("Unexpected token".into()) 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) context.pos >= context.tokens.len() || peek(context).kind.compare(&TokenKind::EOF)
} }

View File

@ -1,6 +0,0 @@
use crate::parser::{Expr, Stmt};
pub trait Visitor<T, U> {
fn visit_stmt(&mut self, stmt: &Stmt) -> T;
fn visit_expr(&mut self, expr: &Expr) -> U;
}