From 046261b028256a51af4060983abee359ed6d18d7 Mon Sep 17 00:00:00 2001 From: George Cosma Date: Sat, 13 Jul 2024 14:50:00 +0300 Subject: [PATCH] i got the asserts to work, at the cost of stack uncertainty --- .vscode/settings.json | 5 + Cargo.toml | 1 + src/execution/mod.rs | 23 ++- src/execution/value.rs | 4 + src/lib.rs | 2 +- tests/common/mod.rs | 2 +- tests/common/spec_run.rs | 4 +- tests/lib.rs | 19 ++- tests/specification/dummy.wast | 85 +++++++++- tests/specification/run.rs | 290 +++++++++++++++++++++++++-------- 10 files changed, 344 insertions(+), 91 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..311ad1fc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.cargo.features": [ + "spec-test" + ] +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 9e4a13a8..1a42fc0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ criterion = { version = "0.5.1", features = ["html_reports"] } [features] default = ["hooks"] hooks = [] +spec-test = [] [[bench]] name = "hook_performance_impact" diff --git a/src/execution/mod.rs b/src/execution/mod.rs index 2107fcc5..15a980a3 100644 --- a/src/execution/mod.rs +++ b/src/execution/mod.rs @@ -104,11 +104,20 @@ where let func_ty = self.types.get(func_inst.ty).unwrap_validated(); // Check correct function parameters and return types - if func_ty.params.valtypes != Param::TYS { - panic!("Invalid `Param` generics"); + #[cfg(not(feature = "spec-test"))] { + if func_ty.params.valtypes != Param::TYS { + panic!("Invalid `Param` generics"); + } + if func_ty.returns.valtypes != Returns::TYS { + panic!("Invalid `Returns` generics"); + } } - if func_ty.returns.valtypes != Returns::TYS { - panic!("Invalid `Returns` generics"); + #[cfg(feature = "spec-test")] { + if func_ty.params.valtypes != param.get_types() { + debug!("Expected: {:?}", func_ty.params.valtypes); + debug!("Actual: {:?}", param.get_types()); + panic!("Invalid `Param` generics"); + } } let mut stack = Stack::new(); @@ -122,11 +131,17 @@ where error?; // Pop return values from stack + #[cfg(not(feature = "spec-test"))] let return_values = Returns::TYS .iter() .map(|ty| stack.pop_value(*ty)) .collect::>(); + #[cfg(feature = "spec-test")] + let return_values = self.types.get(self.store.funcs.get(func_idx).expect("valid FuncIdx").ty).unwrap_validated().returns.valtypes + .iter() + .map(|ty| stack.pop_value(*ty)) + .collect::>(); // Values are reversed because they were popped from stack one-by-one. Now reverse them back let reversed_values = return_values.into_iter().rev(); let ret = Returns::from_values(reversed_values); diff --git a/src/execution/value.rs b/src/execution/value.rs index 9d2c4bd9..e1a66df9 100644 --- a/src/execution/value.rs +++ b/src/execution/value.rs @@ -67,6 +67,10 @@ pub trait InteropValueList { fn into_values(self) -> Vec; #[allow(warnings)] fn from_values(values: impl Iterator) -> Self; + #[cfg(feature = "spec-test")] + fn get_types(&self) -> &[ValType] { + Self::TYS + } } impl InteropValue for u32 { diff --git a/src/lib.rs b/src/lib.rs index 82666c84..6d846488 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,9 +4,9 @@ extern crate alloc; extern crate log; pub use core::error::{Error, Result, RuntimeError}; +pub use core::reader::types::{NumType, ValType}; pub use execution::*; pub use validation::*; -pub use core::reader::types::{NumType, ValType}; pub(crate) mod core; pub(crate) mod execution; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 20327afc..adb38ee3 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1 +1 @@ -pub mod spec_run; \ No newline at end of file +pub mod spec_run; diff --git a/tests/common/spec_run.rs b/tests/common/spec_run.rs index d8f8fd73..fec4af15 100644 --- a/tests/common/spec_run.rs +++ b/tests/common/spec_run.rs @@ -1,3 +1 @@ -pub fn run() { - -} \ No newline at end of file +pub fn run() {} diff --git a/tests/lib.rs b/tests/lib.rs index 7bbdcfc6..8e55aed5 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,13 +1,12 @@ -use log::log_enabled; - -pub mod common; mod arithmetic; +pub mod common; +#[cfg(feature = "spec-test")] mod specification; - #[test_log::test] pub fn test_test() { - let wasm_bytes = wat::parse_str(r#" + let wasm_bytes = wat::parse_str( + r#" (module (func (export "add") (param $x i32) (param $y i32) (result i32) (i32.add @@ -23,13 +22,15 @@ pub fn test_test() { ) ) ) - "#).unwrap(); + "#, + ) + .unwrap(); let validation_info = wasm::validate(&wasm_bytes).expect("validation failed"); let mut instance = wasm::RuntimeInstance::new(&validation_info).expect("instantiation failed"); - let rez: i32 = instance.invoke_func(0, (1,2)).unwrap(); + let rez: i32 = instance.invoke_func(0, (1, 2)).unwrap(); assert_eq!(rez, 3); - let rez: i32 = instance.invoke_func(1, (1,2)).unwrap(); + let rez: i32 = instance.invoke_func(1, (1, 2)).unwrap(); assert_eq!(rez, 3); -} \ No newline at end of file +} diff --git a/tests/specification/dummy.wast b/tests/specification/dummy.wast index 9e94080c..792d949e 100644 --- a/tests/specification/dummy.wast +++ b/tests/specification/dummy.wast @@ -1,5 +1,12 @@ +;; i32 operations + (module (func (export "add") (param $x i32) (param $y i32) (result i32) (i32.add (local.get $x) (local.get $y))) + (func (export "mul") (param $x i32) (param $y i32) (result i32) (i32.mul (local.get $x) (local.get $y))) + (func (export "div_s") (param $x i32) (param $y i32) (result i32) (i32.div_s (local.get $x) (local.get $y))) + (func (export "div_u") (param $x i32) (param $y i32) (result i32) (i32.div_u (local.get $x) (local.get $y))) + (func (export "rem_s") (param $x i32) (param $y i32) (result i32) (i32.rem_s (local.get $x) (local.get $y))) + (func (export "rem_u") (param $x i32) (param $y i32) (result i32) (i32.rem_u (local.get $x) (local.get $y))) ) (assert_return (invoke "add" (i32.const 1) (i32.const 1)) (i32.const 2)) @@ -9,4 +16,80 @@ (assert_return (invoke "add" (i32.const 0x7fffffff) (i32.const 1)) (i32.const 0x80000000)) (assert_return (invoke "add" (i32.const 0x80000000) (i32.const -1)) (i32.const 0x7fffffff)) (assert_return (invoke "add" (i32.const 0x80000000) (i32.const 0x80000000)) (i32.const 0)) -(assert_return (invoke "add" (i32.const 0x3fffffff) (i32.const 1)) (i32.const 0x40000000)) \ No newline at end of file +(assert_return (invoke "add" (i32.const 0x3fffffff) (i32.const 1)) (i32.const 0x40000000)) + +(assert_return (invoke "mul" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_return (invoke "mul" (i32.const 1) (i32.const 0)) (i32.const 0)) +(assert_return (invoke "mul" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_return (invoke "mul" (i32.const 0x10000000) (i32.const 4096)) (i32.const 0)) +(assert_return (invoke "mul" (i32.const 0x80000000) (i32.const 0)) (i32.const 0)) +(assert_return (invoke "mul" (i32.const 0x80000000) (i32.const -1)) (i32.const 0x80000000)) +(assert_return (invoke "mul" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0x80000001)) +(assert_return (invoke "mul" (i32.const 0x01234567) (i32.const 0x76543210)) (i32.const 0x358e7470)) +(assert_return (invoke "mul" (i32.const 0x7fffffff) (i32.const 0x7fffffff)) (i32.const 1)) + +(assert_return (invoke "div_s" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_return (invoke "div_s" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_return (invoke "div_s" (i32.const 0) (i32.const -1)) (i32.const 0)) +(assert_return (invoke "div_s" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_return (invoke "div_s" (i32.const 0x80000000) (i32.const 2)) (i32.const 0xc0000000)) +(assert_return (invoke "div_s" (i32.const 0x80000001) (i32.const 1000)) (i32.const 0xffdf3b65)) +(assert_return (invoke "div_s" (i32.const 5) (i32.const 2)) (i32.const 2)) +(assert_return (invoke "div_s" (i32.const -5) (i32.const 2)) (i32.const -2)) +(assert_return (invoke "div_s" (i32.const 5) (i32.const -2)) (i32.const -2)) +(assert_return (invoke "div_s" (i32.const -5) (i32.const -2)) (i32.const 2)) +(assert_return (invoke "div_s" (i32.const 7) (i32.const 3)) (i32.const 2)) +(assert_return (invoke "div_s" (i32.const -7) (i32.const 3)) (i32.const -2)) +(assert_return (invoke "div_s" (i32.const 7) (i32.const -3)) (i32.const -2)) +(assert_return (invoke "div_s" (i32.const -7) (i32.const -3)) (i32.const 2)) +(assert_return (invoke "div_s" (i32.const 11) (i32.const 5)) (i32.const 2)) +(assert_return (invoke "div_s" (i32.const 17) (i32.const 7)) (i32.const 2)) + +(assert_return (invoke "div_u" (i32.const 1) (i32.const 1)) (i32.const 1)) +(assert_return (invoke "div_u" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_return (invoke "div_u" (i32.const -1) (i32.const -1)) (i32.const 1)) +(assert_return (invoke "div_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 0)) +(assert_return (invoke "div_u" (i32.const 0x80000000) (i32.const 2)) (i32.const 0x40000000)) +(assert_return (invoke "div_u" (i32.const 0x8ff00ff0) (i32.const 0x10001)) (i32.const 0x8fef)) +(assert_return (invoke "div_u" (i32.const 0x80000001) (i32.const 1000)) (i32.const 0x20c49b)) +(assert_return (invoke "div_u" (i32.const 5) (i32.const 2)) (i32.const 2)) +(assert_return (invoke "div_u" (i32.const -5) (i32.const 2)) (i32.const 0x7ffffffd)) +(assert_return (invoke "div_u" (i32.const 5) (i32.const -2)) (i32.const 0)) +(assert_return (invoke "div_u" (i32.const -5) (i32.const -2)) (i32.const 0)) +(assert_return (invoke "div_u" (i32.const 7) (i32.const 3)) (i32.const 2)) +(assert_return (invoke "div_u" (i32.const 11) (i32.const 5)) (i32.const 2)) +(assert_return (invoke "div_u" (i32.const 17) (i32.const 7)) (i32.const 2)) + +(assert_return (invoke "rem_s" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0)) +(assert_return (invoke "rem_s" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_return (invoke "rem_s" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_return (invoke "rem_s" (i32.const 0) (i32.const -1)) (i32.const 0)) +(assert_return (invoke "rem_s" (i32.const -1) (i32.const -1)) (i32.const 0)) +(assert_return (invoke "rem_s" (i32.const 0x80000000) (i32.const -1)) (i32.const 0)) +(assert_return (invoke "rem_s" (i32.const 0x80000000) (i32.const 2)) (i32.const 0)) +(assert_return (invoke "rem_s" (i32.const 0x80000001) (i32.const 1000)) (i32.const -647)) +(assert_return (invoke "rem_s" (i32.const 5) (i32.const 2)) (i32.const 1)) +(assert_return (invoke "rem_s" (i32.const -5) (i32.const 2)) (i32.const -1)) +(assert_return (invoke "rem_s" (i32.const 5) (i32.const -2)) (i32.const 1)) +(assert_return (invoke "rem_s" (i32.const -5) (i32.const -2)) (i32.const -1)) +(assert_return (invoke "rem_s" (i32.const 7) (i32.const 3)) (i32.const 1)) +(assert_return (invoke "rem_s" (i32.const -7) (i32.const 3)) (i32.const -1)) +(assert_return (invoke "rem_s" (i32.const 7) (i32.const -3)) (i32.const 1)) +(assert_return (invoke "rem_s" (i32.const -7) (i32.const -3)) (i32.const -1)) +(assert_return (invoke "rem_s" (i32.const 11) (i32.const 5)) (i32.const 1)) +(assert_return (invoke "rem_s" (i32.const 17) (i32.const 7)) (i32.const 3)) + +(assert_return (invoke "rem_u" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_return (invoke "rem_u" (i32.const 0) (i32.const 1)) (i32.const 0)) +(assert_return (invoke "rem_u" (i32.const -1) (i32.const -1)) (i32.const 0)) +(assert_return (invoke "rem_u" (i32.const 0x80000000) (i32.const -1)) (i32.const 0x80000000)) +(assert_return (invoke "rem_u" (i32.const 0x80000000) (i32.const 2)) (i32.const 0)) +(assert_return (invoke "rem_u" (i32.const 0x8ff00ff0) (i32.const 0x10001)) (i32.const 0x8001)) +(assert_return (invoke "rem_u" (i32.const 0x80000001) (i32.const 1000)) (i32.const 649)) +(assert_return (invoke "rem_u" (i32.const 5) (i32.const 2)) (i32.const 1)) +(assert_return (invoke "rem_u" (i32.const -5) (i32.const 2)) (i32.const 1)) +(assert_return (invoke "rem_u" (i32.const 5) (i32.const -2)) (i32.const 5)) +(assert_return (invoke "rem_u" (i32.const -5) (i32.const -2)) (i32.const -5)) +(assert_return (invoke "rem_u" (i32.const 7) (i32.const 3)) (i32.const 1)) +(assert_return (invoke "rem_u" (i32.const 11) (i32.const 5)) (i32.const 1)) +(assert_return (invoke "rem_u" (i32.const 17) (i32.const 7)) (i32.const 3)) diff --git a/tests/specification/run.rs b/tests/specification/run.rs index 8a87f124..d52b8de2 100644 --- a/tests/specification/run.rs +++ b/tests/specification/run.rs @@ -1,72 +1,218 @@ -use wasm::{validate, value::{InteropValue, InteropValueList, Value}, RuntimeInstance}; - -pub fn run_spec_test(filepath: &str) { - let contents = std::fs::read_to_string(filepath) - .expect("Failed to read .wast file"); - let buf = wast::parser::ParseBuffer::new(&contents) - .expect("Lexer failed for .wast file"); - let wast = wast::parser::parse::(&buf) - .expect("Failed to parse .wast file"); - - // We need to keep the wasm_bytes in-scope for the lifetime of the interpeter. - // As such, we hoist the bytes into an Option, and assign it once a module directive is found. - #[allow(unused_assignments)] - let mut wasm_bytes = None; - let mut interpeter = None; - - for directive in wast.directives { - match directive { - wast::WastDirective::Wat(mut quoted) => { - wasm_bytes = Some(quoted.encode().expect("Failed to encode module into bytes")); - let validation_info = validate(wasm_bytes.as_ref().unwrap()).expect("validation failed"); - interpeter = Some(RuntimeInstance::new(&validation_info).expect("instantiation failed")); - }, - wast::WastDirective::AssertReturn { span: _, exec, results } => { - if let Some(interpeter) = interpeter.as_mut() { - execute_assert_return(interpeter, exec, results) - } else { - todo!() - } - }, - _ => todo!(), - } - } -} - -pub fn execute_assert_return(interpeter: &mut RuntimeInstance, exec: wast::WastExecute, results: Res) { - match exec { - wast::WastExecute::Invoke(invoke_info) => { - let x = interpeter.invoke_named::<_, Res>(invoke_info.name, params_to_interop(invoke_info.args)).unwrap(); - assert_eq!(x, results); - }, - wast::WastExecute::Get { span: _, module: _, global: _ } => todo!(), - wast::WastExecute::Wat(_) => todo!(), - } -} - -pub fn params_to_interop(args: Vec) -> impl InteropValueList { - match args.len() { - 1 => { - return param_to_primitive(&args[0]) - } - _ => todo!() - } -} - -pub fn param_to_primitive(arg: &wast::WastArg) -> impl InteropValue { - match arg { - wast::WastArg::Core(core_arg) => { - match core_arg { - wast::core::WastArgCore::I32(val) => val, - wast::core::WastArgCore::I64(val) => val, - wast::core::WastArgCore::F32(val) => todo!(), - wast::core::WastArgCore::F64(val) => todo!(), - wast::core::WastArgCore::V128(val) => todo!(), - wast::core::WastArgCore::RefNull(_) => todo!(), - wast::core::WastArgCore::RefExtern(_) => todo!(), - wast::core::WastArgCore::RefHost(_) => todo!(), - } - }, - wast::WastArg::Component(_) => todo!(), - } -} +use log::debug; +use wasm::{ + validate, + value::{InteropValueList, Value}, + RuntimeInstance, +}; + + +pub fn run_spec_test(filepath: &str) { + let contents = std::fs::read_to_string(filepath).expect("Failed to read .wast file"); + let buf = wast::parser::ParseBuffer::new(&contents).expect("Lexer failed for .wast file"); + let wast = wast::parser::parse::(&buf).expect("Failed to parse .wast file"); + + // We need to keep the wasm_bytes in-scope for the lifetime of the interpeter. + // As such, we hoist the bytes into an Option, and assign it once a module directive is found. + #[allow(unused_assignments)] + let mut wasm_bytes = None; + let mut interpeter = None; + + for directive in wast.directives { + match directive { + wast::WastDirective::Wat(mut quoted) => { + wasm_bytes = Some(quoted.encode().expect("Failed to encode module into bytes")); + let validation_info = + validate(wasm_bytes.as_ref().unwrap()).expect("validation failed"); + interpeter = + Some(RuntimeInstance::new(&validation_info).expect("instantiation failed")); + } + wast::WastDirective::AssertReturn { + span: _, + exec, + results, + } => { + if let Some(interpeter) = interpeter.as_mut() { + execute_assert_return(interpeter, exec, Results::new(results)); + } else { + todo!() + } + } + _ => todo!("{:?}", directive), + } + } +} + +pub fn execute_assert_return( + interpeter: &mut RuntimeInstance, + exec: wast::WastExecute, + results: Res, +) { + match exec { + wast::WastExecute::Invoke(invoke_info) => { + let actual = interpeter + .invoke_named::<_, Res>(invoke_info.name, Args::new(invoke_info.args)) + .unwrap().into_values(); + + let expected = results.into_values(); + + debug!("actual: {:?}", actual); + debug!("expected: {:?}", expected); + + assert_eq!(actual, expected); + } + wast::WastExecute::Get { + span: _, + module: _, + global: _, + } => todo!(), + wast::WastExecute::Wat(_) => todo!(), + } +} + +struct Args<'a> { + args: Vec>, + types: Vec, +} + +impl<'a> Args<'a> { + pub fn new(args: Vec>) -> Args<'a> { + let types = args.iter().map(arg_to_valtype).collect(); + Self { args, types } + } +} + +impl InteropValueList for Args<'_> { + const TYS: &'static [wasm::ValType] = &[]; + + fn into_values(self) -> Vec { + self.args.into_iter().map(arg_to_value).collect() + } + + fn from_values(values: impl Iterator) -> Self { + Self::new(values.map(value_to_arg).collect()) + } + + fn get_types(&self) -> &[wasm::ValType] { + &self.types + } +} + +struct Results<'a> { + results: Vec>, + types: Vec, +} + +impl<'a> Results<'a> { + pub fn new(results: Vec>) -> Results<'a> { + let types = results.iter().map(result_to_valtype).collect(); + Self { results, types } + } +} + +impl InteropValueList for Results<'_> { + const TYS: &'static [wasm::ValType] = &[]; + + fn into_values(self) -> Vec { + self.results.into_iter().map(result_to_value).collect() + } + + fn from_values(values: impl Iterator) -> Self { + Self::new(values.map(value_to_result).collect()) + } + + fn get_types(&self) -> &[wasm::ValType] { + &self.types + } +} + +pub fn arg_to_value(arg: wast::WastArg) -> Value { + match arg { + wast::WastArg::Core(core_arg) => match core_arg { + wast::core::WastArgCore::I32(val) => Value::I32(val as u32), + wast::core::WastArgCore::I64(val) => Value::I64(val as u64), + wast::core::WastArgCore::F32(_) => todo!(), + wast::core::WastArgCore::F64(_) => todo!(), + wast::core::WastArgCore::V128(_) => todo!(), + wast::core::WastArgCore::RefNull(_) => todo!(), + wast::core::WastArgCore::RefExtern(_) => todo!(), + wast::core::WastArgCore::RefHost(_) => todo!(), + }, + wast::WastArg::Component(_) => todo!(), + } +} + +pub fn value_to_arg(value: Value) -> wast::WastArg<'static> { + match value { + Value::I32(val) => wast::WastArg::Core(wast::core::WastArgCore::I32(val as i32)), + Value::I64(val) => wast::WastArg::Core(wast::core::WastArgCore::I64(val as i64)), + } +} + +pub fn arg_to_valtype(arg: &wast::WastArg) -> wasm::ValType { + match arg { + wast::WastArg::Core(core_arg) => match core_arg { + wast::core::WastArgCore::I32(_) => wasm::ValType::NumType(wasm::NumType::I32), + wast::core::WastArgCore::I64(_) => wasm::ValType::NumType(wasm::NumType::I64), + wast::core::WastArgCore::F32(_) => todo!(), + wast::core::WastArgCore::F64(_) => todo!(), + wast::core::WastArgCore::V128(_) => todo!(), + wast::core::WastArgCore::RefNull(_) => todo!(), + wast::core::WastArgCore::RefExtern(_) => todo!(), + wast::core::WastArgCore::RefHost(_) => todo!(), + }, + wast::WastArg::Component(_) => todo!(), + } +} + +fn result_to_value(result: wast::WastRet) -> Value { + match result { + wast::WastRet::Core(core_arg) => match core_arg { + wast::core::WastRetCore::I32(val) => Value::I32(val as u32), + wast::core::WastRetCore::I64(val) => Value::I64(val as u64), + wast::core::WastRetCore::F32(_) => todo!(), + wast::core::WastRetCore::F64(_) => todo!(), + wast::core::WastRetCore::V128(_) => todo!(), + wast::core::WastRetCore::RefNull(_) => todo!(), + wast::core::WastRetCore::RefExtern(_) => todo!(), + wast::core::WastRetCore::RefHost(_) => todo!(), + wast::core::WastRetCore::RefFunc(_) => todo!(), + wast::core::WastRetCore::RefAny => todo!(), + wast::core::WastRetCore::RefEq => todo!(), + wast::core::WastRetCore::RefArray => todo!(), + wast::core::WastRetCore::RefStruct => todo!(), + wast::core::WastRetCore::RefI31 => todo!(), + wast::core::WastRetCore::Either(_) => todo!(), + }, + wast::WastRet::Component(_) => todo!(), + } +} + +pub fn value_to_result(value: Value) -> wast::WastRet<'static> { + match value { + Value::I32(val) => wast::WastRet::Core(wast::core::WastRetCore::I32(val as i32)), + Value::I64(val) => wast::WastRet::Core(wast::core::WastRetCore::I64(val as i64)), + } +} + +pub fn result_to_valtype(result: &wast::WastRet) -> wasm::ValType { + match result { + wast::WastRet::Core(core_arg) => match core_arg { + wast::core::WastRetCore::I32(_) => wasm::ValType::NumType(wasm::NumType::I32), + wast::core::WastRetCore::I64(_) => wasm::ValType::NumType(wasm::NumType::I64), + wast::core::WastRetCore::F32(_) => todo!(), + wast::core::WastRetCore::F64(_) => todo!(), + wast::core::WastRetCore::V128(_) => todo!(), + wast::core::WastRetCore::RefNull(_) => todo!(), + wast::core::WastRetCore::RefExtern(_) => todo!(), + wast::core::WastRetCore::RefHost(_) => todo!(), + wast::core::WastRetCore::RefFunc(_) => todo!(), + wast::core::WastRetCore::RefAny => todo!(), + wast::core::WastRetCore::RefEq => todo!(), + wast::core::WastRetCore::RefArray => todo!(), + wast::core::WastRetCore::RefStruct => todo!(), + wast::core::WastRetCore::RefI31 => todo!(), + wast::core::WastRetCore::Either(_) => todo!(), + }, + wast::WastRet::Component(_) => todo!(), + } +}