Lines
76.79 %
Functions
13.33 %
Branches
100 %
//! Condition accessors for `(handler-case)` clause variables (Tier 3.3,
//! ADR-0026). `(error-code e)` and `(error-message e)` read the two
//! `$nomi_condition` fields (both `(ref $i8_array)` strings) of a caught
//! condition bound at `EntityRef(Condition)`. Mirror the typed-entity
//! accessor shape: type-check the arg, then `struct.get` the field.
use super::super::context::CompileContext;
use super::super::emit::FunctionEmitter;
use super::NativeSpec;
use crate::ast::{EntityKind, Expr, WasmType};
use crate::error::{Error, Result};
use crate::runtime::SymbolTable;
const CODE_FIELD: u32 = 0;
const MESSAGE_FIELD: u32 = 1;
fn arity_one(name: &str, args: &[Expr]) -> Result<()> {
if args.len() != 1 {
return Err(Error::Arity {
name: name.to_string(),
expected: 1,
actual: args.len(),
});
}
Ok(())
/// Shared stack emit for a condition field accessor: compile the arg
/// (must be `EntityRef(Condition)`), then `struct.get` the field. Returns
/// `StringRef`.
fn condition_field_stack(
ctx: &mut CompileContext,
emit: &mut FunctionEmitter,
symbols: &mut SymbolTable,
args: &[Expr],
name: &str,
field: u32,
) -> Result<WasmType> {
arity_one(name, args)?;
let ty = crate::compiler::expr::compile_for_stack(ctx, emit, symbols, &args[0])?;
let expected = WasmType::EntityRef(EntityKind::Condition);
if ty != expected {
return Err(Error::Type {
expected: format!("{expected} for {name}"),
actual: ty.to_string(),
// The handler-case clause var is stashed in an `anyref` local (the
// caught condition has no narrower WasmType slot), so the value on the
// stack is `anyref` even though its compile-time type is
// `EntityRef(Condition)`. Downcast to the concrete struct before reading.
let condition_idx = ctx.ids.ty_nomi_condition;
emit.ref_cast(condition_idx);
emit.struct_get(condition_idx, field);
Ok(WasmType::StringRef)
fn error_code_eval(_symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
arity_one("ERROR-CODE", args)?;
Ok(Expr::WasmRuntime(WasmType::StringRef))
fn error_code_stack(
condition_field_stack(ctx, emit, symbols, args, "ERROR-CODE", CODE_FIELD)
fn error_message_eval(_symbols: &mut SymbolTable, args: &[Expr]) -> Result<Expr> {
arity_one("ERROR-MESSAGE", args)?;
fn error_message_stack(
condition_field_stack(ctx, emit, symbols, args, "ERROR-MESSAGE", MESSAGE_FIELD)
pub(in crate::compiler::native) const NATIVES: &[NativeSpec] = &[
NativeSpec {
name: "ERROR-CODE",
eval: error_code_eval,
stack: Some(error_code_stack),
effect: None,
},
name: "ERROR-MESSAGE",
eval: error_message_eval,
stack: Some(error_message_stack),
];