update macro crate

This commit is contained in:
vms 2020-07-01 22:47:21 +03:00
parent aa73411663
commit 79d7e181ee
14 changed files with 573 additions and 394 deletions

View File

@ -21,4 +21,5 @@ proc-macro = true
syn = { version = '1.0.33', features = ['full'] }
quote = "1.0.7"
proc-macro2 = "1.0.18"
fluence-sdk-main = { path = "../main", version = "=0.1.11" }

View File

@ -0,0 +1,41 @@
/*
* 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::parsed_type::ParsedType;
pub(crate) struct AstFunctionItem {
pub(crate) name: String,
pub(crate) input_types: Vec<ParsedType>,
// fce supports only one return value now,
// waiting for adding multi-value support in Wasmer.
pub(crate) output_type: ParsedType,
}
pub(crate) struct AstRecordItem {
pub(crate) fields: Vec<ParsedType>,
}
pub(crate) struct AstExternModItem {
pub(crate) namespace: String,
// only imports are possible here
pub(crate) imports: Vec<AstFunctionItem>,
}
pub(crate) enum FCEAst {
Function(AstFunctionItem),
Record(AstRecordItem),
ExternMod(AstExternModItem),
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2018 Fluence Labs Limited
* 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.
@ -13,197 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! This module defines an `invocation_handler` attribute procedural macro. It can be used to
//! simplify the signature of the main module invocation handler:
//!
//! ```
//! use fluence::sdk::*;
//!
//! #[invocation_handler]
//! fn greeting(name: String) -> String {
//! format!("Hello from Fluence to {}", name)
//! }
//! ```
//!
//! To use this macro with a function `f` certain conditions must be met:
//! 1. `f` shouldn't have more than one input argument.
//! 2. `f` shouldn't be `unsafe`, `const`, generic, have custom ABI linkage or variadic param.
//! 3. The type of `f` input (if it presents) and output parameters should be one from
//! {String, Vec<u8>} set.
//! 4. `f` shouldn't have the name `invoke`.
//!
//! For troubleshooting and macros debugging [cargo expand](https://github.com/dtolnay/cargo-expand)
//! can be used.
//!
//! Internally this macro creates a new function `invoke` that converts a raw argument to the
//! appropriate format, calls `f` and then writes `f` result via `memory::write_response_to_mem` to
//! module memory. So to use this crate apart from `fluence` `fluence_sdk_main` has to be imported.
//!
//! The macro also has the `init_fn` and `side_modules` attributes. The first one that can be used
//! for specifying initialization function name. This function is called only once at the first
//! call of the invoke function. It can be used like this:
//!
//! ```
//! use fluence::sdk::*;
//! use log::info;
//!
//! fn init() {
//! logger::WasmLogger::init_with_level(log::Level::Info).is_ok()
//! }
//!
//! #[invocation_handler(init_fn = init)]
//! fn greeting(name: String) -> String {
//! info!("{} has been successfully greeted", name);
//! format!("Hello from Fluence to {}", name)
//! }
//! ```
//!
//! The second macro could be used for generate API to connect with side modules like SQlite and
//! Redis. It can be used like this:
//! ```
//! use fluence::sdk::*;
//!
//! #[invocation_handler(side_modules = (sqlite, redis))]
//! fn greeting(name: String) -> String {
//! sqlite::call("SELECT * from users");
//! sqlite::call("GET user");
//! format!("Hello from Fluence to {}", name)
//! }
//! ```
//!
//! # Examples
//!
//! Please find more examples [here](https://github.com/fluencelabs/tutorials).
#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.1.11")]
#![deny(
dead_code,
// dead_code,
nonstandard_style,
unused_imports,
unused_mut,
unused_variables,
unused_unsafe,
unreachable_patterns
)]
#![warn(rust_2018_idioms)]
#![recursion_limit = "128"]
#![recursion_limit = "1024"]
mod macro_attr_parser;
mod macro_input_parser;
mod fce_ast_types;
mod parsed_type;
mod macro_impl;
mod parse_macro_input;
mod token_stream_generator;
use crate::macro_attr_parser::{generate_side_modules_glue_code, HandlerAttrs};
use crate::macro_input_parser::{InputTypeGenerator, ParsedType, ReturnTypeGenerator};
use macro_impl::fce_impl;
use proc_macro::TokenStream;
use quote::quote;
use syn::spanned::Spanned;
use syn::{parse::Error, parse_macro_input, ItemFn, Visibility};
fn invoke_handler_impl(
attr: proc_macro2::TokenStream,
fn_item: ItemFn,
) -> syn::Result<proc_macro2::TokenStream> {
let ItemFn {
vis,
sig,
..
} = &fn_item;
match vis {
Visibility::Public(_) => {},
_ => return Err(Error::new(
vis.span(),
"The #[faas_export] could be applied only to public functions",
))
}
let input_type = match sig.inputs.len() {
0 => ParsedType::Empty,
1 => ParsedType::from_fn_arg(sig.inputs.first().unwrap())?,
_ => {
return Err(Error::new(
sig.inputs.span(),
"The invocation handler shouldn't have more than one argument",
))
},
};
let output_type = ParsedType::from_return_type(&sig.output)?;
if output_type == ParsedType::Empty {
return Err(Error::new(
sig.output.span(),
"The invocation handler should have the return value",
));
}
let ident = &sig.ident;
let prolog = input_type.generate_fn_prolog();
let prolog = match input_type {
ParsedType::Empty => quote! {
#prolog
let result = #ident();
},
_ => quote! {
#prolog
let result = #ident(arg);
},
};
let epilog = output_type.generate_fn_epilog();
let attrs = syn::parse2::<HandlerAttrs>(attr)?;
let raw_init_fn_name = attrs.init_fn_name();
let raw_side_modules_list = attrs.side_modules();
let resulted_invoke = match raw_init_fn_name {
Some(init_fn_name) => {
let init_fn_name = syn::parse_str::<syn::Ident>(init_fn_name)?;
quote! {
#fn_item
static mut __FLUENCE_SDK_IS_INITED_d28374a960b570e5db00dfe7a0c7b93: bool = false;
#[no_mangle]
pub unsafe fn invoke(ptr: *mut u8, len: usize) -> std::ptr::NonNull<u8> {
if !__FLUENCE_SDK_IS_INITED_d28374a960b570e5db00dfe7a0c7b93 {
#init_fn_name();
unsafe { __FLUENCE_SDK_IS_INITED_d28374a960b570e5db00dfe7a0c7b93 = true; }
}
#prolog
#epilog
}
}
},
None => quote! {
#fn_item
#[no_mangle]
pub unsafe fn invoke(ptr: *mut u8, len: usize) -> std::ptr::NonNull<u8> {
#prolog
#epilog
}
},
};
match raw_side_modules_list {
Some(side_modules) => {
let side_modules_glue_code = generate_side_modules_glue_code(side_modules)?;
Ok(quote! {
#side_modules_glue_code
#resulted_invoke
})
},
_ => Ok(resulted_invoke),
}
}
#[proc_macro_attribute]
pub fn faas_export(attr: TokenStream, input: TokenStream) -> TokenStream {
let fn_item = parse_macro_input!(input as ItemFn);
match invoke_handler_impl(attr.into(), fn_item) {
pub fn fce(_attr: TokenStream, input: TokenStream) -> TokenStream {
// into converts proc_macro::TokenStream to proc_macro2::TokenStream
match fce_impl(input.into()) {
Ok(v) => v,
// converts syn:error to proc_macro2::TokenStream
Err(e) => e.to_compile_error(),

View File

@ -1,208 +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 quote::quote;
use syn::export::TokenStream2;
use syn::parse::{Parse, ParseStream};
pub struct HandlerAttrs {
handler_attrs: Vec<HandlerAttr>,
}
pub enum HandlerAttr {
InitFnName(String),
SideModules(Vec<String>),
}
impl HandlerAttrs {
pub fn init_fn_name(&self) -> Option<&str> {
self.handler_attrs
.iter()
.filter_map(|attr| match attr {
HandlerAttr::InitFnName(name) => Some(&name[..]),
_ => None,
})
.next()
}
pub fn side_modules(&self) -> Option<&Vec<String>> {
self.handler_attrs
.iter()
.filter_map(|attr| match attr {
HandlerAttr::SideModules(modules) => Some(modules),
_ => None,
})
.next()
}
}
impl Default for HandlerAttrs {
fn default() -> Self {
HandlerAttrs {
handler_attrs: Vec::new(),
}
}
}
impl Parse for HandlerAttrs {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let mut attrs = HandlerAttrs::default();
if input.is_empty() {
return Ok(attrs);
}
let attr_opts =
syn::punctuated::Punctuated::<HandlerAttr, syn::token::Comma>::parse_terminated(input)?;
attrs.handler_attrs = attr_opts.into_iter().collect();
Ok(attrs)
}
}
impl Parse for HandlerAttr {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
// trying to parse the `init_fn`/`side_modules`/... tokens
let attr_name = input.step(|cursor| match cursor.ident() {
Some((ident, rem)) => Ok((ident, rem)),
None => Err(cursor.error("Expected a valid ident")),
})?;
match attr_name.to_string().as_str() {
"init_fn" => {
// trying to parse `=`
input.parse::<::syn::token::Eq>()?;
// trying to parse a init function name
match input.parse::<syn::Ident>() {
Ok(init_fn_name) => Ok(HandlerAttr::InitFnName(init_fn_name.to_string())),
Err(_) => Err(syn::Error::new(
attr_name.span(),
"Expected a function name",
)),
}
},
"side_modules" => {
// trying to parse `=`
input.parse::<::syn::token::Eq>()?;
// check for parens
let raw_side_modules_list = match syn::group::parse_parens(&input) {
Ok(parens) => parens.content,
_ => {
match input.parse::<syn::Ident>() {
Ok(module_name) => return Ok(HandlerAttr::SideModules(vec![module_name.to_string()])),
Err(_) => return Err(syn::Error::new(
attr_name.span(),
"Expected a module name name",
)),
}
}
};
let raw_side_modules_opts =
syn::punctuated::Punctuated::<syn::Ident, syn::token::Comma>::parse_terminated(
&raw_side_modules_list,
)?;
let side_modules = raw_side_modules_opts
.iter()
.map(|c| c.to_string())
.collect();
Ok(HandlerAttr::SideModules(side_modules))
},
_ => Err(syn::Error::new(
attr_name.span(),
"Expected a `side_modules` or `init_fn` tokens in invocation_handler macros attributes",
)),
}
}
}
pub fn generate_side_modules_glue_code(side_modules_list: &[String]) -> syn::Result<TokenStream2> {
let mut modules_glue_code = quote!();
for module_name in side_modules_list {
let module_name_ident = syn::parse_str::<syn::Ident>(&module_name)?;
modules_glue_code = quote! {
pub mod #module_name_ident {
#[link(wasm_import_module = #module_name)]
extern "C" {
// Allocate chunk of module memory, and return a pointer to that region
pub fn allocate(size: usize) -> i32;
// Deallocate chunk of module memory after it's not used anymore
pub fn deallocate(ptr: i32, size: usize);
// Call module's invocation handler with data specified by pointer and size
pub fn invoke(ptr: i32, size: usize) -> i32;
// Read 1 byte from ptr location of module memory
pub fn load(ptr: i32) -> u8;
// Put 1 byte at ptr location in module memory
pub fn store(ptr: *mut i32, byte: u8);
}
// Execute query on module
pub fn call(request: &[u8]) -> Vec<u8> {
unsafe {
// Allocate memory for the query in module
let query_ptr = allocate(request.len());
// Store query in module's memory
for (i, byte) in request.iter().enumerate() {
let ptr = query_ptr + i as i32;
store(ptr as *mut i32, *byte);
}
// Execute the query, and get pointer to the result
let response_ptr = invoke(query_ptr, request.len());
// First 4 bytes at result_ptr location encode result size, read that first
let mut response_size: usize = 0;
for byte_id in 0..3 {
let ptr = response_ptr + byte_id as i32;
let b = load(ptr) as usize;
response_size = response_size + (b << (8 * byte_id));
}
// Now we know exact size of the query execution result
// Read query execution result byte-by-byte
let mut response_bytes = vec![0; response_size as usize];
for byte_id in 0..response_size {
let ptr = response_ptr + (byte_id + 4) as i32;
let b = load(ptr);
response_bytes[byte_id as usize] = b;
}
// Deallocate response
deallocate(response_ptr, response_size + 4);
response_bytes
}
}
}
#modules_glue_code
}
}
Ok(modules_glue_code)
}

View File

@ -0,0 +1,77 @@
/*
* 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::parse_macro_input::ParseMacroInput;
use crate::token_stream_generator::TokenStreamGenerator;
use proc_macro2::TokenStream;
use syn::Result;
pub(super) fn fce_impl(tokens: TokenStream) -> Result<TokenStream> {
let item = syn::parse2::<syn::Item>(tokens)?;
let fce_ast_item = item.parse_macro_input()?;
fce_ast_item.generate_token_stream()
/*
let input_type = match sig.inputs.len() {
0 => ParsedType::Empty,
1 => ParsedType::from_fn_arg(sig.inputs.first().unwrap())?,
_ => {
return Err(Error::new(
sig.inputs.span(),
"The invocation handler shouldn't have more than one argument",
))
}
};
let output_type = ParsedType::from_return_type(&sig.output)?;
if output_type == ParsedType::Empty {
return Err(Error::new(
sig.output.span(),
"The invocation handler should have the return value",
));
}
let ident = &sig.ident;
let prolog = input_type.generate_fn_prolog();
let prolog = match input_type {
ParsedType::Empty => quote! {
#prolog
let result = #ident();
},
_ => quote! {
#prolog
let result = #ident(arg);
},
};
let epilog = output_type.generate_fn_epilog();
let resulted_invoke = quote! {
#fn_item
#[no_mangle]
pub unsafe fn invoke(ptr: *mut u8, len: usize) -> std::ptr::NonNull<u8> {
#prolog
#epilog
}
};
Ok(resulted_invoke)
*/
}

