airlang 0.28.0

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

use const_format::concatcp;

use crate::bug;
use crate::cfg::CfgMod;
use crate::cfg::export_func;
use crate::semantics::cfg::Cfg;
use crate::semantics::core::PREFIX_CELL;
use crate::semantics::ctx::Ctx;
use crate::semantics::func::CtxFreeFunc;
use crate::semantics::func::DynFunc;
use crate::semantics::val::LINK;
use crate::semantics::val::LinkVal;
use crate::semantics::val::PrimFuncVal;
use crate::semantics::val::Val;
use crate::type_::Bit;
use crate::type_::Key;
use crate::type_::Map;
use crate::type_::Pair;

// todo design
#[derive(Copy, Clone)]
pub struct LinkLib {
    pub make: PrimFuncVal,
    pub make_constant: PrimFuncVal,
    pub is_constant: PrimFuncVal,
    pub is_available: PrimFuncVal,
    pub get_id: PrimFuncVal,
    pub let_: PrimFuncVal,
}

pub const MAKE: &str = concatcp!(PREFIX_CELL, LINK, ".make");
pub const MAKE_CONSTANT: &str = concatcp!(PREFIX_CELL, LINK, ".make_constant");
pub const IS_CONSTANT: &str = concatcp!(PREFIX_CELL, LINK, ".is_constant");
pub const IS_AVAILABLE: &str = concatcp!(PREFIX_CELL, LINK, ".is_available");
pub const GET_ID: &str = concatcp!(PREFIX_CELL, LINK, ".get_id");
pub const LET: &str = concatcp!(PREFIX_CELL, LINK, ".let");

impl Default for LinkLib {
    fn default() -> Self {
        Self {
            make: CtxFreeFunc { fn_: make }.build(),
            make_constant: CtxFreeFunc { fn_: make_constant }.build(),
            is_constant: CtxFreeFunc { fn_: is_constant }.build(),
            is_available: CtxFreeFunc { fn_: is_available }.build(),
            get_id: CtxFreeFunc { fn_: get_id }.build(),
            let_: CtxFreeFunc { fn_: let_ }.build(),
        }
    }
}

impl CfgMod for LinkLib {
    fn export(self, cfg: &mut Map<Key, Val>) {
        export_func(cfg, MAKE, self.make);
        export_func(cfg, MAKE_CONSTANT, self.make_constant);
        export_func(cfg, IS_CONSTANT, self.is_constant);
        export_func(cfg, IS_AVAILABLE, self.is_available);
        export_func(cfg, GET_ID, self.get_id);
        export_func(cfg, LET, self.let_);
    }
}

pub fn make(_cfg: &mut Cfg, input: Val) -> Val {
    Val::Link(LinkVal::new(input, false))
}

pub fn make_constant(_cfg: &mut Cfg, input: Val) -> Val {
    Val::Link(LinkVal::new(input, true))
}

pub fn is_constant(cfg: &mut Cfg, input: Val) -> Val {
    let Val::Link(link) = input else {
        return bug!(cfg, "{IS_CONSTANT}: expected input to be a link, but got {input}");
    };
    Val::Bit(Bit::from(link.is_const()))
}

pub fn is_available(cfg: &mut Cfg, input: Val) -> Val {
    let Val::Link(link) = input else {
        return bug!(cfg, "{IS_AVAILABLE}: expected input to be a link, but got {input}");
    };
    let available = link.try_borrow().is_ok();
    Val::Bit(Bit::from(available))
}

pub fn get_id(cfg: &mut Cfg, input: Val) -> Val {
    let Val::Link(link) = input else {
        return bug!(cfg, "{GET_ID}: expected input to be a link, but got {input}");
    };
    let id = link.ptr_addr();
    let id = Key::from_string_unchecked(format!("{id:x}"));
    Val::Key(id)
}

pub fn let_(cfg: &mut Cfg, input: Val) -> Val {
    let Val::Pair(pair) = input else {
        return bug!(cfg, "{LET}: expected input to be a pair, but got {input}");
    };
    let pair = Pair::from(pair);
    let Val::Link(link) = pair.left else {
        return bug!(cfg, "{LET}: expected input.left to be a link, but got {}", pair.left);
    };
    let Val::Pair(func_input) = pair.right else {
        return bug!(cfg, "{LET}: expected input.right to be a pair, but got {}", pair.right);
    };
    let func_input = Pair::from(func_input);
    let Val::Func(func) = func_input.left else {
        return bug!(cfg, "{LET}: expected input.right.left to be a function, \
            but got {}", func_input.left);
    };
    let Ok(mut ctx) = link.try_borrow_mut() else {
        return bug!(cfg, "{LET}: link is not available");
    };
    let ctx = Ctx { val: ctx.deref_mut(), const_: link.is_const() };
    func.call(cfg, ctx, func_input.right)
}