Skip to content

Commit

Permalink
feat(interface-types) Introduce the record type.
Browse files Browse the repository at this point in the history
This patch updates the `Type` type to be an enum with 2 variants:
`Function` and `Record`, resp. to represent:

1. `(@interface type (func (param i32 i32) (result string)))`
2. `(@interface type (record string i32))`

This patch updates the binary encoder and decoder, along with the WAT
encoder and decoder.
  • Loading branch information
Hywan committed Mar 24, 2020
1 parent b251d6d commit 68f248f
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 32 deletions.
43 changes: 33 additions & 10 deletions lib/interface-types/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,41 @@ pub enum InterfaceType {
I64,
}

/// Represents a type signature.
///
/// ```wasm,ignore
/// (@interface type (param i32 i32) (result string))
/// ```
/// Represents the kind of type.
#[derive(PartialEq, Debug)]
pub struct Type {
/// Types for the parameters (`(param …)`).
pub inputs: Vec<InterfaceType>,
pub enum TypeKind {
/// A function type.
Function,

/// Types for the results (`(result …)`).
pub outputs: Vec<InterfaceType>,
/// A record type.
Record,
}

/// Represents a type.
#[derive(PartialEq, Debug)]
pub enum Type {
/// A function type, like:
///
/// ```wasm,ignore
/// (@interface type (func (param i32 i32) (result string)))
/// ```
Function {
/// Types for the parameters (`(param …)`).
inputs: Vec<InterfaceType>,

/// Types for the results (`(result …)`).
outputs: Vec<InterfaceType>,
},

/// A record type, like:
///
/// ```wasm,ignore
/// (@interface type (record string i32))
/// ```
Record {
/// Types representing the fields.
fields: Vec<InterfaceType>,
},
}

/// Represents an imported function.
Expand Down
34 changes: 31 additions & 3 deletions lib/interface-types/src/decoders/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ impl TryFrom<u8> for InterfaceType {
}
}

/// Parse a type kind.
impl TryFrom<u8> for TypeKind {
type Error = &'static str;

fn try_from(code: u8) -> Result<Self, Self::Error> {
Ok(match code {
0x00 => Self::Function,
0x01 => Self::Record,
_ => return Err("Unknown type kind code."),
})
}
}

/// Parse an interface kind.
impl TryFrom<u8> for InterfaceKind {
type Error = &'static str;
Expand Down Expand Up @@ -234,10 +247,25 @@ fn types<'input, E: ParseError<&'input [u8]>>(
let mut types = Vec::with_capacity(number_of_types as usize);

for _ in 0..number_of_types {
consume!((input, inputs) = list(input, ty)?);
consume!((input, outputs) = list(input, ty)?);
consume!((input, type_kind) = byte(input)?);

types.push(Type { inputs, outputs });
let type_kind = TypeKind::try_from(type_kind)
.map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?;

match type_kind {
TypeKind::Function => {
consume!((input, inputs) = list(input, ty)?);
consume!((input, outputs) = list(input, ty)?);

types.push(Type::Function { inputs, outputs });
}

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

types.push(Type::Record { fields });
}
}
}

Ok((input, types))
Expand Down
48 changes: 36 additions & 12 deletions lib/interface-types/src/decoders/wat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod keyword {
// New keywords.
custom_keyword!(implement);
custom_keyword!(r#type = "type");
custom_keyword!(record);

// New types.
custom_keyword!(s8);
Expand Down Expand Up @@ -401,25 +402,48 @@ impl<'a> Parse<'a> for Type {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<keyword::r#type>()?;

let (inputs, outputs) = parser.parens(|parser| {
parser.parse::<keyword::func>()?;
let ty = parser.parens(|parser| {
let mut lookahead = parser.lookahead1();

if lookahead.peek::<keyword::func>() {
parser.parse::<keyword::func>()?;

let mut input_types = vec![];
let mut output_types = vec![];
let mut input_types = vec![];
let mut output_types = vec![];

while !parser.is_empty() {
let function_type = parser.parse::<FunctionType>()?;
while !parser.is_empty() {
let function_type = parser.parse::<FunctionType>()?;

match function_type {
FunctionType::Input(mut inputs) => input_types.append(&mut inputs),
FunctionType::Output(mut outputs) => output_types.append(&mut outputs),
match function_type {
FunctionType::Input(mut inputs) => input_types.append(&mut inputs),
FunctionType::Output(mut outputs) => output_types.append(&mut outputs),
}
}
}

Ok((input_types, output_types))
Ok(Type::Function {
inputs: input_types,
outputs: output_types,
})
} else if lookahead.peek::<keyword::record>() {
parser.parse::<keyword::record>()?;

let fields = parser.parens(|parser| {
let mut fields = vec![];

while !parser.is_empty() {
fields.push(parser.parse()?);
}

Ok(fields)
})?;

Ok(Type::Record { fields })
} else {
Err(lookahead.error())
}
})?;

Ok(Type { inputs, outputs })
Ok(ty)
}
}

Expand Down
27 changes: 25 additions & 2 deletions lib/interface-types/src/encoders/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,19 @@ where
}
}

/// Encode a `TypeKind` into bytes.
impl<W> ToBytes<W> for TypeKind
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
match self {
TypeKind::Function => 0x00_u8.to_bytes(writer),
TypeKind::Record => 0x01_u8.to_bytes(writer),
}
}
}

/// Encode an `InterfaceKind` into bytes.
impl<W> ToBytes<W> for InterfaceKind
where
Expand All @@ -136,8 +149,18 @@ where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
self.inputs.to_bytes(writer)?;
self.outputs.to_bytes(writer)?;
match self {
Type::Function { inputs, outputs } => {
TypeKind::Function.to_bytes(writer)?;
inputs.to_bytes(writer)?;
outputs.to_bytes(writer)?;
}

Type::Record { fields } => {
TypeKind::Record.to_bytes(writer)?;
fields.to_bytes(writer)?;
}
}

Ok(())
}
Expand Down
23 changes: 18 additions & 5 deletions lib/interface-types/src/encoders/wat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,24 @@ fn output_types_to_result(output_types: &[InterfaceType]) -> String {
/// Encode a `Type` into a string.
impl<'input> ToString for &Type {
fn to_string(&self) -> String {
format!(
r#"(@interface type (func{inputs}{outputs}))"#,
inputs = input_types_to_param(&self.inputs),
outputs = output_types_to_result(&self.outputs),
)
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::Record { fields } => format!(
r#"(@interface type (record {fields}))"#,
fields = fields
.iter()
.fold(String::new(), |mut accumulator, interface_type| {
accumulator.push(' ');
accumulator.push_str(&interface_type.to_string());
accumulator
}),
),
}
}
}

Expand Down

0 comments on commit 68f248f

Please sign in to comment.