code cleaning

This commit is contained in:
vms 2020-07-08 21:03:44 +03:00
parent 5f26af7990
commit 589daaea45
35 changed files with 733 additions and 1194 deletions

View File

@ -28,6 +28,5 @@ debug = ["fluence-sdk-main/debug"]
members = [
"crates/main",
"crates/macro",
"crates/wit-support",
"crates/wit"
"crates/wit",
]

View File

@ -17,4 +17,4 @@ all-features = true
proc-macro = true
[dependencies]
wit-support = { path = "../wit-support" }
fluence-sdk-wit = { path = "../wit" }

View File

@ -66,7 +66,7 @@
#![warn(rust_2018_idioms)]
#![recursion_limit = "1024"]
use wit_support::fce as fce_impl;
use fluence_sdk_wit::fce as fce_impl;
use proc_macro::TokenStream;
#[proc_macro_attribute]

View File

@ -1,22 +0,0 @@
[package]
name = "wit-support"
version = "0.2.0" # remember to update html_root_url
edition = "2018"
description = "Webassembly interface-types generator"
documentation = "https://docs.rs/fluence/fluence-sdk-macro"
repository = "https://github.com/fluencelabs/rust-sdk/crates/macro"
authors = ["Fluence Labs"]
keywords = ["fluence", "sdk", "webassembly", "wit", "interface-types"]
categories = ["api-bindings", "wasm"]
license = "Apache-2.0"
[package.metadata.docs.rs] # https://docs.rs/about
all-features = true
[dependencies]
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"
uuid = { version = "0.8.1", features = ["v4"] }

View File

