mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-01-22 04:58:35 +01:00
Created CalcError enum and centralised error formatting into once place.
This commit is contained in:
parent
4a02134b22
commit
d0536d6bd6
@ -1,4 +1,5 @@
|
|||||||
use crate::lexer::TokenKind;
|
use crate::lexer::TokenKind;
|
||||||
|
use crate::parser::CalcError;
|
||||||
use crate::parser::Unit;
|
use crate::parser::Unit;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@ -27,11 +28,11 @@ impl TokenKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_unit(&self) -> Result<Unit, String> {
|
pub fn to_unit(&self) -> Result<Unit, CalcError> {
|
||||||
match self {
|
match self {
|
||||||
TokenKind::Deg => Ok(Unit::Degrees),
|
TokenKind::Deg => Ok(Unit::Degrees),
|
||||||
TokenKind::Rad => Ok(Unit::Radians),
|
TokenKind::Rad => Ok(Unit::Radians),
|
||||||
_ => Err(String::from("Invalid unit.")),
|
_ => Err(CalcError::InvalidUnit),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::ast::{Expr, Stmt};
|
use crate::ast::{Expr, Stmt};
|
||||||
use crate::lexer::TokenKind;
|
use crate::lexer::TokenKind;
|
||||||
|
use crate::parser::CalcError;
|
||||||
use crate::parser::Unit;
|
use crate::parser::Unit;
|
||||||
use crate::prelude;
|
use crate::prelude;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
@ -21,7 +22,7 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpret(&mut self, statements: Vec<Stmt>) -> Result<Option<Float>, String> {
|
pub fn interpret(&mut self, statements: Vec<Stmt>) -> Result<Option<Float>, CalcError> {
|
||||||
for (i, stmt) in statements.iter().enumerate() {
|
for (i, stmt) in statements.iter().enumerate() {
|
||||||
let value = eval_stmt(self, stmt);
|
let value = eval_stmt(self, stmt);
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_stmt(context: &mut Context, stmt: &Stmt) -> Result<Float, String> {
|
fn eval_stmt(context: &mut Context, stmt: &Stmt) -> Result<Float, CalcError> {
|
||||||
match stmt {
|
match stmt {
|
||||||
Stmt::VarDecl(identifier, _) => eval_var_decl_stmt(context, stmt, identifier),
|
Stmt::VarDecl(identifier, _) => eval_var_decl_stmt(context, stmt, identifier),
|
||||||
Stmt::FnDecl(_, _, _) => eval_fn_decl_stmt(context),
|
Stmt::FnDecl(_, _, _) => eval_fn_decl_stmt(context),
|
||||||
@ -48,20 +49,20 @@ fn eval_var_decl_stmt(
|
|||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
stmt: &Stmt,
|
stmt: &Stmt,
|
||||||
identifier: &str,
|
identifier: &str,
|
||||||
) -> Result<Float, String> {
|
) -> Result<Float, CalcError> {
|
||||||
context.symbol_table.insert(&identifier, stmt.clone());
|
context.symbol_table.insert(&identifier, stmt.clone());
|
||||||
Ok(Float::with_val(context.precision, 1))
|
Ok(Float::with_val(context.precision, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_fn_decl_stmt(context: &mut Context) -> Result<Float, String> {
|
fn eval_fn_decl_stmt(context: &mut Context) -> Result<Float, CalcError> {
|
||||||
Ok(Float::with_val(context.precision, 1)) // Nothing needs to happen here, since the parser will already have added the FnDecl's to the symbol table.
|
Ok(Float::with_val(context.precision, 1)) // 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<Float, String> {
|
fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result<Float, CalcError> {
|
||||||
eval_expr(context, &expr)
|
eval_expr(context, &expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_expr(context: &mut Context, expr: &Expr) -> Result<Float, String> {
|
fn eval_expr(context: &mut Context, expr: &Expr) -> Result<Float, CalcError> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Binary(left, op, right) => eval_binary_expr(context, &left, op, &right),
|
Expr::Binary(left, op, right) => eval_binary_expr(context, &left, op, &right),
|
||||||
Expr::Unary(op, expr) => eval_unary_expr(context, op, expr),
|
Expr::Unary(op, expr) => eval_unary_expr(context, op, expr),
|
||||||
@ -80,7 +81,7 @@ fn eval_binary_expr(
|
|||||||
left: &Expr,
|
left: &Expr,
|
||||||
op: &TokenKind,
|
op: &TokenKind,
|
||||||
right: &Expr,
|
right: &Expr,
|
||||||
) -> Result<Float, String> {
|
) -> Result<Float, CalcError> {
|
||||||
let left = eval_expr(context, &left)?;
|
let left = eval_expr(context, &left)?;
|
||||||
let right = eval_expr(context, &right)?;
|
let right = eval_expr(context, &right)?;
|
||||||
|
|
||||||
@ -94,7 +95,7 @@ fn eval_binary_expr(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_unary_expr(context: &mut Context, op: &TokenKind, expr: &Expr) -> Result<Float, String> {
|
fn eval_unary_expr(context: &mut Context, op: &TokenKind, expr: &Expr) -> Result<Float, CalcError> {
|
||||||
let expr_value = eval_expr(context, &expr)?;
|
let expr_value = eval_expr(context, &expr)?;
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
@ -103,11 +104,15 @@ fn eval_unary_expr(context: &mut Context, op: &TokenKind, expr: &Expr) -> Result
|
|||||||
context.precision,
|
context.precision,
|
||||||
prelude::special_funcs::factorial(expr_value),
|
prelude::special_funcs::factorial(expr_value),
|
||||||
)),
|
)),
|
||||||
_ => Err(String::from("Invalid operator for unary expression.")),
|
_ => Err(CalcError::InvalidOperator),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_unit_expr(context: &mut Context, expr: &Expr, kind: &TokenKind) -> Result<Float, String> {
|
fn eval_unit_expr(
|
||||||
|
context: &mut Context,
|
||||||
|
expr: &Expr,
|
||||||
|
kind: &TokenKind,
|
||||||
|
) -> Result<Float, CalcError> {
|
||||||
let x = eval_expr(context, &expr);
|
let x = eval_expr(context, &expr);
|
||||||
let unit = kind.to_unit()?;
|
let unit = kind.to_unit()?;
|
||||||
|
|
||||||
@ -126,7 +131,7 @@ fn eval_unit_expr(context: &mut Context, expr: &Expr, kind: &TokenKind) -> Resul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_var_expr(context: &mut Context, identifier: &str) -> Result<Float, String> {
|
fn eval_var_expr(context: &mut Context, identifier: &str) -> Result<Float, CalcError> {
|
||||||
// If there is a constant with this name, return a literal expression with its value
|
// If there is a constant with this name, return a literal expression with its value
|
||||||
if let Some(value) = prelude::CONSTANTS.get(identifier) {
|
if let Some(value) = prelude::CONSTANTS.get(identifier) {
|
||||||
return eval_expr(context, &Expr::Literal((*value).to_string()));
|
return eval_expr(context, &Expr::Literal((*value).to_string()));
|
||||||
@ -136,18 +141,18 @@ fn eval_var_expr(context: &mut Context, identifier: &str) -> Result<Float, Strin
|
|||||||
let var_decl = context.symbol_table.get(identifier).cloned();
|
let var_decl = context.symbol_table.get(identifier).cloned();
|
||||||
match var_decl {
|
match var_decl {
|
||||||
Some(Stmt::VarDecl(_, expr)) => eval_expr(context, &expr),
|
Some(Stmt::VarDecl(_, expr)) => eval_expr(context, &expr),
|
||||||
_ => Err(format!("Undefined variable: '{}'.", identifier)),
|
_ => Err(CalcError::UndefinedVar(identifier.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_literal_expr(context: &mut Context, value: &str) -> Result<Float, String> {
|
fn eval_literal_expr(context: &mut Context, value: &str) -> Result<Float, CalcError> {
|
||||||
match Float::parse(value) {
|
match Float::parse(value) {
|
||||||
Ok(parsed_value) => Ok(Float::with_val(context.precision, parsed_value)),
|
Ok(parsed_value) => Ok(Float::with_val(context.precision, parsed_value)),
|
||||||
Err(_) => Err(format!("Invalid number literal: '{}'.", value)),
|
Err(_) => Err(CalcError::InvalidNumberLiteral(value.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_group_expr(context: &mut Context, expr: &Expr) -> Result<Float, String> {
|
fn eval_group_expr(context: &mut Context, expr: &Expr) -> Result<Float, CalcError> {
|
||||||
eval_expr(context, expr)
|
eval_expr(context, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +160,7 @@ fn eval_fn_call_expr(
|
|||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
identifier: &str,
|
identifier: &str,
|
||||||
expressions: &[Expr],
|
expressions: &[Expr],
|
||||||
) -> Result<Float, String> {
|
) -> Result<Float, CalcError> {
|
||||||
// Prelude
|
// Prelude
|
||||||
let prelude_func = match expressions.len() {
|
let prelude_func = match expressions.len() {
|
||||||
1 => {
|
1 => {
|
||||||
@ -179,9 +184,10 @@ fn eval_fn_call_expr(
|
|||||||
"sum" | "Σ" => {
|
"sum" | "Σ" => {
|
||||||
// Make sure exactly 3 arguments were supplied.
|
// Make sure exactly 3 arguments were supplied.
|
||||||
if expressions.len() != 3 {
|
if expressions.len() != 3 {
|
||||||
return Err(format!(
|
return Err(CalcError::IncorrectAmountOfArguments(
|
||||||
"Expected 3 arguments but got {}.",
|
3,
|
||||||
expressions.len()
|
"sum".into(),
|
||||||
|
expressions.len(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,11 +220,10 @@ fn eval_fn_call_expr(
|
|||||||
match stmt_definition {
|
match stmt_definition {
|
||||||
Some(Stmt::FnDecl(_, arguments, fn_body)) => {
|
Some(Stmt::FnDecl(_, arguments, fn_body)) => {
|
||||||
if arguments.len() != expressions.len() {
|
if arguments.len() != expressions.len() {
|
||||||
return Err(format!(
|
return Err(CalcError::IncorrectAmountOfArguments(
|
||||||
"Expected {} arguments in function '{}' but found {}.",
|
|
||||||
arguments.len(),
|
arguments.len(),
|
||||||
identifier,
|
identifier.into(),
|
||||||
expressions.len()
|
expressions.len(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +237,7 @@ fn eval_fn_call_expr(
|
|||||||
|
|
||||||
eval_expr(context, &*fn_body)
|
eval_expr(context, &*fn_body)
|
||||||
}
|
}
|
||||||
_ => Err(format!("Undefined function: '{}'.", identifier)),
|
_ => Err(CalcError::UndefinedFn(identifier.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +249,7 @@ mod tests {
|
|||||||
|
|
||||||
const PRECISION: u32 = 53;
|
const PRECISION: u32 = 53;
|
||||||
|
|
||||||
fn interpret(stmt: Stmt) -> Result<Option<Float>, String> {
|
fn interpret(stmt: Stmt) -> Result<Option<Float>, CalcError> {
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
let mut context = Context::new(&mut symbol_table, &Unit::Radians, PRECISION);
|
let mut context = Context::new(&mut symbol_table, &Unit::Radians, PRECISION);
|
||||||
context.interpret(vec![stmt])
|
context.interpret(vec![stmt])
|
||||||
@ -318,7 +323,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret(stmt),
|
interpret(stmt),
|
||||||
Err(String::from("Undefined variable: 'x'."))
|
Err(CalcError::UndefinedVar(String::from("x")))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,11 +12,6 @@ pub struct Context {
|
|||||||
symbol_table: SymbolTable,
|
symbol_table: SymbolTable,
|
||||||
angle_unit: Unit,
|
angle_unit: Unit,
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum Unit {
|
|
||||||
Radians,
|
|
||||||
Degrees,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
@ -41,7 +36,29 @@ impl Default for Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(context: &mut Context, input: &str, precision: u32) -> Result<Option<Float>, String> {
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Unit {
|
||||||
|
Radians,
|
||||||
|
Degrees,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum CalcError {
|
||||||
|
IncorrectAmountOfArguments(usize, String, usize),
|
||||||
|
InvalidNumberLiteral(String),
|
||||||
|
InvalidOperator,
|
||||||
|
InvalidUnit,
|
||||||
|
UnexpectedToken(TokenKind),
|
||||||
|
UndefinedFn(String),
|
||||||
|
UndefinedVar(String),
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(
|
||||||
|
context: &mut Context,
|
||||||
|
input: &str,
|
||||||
|
precision: u32,
|
||||||
|
) -> Result<Option<Float>, CalcError> {
|
||||||
context.tokens = Lexer::lex(input);
|
context.tokens = Lexer::lex(input);
|
||||||
context.pos = 0;
|
context.pos = 0;
|
||||||
|
|
||||||
@ -54,7 +71,7 @@ pub fn parse(context: &mut Context, input: &str, precision: u32) -> Result<Optio
|
|||||||
interpreter.interpret(statements)
|
interpreter.interpret(statements)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_stmt(context: &mut Context) -> Result<Stmt, String> {
|
fn parse_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
||||||
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)?,
|
||||||
@ -66,7 +83,7 @@ fn parse_stmt(context: &mut Context) -> 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 Context) -> Result<Stmt, String> {
|
fn parse_identifier_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
||||||
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.
|
||||||
|
|
||||||
@ -99,7 +116,7 @@ fn parse_identifier_stmt(context: &mut Context) -> Result<Stmt, String> {
|
|||||||
return Ok(fn_decl);
|
return Ok(fn_decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
Err("Parsing error.".into())
|
Err(CalcError::Unknown)
|
||||||
} else {
|
} else {
|
||||||
// It is a function call, not a function declaration.
|
// It is a function call, not a function declaration.
|
||||||
// Redo the parsing for this specific part.
|
// Redo the parsing for this specific part.
|
||||||
@ -108,7 +125,7 @@ fn parse_identifier_stmt(context: &mut Context) -> Result<Stmt, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_var_decl_stmt(context: &mut Context) -> Result<Stmt, String> {
|
fn parse_var_decl_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
||||||
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)?;
|
||||||
@ -116,11 +133,11 @@ fn parse_var_decl_stmt(context: &mut Context) -> Result<Stmt, String> {
|
|||||||
Ok(Stmt::VarDecl(identifier.value, Box::new(expr)))
|
Ok(Stmt::VarDecl(identifier.value, Box::new(expr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expr(context: &mut Context) -> Result<Expr, String> {
|
fn parse_expr(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
Ok(parse_sum(context)?)
|
Ok(parse_sum(context)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_sum(context: &mut Context) -> Result<Expr, String> {
|
fn parse_sum(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
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) {
|
||||||
@ -134,7 +151,7 @@ fn parse_sum(context: &mut Context) -> Result<Expr, String> {
|
|||||||
Ok(left)
|
Ok(left)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_factor(context: &mut Context) -> Result<Expr, String> {
|
fn parse_factor(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
let mut left = parse_unary(context)?;
|
let mut left = parse_unary(context)?;
|
||||||
|
|
||||||
while match_token(context, TokenKind::Star)
|
while match_token(context, TokenKind::Star)
|
||||||
@ -155,7 +172,7 @@ fn parse_factor(context: &mut Context) -> Result<Expr, String> {
|
|||||||
Ok(left)
|
Ok(left)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_unary(context: &mut Context) -> Result<Expr, String> {
|
fn parse_unary(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
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)?);
|
||||||
@ -165,7 +182,7 @@ fn parse_unary(context: &mut Context) -> Result<Expr, String> {
|
|||||||
Ok(parse_exponent(context)?)
|
Ok(parse_exponent(context)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_exponent(context: &mut Context) -> Result<Expr, String> {
|
fn parse_exponent(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
let left = parse_factorial(context)?;
|
let left = parse_factorial(context)?;
|
||||||
|
|
||||||
if match_token(context, TokenKind::Power) {
|
if match_token(context, TokenKind::Power) {
|
||||||
@ -177,7 +194,7 @@ fn parse_exponent(context: &mut Context) -> Result<Expr, String> {
|
|||||||
Ok(left)
|
Ok(left)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_factorial(context: &mut Context) -> Result<Expr, String> {
|
fn parse_factorial(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
let expr = parse_primary(context)?;
|
let expr = parse_primary(context)?;
|
||||||
|
|
||||||
Ok(if match_token(context, TokenKind::Exclamation) {
|
Ok(if match_token(context, TokenKind::Exclamation) {
|
||||||
@ -188,7 +205,7 @@ fn parse_factorial(context: &mut Context) -> Result<Expr, String> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_primary(context: &mut Context) -> Result<Expr, String> {
|
fn parse_primary(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
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)?,
|
||||||
@ -203,7 +220,7 @@ fn parse_primary(context: &mut Context) -> Result<Expr, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_group(context: &mut Context) -> Result<Expr, String> {
|
fn parse_group(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
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)?;
|
||||||
@ -211,7 +228,7 @@ fn parse_group(context: &mut Context) -> Result<Expr, String> {
|
|||||||
Ok(group_expr)
|
Ok(group_expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_abs(context: &mut Context) -> Result<Expr, String> {
|
fn parse_abs(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
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)?;
|
||||||
@ -219,7 +236,7 @@ fn parse_abs(context: &mut Context) -> 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 Context) -> Result<Expr, String> {
|
fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
let identifier = advance(context).clone();
|
let identifier = advance(context).clone();
|
||||||
|
|
||||||
// Eg. sqrt64
|
// Eg. sqrt64
|
||||||
@ -294,12 +311,12 @@ fn advance(context: &mut Context) -> &Token {
|
|||||||
previous(context)
|
previous(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(context: &mut Context, kind: TokenKind) -> Result<&Token, String> {
|
fn consume(context: &mut Context, kind: TokenKind) -> Result<&Token, CalcError> {
|
||||||
if match_token(context, kind) {
|
if match_token(context, kind.clone()) {
|
||||||
return Ok(advance(context));
|
return Ok(advance(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
Err("Unexpected token".into())
|
Err(CalcError::UnexpectedToken(kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_at_end(context: &mut Context) -> bool {
|
fn is_at_end(context: &mut Context) -> bool {
|
||||||
@ -313,13 +330,13 @@ mod tests {
|
|||||||
use crate::test_helpers::*;
|
use crate::test_helpers::*;
|
||||||
use test_case::test_case;
|
use test_case::test_case;
|
||||||
|
|
||||||
fn parse_with_context(context: &mut Context, tokens: Vec<Token>) -> Result<Stmt, String> {
|
fn parse_with_context(context: &mut Context, tokens: Vec<Token>) -> Result<Stmt, CalcError> {
|
||||||
context.tokens = tokens;
|
context.tokens = tokens;
|
||||||
|
|
||||||
parse_stmt(context)
|
parse_stmt(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(tokens: Vec<Token>) -> Result<Stmt, String> {
|
fn parse(tokens: Vec<Token>) -> Result<Stmt, CalcError> {
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
context.tokens = tokens;
|
context.tokens = tokens;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use ansi_term::Colour::Red;
|
use ansi_term::Colour::Red;
|
||||||
use kalk::parser::{self};
|
use kalk::parser::{self, CalcError, CalcError::*};
|
||||||
|
|
||||||
pub fn eval(parser: &mut parser::Context, input: &str) {
|
pub fn eval(parser: &mut parser::Context, input: &str) {
|
||||||
match parser::parse(parser, input, 53) {
|
match parser::parse(parser, input, 53) {
|
||||||
@ -8,7 +8,7 @@ pub fn eval(parser: &mut parser::Context, input: &str) {
|
|||||||
let exp = if let Some(exp) = exp_option { exp } else { 0 };
|
let exp = if let Some(exp) = exp_option { exp } else { 0 };
|
||||||
|
|
||||||
if result.is_infinite() {
|
if result.is_infinite() {
|
||||||
err("Too big to process.");
|
print_err("Too big to process.");
|
||||||
/*} else if result.clone().fract() == 0 {
|
/*} else if result.clone().fract() == 0 {
|
||||||
println!("{}", result.to_integer().unwrap());*/
|
println!("{}", result.to_integer().unwrap());*/
|
||||||
} else {
|
} else {
|
||||||
@ -37,10 +37,26 @@ pub fn eval(parser: &mut parser::Context, input: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(None) => print!(""),
|
Ok(None) => print!(""),
|
||||||
Err(msg) => err(&msg),
|
Err(err) => print_calc_err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn err(msg: &str) {
|
fn print_calc_err(err: CalcError) {
|
||||||
|
print_err(&match err {
|
||||||
|
IncorrectAmountOfArguments(expected, func, got) => format!(
|
||||||
|
"Expected {} arguments for function {}, but got {}.",
|
||||||
|
expected, func, got
|
||||||
|
),
|
||||||
|
InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x),
|
||||||
|
InvalidOperator => format!("Invalid operator."),
|
||||||
|
InvalidUnit => format!("Invalid unit."),
|
||||||
|
UnexpectedToken(kind) => format!("Unexpected token: '{:?}'.", kind),
|
||||||
|
UndefinedFn(name) => format!("Undefined function: '{}'.", name),
|
||||||
|
UndefinedVar(name) => format!("Undefined variable: '{}'.", name),
|
||||||
|
Unknown => format!("Unknown error."),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_err(msg: &str) {
|
||||||
println!("{}", Red.paint(msg));
|
println!("{}", Red.paint(msg));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user