Skip to content

Commit

Permalink
feat(interface-types) Introduce RecordType for InterfaceType and …
Browse files Browse the repository at this point in the history
…`Type`.

The `Type::Record` variant now is defined by `RecordType`. In
addition, `InterfaceType` has a new variant: `Record`, that is also
defined by `RecordType`. Encoders and decoders are updated to consider
`RecordType`, which removes code duplication and simplify code.
  • Loading branch information
Hywan committed Mar 26, 2020
1 parent 3c02c50 commit 61b4a42
Show file tree
Hide file tree
Showing 6 changed files with 371 additions and 122 deletions.
15 changes: 11 additions & 4 deletions lib/interface-types/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ pub enum InterfaceType {

/// A 64-bits integer (as defiend in WebAssembly core).
I64,

/// A record.
Record(RecordType),
}

/// Representing a record type.
#[derive(PartialEq, Debug, Clone)]
pub struct RecordType {
/// Types representing the fields.
pub fields: Vec<InterfaceType>,
}

/// Represents the kind of type.
Expand Down Expand Up @@ -81,10 +91,7 @@ pub enum Type {
/// ```wasm,ignore
/// (@interface type (record string i32))
/// ```
Record {
/// Types representing the fields.
fields: Vec<InterfaceType>,
},
Record(RecordType),
}

/// Represents an imported function.
Expand Down
206 changes: 128 additions & 78 deletions lib/interface-types/src/decoders/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,6 @@ use nom::{
};
use std::{convert::TryFrom, str};

/// Parse an `InterfaceType`.
impl TryFrom<u8> for InterfaceType {
type Error = &'static str;

fn try_from(code: u8) -> Result<Self, Self::Error> {
Ok(match code {
0 => Self::S8,
1 => Self::S16,
2 => Self::S32,
3 => Self::S64,
4 => Self::U8,
5 => Self::U16,
6 => Self::U32,
7 => Self::U64,
8 => Self::F32,
9 => Self::F64,
10 => Self::String,
11 => Self::Anyref,
12 => Self::I32,
13 => Self::I64,
_ => return Err("Unknown interface type code."),
})
}
}

/// Parse a type kind.
impl TryFrom<u8> for TypeKind {
type Error = &'static str;
Expand Down Expand Up @@ -95,6 +70,51 @@ fn uleb<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'i
))
}

/// Parse an interface type.
fn ty<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], InterfaceType, E> {
if input.is_empty() {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}

consume!((input, opcode) = byte(input)?);

let ty = match opcode {
0x00 => InterfaceType::S8,
0x01 => InterfaceType::S16,
0x02 => InterfaceType::S32,
0x03 => InterfaceType::S64,
0x04 => InterfaceType::U8,
0x05 => InterfaceType::U16,
0x06 => InterfaceType::U32,
0x07 => InterfaceType::U64,
0x08 => InterfaceType::F32,
0x09 => InterfaceType::F64,
0x0a => InterfaceType::String,
0x0b => InterfaceType::Anyref,
0x0c => InterfaceType::I32,
0x0d => InterfaceType::I64,
0x0e => {
consume!((input, record_type) = record_type(input)?);

InterfaceType::Record(record_type)
}
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
};

Ok((input, ty))
}

/// Parse an record type.
fn record_type<'input, E: ParseError<&'input [u8]>>(
input: &'input [u8],
) -> IResult<&'input [u8], RecordType, E> {
let (output, fields) = list(input, ty)?;

Ok((output, RecordType { fields }))
}

/// Parse a UTF-8 string.
fn string<'input, E: ParseError<&'input [u8]>>(
input: &'input [u8],
Expand Down Expand Up @@ -144,22 +164,6 @@ fn list<'input, I, E: ParseError<&'input [u8]>>(
Ok((input, items))
}

/// Parse a type.
fn ty<'input, E: ParseError<&'input [u8]>>(
input: &'input [u8],
) -> IResult<&'input [u8], InterfaceType, E> {
if input.is_empty() {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}

let (output, ty) = byte(input)?;

match InterfaceType::try_from(ty) {
Ok(ty) => Ok((output, ty)),
Err(_) => Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
}
}