@ -1,299 +0,0 @@
/*
* 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 FnGlueCodeGenerator {
fn generate_arguments(&self) -> Vec<WasmType>;
fn generate_return_expression(&self) -> proc_macro2::TokenStream;
fn generate_fn_sig_return_expression(&self) -> proc_macro2::TokenStream;
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 FnGlueCodeGenerator 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::Utf8String => quote! {},
ParsedType::ByteVector => quote! {},
ParsedType::Record(_) => quote! {},
_ => quote! {
let result =
},
}
}
fn generate_fn_sig_return_expression(&self) -> proc_macro2::TokenStream {
let ty = match self {
ParsedType::I8 => Some("i32"),
ParsedType::I16 => Some("i32"),
ParsedType::I32 => Some("i32"),
ParsedType::I64 => Some("i64"),
ParsedType::U8 => Some("i32"),
ParsedType::U16 => Some("i32"),
ParsedType::U32 => Some("i32"),
ParsedType::U64 => Some("i64"),
ParsedType::F32 => Some("f32"),
ParsedType::F64 => Some("f64"),
ParsedType::Boolean => Some("i32"),
_ => None,
};
match ty {
Some(ty) => {
let ty = syn::Ident::new(ty, proc_macro2::Span::call_site());
quote! { -> #ty}
}
None => quote! {},
}
}
fn generate_fn_prolog(
&self,
generated_arg_id: usize,
supplied_arg_start_id: usize,
) -> proc_macro2::TokenStream {
let generated_arg_id = syn::Ident::new(
&format!("converted_arg_{}", generated_arg_id),
proc_macro2::Span::call_site(),
);
match self {
ParsedType::Empty => unimplemented!(),
ParsedType::I8 => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as i8;
}
}
ParsedType::I16 => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as i16;
}
}
ParsedType::I32 => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as i32;
}
}
ParsedType::I64 => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as i64;
}
}
ParsedType::U8 => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as u8;
}
}
ParsedType::U16 => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as u16;
}
}
ParsedType::U32 => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as u32;
}
}
ParsedType::U64 => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as u64;
}
}
ParsedType::F32 => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as f32;
}
}
ParsedType::F64 => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as f64;
}
}
ParsedType::Boolean => {
let supplied_arg_start_id = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = #supplied_arg_start_id as bool;
}
}
ParsedType::Utf8String => {
let ptr = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
let size = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id + 1),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = String::from_raw_parts(#ptr as _, #size as _ , #size as _);
}
}
ParsedType::ByteVector => {
let ptr = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id),
proc_macro2::Span::call_site(),
);
let size = syn::Ident::new(
&format!("arg_{}", supplied_arg_start_id + 1),
proc_macro2::Span::call_site(),
);
quote! {
let #generated_arg_id = Vec::from_raw_parts(#ptr as _, #size as _, #size as _);
}
}
ParsedType::Record(record_name) => {
quote! {
let #generated_arg_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

@ -1,122 +0,0 @@
/*
* 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 super::ParsedType;
use quote::quote;
pub(crate) trait ForeignModeGlueCodeGenerator {
fn generate_wrapper_sign_expression(&self) -> proc_macro2::TokenStream;
fn generate_input_type(&self) -> proc_macro2::TokenStream;
fn generate_raw_args(&self, arg_start_id: usize) -> proc_macro2::TokenStream;
fn generate_wrapper_epilog(&self) -> proc_macro2::TokenStream;
}
impl ForeignModeGlueCodeGenerator for ParsedType {
fn generate_wrapper_sign_expression(&self) -> proc_macro2::TokenStream {
match self {
ParsedType::Empty => quote! {},
ty @ _ => {
let ty = syn::Ident::new(&ty.to_text_type(), proc_macro2::Span::call_site());
quote! { -> #ty }
}
}
}
fn generate_input_type(&self) -> proc_macro2::TokenStream {
use quote::ToTokens;
match self {
ParsedType::Empty => quote! {},
ty @ _ => syn::Ident::new(&ty.to_text_type(), proc_macro2::Span::call_site())
.to_token_stream(),
}
}
fn generate_raw_args(&self, arg_start_id: usize) -> proc_macro2::TokenStream {
let arg = syn::Ident::new(
&format!("arg_{}", arg_start_id),
proc_macro2::Span::call_site(),
);
match self {
ParsedType::Utf8String => quote! { #arg.as_ptr() as _, #arg.len() as _ },
ParsedType::ByteVector => quote! { #arg.as_ptr() as _, #arg.len() as _ },
_ => quote! { arg },
}
}
fn generate_wrapper_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! {
String::from_raw_parts(
fluence::get_result_ptr() as _,
fluence::get_result_size() as _,
fluence::get_result_size() as _
)
},
ParsedType::ByteVector => quote! {
Vec::from_raw_parts(
fluence::get_result_ptr() as _,
fluence::get_result_size() as _,
fluence::get_result_size() as _
)
},
ParsedType::Record(_) => quote! {
fluence::set_result_ptr(result.as_ptr() as _);
fluence::set_result_size(result.len() as _);
std::mem::forget(result);
},
}
}
}

View File

@ -1,111 +0,0 @@
/*
* Copyright 2020 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 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::FnGlueCodeGenerator;
use proc_macro2::TokenStream;
use quote::quote;
use crate::wasm_type::WasmType;
impl TokenStreamGenerator for fce_ast_types::AstFunctionItem {
fn generate_token_stream(self) -> syn::Result<TokenStream> {
// TODO: change serialization protocol
let fce_type = fce_ast_types::FCEAst::Function(self.clone());
let data = serde_json::to_vec(&fce_type).unwrap();
let data_size = data.len();
let data = syn::LitByteStr::new(&data, proc_macro2::Span::call_site());
let signature = self.signature;
let func_name =
syn::parse_str::<syn::Ident>(&(GENERATED_FUNCS_PREFIX.to_string() + &signature.name))?;
let original_func_ident = syn::parse_str::<syn::Ident>(&signature.name)?;
//let func_name = syn::parse_str::<syn::Ident>(&(GENERATED_FUNCS_PREFIX.to_string() + &self.name))?;
let section_name = GENERATED_SECTION_NAME.to_string() + &signature.name.replace("-", "_");
let export_func_name = signature.name;
//let section_prefix = syn::parse_str::<syn::Ident>(GENERATED_SECTION_PREFIX)?;
let global_static_name = syn::parse_str::<syn::Ident>(
&(GENERATED_SECTION_PREFIX.to_string() + &export_func_name),
)
.unwrap();
let return_type = signature.output_type.generate_fn_sig_return_expression();
let return_expression = signature.output_type.generate_return_expression();
let epilog = signature.output_type.generate_fn_epilog();
let mut prolog = TokenStream::new();
let mut args: Vec<syn::Ident> = Vec::with_capacity(signature.input_types.len());
let mut raw_arg_names = Vec::with_capacity(signature.input_types.len());
let mut raw_arg_types: Vec<WasmType> = Vec::with_capacity(signature.input_types.len());
let mut input_type_id = 0;
for input_type in signature.input_types {
let type_prolog = input_type.generate_fn_prolog(input_type_id, input_type_id);
let type_raw_args = input_type.generate_arguments();
args.push(
syn::parse_str::<syn::Ident>(&format!("converted_arg_{}", input_type_id)).unwrap(),
);
raw_arg_names.extend(type_raw_args.iter().enumerate().map(|(id, _)| {
syn::parse_str::<syn::Ident>(&format!("arg_{}", input_type_id + id)).unwrap()
}));
input_type_id += type_raw_args.len();
raw_arg_types.extend(type_raw_args);
prolog.extend(type_prolog);
}
let original_func = self.original;
let glue_code = quote! {
#original_func
#[cfg_attr(
target_arch = "wasm32",
export_name = #export_func_name
)]
#[no_mangle]
#[doc(hidden)]
#[allow(clippy::all)]
pub unsafe fn #func_name(#(#raw_arg_names: #raw_arg_types),*) #return_type {
#prolog
// calling the original function with converted args
#return_expression #original_func_ident(#(#args), *);
// return value conversation from Rust type to a Wasm type
#epilog
}
// #[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = #section_name]
pub static #global_static_name: [u8; #data_size] = { *#data };
};
Ok(glue_code)
}
}

View File

@ -1,27 +0,0 @@
use proc_macro2::TokenStream;
pub(crate) enum WasmType {
I32,
I64,
F32,
F64,
}
impl quote::ToTokens for WasmType {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
WasmType::I32 => {
syn::Ident::new("i32", proc_macro2::Span::call_site()).to_tokens(tokens)
}
WasmType::I64 => syn::parse_str::<syn::Ident>("i64")
.unwrap()
.to_tokens(tokens),
WasmType::F32 => syn::parse_str::<syn::Ident>("f32")
.unwrap()
.to_tokens(tokens),
WasmType::F64 => syn::parse_str::<syn::Ident>("f64")
.unwrap()
.to_tokens(tokens),
}
}
}

View File

@ -1,13 +1,22 @@
[package]
name = "fluence-wit"
version = "0.1.0"
authors = ["Fluence Labs"]
name = "fluence-sdk-wit"
version = "0.2.0" # remember to update html_root_url
edition = "2018"
description = "Webassembly interface-types generator"
documentation = "https://docs.rs/fluence/fluence-sdk-macro"
repository = "https://github.com/fluencelabs/rust-sdk/crates/macro"
authors = ["Fluence Labs"]
keywords = ["fluence", "sdk", "webassembly", "wit", "interface-types"]
categories = ["api-bindings", "wasm"]
license = "Apache-2.0"
[package.metadata.docs.rs] # https://docs.rs/about
all-features = true
[dependencies]
wit_parser = { path = "/Users/mike/dev/work/fluence/wasm/fce/crates/wit_parser" }
walrus = "0.17.0"
wit-support = { path = "../wit-support" }
wasmer-wit = { package = "wasmer-interface-types", git = "http://github.com/fluencelabs/interface-types", branch = "master", features = ["serde"] }
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"
uuid = { version = "0.8.1", features = ["v4"] }

View File

@ -25,7 +25,7 @@ pub struct AstFunctionSignature {
pub input_types: Vec<ParsedType>,
// fce supports only one return value now,
// waiting for adding multi-value support in Wasmer.
pub output_type: ParsedType,
pub output_type: Option<ParsedType>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]

View File

@ -15,13 +15,19 @@
*/
use crate::parse_macro_input::ParseMacroInput;
use crate::token_stream_generator::TokenStreamGenerator;
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::Result;
pub fn fce(tokens: TokenStream) -> Result<TokenStream> {
let item = syn::parse2::<syn::Item>(tokens)?;
// convert proc_macro2 token to internal AST type
let fce_ast_item = item.parse_macro_input()?;
fce_ast_item.generate_token_stream()
// convert internal AST type to sequence of tokens
let mut tokens = TokenStream::new();
fce_ast_item.to_tokens(&mut tokens);
Ok(tokens)
}

View File

