From 5de2230feccdf6cc479ce5f381eddef325f679a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20R=C3=B6ger?= Date: Tue, 5 Nov 2024 21:40:27 +0100 Subject: [PATCH] feat(expression): add mode prelude numeric fns --- src/lisp/expression.rs | 73 ++++++++++++++++++++++++++++++++++++++++-- src/main.rs | 2 +- 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/lisp/expression.rs b/src/lisp/expression.rs index 08b2ad3..caff7d1 100644 --- a/src/lisp/expression.rs +++ b/src/lisp/expression.rs @@ -34,6 +34,7 @@ pub enum Expression { pub enum EvalError { SymbolNotBound(String), NotAFunction(Expression), + NotANumber(Expression), ArgumentError(String), TypeError(String), NotASymbol(Expression), @@ -189,10 +190,73 @@ fn eval(env: &Environment, expr: Expression) -> Result { fn prelude_add(env: &Environment, expr: Expression) -> Result { let [a, b] = expr.try_into()?; - let a: i64 = eval(env, a)?.try_into()?; - let b: i64 = eval(env, b)?.try_into()?; + match eval(env, a)? { + Expression::Integer(a) => match eval(env, b)? { + Expression::Integer(b) => Ok(Expression::Integer(a + b)), + Expression::Float(b) => Ok(Expression::Float(a as f64 + b)), + x => Err(EvalError::NotANumber(x)), + }, + Expression::Float(a) => match eval(env, b)? { + Expression::Float(b) => Ok(Expression::Float(a + b)), + Expression::Integer(b) => Ok(Expression::Float(a + b as f64)), + x => Err(EvalError::NotANumber(x)), + }, + x => Err(EvalError::NotANumber(x)), + } +} - Ok(Expression::Integer(a + b)) +fn prelude_sub(env: &Environment, expr: Expression) -> Result { + let [a, b] = expr.try_into()?; + + match eval(env, a)? { + Expression::Integer(a) => match eval(env, b)? { + Expression::Integer(b) => Ok(Expression::Integer(a - b)), + Expression::Float(b) => Ok(Expression::Float(a as f64 - b)), + x => Err(EvalError::NotANumber(x)), + }, + Expression::Float(a) => match eval(env, b)? { + Expression::Float(b) => Ok(Expression::Float(a - b)), + Expression::Integer(b) => Ok(Expression::Float(a - b as f64)), + x => Err(EvalError::NotANumber(x)), + }, + x => Err(EvalError::NotANumber(x)), + } +} + +fn prelude_mul(env: &Environment, expr: Expression) -> Result { + let [a, b] = expr.try_into()?; + + match eval(env, a)? { + Expression::Integer(a) => match eval(env, b)? { + Expression::Integer(b) => Ok(Expression::Integer(a * b)), + Expression::Float(b) => Ok(Expression::Float(a as f64 * b)), + x => Err(EvalError::NotANumber(x)), + }, + Expression::Float(a) => match eval(env, b)? { + Expression::Float(b) => Ok(Expression::Float(a * b)), + Expression::Integer(b) => Ok(Expression::Float(a * b as f64)), + x => Err(EvalError::NotANumber(x)), + }, + x => Err(EvalError::NotANumber(x)), + } +} + +fn prelude_div(env: &Environment, expr: Expression) -> Result { + let [a, b] = expr.try_into()?; + + match eval(env, a)? { + Expression::Integer(a) => match eval(env, b)? { + Expression::Integer(b) => Ok(Expression::Integer(a / b)), + Expression::Float(b) => Ok(Expression::Float(a as f64 / b)), + x => Err(EvalError::NotANumber(x)), + }, + Expression::Float(a) => match eval(env, b)? { + Expression::Float(b) => Ok(Expression::Float(a / b)), + Expression::Integer(b) => Ok(Expression::Float(a / b as f64)), + x => Err(EvalError::NotANumber(x)), + }, + x => Err(EvalError::NotANumber(x)), + } } fn prelude_lambda(_env: &Environment, expr: Expression) -> Result { @@ -278,6 +342,9 @@ fn prelude_gt(env: &Environment, expr: Expression) -> Result Result { let mut prelude = Environment::new(); prelude.set("+".to_string(), Expression::Function(prelude_add)); + prelude.set("-".to_string(), Expression::Function(prelude_sub)); + prelude.set("*".to_string(), Expression::Function(prelude_mul)); + prelude.set("/".to_string(), Expression::Function(prelude_div)); prelude.set("lambda".to_string(), Expression::Function(prelude_lambda)); prelude.set("if".to_string(), Expression::Function(prelude_if)); prelude.set("==".to_string(), Expression::Function(prelude_eq)); diff --git a/src/main.rs b/src/main.rs index 39410e0..4cbe31f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use lisp::eval_prelude; use parser::ExpressionStream; fn main() { - let program = "((lambda (x y) (+ (if (< x 10) (+ x 10) x) y)) 2 20)"; + let program = "((lambda (x y) (+ (if (< x 10) (* x 11) x) y)) 2 20)"; for r in ExpressionStream::from_char_stream(program.chars()) { match r {