mirror of
https://github.com/fluencelabs/interface-types
synced 2024-12-04 15:20:20 +00:00
feat(interface-types) Introduce the record type.
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.
This commit is contained in:
parent
63f824a240
commit
c3c6fcbfdd
43
src/ast.rs
43
src/ast.rs
@ -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.
|
||||
|
@ -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;
|
||||
@ -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))
|
||||
|
@ -13,6 +13,7 @@ mod keyword {
|
||||
// New keywords.
|
||||
custom_keyword!(implement);
|
||||
custom_keyword!(r#type = "type");
|
||||
custom_keyword!(record);
|
||||
|
||||
// New types.
|
||||
custom_keyword!(s8);
|
||||
@ -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();
|
||||
|
||||
let mut input_types = vec![];
|
||||
let mut output_types = vec![];
|
||||
if lookahead.peek::<keyword::func>() {
|
||||
parser.parse::<keyword::func>()?;
|
||||
|
||||
while !parser.is_empty() {
|
||||
let function_type = parser.parse::<FunctionType>()?;
|
||||
let mut input_types = vec![];
|
||||
let mut output_types = vec![];
|
||||
|
||||
match function_type {
|
||||
FunctionType::Input(mut inputs) => input_types.append(&mut inputs),
|
||||
FunctionType::Output(mut outputs) => output_types.append(&mut outputs),
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
@ -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(())
|
||||
}
|
||||
|
@ -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
|
||||
}),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user