harn-vm 0.10.116

Async bytecode virtual machine for the Harn programming language
Documentation
use crate::stdlib::macros::{harn_builtin, VmBuiltinDef};
use crate::value::{VmError, VmValue};
use crate::vm::Vm;

use super::require_args;

fn primitive_schema(type_name: &str) -> VmValue {
    VmValue::dict([("type", VmValue::string(type_name))])
}

#[harn_builtin(exposure = "stdlib_internal", effects = [], sig = "__schema_any_witness() -> Schema<unknown>", category = "json")]
fn schema_any_impl(_args: &[VmValue], _out: &mut String) -> Result<VmValue, VmError> {
    Ok(primitive_schema("any"))
}

#[harn_builtin(exposure = "stdlib_internal", effects = [], sig = "__schema_string_witness() -> Schema<string>", category = "json")]
fn schema_string_impl(_args: &[VmValue], _out: &mut String) -> Result<VmValue, VmError> {
    Ok(primitive_schema("string"))
}

#[harn_builtin(exposure = "stdlib_internal", effects = [], sig = "__schema_int_witness() -> Schema<int>", category = "json")]
fn schema_int_impl(_args: &[VmValue], _out: &mut String) -> Result<VmValue, VmError> {
    Ok(primitive_schema("int"))
}

#[harn_builtin(exposure = "stdlib_internal", effects = [], sig = "__schema_float_witness() -> Schema<float>", category = "json")]
fn schema_float_impl(_args: &[VmValue], _out: &mut String) -> Result<VmValue, VmError> {
    Ok(primitive_schema("float"))
}

#[harn_builtin(exposure = "stdlib_internal", effects = [], sig = "__schema_bool_witness() -> Schema<bool>", category = "json")]
fn schema_bool_impl(_args: &[VmValue], _out: &mut String) -> Result<VmValue, VmError> {
    Ok(primitive_schema("bool"))
}

#[harn_builtin(exposure = "stdlib_internal", effects = [], sig = "__schema_nil_witness() -> Schema<nil>", category = "json")]
fn schema_nil_impl(_args: &[VmValue], _out: &mut String) -> Result<VmValue, VmError> {
    Ok(primitive_schema("nil"))
}

#[harn_builtin(exposure = "stdlib_internal", effects = [], sig = "<T> __schema_literal_witness(value: T) -> Schema<T>", category = "json")]
fn schema_literal_impl(args: &[VmValue], _out: &mut String) -> Result<VmValue, VmError> {
    require_args(args, 1, "schema_literal")?;
    Ok(VmValue::dict([("const", args[0].clone())]))
}

#[harn_builtin(exposure = "stdlib_internal", effects = [], sig = "<T> __schema_refine_witness(schema: Schema<T>, constraint: dict) -> Schema<T>", category = "json")]
fn schema_refine_impl(args: &[VmValue], _out: &mut String) -> Result<VmValue, VmError> {
    require_args(args, 2, "schema_refine")?;
    Ok(VmValue::dict([(
        "all_of",
        VmValue::List(std::sync::Arc::new(vec![args[0].clone(), args[1].clone()])),
    )]))
}

const BUILTINS: &[&VmBuiltinDef] = &[
    &SCHEMA_ANY_IMPL_DEF,
    &SCHEMA_STRING_IMPL_DEF,
    &SCHEMA_INT_IMPL_DEF,
    &SCHEMA_FLOAT_IMPL_DEF,
    &SCHEMA_BOOL_IMPL_DEF,
    &SCHEMA_NIL_IMPL_DEF,
    &SCHEMA_LITERAL_IMPL_DEF,
    &SCHEMA_REFINE_IMPL_DEF,
];

pub(super) fn register_builtins(vm: &mut Vm) {
    for def in BUILTINS {
        vm.register_builtin_def(def);
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn stdlib_internal_requires_embedded_stdlib_authority() {
        let mut vm = crate::Vm::new();
        crate::register_vm_stdlib(&mut vm);
        let contract = harn_builtin_registry::builtin_entry("__schema_any_witness")
            .expect("schema witness must be projected into the compiler manifest");
        assert_eq!(
            contract.contract.exposure,
            harn_builtin_meta::BuiltinExposure::StdlibInternal
        );
        let source = "let witness = __schema_any_witness()";
        let program = harn_parser::check_source_strict(source).expect("type-clean program");

        let err = crate::Compiler::new()
            .compile(&program)
            .expect_err("ordinary source must not call stdlib internals");
        assert!(
            err.message.contains("call the public stdlib function"),
            "unexpected diagnostic: {}",
            err.message
        );

        crate::Compiler::new_embedded_stdlib()
            .compile(&program)
            .expect("embedded stdlib may call its private primitive");
    }
}