summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/parser/src/error.rs8
-rw-r--r--crates/tinywasm/Cargo.toml1
-rw-r--r--crates/tinywasm/src/module.rs6
-rw-r--r--crates/tinywasm/tests/mvp.rs89
-rw-r--r--crates/types/src/lib.rs6
-rw-r--r--crates/wasm-testsuite/README.md4
6 files changed, 91 insertions, 23 deletions
diff --git a/crates/parser/src/error.rs b/crates/parser/src/error.rs
index a5c807a..acacfa0 100644
--- a/crates/parser/src/error.rs
+++ b/crates/parser/src/error.rs
@@ -1,8 +1,9 @@
-use core::fmt::Debug;
+use core::fmt::{Debug, Display};
use alloc::string::{String, ToString};
use wasmparser::Encoding;
+#[derive(Debug)]
pub enum ParseError {
InvalidType,
UnsupportedSection(String),
@@ -16,7 +17,7 @@ pub enum ParseError {
Other(String),
}
-impl Debug for ParseError {
+impl Display for ParseError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::InvalidType => write!(f, "invalid type"),
@@ -37,6 +38,9 @@ impl Debug for ParseError {
}
}
+#[cfg(any(feature = "std", all(not(feature = "std"), nightly)))]
+impl crate::std::error::Error for ParseError {}
+
impl From<wasmparser::BinaryReaderError> for ParseError {
fn from(value: wasmparser::BinaryReaderError) -> Self {
Self::ParseError {
diff --git a/crates/tinywasm/Cargo.toml b/crates/tinywasm/Cargo.toml
index 1865614..8c9ea50 100644
--- a/crates/tinywasm/Cargo.toml
+++ b/crates/tinywasm/Cargo.toml
@@ -21,6 +21,7 @@ tinywasm-types={version="0.0.3", path="../types", default-features=false}
wasm-testsuite={path="../wasm-testsuite"}
wast={version="69.0"}
owo-colors={version="3.5"}
+eyre={version="0.6"}
[features]
default=["std", "parser", "logging"]
diff --git a/crates/tinywasm/src/module.rs b/crates/tinywasm/src/module.rs
index 885f28c..8c38a89 100644
--- a/crates/tinywasm/src/module.rs
+++ b/crates/tinywasm/src/module.rs
@@ -10,6 +10,12 @@ pub struct Module {
data: TinyWasmModule,
}
+impl From<&TinyWasmModule> for Module {
+ fn from(data: &TinyWasmModule) -> Self {
+ Self { data: data.clone() }
+ }
+}
+
impl From<TinyWasmModule> for Module {
fn from(data: TinyWasmModule) -> Self {
Self { data }
diff --git a/crates/tinywasm/tests/mvp.rs b/crates/tinywasm/tests/mvp.rs
index 87a36d8..c6fe43d 100644
--- a/crates/tinywasm/tests/mvp.rs
+++ b/crates/tinywasm/tests/mvp.rs
@@ -3,7 +3,8 @@ use std::{
fmt::{Debug, Formatter},
};
-use tinywasm::{Error, Result};
+use eyre::{eyre, Result};
+use log::debug;
use tinywasm_types::TinyWasmModule;
use wast::{
lexer::Lexer,
@@ -11,7 +12,7 @@ use wast::{
QuoteWat, Wast,
};
-fn parse_module(mut module: wast::core::Module) -> Result<TinyWasmModule, Error> {
+fn parse_module(mut module: wast::core::Module) -> Result<TinyWasmModule> {
let parser = tinywasm_parser::Parser::new();
Ok(parser.parse_module_bytes(module.encode().expect("failed to encode module"))?)
}
@@ -27,32 +28,34 @@ fn test_mvp() -> Result<()> {
let wast = wasm_testsuite::get_test_wast(group).expect("failed to get test wast");
let wast = std::str::from_utf8(&wast).expect("failed to convert wast to utf8");
- let mut lexer = Lexer::new(&wast);
+ let mut lexer = Lexer::new(wast);
// we need to allow confusing unicode characters since they are technically valid wasm
lexer.allow_confusing_unicode(true);
let buf = ParseBuffer::new_with_lexer(lexer).expect("failed to create parse buffer");
let wast_data = parser::parse::<Wast>(&buf).expect("failed to parse wat");
+ let mut last_module: Option<TinyWasmModule> = None;
for (i, directive) in wast_data.directives.into_iter().enumerate() {
let span = directive.span();
-
use wast::WastDirective::*;
let name = format!("{}-{}", group, i);
+
match directive {
// TODO: needs to support more binary sections
Wat(QuoteWat::Wat(wast::Wat::Module(module))) => {
- let module = std::panic::catch_unwind(|| parse_module(module));
- test_group.add_result(
- &format!("{}-parse", name),
- span,
- match module {
- Ok(Ok(_)) => Ok(()),
- Ok(Err(e)) => Err(e),
- Err(e) => Err(Error::Other(format!("failed to parse module: {:?}", e))),
- },
- );
+ let result = std::panic::catch_unwind(|| parse_module(module))
+ .map_err(|e| eyre!("failed to parse module: {:?}", e))
+ .and_then(|res| res);
+
+ match &result {
+ Err(_) => last_module = None,
+ Ok(m) => last_module = Some(m.clone()),
+ }
+
+ test_group.add_result(&format!("{}-parse", name), span, result.map(|_| ()));
}
+
// these all pass already :)
AssertMalformed {
span,
@@ -64,11 +67,49 @@ fn test_mvp() -> Result<()> {
&format!("{}-malformed", name),
span,
match res {
- Ok(Ok(_)) => Err(Error::Other("expected module to be malformed".to_string())),
+ Ok(Ok(_)) => Err(eyre!("expected module to be malformed")),
Err(_) | Ok(Err(_)) => Ok(()),
},
);
}
+ AssertReturn { span, exec, results: _ } => {
+ let Some(module) = last_module.as_ref() else {
+ // println!("no module found for assert_return: {:?}", exec);
+ continue;
+ };
+
+ let res: Result<Result<()>, _> = std::panic::catch_unwind(|| {
+ let mut store = tinywasm::Store::new();
+ let module = tinywasm::Module::from(module);
+ let instance = module.instantiate(&mut store)?;
+
+ use wast::WastExecute::*;
+ match exec {
+ Wat(_) => return Result::Ok(()), // not used by the testsuite
+ Get { module: _, global: _ } => return Result::Ok(()),
+ Invoke(invoke) => {
+ for arg in invoke.args {
+ let arg = get_tinywasm_wasm_value(arg)?;
+ let _res = instance.get_func(&store, invoke.name)?.call(&mut store, &[arg])?;
+ // TODO: check the result
+ }
+ }
+ }
+
+ Ok(())
+ });
+
+ let res = match res {
+ Err(e) => Err(eyre!("test panicked: {:?}", e)),
+ Ok(Err(e)) => Err(e),
+ Ok(Ok(())) => Ok(()),
+ };
+
+ test_group.add_result(&format!("{}-return", name), span, res);
+ }
+ Invoke(m) => {
+ debug!("invoke: {:?}", m);
+ }
// _ => test_group.add_result(
// &format!("{}-unknown", name),
// span,
@@ -82,13 +123,29 @@ fn test_mvp() -> Result<()> {
if test_suite.failed() {
eprintln!("\n\nfailed one or more tests:\n{:#?}", test_suite);
- Err(Error::Other("failed one or more tests".to_string()))
+ Err(eyre!("failed one or more tests"))
} else {
println!("\n\npassed all tests:\n{:#?}", test_suite);
Ok(())
}
}
+fn get_tinywasm_wasm_value(arg: wast::WastArg) -> Result<tinywasm_types::WasmValue> {
+ let wast::WastArg::Core(arg) = arg else {
+ return Err(eyre!("unsupported arg type"));
+ };
+
+ use tinywasm_types::WasmValue;
+ use wast::core::WastArgCore::*;
+ Ok(match arg {
+ F32(f) => WasmValue::F32(f32::from_bits(f.bits)),
+ F64(f) => WasmValue::F64(f64::from_bits(f.bits)),
+ I32(i) => WasmValue::I32(i),
+ I64(i) => WasmValue::I64(i),
+ _ => return Err(eyre!("unsupported arg type")),
+ })
+}
+
struct TestSuite(BTreeMap<String, TestGroup>);
impl TestSuite {
diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs
index 4e09e00..4defb23 100644
--- a/crates/types/src/lib.rs
+++ b/crates/types/src/lib.rs
@@ -36,7 +36,7 @@ pub use instructions::*;
/// This is the internal representation of a WebAssembly module in TinyWasm.
/// TinyWasmModules are validated before being created, so they are guaranteed to be valid (as long as they were created by TinyWasm).
/// This means you should not trust a TinyWasmModule created by a third party to be valid.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct TinyWasmModule {
/// The version of the WebAssembly module.
pub version: Option<u16>,
@@ -266,7 +266,7 @@ pub struct FuncType {
}
/// A WebAssembly Function
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct Function {
pub ty: TypeAddr,
pub locals: Box<[ValType]>,
@@ -274,7 +274,7 @@ pub struct Function {
}
/// A WebAssembly Module Export
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct Export {
/// The name of the export.
pub name: Box<str>,
diff --git a/crates/wasm-testsuite/README.md b/crates/wasm-testsuite/README.md
index c3dcde2..51d574c 100644
--- a/crates/wasm-testsuite/README.md
+++ b/crates/wasm-testsuite/README.md
@@ -7,9 +7,9 @@ This crate embeds the latest version of the [WebAssembly Test Suite](https://git
```rust
use wasm_testsuite::{MVP_TESTS, get_test_wast};
-wasm_testsuite::MVP_TESTS.iter().for_each(|test| {
+MVP_TESTS.iter().for_each(|test| {
let wast_bytes = get_test_wast(test).expect("Failed to get wast bytes");
- let wast = std::str::from_utf8(&wast).expect("failed to convert wast to utf8");
+ let wast = std::str::from_utf8(&wast_bytes).expect("failed to convert wast to utf8");
// Do something with the wast (e.g. parse it using the `wast` crate)
});