From eb11794240ddd14ba544a37d9a3fecfcd5f20214 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 13 Aug 2020 21:02:23 +0300 Subject: [PATCH] refactor Record type --- src/decoders/binary.rs | 36 +++++- src/decoders/wat.rs | 22 +++- src/encoders/binary.rs | 17 ++- src/encoders/wat.rs | 15 ++- src/errors.rs | 23 +++- src/interpreter/instructions/byte_arrays.rs | 2 +- src/interpreter/instructions/call_core.rs | 18 +-- src/interpreter/instructions/mod.rs | 115 +++++++++++++++++- src/interpreter/instructions/numbers.rs | 2 +- src/interpreter/instructions/records.rs | 62 ++++++---- src/interpreter/instructions/records/utils.rs | 25 ++-- src/interpreter/instructions/strings.rs | 2 +- src/interpreter/mod.rs | 3 +- src/interpreter/wasm/structures.rs | 14 ++- src/serde/de.rs | 16 +-- src/types.rs | 23 +++- src/values.rs | 18 +-- 17 files changed, 306 insertions(+), 107 deletions(-) diff --git a/src/decoders/binary.rs b/src/decoders/binary.rs index 4b21c6a..fc0e678 100644 --- a/src/decoders/binary.rs +++ b/src/decoders/binary.rs @@ -1,6 +1,6 @@ //! Parse the WIT binary representation into an [AST](crate::ast). -use crate::{ast::*, interpreter::Instruction, types::*, vec1::Vec1}; +use crate::{ast::*, interpreter::Instruction, types::*}; use nom::{ error::{make_error, ErrorKind, ParseError}, Err, IResult, @@ -70,6 +70,25 @@ fn uleb<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'i )) } +fn record_field<'input, E: ParseError<&'input [u8]>>( + mut input: &'input [u8], +) -> IResult<&'input [u8], RecordFieldType, E> { + if input.is_empty() { + return Err(Err::Error(make_error(input, ErrorKind::Eof))); + } + + consume!((input, name) = string(input)?); + consume!((input, ty) = ty(input)?); + + Ok(( + input, + RecordFieldType { + name: name.to_owned(), + ty, + }, + )) +} + /// Parse an interface type. fn ty<'input, E: ParseError<&'input [u8]>>( mut input: &'input [u8], @@ -97,9 +116,9 @@ fn ty<'input, E: ParseError<&'input [u8]>>( 0x0c => InterfaceType::I32, 0x0d => InterfaceType::I64, 0x0e => { - consume!((input, record_type) = record_type(input)?); + consume!((input, record_name) = string(input)?); - InterfaceType::Record(record_type) + InterfaceType::Record(record_name.to_owned()) } _ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))), }; @@ -111,11 +130,15 @@ fn ty<'input, E: ParseError<&'input [u8]>>( fn record_type<'input, E: ParseError<&'input [u8]>>( input: &'input [u8], ) -> IResult<&'input [u8], RecordType, E> { - let (output, fields) = list(input, ty)?; + use crate::vec1::Vec1; + + let (output, name) = string(input)?; + let (output, fields) = list(output, record_field)?; Ok(( output, RecordType { + name: name.to_owned(), fields: Vec1::new(fields).expect("Record must have at least one field, zero given."), }, )) @@ -240,6 +263,7 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( 0x38 => (input, Instruction::ByteArrayLowerMemory), 0x39 => (input, Instruction::ByteArraySize), +/* 0x25 => { consume!((input, argument_0) = uleb(input)?); @@ -260,6 +284,7 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( }, ) } + */ 0x3A => { consume!((input, argument_0) = uleb(input)?); @@ -832,8 +857,11 @@ mod tests { Instruction::StringLiftMemory, Instruction::StringLowerMemory, Instruction::StringSize, + /* Instruction::RecordLift { type_index: 1 }, Instruction::RecordLower { type_index: 1 }, + + */ ], )); diff --git a/src/decoders/wat.rs b/src/decoders/wat.rs index 2f82f60..6e10bb3 100644 --- a/src/decoders/wat.rs +++ b/src/decoders/wat.rs @@ -154,17 +154,25 @@ impl Parse<'_> for RecordType { fn parse(parser: Parser<'_>) -> Result { parser.parse::()?; + parser.parse::()?; + let record_name = parser.parse()?; + let mut fields = vec![]; while !parser.is_empty() { fields.push(parser.parens(|parser| { - parser.parse::()?; + parser.parse::()?; + let name = parser.parse()?; - parser.parse() + parser.parse::()?; + let ty = parser.parse()?; + + Ok(RecordFieldType { name, ty }) })?); } Ok(RecordType { + name: record_name, fields: Vec1::new(fields).expect("Record must have at least one field, zero given."), }) } @@ -339,7 +347,9 @@ impl<'a> Parse<'a> for Instruction { parser.parse::()?; Ok(Instruction::ByteArraySize) - } else if lookahead.peek::() { + } + /* + else if lookahead.peek::() { parser.parse::()?; Ok(Instruction::RecordLift { @@ -351,7 +361,9 @@ impl<'a> Parse<'a> for Instruction { Ok(Instruction::RecordLower { type_index: parser.parse()?, }) - } else if lookahead.peek::() { + } + */ + else if lookahead.peek::() { parser.parse::()?; Ok(Instruction::RecordLiftMemory { @@ -857,8 +869,10 @@ mod tests { Instruction::StringLiftMemory, Instruction::StringLowerMemory, Instruction::StringSize, + /* Instruction::RecordLift { type_index: 42 }, Instruction::RecordLower { type_index: 42 }, + */ ]; assert_eq!(inputs.len(), outputs.len()); diff --git a/src/encoders/binary.rs b/src/encoders/binary.rs index ca242c7..88a4e2b 100644 --- a/src/encoders/binary.rs +++ b/src/encoders/binary.rs @@ -111,18 +111,30 @@ where InterfaceType::I64 => 0x0d_u8.to_bytes(writer), InterfaceType::Record(record_type) => { 0x0e_u8.to_bytes(writer)?; - record_type.to_bytes(writer) + record_type.as_str().to_bytes(writer) } } } } +/// Encode a `RecordType` into bytes. +impl ToBytes for RecordFieldType +where + W: Write, +{ + fn to_bytes(&self, writer: &mut W) -> io::Result<()> { + self.name.as_str().to_bytes(writer)?; + self.ty.to_bytes(writer) + } +} + /// Encode a `RecordType` into bytes. impl ToBytes for RecordType where W: Write, { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { + self.name.as_str().to_bytes(writer)?; self.fields.to_bytes(writer) } } @@ -338,7 +350,7 @@ where Instruction::ByteArrayLiftMemory => 0x37_u8.to_bytes(writer)?, Instruction::ByteArrayLowerMemory => 0x38_u8.to_bytes(writer)?, Instruction::ByteArraySize => 0x39_u8.to_bytes(writer)?, - + /* Instruction::RecordLift { type_index } => { 0x25_u8.to_bytes(writer)?; (*type_index as u64).to_bytes(writer)? @@ -347,6 +359,7 @@ where 0x26_u8.to_bytes(writer)?; (*type_index as u64).to_bytes(writer)? } + */ Instruction::RecordLiftMemory { type_index } => { 0x3A_u8.to_bytes(writer)?; (*type_index as u64).to_bytes(writer)? diff --git a/src/encoders/wat.rs b/src/encoders/wat.rs index aa102f3..dcf75e6 100644 --- a/src/encoders/wat.rs +++ b/src/encoders/wat.rs @@ -85,13 +85,18 @@ impl ToString for &InterfaceType { impl ToString for &RecordType { fn to_string(&self) -> String { format!( - "record{fields}", + "record {} {fields}", + self.name, fields = self .fields .iter() - .fold(String::new(), |mut accumulator, interface_type| { + .fold(String::new(), |mut accumulator, field_type| { accumulator.push(' '); - accumulator.push_str(&format!("(field {})", &interface_type.to_string())); + accumulator.push_str(&format!( + "{}: {}\n", + field_type.name, + (&field_type.ty).to_string() + )); accumulator }), ) @@ -142,8 +147,10 @@ impl ToString for &Instruction { Instruction::ByteArrayLiftMemory => "byte_array.lift_memory".into(), Instruction::ByteArrayLowerMemory => "byte_array.lower_memory".into(), Instruction::ByteArraySize => "byte_array.size".into(), + /* Instruction::RecordLift { type_index } => format!("record.lift {}", type_index), Instruction::RecordLower { type_index } => format!("record.lower {}", type_index), + */ Instruction::RecordLiftMemory { type_index } => { format!("record.lift_memory {}", type_index) } @@ -475,8 +482,10 @@ mod tests { (&Instruction::StringLiftMemory).to_string(), (&Instruction::StringLowerMemory).to_string(), (&Instruction::StringSize).to_string(), + /* (&Instruction::RecordLift { type_index: 42 }).to_string(), (&Instruction::RecordLower { type_index: 42 }).to_string(), + */ ]; let outputs = vec![ "arg.get 7", diff --git a/src/errors.rs b/src/errors.rs index decf278..2ddbfe6 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,7 @@ //! The error module contains all the data structures that represent //! an error. +use crate::values::InterfaceValue; use crate::{ast::TypeKind, interpreter::Instruction, types::InterfaceType}; use std::{ error::Error, @@ -21,7 +22,7 @@ pub type InterpreterResult = Result; #[derive(Debug)] pub struct WasmValueNativeCastError { /// The initial type. - pub from: InterfaceType, + pub from: InterfaceValue, /// The targeted type. /// @@ -98,7 +99,7 @@ pub enum InstructionErrorKind { expected_type: InterfaceType, /// The received type. - received_type: InterfaceType, + received_value: InterfaceValue, }, /// Need to read some values from the stack, but it doesn't @@ -163,6 +164,12 @@ pub enum InstructionErrorKind { type_index: u32, }, + /// The searched by name type doesn't exist. + RecordTypeByNameIsMissing { + /// The record type name. + type_name: String, + }, + /// Read a type that has an unexpected type. InvalidTypeKind { /// The expected kind. @@ -199,11 +206,11 @@ impl Display for InstructionErrorKind { Self::InvalidValueOnTheStack { expected_type, - received_type, + received_value, } => write!( formatter, - "read a value of type `{:?}` from the stack, but the type `{:?}` was expected", - received_type, expected_type, + "read a value `{:?}` from the stack, that can't be converted to `{:?}`", + received_value, expected_type, ), Self::StackIsTooSmall { needed } => write!( @@ -261,6 +268,12 @@ impl Display for InstructionErrorKind { "read a type of kind `{:?}`, but the kind `{:?}` was expected", received_kind, expected_kind ), + + Self::RecordTypeByNameIsMissing { type_name } => write!( + formatter, + "type with `{}` is missing in a Wasm binary", + type_name + ), Self::SerdeError(err) => write!( formatter, "serde error: {}", err, diff --git a/src/interpreter/instructions/byte_arrays.rs b/src/interpreter/instructions/byte_arrays.rs index fcc908b..4b9fec8 100644 --- a/src/interpreter/instructions/byte_arrays.rs +++ b/src/interpreter/instructions/byte_arrays.rs @@ -127,7 +127,7 @@ executable_instruction!( instruction, InstructionErrorKind::InvalidValueOnTheStack { expected_type: InterfaceType::ByteArray, - received_type: (&value).into(), + received_value: value, }, )), diff --git a/src/interpreter/instructions/call_core.rs b/src/interpreter/instructions/call_core.rs index c4c1632..533740c 100644 --- a/src/interpreter/instructions/call_core.rs +++ b/src/interpreter/instructions/call_core.rs @@ -2,13 +2,12 @@ use crate::{ errors::{InstructionError, InstructionErrorKind}, interpreter::wasm::structures::{FunctionIndex, TypedIndex}, interpreter::Instruction, - types::InterfaceType, }; executable_instruction!( call_core(function_index: u32, instruction: Instruction) -> _ { move |runtime| -> _ { - let instance = &mut runtime.wasm_instance; + let instance = &runtime.wasm_instance; let index = FunctionIndex::new(function_index as usize); let local_or_import = instance.local_or_import(index).ok_or_else(|| { @@ -29,21 +28,8 @@ executable_instruction!( }, ) })?; - let input_types = inputs - .iter() - .map(Into::into) - .collect::>(); - if input_types != local_or_import.inputs() { - return Err(InstructionError::new( - instruction, - InstructionErrorKind::LocalOrImportSignatureMismatch { - function_index, - expected: (local_or_import.inputs().to_vec(), vec![]), - received: (input_types, vec![]), - }, - )); - } + super::check_function_signature(&**instance, local_or_import, &inputs, instruction)?; let outputs = local_or_import.call(&inputs).map_err(|_| { InstructionError::new( diff --git a/src/interpreter/instructions/mod.rs b/src/interpreter/instructions/mod.rs index 63b98bd..219095a 100644 --- a/src/interpreter/instructions/mod.rs +++ b/src/interpreter/instructions/mod.rs @@ -7,6 +7,8 @@ mod records; mod strings; mod swap2; +use crate::interpreter::wasm; +use crate::types::InterfaceType; use crate::{ errors::{InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError}, values::{InterfaceValue, NativeType}, @@ -153,6 +155,7 @@ pub enum Instruction { /// The `string.size` instruction. ByteArraySize, + /* /// The `record.lift` instruction. RecordLift { /// The type index of the record. @@ -165,6 +168,8 @@ pub enum Instruction { type_index: u32, }, + */ + /// The `record.lift_memory` instruction. RecordLiftMemory { /// The type index of the record. @@ -197,6 +202,114 @@ where .map_err(|error| InstructionError::new(instruction, InstructionErrorKind::ToNative(error))) } +pub(crate) fn check_function_signature< + 'instance, + Instance, + Export, + LocalImport, + Memory, + MemoryView, +>( + instance: &'instance Instance, + local_import: &LocalImport, + values: &[InterfaceValue], + instruction: Instruction, +) -> Result<(), InstructionError> +where + Export: wasm::structures::Export + 'instance, + LocalImport: wasm::structures::LocalImport + 'instance, + Memory: wasm::structures::Memory + 'instance, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, +{ + let func_inputs = local_import.inputs(); + + for (func_input_arg, value) in func_inputs.iter().zip(values.iter()) { + is_value_compatible_to_type(instance, &func_input_arg, value, instruction)?; + } + + Ok(()) +} + +/// Check whether the provided value could be a value of the provided type. +pub(crate) fn is_value_compatible_to_type< + 'instance, + Instance, + Export, + LocalImport, + Memory, + MemoryView, +>( + instance: &'instance Instance, + interface_type: &InterfaceType, + interface_value: &InterfaceValue, + instruction: Instruction, +) -> Result<(), InstructionError> +where + Export: wasm::structures::Export + 'instance, + LocalImport: wasm::structures::LocalImport + 'instance, + Memory: wasm::structures::Memory + 'instance, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, +{ + match (&interface_type, interface_value) { + (InterfaceType::S8, InterfaceValue::S8(_)) => Ok(()), + (InterfaceType::S16, InterfaceValue::S16(_)) => Ok(()), + (InterfaceType::S32, InterfaceValue::S32(_)) => Ok(()), + (InterfaceType::S64, InterfaceValue::S64(_)) => Ok(()), + (InterfaceType::U8, InterfaceValue::U8(_)) => Ok(()), + (InterfaceType::U16, InterfaceValue::U16(_)) => Ok(()), + (InterfaceType::U32, InterfaceValue::U32(_)) => Ok(()), + (InterfaceType::U64, InterfaceValue::U64(_)) => Ok(()), + (InterfaceType::I32, InterfaceValue::I32(_)) => Ok(()), + (InterfaceType::I64, InterfaceValue::I64(_)) => Ok(()), + (InterfaceType::F32, InterfaceValue::F32(_)) => Ok(()), + (InterfaceType::F64, InterfaceValue::F64(_)) => Ok(()), + (InterfaceType::String, InterfaceValue::String(_)) => Ok(()), + (InterfaceType::ByteArray, InterfaceValue::ByteArray(_)) => Ok(()), + (InterfaceType::Record(ref record_name), InterfaceValue::Record(record_fields)) => { + let record_type = instance.wit_record_by_name(record_name).ok_or_else(|| { + InstructionError::new( + instruction, + InstructionErrorKind::RecordTypeByNameIsMissing { + type_name: record_name.to_owned(), + }, + ) + })?; + + if record_fields.len() != record_type.fields.len() { + return Err(InstructionError::new( + instruction, + InstructionErrorKind::InvalidValueOnTheStack { + expected_type: interface_type.clone(), + received_value: interface_value.clone(), + }, + )); + } + + for (record_type_field, record_value_field) in + record_type.fields.iter().zip(record_fields.iter()) + { + is_value_compatible_to_type( + instance, + &record_type_field.ty, + record_value_field, + instruction, + )?; + } + + Ok(()) + } + _ => Err(InstructionError::new( + instruction, + InstructionErrorKind::InvalidValueOnTheStack { + expected_type: interface_type.clone(), + received_value: interface_value.clone(), + }, + )), + } +} + #[cfg(test)] pub(crate) mod tests { use crate::{ast::*, interpreter::wasm, types::*, values::*}; @@ -381,7 +494,7 @@ pub(crate) mod tests { Some(&self.memory) } - fn wit_type(&self, index: u32) -> Option<&Type> { + fn wit_type_by_id(&self, index: u32) -> Option<&Type> { self.wit_types.get(index as usize) } } diff --git a/src/interpreter/instructions/numbers.rs b/src/interpreter/instructions/numbers.rs index bedae26..e2d4d79 100644 --- a/src/interpreter/instructions/numbers.rs +++ b/src/interpreter/instructions/numbers.rs @@ -33,7 +33,7 @@ macro_rules! lowering_lifting { instruction, InstructionErrorKind::InvalidValueOnTheStack { expected_type: InterfaceType::$from_variant, - received_type: (&wrong_value).into(), + received_value: wrong_value, } )) }, diff --git a/src/interpreter/instructions/records.rs b/src/interpreter/instructions/records.rs index fc81809..6f0dd15 100644 --- a/src/interpreter/instructions/records.rs +++ b/src/interpreter/instructions/records.rs @@ -9,18 +9,16 @@ use crate::interpreter::instructions::to_native; use crate::{ ast::{Type, TypeKind}, errors::{InstructionError, InstructionErrorKind}, - interpreter::{ - stack::{Stack, Stackable}, - Instruction, - }, + interpreter::Instruction, types::{InterfaceType, RecordType}, - values::{FlattenInterfaceValueIterator, InterfaceValue}, + values::InterfaceValue, vec1::Vec1, }; use std::collections::VecDeque; use std::convert::TryInto; +/* /// Build an `InterfaceValue::Record` based on values on the stack. /// /// To fill a record, every field `field_1` to `field_n` must get its @@ -105,10 +103,11 @@ where } }) } + */ fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance mut Instance, - record_type: RecordType, + instance: &'instance Instance, + record_type: &RecordType, offset: usize, instruction: Instruction, ) -> Result @@ -123,8 +122,8 @@ where fn record_size(record_type: &RecordType) -> usize { let mut record_size = 0; - for ty in record_type.fields.iter() { - let params_count = match ty { + for field_type in record_type.fields.iter() { + let params_count = match field_type.ty { InterfaceType::String | InterfaceType::ByteArray => 2, _ => 1, }; @@ -137,16 +136,16 @@ where let length = record_type.fields.len(); let mut values = VecDeque::with_capacity(length); - let size = record_size(&record_type); + let size = record_size(record_type); let data = read_from_instance_mem(instance, instruction, offset, size)?; // TODO: add error handling let data = safe_transmute::transmute_many::(&data).unwrap(); let mut field_id = 0; - for field in record_type.fields.into_vec() { + for field in (*record_type.fields).iter() { let value = data[field_id]; - match field { + match &field.ty { InterfaceType::S8 => { values.push_back(InterfaceValue::S8(value as _)); } @@ -201,7 +200,7 @@ where utils::deallocate(instance, instruction, string_offset as _, string_size as _)?; } else { - values.push_back(InterfaceValue::String("".to_string())); + values.push_back(InterfaceValue::String(String::new())); } } InterfaceType::ByteArray => { @@ -224,9 +223,21 @@ where values.push_back(InterfaceValue::ByteArray(vec![])); } } - InterfaceType::Record(record_type) => { + InterfaceType::Record(record_type_name) => { let offset = value; + let record_type = + instance + .wit_record_by_name(&record_type_name) + .ok_or_else(|| { + InstructionError::new( + instruction, + InstructionErrorKind::RecordTypeByNameIsMissing { + type_name: record_type_name.to_owned(), + }, + ) + })?; + values.push_back(record_lift_memory_( instance, record_type, @@ -275,8 +286,8 @@ where .map_err(|k| InstructionError::new(instruction, k))?; // TODO: size = 0 - let instance = &mut runtime.wasm_instance; - let record_type = match instance.wit_type(type_index).ok_or_else(|| { + let instance = &runtime.wasm_instance; + let record_type = match instance.wit_type_by_id(type_index).ok_or_else(|| { InstructionError::new( instruction, InstructionErrorKind::TypeIsMissing { type_index }, @@ -294,7 +305,7 @@ where } }; - let record = record_lift_memory_(*instance, record_type, offset, instruction)?; + let record = record_lift_memory_(&**instance, &record_type, offset, instruction)?; runtime.stack.push(record); Ok(()) @@ -353,8 +364,8 @@ where result.push(value.len() as _); } - InterfaceValue::Record(record) => { - let record_ptr = record_lower_memory_(instance, instruction, record)?; + InterfaceValue::Record(values) => { + let record_ptr = record_lower_memory_(instance, instruction, values)?; result.push(record_ptr as _); } @@ -384,7 +395,7 @@ where Box::new({ move |runtime| -> _ { let instance = &mut runtime.wasm_instance; - let record_type = match instance.wit_type(type_index).ok_or_else(|| { + let record_type = match instance.wit_type_by_id(type_index).ok_or_else(|| { InstructionError::new( instruction, InstructionErrorKind::TypeIsMissing { type_index }, @@ -401,10 +412,9 @@ where )) } }; + match runtime.stack.pop1() { - Some(InterfaceValue::Record(record_values)) - if record_type == &(&*record_values).into() => - { + Some(InterfaceValue::Record(record_values)) => { /* let value: Vec = crate::serde::de::from_interface_values(&record_values) .map_err(|e| { @@ -426,8 +436,8 @@ where Some(value) => Err(InstructionError::new( instruction, InstructionErrorKind::InvalidValueOnTheStack { - expected_type: InterfaceType::Record(record_type.clone()), - received_type: (&value).into(), + expected_type: InterfaceType::Record(record_type.name.clone()), + received_value: value, }, )), None => Err(InstructionError::new( @@ -439,6 +449,7 @@ where }) } +/* pub(crate) fn record_lower( type_index: u32, instruction: Instruction, @@ -498,3 +509,4 @@ where } }) } + */ diff --git a/src/interpreter/instructions/records/utils.rs b/src/interpreter/instructions/records/utils.rs index ccae7ee..4e99ed2 100644 --- a/src/interpreter/instructions/records/utils.rs +++ b/src/interpreter/instructions/records/utils.rs @@ -42,7 +42,7 @@ where } pub(super) fn write_to_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance mut Instance, + instance: &'instance Instance, instruction: Instruction, bytes: &[u8], ) -> Result @@ -74,7 +74,7 @@ where } pub(super) fn allocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance mut Instance, + instance: &'instance Instance, instruction: Instruction, size: i32, ) -> Result @@ -105,7 +105,7 @@ where } pub(super) fn deallocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance mut Instance, + instance: &'instance Instance, instruction: Instruction, mem_ptr: i32, size: i32, @@ -128,7 +128,7 @@ where } fn call_core<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance mut Instance, + instance: &'instance Instance, function_index: u32, instruction: Instruction, inputs: Vec, @@ -147,20 +147,9 @@ where InstructionErrorKind::LocalOrImportIsMissing { function_index }, ) })?; - let input_types = inputs - .iter() - .map(Into::into) - .collect::>(); - if input_types != local_or_import.inputs() { - return Err(InstructionError::new( - instruction, - InstructionErrorKind::LocalOrImportSignatureMismatch { - function_index, - expected: (local_or_import.inputs().to_vec(), vec![]), - received: (input_types, vec![]), - }, - )); - } + + crate::interpreter::instructions::check_function_signature(instance, local_or_import, &inputs, instruction)?; + let outputs = local_or_import.call(&inputs).map_err(|_| { InstructionError::new( instruction, diff --git a/src/interpreter/instructions/strings.rs b/src/interpreter/instructions/strings.rs index cdbfe80..1b36cb9 100644 --- a/src/interpreter/instructions/strings.rs +++ b/src/interpreter/instructions/strings.rs @@ -131,7 +131,7 @@ executable_instruction!( instruction, InstructionErrorKind::InvalidValueOnTheStack { expected_type: InterfaceType::String, - received_type: (&value).into(), + received_value: (&value).clone(), }, )), diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 76aa69a..68c3f1f 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -245,13 +245,14 @@ where } Instruction::ByteArraySize => instructions::byte_array_size(*instruction), + /* Instruction::RecordLift { type_index } => { instructions::record_lift(*type_index, *instruction) } Instruction::RecordLower { type_index } => { instructions::record_lower(*type_index, *instruction) } - + */ Instruction::RecordLiftMemory { type_index } => { instructions::record_lift_memory(*type_index, *instruction) } diff --git a/src/interpreter/wasm/structures.rs b/src/interpreter/wasm/structures.rs index 217a418..0893c86 100644 --- a/src/interpreter/wasm/structures.rs +++ b/src/interpreter/wasm/structures.rs @@ -1,5 +1,6 @@ #![allow(missing_docs)] +use crate::types::RecordType; use crate::{ast, types::InterfaceType, values::InterfaceValue}; use std::{cell::Cell, ops::Deref}; @@ -72,9 +73,10 @@ where MV: MemoryView, { fn export(&self, export_name: &str) -> Option<&E>; - fn local_or_import(&mut self, index: I) -> Option<&LI>; + fn local_or_import(&self, index: I) -> Option<&LI>; fn memory(&self, index: usize) -> Option<&M>; - fn wit_type(&self, index: u32) -> Option<&ast::Type>; + fn wit_type_by_id(&self, index: u32) -> Option<&ast::Type>; + fn wit_record_by_name(&self, name: &str) -> Option<&RecordType>; } impl Export for () { @@ -154,11 +156,15 @@ where None } - fn local_or_import(&mut self, _index: I) -> Option<&LI> { + fn local_or_import(&self, _index: I) -> Option<&LI> { None } - fn wit_type(&self, _index: u32) -> Option<&ast::Type> { + fn wit_type_by_id(&self, _index: u32) -> Option<&ast::Type> { + None + } + + fn wit_record_by_name(&self, _name: &str) -> Option<&RecordType> { None } } diff --git a/src/serde/de.rs b/src/serde/de.rs index b4e82e0..9d901ea 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -91,7 +91,7 @@ macro_rules! next { Some(wrong_value) => Err(DeserializeError::TypeMismatch { expected_type: InterfaceType::$variant, - received_type: (*wrong_value).into(), + received_value: (*wrong_value).clone(), }), None => Err(DeserializeError::InputEmpty), @@ -122,7 +122,7 @@ impl<'de> Deserializer<'de> { Some(wrong_value) => Err(DeserializeError::TypeMismatch { expected_type: InterfaceType::String, - received_type: (*wrong_value).into(), + received_value: (*wrong_value).clone(), }), None => Err(DeserializeError::InputEmpty), @@ -139,7 +139,7 @@ impl<'de> Deserializer<'de> { Some(wrong_value) => Err(DeserializeError::TypeMismatch { expected_type: InterfaceType::ByteArray, - received_type: (*wrong_value).into(), + received_value: (*wrong_value).clone(), }), None => Err(DeserializeError::InputEmpty), @@ -165,7 +165,7 @@ pub enum DeserializeError { expected_type: InterfaceType, /// The received type. - received_type: InterfaceType, + received_value: InterfaceValue, }, /// Arbitrary message. @@ -186,11 +186,11 @@ impl Display for DeserializeError { Self::InputEmpty => write!(formatter, "Unexpected end of input"), Self::TypeMismatch { ref expected_type, - ref received_type, + ref received_value, } => write!( formatter, - "Type mismatch detected, expected `{:?}` but received `{:?}`", - expected_type, received_type + "Type mismatch detected: `{:?}` can't be converted to `{:?}`", + received_value, expected_type, ), } } @@ -220,7 +220,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { Some(InterfaceValue::ByteArray(_)) => self.deserialize_bytes(visitor), Some(InterfaceValue::I32(_)) => self.deserialize_i32(visitor), Some(InterfaceValue::I64(_)) => self.deserialize_i64(visitor), - Some(InterfaceValue::Record(_)) => unreachable!("Records should have been flattened."), // already flattened + Some(InterfaceValue::Record(..)) => unreachable!("Records should have been flattened."), // already flattened None => Err(DeserializeError::InputEmpty), } } diff --git a/src/types.rs b/src/types.rs index e4d6ca4..444667d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -51,15 +51,30 @@ pub enum InterfaceType { /// A 64-bits integer (as defiend in WebAssembly core). I64, - /// A record. - Record(RecordType), + /// A record contains type name. + // TODO: consider making it &str + Record(String), +} + +/// Represents a record field type. +#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)] +pub struct RecordFieldType { + // TODO: make name optional to support structures with anonymous fields in Rust + /// A field name. + pub name: String, + + /// A field type. + pub ty: InterfaceType, } /// Represents a record type. #[derive(PartialEq, Debug, Clone, Serialize, Deserialize)] pub struct RecordType { - /// Types representing the fields. + /// A record name. + pub name: String, + + /// Types and names representing the fields. /// A record must have at least one field, hence the /// [`Vec1`][crate::vec1::Vec1]. - pub fields: Vec1, + pub fields: Vec1, } diff --git a/src/values.rs b/src/values.rs index 13156d1..a705f5e 100644 --- a/src/values.rs +++ b/src/values.rs @@ -1,10 +1,6 @@ //! Defines WIT values and associated operations. -use crate::{ - errors::WasmValueNativeCastError, - types::{InterfaceType, RecordType}, - vec1::Vec1, -}; +use crate::{errors::WasmValueNativeCastError, types::InterfaceType, vec1::Vec1}; use std::{convert::TryFrom, slice::Iter}; #[cfg(feature = "serde")] @@ -60,6 +56,7 @@ pub enum InterfaceValue { Record(Vec1), } +/* impl From<&InterfaceValue> for InterfaceType { fn from(value: &InterfaceValue) -> Self { match value { @@ -78,10 +75,11 @@ impl From<&InterfaceValue> for InterfaceType { //InterfaceValue::Anyref(_) => Self::Anyref, InterfaceValue::I32(_) => Self::I32, InterfaceValue::I64(_) => Self::I64, - InterfaceValue::Record(values) => Self::Record((&**values).into()), + InterfaceValue::Record(name) => Self::Record(name.to_owned()), } } } + */ impl Default for InterfaceValue { fn default() -> Self { @@ -89,6 +87,7 @@ impl Default for InterfaceValue { } } +/* impl From<&Vec> for RecordType { fn from(values: &Vec) -> Self { RecordType { @@ -97,6 +96,7 @@ impl From<&Vec> for RecordType { } } } + */ /// Represents a native type supported by WIT. pub trait NativeType { @@ -123,7 +123,7 @@ macro_rules! native { match w { InterfaceValue::$variant(n) => Ok(n.clone()), _ => Err(WasmValueNativeCastError { - from: w.into(), + from: w.clone(), to: <$native_type>::INTERFACE_TYPE, }), } @@ -173,8 +173,8 @@ impl<'a> Iterator for FlattenInterfaceValueIterator<'a> { } // Recursively iterate over the record. - Some(InterfaceValue::Record(values)) => { - self.iterators.push(values.iter()); + Some(InterfaceValue::Record(fields)) => { + self.iterators.push(fields.iter()); self.next() }