View File

@ -0,0 +1,41 @@
/*
* 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.
*/
mod item_fn;
mod item_foreign_mod;
mod item_record;
use crate::fce_ast_types::FCEAst;
pub(crate) trait ParseMacroInput {
fn parse_macro_input(self) -> syn::Result<FCEAst>;
}
impl ParseMacroInput for syn::Item {
fn parse_macro_input(self) -> syn::Result<FCEAst> {
use syn::spanned::Spanned;
match self {
syn::Item::Fn(function) => function.parse_macro_input(),
syn::Item::ForeignMod(extern_mod) => extern_mod.parse_macro_input(),
syn::Item::Struct(item_struct) => item_struct.parse_macro_input(),
_ => Err(syn::Error::new(
self.span(),
"At now, #[fce] could be applied only to a function, extern block or struct",
)),
}
}
}

View File

@ -0,0 +1,109 @@
/*
* 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::ParseMacroInput;
use crate::fce_ast_types;
use crate::fce_ast_types::FCEAst;
use syn::Result;
impl ParseMacroInput for syn::ItemFn {
fn parse_macro_input(self) -> Result<FCEAst> {
parse_function(self.sig, self.vis).map(|f| FCEAst::Function(f))
}
}
pub(super) fn parse_function(
function_sig: syn::Signature,
function_vis: syn::Visibility,
) -> Result<fce_ast_types::AstFunctionItem> {
use crate::parsed_type::ParsedType;
check_func(&function_sig, function_vis)?;
let syn::Signature { inputs, output, .. } = function_sig;
let input_types = inputs
.iter()
.map(ParsedType::from_fn_arg)
.collect::<Result<Vec<_>>>()?;
let output_type = ParsedType::from_return_type(&output)?;
let ast_function_item = fce_ast_types::AstFunctionItem {
name: function_sig.ident.to_string(),
input_types,
output_type,
};
Ok(ast_function_item)
}
/// Check whether the #[fce] macro could be applied to a function.
fn check_func(function_sig: &syn::Signature, function_vis: syn::Visibility) -> Result<()> {
use syn::Error;
use syn::spanned::Spanned;
let syn::Signature {
constness,
unsafety,
abi,
variadic,
generics,
..
} = function_sig;
if let Some(constness) = constness {
return Err(Error::new(
constness.span,
"FCE export function shouldn't be constant",
));
}
if let Some(unsafety) = unsafety {
return Err(Error::new(
unsafety.span,
"FCE export function shouldn't be unsafe",
));
}
if let Some(abi) = abi {
return Err(Error::new(
abi.extern_token.span,
"FCE export function shouldn't have any custom linkage",
));
}
if !generics.params.is_empty() || generics.where_clause.is_some() {
return Err(Error::new(
function_sig.span(),
"FCE export function shouldn't use template parameters",
));
}
if let Some(_) = variadic {
return Err(Error::new(
variadic.span(),
"FCE export function shouldn't use variadic interface",
));
}
// TODO: check for a lifetime
match function_vis {
syn::Visibility::Public(_) => Ok(()),
_ => Err(Error::new(
variadic.span(),
"FCE export function should be public",
)),
}
}

View File

@ -0,0 +1,117 @@
/*
* 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::ParseMacroInput;
use crate::fce_ast_types;
use crate::fce_ast_types::FCEAst;
use syn::Error;
use syn::Result;
use syn::spanned::Spanned;
const LINK_DIRECTIVE_NAME: &str = "link";
const LINK_NAME_DIRECTIVE_NAME: &str = "link_name";
const WASM_IMPORT_MODULE_DIRECTIVE_NAME: &str = "wasm_import_module";
impl ParseMacroInput for syn::ItemForeignMod {
fn parse_macro_input(self) -> Result<FCEAst> {
match self.abi.name {
Some(ref name) if name.value() != "C".to_string() => {
return Err(Error::new(self.span(), "only 'C' abi is allowed"))
}
_ => {}
};
let self_span = self.span();
let imports = self
.items
.into_iter()
.map(parse_raw_foreign_item)
.collect::<Result<_>>()?;
// try to find and parse wasm module name from
// #[link(wasm_import_module = "host")]
let wasm_import_module: Option<String> = self
.attrs
.into_iter()
.filter_map(|attr| attr.parse_meta().ok())
.filter(|meta| meta.path().is_ident(LINK_DIRECTIVE_NAME))
.filter_map(|meta| match meta {
syn::Meta::List(meta_list) => Some(meta_list),
_ => None,
})
.filter_map(|meta_list| match meta_list.nested.first().unwrap() {
syn::NestedMeta::Meta(meta) => Some(meta.clone()),
_ => None,
})
.filter(|meta| meta.path().is_ident(WASM_IMPORT_MODULE_DIRECTIVE_NAME))
.map(extract_value)
.collect();
match wasm_import_module {
Some(namespace) => {
let extern_mod_item = fce_ast_types::AstExternModItem { namespace, imports };
Ok(FCEAst::ExternMod(extern_mod_item))
}
None => Err(Error::new(
self_span,
"import module name should be defined by 'wasm_import_module' directive",
)),
}
}
}
fn parse_raw_foreign_item(raw_item: syn::ForeignItem) -> Result<fce_ast_types::AstFunctionItem> {
let function_item = match raw_item {
syn::ForeignItem::Fn(function_item) => function_item,
_ => {
return Err(Error::new(
raw_item.span(),
"#[fce] could be upplied only to a function, struct ot extern block",
))
}
};
// parse the link_name attribute
// #[link_name = "put"]
// fn ipfs_put(ptr: i32, size: i32);
let link_name: Option<String> = function_item
.attrs
.iter()
.filter_map(|attr| attr.parse_meta().ok())
.filter(|meta| meta.path().is_ident(LINK_NAME_DIRECTIVE_NAME))
.map(extract_value)
.collect();
let mut function_item = super::item_fn::parse_function(function_item.sig, function_item.vis)?;
if let Some(link_name) = link_name {
function_item.name = link_name;
}
Ok(function_item)
}
fn extract_value(nested_meta: syn::Meta) -> Option<String> {
match nested_meta {
syn::Meta::NameValue(name_value) => match name_value.lit {
syn::Lit::Str(str) => Some(str.value()),
_ => None,
},
_ => None,
}
}

View File

@ -0,0 +1,25 @@
/*
* 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::ParseMacroInput;
use crate::fce_ast_types::FCEAst;
use syn::Result;
impl ParseMacroInput for syn::ItemStruct {
fn parse_macro_input(self) -> Result<FCEAst> {
unimplemented!()
}
}

View File

@ -15,13 +15,26 @@
*/
use quote::quote;
use syn::{parse::Error, spanned::Spanned};
use syn::parse::Error;
use syn::spanned::Spanned;
#[derive(PartialEq)]
pub enum ParsedType {
pub(crate) enum ParsedType {
Empty,
I8,
I16,
I32,
I64,
U8,
U16,
U32,
U64,
F32,
F64,
Boolean,
Utf8String,
ByteVector,
Empty,
Record(String),
}
impl ParsedType {
@ -103,6 +116,17 @@ impl ParsedType {
})?;
match type_segment.ident.to_string().as_str() {
"i8" => Ok(ParsedType::I8),
"i16" => Ok(ParsedType::I16),
"i32" => Ok(ParsedType::I32),
"i64" => Ok(ParsedType::I64),
"u8" => Ok(ParsedType::U8),
"u16" => Ok(ParsedType::U16),
"u32" => Ok(ParsedType::U32),
"u64" => Ok(ParsedType::U64),
"f32" => Ok(ParsedType::F32),
"f64" => Ok(ParsedType::F32),
"bool" => Ok(ParsedType::Boolean),
"String" => Ok(ParsedType::Utf8String),
"Vec" => match parse_vec_bracket(&type_segment.arguments) {
Ok(value) => match value.as_str() {
@ -114,9 +138,9 @@ impl ParsedType {
},
Err(e) => Err(e),
},
_ => Err(Error::new(
type_name => Err(Error::new(
type_segment.span(),
"Only String and Vec<u8> input types are supported (also, it is possible not to specify the input argument)",
format!("{} is unsupported", type_name),
)),
}
}
@ -136,15 +160,15 @@ impl ParsedType {
}
}
pub trait InputTypeGenerator {
pub trait PrologGenerator {
fn generate_fn_prolog(&self) -> proc_macro2::TokenStream;
}
pub trait ReturnTypeGenerator {
pub trait EpilogGenerator {
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream;
}
impl InputTypeGenerator for ParsedType {
impl PrologGenerator for ParsedType {
fn generate_fn_prolog(&self) -> proc_macro2::TokenStream {
match self {
ParsedType::Utf8String => quote! {
@ -160,11 +184,12 @@ impl InputTypeGenerator for ParsedType {
// this way does it without any additional imports of the export allocator module
let arg = memory::read_request_from_mem(ptr, len);
},
_ => unimplemented!(),
}
}
}
impl ReturnTypeGenerator for ParsedType {
impl EpilogGenerator for ParsedType {
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream {
match self {
ParsedType::Utf8String => quote! {
@ -178,6 +203,7 @@ impl ReturnTypeGenerator for ParsedType {
.expect("Putting result vector to memory has failed")
},
ParsedType::Empty => quote! {},
_ => unimplemented!(),
}
}
}

View File

@ -0,0 +1,37 @@
/*
* 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.
*/
mod fn_generator;
mod foreign_mod_generator;
mod record_generator;
use crate::fce_ast_types::FCEAst;
use proc_macro2::TokenStream;
pub(crate) trait TokenStreamGenerator {
fn generate_token_stream(self) -> syn::Result<TokenStream>;
}
impl TokenStreamGenerator for FCEAst {
fn generate_token_stream(self) -> syn::Result<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(),
}
}
}

View File

@ -0,0 +1,26 @@
/*
* 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::fce_ast_types;
use super::TokenStreamGenerator;
use proc_macro2::TokenStream;
impl TokenStreamGenerator for fce_ast_types::AstFunctionItem {
fn generate_token_stream(self) -> syn::Result<TokenStream> {
unimplemented!()
}
}

View File

@ -0,0 +1,26 @@
/*
* 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::fce_ast_types;
use super::TokenStreamGenerator;
use proc_macro2::TokenStream;
impl TokenStreamGenerator for fce_ast_types::AstExternModItem {
fn generate_token_stream(self) -> syn::Result<TokenStream> {
unimplemented!()
}
}

View File

@ -0,0 +1,26 @@
/*
* 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::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> {
unimplemented!()
}
}