improve foreign item parsing

This commit is contained in:
vms 2020-07-03 13:04:51 +03:00
parent 06dc49e6e3
commit 1b76203c91
7 changed files with 287 additions and 207 deletions

View File

@ -21,7 +21,7 @@ use serde::Deserialize;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct AstFunctionItem {
pub(crate) name: String,
pub(crate) rust_name: String,
pub(crate) input_types: Vec<ParsedType>,
// fce supports only one return value now,
// waiting for adding multi-value support in Wasmer.
@ -33,11 +33,18 @@ pub(crate) struct AstRecordItem {
pub(crate) fields: Vec<ParsedType>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct AstExternFnItem {
pub(crate) link_name: Option<String>,
// only imports are possible here
pub(crate) function: AstFunctionItem,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct AstExternModItem {
pub(crate) namespace: String,
// only imports are possible here
pub(crate) imports: Vec<AstFunctionItem>,
pub(crate) imports: Vec<AstExternFnItem>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]

View File

@ -44,7 +44,7 @@ pub(super) fn parse_function(
let output_type = ParsedType::from_return_type(&output)?;
let ast_function_item = fce_ast_types::AstFunctionItem {
name: function_sig.ident.to_string(),
rust_name: function_sig.ident.to_string(),
input_types,
output_type,
};

View File

@ -80,13 +80,13 @@ impl ParseMacroInput for syn::ItemForeignMod {
}
}
fn parse_raw_foreign_item(raw_item: syn::ForeignItem) -> Result<fce_ast_types::AstFunctionItem> {
fn parse_raw_foreign_item(raw_item: syn::ForeignItem) -> Result<fce_ast_types::AstExternFnItem> {
let function_item = match raw_item {
syn::ForeignItem::Fn(function_item) => function_item,
_ => {
return Err(Error::new(
raw_item.span(),
"#[fce] could be upplied only to a function, struct ot extern block",
"#[fce] could be applied only to a function, struct ot extern block",
))
}
};
@ -102,13 +102,13 @@ fn parse_raw_foreign_item(raw_item: syn::ForeignItem) -> Result<fce_ast_types::A
.map(extract_value)
.collect();
let mut function_item = super::item_fn::parse_function(function_item.sig, function_item.vis)?;
let function = super::item_fn::parse_function(function_item.sig, function_item.vis)?;
let ast_extern_fn_item = fce_ast_types::AstExternFnItem {
link_name,
function,
};
if let Some(link_name) = link_name {
function_item.name = link_name;
}
Ok(function_item)
Ok(ast_extern_fn_item)
}
fn extract_value(nested_meta: syn::Meta) -> Option<String> {

View File

@ -14,9 +14,10 @@
* limitations under the License.
*/
use crate::wasm_type::WasmType;
mod glue_code_generator;
pub(crate) use glue_code_generator::GlueCodeGenerator;
use quote::quote;
use serde::Serialize;
use serde::Deserialize;
use syn::parse::Error;
@ -163,190 +164,3 @@ impl ParsedType {
}
}
}
// TODO: replace String with Ident
pub(crate) trait MacroPartsGenerator {
fn generate_arguments(&self) -> Vec<WasmType>;
fn generate_return_expression(&self) -> proc_macro2::TokenStream;
fn generate_return_type(&self) -> String;
fn generate_fn_prolog(
&self,
generated_arg_id: usize,
supplied_arg_start_id: usize,
) -> proc_macro2::TokenStream;
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream;
}
impl MacroPartsGenerator for ParsedType {
fn generate_arguments(&self) -> Vec<WasmType> {
// TODO: investigate possible issues in conversion between signed and unsigned types
match self {
ParsedType::Empty => vec![],
ParsedType::I8 => vec![WasmType::I32],
ParsedType::I16 => vec![WasmType::I32],
ParsedType::I32 => vec![WasmType::I32],
ParsedType::I64 => vec![WasmType::I64],
ParsedType::U8 => vec![WasmType::I32],
ParsedType::U16 => vec![WasmType::I32],
ParsedType::U32 => vec![WasmType::I32],
ParsedType::U64 => vec![WasmType::I64],
ParsedType::F32 => vec![WasmType::F32],
ParsedType::F64 => vec![WasmType::F64],
ParsedType::Boolean => vec![WasmType::I32],
ParsedType::Utf8String => vec![WasmType::I32, WasmType::I32],
ParsedType::ByteVector => vec![WasmType::I32, WasmType::I32],
ParsedType::Record(_) => vec![WasmType::I32, WasmType::I32],
}
}
fn generate_return_expression(&self) -> proc_macro2::TokenStream {
match self {
ParsedType::Empty => quote! {},
ParsedType::Utf8String => quote! {},
ParsedType::ByteVector => quote! {},
ParsedType::Record(_) => quote! {},
_ => quote! {
let result =
},
}
}
fn generate_return_type(&self) -> String {
match self {
ParsedType::I8 => "-> i32",
ParsedType::I16 => "-> i32",
ParsedType::I32 => "-> i32",
ParsedType::I64 => "-> i64",
ParsedType::U8 => "-> i32",
ParsedType::U16 => "-> i32",
ParsedType::U32 => "-> i32",
ParsedType::U64 => "-> i64",
ParsedType::F32 => "-> f32",
ParsedType::F64 => "-> f64",
ParsedType::Boolean => "-> i32",
_ => "",
}
.to_string()
}
fn generate_fn_prolog(
&self,
generated_ard_id: usize,
supplied_arg_start_id: usize,
) -> proc_macro2::TokenStream {
match self {
ParsedType::Empty => unimplemented!(),
ParsedType::I8 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as i8;
},
ParsedType::I16 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as i16;
},
ParsedType::I32 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as i32;
},
ParsedType::I64 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as i64;
},
ParsedType::U8 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as u8;
},
ParsedType::U16 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as u16;
},
ParsedType::U32 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as u32;
},
ParsedType::U64 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as u64;
},
ParsedType::F32 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as f32;
},
ParsedType::F64 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as f64;
},
ParsedType::Boolean => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as bool;
},
ParsedType::Utf8String => quote! {
let converted_arg_#generated_ard_id = String::from_raw_parts(
arg_#supplied_arg_start_id,
arg_#(supplied_arg_start_id+1),
arg_#(supplied_arg_start_id+1)
);
},
ParsedType::ByteVector => quote! {
let converted_arg_#generated_ard_id = Vec::from_raw_parts(
arg_#supplied_arg_start_id,
arg_#(supplied_arg_start_id+1),
arg_#(supplied_arg_start_id+1)
);
},
ParsedType::Record(record_name) => quote! {
let converted_arg_#generated_ard_id = __fce_generated_converter_#record_name(
arg_#supplied_arg_start_id,
arg_#(supplied_arg_start_id+1)
);
},
}
}
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream {
match self {
ParsedType::Empty => quote! {},
ParsedType::I8 => quote! {
return result as _;
},
ParsedType::I16 => quote! {
return result as _;
},
ParsedType::I32 => quote! {
return result as _;
},
ParsedType::I64 => quote! {
return result as _;
},
ParsedType::U8 => quote! {
return result as _;
},
ParsedType::U16 => quote! {
return result as _;
},
ParsedType::U32 => quote! {
return result as _;
},
ParsedType::U64 => quote! {
return result as _;
},
ParsedType::F32 => quote! {
return result as _;
},
ParsedType::F64 => quote! {
return result as _;
},
ParsedType::Boolean => quote! {
return result as _;
},
ParsedType::Utf8String => quote! {
fluence::set_result_ptr(result.as_ptr() as _);
fluence::set_result_size(result.len() as _);
std::mem::forget(result);
},
ParsedType::ByteVector => quote! {
fluence::set_result_ptr(result.as_ptr() as _);
fluence::set_result_size(result.len() as _);
std::mem::forget(result);
},
ParsedType::Record(_) => quote! {
fluence::set_result_ptr(result.as_ptr() as _);
fluence::set_result_size(result.len() as _);
std::mem::forget(result);
},
}
}
}

