euph 0.1.1

A functional stack-based programming language
use std::ops::{
    Add,
    Div,
    Mul,
    Rem,
    Sub,
};

use num_traits::Pow;
use ordered_float::{
    FloatCore,
    OrderedFloat,
};

use crate::{
    fns::EuDef,
    types::EuType,
};

#[crabtime::function]
fn gen_fn_int_consts() {
    let types = ["I32", "I64"];
    let consts = ["MIN", "MAX"];
    for t in types {
        let n = t.to_lowercase();
        for c in consts {
            crabtime::output! {
                pub const {{c}}_{{t}}: EuDef = |env| {
                    env.push(EuType::{{t}}({{n}}::{{c}}));
                    Ok(())
                };
            };
        }
    }
}

gen_fn_int_consts!();

#[crabtime::function]
fn gen_fn_float_consts() {
    let types = ["F64"];
    let consts = [("MIN", "min_value"), ("MAX", "max_value")];
    for t in types {
        for (c, f) in consts {
            crabtime::output! {
                pub const {{c}}_{{t}}: EuDef = |env| {
                    env.push(EuType::{{t}}(OrderedFloat::{{f}}()));
                    Ok(())
                };
            };
        }
    }
}

gen_fn_float_consts!();

pub const INF: EuDef = |env| {
    env.push(EuType::F64(OrderedFloat::infinity()));
    Ok(())
};

pub const NAN: EuDef = |env| {
    env.push(EuType::F64(OrderedFloat::nan()));
    Ok(())
};

#[crabtime::function]
fn gen_def_to_num() {
    let types = ["I32", "I64", "F64", "IBig"];
    for &t in &types {
        let n = t.to_lowercase();
        let n_up = t.to_uppercase();
        crabtime::output! {
            pub const TO_{{n_up}}: EuDef = |env| {
                let a0 = env.pop()?;
                env.push(EuType::opt(a0.to_{{n}}().map(EuType::{{n}})));
                Ok(())
            };
        }
    }
}

gen_def_to_num!();
pub const NEG: EuDef = |env| {
    let a0 = env.pop()?;
    env.push((-a0)?);
    Ok(())
};

#[crabtime::function]
fn gen_fn_math_binops() {
    for name in ["ADD", "SUB", "MUL", "DIV", "REM", "POW"] {
        let op = name.to_lowercase();
        crabtime::output! {
            pub const {{name}}: EuDef = |env| {
                env.check_nargs(2)?;
                let a1 = env.stack.pop().unwrap();
                let a0 = env.stack.pop().unwrap();
                env.push(a0.{{op}}(a1)?);
                Ok(())
            };
        }
    }
}

gen_fn_math_binops!();