mirror of
https://github.com/fluencelabs/wasmer
synced 2025-07-03 10:31:34 +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:
@ -50,18 +50,41 @@ pub enum InterfaceType {
|
|||||||
I64,
|
I64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a type signature.
|
/// Represents the kind of type.
|
||||||
///
|
|
||||||
/// ```wasm,ignore
|
|
||||||
/// (@interface type (param i32 i32) (result string))
|
|
||||||
/// ```
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct Type {
|
pub enum TypeKind {
|
||||||
/// Types for the parameters (`(param …)`).
|
/// A function type.
|
||||||
pub inputs: Vec<InterfaceType>,
|
Function,
|
||||||
|
|
||||||
/// Types for the results (`(result …)`).
|
/// A record type.
|
||||||
pub outputs: Vec<InterfaceType>,
|
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.
|
/// 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.
|
/// Parse an interface kind.
|
||||||
impl TryFrom<u8> for InterfaceKind {
|
impl TryFrom<u8> for InterfaceKind {
|
||||||
type Error = &'static str;
|
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);
|
let mut types = Vec::with_capacity(number_of_types as usize);
|
||||||
|
|
||||||
for _ in 0..number_of_types {
|
for _ in 0..number_of_types {
|
||||||
consume!((input, inputs) = list(input, ty)?);
|
consume!((input, type_kind) = byte(input)?);
|
||||||
consume!((input, outputs) = list(input, ty)?);
|
|
||||||
|
|
||||||
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))
|
Ok((input, types))
|
||||||
|
@ -13,6 +13,7 @@ mod keyword {
|
|||||||
// New keywords.
|
// New keywords.
|
||||||
custom_keyword!(implement);
|
custom_keyword!(implement);
|
||||||
custom_keyword!(r#type = "type");
|
custom_keyword!(r#type = "type");
|
||||||
|
custom_keyword!(record);
|
||||||
|
|
||||||
// New types.
|
// New types.
|
||||||
custom_keyword!(s8);
|
custom_keyword!(s8);
|
||||||
@ -401,25 +402,48 @@ impl<'a> Parse<'a> for Type {
|
|||||||
fn parse(parser: Parser<'a>) -> Result<Self> {
|
fn parse(parser: Parser<'a>) -> Result<Self> {
|
||||||
parser.parse::<keyword::r#type>()?;
|
parser.parse::<keyword::r#type>()?;
|
||||||
|
|
||||||
let (inputs, outputs) = parser.parens(|parser| {
|
let ty = parser.parens(|parser| {
|
||||||
parser.parse::<keyword::func>()?;
|
let mut lookahead = parser.lookahead1();
|
||||||
|
|
||||||
let mut input_types = vec![];
|
if lookahead.peek::<keyword::func>() {
|
||||||
let mut output_types = vec![];
|
parser.parse::<keyword::func>()?;
|
||||||
|
|
||||||
while !parser.is_empty() {
|
let mut input_types = vec![];
|
||||||
let function_type = parser.parse::<FunctionType>()?;
|
let mut output_types = vec![];
|
||||||
|
|
||||||
match function_type {
|
while !parser.is_empty() {
|
||||||
FunctionType::Input(mut inputs) => input_types.append(&mut inputs),
|
let function_type = parser.parse::<FunctionType>()?;
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
/// Encode an `InterfaceKind` into bytes.
|
||||||
impl<W> ToBytes<W> for InterfaceKind
|
impl<W> ToBytes<W> for InterfaceKind
|
||||||
where
|
where
|
||||||
@ -136,8 +149,18 @@ where
|
|||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
|
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
|
||||||
self.inputs.to_bytes(writer)?;
|
match self {
|
||||||
self.outputs.to_bytes(writer)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -167,11 +167,24 @@ fn output_types_to_result(output_types: &[InterfaceType]) -> String {
|
|||||||
/// Encode a `Type` into a string.
|
/// Encode a `Type` into a string.
|
||||||
impl<'input> ToString for &Type {
|
impl<'input> ToString for &Type {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
format!(
|
match self {
|
||||||
r#"(@interface type (func{inputs}{outputs}))"#,
|
Type::Function { inputs, outputs } => format!(
|
||||||
inputs = input_types_to_param(&self.inputs),
|
r#"(@interface type (func{inputs}{outputs}))"#,
|
||||||
outputs = output_types_to_result(&self.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
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user