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
}
#[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)
}
}