View File

@ -0,0 +1,207 @@
/*
* Copyright 2018 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::wasm_type::WasmType;
use super::ParsedType;
use quote::quote;
pub(crate) trait GlueCodeGenerator {
fn generate_arguments(&self) -> Vec<WasmType>;
fn generate_return_expression(&self) -> proc_macro2::TokenStream;
// TODO: replace String with Ident
fn generate_return_type(&self) -> String;
fn generate_fn_prolog(
&self,
generated_arg_id: usize,
supplied_arg_start_id: usize,
) -> proc_macro2::TokenStream;
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream;
}
impl GlueCodeGenerator for ParsedType {
fn generate_arguments(&self) -> Vec<WasmType> {
// TODO: investigate possible issues in conversion between signed and unsigned types
match self {
ParsedType::Empty => vec![],
ParsedType::I8 => vec![WasmType::I32],
ParsedType::I16 => vec![WasmType::I32],
ParsedType::I32 => vec![WasmType::I32],
ParsedType::I64 => vec![WasmType::I64],
ParsedType::U8 => vec![WasmType::I32],
ParsedType::U16 => vec![WasmType::I32],
ParsedType::U32 => vec![WasmType::I32],
ParsedType::U64 => vec![WasmType::I64],
ParsedType::F32 => vec![WasmType::F32],
ParsedType::F64 => vec![WasmType::F64],
ParsedType::Boolean => vec![WasmType::I32],
ParsedType::Utf8String => vec![WasmType::I32, WasmType::I32],
ParsedType::ByteVector => vec![WasmType::I32, WasmType::I32],
ParsedType::Record(_) => vec![WasmType::I32, WasmType::I32],
}
}
fn generate_return_expression(&self) -> proc_macro2::TokenStream {
match self {
ParsedType::Empty => quote! {},
ParsedType::Utf8String => quote! {},
ParsedType::ByteVector => quote! {},
ParsedType::Record(_) => quote! {},
_ => quote! {
let result =
},
}
}
fn generate_return_type(&self) -> String {
match self {
ParsedType::I8 => "-> i32",
ParsedType::I16 => "-> i32",
ParsedType::I32 => "-> i32",
ParsedType::I64 => "-> i64",
ParsedType::U8 => "-> i32",
ParsedType::U16 => "-> i32",
ParsedType::U32 => "-> i32",
ParsedType::U64 => "-> i64",
ParsedType::F32 => "-> f32",
ParsedType::F64 => "-> f64",
ParsedType::Boolean => "-> i32",
_ => "",
}
.to_string()
}
fn generate_fn_prolog(
&self,
generated_ard_id: usize,
supplied_arg_start_id: usize,
) -> proc_macro2::TokenStream {
match self {
ParsedType::Empty => unimplemented!(),
ParsedType::I8 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as i8;
},
ParsedType::I16 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as i16;
},
ParsedType::I32 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as i32;
},
ParsedType::I64 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as i64;
},
ParsedType::U8 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as u8;
},
ParsedType::U16 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as u16;
},
ParsedType::U32 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as u32;
},
ParsedType::U64 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as u64;
},
ParsedType::F32 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as f32;
},
ParsedType::F64 => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as f64;
},
ParsedType::Boolean => quote! {
let converted_arg_#generated_ard_id = arg_#supplied_arg_start_id as bool;
},
ParsedType::Utf8String => quote! {
let converted_arg_#generated_ard_id = String::from_raw_parts(
arg_#supplied_arg_start_id,
arg_#(supplied_arg_start_id+1),
arg_#(supplied_arg_start_id+1)
);
},
ParsedType::ByteVector => quote! {
let converted_arg_#generated_ard_id = Vec::from_raw_parts(
arg_#supplied_arg_start_id,
arg_#(supplied_arg_start_id+1),
arg_#(supplied_arg_start_id+1)
);
},
ParsedType::Record(record_name) => quote! {
let converted_arg_#generated_ard_id = __fce_generated_converter_#record_name(
arg_#supplied_arg_start_id,
arg_#(supplied_arg_start_id+1)
);
},
}
}
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream {
match self {
ParsedType::Empty => quote! {},
ParsedType::I8 => quote! {
return result as _;
},
ParsedType::I16 => quote! {
return result as _;
},
ParsedType::I32 => quote! {
return result as _;
},
ParsedType::I64 => quote! {
return result as _;
},
ParsedType::U8 => quote! {
return result as _;
},
ParsedType::U16 => quote! {
return result as _;
},
ParsedType::U32 => quote! {
return result as _;
},
ParsedType::U64 => quote! {
return result as _;
},
ParsedType::F32 => quote! {
return result as _;
},
ParsedType::F64 => quote! {
return result as _;
},
ParsedType::Boolean => quote! {
return result as _;
},
ParsedType::Utf8String => quote! {
fluence::set_result_ptr(result.as_ptr() as _);
fluence::set_result_size(result.len() as _);
std::mem::forget(result);
},
ParsedType::ByteVector => quote! {
fluence::set_result_ptr(result.as_ptr() as _);
fluence::set_result_size(result.len() as _);
std::mem::forget(result);
},
ParsedType::Record(_) => quote! {
fluence::set_result_ptr(result.as_ptr() as _);
fluence::set_result_size(result.len() as _);
std::mem::forget(result);
},
}
}
}

View File

@ -14,12 +14,12 @@
* limitations under the License.
*/
use crate::fce_ast_types;
use crate::parsed_type::MacroPartsGenerator;
use super::GENERATED_FUNCS_PREFIX;
use super::GENERATED_SECTION_NAME;
use super::GENERATED_SECTION_PREFIX;
use super::TokenStreamGenerator;
use crate::fce_ast_types;
use crate::parsed_type::GlueCodeGenerator;
use proc_macro2::TokenStream;
use quote::quote;
@ -29,7 +29,7 @@ impl TokenStreamGenerator for fce_ast_types::AstFunctionItem {
fn generate_token_stream(self) -> syn::Result<TokenStream> {
let data = serde_json::to_string(&self).unwrap();
let data_size = data.len();
let func_name = self.name;
let func_name = self.rust_name;
let prefix = GENERATED_FUNCS_PREFIX;
let section_name = GENERATED_SECTION_NAME;
@ -67,17 +67,19 @@ impl TokenStreamGenerator for fce_ast_types::AstFunctionItem {
)]
#[doc(hidden)]
#[allow(clippy::all)]
pub extern "C" fn #prefix#func_name(#(#raw_args)*) #return_type {
pub extern "C" unsafe fn #prefix#func_name(#(#raw_args)*) #return_type {
#prolog
// calling the original function with converted args
#return_expression #func_name(#(#args)*);
// return value conversation from Rust type to a Wasm type
#epilog
}
#[cfg(target_arch = "wasm32")]
#[allow(clippy::all)]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = #section_name]
pub static #func_name#section_prefix#generated_global_name: [u8; #data_size] = { #data };
};