/// Parse an instruction with its arguments.
fn instruction<'input, E: ParseError<&'input [u8]>>(
input: &'input [u8],
Expand Down Expand Up @@ -261,9 +265,9 @@ fn types<'input, E: ParseError<&'input [u8]>>(
}

TypeKind::Record => {
consume!((input, fields) = list(input, ty)?);
consume!((input, record_type) = record_type(input)?);

types.push(Type::Record { fields });
types.push(Type::Record(record_type));
}
}
}
Expand Down Expand Up @@ -575,40 +579,10 @@ mod tests {
);
}

#[test]
fn test_string() {
let input = &[
0x03, // string of 3 bytes
0x61, // "a"
0x62, // "b"
0x63, // "c"
0x64, 0x65,
];
let output = Ok((&[0x64, 0x65][..], "abc"));

assert_eq!(string::<()>(input), output);
}

#[test]
fn test_list() {
let input = &[
0x02, // list of 2 items
0x01, // string of 1 byte
0x61, // "a"
0x02, // string of 2 bytes
0x62, // "b"
0x63, // "c"
0x07,
];
let output = Ok((&[0x07][..], vec!["a", "bc"]));

assert_eq!(list::<&str, ()>(input, string), output);
}

#[test]
fn test_ty() {
let input = &[
0x0e, // list of 14 items
0x0f, // list of 15 items
0x00, // S8
0x01, // S16
0x02, // S32
Expand All @@ -623,6 +597,7 @@ mod tests {
0x0b, // Anyref
0x0c, // I32
0x0d, // I64
0x0e, 0x01, 0x02, // Record
0x01,
];
let output = Ok((
Expand All @@ -642,10 +617,85 @@ mod tests {
InterfaceType::Anyref,
InterfaceType::I32,
InterfaceType::I64,
InterfaceType::Record(RecordType {
fields: vec![InterfaceType::S32],
}),
],
));

assert_eq!(list::<InterfaceType, ()>(input, ty), output);
assert_eq!(list::<_, ()>(input, ty), output);
}

#[test]
fn test_record_type() {
let input = &[
0x03, // list of 3 items
0x01, // 1 field
0x0a, // String
0x02, // 2 fields
0x0a, // String
0x0c, // I32
0x03, // 3 fields
0x0a, // String
0x0e, // Record
0x02, // 2 fields
0x0c, // I32
0x0c, // I32
0x09, // F64
0x01,
];
let output = Ok((
&[0x01][..],
vec![
RecordType {
fields: vec![InterfaceType::String],
},
RecordType {
fields: vec![InterfaceType::String, InterfaceType::I32],
},
RecordType {
fields: vec![
InterfaceType::String,
InterfaceType::Record(RecordType {
fields: vec![InterfaceType::I32, InterfaceType::I32],
}),
InterfaceType::F64,
],
},
],
));

assert_eq!(list::<_, ()>(input, record_type), output);
}

#[test]
fn test_string() {
let input = &[
0x03, // string of 3 bytes
0x61, // "a"
0x62, // "b"
0x63, // "c"
0x64, 0x65,
];
let output = Ok((&[0x64, 0x65][..], "abc"));

assert_eq!(string::<()>(input), output);
}

#[test]
fn test_list() {
let input = &[
0x02, // list of 2 items
0x01, // string of 1 byte
0x61, // "a"
0x02, // string of 2 bytes
0x62, // "b"
0x63, // "c"
0x07,
];
let output = Ok((&[0x07][..], vec!["a", "bc"]));

assert_eq!(list::<_, ()>(input, string), output);
}

#[test]
Expand Down Expand Up @@ -734,7 +784,7 @@ mod tests {
],
));

assert_eq!(list::<Instruction, ()>(input, instruction), output);
assert_eq!(list::<_, ()>(input, instruction), output);
}

#[test]
Expand Down Expand Up @@ -787,9 +837,9 @@ mod tests {
inputs: vec![InterfaceType::S32, InterfaceType::S32],
outputs: vec![InterfaceType::S32],
},
Type::Record {
Type::Record(RecordType {
fields: vec![InterfaceType::S32, InterfaceType::S32],
},
}),
],
));

Expand Down
Loading

0 comments on commit 61b4a42

Please sign in to comment.