Merge pull request #5 from fluencelabs/record_support

Record refactoring
This commit is contained in:
vms 2020-09-16 00:25:02 +03:00 committed by GitHub
commit 0f8638c594
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 123 additions and 65 deletions

View File

@ -25,7 +25,7 @@ pub struct AstFunctionSignature {
#[serde(skip)]
pub visibility: Option<syn::Visibility>,
pub name: String,
pub input_types: Vec<ParsedType>,
pub arguments: Vec<(String, ParsedType)>,
// fce supports only one return value now,
// waiting for adding multi-value support in Wasmer.
pub output_type: Option<ParsedType>,

View File

@ -44,4 +44,4 @@ pub use parsed_type::ParsedType;
pub use token_stream_generator::GENERATED_WRAPPER_FUNC_PREFIX;
pub use token_stream_generator::GENERATED_SECTION_PREFIX;
pub use token_stream_generator::GENERATED_GLOBAL_PREFIX;
pub use wasm_type::WasmType;
pub use wasm_type::RustType;

View File

@ -36,22 +36,44 @@ pub(super) fn try_to_ast_signature(
visibility: syn::Visibility,
) -> Result<fce_ast_types::AstFunctionSignature> {
use crate::parsed_type::ParsedType;
use syn::spanned::Spanned;
use quote::ToTokens;
check_function(&signature)?;
let syn::Signature { inputs, output, .. } = signature;
let input_types = inputs
let arguments = inputs
.iter()
.map(ParsedType::from_fn_arg)
.collect::<Result<Vec<_>>>()?;
.map(|arg| -> Result<(String, ParsedType)> {
let pat = match arg {
syn::FnArg::Typed(arg) => arg,
_ => {
return Err(syn::Error::new(
arg.span(),
"`self` argument types aren't supported",
))
}
};
Ok((
pat.pat
.to_token_stream()
.to_string()
.split(' ')
.last()
.unwrap_or_default()
.to_string(),
ParsedType::from_type(pat.ty.as_ref())?,
))
})
.collect::<Result<Vec<(_, _)>>>()?;
let output_type = ParsedType::from_return_type(&output)?;
let ast_function_item = fce_ast_types::AstFunctionSignature {
visibility: Some(visibility),
name: signature.ident.to_string(),
input_types,
arguments,
output_type,
};

View File

@ -37,7 +37,14 @@ impl ParseMacroInput for syn::ItemStruct {
.iter()
.map(|field| {
check_field(field)?;
let field_name = field.ident.as_ref().map(|ident| ident.to_string());
let field_name = field.ident.as_ref().map(|ident| {
ident
.to_string()
.split(' ')
.last()
.unwrap_or_default()
.to_string()
});
let field_type = ParsedType::from_type(&field.ty)?;
Ok(AstRecordField {
name: field_name,

View File

@ -48,7 +48,7 @@ pub enum ParsedType {
Boolean,
Utf8String,
ByteVector,
Record(String), // full type name
Record(String), // short type name
}
impl ParsedType {
@ -114,7 +114,7 @@ impl ParsedType {
syn::Type::Path(path) => Ok(&path.path),
_ => Err(Error::new(
input_type.span(),
"Incorrect argument type - only Vec<u8> and String are supported",
"Incorrect argument type - passing only by value is supported now",
)),
}?;
@ -152,14 +152,19 @@ impl ParsedType {
type_segment.span(),
"type with lifetimes or generics aren't allowed".to_string(),
)),
_ => Ok(ParsedType::Record(path.into_token_stream().to_string())),
_ => Ok(ParsedType::Record(
(&type_segment.ident).into_token_stream().to_string(),
)),
}
}
pub fn from_fn_arg(fn_arg: &syn::FnArg) -> syn::Result<Self> {
match fn_arg {
syn::FnArg::Typed(arg) => ParsedType::from_type(&arg.ty),
_ => Err(Error::new(fn_arg.span(), "Unknown argument")),
_ => Err(Error::new(
fn_arg.span(),
"`self` argument types aren't supported",
)),
}
}

View File

@ -15,28 +15,29 @@
*/
use super::ParsedType;
use crate::wasm_type::WasmType;
use crate::wasm_type::RustType;
/// This trait could be used to generate raw args needed to construct a export function.
pub(crate) trait FnArgGlueCodeGenerator {
fn generate_arguments(&self) -> Vec<WasmType>;
fn generate_arguments(&self) -> Vec<RustType>;
}
impl FnArgGlueCodeGenerator for ParsedType {
fn generate_arguments(&self) -> Vec<WasmType> {
match self {
ParsedType::Boolean
| ParsedType::I8
| ParsedType::I16
| ParsedType::I32
| ParsedType::U8
| ParsedType::U16
| ParsedType::U32
| ParsedType::Record(_) => vec![WasmType::I32],
ParsedType::I64 | ParsedType::U64 => vec![WasmType::I64],
ParsedType::F32 => vec![WasmType::F32],
ParsedType::F64 => vec![WasmType::F64],
ParsedType::Utf8String | ParsedType::ByteVector => vec![WasmType::I32, WasmType::I32],
impl FnArgGlueCodeGenerator for (String, ParsedType) {
fn generate_arguments(&self) -> Vec<RustType> {
match self.1 {
ParsedType::Boolean => vec![RustType::I32],
ParsedType::I8 => vec![RustType::I8],
ParsedType::I16 => vec![RustType::I16],
ParsedType::I32 => vec![RustType::I32],
ParsedType::I64 => vec![RustType::I64],
ParsedType::U8 => vec![RustType::U8],
ParsedType::U16 => vec![RustType::U16],
ParsedType::U32 => vec![RustType::U32],
ParsedType::U64 => vec![RustType::U64],
ParsedType::Record(_) => vec![RustType::U32],
ParsedType::F32 => vec![RustType::F32],
ParsedType::F64 => vec![RustType::F64],
ParsedType::Utf8String | ParsedType::ByteVector => vec![RustType::U32, RustType::U32],
}
}
}

View File

@ -53,19 +53,17 @@ impl FnEpilogGlueCodeGenerator for Option<ParsedType> {
fn generate_fn_return_type(ty: &Option<ParsedType>) -> proc_macro2::TokenStream {
let ty = match ty {
Some(ParsedType::Boolean)
| Some(ParsedType::I8)
| Some(ParsedType::I16)
| Some(ParsedType::I32)
| Some(ParsedType::U8)
| Some(ParsedType::U16)
| Some(ParsedType::U32) => Some("i32"),
Some(ParsedType::I64) | Some(ParsedType::U64) => Some("i64"),
Some(ParsedType::Boolean) => Some("i32"),
Some(ParsedType::I8) => Some("i8"),
Some(ParsedType::I16) => Some("i16"),
Some(ParsedType::I32) => Some("i32"),
Some(ParsedType::I64) => Some("i64"),
Some(ParsedType::U8) => Some("u8"),
Some(ParsedType::U16) => Some("u16"),
Some(ParsedType::U32) => Some("u32"),
Some(ParsedType::U64) => Some("u64"),
Some(ParsedType::F32) => Some("f32"),
Some(ParsedType::F64) => Some("f64"),
None
| Some(ParsedType::Utf8String)
| Some(ParsedType::ByteVector)

View File

@ -17,14 +17,14 @@
use super::ParsedType;
use super::FnArgGlueCodeGenerator;
use crate::new_ident;
use crate::wasm_type::WasmType;
use crate::wasm_type::RustType;
use quote::quote;
/// Describes various parts of a function prolog.
pub(crate) struct FnPrologDescriptor {
pub(crate) raw_arg_names: Vec<syn::Ident>,
pub(crate) raw_arg_types: Vec<WasmType>,
pub(crate) raw_arg_types: Vec<RustType>,
pub(crate) prolog: proc_macro2::TokenStream,
pub(crate) args: Vec<syn::Ident>,
}
@ -44,7 +44,7 @@ pub(crate) trait FnPrologGlueCodeGenerator {
fn generate_prolog(&self) -> FnPrologDescriptor;
}
impl FnPrologGlueCodeGenerator for Vec<ParsedType> {
impl FnPrologGlueCodeGenerator for Vec<(String, ParsedType)> {
fn generate_prolog(&self) -> FnPrologDescriptor {
let mut prolog = proc_macro2::TokenStream::new();
let mut args: Vec<syn::Ident> = Vec::with_capacity(self.len());
@ -52,9 +52,9 @@ impl FnPrologGlueCodeGenerator for Vec<ParsedType> {
let mut raw_arg_types = Vec::with_capacity(self.len());
let mut input_type_id = 0;
for input_type in self {
let type_prolog = generate_type_prolog(input_type, input_type_id, input_type_id);
let curr_raw_arg_types = input_type.generate_arguments();
for arg in self {
let type_prolog = generate_type_prolog(&arg.1, input_type_id, input_type_id);
let curr_raw_arg_types = arg.generate_arguments();
args.push(new_ident!(format!("converted_arg_{}", input_type_id)));
@ -87,6 +87,12 @@ fn generate_type_prolog(
let generated_arg_id = new_ident!(format!("converted_arg_{}", generated_arg_id));
match ty {
ParsedType::Boolean => {
let supplied_arg_start_id = new_ident!(format!("arg_{}", supplied_arg_start_id));
quote! {
let #generated_arg_id = #supplied_arg_start_id != 0;
}
}
ty if !ty.is_complex_type() => {
let supplied_arg_start_id = new_ident!(format!("arg_{}", supplied_arg_start_id));
quote! {

View File

@ -36,7 +36,8 @@ impl ForeignModArgGlueCodeGenerator for ParsedType {
#arg.__fce_generated_serialize() as _
}
}
_ => quote! { arg },
ParsedType::Boolean => quote! { #arg as _ },
_ => quote! { #arg },
}
}
}

View File

@ -41,6 +41,9 @@ impl ForeignModEpilogGlueCodeGenerator for Option<ParsedType> {
fn generate_wrapper_epilog(&self) -> proc_macro2::TokenStream {
match self {
None => quote!(),
Some(ParsedType::Boolean) => quote! {
return result != 0;
},
Some(ty) if !ty.is_complex_type() => quote! {
return result as _;
},

View File

@ -15,7 +15,7 @@
*/
use super::ParsedType;
use crate::wasm_type::WasmType;
use crate::wasm_type::RustType;
use crate::new_ident;
pub(crate) struct WrapperDescriptor {
@ -28,7 +28,7 @@ pub(crate) struct WrapperDescriptor {
pub(crate) struct ExternDescriptor {
pub(crate) raw_arg_names: Vec<syn::Ident>,
pub(crate) raw_arg_types: Vec<WasmType>,
pub(crate) raw_arg_types: Vec<RustType>,
}
/// This trait could be used to generate various parts needed to construct prolog of an wrapper
@ -57,25 +57,28 @@ pub(crate) trait ForeignModPrologGlueCodeGenerator {
fn generate_extern_prolog(&self) -> ExternDescriptor;
}
impl ForeignModPrologGlueCodeGenerator for Vec<ParsedType> {
impl ForeignModPrologGlueCodeGenerator for Vec<(String, ParsedType)> {
fn generate_wrapper_prolog(&self) -> WrapperDescriptor {
use crate::parsed_type::foreign_mod_arg::ForeignModArgGlueCodeGenerator;
let arg_types: Vec<proc_macro2::TokenStream> = self
.iter()
.map(|input_type| input_type.to_token_stream())
.map(|(_, input_type)| input_type.to_token_stream())
.collect();
let (arg_names, arg_transforms, arg_drops) = self
.iter()
.enumerate()
.fold((Vec::new(), proc_macro2::TokenStream::new(), proc_macro2::TokenStream::new()), |(mut arg_names, mut arg_transforms, mut arg_drops), (id, ty)| {
.fold((Vec::new(), proc_macro2::TokenStream::new(), proc_macro2::TokenStream::new()), |(mut arg_names, mut arg_transforms, mut arg_drops), (id, (_, ty))| {
let arg_ident = new_ident!(format!("arg_{}", id));
arg_names.push(arg_ident.clone());
if ty.is_complex_type() {
arg_transforms.extend(quote::quote! { let mut #arg_ident = std::mem::ManuallyDrop::new(#arg_ident); });
arg_drops.extend(quote::quote! { std::mem::ManuallyDrop::drop(&mut #arg_ident); });
match ty {
ParsedType::ByteVector | ParsedType::Utf8String => {
arg_transforms.extend(quote::quote! { let mut #arg_ident = std::mem::ManuallyDrop::new(#arg_ident); });
arg_drops.extend(quote::quote! { std::mem::ManuallyDrop::drop(&mut #arg_ident); });
},
_ => {}
}
(arg_names, arg_transforms, arg_drops)
@ -84,7 +87,7 @@ impl ForeignModPrologGlueCodeGenerator for Vec<ParsedType> {
let raw_args: Vec<proc_macro2::TokenStream> = self
.iter()
.enumerate()
.map(|(id, input_type)| input_type.generate_raw_args(id))
.map(|(id, (_, input_type))| input_type.generate_raw_args(id))
.collect();
WrapperDescriptor {
@ -99,7 +102,7 @@ impl ForeignModPrologGlueCodeGenerator for Vec<ParsedType> {
fn generate_extern_prolog(&self) -> ExternDescriptor {
use crate::parsed_type::FnArgGlueCodeGenerator;
let raw_arg_types: Vec<WasmType> = self
let raw_arg_types: Vec<RustType> = self
.iter()
.map(|input_type| input_type.generate_arguments())
.flatten()

View File

@ -49,7 +49,7 @@ impl quote::ToTokens for fce_ast_types::AstFunctionItem {
raw_arg_types,
prolog,
args,
} = &signature.input_types.generate_prolog();
} = &signature.arguments.generate_prolog();
let FnEpilogDescriptor {
fn_return_type,

View File

@ -74,7 +74,7 @@ fn generate_extern_section_items(extern_item: &fce_ast_types::AstExternModItem)
let ExternDescriptor {
raw_arg_names,
raw_arg_types,
} = signature.input_types.generate_extern_prolog();
} = signature.arguments.generate_extern_prolog();
let func = quote! {
#[link_name = #link_name]
@ -110,7 +110,7 @@ fn generate_wrapper_functions(extern_item: &fce_ast_types::AstExternModItem) ->
raw_args,
arg_transforms,
arg_drops,
} = signature.input_types.generate_wrapper_prolog();
} = signature.arguments.generate_wrapper_prolog();
let FnEpilogDescriptor {
return_expression, ..

View File

@ -1,21 +1,33 @@
use proc_macro2::TokenStream;
/// Raw Wasm types according to the spec except i128.
pub enum WasmType {
pub enum RustType {
U8,
U16,
U32,
U64,
I8,
I16,
I32,
I64,
F32,
F64,
}
impl quote::ToTokens for WasmType {
impl quote::ToTokens for RustType {
fn to_tokens(&self, tokens: &mut TokenStream) {
let call_site = proc_macro2::Span::call_site();
match self {
WasmType::I32 => syn::Ident::new("i32", call_site).to_tokens(tokens),
WasmType::I64 => syn::Ident::new("i64", call_site).to_tokens(tokens),
WasmType::F32 => syn::Ident::new("f32", call_site).to_tokens(tokens),
WasmType::F64 => syn::Ident::new("f64", call_site).to_tokens(tokens),
RustType::U8 => syn::Ident::new("u8", call_site).to_tokens(tokens),
RustType::U16 => syn::Ident::new("u16", call_site).to_tokens(tokens),
RustType::U32 => syn::Ident::new("u32", call_site).to_tokens(tokens),
RustType::U64 => syn::Ident::new("u64", call_site).to_tokens(tokens),
RustType::I8 => syn::Ident::new("i8", call_site).to_tokens(tokens),
RustType::I16 => syn::Ident::new("i16", call_site).to_tokens(tokens),
RustType::I32 => syn::Ident::new("i32", call_site).to_tokens(tokens),
RustType::I64 => syn::Ident::new("i64", call_site).to_tokens(tokens),
RustType::F32 => syn::Ident::new("f32", call_site).to_tokens(tokens),
RustType::F64 => syn::Ident::new("f64", call_site).to_tokens(tokens),
}
}
}