diff --git a/src/interpreter.rs b/src/interpreter.rs index 77c082f..324dc77 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -55,7 +55,7 @@ fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result { 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::Unary(op, expr) => eval_unary_expr(context, op, 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), @@ -85,8 +85,14 @@ fn eval_binary_expr( }) } -fn eval_unary_expr(context: &mut Context, expr: &Expr) -> Result { - eval_expr(context, &expr).clone() +fn eval_unary_expr(context: &mut Context, op: &TokenKind, expr: &Expr) -> Result { + let expr_value = eval_expr(context, &expr)?.clone(); + + match op { + TokenKind::Minus => Ok(-expr_value), + TokenKind::Exclamation => Ok(prelude::funcs::factorial(expr_value)), + _ => Err(String::from("Invalid operator for unary expression.")), + } } fn eval_unit_expr(context: &mut Context, expr: &Expr, kind: &TokenKind) -> Result { diff --git a/src/lexer.rs b/src/lexer.rs index 8e00b93..324bd5b 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -12,6 +12,7 @@ pub enum TokenKind { Slash, Power, Equals, + Exclamation, Deg, Rad, @@ -106,6 +107,10 @@ impl<'a> Lexer<'a> { self.advance(); self.build(TokenKind::Equals, "") } + '!' => { + self.advance(); + self.build(TokenKind::Exclamation, "") + } ',' => { self.advance(); self.build(TokenKind::Comma, "") diff --git a/src/parser.rs b/src/parser.rs index 67368be..789de4e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -30,7 +30,6 @@ pub fn parse(context: &mut Context, input: &str, angle_unit: Unit) -> Result Result { } fn parse_exponent(context: &mut Context) -> Result { - let left = parse_primary(context)?; + let left = parse_factorial(context)?; if match_token(context, TokenKind::Power) { let op = advance(context).kind.clone(); @@ -158,6 +157,17 @@ fn parse_exponent(context: &mut Context) -> Result { Ok(left) } +fn parse_factorial(context: &mut Context) -> Result { + let expr = parse_primary(context)?; + + Ok(if match_token(context, TokenKind::Exclamation) { + advance(context); + Expr::Unary(TokenKind::Exclamation, Box::new(expr)) + } else { + expr + }) +} + fn parse_primary(context: &mut Context) -> Result { let expr = match peek(context).kind { TokenKind::OpenParenthesis => parse_group(context)?, diff --git a/src/prelude.rs b/src/prelude.rs index be915a6..fd3b6fa 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -56,6 +56,7 @@ pub const BINARY_FUNCS: phf::Map<&'static str, BinaryFuncInfo> = phf::phf_map! { "min" => BinaryFuncInfo(min, Other), "hyp" => BinaryFuncInfo(hyp, Other), "log" => BinaryFuncInfo(logx, Other), + "sqrt" => BinaryFuncInfo(nth_sqrt, Other), }; enum FuncType { @@ -124,7 +125,7 @@ fn from_angle_unit(x: f64, angle_unit: &Unit) -> f64 { } } -mod funcs { +pub mod funcs { pub fn abs(x: f64) -> f64 { x.abs() } @@ -212,6 +213,15 @@ mod funcs { x.exp() } + pub fn factorial(x: f64) -> f64 { + let mut value = 1; + for i in 1..=x as i32 { + value *= i; + } + + value as f64 + } + pub fn floor(x: f64) -> f64 { x.floor() } @@ -268,6 +278,10 @@ mod funcs { x.sqrt() } + pub fn nth_sqrt(x: f64, n: f64) -> f64 { + x.powf(1f64 / n) + } + pub fn tan(x: f64) -> f64 { x.tan() }