This commit is contained in:
vms 2020-08-14 19:26:20 +03:00
parent 458adc2534
commit d4bc6326b9
7 changed files with 125 additions and 33 deletions

2
Cargo.lock generated
View File

@ -185,7 +185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
[[package]]
name = "wasmer-interface-types"
name = "wasmer-interface-types-fl"
version = "0.17.0"
dependencies = [
"nom",

View File

@ -1,5 +1,5 @@
[package]
name = "wasmer-interface-types"
name = "wasmer-interface-types-fl"
version = "0.17.0"
description = "WebAssembly Interface Types library for Wasmer"
license = "MIT"

View File

@ -26,11 +26,18 @@ pub enum Type {
/// (@interface type (func (param i32 i32) (result string)))
/// ```
Function {
/// Name of a function.
name: String,
/// Types for the parameters (`(param …)`).
inputs: Vec<InterfaceType>,
arg_types: Vec<InterfaceType>,
/// Name of function argument types.
// TODO: introduce a struct combines name and type of a field
arg_names: Vec<String>,
/// Types for the results (`(result …)`).
outputs: Vec<InterfaceType>,
output_types: Vec<InterfaceType>,
},
/// A record type, like:

View File

@ -121,7 +121,7 @@ fn record_type<'input, E: ParseError<&'input [u8]>>(
))
}
/// Parse a UTF-8 string.
/// Parse a UTF-8 string into &str.
fn string<'input, E: ParseError<&'input [u8]>>(
input: &'input [u8],
) -> IResult<&'input [u8], &'input str, E> {
@ -143,6 +143,28 @@ fn string<'input, E: ParseError<&'input [u8]>>(
))
}
/// Parse a UTF-8 string into String.
fn owned_string<'input, E: ParseError<&'input [u8]>>(
input: &'input [u8],
) -> IResult<&'input [u8], String, E> {
if input.is_empty() {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}
let length = input[0] as usize;
let input = &input[1..];
if input.len() < length {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}
Ok((
&input[length..],
String::from_utf8(input[..length].to_vec())
.map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?,
))
}
/// Parse a list, with an item parser.
#[allow(clippy::type_complexity)]
fn list<'input, I, E: ParseError<&'input [u8]>>(
@ -306,10 +328,17 @@ fn types<'input, E: ParseError<&'input [u8]>>(
match type_kind {
TypeKind::Function => {
consume!((input, inputs) = list(input, ty)?);
consume!((input, outputs) = list(input, ty)?);
consume!((input, name) = string(input)?);
consume!((input, arg_types) = list(input, ty)?);
consume!((input, arg_names) = list(input, owned_string)?);
consume!((input, output_types) = list(input, ty)?);
types.push(Type::Function { inputs, outputs });
types.push(Type::Function {
name: String::from(name),
arg_types,
arg_names,
output_types,
});
}
TypeKind::Record => {

View File

@ -403,7 +403,7 @@ impl Parse<'_> for AtInterface {
#[derive(PartialEq, Debug)]
enum FunctionType {
Input(Vec<InterfaceType>),
Header(String, Vec<String>, Vec<InterfaceType>),
Output(Vec<InterfaceType>),
}
@ -414,14 +414,17 @@ impl Parse<'_> for FunctionType {
if lookahead.peek::<keyword::param>() {
parser.parse::<keyword::param>()?;
let func_name = parser.parse()?;
let mut inputs = vec![];
let mut names = vec![];
let mut types = vec![];
while !parser.is_empty() {
inputs.push(parser.parse()?);
names.push(parser.parse()?);
types.push(parser.parse()?);
}
Ok(FunctionType::Input(inputs))
Ok(FunctionType::Header(func_name, names, types))
} else if lookahead.peek::<keyword::result>() {
parser.parse::<keyword::result>()?;
@ -488,21 +491,39 @@ impl<'a> Parse<'a> for Type {
if lookahead.peek::<keyword::func>() {
parser.parse::<keyword::func>()?;
let mut input_types = vec![];
let mut arg_types = vec![];
let mut arg_names = vec![];
let mut output_types = vec![];
let mut name: Option<String> = None;
while !parser.is_empty() {
let function_type = parser.parse::<FunctionType>()?;
match function_type {
FunctionType::Input(mut inputs) => input_types.append(&mut inputs),
FunctionType::Header(func_name, mut names, mut types) => {
name = Some(func_name);
arg_names.append(&mut names);
arg_types.append(&mut types);
},
FunctionType::Output(mut outputs) => output_types.append(&mut outputs),
}
}
if name.is_none() {
return Err(parser.error("Malformed wast: function doesn't contain name"));
}
if arg_types.len() != arg_names.len() {
return Err(parser.error("Malformed wast: function argument types count should be equal to argument names count"));
}
// It's has been already checked for None.
let name = name.unwrap();
Ok(Type::Function {
inputs: input_types,
outputs: output_types,
name,
arg_types,
arg_names,
output_types,
})
} else if lookahead.peek::<keyword::record>() {
Ok(Type::Record(parser.parse()?))
@ -874,7 +895,7 @@ mod tests {
#[test]
fn test_param_empty() {
let input = buffer("(param)");
let output = FunctionType::Input(vec![]);
let output = FunctionType::InputTypes(vec![]);
assert_eq!(parser::parse::<FunctionType>(&input).unwrap(), output);
}
@ -882,7 +903,7 @@ mod tests {
#[test]
fn test_param() {
let input = buffer("(param i32 string)");
let output = FunctionType::Input(vec![InterfaceType::I32, InterfaceType::String]);
let output = FunctionType::InputTypes(vec![InterfaceType::I32, InterfaceType::String]);
assert_eq!(parser::parse::<FunctionType>(&input).unwrap(), output);
}

View File

@ -66,6 +66,24 @@ where
}
}
/// Encode a String into bytes.
///
/// Decoder is `decoders::binary::string`.
impl<W> ToBytes<W> for String
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
// Size first.
writer.write_all(&[self.len() as u8])?;
// Then the string.
writer.write_all(self.as_bytes())?;
Ok(())
}
}
/// Encode a vector into bytes.
///
/// Decoder is `decoders::binary::list`.
@ -165,10 +183,17 @@ where
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
match self {
Type::Function { inputs, outputs } => {
Type::Function {
name,
arg_types,
arg_names,
output_types,
} => {
TypeKind::Function.to_bytes(writer)?;
inputs.to_bytes(writer)?;
outputs.to_bytes(writer)?;
name.to_bytes(writer)?;
arg_types.to_bytes(writer)?;
arg_names.to_bytes(writer)?;
output_types.to_bytes(writer)?;
}
Type::Record(record_type) => {

View File

@ -158,19 +158,23 @@ impl ToString for &Instruction {
/// Encode a list of `InterfaceType` representing inputs into a
/// string.
fn input_types_to_param(input_types: &[InterfaceType]) -> String {
if input_types.is_empty() {
"".into()
fn encode_arguments(arg_types: &[InterfaceType], arg_names: &[String]) -> String {
// here we know that arg_names and arg_types have the same length
if arg_names.is_empty() {
String::from("")
} else {
format!(
"\n (param{})",
input_types
.iter()
.fold(String::new(), |mut accumulator, interface_type| {
arg_names.iter().zip(arg_types.iter()).fold(
String::new(),
|mut accumulator, (name, ty)| {
accumulator.push(' ');
accumulator.push_str(&interface_type.to_string());
accumulator.push_str(name);
accumulator.push_str(": ");
accumulator.push_str(&ty.to_string());
accumulator
})
}
)
)
}
}
@ -198,10 +202,16 @@ fn output_types_to_result(output_types: &[InterfaceType]) -> String {
impl<'input> ToString for &Type {
fn to_string(&self) -> String {
match self {
Type::Function { inputs, outputs } => format!(
r#"(@interface type (func{inputs}{outputs}))"#,
inputs = input_types_to_param(&inputs),
outputs = output_types_to_result(&outputs),
Type::Function {
name,
arg_types,
arg_names,
output_types,
} => format!(
r#"(@interface type (func {name} {args}{output_types}))"#,
name = name,
args = encode_arguments(arg_types, arg_names),
output_types = output_types_to_result(&output_types),
),
Type::Record(record_type) => format!(