#![cfg(feature = "wasm")]
use metadol::parse_dol_file;
use metadol::parse_file;
use metadol::wasm::{WasmCompiler, WasmError, WasmRuntime};
#[test]
fn test_wasm_magic_number() {
let valid_wasm = vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00];
assert_eq!(&valid_wasm[0..4], b"\0asm");
}
#[test]
fn test_wasm_version() {
let valid_wasm = vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00];
let version = u32::from_le_bytes([valid_wasm[4], valid_wasm[5], valid_wasm[6], valid_wasm[7]]);
assert_eq!(version, 1);
}
#[test]
fn test_wasm_invalid_magic_number() {
let invalid_wasm = vec![0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00];
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let result = runtime.load(&invalid_wasm);
assert!(result.is_err());
}
#[test]
fn test_wasm_invalid_version() {
let invalid_wasm = vec![0x00, 0x61, 0x73, 0x6D, 0xFF, 0xFF, 0xFF, 0xFF];
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let result = runtime.load(&invalid_wasm);
assert!(result.is_err());
}
#[test]
fn test_wasm_truncated_module() {
let truncated_wasm = vec![0x00, 0x61, 0x73, 0x6D];
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let result = runtime.load(&truncated_wasm);
assert!(result.is_err());
}
#[test]
fn test_wasm_empty_module() {
let empty_wasm = vec![];
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let result = runtime.load(&empty_wasm);
assert!(result.is_err());
}
#[test]
fn test_wasm_runtime_new() {
let result = WasmRuntime::new();
assert!(
result.is_ok(),
"Failed to create WASM runtime: {:?}",
result.err()
);
}
#[test]
fn test_wasm_runtime_multiple_instances() {
let runtime1 = WasmRuntime::new();
let runtime2 = WasmRuntime::new();
assert!(runtime1.is_ok());
assert!(runtime2.is_ok());
}
#[test]
fn test_wasm_load_minimal_module() {
let minimal_wasm = vec![
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, ];
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let result = runtime.load(&minimal_wasm);
assert!(
result.is_ok(),
"Failed to load minimal WASM module: {:?}",
result.err()
);
}
#[test]
fn test_wasm_module_with_function() {
let wasm_with_func = vec![
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7F, 0x03, 0x02, 0x01, 0x00, 0x07, 0x09, 0x01, 0x05, 0x67, 0x65, 0x74, 0x34, 0x32, 0x00,
0x00, 0x0A, 0x06, 0x01, 0x04, 0x00, 0x41, 0x2A, 0x0B, ];
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let result = runtime.load(&wasm_with_func);
assert!(
result.is_ok(),
"Failed to load WASM module with function: {:?}",
result.err()
);
let mut module = result.unwrap();
let call_result = module.call("get42", &[]);
assert!(
call_result.is_ok(),
"Failed to call WASM function: {:?}",
call_result.err()
);
}
#[test]
fn test_wasm_call_nonexistent_function() {
let minimal_wasm = vec![
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, ];
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut module = runtime.load(&minimal_wasm).expect("Failed to load module");
let result = module.call("nonexistent", &[]);
assert!(result.is_err(), "Should fail to call nonexistent function");
}
#[test]
fn test_wasm_compiler_error_message() {
let source = r#"
gene Counter {
has value: Int64
}
exegesis { A counter. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let result = compiler.compile(&module);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
err.message.contains("No functions found") || err.message.contains("not fully implemented"),
"Expected function-related error, got: {}",
err.message
);
}
#[test]
fn test_wasm_compiler_with_optimization() {
let source = r#"
fun add(a: Int32, b: Int32) -> Int32 {
return a + b
}
exegesis { Adds two integers. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new().with_optimization(true);
let result = compiler.compile(&module);
assert!(result.is_ok(), "Compilation failed: {:?}", result.err());
let wasm_bytes = result.unwrap();
assert!(wasm_bytes.len() >= 8, "WASM output too short");
assert_eq!(&wasm_bytes[0..4], b"\0asm", "Invalid WASM magic number");
}
#[test]
fn test_wasm_compiler_default() {
let _compiler = WasmCompiler::default();
}
#[test]
fn test_wasm_error_new() {
let error = WasmError::new("Test error");
assert_eq!(error.message, "Test error");
}
#[test]
fn test_wasm_error_display() {
let error = WasmError::new("Test error");
let display = format!("{}", error);
assert!(display.contains("WASM error"));
assert!(display.contains("Test error"));
}
#[test]
fn test_wasm_error_from_io() {
use std::io;
let io_error = io::Error::new(io::ErrorKind::NotFound, "File not found");
let wasm_error: WasmError = io_error.into();
assert!(wasm_error.message.contains("I/O error"));
assert!(wasm_error.message.contains("File not found"));
}
#[test]
fn test_compile_and_execute_simple_function() {
let source = r#"
fun add(a: i64, b: i64) -> i64 {
return a + b
}
exegesis { Adds two integers. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("add", &[5i64.into(), 3i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(8));
}
#[test]
fn test_compile_and_execute_gene_method_with_field_access() {
let source = r#"
gene Counter {
has value: Int64
fun increment() -> Int64 {
return value + 1
}
}
exegesis { A counter with increment method. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new().with_optimization(true);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("Counter.increment", &[0i32.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
}
#[test]
fn test_compile_and_execute_gene_method_simple() {
let source = r#"
gene Math {
fun add(a: i64, b: i64) -> i64 {
return a + b
}
fun multiply(x: i64, y: i64) -> i64 {
return x * y
}
}
exegesis { Simple math operations. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("Math.add", &[5i64.into(), 3i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(8));
let result = wasm_module
.call("Math.multiply", &[6i64.into(), 7i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(42));
}
#[test]
fn test_compile_with_control_flow() {
let source = r#"
fun max(a: i64, b: i64) -> i64 {
if a > b {
return a
}
return b
}
exegesis { Returns the maximum of two integers. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("max", &[10i64.into(), 5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(10));
let result = wasm_module
.call("max", &[3i64.into(), 7i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(7));
}
#[test]
fn test_compile_with_pattern_matching() {
let source = r#"
fun classify(x: i64) -> i64 {
match x {
0 => 100,
1 => 200,
_ => 300,
}
}
exegesis { Classifies an integer. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("classify", &[0i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(100));
let result = wasm_module
.call("classify", &[1i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(200));
let result = wasm_module
.call("classify", &[42i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(300));
}
#[test]
fn test_wasm_runtime_many_modules() {
let minimal_wasm = vec![
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, ];
let runtime = WasmRuntime::new().expect("Failed to create runtime");
for _ in 0..10 {
let result = runtime.load(&minimal_wasm);
assert!(result.is_ok(), "Failed to load module");
}
}
#[test]
fn test_compile_and_execute_while_loop_sum() {
let source = r#"
fun test_while_sum(n: i64) -> i64 {
let total: i64 = 0
let i: i64 = 0
while i < n {
total = total + i
i = i + 1
}
return total
}
exegesis { Sums integers from 0 to n-1 using a while loop. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("test_while_sum", &[5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(10));
let result = wasm_module
.call("test_while_sum", &[1i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
let result = wasm_module
.call("test_while_sum", &[0i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_compile_and_execute_for_loop_sum() {
let source = r#"
fun test_for_sum(n: i64) -> i64 {
let total: i64 = 0
for i in 0..n {
total = total + i
}
return total
}
exegesis { Sums integers from 0 to n-1 using a for loop. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("test_for_sum", &[5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(10));
}
#[test]
fn test_compile_and_execute_loop_with_break() {
let source = r#"
fun test_loop_break(target: i64) -> i64 {
let counter: i64 = 0
loop {
counter = counter + 1
if counter >= target {
break
}
}
return counter
}
exegesis { Counts up until reaching target using loop with break. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("test_loop_break", &[5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(5));
}
#[test]
fn test_compile_and_execute_variable_reassignment() {
let source = r#"
fun test_reassign(x: i64) -> i64 {
let a: i64 = x
a = a + 10
a = a * 2
return a
}
exegesis { Tests variable reassignment. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("test_reassign", &[5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(30));
}
#[test]
fn test_compile_and_execute_factorial() {
let source = r#"
fun factorial(n: i64) -> i64 {
let result: i64 = 1
for i in 1..n {
result = result * i
}
return result
}
exegesis { Computes factorial of n-1 using for loop. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("factorial", &[5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(24));
let result = wasm_module
.call("factorial", &[1i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
}
#[test]
fn test_compile_gene_inheritance_layout() {
use metadol::Parser;
let source = r#"
module inheritance_test @ 0.1.0
gene Animal {
has age: i64
fun get_age() -> i64 {
return age
}
}
gene Dog extends Animal {
has breed_id: i64
fun bark_count() -> i64 {
return age * 2
}
}
"#;
let mut parser = Parser::new(source);
let dol_file = parser.parse_file().expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler
.compile_file(&dol_file)
.expect("Compilation failed");
assert!(wasm_bytes.len() > 8, "WASM should have content");
assert_eq!(&wasm_bytes[0..4], b"\0asm", "Should have WASM magic");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load WASM");
let result = wasm_module
.call("Animal.get_age", &[0i32.into()])
.expect("Call Animal.get_age failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_compile_gene_inheritance_child_access_parent_field() {
use metadol::Parser;
let source = r#"
module inheritance_test @ 0.1.0
gene Animal {
has age: i64
}
gene Dog extends Animal {
has breed_id: i64
fun bark_count() -> i64 {
return age * 2
}
}
"#;
let mut parser = Parser::new(source);
let dol_file = parser.parse_file().expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler
.compile_file(&dol_file)
.expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load WASM");
let result = wasm_module
.call("Dog.bark_count", &[0i32.into()])
.expect("Call Dog.bark_count failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_compile_gene_inheritance_reverse_order() {
use metadol::Parser;
let source = r#"
module inheritance_test @ 0.1.0
gene Dog extends Animal {
has breed_id: i64
fun get_breed() -> i64 {
return breed_id
}
}
gene Animal {
has age: i64
fun get_age() -> i64 {
return age
}
}
"#;
let mut parser = Parser::new(source);
let dol_file = parser.parse_file().expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler
.compile_file(&dol_file)
.expect("Compilation failed with reverse order");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let _wasm_module = runtime.load(&wasm_bytes).expect("Failed to load WASM");
}
#[test]
#[ignore] fn test_wasm_compilation_performance() {
use std::time::Instant;
let source = r#"
gene LargeGene {
has field1: Int64
has field2: Int64
has field3: Int64
has field4: Int64
has field5: Int64
fun method1() -> Int64 { return field1 }
fun method2() -> Int64 { return field2 }
fun method3() -> Int64 { return field3 }
fun method4() -> Int64 { return field4 }
fun method5() -> Int64 { return field5 }
}
exegesis { A large gene for performance testing. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new().with_optimization(true);
let start = Instant::now();
let _result = compiler.compile(&module);
let duration = start.elapsed();
assert!(
duration.as_secs() < 5,
"Compilation took too long: {:?}",
duration
);
}
#[test]
fn test_enum_variant_access() {
let source = r#"
fun get_node() -> AccountType {
return AccountType.Node
}
exegesis { Function returning enum variant discriminant. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
compiler.register_enum(
"AccountType",
vec![
"Node".to_string(),
"RevivalPool".to_string(),
"Treasury".to_string(),
],
);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module.call("get_node", &[]).expect("Call failed");
assert_eq!(
result.first().and_then(|v| v.i32()),
Some(0),
"Node should be index 0"
);
}
#[test]
fn test_enum_variant_revival_pool() {
let source = r#"
fun get_revival_pool() -> AccountType {
return AccountType.RevivalPool
}
exegesis { Function returning RevivalPool variant. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
compiler.register_enum(
"AccountType",
vec![
"Node".to_string(),
"RevivalPool".to_string(),
"Treasury".to_string(),
],
);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("get_revival_pool", &[])
.expect("Call failed");
assert_eq!(
result.first().and_then(|v| v.i32()),
Some(1),
"RevivalPool should be index 1"
);
}
#[test]
fn test_enum_variant_treasury() {
let source = r#"
fun get_treasury() -> AccountType {
return AccountType.Treasury
}
exegesis { Function returning Treasury variant. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
compiler.register_enum(
"AccountType",
vec![
"Node".to_string(),
"RevivalPool".to_string(),
"Treasury".to_string(),
],
);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module.call("get_treasury", &[]).expect("Call failed");
assert_eq!(
result.first().and_then(|v| v.i32()),
Some(2),
"Treasury should be index 2"
);
}
#[test]
fn test_enum_type_mapping() {
let source = r#"
fun compare_account_type(a: AccountType, b: AccountType) -> i32 {
if a == b {
return 1
}
return 0
}
exegesis { Compare two account types. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
compiler.register_enum(
"AccountType",
vec![
"Node".to_string(),
"RevivalPool".to_string(),
"Treasury".to_string(),
],
);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("compare_account_type", &[0i32.into(), 0i32.into()])
.expect("Call failed");
assert_eq!(
result.first().and_then(|v| v.i64()),
Some(1),
"Same values should be equal"
);
let result = wasm_module
.call("compare_account_type", &[0i32.into(), 1i32.into()])
.expect("Call failed");
assert_eq!(
result.first().and_then(|v| v.i64()),
Some(0),
"Different values should not be equal"
);
}
#[test]
fn test_multiple_enums() {
let source = r#"
fun get_cpu_resource() -> ResourceType {
return ResourceType.Cpu
}
exegesis { Gets CPU resource type. }
fun get_storage_resource() -> ResourceType {
return ResourceType.Storage
}
exegesis { Gets storage resource type. }
fun get_admin_role() -> Role {
return Role.Admin
}
exegesis { Gets admin role. }
"#;
let file = parse_dol_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
compiler.register_enum(
"ResourceType",
vec![
"Cpu".to_string(),
"Memory".to_string(),
"Gpu".to_string(),
"Storage".to_string(),
"Bandwidth".to_string(),
],
);
compiler.register_enum(
"Role",
vec!["Admin".to_string(), "User".to_string(), "Guest".to_string()],
);
let wasm_bytes = compiler.compile_file(&file).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("get_cpu_resource", &[])
.expect("Call failed");
assert_eq!(
result.first().and_then(|v| v.i32()),
Some(0),
"Cpu should be index 0"
);
let result = wasm_module
.call("get_storage_resource", &[])
.expect("Call failed");
assert_eq!(
result.first().and_then(|v| v.i32()),
Some(3),
"Storage should be index 3"
);
let result = wasm_module
.call("get_admin_role", &[])
.expect("Call failed");
assert_eq!(
result.first().and_then(|v| v.i32()),
Some(0),
"Admin should be index 0"
);
}
#[test]
fn test_enum_registry_api() {
let mut compiler = WasmCompiler::new();
assert!(!compiler.has_enum("AccountType"));
compiler.register_enum(
"AccountType",
vec![
"Node".to_string(),
"RevivalPool".to_string(),
"Treasury".to_string(),
],
);
assert!(compiler.has_enum("AccountType"));
assert!(!compiler.has_enum("UnknownType"));
assert_eq!(
compiler.get_enum_variant_index("AccountType", "Node"),
Some(0)
);
assert_eq!(
compiler.get_enum_variant_index("AccountType", "RevivalPool"),
Some(1)
);
assert_eq!(
compiler.get_enum_variant_index("AccountType", "Treasury"),
Some(2)
);
assert_eq!(
compiler.get_enum_variant_index("AccountType", "Unknown"),
None
);
assert_eq!(compiler.get_enum_variant_index("UnknownType", "Node"), None);
}
#[test]
fn test_compile_string_literal_returns_pointer() {
let source = r#"
fun get_greeting() -> String {
return "Hello, World!"
}
exegesis { Returns a greeting string. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let result = compiler.compile(&module);
assert!(
result.is_ok(),
"String literal compilation failed: {:?}",
result.err()
);
let wasm_bytes = result.unwrap();
assert!(wasm_bytes.len() >= 8, "WASM output too short");
assert_eq!(&wasm_bytes[0..4], b"\0asm", "Invalid WASM magic number");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module.call("get_greeting", &[]).expect("Call failed");
let ptr = result
.first()
.and_then(|v| v.i32())
.expect("Expected i32 result");
assert_eq!(ptr, 0, "Expected string pointer at offset 0");
}
#[test]
#[ignore] fn test_string_literal_in_data_section() {
let source = r#"
fun get_message() -> String {
return "Test"
}
exegesis { Returns a test string. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module.call("get_message", &[]).expect("Call failed");
let ptr = result
.first()
.and_then(|v| v.i32())
.expect("Expected i32 result");
assert_eq!(ptr, 0, "Expected string at offset 0");
}
#[test]
fn test_multiple_string_literals() {
let source = r#"
fun get_hello() -> String {
return "hello"
}
exegesis { Returns hello. }
fun get_world() -> String {
return "world"
}
exegesis { Returns world. }
fun get_hello_again() -> String {
return "hello"
}
exegesis { Returns hello again. }
"#;
let file = parse_dol_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile_file(&file).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let hello_ptr = wasm_module
.call("get_hello", &[])
.expect("Call failed")
.first()
.and_then(|v| v.i32())
.expect("Expected i32");
let world_ptr = wasm_module
.call("get_world", &[])
.expect("Call failed")
.first()
.and_then(|v| v.i32())
.expect("Expected i32");
let hello_again_ptr = wasm_module
.call("get_hello_again", &[])
.expect("Call failed")
.first()
.and_then(|v| v.i32())
.expect("Expected i32");
assert_eq!(
hello_ptr, hello_again_ptr,
"Duplicate strings should have same pointer"
);
assert_ne!(
hello_ptr, world_ptr,
"Different strings should have different pointers"
);
}
#[test]
fn test_string_type_in_function_parameter() {
let source = r#"
fun identity(s: String) -> String {
return s
}
exegesis { Returns the input string. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let result = compiler.compile(&module);
assert!(
result.is_ok(),
"String parameter compilation failed: {:?}",
result.err()
);
}
#[test]
#[ignore] fn test_empty_string_literal() {
let source = r#"
fun get_empty() -> String {
return ""
}
exegesis { Returns an empty string. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module.call("get_empty", &[]).expect("Call failed");
let ptr = result
.first()
.and_then(|v| v.i32())
.expect("Expected i32 result");
assert_eq!(ptr, 0, "Expected empty string at offset 0");
}
#[test]
fn test_hello_world_spirit_e2e() {
let source = r#"
fun spirit_main(input: i64) -> i64 {
return input * 2
}
exegesis { Spirit main entry point - doubles input. }
"#;
let module = parse_file(source).expect("Failed to parse Hello Spirit");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler
.compile(&module)
.expect("Failed to compile Hello Spirit to WASM");
assert!(wasm_bytes.len() > 8, "WASM should have content");
assert_eq!(&wasm_bytes[0..4], b"\0asm", "Should have WASM magic number");
let runtime = WasmRuntime::new().expect("Failed to create WASM runtime");
let mut wasm_module = runtime
.load(&wasm_bytes)
.expect("Failed to load Spirit WASM");
let result = wasm_module
.call("spirit_main", &[21i64.into()])
.expect("Call spirit_main failed");
assert_eq!(
result.first().and_then(|v| v.i64()),
Some(42),
"Spirit should double input: 21 * 2 = 42"
);
}
#[test]
fn test_spirit_with_computation() {
let source = r#"
fun fibonacci(n: i64) -> i64 {
if n <= 1 {
return n
}
let a: i64 = 0
let b: i64 = 1
let i: i64 = 2
while i <= n {
let temp: i64 = a + b
a = b
b = temp
i = i + 1
}
return b
}
exegesis { Computes nth Fibonacci number iteratively. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("fibonacci", &[10i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(55));
let result = wasm_module
.call("fibonacci", &[7i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(13));
}
#[test]
fn test_spirit_enr_entropy() {
let source = r#"
fun calculate_entropy_cost(hops: i64, base_cost: i64) -> i64 {
return hops * base_cost
}
exegesis { Calculate entropy cost based on hop count. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("calculate_entropy_cost", &[5i64.into(), 10i64.into()])
.expect("Call failed");
assert_eq!(
result.first().and_then(|v| v.i64()),
Some(50),
"5 hops * 10 cost = 50"
);
}
#[test]
fn test_spirit_control_flow() {
let source = r#"
fun process_request(request_type: i64, value: i64) -> i64 {
match request_type {
0 => {
// Echo request
return value
},
1 => {
// Double request
return value * 2
},
2 => {
// Square request
return value * value
},
_ => {
// Unknown request
return 0
},
}
}
exegesis { Process different request types. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("process_request", &[0i64.into(), 42i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(42));
let result = wasm_module
.call("process_request", &[1i64.into(), 21i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(42));
let result = wasm_module
.call("process_request", &[2i64.into(), 7i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(49));
let result = wasm_module
.call("process_request", &[99i64.into(), 100i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_member_access_f64_field() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, WasmFieldType};
let source = r#"
fun get_temperature() -> f64 {
let sensor = Sensor { temperature: 98.6, humidity: 0.65 }
return sensor.temperature
}
exegesis { Gets the temperature from a sensor. }
"#;
let module = parse_file(source).expect("Failed to parse");
let sensor_layout = GeneLayout {
name: "Sensor".to_string(),
fields: vec![
FieldLayout::primitive("temperature", 0, WasmFieldType::F64),
FieldLayout::primitive("humidity", 8, WasmFieldType::F64),
],
total_size: 16,
alignment: 8,
};
let mut compiler = WasmCompiler::new();
compiler.register_gene_layout(sensor_layout);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("get_temperature", &[])
.expect("Call failed");
let temp = result
.first()
.and_then(|v| v.f64())
.expect("Expected f64 result");
assert!((temp - 98.6).abs() < 0.001, "Expected 98.6, got {}", temp);
}
#[test]
fn test_struct_literal_f64_field() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, WasmFieldType};
let source = r#"
fun get_humidity() -> f64 {
let sensor = Sensor { temperature: 72.5, humidity: 0.45 }
return sensor.humidity
}
exegesis { Gets humidity from a sensor. }
"#;
let module = parse_file(source).expect("Failed to parse");
let sensor_layout = GeneLayout {
name: "Sensor".to_string(),
fields: vec![
FieldLayout::primitive("temperature", 0, WasmFieldType::F64),
FieldLayout::primitive("humidity", 8, WasmFieldType::F64),
],
total_size: 16,
alignment: 8,
};
let mut compiler = WasmCompiler::new();
compiler.register_gene_layout(sensor_layout);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module.call("get_humidity", &[]).expect("Call failed");
let humidity = result
.first()
.and_then(|v| v.f64())
.expect("Expected f64 result");
assert!(
(humidity - 0.45).abs() < 0.001,
"Expected 0.45, got {}",
humidity
);
}
#[test]
fn test_struct_literal_mixed_i64_f64() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, WasmFieldType};
let source = r#"
fun get_average_temp() -> f64 {
let reading = WeatherReading { timestamp: 1704312000, temperature: 72.5, pressure: 1013.25 }
return reading.pressure
}
exegesis { Gets pressure from a weather reading with mixed field types. }
"#;
let module = parse_file(source).expect("Failed to parse");
let reading_layout = GeneLayout {
name: "WeatherReading".to_string(),
fields: vec![
FieldLayout::primitive("timestamp", 0, WasmFieldType::I64),
FieldLayout::primitive("temperature", 8, WasmFieldType::F64),
FieldLayout::primitive("pressure", 16, WasmFieldType::F64),
],
total_size: 24,
alignment: 8,
};
let mut compiler = WasmCompiler::new();
compiler.register_gene_layout(reading_layout);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("get_average_temp", &[])
.expect("Call failed");
let pressure = result
.first()
.and_then(|v| v.f64())
.expect("Expected f64 result");
assert!(
(pressure - 1013.25).abs() < 0.001,
"Expected 1013.25, got {}",
pressure
);
}
#[test]
fn test_unary_negation() {
let source = r#"
fun negate(x: i64) -> i64 {
return -x
}
exegesis { Negates an integer. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("negate", &[42i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(-42));
let result = wasm_module
.call("negate", &[(-100i64).into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(100));
let result = wasm_module
.call("negate", &[0i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_unary_negation_in_expression() {
let source = r#"
fun subtract_via_negation(a: i64, b: i64) -> i64 {
return a + -b
}
exegesis { Subtracts b from a using negation. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("subtract_via_negation", &[10i64.into(), 3i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(7));
}
#[test]
fn test_unary_not() {
let source = r#"
fun invert(x: i64) -> i64 {
if !x {
return 1
}
return 0
}
exegesis { Returns 1 if x is falsy (0), 0 otherwise. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("invert", &[0i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
let result = wasm_module
.call("invert", &[42i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
let result = wasm_module
.call("invert", &[1i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_nested_field_access() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, WasmFieldType};
let source = r#"
fun sum_coordinates() -> i64 {
let p1 = Point { x: 10, y: 20 }
let p2 = Point { x: 5, y: 15 }
return p1.x + p2.y
}
exegesis { Sums x from one point and y from another. }
"#;
let module = parse_file(source).expect("Failed to parse");
let point_layout = GeneLayout {
name: "Point".to_string(),
fields: vec![
FieldLayout::primitive("x", 0, WasmFieldType::I64),
FieldLayout::primitive("y", 8, WasmFieldType::I64),
],
total_size: 16,
alignment: 8,
};
let mut compiler = WasmCompiler::new();
compiler.register_gene_layout(point_layout);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("sum_coordinates", &[])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(25));
}
#[test]
fn test_multiple_struct_literals() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, WasmFieldType};
let source = r#"
fun distance_squared() -> i64 {
let start = Point { x: 0, y: 0 }
let end = Point { x: 3, y: 4 }
let dx = end.x - start.x
let dy = end.y - start.y
return dx * dx + dy * dy
}
exegesis { Calculates squared distance between two points. }
"#;
let module = parse_file(source).expect("Failed to parse");
let point_layout = GeneLayout {
name: "Point".to_string(),
fields: vec![
FieldLayout::primitive("x", 0, WasmFieldType::I64),
FieldLayout::primitive("y", 8, WasmFieldType::I64),
],
total_size: 16,
alignment: 8,
};
let mut compiler = WasmCompiler::new();
compiler.register_gene_layout(point_layout);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("distance_squared", &[])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(25));
}
#[test]
fn test_struct_field_in_conditional() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, WasmFieldType};
let source = r#"
fun is_origin() -> i64 {
let p = Point { x: 0, y: 0 }
if p.x == 0 {
if p.y == 0 {
return 1
}
}
return 0
}
exegesis { Checks if point is at origin. }
"#;
let module = parse_file(source).expect("Failed to parse");
let point_layout = GeneLayout {
name: "Point".to_string(),
fields: vec![
FieldLayout::primitive("x", 0, WasmFieldType::I64),
FieldLayout::primitive("y", 8, WasmFieldType::I64),
],
total_size: 16,
alignment: 8,
};
let mut compiler = WasmCompiler::new();
compiler.register_gene_layout(point_layout);
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module.call("is_origin", &[]).expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
}
#[test]
fn test_double_negation() {
let source = r#"
fun double_negate(x: i64) -> i64 {
return -(-x)
}
exegesis { Double negates a number (returns original). }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("double_negate", &[42i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(42));
let result = wasm_module
.call("double_negate", &[(-17i64).into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(-17));
}
#[test]
fn test_wasm_field_type_size() {
use metadol::wasm::layout::WasmFieldType;
assert_eq!(WasmFieldType::I32.size(), 4);
assert_eq!(WasmFieldType::I64.size(), 8);
assert_eq!(WasmFieldType::F32.size(), 4);
assert_eq!(WasmFieldType::F64.size(), 8);
assert_eq!(WasmFieldType::Ptr.size(), 4);
}
#[test]
fn test_wasm_field_type_alignment() {
use metadol::wasm::layout::WasmFieldType;
assert_eq!(WasmFieldType::I32.alignment(), 4);
assert_eq!(WasmFieldType::I64.alignment(), 8);
assert_eq!(WasmFieldType::F32.alignment(), 4);
assert_eq!(WasmFieldType::F64.alignment(), 8);
assert_eq!(WasmFieldType::Ptr.alignment(), 4);
}
#[test]
fn test_wasm_field_type_alignment_log2() {
use metadol::wasm::layout::WasmFieldType;
assert_eq!(WasmFieldType::I32.alignment_log2(), 2);
assert_eq!(WasmFieldType::I64.alignment_log2(), 3);
assert_eq!(WasmFieldType::F32.alignment_log2(), 2);
assert_eq!(WasmFieldType::F64.alignment_log2(), 3);
assert_eq!(WasmFieldType::Ptr.alignment_log2(), 2);
}
#[test]
fn test_wasm_field_type_display() {
use metadol::wasm::layout::WasmFieldType;
assert_eq!(format!("{}", WasmFieldType::I32), "i32");
assert_eq!(format!("{}", WasmFieldType::I64), "i64");
assert_eq!(format!("{}", WasmFieldType::F32), "f32");
assert_eq!(format!("{}", WasmFieldType::F64), "f64");
assert_eq!(format!("{}", WasmFieldType::Ptr), "ptr");
}
#[test]
fn test_wasm_field_type_to_val_type() {
use metadol::wasm::layout::WasmFieldType;
assert_eq!(WasmFieldType::I32.to_val_type(), wasm_encoder::ValType::I32);
assert_eq!(WasmFieldType::Ptr.to_val_type(), wasm_encoder::ValType::I32);
assert_eq!(WasmFieldType::I64.to_val_type(), wasm_encoder::ValType::I64);
assert_eq!(WasmFieldType::F32.to_val_type(), wasm_encoder::ValType::F32);
assert_eq!(WasmFieldType::F64.to_val_type(), wasm_encoder::ValType::F64);
}
#[test]
fn test_field_layout_primitive() {
use metadol::wasm::layout::{FieldLayout, WasmFieldType};
let field = FieldLayout::primitive("x", 0, WasmFieldType::F64);
assert_eq!(field.name, "x");
assert_eq!(field.offset, 0);
assert_eq!(field.size, 8);
assert_eq!(field.alignment, 8);
assert_eq!(field.wasm_type, WasmFieldType::F64);
assert!(!field.is_reference);
assert!(field.nested_layout.is_none());
}
#[test]
fn test_field_layout_reference() {
use metadol::wasm::layout::{FieldLayout, WasmFieldType};
let field = FieldLayout::reference("other", 16);
assert_eq!(field.name, "other");
assert_eq!(field.offset, 16);
assert_eq!(field.size, 4);
assert_eq!(field.alignment, 4);
assert_eq!(field.wasm_type, WasmFieldType::Ptr);
assert!(field.is_reference);
assert!(field.nested_layout.is_none());
}
#[test]
fn test_field_layout_inline() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, WasmFieldType};
let inner_layout = GeneLayout {
name: "Inner".to_string(),
fields: vec![FieldLayout::primitive("val", 0, WasmFieldType::I32)],
total_size: 4,
alignment: 4,
};
let field = FieldLayout::inline("nested", 8, inner_layout);
assert_eq!(field.name, "nested");
assert_eq!(field.offset, 8);
assert_eq!(field.size, 4);
assert_eq!(field.alignment, 4);
assert!(!field.is_reference);
assert!(field.nested_layout.is_some());
assert_eq!(field.nested_layout.as_ref().unwrap().name, "Inner");
}
#[test]
fn test_gene_layout_new() {
use metadol::wasm::layout::GeneLayout;
let layout = GeneLayout::new("TestGene");
assert_eq!(layout.name, "TestGene");
assert!(layout.fields.is_empty());
assert_eq!(layout.total_size, 0);
assert_eq!(layout.alignment, 1);
}
#[test]
fn test_gene_layout_default() {
use metadol::wasm::layout::GeneLayout;
let layout = GeneLayout::default();
assert_eq!(layout.name, "");
assert!(layout.fields.is_empty());
assert_eq!(layout.total_size, 0);
assert_eq!(layout.alignment, 1);
}
#[test]
fn test_gene_layout_get_field() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, WasmFieldType};
let layout = GeneLayout {
name: "Point".to_string(),
fields: vec![
FieldLayout::primitive("x", 0, WasmFieldType::F64),
FieldLayout::primitive("y", 8, WasmFieldType::F64),
],
total_size: 16,
alignment: 8,
};
let x_field = layout.get_field("x");
assert!(x_field.is_some());
assert_eq!(x_field.unwrap().offset, 0);
let y_field = layout.get_field("y");
assert!(y_field.is_some());
assert_eq!(y_field.unwrap().offset, 8);
let z_field = layout.get_field("z");
assert!(z_field.is_none());
assert_eq!(layout.get_field_offset("x"), Some(0));
assert_eq!(layout.get_field_offset("y"), Some(8));
assert_eq!(layout.get_field_offset("z"), None);
}
#[test]
fn test_gene_layout_type_id() {
use metadol::wasm::layout::GeneLayout;
let layout1 = GeneLayout::new("Point");
let layout2 = GeneLayout::new("Point");
let layout3 = GeneLayout::new("Vector");
assert_eq!(layout1.type_id(), layout2.type_id());
assert_ne!(layout1.type_id(), layout3.type_id());
assert_ne!(layout1.type_id(), 0);
}
#[test]
fn test_gene_layout_references() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, WasmFieldType};
let no_refs = GeneLayout {
name: "NoRefs".to_string(),
fields: vec![
FieldLayout::primitive("a", 0, WasmFieldType::I64),
FieldLayout::primitive("b", 8, WasmFieldType::I64),
],
total_size: 16,
alignment: 8,
};
assert!(!no_refs.has_references());
assert!(no_refs.pointer_offsets().is_empty());
let with_refs = GeneLayout {
name: "WithRefs".to_string(),
fields: vec![
FieldLayout::primitive("val", 0, WasmFieldType::I64),
FieldLayout::reference("next", 8),
FieldLayout::reference("prev", 12),
],
total_size: 16,
alignment: 8,
};
assert!(with_refs.has_references());
let offsets = with_refs.pointer_offsets();
assert_eq!(offsets.len(), 2);
assert!(offsets.contains(&8));
assert!(offsets.contains(&12));
}
#[test]
fn test_gene_layout_field_count() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, WasmFieldType};
let empty = GeneLayout::new("Empty");
assert!(empty.is_empty());
assert_eq!(empty.field_count(), 0);
let with_fields = GeneLayout {
name: "Point".to_string(),
fields: vec![
FieldLayout::primitive("x", 0, WasmFieldType::F64),
FieldLayout::primitive("y", 8, WasmFieldType::F64),
],
total_size: 16,
alignment: 8,
};
assert!(!with_fields.is_empty());
assert_eq!(with_fields.field_count(), 2);
}
#[test]
fn test_gene_layout_registry() {
use metadol::wasm::layout::{FieldLayout, GeneLayout, GeneLayoutRegistry, WasmFieldType};
let mut registry = GeneLayoutRegistry::new();
assert!(registry.is_empty());
assert_eq!(registry.len(), 0);
assert!(!registry.contains("Point"));
assert!(registry.get("Point").is_none());
let point = GeneLayout {
name: "Point".to_string(),
fields: vec![
FieldLayout::primitive("x", 0, WasmFieldType::F64),
FieldLayout::primitive("y", 8, WasmFieldType::F64),
],
total_size: 16,
alignment: 8,
};
registry.register(point);
assert!(!registry.is_empty());
assert_eq!(registry.len(), 1);
assert!(registry.contains("Point"));
let retrieved = registry.get("Point");
assert!(retrieved.is_some());
assert_eq!(retrieved.unwrap().total_size, 16);
let vector = GeneLayout {
name: "Vector".to_string(),
fields: vec![
FieldLayout::primitive("dx", 0, WasmFieldType::F64),
FieldLayout::primitive("dy", 8, WasmFieldType::F64),
],
total_size: 16,
alignment: 8,
};
registry.register(vector);
assert_eq!(registry.len(), 2);
let names: Vec<_> = registry.iter().map(|(n, _)| n.clone()).collect();
assert!(names.contains(&"Point".to_string()));
assert!(names.contains(&"Vector".to_string()));
let removed = registry.remove("Point");
assert!(removed.is_some());
assert_eq!(removed.unwrap().name, "Point");
assert!(!registry.contains("Point"));
assert_eq!(registry.len(), 1);
registry.clear();
assert!(registry.is_empty());
assert_eq!(registry.len(), 0);
}
#[test]
fn test_bump_allocator_new() {
use metadol::wasm::alloc::BumpAllocator;
let allocator = BumpAllocator::new(0, 1);
assert_eq!(allocator.heap_base_global(), 0);
assert_eq!(allocator.heap_end_global(), 1);
let allocator2 = BumpAllocator::new(5, 10);
assert_eq!(allocator2.heap_base_global(), 5);
assert_eq!(allocator2.heap_end_global(), 10);
}
#[test]
fn test_alloc_constants() {
use metadol::wasm::alloc::{
DEFAULT_HEAP_START, DEFAULT_MEMORY_PAGES, MAX_MEMORY_PAGES, PAGE_SIZE,
};
assert_eq!(DEFAULT_MEMORY_PAGES, 1);
assert_eq!(MAX_MEMORY_PAGES, 256);
assert_eq!(PAGE_SIZE, 65536);
assert_eq!(DEFAULT_HEAP_START, 1024);
assert!(DEFAULT_HEAP_START < PAGE_SIZE);
assert!(DEFAULT_MEMORY_PAGES <= MAX_MEMORY_PAGES);
}
#[test]
fn test_bump_allocator_emit_globals() {
use metadol::wasm::alloc::BumpAllocator;
use wasm_encoder::Module;
let mut module = Module::new();
BumpAllocator::emit_globals(&mut module, 1024);
let bytes = module.finish();
assert!(!bytes.is_empty());
assert_eq!(&bytes[0..4], b"\0asm");
}
#[test]
fn test_bump_allocator_emit_globals_with_end() {
use metadol::wasm::alloc::BumpAllocator;
use wasm_encoder::Module;
let mut module = Module::new();
BumpAllocator::emit_globals_with_end(&mut module, 2048, 4 * 65536);
let bytes = module.finish();
assert!(!bytes.is_empty());
assert_eq!(&bytes[0..4], b"\0asm");
}
#[test]
fn test_bump_allocator_emit_memory_section() {
use metadol::wasm::alloc::BumpAllocator;
use wasm_encoder::Module;
let mut module = Module::new();
BumpAllocator::emit_memory_section(&mut module, 2);
let bytes = module.finish();
assert!(!bytes.is_empty());
assert_eq!(&bytes[0..4], b"\0asm");
}
#[test]
fn test_bump_allocator_emit_alloc_function() {
use metadol::wasm::alloc::BumpAllocator;
let instructions = BumpAllocator::emit_alloc_function();
assert!(instructions.len() > 10);
assert!(matches!(
instructions[0],
wasm_encoder::Instruction::GlobalGet(0)
));
assert!(matches!(
instructions.last(),
Some(wasm_encoder::Instruction::End)
));
}
#[test]
fn test_bump_allocator_build_alloc_function() {
use metadol::wasm::alloc::BumpAllocator;
let function = BumpAllocator::build_alloc_function();
let mut func_section = wasm_encoder::CodeSection::new();
func_section.function(&function);
}
#[test]
fn test_bump_allocator_alloc_type_signature() {
use metadol::wasm::alloc::BumpAllocator;
let (params, results) = BumpAllocator::alloc_type_signature();
assert_eq!(params.len(), 2);
assert_eq!(params[0], wasm_encoder::ValType::I32);
assert_eq!(params[1], wasm_encoder::ValType::I32);
assert_eq!(results.len(), 1);
assert_eq!(results[0], wasm_encoder::ValType::I32);
}
#[test]
fn test_wasm_runtime_default() {
let runtime = WasmRuntime::default();
drop(runtime);
}
#[test]
fn test_wasm_module_instance() {
let source = r#"
fun get_value() -> i64 {
return 42
}
exegesis { Returns 42. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let instance = wasm_module.instance();
let _ = instance;
let result = wasm_module.call("get_value", &[]).expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(42));
}
#[test]
fn test_wasm_module_store_mut() {
let source = r#"
fun add(a: i64, b: i64) -> i64 {
return a + b
}
exegesis { Adds two numbers. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
{
let store = wasm_module.store_mut();
let _data = store.data();
}
let result = wasm_module
.call("add", &[10i64.into(), 32i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(42));
}
#[test]
fn test_wasm_runtime_load_file_error() {
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let result = runtime.load_file("/nonexistent/path/module.wasm");
assert!(result.is_err());
}
#[test]
fn test_wasm_runtime_load_file() {
use std::io::Write;
let source = r#"
fun double(x: i64) -> i64 {
return x * 2
}
exegesis { Doubles a number. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let temp_path = "/tmp/test_load_file.wasm";
let mut file = std::fs::File::create(temp_path).expect("Failed to create temp file");
file.write_all(&wasm_bytes)
.expect("Failed to write WASM bytes");
drop(file);
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime
.load_file(temp_path)
.expect("Failed to load from file");
let result = wasm_module
.call("double", &[21i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(42));
std::fs::remove_file(temp_path).ok();
}
#[test]
fn test_bool_literal_compilation() {
let source = r#"
fun get_true() -> i64 {
if true {
return 1
}
return 0
}
exegesis { Returns 1. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module.call("get_true", &[]).expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
}
#[test]
fn test_bool_false_literal() {
let source = r#"
fun get_false() -> i64 {
if false {
return 1
}
return 0
}
exegesis { Returns 0. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module.call("get_false", &[]).expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_match_with_wildcard() {
let source = r#"
fun classify(x: i64) -> i64 {
match x {
0 => 100,
1 => 200,
_ => 999,
}
}
exegesis { Classifies value. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("classify", &[0i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(100));
let result = wasm_module
.call("classify", &[1i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(200));
let result = wasm_module
.call("classify", &[42i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(999));
}
#[test]
fn test_if_else_with_returns() {
let source = r#"
fun sign(x: i64) -> i64 {
if x > 0 {
return 1
}
if x < 0 {
return -1
}
return 0
}
exegesis { Returns sign of number. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("sign", &[5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
let result = wasm_module
.call("sign", &[(-7i64).into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(-1));
let result = wasm_module
.call("sign", &[0i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_while_loop() {
let source = r#"
fun sum_to(n: i64) -> i64 {
let result = 0
let i = 0
while i <= n {
result = result + i
i = i + 1
}
return result
}
exegesis { Sum of 0 to n. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("sum_to", &[5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(15));
}
#[test]
fn test_for_loop_range_literal() {
let source = r#"
fun sum_five() -> i64 {
let total = 0
for i in 0..5 {
total = total + i
}
return total
}
exegesis { Sum 0 to 4. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module.call("sum_five", &[]).expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(10));
}
#[test]
fn test_modulo_operator() {
let source = r#"
fun is_even(x: i64) -> i64 {
if x % 2 == 0 {
return 1
}
return 0
}
exegesis { Returns 1 if even. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("is_even", &[4i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
let result = wasm_module
.call("is_even", &[7i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_division_operator() {
let source = r#"
fun divide(a: i64, b: i64) -> i64 {
return a / b
}
exegesis { Divides a by b. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("divide", &[42i64.into(), 6i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(7));
}
#[test]
fn test_logical_and() {
let source = r#"
fun both_positive(a: i64, b: i64) -> i64 {
if a > 0 && b > 0 {
return 1
}
return 0
}
exegesis { Returns 1 if both positive. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("both_positive", &[5i64.into(), 3i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
let result = wasm_module
.call("both_positive", &[5i64.into(), (-3i64).into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_logical_or() {
let source = r#"
fun either_positive(a: i64, b: i64) -> i64 {
if a > 0 || b > 0 {
return 1
}
return 0
}
exegesis { Returns 1 if either positive. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("either_positive", &[(-5i64).into(), 3i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
let result = wasm_module
.call("either_positive", &[(-5i64).into(), (-3i64).into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_lte_operator() {
let source = r#"
fun is_lte(a: i64, b: i64) -> i64 {
if a <= b {
return 1
}
return 0
}
exegesis { Returns 1 if a <= b. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("is_lte", &[5i64.into(), 5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
let result = wasm_module
.call("is_lte", &[4i64.into(), 5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
let result = wasm_module
.call("is_lte", &[6i64.into(), 5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_gte_operator() {
let source = r#"
fun is_gte(a: i64, b: i64) -> i64 {
if a >= b {
return 1
}
return 0
}
exegesis { Returns 1 if a >= b. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("is_gte", &[5i64.into(), 5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
let result = wasm_module
.call("is_gte", &[6i64.into(), 5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
let result = wasm_module
.call("is_gte", &[4i64.into(), 5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
}
#[test]
fn test_not_equal_operator() {
let source = r#"
fun is_ne(a: i64, b: i64) -> i64 {
if a != b {
return 1
}
return 0
}
exegesis { Returns 1 if a != b. }
"#;
let module = parse_file(source).expect("Failed to parse");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile(&module).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load module");
let result = wasm_module
.call("is_ne", &[5i64.into(), 5i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(0));
let result = wasm_module
.call("is_ne", &[5i64.into(), 6i64.into()])
.expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(1));
}
#[test]
fn test_gene_constructor_export() {
let source = r#"
/// A 2D point gene
gene Point {
has x: Int64
has y: Int64
}
/// Function that uses a Point
pub fun get_point_sum() -> Int64 {
let p = Point { x: 10, y: 20 }
p.x + p.y
}
"#;
let file = parse_dol_file(source).expect("Parse failed");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile_file(&file).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load WASM");
let result = wasm_module.call("get_point_sum", &[]).expect("Call failed");
assert_eq!(result.first().and_then(|v| v.i64()), Some(30));
let result = wasm_module
.call("new_Point", &[100i64.into(), 200i64.into()])
.expect("Call new_Point failed");
let ptr = result
.first()
.and_then(|v| v.i32())
.expect("Expected i32 pointer result");
assert!(ptr >= 0, "Pointer should be non-negative");
}
#[test]
fn test_gene_constructor_with_floats() {
let source = r#"
/// A 2D vector with float components
gene Vector2D {
has dx: Float64
has dy: Float64
}
/// Create and use a vector
pub fun test_vector() -> Float64 {
let v = Vector2D { dx: 3.0, dy: 4.0 }
v.dx + v.dy
}
"#;
let file = parse_dol_file(source).expect("Parse failed");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile_file(&file).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load WASM");
let result = wasm_module.call("test_vector", &[]).expect("Call failed");
let sum = result.first().and_then(|v| v.f64()).expect("Expected f64");
assert!((sum - 7.0).abs() < 0.0001, "Expected 7.0, got {}", sum);
let result = wasm_module.call(
"new_Vector2D",
&[
wasmtime::Val::F64(1.5f64.to_bits()),
wasmtime::Val::F64(2.5f64.to_bits()),
],
);
assert!(
result.is_ok(),
"new_Vector2D constructor should be callable: {:?}",
result.err()
);
}
#[test]
fn test_multiple_gene_constructors() {
let source = r#"
/// A 2D point
gene Point {
has x: Int64
has y: Int64
}
/// A 3D point
gene Point3D {
has x: Int64
has y: Int64
has z: Int64
}
/// Sum coordinates of both points
pub fun test_both() -> Int64 {
let p2 = Point { x: 1, y: 2 }
let p3 = Point3D { x: 10, y: 20, z: 30 }
p2.x + p2.y + p3.x + p3.y + p3.z
}
"#;
let file = parse_dol_file(source).expect("Parse failed");
let mut compiler = WasmCompiler::new();
let wasm_bytes = compiler.compile_file(&file).expect("Compilation failed");
let runtime = WasmRuntime::new().expect("Failed to create runtime");
let mut wasm_module = runtime.load(&wasm_bytes).expect("Failed to load WASM");
let result = wasm_module.call("test_both", &[]).expect("Call failed");
assert_eq!(
result.first().and_then(|v| v.i64()),
Some(63),
"1+2+10+20+30 = 63"
);
let result = wasm_module
.call("new_Point", &[5i64.into(), 6i64.into()])
.expect("new_Point should be exported");
assert!(result.first().and_then(|v| v.i32()).is_some());
let result = wasm_module
.call("new_Point3D", &[1i64.into(), 2i64.into(), 3i64.into()])
.expect("new_Point3D should be exported");
assert!(result.first().and_then(|v| v.i32()).is_some());
}