@ -1,109 +1,45 @@
mod wit_generator;
mod wasm_ast_extractor;
/*
* Copyright 2020 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 wit_generator::WITGenerator;
#![doc(html_root_url = "https://docs.rs/wit-support/0.2.0")]
#![deny(
dead_code,
nonstandard_style,
unused_imports,
unused_mut,
unused_unsafe,
unreachable_patterns
)]
#![recursion_limit = "1024"]
#![warn(rust_2018_idioms)]
pub use wit_support::FCEAst;
use wasmer_wit::ast::Interfaces;
/// This crate contains functions and types to support work with WebAssembly interface-types
/// in Fluence.
pub fn embed_wit(path: std::path::PathBuf) {
let ast_set = wasm_ast_extractor::wasm_ast_extractor(path.clone()).unwrap();
let interfaces = generate_interfaces(&ast_set);
wit_parser::embed_wit(path.clone(), path.clone(), &interfaces).unwrap();
}
mod fce_ast_types;
mod fce_macro_impl;
mod parsed_type;
mod parse_macro_input;
mod token_stream_generator;
mod utils;
mod wasm_type;
fn generate_interfaces(ast_set: &[FCEAst]) -> Interfaces<'_> {
let mut interfaces = Interfaces::default();
generate_default_api(&mut interfaces);
for ast in ast_set {
ast.generate_wit(&mut interfaces);
}
interfaces
}
fn generate_default_api(interfaces: &mut Interfaces) {
use wasmer_wit::ast::Type;
use wasmer_wit::ast::Export;
use wasmer_wit::types::InterfaceType as IType;
let allocate_inputs = vec![IType::I32];
let allocate_outputs = vec![IType::I32];
let allocate_func_type = Type::Function {
inputs: allocate_inputs,
outputs: allocate_outputs,
};
let deallocate_inputs = vec![IType::I32, IType::I32];
let deallocate_outputs = vec![];
let deallocate_func_type = Type::Function {
inputs: deallocate_inputs,
outputs: deallocate_outputs,
};
let get_result_inputs = vec![];
let get_result_outputs = vec![IType::I32];
let get_result_size_func_type = Type::Function {
inputs: get_result_inputs.clone(),
outputs: get_result_outputs.clone(),
};
let get_result_ptr_func_type = Type::Function {
inputs: get_result_inputs,
outputs: get_result_outputs,
};
let set_result_inputs = vec![IType::I32];
let set_result_outputs = vec![];
let set_result_size_func_type = Type::Function {
inputs: set_result_inputs.clone(),
outputs: set_result_outputs.clone(),
};
let set_result_ptr_func_type = Type::Function {
inputs: set_result_inputs,
outputs: set_result_outputs,
};
interfaces.types.push(allocate_func_type);
interfaces.types.push(deallocate_func_type);
interfaces.types.push(get_result_size_func_type);
interfaces.types.push(get_result_ptr_func_type);
interfaces.types.push(set_result_size_func_type);
interfaces.types.push(set_result_ptr_func_type);
let allocate_export = Export {
name: "allocate",
function_type: 0,
};
interfaces.exports.push(allocate_export);
let deallocate_export = Export {
name: "deallocate",
function_type: 1,
};
interfaces.exports.push(deallocate_export);
let get_result_size_export = Export {
name: "get_result_size",
function_type: 2,
};
interfaces.exports.push(get_result_size_export);
let get_result_ptr_export = Export {
name: "get_result_ptr",
function_type: 3,
};
interfaces.exports.push(get_result_ptr_export);
let set_result_size_export = Export {
name: "set_result_size",
function_type: 4,
};
interfaces.exports.push(set_result_size_export);
let set_result_ptr_export = Export {
name: "set_result_ptr",
function_type: 5,
};
interfaces.exports.push(set_result_ptr_export);
}
pub use fce_ast_types::*;
pub use fce_macro_impl::fce;
pub use parsed_type::ParsedType;
pub use token_stream_generator::GENERATED_FUNC_PREFIX;
pub use token_stream_generator::GENERATED_SECTION_PREFIX;
pub use token_stream_generator::GENERATED_GLOBAL_PREFIX;

View File

@ -14,11 +14,18 @@
* limitations under the License.
*/
mod fn_glue_code_generator;
mod foreign_mod_glue_code_generator;
mod fn_arg;
mod fn_epilog;
mod fn_prolog;
mod foreign_mod_arg;
mod foreign_mod_epilog;
mod foreign_mod_prolog;
pub(crate) use fn_glue_code_generator::FnGlueCodeGenerator;
pub(crate) use foreign_mod_glue_code_generator::ForeignModeGlueCodeGenerator;
pub(crate) use fn_arg::*;
pub(crate) use fn_epilog::*;
pub(crate) use fn_prolog::*;
pub(crate) use foreign_mod_prolog::*;
pub(crate) use foreign_mod_epilog::*;
use serde::Serialize;
use serde::Deserialize;
@ -27,7 +34,6 @@ use syn::spanned::Spanned;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ParsedType {
Empty,
I8,
I16,
I32,
@ -159,16 +165,15 @@ impl ParsedType {
}
}
pub fn from_return_type(ret_type: &syn::ReturnType) -> syn::Result<Self> {
pub fn from_return_type(ret_type: &syn::ReturnType) -> syn::Result<Option<Self>> {
match ret_type {
syn::ReturnType::Type(_, t) => ParsedType::from_type(t.as_ref()),
syn::ReturnType::Default => Ok(ParsedType::Empty),
syn::ReturnType::Type(_, t) => Ok(Some(ParsedType::from_type(t.as_ref())?)),
syn::ReturnType::Default => Ok(None),
}
}
pub fn to_text_type(&self) -> String {
match self {
ParsedType::Empty => "",
ParsedType::I8 => "i8",
ParsedType::I16 => "i16",
ParsedType::I32 => "i32",
@ -186,4 +191,21 @@ impl ParsedType {
}
.into()
}
pub fn is_integral_type(&self) -> bool {
match self {
ParsedType::Boolean
| ParsedType::I8
| ParsedType::I16
| ParsedType::I32
| ParsedType::I64
| ParsedType::U8
| ParsedType::U16
| ParsedType::U32
| ParsedType::U64
| ParsedType::F32
| ParsedType::F64 => false,
ParsedType::Utf8String | ParsedType::ByteVector | ParsedType::Record(_) => true,
}
}
}

View File

@ -0,0 +1,28 @@
use super::ParsedType;
use crate::wasm_type::WasmType;
/// 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>;
}
impl FnArgGlueCodeGenerator for ParsedType {
fn generate_arguments(&self) -> Vec<WasmType> {
// TODO: investigate possible issues in conversion between signed and unsigned types
match self {
ParsedType::Boolean
| ParsedType::I8
| ParsedType::I16
| ParsedType::I32
| ParsedType::U8
| ParsedType::U16
| ParsedType::U32 => vec![WasmType::I32],
ParsedType::I64 | ParsedType::U64 => vec![WasmType::I64],
ParsedType::F32 => vec![WasmType::F32],
ParsedType::F64 => vec![WasmType::F64],
ParsedType::Utf8String | ParsedType::ByteVector | ParsedType::Record(_) => {
vec![WasmType::I32, WasmType::I32]
}
}
}
}

View File

