rustleaf 0.1.0

A simple programming language interpreter written in Rust
Documentation
use crate::core::{Args, Value};
use crate::eval::Evaluator;
use anyhow::{anyhow, Result};

fn value_to_f64(value: &Value) -> Result<f64> {
    match value {
        Value::Int(n) => Ok(*n as f64),
        Value::Float(f) => Ok(*f),
        _ => Err(anyhow!("Expected a number, got {:?}", value)),
    }
}

pub fn sqrt(mut args: Args) -> Result<Value> {
    args.set_function_name("sqrt");
    let arg = args.expect("value")?;
    args.complete()?;

    let f = value_to_f64(&arg)?;
    if f < 0.0 {
        return Err(anyhow!("sqrt() of negative number"));
    }
    Ok(Value::Float(f.sqrt()))
}

pub fn sin(mut args: Args) -> Result<Value> {
    args.set_function_name("sin");
    let arg = args.expect("value")?;
    args.complete()?;

    let f = value_to_f64(&arg)?;
    Ok(Value::Float(f.sin()))
}

pub fn cos(mut args: Args) -> Result<Value> {
    args.set_function_name("cos");
    let arg = args.expect("value")?;
    args.complete()?;

    let f = value_to_f64(&arg)?;
    Ok(Value::Float(f.cos()))
}

pub fn tan(mut args: Args) -> Result<Value> {
    args.set_function_name("tan");
    let arg = args.expect("value")?;
    args.complete()?;

    let f = value_to_f64(&arg)?;
    Ok(Value::Float(f.tan()))
}

pub fn abs(mut args: Args) -> Result<Value> {
    args.set_function_name("abs");
    let arg = args.expect("value")?;
    args.complete()?;

    match arg {
        Value::Int(n) => Ok(Value::Int(n.abs())),
        Value::Float(f) => Ok(Value::Float(f.abs())),
        _ => Err(anyhow!("abs() requires a number, got {:?}", arg)),
    }
}

pub fn floor(mut args: Args) -> Result<Value> {
    args.set_function_name("floor");
    let arg = args.expect("value")?;
    args.complete()?;

    match arg {
        Value::Int(n) => Ok(Value::Int(n)),
        Value::Float(f) => Ok(Value::Int(f.floor() as i64)),
        _ => Err(anyhow!("floor() requires a number, got {:?}", arg)),
    }
}

pub fn ceil(mut args: Args) -> Result<Value> {
    args.set_function_name("ceil");
    let arg = args.expect("value")?;
    args.complete()?;

    match arg {
        Value::Int(n) => Ok(Value::Int(n)),
        Value::Float(f) => Ok(Value::Int(f.ceil() as i64)),
        _ => Err(anyhow!("ceil() requires a number, got {:?}", arg)),
    }
}

pub fn round(mut args: Args) -> Result<Value> {
    args.set_function_name("round");
    let arg = args.expect("value")?;
    args.complete()?;

    match arg {
        Value::Int(n) => Ok(Value::Int(n)),
        Value::Float(f) => Ok(Value::Int(f.round() as i64)),
        _ => Err(anyhow!("round() requires a number, got {:?}", arg)),
    }
}

pub fn min(mut args: Args) -> Result<Value> {
    args.set_function_name("min");
    let first = args.expect("first")?;
    let second = args.expect("second")?;
    args.complete()?;

    match (first, second) {
        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a.min(b))),
        (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(b))),
        (Value::Int(a), Value::Float(b)) => Ok(Value::Float((a as f64).min(b))),
        (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a.min(b as f64))),
        _ => Err(anyhow!("min() requires two numbers")),
    }
}

pub fn max(mut args: Args) -> Result<Value> {
    args.set_function_name("max");
    let first = args.expect("first")?;
    let second = args.expect("second")?;
    args.complete()?;

    match (first, second) {
        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a.max(b))),
        (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(b))),
        (Value::Int(a), Value::Float(b)) => Ok(Value::Float((a as f64).max(b))),
        (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a.max(b as f64))),
        _ => Err(anyhow!("max() requires two numbers")),
    }
}

pub fn log(mut args: Args) -> Result<Value> {
    args.set_function_name("log");
    let arg = args.expect("value")?;
    args.complete()?;

    let f = value_to_f64(&arg)?;
    if f <= 0.0 {
        return Err(anyhow!("log() of non-positive number"));
    }
    Ok(Value::Float(f.ln()))
}

pub fn log10(mut args: Args) -> Result<Value> {
    args.set_function_name("log10");
    let arg = args.expect("value")?;
    args.complete()?;

    let f = value_to_f64(&arg)?;
    if f <= 0.0 {
        return Err(anyhow!("log10() of non-positive number"));
    }
    Ok(Value::Float(f.log10()))
}

pub fn exp(mut args: Args) -> Result<Value> {
    args.set_function_name("exp");
    let arg = args.expect("value")?;
    args.complete()?;

    let f = value_to_f64(&arg)?;
    Ok(Value::Float(f.exp()))
}

pub fn register_math(evaluator: &mut Evaluator) {
    evaluator.register_builtin_fn("sqrt", sqrt);
    evaluator.register_builtin_fn("sin", sin);
    evaluator.register_builtin_fn("cos", cos);
    evaluator.register_builtin_fn("tan", tan);
    evaluator.register_builtin_fn("abs", abs);
    evaluator.register_builtin_fn("floor", floor);
    evaluator.register_builtin_fn("ceil", ceil);
    evaluator.register_builtin_fn("round", round);
    evaluator.register_builtin_fn("min", min);
    evaluator.register_builtin_fn("max", max);
    evaluator.register_builtin_fn("log", log);
    evaluator.register_builtin_fn("log10", log10);
    evaluator.register_builtin_fn("exp", exp);
}