diff --git a/src/ast.rs b/src/ast.rs index 6bc68cc..e51559e 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -17,6 +17,16 @@ pub enum TypeKind { Record, } +/// Represents the function argument type. +#[derive(PartialEq, Debug, Clone)] +pub struct FunctionArg { + /// A function argument name. + pub name: String, + + /// A function argument type. + pub ty: InterfaceType, +} + /// Represents a type. #[derive(PartialEq, Debug, Clone)] pub enum Type { @@ -26,15 +36,8 @@ pub enum Type { /// (@interface type (func (param i32 i32) (result string))) /// ``` Function { - /// Name of a function. - name: String, - - /// Types for the parameters (`(param …)`). - 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 parameters (`(param (name i32))`). + arguments: Vec, /// Types for the results (`(result …)`). output_types: Vec, diff --git a/src/decoders/binary.rs b/src/decoders/binary.rs index 5fc6216..ba08660 100644 --- a/src/decoders/binary.rs +++ b/src/decoders/binary.rs @@ -77,16 +77,23 @@ fn record_field<'input, E: ParseError<&'input [u8]>>( return Err(Err::Error(make_error(input, ErrorKind::Eof))); } - consume!((input, name) = string(input)?); + consume!((input, name) = owned_string(input)?); consume!((input, ty) = ty(input)?); - Ok(( - input, - RecordFieldType { - name: name.to_owned(), - ty, - }, - )) + Ok((input, RecordFieldType { name, ty })) +} + +fn function_arg<'input, E: ParseError<&'input [u8]>>( + mut input: &'input [u8], +) -> IResult<&'input [u8], FunctionArg, E> { + if input.is_empty() { + return Err(Err::Error(make_error(input, ErrorKind::Eof))); + } + + consume!((input, name) = owned_string(input)?); + consume!((input, ty) = ty(input)?); + + Ok((input, FunctionArg { name, ty })) } /// Parse an interface type. @@ -116,9 +123,9 @@ fn ty<'input, E: ParseError<&'input [u8]>>( 0x0c => InterfaceType::I32, 0x0d => InterfaceType::I64, 0x0e => { - consume!((input, record_name) = string(input)?); + consume!((input, record_name) = owned_string(input)?); - InterfaceType::Record(record_name.to_owned()) + InterfaceType::Record(record_name) } _ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))), }; @@ -132,13 +139,13 @@ fn record_type<'input, E: ParseError<&'input [u8]>>( ) -> IResult<&'input [u8], RecordType, E> { use crate::vec1::Vec1; - let (output, name) = string(input)?; + let (output, name) = owned_string(input)?; let (output, fields) = list(output, record_field)?; Ok(( output, RecordType { - name: name.to_owned(), + name, fields: Vec1::new(fields).expect("Record must have at least one field, zero given."), }, )) @@ -352,15 +359,11 @@ fn types<'input, E: ParseError<&'input [u8]>>( match type_kind { TypeKind::Function => { - consume!((input, name) = string(input)?); - consume!((input, arg_types) = list(input, ty)?); - consume!((input, arg_names) = list(input, owned_string)?); + consume!((input, arguments) = list(input, function_arg)?); consume!((input, output_types) = list(input, ty)?); types.push(Type::Function { - name: String::from(name), - arg_types, - arg_names, + arguments, output_types, }); } diff --git a/src/decoders/wat.rs b/src/decoders/wat.rs index 5de4da8..19d202d 100644 --- a/src/decoders/wat.rs +++ b/src/decoders/wat.rs @@ -416,7 +416,7 @@ impl Parse<'_> for AtInterface { #[derive(PartialEq, Debug)] enum FunctionType { - Header(String, Vec, Vec), + Header(Vec), Output(Vec), } @@ -427,17 +427,19 @@ impl Parse<'_> for FunctionType { if lookahead.peek::() { parser.parse::()?; - let func_name = parser.parse()?; - let mut names = vec![]; - let mut types = vec![]; + let mut arguments = vec![]; while !parser.is_empty() { - names.push(parser.parse()?); - types.push(parser.parse()?); + let arg_name: String = parser.parse()?; + let arg_type: InterfaceType = parser.parse()?; + arguments.push(FunctionArg { + name: arg_name, + ty: arg_type, + }); } - Ok(FunctionType::Header(func_name, names, types)) + Ok(FunctionType::Header(arguments)) } else if lookahead.peek::() { parser.parse::()?; @@ -504,38 +506,22 @@ impl<'a> Parse<'a> for Type { if lookahead.peek::() { parser.parse::()?; - let mut arg_types = vec![]; - let mut arg_names = vec![]; + let mut arguments = vec![]; let mut output_types = vec![]; - let mut name: Option = None; while !parser.is_empty() { let function_type = parser.parse::()?; match function_type { - FunctionType::Header(func_name, mut names, mut types) => { - name = Some(func_name); - arg_names.append(&mut names); - arg_types.append(&mut types); - }, + FunctionType::Header(mut func_arguments) => { + arguments.append(&mut func_arguments); + } 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 { - name, - arg_types, - arg_names, + arguments, output_types, }) } else if lookahead.peek::() { diff --git a/src/encoders/binary.rs b/src/encoders/binary.rs index e4d4081..7fb8f7f 100644 --- a/src/encoders/binary.rs +++ b/src/encoders/binary.rs @@ -186,6 +186,16 @@ where } } +impl ToBytes for FunctionArg +where + W: Write, +{ + fn to_bytes(&self, writer: &mut W) -> io::Result<()> { + self.name.to_bytes(writer)?; + self.ty.to_bytes(writer) + } +} + /// Encode a `Type` into bytes. /// /// Decoder is in `decoders::binary::types`. @@ -196,15 +206,11 @@ where fn to_bytes(&self, writer: &mut W) -> io::Result<()> { match self { Type::Function { - name, - arg_types, - arg_names, + arguments, output_types, } => { TypeKind::Function.to_bytes(writer)?; - name.to_bytes(writer)?; - arg_types.to_bytes(writer)?; - arg_names.to_bytes(writer)?; + arguments.to_bytes(writer)?; output_types.to_bytes(writer)?; } diff --git a/src/encoders/wat.rs b/src/encoders/wat.rs index a2d98a5..b566663 100644 --- a/src/encoders/wat.rs +++ b/src/encoders/wat.rs @@ -165,16 +165,16 @@ impl ToString for &Instruction { /// Encode a list of `InterfaceType` representing inputs into a /// string. -fn encode_arguments(arg_types: &[InterfaceType], arg_names: &[String]) -> String { +fn encode_function_arguments(arguments: &[FunctionArg]) -> String { // here we know that arg_names and arg_types have the same length - if arg_names.is_empty() { + if arguments.is_empty() { String::from("") } else { format!( "\n (param{})", - arg_names.iter().zip(arg_types.iter()).fold( + arguments.iter().fold( String::new(), - |mut accumulator, (name, ty)| { + |mut accumulator, FunctionArg { name, ty }| { accumulator.push(' '); accumulator.push_str(name); accumulator.push_str(": "); @@ -210,14 +210,11 @@ impl<'input> ToString for &Type { fn to_string(&self) -> String { match self { Type::Function { - name, - arg_types, - arg_names, + arguments, output_types, } => format!( - r#"(@interface type (func {name} {args}{output_types}))"#, - name = name, - args = encode_arguments(arg_types, arg_names), + r#"(@interface type (func {args} {output_types}))"#, + args = encode_function_arguments(arguments), output_types = output_types_to_result(&output_types), ),