mirror of
https://github.com/fluencelabs/marine-rs-sdk-test
synced 2024-12-04 15:20:18 +00:00
update function generation
This commit is contained in:
parent
9839e54383
commit
2c68bb7a2c
@ -21,5 +21,7 @@ proc-macro = true
|
||||
syn = { version = '1.0.33', features = ['full'] }
|
||||
quote = "1.0.7"
|
||||
proc-macro2 = "1.0.18"
|
||||
serde = { version = "1.0.110", features = ["derive"] }
|
||||
serde_json = "1.0.56"
|
||||
|
||||
fluence-sdk-main = { path = "../main", version = "=0.1.11" }
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
use crate::parsed_type::ParsedType;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) struct AstFunctionItem {
|
||||
pub(crate) name: String,
|
||||
pub(crate) input_types: Vec<ParsedType>,
|
||||
@ -24,16 +28,19 @@ pub(crate) struct AstFunctionItem {
|
||||
pub(crate) output_type: ParsedType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) struct AstRecordItem {
|
||||
pub(crate) fields: Vec<ParsedType>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) struct AstExternModItem {
|
||||
pub(crate) namespace: String,
|
||||
// only imports are possible here
|
||||
pub(crate) imports: Vec<AstFunctionItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) enum FCEAst {
|
||||
Function(AstFunctionItem),
|
||||
Record(AstRecordItem),
|
||||
|
@ -31,6 +31,7 @@ mod parsed_type;
|
||||
mod macro_impl;
|
||||
mod parse_macro_input;
|
||||
mod token_stream_generator;
|
||||
mod wasm_type;
|
||||
|
||||
use macro_impl::fce_impl;
|
||||
use proc_macro::TokenStream;
|
||||
|
@ -26,52 +26,6 @@ pub(super) fn fce_impl(tokens: TokenStream) -> Result<TokenStream> {
|
||||
fce_ast_item.generate_token_stream()
|
||||
|
||||
/*
|
||||
let input_type = match sig.inputs.len() {
|
||||
0 => ParsedType::Empty,
|
||||
1 => ParsedType::from_fn_arg(sig.inputs.first().unwrap())?,
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
sig.inputs.span(),
|
||||
"The invocation handler shouldn't have more than one argument",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let output_type = ParsedType::from_return_type(&sig.output)?;
|
||||
if output_type == ParsedType::Empty {
|
||||
return Err(Error::new(
|
||||
sig.output.span(),
|
||||
"The invocation handler should have the return value",
|
||||
));
|
||||
}
|
||||
|
||||
let ident = &sig.ident;
|
||||
let prolog = input_type.generate_fn_prolog();
|
||||
let prolog = match input_type {
|
||||
ParsedType::Empty => quote! {
|
||||
#prolog
|
||||
|
||||
let result = #ident();
|
||||
},
|
||||
_ => quote! {
|
||||
#prolog
|
||||
|
||||
let result = #ident(arg);
|
||||
},
|
||||
};
|
||||
let epilog = output_type.generate_fn_epilog();
|
||||
|
||||
let resulted_invoke = quote! {
|
||||
#fn_item
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn invoke(ptr: *mut u8, len: usize) -> std::ptr::NonNull<u8> {
|
||||
#prolog
|
||||
|
||||
#epilog
|
||||
}
|
||||
};
|
||||
|
||||
Ok(resulted_invoke)
|
||||
*/
|
||||
*/
|
||||
}
|
||||
|
@ -14,12 +14,76 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
use super::ParseMacroInput;
|
||||
use crate::fce_ast_types;
|
||||
use crate::fce_ast_types::FCEAst;
|
||||
|
||||
use syn::Error;
|
||||
use syn::Result;
|
||||
use syn::spanned::Spanned;
|
||||
use crate::parsed_type::ParsedType;
|
||||
|
||||
impl ParseMacroInput for syn::ItemStruct {
|
||||
fn parse_macro_input(self) -> Result<FCEAst> {
|
||||
unimplemented!()
|
||||
check_record(&self)?;
|
||||
|
||||
let fields = match self.fields {
|
||||
syn::Fields::Named(named_field) => named_field,
|
||||
_ => return Err(Error::new(self.span(), "only named field allowed")),
|
||||
};
|
||||
|
||||
let fields = fields
|
||||
.named
|
||||
.iter()
|
||||
.map(|field| {
|
||||
check_field(field)?;
|
||||
ParsedType::from_type(&field.ty)
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
let ast_record_item = fce_ast_types::AstRecordItem { fields };
|
||||
|
||||
Ok(FCEAst::Record(ast_record_item))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_record(record: &syn::ItemStruct) -> Result<()> {
|
||||
match record.vis {
|
||||
syn::Visibility::Public(_) => {}
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
record.span(),
|
||||
"#[fce] could be applied only to public struct",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
if record.generics.lt_token.is_some()
|
||||
|| record.generics.gt_token.is_some()
|
||||
|| record.generics.where_clause.is_some()
|
||||
{
|
||||
return Err(Error::new(
|
||||
record.span(),
|
||||
"#[fce] couldn't be applied to a struct with generics",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_field(field: &syn::Field) -> Result<()> {
|
||||
match field.vis {
|
||||
syn::Visibility::Public(_) => {}
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
field.span(),
|
||||
"#[fce] could be applied only to struct with all public fields",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
if !field.attrs.is_empty() {
|
||||
return Err(Error::new(field.span(), "field attributes isn't allowed"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -14,11 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::wasm_type::WasmType;
|
||||
|
||||
use quote::quote;
|
||||
use serde::Serialize;
|
||||
use serde::Deserialize;
|
||||
use syn::parse::Error;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) enum ParsedType {
|
||||
Empty,
|
||||
I8,
|
||||
@ -160,31 +164,106 @@ impl ParsedType {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PrologGenerator {
|
||||
fn generate_fn_prolog(&self) -> proc_macro2::TokenStream;
|
||||
pub(crate) trait ArgumentsGenerator {
|
||||
fn generate_arguments(&self) -> Vec<WasmType>;
|
||||
}
|
||||
|
||||
pub trait EpilogGenerator {
|
||||
pub(crate) trait PrologGenerator {
|
||||
fn generate_fn_prolog(
|
||||
&self,
|
||||
generated_arg_id: usize,
|
||||
supplied_arg_start_id: usize,
|
||||
) -> proc_macro2::TokenStream;
|
||||
}
|
||||
|
||||
pub(crate) trait EpilogGenerator {
|
||||
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream;
|
||||
}
|
||||
|
||||
impl PrologGenerator for ParsedType {
|
||||
fn generate_fn_prolog(&self) -> proc_macro2::TokenStream {
|
||||
impl ArgumentsGenerator 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],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrologGenerator for ParsedType {
|
||||
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 arg = memory::read_request_from_mem(ptr, len);
|
||||
// TODO: it should be changed to more accurate check
|
||||
let arg = String::from_utf8(arg).unwrap();
|
||||
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 arg = memory::read_request_from_mem(ptr, len);
|
||||
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::Empty => quote! {
|
||||
// it is needed to delete memory occupied by the input argument
|
||||
// this way does it without any additional imports of the export allocator module
|
||||
let arg = memory::read_request_from_mem(ptr, len);
|
||||
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)
|
||||
);
|
||||
},
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,18 +271,55 @@ impl PrologGenerator for ParsedType {
|
||||
impl EpilogGenerator for ParsedType {
|
||||
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream {
|
||||
match self {
|
||||
ParsedType::Empty => quote! {},
|
||||
ParsedType::I8 => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::I16 => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::I32 => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::I64 => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::U8 => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::U16 => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::U32 => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::U64 => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::F32 => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::F64 => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::Boolean => quote! {
|
||||
return result;
|
||||
},
|
||||
ParsedType::Utf8String => quote! {
|
||||
memory::write_response_to_mem(
|
||||
result.as_bytes()
|
||||
)
|
||||
.expect("Putting result string to memory has failed")
|
||||
fluence::set_result_ptr(result.as_ptr() as _);
|
||||
fluence::set_result_size(result.len() as _);
|
||||
std::mem::forget(result);
|
||||
},
|
||||
ParsedType::ByteVector => quote! {
|
||||
memory::write_response_to_mem(&result[..])
|
||||
.expect("Putting result vector to memory has failed")
|
||||
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);
|
||||
},
|
||||
ParsedType::Empty => quote! {},
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ use crate::fce_ast_types::FCEAst;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
const GENERATED_FUNCS_PREFIX: &str = "__fce_generated_func_";
|
||||
|
||||
pub(crate) trait TokenStreamGenerator {
|
||||
fn generate_token_stream(self) -> syn::Result<TokenStream>;
|
||||
}
|
||||
|
@ -15,12 +15,42 @@
|
||||
*/
|
||||
|
||||
use crate::fce_ast_types;
|
||||
use crate::parsed_type::ArgumentsGenerator;
|
||||
use crate::parsed_type::EpilogGenerator;
|
||||
use crate::parsed_type::PrologGenerator;
|
||||
use super::GENERATED_FUNCS_PREFIX;
|
||||
use super::TokenStreamGenerator;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
impl TokenStreamGenerator for fce_ast_types::AstFunctionItem {
|
||||
fn generate_token_stream(self) -> syn::Result<TokenStream> {
|
||||
unimplemented!()
|
||||
let func_name = self.name;
|
||||
let prefix = "__fce_generated_func_";
|
||||
|
||||
let embedded_tokens = quote! {
|
||||
#[cfg_attr(
|
||||
target_arch = "wasm32",
|
||||
export_name = #func_name
|
||||
)]
|
||||
#[doc(hidden)]
|
||||
#[allow(clippy::all)]
|
||||
pub extern "C" fn #prefix_#func_name(#(#raw_args)*) #ret_type {
|
||||
#prolog
|
||||
|
||||
#ret_expression #func_name(#(#args)*);
|
||||
|
||||
#epilog
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[allow(clippy::all)]
|
||||
#[doc(hidden)]
|
||||
#[link_section = #section_name]
|
||||
pub static #generated_global_name: [u8; #size] = { #data };
|
||||
};
|
||||
|
||||
Ok(embedded_tokens)
|
||||
}
|
||||
}
|
||||
|
15
crates/macro/src/wasm_type.rs
Normal file
15
crates/macro/src/wasm_type.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::TokenStreamExt;
|
||||
|
||||
pub(crate) enum WasmType {
|
||||
I32,
|
||||
I64,
|
||||
F32,
|
||||
F64,
|
||||
}
|
||||
|
||||
impl quote::ToTokens for WasmType {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
tokens.append(self.clone());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user