sim-nest 0.1.5

The SIM constellation umbrella facade: one crate that re-exports the runtime kernel, codecs, number domains, and libraries behind features.
Documentation
use std::sync::Arc;

use sim_kernel::{Cx, FunctionId, Linker, LoadCx, Result, Symbol};
use sim_shape::AnyShape;

use crate::{
    classes::NativeClass,
    functions::FunctionObject,
    macros::macroexpand_function,
    runtime::{
        eval_policy::WithEvalPolicyFunction,
        lambda::LambdaBuilder,
        lists::{
            car_function, cdr_function, cons_function, drop_function, empty_list_function,
            head_function, len_cmp_function, len_eq_function, len_gt_function, len_gte_function,
            len_lt_function, len_lte_function, list_function, list_impl_function, nth_function,
            tail_function, take_function,
        },
        realize::{LocalEvalFabricObject, RealizeFunction},
        shape_ops::{
            shape_class_symbols, shape_helper_function, shape_helper_symbol_names,
            shape_runtime_class,
        },
        tables::len_function,
    },
    shapes::CORE_SHAPE_CLASS,
};

use super::register_browse::register_core_browse_functions;
use super::register_tables::register_core_table_functions;

pub(super) trait CoreBuildCx {
    fn factory(&self) -> &dyn sim_kernel::Factory;
    fn fresh_function_id(&mut self) -> FunctionId;
    fn fresh_case_id(&mut self) -> sim_kernel::CaseId;
}

impl CoreBuildCx for Cx {
    fn factory(&self) -> &dyn sim_kernel::Factory {
        self.factory()
    }

    fn fresh_function_id(&mut self) -> FunctionId {
        self.registry_mut().fresh_function_id()
    }

    fn fresh_case_id(&mut self) -> sim_kernel::CaseId {
        self.registry_mut().fresh_case_id()
    }
}

impl CoreBuildCx for LoadCx {
    fn factory(&self) -> &dyn sim_kernel::Factory {
        self.factory()
    }

    fn fresh_function_id(&mut self) -> FunctionId {
        self.fresh_function_id()
    }

    fn fresh_case_id(&mut self) -> sim_kernel::CaseId {
        self.fresh_case_id()
    }
}

pub(super) fn register_core_classes(
    cx: &mut impl CoreBuildCx,
    linker: &mut Linker<'_>,
) -> Result<()> {
    for (symbol, class_id) in [
        (
            Symbol::qualified("core", "Class"),
            sim_kernel::CORE_CLASS_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Function"),
            sim_kernel::CORE_FUNCTION_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Macro"),
            sim_kernel::CORE_MACRO_CLASS_ID,
        ),
        (
            Symbol::qualified("core", CORE_SHAPE_CLASS),
            sim_kernel::CORE_SHAPE_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "ShapeMatch"),
            sim_kernel::CORE_SHAPE_MATCH_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Codec"),
            sim_kernel::CORE_CODEC_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Help"),
            sim_kernel::CORE_HELP_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Test"),
            sim_kernel::CORE_TEST_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "NumberDomain"),
            sim_kernel::CORE_NUMBER_DOMAIN_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Nil"),
            sim_kernel::CORE_NIL_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Bool"),
            sim_kernel::CORE_BOOL_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Number"),
            sim_kernel::CORE_NUMBER_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Symbol"),
            sim_kernel::CORE_SYMBOL_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "String"),
            sim_kernel::CORE_STRING_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Bytes"),
            sim_kernel::CORE_BYTES_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "List"),
            sim_kernel::CORE_LIST_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Table"),
            sim_kernel::CORE_TABLE_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Expr"),
            sim_kernel::CORE_EXPR_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Thunk"),
            sim_kernel::CORE_THUNK_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "EvalRequest"),
            sim_kernel::CORE_EVAL_REQUEST_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "EvalReply"),
            sim_kernel::CORE_EVAL_REPLY_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "LocalEvalFabric"),
            sim_kernel::CORE_LOCAL_EVAL_FABRIC_CLASS_ID,
        ),
        (
            Symbol::qualified("core", "Card"),
            sim_kernel::CORE_CARD_CLASS_ID,
        ),
    ] {
        let class_id = linker.class_with_id(symbol.clone(), class_id)?;
        let constructor_id = cx.fresh_function_id();
        let class = empty_class(class_id, constructor_id, symbol);
        let value = cx.factory().opaque(Arc::new(class))?;
        linker.bind_class_value(class_id, value)?;
    }
    for symbol in shape_class_symbols() {
        let class_id = linker.class(symbol.clone())?;
        let class = shape_runtime_class(
            class_id,
            cx.fresh_function_id(),
            cx.fresh_case_id(),
            symbol.name.as_ref(),
        );
        let value = cx.factory().opaque(Arc::new(class))?;
        linker.bind_class_value(class_id, value)?;
    }
    Ok(())
}

