From d4bc6326b9d35d05939fe2b6f8ee974dc41f9ae8 Mon Sep 17 00:00:00 2001 From: vms Date: Fri, 14 Aug 2020 19:26:20 +0300 Subject: [PATCH] update --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/ast.rs | 11 +++++++++-- src/decoders/binary.rs | 37 +++++++++++++++++++++++++++++++++---- src/decoders/wat.rs | 41 +++++++++++++++++++++++++++++++---------- src/encoders/binary.rs | 31 ++++++++++++++++++++++++++++--- src/encoders/wat.rs | 34 ++++++++++++++++++++++------------ 7 files changed, 125 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c29b454..eeb628a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 0f056d8..895ae13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/ast.rs b/src/ast.rs index 96aed0e..6bc68cc 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -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, + arg_types: Vec, + + /// Name of function argument types. + // TODO: introduce a struct combines name and type of a field + arg_names: Vec, /// Types for the results (`(result …)`). - outputs: Vec, + output_types: Vec, }, /// A record type, like: diff --git a/src/decoders/binary.rs b/src/decoders/binary.rs index 4b21c6a..e2a1e2d 100644 --- a/src/decoders/binary.rs +++ b/src/decoders/binary.rs @@ -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 => { diff --git a/src/decoders/wat.rs b/src/decoders/wat.rs index 2f82f60..f6aa2c9 100644 --- a/src/decoders/wat.rs +++ b/src/decoders/wat.rs @@ -403,7 +403,7 @@ impl Parse<'_> for AtInterface { #[derive(PartialEq, Debug)] enum FunctionType { - Input(Vec), + Header(String, Vec, Vec), Output(Vec), } @@ -414,14 +414,17 @@ impl Parse<'_> for FunctionType { if lookahead.peek::() { parser.parse::()?; + 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::() { parser.parse::()?; @@ -488,21 +491,39 @@ impl<'a> Parse<'a> for Type { if lookahead.peek::() { parser.parse::()?; - let mut input_types = vec![]; + let mut arg_types = vec![]; + let mut arg_names = vec![]; let mut output_types = vec![]; + let mut name: Option = None; while !parser.is_empty() { let function_type = parser.parse::()?; 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::() { 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::(&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::(&input).unwrap(), output); } diff --git a/src/encoders/binary.rs b/src/encoders/binary.rs index ca242c7..2b3a90f 100644 --- a/src/encoders/binary.rs +++ b/src/encoders/binary.rs @@ -66,6 +66,24 @@ where } } +/// Encode a String into bytes. +/// +/// Decoder is `decoders::binary::string`. +impl ToBytes 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) => { diff --git a/src/encoders/wat.rs b/src/encoders/wat.rs index aa102f3..3b06d27 100644 --- a/src/encoders/wat.rs +++ b/src/encoders/wat.rs @@ -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!(