airlang 0.27.0

Air is a universal, reliable, and lean programming language.
Documentation
use std::mem::take;
use std::ops::DerefMut;

use super::DynFunc;
use super::PrimCtx;
use super::PrimInput;
use crate::semantics::cfg::Cfg;
use crate::semantics::core::Eval;
use crate::semantics::ctx::Ctx;
use crate::semantics::ctx::DynCtx;
use crate::semantics::val::LinkVal;
use crate::semantics::val::Val;
use crate::type_::Key;

#[derive(Clone)]
pub struct CompFunc {
    pub(crate) prelude: Val,
    pub(crate) body: Val,
    pub(crate) ctx: CompCtx,
    pub(crate) input: CompInput,
}

#[derive(Clone)]
pub(crate) struct CompCtx {
    pub(crate) name: Key,
    pub(crate) prim: PrimCtx,
}

#[derive(Clone)]
pub(crate) struct CompInput {
    pub(crate) name: Key,
    pub(crate) prim: PrimInput,
}

impl DynFunc<Cfg, Val, Val, Val> for CompFunc {
    fn call(&self, cfg: &mut Cfg, ctx: Ctx<Val>, input: Val) -> Val {
        let mut new_ctx = self.prelude.clone();
        let new_ctx = Ctx::new_mut(&mut new_ctx);
        if matches!(self.input.prim, PrimInput::Default) {
            let set_result = new_ctx.val.set(cfg, self.input.name.clone(), input);
            if set_result.is_none() {
                return Val::default();
            }
        }
        let const_ = match self.ctx.prim {
            PrimCtx::Free => return Eval.call(cfg, new_ctx, self.body.clone()),
            PrimCtx::Const_ => true,
            PrimCtx::Mut => {
                if ctx.const_ {
                    cfg.abort();
                    return Val::default();
                }
                false
            },
            PrimCtx::Default => ctx.const_,
        };
        let ctx_link = LinkVal::new(take(ctx.val), const_);
        let output = 'output: {
            if new_ctx.val.set(cfg, self.ctx.name.clone(), Val::Link(ctx_link.clone())).is_none() {
                break 'output Val::default();
            }
            Eval.call(cfg, new_ctx, self.body.clone())
        };
        let mut ctx_updated =
            ctx_link.try_borrow_mut().expect("ctx link should not be borrowed after eval");
        *ctx.val = take(ctx_updated.deref_mut());
        output
    }
}