@ -0,0 +1,111 @@
/*
* Copyright 2020 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::new_ident;
use super::ParsedType;
use quote::quote;
/// Describes various parts of a function epilog.
pub(crate) struct FnEpilogDescriptor {
pub(crate) fn_return_type: proc_macro2::TokenStream,
pub(crate) return_expression: proc_macro2::TokenStream,
pub(crate) epilog: proc_macro2::TokenStream,
}
/// This trait could be used to generate various parts needed to construct epilog of an export
/// function. They are marked with # in the following example:
/// ```
/// quote! {
/// pub unsafe fn foo(...) #fn_return_type {
/// ...
/// #return_expression original_foo(...);
/// #epilog
/// }
/// }
/// ```
pub(crate) trait FnEpilogGlueCodeGenerator {
fn generate_fn_epilog(&self) -> FnEpilogDescriptor;
}
impl FnEpilogGlueCodeGenerator for Option<ParsedType> {
fn generate_fn_epilog(&self) -> FnEpilogDescriptor {
FnEpilogDescriptor {
fn_return_type: generate_fn_return_type(self),
return_expression: generate_return_expression(self),
epilog: generate_epilog(self),
}
}
}
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::F32) => Some("f32"),
Some(ParsedType::F64) => Some("f64"),
None
| Some(ParsedType::Utf8String)
| Some(ParsedType::ByteVector)
| Some(ParsedType::Record(_)) => None,
};
match ty {
Some(ty) => {
let ty = new_ident!(ty);
quote! { -> #ty}
}
None => quote! {},
}
}
fn generate_return_expression(ty: &Option<ParsedType>) -> proc_macro2::TokenStream {
match ty {
None
| Some(ParsedType::Utf8String)
| Some(ParsedType::ByteVector)
| Some(ParsedType::Record(_)) => quote! {},
_ => quote! {
let result =
},
}
}
fn generate_epilog(ty: &Option<ParsedType>) -> proc_macro2::TokenStream {
match ty {
None => quote!(),
Some(ty) if !ty.is_integral_type() => quote! {
return result as _;
},
Some(ty) if ty.is_integral_type() => quote! {
fluence::set_result_ptr(result.as_ptr() as _);
fluence::set_result_size(result.len() as _);
std::mem::forget(result);
},
_ => {
panic!("perhaps new type's been added to ParsedType, and this match became incomplete")
}
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright 2020 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 super::ParsedType;
use super::FnArgGlueCodeGenerator;
use crate::new_ident;
use crate::wasm_type::WasmType;
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) prolog: proc_macro2::TokenStream,
pub(crate) args: Vec<syn::Ident>,
}
/// This trait could be used to generate various parts needed to construct prolog of an export
/// function. They are marked with # in the following example:
/// ```
/// quote! {
/// fn foo(#(#raw_arg_names: #raw_arg_types),*) {
/// #prolog
/// let result = original_foo(#(#args), *);
/// ...
/// }
/// }
/// ```
pub(crate) trait FnPrologGlueCodeGenerator {
fn generate_prolog(&self) -> FnPrologDescriptor;
}
impl FnPrologGlueCodeGenerator for Vec<ParsedType> {
fn generate_prolog(&self) -> FnPrologDescriptor {
let mut prolog = proc_macro2::TokenStream::new();
let mut args: Vec<syn::Ident> = Vec::with_capacity(self.len());
let mut raw_arg_names = Vec::with_capacity(self.len());
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();
args.push(new_ident!(format!("converted_arg_{}", input_type_id)));
raw_arg_names.extend(
curr_raw_arg_types
.iter()
.enumerate()
.map(|(id, _)| new_ident!(format!("arg_{}", input_type_id + id))),
);
input_type_id += curr_raw_arg_types.len();
raw_arg_types.extend(curr_raw_arg_types);
prolog.extend(type_prolog);
}
FnPrologDescriptor {
raw_arg_names,
raw_arg_types,
prolog,
args,
}
}
}
fn generate_type_prolog(
ty: &ParsedType,
generated_arg_id: usize,
supplied_arg_start_id: usize,
) -> proc_macro2::TokenStream {
let generated_arg_id = new_ident!(format!("converted_arg_{}", generated_arg_id));
match ty {
ty if !ty.is_integral_type() => {
let supplied_arg_start_id = new_ident!(format!("arg_{}", supplied_arg_start_id));
quote! {
let #generated_arg_id = #supplied_arg_start_id as _;
}
}
ty => {
// all complex types are represented with pointer and size
let ptr = new_ident!(format!("arg_{}", supplied_arg_start_id));
let size = new_ident!(format!("arg_{}", supplied_arg_start_id + 1));
match ty {
ParsedType::Utf8String => quote! {
let #generated_arg_id = String::from_raw_parts(#ptr as _, #size as _ , #size as _);
},
ParsedType::ByteVector => quote! {
let #generated_arg_id = Vec::from_raw_parts(#ptr as _, #size as _, #size as _);
},
ParsedType::Record(record_name) => quote! {
let #generated_arg_id = __fce_generated_converter_#record_name(#ptr, #size);
},
_ => panic!(
"perhaps new type's been added to ParsedType, and this match became incomplete"
),
}
}
}
}

View File

@ -0,0 +1,37 @@
/*
* 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 super::ParsedType;
use quote::quote;
/// This trait could be used to generate raw args needed to construct a wrapper of an import
/// function.
pub(crate) trait ForeignModArgGlueCodeGenerator {
fn generate_raw_args(&self, arg_start_id: usize) -> proc_macro2::TokenStream;
}
impl ForeignModArgGlueCodeGenerator for ParsedType {
fn generate_raw_args(&self, arg_start_id: usize) -> proc_macro2::TokenStream {
let arg = crate::new_ident!(format!("arg_{}", arg_start_id));
match self {
ParsedType::Utf8String | ParsedType::ByteVector => {
quote! { #arg.as_ptr() as _, #arg.len() as _ }
}
_ => quote! { arg },
}
}
}

View File

@ -0,0 +1,67 @@
/*
* 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 super::ParsedType;
use crate::new_ident;
use quote::quote;
/// This trait could be used to generate various parts needed to construct epilog of an wrapper of
/// import function.
pub(crate) trait ForeignModEpilogGlueCodeGenerator {
fn generate_wrapper_return_type(&self) -> proc_macro2::TokenStream;
fn generate_wrapper_epilog(&self) -> proc_macro2::TokenStream;
}
impl ForeignModEpilogGlueCodeGenerator for Option<ParsedType> {
fn generate_wrapper_return_type(&self) -> proc_macro2::TokenStream {
match self {
Some(ty) => {
let ty = new_ident!(ty.to_text_type());
quote! { -> #ty }
}
None => quote!(),
}
}
fn generate_wrapper_epilog(&self) -> proc_macro2::TokenStream {
match self {
None => quote!(),
Some(ty) if !ty.is_integral_type() => quote! {
return result as _;
},
Some(ParsedType::Utf8String) => quote! {
String::from_raw_parts(
fluence::get_result_ptr() as _,
fluence::get_result_size() as _,
fluence::get_result_size() as _
)
},
Some(ParsedType::ByteVector) => quote! {
Vec::from_raw_parts(
fluence::get_result_ptr() as _,
fluence::get_result_size() as _,
fluence::get_result_size() as _
)
},
Some(ParsedType::Record(_)) => unimplemented!(),
_ => panic!(
"perhaps new type's been added to ParsedType, and this match became incomplete"
),
}
}
}

View File

@ -0,0 +1,104 @@
/*
* 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 super::ParsedType;
use crate::wasm_type::WasmType;
use crate::new_ident;
pub(crate) struct WrapperDescriptor {
pub(crate) arg_names: Vec<syn::Ident>,
pub(crate) arg_types: Vec<proc_macro2::TokenStream>,
pub(crate) raw_args: Vec<proc_macro2::TokenStream>,
}
pub(crate) struct ExternDescriptor {
pub(crate) raw_arg_names: Vec<syn::Ident>,
pub(crate) raw_arg_types: Vec<WasmType>,
}
/// This trait could be used to generate various parts needed to construct prolog of an wrapper
/// function or extern block. They are marked with # in the following examples:
/// ```
/// quote! {
/// fn foo(#(#arg_names: #arg_types), *) {
/// let result = original_foo(#(#raw_args), *);
/// ...
/// }
/// }
/// ```
///
/// ```
/// quote! {
/// extern "C" {
/// #[link_name = "foo_link_name"]
/// pub fn foo(#(#raw_arg_names: #raw_arg_types),*);
/// }
/// }
/// ```
pub(crate) trait ForeignModPrologGlueCodeGenerator {
fn generate_wrapper_prolog(&self) -> WrapperDescriptor;
fn generate_extern_prolog(&self) -> ExternDescriptor;
}
impl ForeignModPrologGlueCodeGenerator for Vec<ParsedType> {
fn generate_wrapper_prolog(&self) -> WrapperDescriptor {
use crate::parsed_type::foreign_mod_arg::ForeignModArgGlueCodeGenerator;
use quote::ToTokens;
let arg_types: Vec<proc_macro2::TokenStream> = self
.iter()
.map(|input_type| new_ident!(input_type.to_text_type()).to_token_stream())
.collect();
let arg_names: Vec<syn::Ident> = arg_types
.iter()
.enumerate()
.map(|(id, _)| new_ident!(format!("arg_{}", id)))
.collect();
let raw_args: Vec<proc_macro2::TokenStream> = self
.iter()
.enumerate()
.map(|(id, input_type)| input_type.generate_raw_args(id))
.collect();
WrapperDescriptor {
arg_names,
arg_types,
raw_args,
}
}
fn generate_extern_prolog(&self) -> ExternDescriptor {
use crate::parsed_type::FnArgGlueCodeGenerator;
let raw_arg_types: Vec<WasmType> = self
.iter()
.map(|input_type| input_type.generate_arguments())
.flatten()
.collect();
let raw_arg_names: Vec<syn::Ident> = raw_arg_types
.iter()
.enumerate()
.map(|(id, _)| new_ident!(format!("arg_{}", id)))
.collect();
ExternDescriptor {
raw_arg_names,
raw_arg_types,
}
}
}

View File

@ -22,20 +22,16 @@ use crate::fce_ast_types::FCEAst;
use proc_macro2::TokenStream;
const GENERATED_FUNCS_PREFIX: &str = "__fce_generated_func_";
pub const GENERATED_SECTION_NAME: &str = "__fce_generated_section__";
const GENERATED_SECTION_PREFIX: &str = "__fce_generated_static_global_";
pub const GENERATED_FUNC_PREFIX: &str = "__fce_generated_func_";
pub const GENERATED_SECTION_PREFIX: &str = "__fce_generated_section__";
pub const GENERATED_GLOBAL_PREFIX: &str = "__fce_generated_static_global_";
pub(crate) trait TokenStreamGenerator {
fn generate_token_stream(self) -> syn::Result<TokenStream>;
}
impl TokenStreamGenerator for FCEAst {
fn generate_token_stream(self) -> syn::Result<TokenStream> {
impl quote::ToTokens for FCEAst {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
FCEAst::Function(ast_function) => ast_function.generate_token_stream(),
FCEAst::ExternMod(ast_extern) => ast_extern.generate_token_stream(),
FCEAst::Record(ast_record) => ast_record.generate_token_stream(),
FCEAst::Function(ast_function) => ast_function.to_tokens(tokens),
FCEAst::ExternMod(ast_extern) => ast_extern.to_tokens(tokens),
FCEAst::Record(ast_record) => ast_record.to_tokens(tokens),
}
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright 2020 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 super::*;
use crate::fce_ast_types;
use crate::parsed_type::FnEpilogGlueCodeGenerator;
use crate::parsed_type::FnEpilogDescriptor;
use crate::parsed_type::FnPrologGlueCodeGenerator;
use crate::parsed_type::FnPrologDescriptor;
use crate::new_ident;
use proc_macro2::TokenStream;
use quote::quote;
impl quote::ToTokens for fce_ast_types::AstFunctionItem {
fn to_tokens(&self, tokens: &mut TokenStream) {
// TODO: change serialization protocol
let fce_type = fce_ast_types::FCEAst::Function(self.clone());
// there is no condition for serialization to fail
let data = serde_json::to_vec(&fce_type).unwrap();
let data_size = data.len();
let data = syn::LitByteStr::new(&data, proc_macro2::Span::call_site());
let signature = &self.signature;
let func_name = new_ident!(GENERATED_FUNC_PREFIX.to_string() + &signature.name);
let original_func_ident = new_ident!(signature.name);
let section_name = GENERATED_SECTION_PREFIX.to_string() + &signature.name.replace("-", "_");
let export_func_name = &signature.name;
let global_static_name =
new_ident!(GENERATED_GLOBAL_PREFIX.to_string() + &export_func_name);
let FnPrologDescriptor {
raw_arg_names,
raw_arg_types,
prolog,
args,
} = &signature.input_types.generate_prolog();
let FnEpilogDescriptor {
fn_return_type,
return_expression,
epilog,
} = signature.output_type.generate_fn_epilog();
// here this Option must be Some
let original_func = &self.original;
let glue_code = quote! {
#original_func
#[cfg_attr(
target_arch = "wasm32",
export_name = #export_func_name
)]
#[no_mangle]
#[doc(hidden)]
#[allow(clippy::all)]
pub unsafe fn #func_name(#(#raw_arg_names: #raw_arg_types),*) #fn_return_type {
#prolog
// calling the original function with converted args
#return_expression #original_func_ident(#(#args), *);
// return value conversation from Rust type to a Wasm type
#epilog
}
// #[cfg(target_arch = "wasm32")]
#[doc(hidden)]
#[allow(clippy::all)]
#[link_section = #section_name]
pub static #global_static_name: [u8; #data_size] = { *#data };
};
tokens.extend(glue_code);
}
}

View File

@ -14,31 +14,27 @@
* limitations under the License.
*/
use super::TokenStreamGenerator;
use super::GENERATED_FUNCS_PREFIX;
use super::GENERATED_SECTION_NAME;
use super::GENERATED_FUNC_PREFIX;
use super::GENERATED_SECTION_PREFIX;
use super::GENERATED_GLOBAL_PREFIX;
use crate::fce_ast_types;
use crate::new_ident;
use proc_macro2::TokenStream;
use quote::quote;
use crate::parsed_type::FnGlueCodeGenerator;
use crate::parsed_type::ForeignModeGlueCodeGenerator;
use crate::parsed_type::*;
impl TokenStreamGenerator for fce_ast_types::AstExternModItem {
fn generate_token_stream(self) -> syn::Result<TokenStream> {
impl quote::ToTokens for fce_ast_types::AstExternModItem {
fn to_tokens(&self, tokens: &mut TokenStream) {
// TODO: change serialization protocol
let fce_type = fce_ast_types::FCEAst::ExternMod(self.clone());
let data = serde_json::to_vec(&fce_type).unwrap();
let data_size = data.len();
let data = syn::LitByteStr::new(&data, proc_macro2::Span::call_site());
let global_static_name = syn::Ident::new(
&(GENERATED_SECTION_PREFIX.to_string() + &self.namespace.replace(".", "_")),
proc_macro2::Span::call_site(),
);
let section_name = GENERATED_SECTION_NAME.to_string() + &self.namespace.replace(".", "_");
let global_static_name =
new_ident!(GENERATED_GLOBAL_PREFIX.to_string() + &self.namespace.replace(".", "_"));
let section_name = GENERATED_SECTION_PREFIX.to_string() + &self.namespace.replace(".", "_");
let wasm_import_module_name = &self.namespace;
let generated_imports = generate_extern_section_items(&self);
@ -60,41 +56,28 @@ impl TokenStreamGenerator for fce_ast_types::AstExternModItem {
pub static #global_static_name: [u8; #data_size] = { *#data };
};
Ok(glue_code)
tokens.extend(glue_code);
}
}
fn generate_extern_section_items(extern_item: &fce_ast_types::AstExternModItem) -> TokenStream {
use crate::wasm_type::WasmType;
let mut token_stream = TokenStream::new();
for import in &extern_item.imports {
let ret_type = import
.signature
.output_type
.generate_fn_sig_return_expression();
let link_name = import
.link_name
.as_ref()
.unwrap_or_else(|| &import.signature.name);
let import_name = generate_import_name(&import.signature.name);
let raw_arg_types: Vec<WasmType> = import
.signature
.input_types
.iter()
.map(|input_type| input_type.generate_arguments())
.flatten()
.collect();
let raw_arg_names: Vec<syn::Ident> = raw_arg_types
.iter()
.enumerate()
.map(|(id, _)| syn::Ident::new(&format!("arg_{}", id), proc_macro2::Span::call_site()))
.collect();
let signature = &import.signature;
let FnEpilogDescriptor { fn_return_type, .. } = signature.output_type.generate_fn_epilog();
let link_name = import.link_name.as_ref().unwrap_or_else(|| &signature.name);
let import_name = generate_import_name(&signature.name);
let ExternDescriptor {
raw_arg_names,
raw_arg_types,
} = signature.input_types.generate_extern_prolog();
let func = quote! {
#[link_name = #link_name]
pub fn #import_name(#(#raw_arg_names: #raw_arg_types),*) #ret_type;
pub fn #import_name(#(#raw_arg_names: #raw_arg_types),*) #fn_return_type;
};
token_stream.extend(func);
@ -104,44 +87,32 @@ fn generate_extern_section_items(extern_item: &fce_ast_types::AstExternModItem)
}
fn generate_import_name(import_name: &str) -> syn::Ident {
syn::Ident::new(
&format!("{}_{}", GENERATED_FUNCS_PREFIX, import_name),
proc_macro2::Span::call_site(),
)
crate::new_ident!(format!("{}_{}", GENERATED_FUNC_PREFIX, import_name))
}
fn generate_wrapper_functions(extern_item: &fce_ast_types::AstExternModItem) -> TokenStream {
let mut token_stream = TokenStream::new();
for import in &extern_item.imports {
let visibility = syn::Ident::new("pub", proc_macro2::Span::call_site());
let func_name = syn::Ident::new(&import.signature.name, proc_macro2::Span::call_site());
let arg_types: Vec<proc_macro2::TokenStream> = import
.signature
.input_types
.iter()
.map(|input_type| input_type.generate_input_type())
.collect();
let arg_names: Vec<syn::Ident> = arg_types
.iter()
.enumerate()
.map(|(id, _)| syn::Ident::new(&format!("arg_{}", id), proc_macro2::Span::call_site()))
.collect();
let return_type = import
.signature
.output_type
.generate_wrapper_sign_expression();
let import_func_name = generate_import_name(&import.signature.name);
let raw_args: Vec<proc_macro2::TokenStream> = import
.signature
.input_types
.iter()
.enumerate()
.map(|(id, input_type)| input_type.generate_raw_args(id))
.collect();
let signature = &import.signature;
let return_expression = import.signature.output_type.generate_return_expression();
let epilog = import.signature.output_type.generate_wrapper_epilog();
let visibility = new_ident!("pub");
let func_name = new_ident!(&signature.name);
let return_type = signature.output_type.generate_wrapper_return_type();
let import_func_name = generate_import_name(&signature.name);
let WrapperDescriptor {
arg_names,
arg_types,
raw_args,
} = signature.input_types.generate_wrapper_prolog();
let FnEpilogDescriptor {
return_expression, ..
} = signature.output_type.generate_fn_epilog();
let epilog = signature.output_type.generate_wrapper_epilog();
let wrapper_func = quote! {
// #[cfg(target_arch = "wasm32")]

View File

@ -15,12 +15,11 @@
*/
use crate::fce_ast_types;
use super::TokenStreamGenerator;
use proc_macro2::TokenStream;
impl TokenStreamGenerator for fce_ast_types::AstRecordItem {
fn generate_token_stream(self) -> syn::Result<TokenStream> {
impl quote::ToTokens for fce_ast_types::AstRecordItem {
fn to_tokens(&self, _tokens: &mut TokenStream) {
unimplemented!()
}
}

View File

@ -14,26 +14,10 @@
* limitations under the License.
*/
#![doc(html_root_url = "https://docs.rs/wit-support/0.2.0")]
#![deny(
dead_code,
nonstandard_style,
unused_imports,
unused_mut,
unused_unsafe,
unreachable_patterns
)]
#![warn(rust_2018_idioms)]
#![recursion_limit = "1024"]
mod fce_ast_types;
mod fce_macro_impl;
mod parsed_type;
mod parse_macro_input;
mod token_stream_generator;
mod wasm_type;
pub use fce_ast_types::*;
pub use fce_macro_impl::fce;
pub use parsed_type::ParsedType;
pub use token_stream_generator::GENERATED_SECTION_NAME;
#[macro_export]
/// Crates new syn::Ident with the given string and new call span
macro_rules! new_ident {
($string: expr) => {
syn::Ident::new(&$string, proc_macro2::Span::call_site());
};
}

View File

@ -1,28 +0,0 @@
use walrus::ModuleConfig;
#[derive(Default, Clone)]
struct WasmAst {
exports: Vec<wit_support::AstFunctionItem>,
imports: Vec<wit_support::AstExternModItem>,
records: Vec<wit_support::AstRecordItem>,
}
pub(crate) fn wasm_ast_extractor(
wasm_path: std::path::PathBuf,
) -> Result<Vec<wit_support::FCEAst>, std::io::Error> {
let module = ModuleConfig::new().parse_file(wasm_path).unwrap();
let mut decoded_ast = Vec::new();
for custom_module in module.customs.iter().filter(|(_, section)| {
section
.name()
.starts_with(wit_support::GENERATED_SECTION_NAME)
}) {
let default_ids = walrus::IdsToIndices::default();
let raw_data = custom_module.1.data(&default_ids);
let decoded_json: wit_support::FCEAst = serde_json::from_slice(&raw_data).unwrap();
decoded_ast.push(decoded_json);
}
Ok(decoded_ast)
}

View File

@ -0,0 +1,21 @@
use proc_macro2::TokenStream;
/// Raw Wasm types according to the spec except i128.
pub(crate) enum WasmType {
I32,
I64,
F32,
F64,
}
impl quote::ToTokens for WasmType {
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),
}
}
}

View File

@ -1,36 +0,0 @@
mod fn_wit_generator;
mod foreign_mod_wit_generator;
mod record_wit_generator;
mod utils;
use super::FCEAst;
use wasmer_wit::types::InterfaceType as IType;
use wasmer_wit::ast::Interfaces;
use wasmer_wit::interpreter::Instruction;
pub trait WITGenerator {
fn generate_wit<'a>(&'a self, interfaces: &mut Interfaces<'a>);
}
trait FnInstructionGenerator {
fn generate_instructions_for_input_type(&self, arg_id: u32) -> Vec<Instruction>;
fn generate_instructions_for_output_type(&self) -> Vec<Instruction>;
}
trait ForeignModInstructionGenerator {
fn generate_instructions_for_input_type(&self, arg_id: u32) -> Vec<Instruction>;
fn generate_instructions_for_output_type(&self) -> Vec<Instruction>;
}
impl WITGenerator for FCEAst {
fn generate_wit<'a>(&'a self, interfaces: &mut Interfaces<'a>) {
match self {
FCEAst::Function(func) => func.generate_wit(interfaces),
FCEAst::ExternMod(extern_mod) => extern_mod.generate_wit(interfaces),
FCEAst::Record(record) => record.generate_wit(interfaces),
}
}
}

View File

@ -1,136 +0,0 @@
use super::WITGenerator;
use super::Interfaces;
use super::utils::ptype_to_itype;
use super::FnInstructionGenerator;
use wit_support::AstFunctionItem;
use wit_support::ParsedType;
use wasmer_wit::interpreter::Instruction;
impl WITGenerator for AstFunctionItem {
fn generate_wit<'a>(&'a self, interfaces: &mut Interfaces<'a>) {
use wasmer_wit::ast::Type;
use wasmer_wit::ast::Adapter;
let inputs = self
.signature
.input_types
.iter()
.map(ptype_to_itype)
.collect::<Vec<_>>();
let outputs = vec![ptype_to_itype(&self.signature.output_type)];
interfaces.types.push(Type::Function {
inputs: inputs.clone(),
outputs: outputs.clone(),
});
// TODO: replace with Wasm types
interfaces.types.push(Type::Function { inputs, outputs });
let adapter_idx = (interfaces.types.len() - 2) as u32;
let export_idx = (interfaces.types.len() - 1) as u32;
interfaces.exports.push(wasmer_wit::ast::Export {
name: &self.signature.name,
function_type: export_idx,
});
let mut instructions: Vec<Instruction> = self
.signature
.input_types
.iter()
.rev()
.enumerate()
.map(|(id, input_type)| input_type.generate_instructions_for_input_type(id as _))
.flatten()
.collect();
instructions.push(Instruction::CallCore {
function_index: export_idx,
});
instructions.extend(
self.signature
.output_type
.generate_instructions_for_output_type(),
);
let adapter = Adapter {
function_type: adapter_idx,
instructions,
};
interfaces.adapters.push(adapter);
let implementation = wasmer_wit::ast::Implementation {
core_function_type: export_idx,
adapter_function_type: adapter_idx,
};
interfaces.implementations.push(implementation);
}
}
impl FnInstructionGenerator for ParsedType {
fn generate_instructions_for_input_type(&self, index: u32) -> Vec<Instruction> {
match self {
ParsedType::I8 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS8],
ParsedType::I16 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS16],
ParsedType::I32 => vec![Instruction::ArgumentGet { index }],
ParsedType::I64 => vec![Instruction::ArgumentGet { index }],
ParsedType::U8 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU8],
ParsedType::U16 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU16],
ParsedType::U32 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU32],
ParsedType::U64 => vec![Instruction::ArgumentGet { index }, Instruction::I64FromU64],
ParsedType::F32 => vec![Instruction::ArgumentGet { index }],
ParsedType::F64 => vec![Instruction::ArgumentGet { index }],
ParsedType::Utf8String => vec![
Instruction::ArgumentGet { index },
Instruction::StringSize,
Instruction::CallCore { function_index: 0 },
Instruction::ArgumentGet { index },
Instruction::StringLowerMemory,
],
ParsedType::ByteVector => vec![
Instruction::ArgumentGet { index },
Instruction::StringSize,
Instruction::CallCore { function_index: 0 },
Instruction::ArgumentGet { index },
Instruction::StringLowerMemory,
],
_ => unimplemented!(),
}
}
fn generate_instructions_for_output_type(&self) -> Vec<Instruction> {
match self {
ParsedType::I8 => vec![Instruction::S8FromI32],
ParsedType::I16 => vec![Instruction::S16FromI32],
ParsedType::I32 => vec![],
ParsedType::I64 => vec![],
ParsedType::U8 => vec![Instruction::U8FromI32],
ParsedType::U16 => vec![Instruction::U16FromI32],
ParsedType::U32 => vec![Instruction::U32FromI32],
ParsedType::U64 => vec![Instruction::U64FromI64],
ParsedType::F32 => vec![],
ParsedType::F64 => vec![],
ParsedType::Utf8String => vec![
Instruction::CallCore { function_index: 3 },
Instruction::CallCore { function_index: 2 },
Instruction::StringLiftMemory,
Instruction::CallCore { function_index: 3 },
Instruction::CallCore { function_index: 2 },
Instruction::CallCore { function_index: 1 },
],
ParsedType::ByteVector => vec![
Instruction::CallCore { function_index: 3 },
Instruction::CallCore { function_index: 2 },
Instruction::StringLiftMemory,
Instruction::CallCore { function_index: 3 },
Instruction::CallCore { function_index: 2 },
Instruction::CallCore { function_index: 1 },
],
_ => unimplemented!(),
}
}
}

