sim-nest 0.2.1

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

use sim::kernel::{
    CapabilitySet, Cx, DefaultFactory, EagerPolicy, Error, Expr, ReadPolicy, Symbol, TrustLevel,
    macro_expand_eval_capability, read_eval_capability,
};
use sim::lib_lang_python::{
    DynamicAdmission, DynamicPython, PYTHON_FIDELITY, PythonEvalPolicy, PythonValue,
};
use sim::shape::AnyShape;

pub fn capability_scoped_python() -> Result<(), Box<dyn std::error::Error>> {
    let (mut cx, seat) = Cx::new_seated(Arc::new(EagerPolicy), Arc::new(DefaultFactory));
    sim::runtime::install_core_runtime(&mut cx);
    let python_codec_id = cx.registry_mut().fresh_codec_id();
    cx.load_lib(&sim::codec_python::PythonCodecLib::new(python_codec_id))?;
    let dynamic = DynamicPython::default();

    let denied = dynamic.eval(
        &mut cx,
        "40 + 2",
        DynamicAdmission::new(
            ReadPolicy {
                trust: TrustLevel::Untrusted,
                capabilities: CapabilitySet::new(),
            },
            CapabilitySet::new(),
        ),
    );
    assert!(matches!(denied, Err(Error::TrustDenied { .. } | Error::CapabilityDenied { .. })));

    let read_eval = read_eval_capability();
    let expand_eval = macro_expand_eval_capability();
    seat.grant(&mut cx, read_eval.clone())?;
    seat.grant(&mut cx, expand_eval.clone())?;
    let trusted = || ReadPolicy {
        trust: TrustLevel::TrustedSource,
        capabilities: CapabilitySet::new().grant(read_eval.clone()),
    };
    let admitted = || DynamicAdmission {
        read_policy: trusted(),
        requires: vec![read_eval.clone(), expand_eval.clone()],
        allow: CapabilitySet::new().grant(expand_eval.clone()),
        expected_shape: Arc::new(AnyShape),
    };
    let evaluated = dynamic.eval(&mut cx, "40 + 2", admitted())?;
    assert!(matches!(
        evaluated.object().as_expr(&mut cx)?,
        Expr::Call { operator, .. }
            if *operator == Expr::Symbol(Symbol::qualified("python", "module"))
    ));
    let executed = dynamic.exec(&mut cx, "answer = 40 + 2\nanswer", admitted())?;
    assert!(matches!(
        executed.object().as_expr(&mut cx)?,
        Expr::Call { operator, .. }
            if *operator == Expr::Symbol(Symbol::qualified("python", "module"))
    ));

    let tree = sim::codec_python::parse_module("answer = 40 + 2\nanswer")?;
    let lowered = sim::codec_python::lower_python(&tree);
    let value = PythonEvalPolicy::new(128)?.eval_lowered(&lowered, &mut BTreeMap::new())?;
    assert_eq!(value, PythonValue::Int(42));
    assert!(PYTHON_FIDELITY.expected_gaps.iter().any(|gap| gap.contains("CPython")));
    assert!(PYTHON_FIDELITY.expected_gaps.iter().any(|gap| gap.contains("compiler")));
    Ok(())
}