feat(interface-types) Replace nom by wast for decoding WIT's text format.

This commit is contained in:
Ivan Enderlin 2020-02-20 12:15:23 +01:00
parent e90365beb1
commit 9b98a211cd
3 changed files with 420 additions and 328 deletions

View File

@ -8,4 +8,5 @@ repository = "https://github.com/wasmerio/wasmer"
edition = "2018"
[dependencies]
nom = "5.1"
nom = "5.1"
wast = "8.0"

View File

@ -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<Export<'input>>,

View File

@ -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<Self> {
let mut lookahead = parser.lookahead1();
alt((
int, float, any, string, seq, r#i32, r#i64, r#f32, r#f64, anyref,
))(input)
if lookahead.peek::<kw::int>() {
parser.parse::<kw::int>()?;
Ok(InterfaceType::Int)
} else if lookahead.peek::<kw::float>() {
parser.parse::<kw::float>()?;
Ok(InterfaceType::Float)
} else if lookahead.peek::<kw::any>() {
parser.parse::<kw::any>()?;
Ok(InterfaceType::Any)
} else if lookahead.peek::<kw::string>() {
parser.parse::<kw::string>()?;
Ok(InterfaceType::String)
} else if lookahead.peek::<kw::seq>() {
parser.parse::<kw::seq>()?;
Ok(InterfaceType::Seq)
} else if lookahead.peek::<kw::i32>() {
parser.parse::<kw::i32>()?;
Ok(InterfaceType::I32)
} else if lookahead.peek::<kw::i64>() {
parser.parse::<kw::i64>()?;
Ok(InterfaceType::I64)
} else if lookahead.peek::<kw::f32>() {
parser.parse::<kw::f32>()?;
Ok(InterfaceType::F32)
} else if lookahead.peek::<kw::f64>() {
parser.parse::<kw::f64>()?;
Ok(InterfaceType::F64)
} else if lookahead.peek::<kw::anyref>() {
parser.parse::<kw::anyref>()?;
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<InterfaceType>, 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<Self> {
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<InterfaceType>, E> {
delimited(
char('('),
preceded(
opt(whitespace),
preceded(tag("result"), many0(preceded(whitespace, interface_type))),
),
char(')'),
)(input)
#[derive(PartialEq, Debug)]
enum FunctionType {
Input(Vec<InterfaceType>),
Output(Vec<InterfaceType>),
}
/// 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<Self> {
parser.parens(|parser| {
let mut lookahead = parser.lookahead1();
if lookahead.peek::<kw::param>() {
parser.parse::<kw::param>()?;
let mut inputs = vec![];
while !parser.is_empty() {
inputs.push(parser.parse()?);
}
Ok(FunctionType::Input(inputs))
} else if lookahead.peek::<kw::result>() {
parser.parse::<kw::result>()?;
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<Self> {
parser.parens(|parser| {
let mut lookahead = parser.lookahead1();
if lookahead.peek::<AtInterface>() {
parser.parse::<AtInterface>()?;
let mut lookahead = parser.lookahead1();
if lookahead.peek::<kw::export>() {
Ok(Interface::Export(parser.parse()?))
} else if lookahead.peek::<kw::func>() {
Ok(Interface::Import(parser.parse()?))
} else if lookahead.peek::<kw::adapt>() {
Ok(Interface::Adapter(parser.parse()?))
} else if lookahead.peek::<kw::forward>() {
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<Self> {
parser.parse::<kw::export>()?;
let name = parser.parse()?;
let mut input_types = vec![];
let mut output_types = vec![];
while !parser.is_empty() {
let function_type = parser.parse::<FunctionType>()?;
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<Self> {
parser.parse::<kw::func>()?;
parser.parse::<Id>()?;
/// 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::<kw::import>()?;
/// 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::<FunctionType>()?;
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<Self> {
parser.parse::<kw::adapt>()?;
let (kind, namespace, name) = parser.parens(|parser| {
let mut lookahead = parser.lookahead1();
if lookahead.peek::<kw::import>() {
parser.parse::<kw::import>()?;
Ok((AdapterKind::Import, parser.parse()?, parser.parse()?))
} else if lookahead.peek::<kw::export>() {
parser.parse::<kw::export>()?;
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::<FunctionType>()?;
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<Self> {
parser.parse::<kw::forward>()?;
let name = parser.parens(|parser| {
parser.parse::<kw::export>()?;
Ok((parser.parse()?))
})?;
Ok(Forward { name })
}
}
impl<'a> Parse<'a> for Interfaces<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut interfaces: Interfaces = Default::default();
while !parser.is_empty() {
let interface = parser.parse::<Interface>()?;
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::<InterfaceType>(&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::<FunctionType>(&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::<FunctionType>(&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::<FunctionType>(&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::<FunctionType>(&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::<Interface>(&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::<Interface>(&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::<Interface>(&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::<Interface>(&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::<Interface>(&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::<Interface>(&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::<Interface>(&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::<Interface>(&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::<Interface>(&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::<Interface>(&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::<Interface>(&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::<Interfaces>(&input).unwrap(), output);
}
}