mirror of
https://github.com/fluencelabs/marine-rs-sdk-test
synced 2024-12-04 15:20:18 +00:00
code cleaning
This commit is contained in:
parent
5f26af7990
commit
589daaea45
@ -28,6 +28,5 @@ debug = ["fluence-sdk-main/debug"]
|
||||
members = [
|
||||
"crates/main",
|
||||
"crates/macro",
|
||||
"crates/wit-support",
|
||||
"crates/wit"
|
||||
"crates/wit",
|
||||
]
|
||||
|
@ -17,4 +17,4 @@ all-features = true
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
wit-support = { path = "../wit-support" }
|
||||
fluence-sdk-wit = { path = "../wit" }
|
||||
|
@ -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]
|
||||
|
@ -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"] }
|
@ -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);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
@ -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"] }
|
||||
|
@ -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)]
|
@ -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)
|
||||
}
|
@ -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;
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
28
crates/wit/src/parsed_type/fn_arg.rs
Normal file
28
crates/wit/src/parsed_type/fn_arg.rs
Normal 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]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
111
crates/wit/src/parsed_type/fn_epilog.rs
Normal file
111
crates/wit/src/parsed_type/fn_epilog.rs
Normal 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")
|
||||
}
|
||||
}
|
||||
}
|
116
crates/wit/src/parsed_type/fn_prolog.rs
Normal file
116
crates/wit/src/parsed_type/fn_prolog.rs
Normal 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"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
crates/wit/src/parsed_type/foreign_mod_arg.rs
Normal file
37
crates/wit/src/parsed_type/foreign_mod_arg.rs
Normal 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 },
|
||||
}
|
||||
}
|
||||
}
|
67
crates/wit/src/parsed_type/foreign_mod_epilog.rs
Normal file
67
crates/wit/src/parsed_type/foreign_mod_epilog.rs
Normal 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"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
104
crates/wit/src/parsed_type/foreign_mod_prolog.rs
Normal file
104
crates/wit/src/parsed_type/foreign_mod_prolog.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
92
crates/wit/src/token_stream_generator/fn_generator.rs
Normal file
92
crates/wit/src/token_stream_generator/fn_generator.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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")]
|
@ -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!()
|
||||
}
|
||||
}
|
@ -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());
|
||||
};
|
||||
}
|
@ -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)
|
||||
}
|
21
crates/wit/src/wasm_type.rs
Normal file
21
crates/wit/src/wasm_type.rs
Normal 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),
|
||||
}
|
||||
}
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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!()
|
||||
}
|
||||
}
|
@ -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!(),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user