pub(super) fn register_core_functions(
    cx: &mut impl CoreBuildCx,
    linker: &mut Linker<'_>,
) -> Result<()> {
    link_function(
        cx,
        linker,
        Symbol::qualified("core", "macroexpand"),
        macroexpand_function,
    )?;
    link_function(cx, linker, Symbol::new("macroexpand"), macroexpand_function)?;
    link_callable_value(
        cx,
        linker,
        Symbol::qualified("core", "lambda"),
        Arc::new(LambdaBuilder),
    )?;
    link_callable_value(cx, linker, Symbol::new("lambda"), Arc::new(LambdaBuilder))?;
    link_callable_value(
        cx,
        linker,
        Symbol::qualified("core", "with-eval-policy"),
        Arc::new(WithEvalPolicyFunction),
    )?;
    link_callable_value(
        cx,
        linker,
        Symbol::new("with-eval-policy"),
        Arc::new(WithEvalPolicyFunction),
    )?;
    register_core_browse_functions(cx, linker)?;
    for (namespace, name) in shape_helper_symbol_names() {
        let function_id = linker.function(Symbol::qualified(namespace, name))?;
        let function = shape_helper_function(function_id, cx.fresh_case_id(), namespace, name);
        let value = cx.factory().opaque(Arc::new(function))?;
        linker.bind_function_value(function_id, value)?;
    }
    link_function(cx, linker, Symbol::qualified("core", "list"), list_function)?;
    link_function(cx, linker, Symbol::new("list"), list_function)?;
    link_function(cx, linker, Symbol::qualified("core", "cons"), cons_function)?;
    link_function(cx, linker, Symbol::new("cons"), cons_function)?;
    link_function(cx, linker, Symbol::qualified("core", "car"), car_function)?;
    link_function(cx, linker, Symbol::new("car"), car_function)?;
    link_function(cx, linker, Symbol::qualified("core", "cdr"), cdr_function)?;
    link_function(cx, linker, Symbol::new("cdr"), cdr_function)?;
    link_function(cx, linker, Symbol::qualified("core", "head"), head_function)?;
    link_function(cx, linker, Symbol::new("head"), head_function)?;
    link_function(cx, linker, Symbol::qualified("core", "tail"), tail_function)?;
    link_function(cx, linker, Symbol::new("tail"), tail_function)?;
    link_function(
        cx,
        linker,
        Symbol::qualified("core", "empty?"),
        empty_list_function,
    )?;
    link_function(cx, linker, Symbol::new("empty?"), empty_list_function)?;
    link_function(cx, linker, Symbol::qualified("core", "len"), len_function)?;
    link_function(cx, linker, Symbol::new("len"), len_function)?;
    link_function(
        cx,
        linker,
        Symbol::qualified("core", "len-cmp"),
        len_cmp_function,
    )?;
    link_function(cx, linker, Symbol::new("len-cmp"), len_cmp_function)?;
    link_function(
        cx,
        linker,
        Symbol::qualified("core", "len<"),
        len_lt_function,
    )?;
    link_function(cx, linker, Symbol::new("len<"), len_lt_function)?;
    link_function(
        cx,
        linker,
        Symbol::qualified("core", "len<="),
        len_lte_function,
    )?;
    link_function(cx, linker, Symbol::new("len<="), len_lte_function)?;
    link_function(
        cx,
        linker,
        Symbol::qualified("core", "len="),
        len_eq_function,
    )?;
    link_function(cx, linker, Symbol::new("len="), len_eq_function)?;
    link_function(
        cx,
        linker,
        Symbol::qualified("core", "len>="),
        len_gte_function,
    )?;
    link_function(cx, linker, Symbol::new("len>="), len_gte_function)?;
    link_function(
        cx,
        linker,
        Symbol::qualified("core", "len>"),
        len_gt_function,
    )?;
    link_function(cx, linker, Symbol::new("len>"), len_gt_function)?;
    link_function(cx, linker, Symbol::qualified("core", "nth"), nth_function)?;
    link_function(cx, linker, Symbol::new("nth"), nth_function)?;
    link_function(cx, linker, Symbol::qualified("core", "take"), take_function)?;
    link_function(cx, linker, Symbol::new("take"), take_function)?;
    link_function(cx, linker, Symbol::qualified("core", "drop"), drop_function)?;
    link_function(cx, linker, Symbol::new("drop"), drop_function)?;
    link_list_impl_function(cx, linker, Symbol::qualified("core", "list-impl"))?;
    link_list_impl_function(cx, linker, Symbol::new("list-impl"))?;
    register_core_table_functions(cx, linker)?;
    link_callable_value(
        cx,
        linker,
        Symbol::qualified("core", "realize"),
        Arc::new(RealizeFunction),
    )?;
    link_callable_value(
        cx,
        linker,
        Symbol::new("realize"),
        Arc::new(RealizeFunction),
    )?;
    Ok(())
}

