airlang 0.25.0

Air is a minimalist and universal programming language.
Documentation
use const_format::concatcp;

pub use self::arbitrary::Arbitrary;

_____!();

use rand::make_rng;
use rand::rngs::SmallRng;

use crate::bug;
use crate::cfg::CfgMod;
use crate::cfg::extend_func;
use crate::semantics::cfg::Cfg;
use crate::semantics::core::PREFIX_CELL;
use crate::semantics::func::CtxConstInputFreeFunc;
use crate::semantics::func::CtxFreeInputAwareFunc;
use crate::semantics::val::BIT;
use crate::semantics::val::BYTE;
use crate::semantics::val::CALL;
use crate::semantics::val::CELL;
use crate::semantics::val::CFG;
use crate::semantics::val::DECIMAL;
use crate::semantics::val::FUNC;
use crate::semantics::val::FuncVal;
use crate::semantics::val::INT;
use crate::semantics::val::KEY;
use crate::semantics::val::LINK;
use crate::semantics::val::LIST;
use crate::semantics::val::LinkVal;
use crate::semantics::val::MAP;
use crate::semantics::val::PAIR;
use crate::semantics::val::PrimFuncVal;
use crate::semantics::val::QUOTE;
use crate::semantics::val::TEXT;
use crate::semantics::val::UNIT;
use crate::semantics::val::Val;
use crate::type_::Bit;
use crate::type_::Byte;
use crate::type_::Call;
use crate::type_::Cell;
use crate::type_::Decimal;
use crate::type_::Int;
use crate::type_::Key;
use crate::type_::List;
use crate::type_::Map;
use crate::type_::Pair;
use crate::type_::Quote;
use crate::type_::Text;
use crate::type_::Unit;

#[derive(Clone)]
pub struct ValueLib {
    /// should be overridden if there are extension types
    pub any: PrimFuncVal,
    pub get_type: PrimFuncVal,
    pub equal: PrimFuncVal,
}

const VALUE: &str = "value";

pub const ANY: &str = concatcp!(PREFIX_CELL, VALUE, ".any");
pub const GET_TYPE: &str = concatcp!(PREFIX_CELL, VALUE, ".get_type");
pub const EQUAL: &str = concatcp!(PREFIX_CELL, VALUE, ".equal");

impl Default for ValueLib {
    fn default() -> Self {
        ValueLib {
            any: CtxFreeInputAwareFunc { fn_: any }.build(),
            get_type: CtxConstInputFreeFunc { fn_: get_type }.build(),
            equal: CtxFreeInputAwareFunc { fn_: equal }.build(),
        }
    }
}

impl CfgMod for ValueLib {
    fn extend(self, cfg: &mut Cfg) {
        extend_func(cfg, ANY, self.any);
        extend_func(cfg, GET_TYPE, self.get_type);
        extend_func(cfg, EQUAL, self.equal);
    }
}

const TYPE_UNIT: &str = concatcp!(PREFIX_CELL, UNIT);
const TYPE_BIT: &str = concatcp!(PREFIX_CELL, BIT);
const TYPE_KEY: &str = concatcp!(PREFIX_CELL, KEY);
const TYPE_TEXT: &str = concatcp!(PREFIX_CELL, TEXT);
const TYPE_INT: &str = concatcp!(PREFIX_CELL, INT);
const TYPE_DECIMAL: &str = concatcp!(PREFIX_CELL, DECIMAL);
const TYPE_BYTE: &str = concatcp!(PREFIX_CELL, BYTE);
const TYPE_CELL: &str = concatcp!(PREFIX_CELL, CELL);
const TYPE_PAIR: &str = concatcp!(PREFIX_CELL, PAIR);
const TYPE_LIST: &str = concatcp!(PREFIX_CELL, LIST);
const TYPE_MAP: &str = concatcp!(PREFIX_CELL, MAP);
const TYPE_QUOTE: &str = concatcp!(PREFIX_CELL, QUOTE);
const TYPE_CALL: &str = concatcp!(PREFIX_CELL, CALL);
const TYPE_LINK: &str = concatcp!(PREFIX_CELL, LINK);
const TYPE_CFG: &str = concatcp!(PREFIX_CELL, CFG);
const TYPE_FUNC: &str = concatcp!(PREFIX_CELL, FUNC);

pub fn any(cfg: &mut Cfg, input: Val) -> Val {
    const DEPTH: usize = 0;
    let mut rng: SmallRng = make_rng();
    let rng = &mut rng;
    match input {
        Val::Unit(_) => Val::any(rng, DEPTH),
        Val::Key(s) => match &*s {
            TYPE_UNIT => Val::Unit(Unit::any(rng, DEPTH)),
            TYPE_BIT => Val::Bit(Bit::any(rng, DEPTH)),
            TYPE_KEY => Val::Key(Key::any(rng, DEPTH)),
            TYPE_TEXT => Val::Text(Text::any(rng, DEPTH).into()),
            TYPE_INT => Val::Int(Int::any(rng, DEPTH).into()),
            TYPE_DECIMAL => Val::Decimal(Decimal::any(rng, DEPTH).into()),
            TYPE_BYTE => Val::Byte(Byte::any(rng, DEPTH).into()),
            TYPE_CELL => Val::Cell(Cell::<Val>::any(rng, DEPTH).into()),
            TYPE_PAIR => Val::Pair(Pair::<Val, Val>::any(rng, DEPTH).into()),
            TYPE_LIST => Val::List(List::<Val>::any(rng, DEPTH).into()),
            TYPE_MAP => Val::Map(Map::<Key, Val>::any(rng, DEPTH).into()),
            TYPE_QUOTE => Val::Quote(Quote::<Val>::any(rng, DEPTH).into()),
            TYPE_CALL => Val::Call(Call::<Val, Val>::any(rng, DEPTH).into()),
            TYPE_LINK => Val::Link(LinkVal::any(rng, DEPTH)),
            TYPE_CFG => Val::Cfg(Cfg::any(rng, DEPTH).into()),
            TYPE_FUNC => Val::Func(FuncVal::any(rng, DEPTH)),
            s => bug!(cfg, "{ANY}: unknown type {s}"),
        },
        v => bug!(cfg, "{ANY}: expected input to be a key or a unit, but got {v}"),
    }
}

pub fn get_type(_cfg: &mut Cfg, ctx: &Val) -> Val {
    let s = match ctx {
        Val::Unit(_) => TYPE_UNIT,
        Val::Bit(_) => TYPE_BIT,
        Val::Key(_) => TYPE_KEY,
        Val::Text(_) => TYPE_TEXT,
        Val::Int(_) => TYPE_INT,
        Val::Decimal(_) => TYPE_DECIMAL,
        Val::Byte(_) => TYPE_BYTE,
        Val::Cell(_) => TYPE_CELL,
        Val::Pair(_) => TYPE_PAIR,
        Val::List(_) => TYPE_LIST,
        Val::Map(_) => TYPE_MAP,
        Val::Quote(_) => TYPE_QUOTE,
        Val::Call(_) => TYPE_CALL,
        Val::Link(_) => TYPE_LINK,
        Val::Cfg(_) => TYPE_CFG,
        Val::Func(_) => TYPE_FUNC,
        Val::Dyn(val) => return Val::Key(val.type_name()),
    };
    Val::Key(Key::from_str_unchecked(s))
}

// todo design
pub fn equal(cfg: &mut Cfg, input: Val) -> Val {
    let Val::Pair(pair) = input else {
        return bug!(cfg, "{EQUAL}: expected input to be a pair, but got {input}");
    };
    Val::Bit(Bit::from(pair.left == pair.right))
}

mod arbitrary;