View File

@ -1,146 +0,0 @@
use super::WITGenerator;
use super::Interfaces;
use super::utils::ptype_to_itype;
use super::ForeignModInstructionGenerator;
use wit_support::AstExternModItem;
use wit_support::AstExternFnItem;
use wit_support::ParsedType;
use wasmer_wit::interpreter::Instruction;
impl WITGenerator for AstExternModItem {
fn generate_wit<'a>(&'a self, interfaces: &mut Interfaces<'a>) {
for import in &self.imports {
generate_wit_for_import(import, &self.namespace, interfaces);
}
}
}
fn generate_wit_for_import<'a>(
import: &'a AstExternFnItem,
namespace: &'a String,
interfaces: &mut Interfaces<'a>,
) {
use wasmer_wit::ast::Type;
use wasmer_wit::ast::Adapter;
let inputs = import
.signature
.input_types
.iter()
.map(ptype_to_itype)
.collect::<Vec<_>>();
let outputs = vec![ptype_to_itype(&import.signature.output_type)];
interfaces.types.push(Type::Function {
inputs: inputs.clone(),
outputs: outputs.clone(),
});
// TODO: replace with Wasm types
interfaces.types.push(Type::Function { inputs, outputs });
let adapter_idx = (interfaces.types.len() - 2) as u32;
let import_idx = (interfaces.types.len() - 1) as u32;
interfaces.imports.push(wasmer_wit::ast::Import {
namespace: &namespace,
name: &import.signature.name,
function_type: import_idx,
});
let mut instructions: Vec<Instruction> = import
.signature
.input_types
.iter()
.rev()
.enumerate()
.map(|(id, input_type)| input_type.generate_instructions_for_input_type(id as _))
.flatten()
.collect();
instructions.push(Instruction::CallCore {
function_index: import_idx,
});
instructions.extend(
import
.signature
.output_type
.generate_instructions_for_output_type(),
);
let adapter = Adapter {
function_type: adapter_idx,
instructions,
};
interfaces.adapters.push(adapter);
let implementation = wasmer_wit::ast::Implementation {
core_function_type: import_idx,
adapter_function_type: adapter_idx,
};
interfaces.implementations.push(implementation);
}
impl ForeignModInstructionGenerator for ParsedType {
fn generate_instructions_for_input_type(&self, index: u32) -> Vec<Instruction> {
match self {
ParsedType::I8 => vec![Instruction::ArgumentGet { index }, Instruction::S8FromI32],
ParsedType::I16 => vec![Instruction::ArgumentGet { index }, Instruction::S16FromI32],
ParsedType::I32 => vec![Instruction::ArgumentGet { index }],
ParsedType::I64 => vec![Instruction::ArgumentGet { index }],
ParsedType::U8 => vec![Instruction::ArgumentGet { index }, Instruction::U8FromI32],
ParsedType::U16 => vec![Instruction::ArgumentGet { index }, Instruction::U16FromI32],
ParsedType::U32 => vec![Instruction::ArgumentGet { index }, Instruction::U32FromI32],
ParsedType::U64 => vec![Instruction::ArgumentGet { index }, Instruction::U64FromI64],
ParsedType::F32 => vec![Instruction::ArgumentGet { index }],
ParsedType::F64 => vec![Instruction::ArgumentGet { index }],
ParsedType::Utf8String => vec![
Instruction::ArgumentGet { index },
Instruction::ArgumentGet { index: index + 1 },
Instruction::StringLiftMemory,
],
ParsedType::ByteVector => vec![
Instruction::ArgumentGet { index },
Instruction::ArgumentGet { index: index + 1 },
Instruction::StringLiftMemory,
],
_ => unimplemented!(),
}
}
fn generate_instructions_for_output_type(&self) -> Vec<Instruction> {
match self {
ParsedType::I8 => vec![Instruction::I32FromS8],
ParsedType::I16 => vec![Instruction::I32FromS16],
ParsedType::I32 => vec![],
ParsedType::I64 => vec![],
ParsedType::U8 => vec![Instruction::I32FromU8],
ParsedType::U16 => vec![Instruction::I32FromU16],
ParsedType::U32 => vec![Instruction::I32FromU32],
ParsedType::U64 => vec![Instruction::I64FromU64],
ParsedType::F32 => vec![],
ParsedType::F64 => vec![],
ParsedType::Utf8String => vec![
Instruction::Dup,
Instruction::StringSize,
Instruction::CallCore { function_index: 0 },
Instruction::Swap2,
Instruction::StringLowerMemory,
Instruction::CallCore { function_index: 4 },
Instruction::CallCore { function_index: 5 },
],
ParsedType::ByteVector => vec![
Instruction::Dup,
Instruction::StringSize,
Instruction::CallCore { function_index: 0 },
Instruction::Swap2,
Instruction::StringLowerMemory,
Instruction::CallCore { function_index: 4 },
Instruction::CallCore { function_index: 5 },
],
_ => unimplemented!(),
}
}
}

View File

@ -1,10 +0,0 @@
use super::WITGenerator;
use super::Interfaces;
use wit_support::AstRecordItem;
impl WITGenerator for AstRecordItem {
fn generate_wit<'a>(&'a self, _interfaces: &mut Interfaces<'a>) {
unimplemented!()
}
}

View File

@ -1,22 +0,0 @@
use super::IType;
use wit_support::ParsedType;
pub(crate) fn ptype_to_itype(pty: &ParsedType) -> IType {
match pty {
ParsedType::I8 => IType::S8,
ParsedType::I16 => IType::S16,
ParsedType::I32 => IType::S32,
ParsedType::I64 => IType::S64,
ParsedType::U8 => IType::U8,
ParsedType::U16 => IType::U16,
ParsedType::U32 => IType::U32,
ParsedType::U64 => IType::U64,
ParsedType::F32 => IType::F32,
ParsedType::F64 => IType::F64,
ParsedType::Boolean => IType::I32,
ParsedType::Utf8String => IType::String,
ParsedType::ByteVector => IType::String,
ParsedType::Empty => panic!("this shouldn't happen"),
ParsedType::Record(_) => unimplemented!(),
}
}