pub(super) fn register_core_values(
    cx: &mut impl CoreBuildCx,
    linker: &mut Linker<'_>,
) -> Result<()> {
    linker.value(
        Symbol::qualified("core", "local-fabric"),
        cx.factory().opaque(Arc::new(LocalEvalFabricObject))?,
    )?;
    Ok(())
}

pub(super) fn link_function(
    cx: &mut impl CoreBuildCx,
    linker: &mut Linker<'_>,
    symbol: Symbol,
    build: fn(sim_kernel::CaseId, FunctionId, Symbol) -> FunctionObject,
) -> Result<()> {
    let function_id = linker.function(symbol.clone())?;
    let function = build(cx.fresh_case_id(), function_id, symbol);
    let function_value = cx.factory().opaque(Arc::new(function))?;
    linker.bind_function_value(function_id, function_value)?;
    Ok(())
}

pub(super) fn link_two_case_function(
    cx: &mut impl CoreBuildCx,
    linker: &mut Linker<'_>,
    symbol: Symbol,
    build: fn(sim_kernel::CaseId, sim_kernel::CaseId, FunctionId, Symbol) -> FunctionObject,
) -> Result<()> {
    let function_id = linker.function(symbol.clone())?;
    let function = build(cx.fresh_case_id(), cx.fresh_case_id(), function_id, symbol);
    let function_value = cx.factory().opaque(Arc::new(function))?;
    linker.bind_function_value(function_id, function_value)?;
    Ok(())
}

fn link_callable_value(
    cx: &mut impl CoreBuildCx,
    linker: &mut Linker<'_>,
    symbol: Symbol,
    value: Arc<dyn sim_kernel::RuntimeObject>,
) -> Result<()> {
    let function_id = linker.function(symbol)?;
    let value = cx.factory().opaque(value)?;
    linker.bind_function_value(function_id, value)?;
    Ok(())
}

fn link_list_impl_function(
    cx: &mut impl CoreBuildCx,
    linker: &mut Linker<'_>,
    symbol: Symbol,
) -> Result<()> {
    let function_id = linker.function(symbol.clone())?;
    let function = list_impl_function(cx.fresh_case_id(), cx.fresh_case_id(), function_id, symbol);
    let function_value = cx.factory().opaque(Arc::new(function))?;
    linker.bind_function_value(function_id, function_value)?;
    Ok(())
}

fn empty_function(id: FunctionId, symbol: Symbol) -> FunctionObject {
    FunctionObject::new(id, symbol, Vec::new())
}

fn empty_class(
    class_id: sim_kernel::ClassId,
    function_id: FunctionId,
    symbol: Symbol,
) -> NativeClass {
    NativeClass::new(
        class_id,
        symbol.clone(),
        empty_function(function_id, symbol),
        Some(Arc::new(AnyShape)),
        Vec::new(),
    )
    .with_read_constructor(None)
}