Lines
98.28 %
Functions
91.67 %
Branches
100 %
//! `(error 'code "message")` special form. Validates the compile-side
//! surface: arity rejection, type rejection (non-symbol code arg), and
//! that the eval-mode module still declares the `__nomi_raise` import.
//!
//! Since Tier 3 (ADR-0026) `(error)` lowers to a native `throw
//! $nomi_error`, not a direct `call __nomi_raise`. The import is still
//! present because the compiler-emitted boundary `try_table` around the
//! body bridges an uncaught throw to `__nomi_raise` — so the
//! import-presence assertion still holds, now via the boundary handler.
//! Runtime classification is covered by the rpc-side raise unit tests +
//! integration tests.
use nomiscript::{Compiler, Program, Reader, SymbolTable};
use wasmparser::{Validator, WasmFeatures};
fn validate(wasm: &[u8]) {
let f = WasmFeatures::default()
| WasmFeatures::GC
| WasmFeatures::REFERENCE_TYPES
| WasmFeatures::FUNCTION_REFERENCES
| WasmFeatures::EXCEPTIONS;
Validator::new_with_features(f)
.validate_all(wasm)
.expect("wasm validation failed");
}
fn compile_eval(src: &str) -> Vec<u8> {
let program: Program = Reader::parse(src).expect("parse");
let mut compiler = Compiler::with_host_fns(Vec::new());
let mut symbols = SymbolTable::with_builtins();
let (bytes, _ty) = compiler
.compile_eval_with_type(&program, &mut symbols)
.unwrap_or_else(|e| panic!("compile {src:?}: {e}"));
validate(&bytes);
bytes
fn compile_expect_error(src: &str) -> String {
match compiler.compile_eval_with_type(&program, &mut symbols) {
Ok(_) => panic!("expected compile error for {src:?}"),
Err(e) => e.to_string(),
fn module_imports_nomi_raise(wasm: &[u8]) -> bool {
// Wasm import-section names are stored as raw byte strings — both
// module ("nomi") and field ("__nomi_raise") appear verbatim in
// the binary, so a substring scan is enough to confirm the import
// was emitted without coupling to wasmparser's import-iter shape.
wasm.windows(b"__nomi_raise".len())
.any(|w| w == b"__nomi_raise")
#[test]
fn error_form_module_declares_nomi_raise_boundary_import() {
let wasm = compile_eval(r#"(error 'no-such-account "id=42")"#);
assert!(
module_imports_nomi_raise(&wasm),
"module must declare a `nomi.__nomi_raise` import (the boundary bridge)"
);
fn error_form_zero_args_is_arity_error() {
let err = compile_expect_error("(error)");
assert!(err.contains("Arity") || err.contains("error"), "got: {err}");
fn error_form_one_arg_is_arity_error() {
let err = compile_expect_error("(error 'just-code)");
fn error_form_three_args_is_arity_error() {
let err = compile_expect_error(r#"(error 'a "b" "c")"#);
fn error_form_unquoted_first_arg_is_type_error() {
let err = compile_expect_error(r#"(error "string-not-symbol" "msg")"#);
err.contains("Type") || err.contains("quoted symbol"),
"got: {err}"
fn error_form_runtime_message_arg_compiles() {
// Message can be any StringRef-typed expression — most often a
// literal, but a let-bound runtime string must work too.
let wasm = compile_eval(r#"(let* ((m "boom")) (error 'oops m))"#);
assert!(module_imports_nomi_raise(&wasm));