airlang 0.28.0

Air is a universal, reliable, and lean programming language.
Documentation
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::fact::Fact;
use crate::semantics::func::CtxFreeFunc;
use crate::semantics::func::DefaultFunc;
use crate::semantics::val::PrimFuncVal;
use crate::semantics::val::Val;
use crate::type_::Key;
use crate::type_::Map;
use crate::type_::Pair;

#[derive(Copy, Clone)]
pub struct FactLib {
    pub make: PrimFuncVal,
    pub get_function: PrimFuncVal,
    pub get_input: PrimFuncVal,
    pub get_output: PrimFuncVal,
}

const FACT: &str = "fact";

pub const MAKE: &str = concatcp!(PREFIX_CELL, FACT, ".make");
pub const GET_FUNCTION: &str = concatcp!(PREFIX_CELL, FACT, ".get_function");
pub const GET_INPUT: &str = concatcp!(PREFIX_CELL, FACT, ".get_input");
pub const GET_OUTPUT: &str = concatcp!(PREFIX_CELL, FACT, ".get_output");

impl Default for FactLib {
    fn default() -> Self {
        Self {
            make: DefaultFunc { fn_: make }.build(),
            get_function: CtxFreeFunc { fn_: get_function }.build(),
            get_input: CtxFreeFunc { fn_: get_input }.build(),
            get_output: CtxFreeFunc { fn_: get_output }.build(),
        }
    }
}

impl CfgMod for FactLib {
    fn export(self, cfg: &mut Map<Key, Val>) {
        export_func(cfg, MAKE, self.make);
        export_func(cfg, GET_FUNCTION, self.get_function);
        export_func(cfg, GET_INPUT, self.get_input);
        export_func(cfg, GET_OUTPUT, self.get_output);
    }
}

fn make(cfg: &mut Cfg, ctx: Ctx<Val>, input: Val) -> Val {
    let Val::Pair(pair) = input else {
        return bug!(cfg, "{MAKE}: expected input to be a pair, but got {input}");
    };
    let pair = Pair::from(pair);
    let Val::Func(func) = pair.left else {
        return bug!(cfg, "{MAKE}: expected input.left to be a function, but got {}", pair.left);
    };
    let fact = Fact::new(cfg, ctx, func, pair.right);
    if cfg.is_aborted() {
        return Val::default();
    }
    Val::Fact(fact.into())
}

fn get_function(cfg: &mut Cfg, input: Val) -> Val {
    let Val::Fact(fact) = input else {
        return bug!(cfg, "{GET_FUNCTION}: expected input to be a fact, but got {input}");
    };
    Val::Func(fact.func().clone())
}

fn get_input(cfg: &mut Cfg, input: Val) -> Val {
    let Val::Fact(fact) = input else {
        return bug!(cfg, "{GET_INPUT}: expected input to be a fact, but got {input}");
    };
    fact.input().clone()
}

fn get_output(cfg: &mut Cfg, input: Val) -> Val {
    let Val::Fact(fact) = input else {
        return bug!(cfg, "{GET_OUTPUT}: expected input to be a fact, but got {input}");
    };
    fact.output().clone()
}