commute arg name and type to one struct

This commit is contained in:
vms 2020-08-18 04:32:43 +03:00
parent e28914ae01
commit 37458bc559
5 changed files with 66 additions and 71 deletions

View File

@ -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<InterfaceType>,
/// Name of function argument types.
// TODO: introduce a struct combines name and type of a field
arg_names: Vec<String>,
/// Types for the parameters (`(param (name i32))`).
arguments: Vec<FunctionArg>,
/// Types for the results (`(result …)`).
output_types: Vec<InterfaceType>,

View File

@ -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,
});
}

View File

@ -416,7 +416,7 @@ impl Parse<'_> for AtInterface {
#[derive(PartialEq, Debug)]
enum FunctionType {
Header(String, Vec<String>, Vec<InterfaceType>),
Header(Vec<FunctionArg>),
Output(Vec<InterfaceType>),
}
@ -427,17 +427,19 @@ impl Parse<'_> for FunctionType {
if lookahead.peek::<keyword::param>() {
parser.parse::<keyword::param>()?;
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::<keyword::result>() {
parser.parse::<keyword::result>()?;
@ -504,38 +506,22 @@ impl<'a> Parse<'a> for Type {
if lookahead.peek::<keyword::func>() {
parser.parse::<keyword::func>()?;
let mut arg_types = vec![];
let mut arg_names = vec![];
let mut arguments = 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::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::<keyword::record>() {

View File

@ -186,6 +186,16 @@ where
}
}
impl<W> ToBytes<W> 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)?;
}

View File

@ -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),
),