mirror of
https://github.com/fluencelabs/marine-rs-sdk
synced 2025-03-15 22:30:50 +00:00
update macro crate
This commit is contained in:
parent
aa73411663
commit
79d7e181ee
@ -21,4 +21,5 @@ proc-macro = true
|
|||||||
syn = { version = '1.0.33', features = ['full'] }
|
syn = { version = '1.0.33', features = ['full'] }
|
||||||
quote = "1.0.7"
|
quote = "1.0.7"
|
||||||
proc-macro2 = "1.0.18"
|
proc-macro2 = "1.0.18"
|
||||||
|
|
||||||
fluence-sdk-main = { path = "../main", version = "=0.1.11" }
|
fluence-sdk-main = { path = "../main", version = "=0.1.11" }
|
||||||
|
41
crates/macro/src/fce_ast_types.rs
Normal file
41
crates/macro/src/fce_ast_types.rs
Normal 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),
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018 Fluence Labs Limited
|
* Copyright 2020 Fluence Labs Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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")]
|
#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.1.11")]
|
||||||
#![deny(
|
#![deny(
|
||||||
dead_code,
|
// dead_code,
|
||||||
nonstandard_style,
|
nonstandard_style,
|
||||||
unused_imports,
|
unused_imports,
|
||||||
unused_mut,
|
unused_mut,
|
||||||
unused_variables,
|
|
||||||
unused_unsafe,
|
unused_unsafe,
|
||||||
unreachable_patterns
|
unreachable_patterns
|
||||||
)]
|
)]
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
#![recursion_limit = "128"]
|
#![recursion_limit = "1024"]
|
||||||
|
|
||||||
mod macro_attr_parser;
|
mod fce_ast_types;
|
||||||
mod macro_input_parser;
|
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 macro_impl::fce_impl;
|
||||||
use crate::macro_input_parser::{InputTypeGenerator, ParsedType, ReturnTypeGenerator};
|
|
||||||
use proc_macro::TokenStream;
|
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]
|
#[proc_macro_attribute]
|
||||||
pub fn faas_export(attr: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn fce(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let fn_item = parse_macro_input!(input as ItemFn);
|
// into converts proc_macro::TokenStream to proc_macro2::TokenStream
|
||||||
match invoke_handler_impl(attr.into(), fn_item) {
|
match fce_impl(input.into()) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
// converts syn:error to proc_macro2::TokenStream
|
// converts syn:error to proc_macro2::TokenStream
|
||||||
Err(e) => e.to_compile_error(),
|
Err(e) => e.to_compile_error(),
|
||||||
|
@ -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)
|
|
||||||
}
|
|
77
crates/macro/src/macro_impl.rs
Normal file
77
crates/macro/src/macro_impl.rs
Normal 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)
|
||||||
|
*/
|
||||||
|
}
|
41
crates/macro/src/parse_macro_input.rs
Normal file
41
crates/macro/src/parse_macro_input.rs
Normal 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",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
109
crates/macro/src/parse_macro_input/item_fn.rs
Normal file
109
crates/macro/src/parse_macro_input/item_fn.rs
Normal 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",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
117
crates/macro/src/parse_macro_input/item_foreign_mod.rs
Normal file
117
crates/macro/src/parse_macro_input/item_foreign_mod.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
25
crates/macro/src/parse_macro_input/item_record.rs
Normal file
25
crates/macro/src/parse_macro_input/item_record.rs
Normal 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!()
|
||||||
|
}
|
||||||
|
}
|
@ -15,13 +15,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{parse::Error, spanned::Spanned};
|
use syn::parse::Error;
|
||||||
|
use syn::spanned::Spanned;
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum ParsedType {
|
pub(crate) enum ParsedType {
|
||||||
|
Empty,
|
||||||
|
I8,
|
||||||
|
I16,
|
||||||
|
I32,
|
||||||
|
I64,
|
||||||
|
U8,
|
||||||
|
U16,
|
||||||
|
U32,
|
||||||
|
U64,
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
Boolean,
|
||||||
Utf8String,
|
Utf8String,
|
||||||
ByteVector,
|
ByteVector,
|
||||||
Empty,
|
Record(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParsedType {
|
impl ParsedType {
|
||||||
@ -103,6 +116,17 @@ impl ParsedType {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
match type_segment.ident.to_string().as_str() {
|
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),
|
"String" => Ok(ParsedType::Utf8String),
|
||||||
"Vec" => match parse_vec_bracket(&type_segment.arguments) {
|
"Vec" => match parse_vec_bracket(&type_segment.arguments) {
|
||||||
Ok(value) => match value.as_str() {
|
Ok(value) => match value.as_str() {
|
||||||
@ -114,9 +138,9 @@ impl ParsedType {
|
|||||||
},
|
},
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
},
|
},
|
||||||
_ => Err(Error::new(
|
type_name => Err(Error::new(
|
||||||
type_segment.span(),
|
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;
|
fn generate_fn_prolog(&self) -> proc_macro2::TokenStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ReturnTypeGenerator {
|
pub trait EpilogGenerator {
|
||||||
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream;
|
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputTypeGenerator for ParsedType {
|
impl PrologGenerator for ParsedType {
|
||||||
fn generate_fn_prolog(&self) -> proc_macro2::TokenStream {
|
fn generate_fn_prolog(&self) -> proc_macro2::TokenStream {
|
||||||
match self {
|
match self {
|
||||||
ParsedType::Utf8String => quote! {
|
ParsedType::Utf8String => quote! {
|
||||||
@ -160,11 +184,12 @@ impl InputTypeGenerator for ParsedType {
|
|||||||
// this way does it without any additional imports of the export allocator module
|
// this way does it without any additional imports of the export allocator module
|
||||||
let arg = memory::read_request_from_mem(ptr, len);
|
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 {
|
fn generate_fn_epilog(&self) -> proc_macro2::TokenStream {
|
||||||
match self {
|
match self {
|
||||||
ParsedType::Utf8String => quote! {
|
ParsedType::Utf8String => quote! {
|
||||||
@ -178,6 +203,7 @@ impl ReturnTypeGenerator for ParsedType {
|
|||||||
.expect("Putting result vector to memory has failed")
|
.expect("Putting result vector to memory has failed")
|
||||||
},
|
},
|
||||||
ParsedType::Empty => quote! {},
|
ParsedType::Empty => quote! {},
|
||||||
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
37
crates/macro/src/token_stream_generator.rs
Normal file
37
crates/macro/src/token_stream_generator.rs
Normal 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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
crates/macro/src/token_stream_generator/fn_generator.rs
Normal file
26
crates/macro/src/token_stream_generator/fn_generator.rs
Normal 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!()
|
||||||
|
}
|
||||||
|
}
|
@ -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!()
|
||||||
|
}
|
||||||
|
}
|
26
crates/macro/src/token_stream_generator/record_generator.rs
Normal file
26
crates/macro/src/token_stream_generator/record_generator.rs
Normal 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!()
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user