feat(expression): add mode prelude numeric fns

This commit is contained in:
Jonas Röger 2024-11-05 21:40:27 +01:00
parent 578e0c2435
commit 5de2230fec
Signed by: jonas
GPG Key ID: 4000EB35E1AE0F07
2 changed files with 71 additions and 4 deletions

View File

@ -34,6 +34,7 @@ pub enum Expression {
pub enum EvalError { pub enum EvalError {
SymbolNotBound(String), SymbolNotBound(String),
NotAFunction(Expression), NotAFunction(Expression),
NotANumber(Expression),
ArgumentError(String), ArgumentError(String),
TypeError(String), TypeError(String),
NotASymbol(Expression), NotASymbol(Expression),
@ -189,10 +190,73 @@ fn eval(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
fn prelude_add(env: &Environment, expr: Expression) -> Result<Expression, EvalError> { fn prelude_add(env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
let [a, b] = expr.try_into()?; let [a, b] = expr.try_into()?;
let a: i64 = eval(env, a)?.try_into()?; match eval(env, a)? {
let b: i64 = eval(env, b)?.try_into()?; 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<Expression, EvalError> {
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<Expression, EvalError> {
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<Expression, EvalError> {
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<Expression, EvalError> { fn prelude_lambda(_env: &Environment, expr: Expression) -> Result<Expression, EvalError> {
@ -278,6 +342,9 @@ fn prelude_gt(env: &Environment, expr: Expression) -> Result<Expression, EvalErr
pub fn eval_prelude(expr: Expression) -> Result<Expression, EvalError> { pub fn eval_prelude(expr: Expression) -> Result<Expression, EvalError> {
let mut prelude = Environment::new(); let mut prelude = Environment::new();
prelude.set("+".to_string(), Expression::Function(prelude_add)); 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("lambda".to_string(), Expression::Function(prelude_lambda));
prelude.set("if".to_string(), Expression::Function(prelude_if)); prelude.set("if".to_string(), Expression::Function(prelude_if));
prelude.set("==".to_string(), Expression::Function(prelude_eq)); prelude.set("==".to_string(), Expression::Function(prelude_eq));

View File

@ -4,7 +4,7 @@ use lisp::eval_prelude;
use parser::ExpressionStream; use parser::ExpressionStream;
fn main() { 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()) { for r in ExpressionStream::from_char_stream(program.chars()) {
match r { match r {