From 9b98a211cdd2182d3979c14764258d64eb9c02e3 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 20 Feb 2020 12:15:23 +0100 Subject: [PATCH] feat(interface-types) Replace nom by wast for decoding WIT's text format. --- Cargo.toml | 3 +- src/ast.rs | 2 +- src/decoders/wat.rs | 743 +++++++++++++++++++++++++------------------- 3 files changed, 420 insertions(+), 328 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a3d2474..74a2b8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,5 @@ repository = "https://github.com/wasmerio/wasmer" edition = "2018" [dependencies] -nom = "5.1" \ No newline at end of file +nom = "5.1" +wast = "8.0" \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index 1a9c89b..6bb7e9e 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -190,7 +190,7 @@ pub struct Forward<'input> { /// Represents a set of interfaces, i.e. it entirely describes a WIT /// definition. -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Default, Debug)] pub struct Interfaces<'input> { /// All the exported functions. pub exports: Vec>, diff --git a/src/decoders/wat.rs b/src/decoders/wat.rs index 264b6fc..1c85e3f 100644 --- a/src/decoders/wat.rs +++ b/src/decoders/wat.rs @@ -3,285 +3,331 @@ #![allow(unused)] use crate::ast::*; -use nom::{ - branch::alt, - bytes::complete::{escaped, tag, take_while1}, - character::complete::{alphanumeric1, char, one_of}, - combinator::{cut, map, opt, value}, - error::ParseError, - multi::many0, - sequence::{delimited, preceded, terminated, tuple}, - AsChar, IResult, +use wast::{ + parser::{Cursor, Parse, Parser, Peek, Result}, + Id, }; -/// Parse a whitespace. -fn whitespace<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, &'input str, E> { - let whitespaces = " \t\r\n"; +mod kw { + pub use wast::{ + custom_keyword, + kw::{anyref, export, f32, f64, func, i32, i64, import, param, result}, + }; - take_while1(move |c| whitespaces.contains(c))(input) + custom_keyword!(adapt); + custom_keyword!(forward); + custom_keyword!(int); + custom_keyword!(float); + custom_keyword!(any); + custom_keyword!(string); + custom_keyword!(seq); } -/// Parse an `InterfaceType`. -fn interface_type<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, InterfaceType, E> { - let int = value(InterfaceType::Int, tag("Int")); - let float = value(InterfaceType::Float, tag("Float")); - let any = value(InterfaceType::Any, tag("Any")); - let string = value(InterfaceType::String, tag("String")); - let seq = value(InterfaceType::Seq, tag("Seq")); - let r#i32 = value(InterfaceType::I32, tag("i32")); - let r#i64 = value(InterfaceType::I64, tag("i64")); - let r#f32 = value(InterfaceType::F32, tag("f32")); - let r#f64 = value(InterfaceType::F64, tag("f64")); - let anyref = value(InterfaceType::AnyRef, tag("anyref")); +/// Issue: Uppercased keyword aren't supported for the moment. +impl Parse<'_> for InterfaceType { + fn parse(parser: Parser<'_>) -> Result { + let mut lookahead = parser.lookahead1(); - alt(( - int, float, any, string, seq, r#i32, r#i64, r#f32, r#f64, anyref, - ))(input) + if lookahead.peek::() { + parser.parse::()?; + + Ok(InterfaceType::Int) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(InterfaceType::Float) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(InterfaceType::Any) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(InterfaceType::String) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(InterfaceType::Seq) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(InterfaceType::I32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(InterfaceType::I64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(InterfaceType::F32) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(InterfaceType::F64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(InterfaceType::AnyRef) + } else { + Err(lookahead.error()) + } + } } -/// Parse a string. -fn string<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, &'input str, E> { - escaped(alphanumeric1, '\\', one_of(r#""\"#))(input) +struct AtInterface; + +impl Peek for AtInterface { + fn peek(cursor: Cursor<'_>) -> bool { + cursor.reserved().map(|(string, _)| string) == Some("@interface") + } + + fn display() -> &'static str { + "`@interface`" + } } -/// Parse a `(param …)`. -fn param<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, Vec, E> { - delimited( - char('('), - preceded( - opt(whitespace), - preceded(tag("param"), many0(preceded(whitespace, interface_type))), - ), - char(')'), - )(input) +impl Parse<'_> for AtInterface { + fn parse(parser: Parser<'_>) -> Result { + parser.step(|cursor| { + if let Some(("@interface", rest)) = cursor.reserved() { + return Ok((AtInterface, rest)); + } + + Err(cursor.error("expected `@interface`")) + }) + } } -/// Parse a `(result …)`. -fn result<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, Vec, E> { - delimited( - char('('), - preceded( - opt(whitespace), - preceded(tag("result"), many0(preceded(whitespace, interface_type))), - ), - char(')'), - )(input) +#[derive(PartialEq, Debug)] +enum FunctionType { + Input(Vec), + Output(Vec), } -/// Parse an `Export`. -fn export<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, Export, E> { - map( - delimited( - char('('), - preceded( - opt(whitespace), - preceded( - tag("@interface"), - preceded( - whitespace, - preceded( - tag("export"), - tuple(( - preceded( - whitespace, - preceded(char('"'), cut(terminated(string, char('"')))), - ), - opt(preceded(whitespace, param)), - opt(preceded(whitespace, result)), - )), - ), - ), - ), - ), - char(')'), - ), - |(name, input_types, output_types)| Export { +impl Parse<'_> for FunctionType { + fn parse(parser: Parser<'_>) -> Result { + parser.parens(|parser| { + let mut lookahead = parser.lookahead1(); + + if lookahead.peek::() { + parser.parse::()?; + + let mut inputs = vec![]; + + while !parser.is_empty() { + inputs.push(parser.parse()?); + } + + Ok(FunctionType::Input(inputs)) + } else if lookahead.peek::() { + parser.parse::()?; + + let mut outputs = vec![]; + + while !parser.is_empty() { + outputs.push(parser.parse()?); + } + + Ok(FunctionType::Output(outputs)) + } else { + Err(lookahead.error()) + } + }) + } +} + +#[derive(PartialEq, Debug)] +enum Interface<'a> { + Export(Export<'a>), + Type(Type<'a>), + Import(Import<'a>), + Adapter(Adapter<'a>), + Forward(Forward<'a>), +} + +impl<'a> Parse<'a> for Interface<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parens(|parser| { + let mut lookahead = parser.lookahead1(); + + if lookahead.peek::() { + parser.parse::()?; + + let mut lookahead = parser.lookahead1(); + + if lookahead.peek::() { + Ok(Interface::Export(parser.parse()?)) + } else if lookahead.peek::() { + Ok(Interface::Import(parser.parse()?)) + } else if lookahead.peek::() { + Ok(Interface::Adapter(parser.parse()?)) + } else if lookahead.peek::() { + Ok(Interface::Forward(parser.parse()?)) + } else { + Err(lookahead.error()) + } + } else { + Err(lookahead.error()) + } + }) + } +} + +impl<'a> Parse<'a> for Export<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let name = parser.parse()?; + + let mut input_types = vec![]; + let mut output_types = vec![]; + + while !parser.is_empty() { + let function_type = parser.parse::()?; + + match function_type { + FunctionType::Input(mut inputs) => input_types.append(&mut inputs), + FunctionType::Output(mut outputs) => output_types.append(&mut outputs), + } + } + + Ok(Export { name, - input_types: input_types.unwrap_or_else(|| vec![]), - output_types: output_types.unwrap_or_else(|| vec![]), - }, - )(input) + input_types, + output_types, + }) + } } -/// Parse an `(import "ns" "foo")`. -fn import_qualifier<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, (&'input str, &'input str), E> { - delimited( - char('('), - preceded( - opt(whitespace), - preceded( - tag("import"), - tuple(( - preceded( - whitespace, - preceded(char('"'), cut(terminated(string, char('"')))), - ), - preceded( - whitespace, - preceded(char('"'), cut(terminated(string, char('"')))), - ), - )), - ), - ), - char(')'), - )(input) -} +impl<'a> Parse<'a> for Import<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + parser.parse::()?; -/// Parse an `(export "foo")`. -fn export_qualifier<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, &'input str, E> { - delimited( - char('('), - preceded( - opt(whitespace), - preceded( - tag("export"), - preceded( - whitespace, - preceded(char('"'), cut(terminated(string, char('"')))), - ), - ), - ), - char(')'), - )(input) -} + let (namespace, name) = parser.parens(|parser| { + parser.parse::()?; -/// Parse a `$…`. -fn index_variable<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, &'input str, E> { - preceded( - char('$'), - take_while1(move |c: char| c.is_alphanum() || c == '_'), - )(input) -} + Ok((parser.parse()?, parser.parse()?)) + })?; + let mut input_types = vec![]; + let mut output_types = vec![]; -/// Parse an `Import`. -fn import<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, Import, E> { - map( - delimited( - char('('), - preceded( - opt(whitespace), - preceded( - tag("@interface"), - preceded( - whitespace, - preceded( - tag("func"), - tuple(( - opt(preceded(whitespace, index_variable)), - preceded(whitespace, import_qualifier), - opt(preceded(whitespace, param)), - opt(preceded(whitespace, result)), - )), - ), - ), - ), - ), - char(')'), - ), - |(_index, (namespace, name), input_types, output_types)| Import { + while !parser.is_empty() { + let function_type = parser.parse::()?; + + match function_type { + FunctionType::Input(mut inputs) => input_types.append(&mut inputs), + FunctionType::Output(mut outputs) => output_types.append(&mut outputs), + } + } + + Ok(Import { namespace, name, - input_types: input_types.unwrap_or_else(|| vec![]), - output_types: output_types.unwrap_or_else(|| vec![]), - }, - )(input) + input_types, + output_types, + }) + } } -/// Parse an `Adapter`. -fn adapter<'input, E: ParseError<&'input str>>( - input: &'input str, -) -> IResult<&'input str, Adapter, E> { - fn adapter_import<'input, E: ParseError<&'input str>>( - input: &'input str, - ) -> IResult<&'input str, Adapter, E> { - map( - tuple(( - preceded(whitespace, import_qualifier), - opt(preceded(whitespace, param)), - opt(preceded(whitespace, result)), - )), - |((namespace, name), input_types, output_types)| Adapter::Import { +impl<'a> Parse<'a> for Adapter<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + + let (kind, namespace, name) = parser.parens(|parser| { + let mut lookahead = parser.lookahead1(); + + if lookahead.peek::() { + parser.parse::()?; + + Ok((AdapterKind::Import, parser.parse()?, parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok((AdapterKind::Export, "", parser.parse()?)) + } else { + Err(lookahead.error()) + } + })?; + let mut input_types = vec![]; + let mut output_types = vec![]; + + while !parser.is_empty() { + let function_type = parser.parse::()?; + + match function_type { + FunctionType::Input(mut inputs) => input_types.append(&mut inputs), + FunctionType::Output(mut outputs) => output_types.append(&mut outputs), + } + } + + Ok(match kind { + AdapterKind::Import => Adapter::Import { namespace, name, - input_types: input_types.unwrap_or_else(|| vec![]), - output_types: output_types.unwrap_or_else(|| vec![]), + input_types, + output_types, instructions: vec![], }, - )(input) - } - fn adapter_export<'input, E: ParseError<&'input str>>( - input: &'input str, - ) -> IResult<&'input str, Adapter, E> { - map( - tuple(( - preceded(whitespace, export_qualifier), - opt(preceded(whitespace, param)), - opt(preceded(whitespace, result)), - )), - |(name, input_types, output_types)| Adapter::Export { + AdapterKind::Export => Adapter::Export { name, - input_types: input_types.unwrap_or_else(|| vec![]), - output_types: output_types.unwrap_or_else(|| vec![]), + input_types, + output_types, instructions: vec![], }, - )(input) - } - delimited( - char('('), - preceded( - opt(whitespace), - preceded( - tag("@interface"), - preceded( - whitespace, - preceded(tag("adapt"), alt((adapter_import, adapter_export))), - ), - ), - ), - char(')'), - )(input) + _ => unimplemented!("Adapter of kind “helper” is not implemented yet."), + }) + } +} + +impl<'a> Parse<'a> for Forward<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + + let name = parser.parens(|parser| { + parser.parse::()?; + + Ok((parser.parse()?)) + })?; + + Ok(Forward { name }) + } +} + +impl<'a> Parse<'a> for Interfaces<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut interfaces: Interfaces = Default::default(); + + while !parser.is_empty() { + let interface = parser.parse::()?; + + match interface { + Interface::Export(export) => interfaces.exports.push(export), + Interface::Type(ty) => interfaces.types.push(ty), + Interface::Import(import) => interfaces.imports.push(import), + Interface::Adapter(adapter) => interfaces.adapters.push(adapter), + Interface::Forward(forward) => interfaces.forwards.push(forward), + } + } + + Ok(interfaces) + } } #[cfg(test)] mod tests { use super::*; + use wast::parser::{self, ParseBuffer}; - #[test] - fn test_whitespace() { - let inputs = vec![" a", " a", "\n a", "\r\n a"]; - let outputs = vec![" ", " ", "\n ", "\r\n "]; - - for (nth, input) in inputs.iter().enumerate() { - assert_eq!(whitespace::<()>(input), Ok(("a", outputs[nth]))); - } + fn buffer(input: &str) -> ParseBuffer { + ParseBuffer::new(input).expect("Failed to build the parser buffer.") } #[test] fn test_interface_type() { let inputs = vec![ - "Int", "Float", "Any", "String", "Seq", "i32", "i64", "f32", "f64", "anyref", + "int", "float", "any", "string", "seq", "i32", "i64", "f32", "f64", "anyref", ]; let outputs = vec![ InterfaceType::Int, @@ -299,208 +345,253 @@ mod tests { assert_eq!(inputs.len(), outputs.len()); for (nth, input) in inputs.iter().enumerate() { - assert_eq!(interface_type::<()>(input), Ok(("", outputs[nth]))); + assert_eq!( + parser::parse::(&buffer(input)).unwrap(), + outputs[nth] + ); } } #[test] fn test_param_empty() { - let input = "(param)"; - let output = vec![]; + let input = buffer("(param)"); + let output = FunctionType::Input(vec![]); - assert_eq!(param::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_param() { - let input = "(param i32 String)"; - let output = vec![InterfaceType::I32, InterfaceType::String]; + let input = buffer("(param i32 string)"); + let output = FunctionType::Input(vec![InterfaceType::I32, InterfaceType::String]); - assert_eq!(param::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_result_empty() { - let input = "(result)"; - let output = vec![]; + let input = buffer("(result)"); + let output = FunctionType::Output(vec![]); - assert_eq!(result::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_result() { - let input = "(result i32 String)"; - let output = vec![InterfaceType::I32, InterfaceType::String]; + let input = buffer("(result i32 string)"); + let output = FunctionType::Output(vec![InterfaceType::I32, InterfaceType::String]); - assert_eq!(result::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_export_with_no_param_no_result() { - let input = r#"(@interface export "foo")"#; - let output = Export { - name: "foo", - input_types: vec![], - output_types: vec![], - }; - - assert_eq!(export::<()>(input), Ok(("", output))); + let input = buffer(r#"(@interface export "foo")"#); } #[test] fn test_export_with_some_param_no_result() { - let input = r#"(@interface export "foo" (param i32))"#; - let output = Export { + let input = buffer(r#"(@interface export "foo" (param i32))"#); + let output = Interface::Export(Export { name: "foo", input_types: vec![InterfaceType::I32], output_types: vec![], - }; + }); - assert_eq!(export::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_export_with_no_param_some_result() { - let input = r#"(@interface export "foo" (result i32))"#; - let output = Export { + let input = buffer(r#"(@interface export "foo" (result i32))"#); + let output = Interface::Export(Export { name: "foo", input_types: vec![], output_types: vec![InterfaceType::I32], - }; + }); - assert_eq!(export::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_export_with_some_param_some_result() { - let input = r#"(@interface export "foo" (param String) (result i32 i32))"#; - let output = Export { + let input = buffer(r#"(@interface export "foo" (param string) (result i32 i32))"#); + let output = Interface::Export(Export { name: "foo", input_types: vec![InterfaceType::String], output_types: vec![InterfaceType::I32, InterfaceType::I32], - }; + }); - assert_eq!(export::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_export_escaped_name() { - let input = r#"(@interface export "fo\"o")"#; - let output = Export { - name: r#"fo\"o"#, + let input = buffer(r#"(@interface export "fo\"o")"#); + let output = Interface::Export(Export { + name: r#"fo"o"#, input_types: vec![], output_types: vec![], - }; + }); - assert_eq!(export::<()>(input), Ok(("", output))); - } - - #[test] - fn test_import_qualifier() { - let input = r#"(import "ns" "name")"#; - let output = ("ns", "name"); - - assert_eq!(import_qualifier::<()>(input), Ok(("", output))); - } - - #[test] - fn test_export_qualifier() { - let input = r#"(export "name")"#; - let output = "name"; - - assert_eq!(export_qualifier::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_import_with_no_param_no_result() { - let input = r#"(@interface func $ns_foo (import "ns" "foo"))"#; - let output = Import { + let input = buffer(r#"(@interface func $ns_foo (import "ns" "foo"))"#); + let output = Interface::Import(Import { namespace: "ns", name: "foo", input_types: vec![], output_types: vec![], - }; + }); - assert_eq!(import::<()>(input), Ok(("", output))); - } - - #[test] - fn test_import_with_no_index_variable_no_param_no_result() { - let input = r#"(@interface func (import "ns" "foo"))"#; - let output = Import { - namespace: "ns", - name: "foo", - input_types: vec![], - output_types: vec![], - }; - - assert_eq!(import::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_import_with_some_param_no_result() { - let input = r#"(@interface func $ns_foo (import "ns" "foo") (param i32))"#; - let output = Import { + let input = buffer(r#"(@interface func $ns_foo (import "ns" "foo") (param i32))"#); + let output = Interface::Import(Import { namespace: "ns", name: "foo", input_types: vec![InterfaceType::I32], output_types: vec![], - }; + }); - assert_eq!(import::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_import_with_no_param_some_result() { - let input = r#"(@interface func $ns_foo (import "ns" "foo") (result i32))"#; - let output = Import { + let input = buffer(r#"(@interface func $ns_foo (import "ns" "foo") (result i32))"#); + let output = Interface::Import(Import { namespace: "ns", name: "foo", input_types: vec![], output_types: vec![InterfaceType::I32], - }; + }); - assert_eq!(import::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_import_with_some_param_some_result() { - let input = - r#"(@interface func $ns_foo (import "ns" "foo") (param String) (result i32 i32))"#; - let output = Import { + let input = buffer( + r#"(@interface func $ns_foo (import "ns" "foo") (param string) (result i32 i32))"#, + ); + let output = Interface::Import(Import { namespace: "ns", name: "foo", input_types: vec![InterfaceType::String], output_types: vec![InterfaceType::I32, InterfaceType::I32], - }; + }); - assert_eq!(import::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_adapter_import() { - let input = r#"(@interface adapt (import "ns" "foo") (param i32 i32) (result i32))"#; - let output = Adapter::Import { + let input = + buffer(r#"(@interface adapt (import "ns" "foo") (param i32 i32) (result i32))"#); + let output = Interface::Adapter(Adapter::Import { namespace: "ns", name: "foo", input_types: vec![InterfaceType::I32, InterfaceType::I32], output_types: vec![InterfaceType::I32], instructions: vec![], - }; + }); - assert_eq!(adapter::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] fn test_adapter_export() { - let input = r#"(@interface adapt (export "foo") (param i32 i32) (result i32))"#; - let output = Adapter::Export { + let input = buffer(r#"(@interface adapt (export "foo") (param i32 i32) (result i32))"#); + let output = Interface::Adapter(Adapter::Export { name: "foo", input_types: vec![InterfaceType::I32, InterfaceType::I32], output_types: vec![InterfaceType::I32], instructions: vec![], + }); + + assert_eq!(parser::parse::(&input).unwrap(), output); + } + #[test] + fn test_forward() { + let input = buffer(r#"(@interface forward (export "foo"))"#); + let output = Interface::Forward(Forward { name: "foo" }); + + assert_eq!(parser::parse::(&input).unwrap(), output); + } + + #[test] + fn test_interfaces() { + let input = buffer( + r#"(@interface export "foo" + (param i32)) + +(@interface export "bar") + +(@interface func $ns_foo (import "ns" "foo") + (result i32)) + +(@interface func $ns_bar (import "ns" "bar")) + +(@interface adapt (import "ns" "foo") + (param i32)) + +(@interface adapt (export "bar")) + +(@interface forward (export "main"))"#, + ); + let output = Interfaces { + exports: vec![ + Export { + name: "foo", + input_types: vec![InterfaceType::I32], + output_types: vec![], + }, + Export { + name: "bar", + input_types: vec![], + output_types: vec![], + }, + ], + types: vec![], + imports: vec![ + Import { + namespace: "ns", + name: "foo", + input_types: vec![], + output_types: vec![InterfaceType::I32], + }, + Import { + namespace: "ns", + name: "bar", + input_types: vec![], + output_types: vec![], + }, + ], + adapters: vec![ + Adapter::Import { + namespace: "ns", + name: "foo", + input_types: vec![InterfaceType::I32], + output_types: vec![], + instructions: vec![], + }, + Adapter::Export { + name: "bar", + input_types: vec![], + output_types: vec![], + instructions: vec![], + }, + ], + forwards: vec![Forward { name: "main" }], }; - assert_eq!(adapter::<()>(input), Ok(("", output))); + assert_eq!(parser::parse::(&input).unwrap(), output); } }