View File

@ -14,13 +14,63 @@
* limitations under the License.
*/
use crate::fce_ast_types;
use super::TokenStreamGenerator;
use super::GENERATED_FUNCS_PREFIX;
use super::GENERATED_SECTION_NAME;
use super::GENERATED_SECTION_PREFIX;
use crate::fce_ast_types;
use proc_macro2::TokenStream;
use quote::quote;
impl TokenStreamGenerator for fce_ast_types::AstExternModItem {
fn generate_token_stream(self) -> syn::Result<TokenStream> {
unimplemented!()
let data = serde_json::to_string(&self).unwrap();
let data_size = data.len();
let prefix = GENERATED_FUNCS_PREFIX;
let section_name = GENERATED_SECTION_NAME;
let section_prefix = GENERATED_SECTION_PREFIX;
let generated_global_name = uuid::Uuid::new_v4().to_string();
let visibility = "pub";
let wasm_import_module_name = self.namespace;
let glue_code = quote! {
#[link(wasm_import_module = #wasm_import_module_name)]
#[cfg(target_arch = "wasm32")]
extern "C" {
fn #import_name(#(#raw_args),*) #import_ret_type;
}
#[cfg(target_arch = "wasm32")]
unsafe fn #glue_import_name(#(#args),*) #glue_ret_type {
#prolog
#import_name();
}
#[cfg_attr(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#visibility unsafe fn #prefix#func_name(#(#args)*) #return_type {
// arg conversations from Rust types to Wasm types
#prolog
// calling the original function with converted args
#return_expression #func_name(#(#raw_args)*);
// return value conversation from Wasm type to a Rust type
#epilog
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = #section_name]
pub static #func_name#section_prefix#generated_global_name: [u8; #data_size] = { #data };
};
Ok(glue_code)
}
}