Lines
89.19 %
Functions
55.56 %
Branches
100 %
//! Shared helpers for the categorized `codegen::*` integration tests.
//!
//! Every codegen test follows the same pattern: compile a script via
//! the public `Compiler`, validate the emitted wasm with `wasmparser`,
//! and use real production patterns (host-fn calls inside a `let*`) to
//! introduce runtime-typed locals. The legacy approach of injecting
//! `Symbol::new(...).with_value(Expr::WasmRuntime(_))` into the symbol
//! table is gone — it bypassed the binder-promotion contract that
//! `compile_for_stack(WasmRuntime)` now refuses.
#![allow(dead_code)]
use nomiscript::{Compiler, Reader, SymbolTable};
use wasmparser::{Validator, WasmFeatures};
/// Validate emitted wasm under the GC + function-references feature
/// set the compiler targets. Catches missing-operand bugs, malformed
/// type sections, and ref.cast errors that the legacy "is the magic
/// header correct" check missed.
pub fn validate_wasm(wasm: &[u8]) {
let features = WasmFeatures::default()
| WasmFeatures::GC
| WasmFeatures::REFERENCE_TYPES
| WasmFeatures::FUNCTION_REFERENCES
| WasmFeatures::EXCEPTIONS;
Validator::new_with_features(features)
.validate_all(wasm)
.expect("wasm validation failed");
}
/// Compile a script in the wasm-builtins symbol table and assert the
/// result validates. Returns the bytes for callers that want to inspect
/// them further.
pub fn compile_and_validate(src: &str) -> Vec<u8> {
let program = Reader::parse(src).unwrap_or_else(|e| panic!("parse {src:?}: {e}"));
let mut symbols = SymbolTable::with_builtins_for_wasm();
let mut compiler = Compiler::new();
let wasm = compiler
.compile(&program, &mut symbols)
.unwrap_or_else(|e| panic!("compile {src:?}: {e}"));
validate_wasm(&wasm);
wasm
/// Compile a script and expect a compile error. Returns the error
/// message for callers that want to assert on its contents.
pub fn compile_expect_error(src: &str) -> String {
match compiler.compile(&program, &mut symbols) {
Ok(_) => panic!("expected compile error for {src:?}"),
Err(e) => e.to_string(),
/// Wraps a script body in a `let*` that introduces a runtime-typed
/// `X` of `WasmType::Ratio` via the entity accessor host fn. Use this
/// when a test wants to exercise the runtime-arithmetic / runtime-
/// control-flow codegen path: any `X` inside the body resolves to a
/// real `WasmLocal(idx, Ratio)` and the wasm has a producer for it.
pub fn wrap_with_runtime_ratio(body: &str) -> String {
format!("(let* ((X (transaction-post-date 0))) {body})")
/// Same as [`wrap_with_runtime_ratio`] but binds `IDX` to a runtime
/// `WasmType::I32`. Uses `(entity-count)` as the producer. The name
/// `IDX` matches the entity-accessor host fn convention (`(entity-type
/// IDX)` etc.) so test bodies read naturally.
pub fn wrap_with_runtime_i32(body: &str) -> String {
format!("(let* ((IDX (entity-count))) {body})")
/// Combines [`wrap_with_runtime_ratio`] for a value `X` and
/// [`wrap_with_runtime_i32`] for a value `IDX`. Useful when a test
/// needs both a runtime ratio and a runtime entity index in scope.
pub fn wrap_with_runtime_ratio_and_idx(body: &str) -> String {
format!("(let* ((X (transaction-post-date 0)) (IDX (entity-count))) {body})")