blr-lang 0.1.0

A language implementation that provides type safe dataframes
Documentation
use super::{Expr, ItemId, NodeId, Symbol, Var};

pub fn make_vars<const N: usize>() -> [Var; N] {
    let mut vars = [Var(0); N];
    for (i, var) in vars.iter_mut().enumerate() {
        *var = Var(i);
    }
    vars
}

/// ExprBuilder should only be used for testing.
/// It is not thread safe, and just offers convenience for constructing ASTs by hand.
#[derive(Default)]
pub struct ExprBuilder {
    node_id: std::cell::Cell<u32>,
}

impl ExprBuilder {
    fn next_id(&self) -> NodeId {
        let id = self.node_id.get();
        self.node_id.set(id + 1);
        NodeId(id)
    }

    pub fn var<V>(&self, var: V) -> Expr<V> {
        Expr::Variable(self.next_id(), var)
    }

    pub fn int<V>(&self, i: i64) -> Expr<V> {
        Expr::Integer(self.next_id(), i)
    }

    pub fn float<V>(&self, f: f64) -> Expr<V> {
        Expr::Float(self.next_id(), f)
    }

    pub fn make_funs<const N: usize>(&self, body: impl FnOnce([Var; N]) -> Expr<Var>) -> Expr<Var> {
        let vars = make_vars();
        let body = body(vars);
        self.funs(vars, body)
    }

    pub fn funs<V, Vars>(&self, vars: Vars, body: Expr<V>) -> Expr<V>
    where
        Vars: IntoIterator<Item = V>,
        Vars::IntoIter: DoubleEndedIterator,
    {
        vars.into_iter().rfold(body, |body, var| {
            Expr::abstraction(self.next_id(), var, body)
        })
    }

    pub fn fun<V>(&self, var: V, body: Expr<V>) -> Expr<V> {
        self.funs([var], body)
    }

    pub fn apps<V>(&self, head: Expr<V>, params: impl IntoIterator<Item = Expr<V>>) -> Expr<V> {
        params.into_iter().fold(head, |head, param| {
            Expr::application(self.next_id(), head, param)
        })
    }

    pub fn app<V>(&self, fun: Expr<V>, param: Expr<V>) -> Expr<V> {
        self.apps(fun, [param])
    }

    pub fn locals<V, Binds>(&self, binds: Binds, body: Expr<V>) -> Expr<V>
    where
        Binds: IntoIterator<Item = (V, Expr<V>)>,
        Binds::IntoIter: DoubleEndedIterator,
    {
        binds.into_iter().rfold(body, |body, (var, defn)| {
            Expr::application(
                self.next_id(),
                Expr::abstraction(self.next_id(), var, body),
                defn,
            )
        })
    }

    pub fn label<V>(&self, label: impl ToString, value: Expr<V>) -> Expr<V> {
        Expr::label(self.next_id(), label, value)
    }
    pub fn unlabel<V>(&self, value: Expr<V>, label: impl ToString) -> Expr<V> {
        Expr::unlabel(self.next_id(), value, label)
    }

    pub fn concatenate<V>(&self, left: Expr<V>, right: Expr<V>) -> Expr<V> {
        Expr::concatenate(self.next_id(), left, right)
    }
    pub fn concatenates<V>(
        &self,
        head: Expr<V>,
        tail: impl IntoIterator<Item = Expr<V>>,
    ) -> Expr<V> {
        tail.into_iter().fold(head, |head, tail| {
            Expr::concatenate(self.next_id(), head, tail)
        })
    }

    pub fn project<V>(&self, value: Expr<V>) -> Expr<V> {
        Expr::project(self.next_id(), value)
    }

    pub fn item<V>(&self, item: ItemId, symbol: Symbol) -> Expr<V> {
        Expr::Item(self.next_id(), item, symbol)
    }
}