mirror of
https://github.com/fluencelabs/interface-types
synced 2025-04-24 15:22:13 +00:00
feat(interface-types) Replace nom by wast for decoding WIT's text format.
This commit is contained in:
parent
e90365beb1
commit
9b98a211cd
@ -8,4 +8,5 @@ repository = "https://github.com/wasmerio/wasmer"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nom = "5.1"
|
||||
nom = "5.1"
|
||||
wast = "8.0"
|
@ -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>>,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user