some improvements

This commit is contained in:
vms 2021-04-05 01:09:55 +03:00
parent 440c5992c1
commit 7b8d72e84c
12 changed files with 179 additions and 88 deletions

View File

@ -17,6 +17,7 @@
mod item_fn;
mod item_foreign_mod;
mod item_record;
mod utils;
use crate::fce_ast_types::FCEAst;

View File

@ -20,7 +20,6 @@ use crate::ParsedType;
use crate::fce_ast_types::FCEAst;
use crate::fce_ast_types::AstFunctionItem;
use crate::fce_ast_types::AstFuncArgument;
use crate::parsed_type::passing_style_of;
use crate::syn_error;
use syn::Result;
@ -148,23 +147,10 @@ fn check_parsed_functions<'a>(
/// Vec<Vec<&Vec<String>>> => true
/// &Vec<String> => false
fn contains_inner_ref(ty: &ParsedType) -> bool {
fn contains_inner_ref_impl(ty: &ParsedType) -> bool {
use crate::parsed_type::PassingStyle;
match ty {
ParsedType::Vector(ty, passing_style) => match passing_style {
PassingStyle::ByValue => contains_inner_ref_impl(ty),
PassingStyle::ByRef | PassingStyle::ByMutRef => true,
},
_ => match passing_style_of(ty) {
PassingStyle::ByValue => false,
PassingStyle::ByRef | PassingStyle::ByMutRef => true,
},
}
}
use super::utils::contain_inner_ref;
match ty {
ParsedType::Vector(ty, _) => contains_inner_ref_impl(ty),
ParsedType::Vector(ty, _) => contain_inner_ref(ty),
// Structs are checked while parsing
_ => false,
}

View File

@ -28,65 +28,105 @@ 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(name) if name.value() != "C" => {
return syn_error!(self.span(), "only 'C' abi is allowed")
}
_ => {}
check_foreign_section(&self)?;
let wasm_import_module: Option<String> = parse_wasm_import_module(&self);
let namespace = try_extract_namespace(wasm_import_module, &self)?;
let imports = extract_import_functions(&self)?;
check_imports(imports.iter().zip(self.items.iter().map(|i| i.span())))?;
let extern_mod_item = fce_ast_types::AstExternModItem {
namespace,
imports,
original: Some(self),
};
Ok(FCEAst::ExternMod(extern_mod_item))
}
}
let self_span = self.span();
fn check_foreign_section(foreign_mod: &syn::ItemForeignMod) -> Result<()> {
match &foreign_mod.abi.name {
Some(name) if name.value() != "C" => {
syn_error!(foreign_mod.span(), "only 'C' abi is allowed")
}
_ => Ok(()),
}
}
let imports = self
.items
.iter()
.cloned()
.map(parse_raw_foreign_item)
.collect::<Result<_>>()?;
/// Tries to find and parse wasm module name from
/// #[link(wasm_import_module = "host")]
fn parse_wasm_import_module(foreign_mod: &syn::ItemForeignMod) -> Option<String> {
foreign_mod
.attrs
.iter()
.filter_map(|attr| attr.parse_meta().ok())
.filter(|meta| meta.path().is_ident(LINK_DIRECTIVE_NAME))
.filter_map(|meta| {
let pair = match meta {
syn::Meta::List(mut meta_list) if meta_list.nested.len() == 1 => {
meta_list.nested.pop().unwrap()
}
_ => return None,
};
Some(pair.into_tuple().0)
})
.filter_map(|nested| match nested {
syn::NestedMeta::Meta(meta) => Some(meta),
_ => None,
})
.filter(|meta| meta.path().is_ident(WASM_IMPORT_MODULE_DIRECTIVE_NAME))
.map(extract_value)
.collect()
}
// try to find and parse wasm module name from
// #[link(wasm_import_module = "host")]
let wasm_import_module: Option<String> = self
.attrs
.iter()
.filter_map(|attr| attr.parse_meta().ok())
.filter(|meta| meta.path().is_ident(LINK_DIRECTIVE_NAME))
.filter_map(|meta| {
let pair = match meta {
syn::Meta::List(mut meta_list) if meta_list.nested.len() == 1 => {
meta_list.nested.pop().unwrap()
}
_ => return None,
};
Some(pair.into_tuple().0)
})
.filter_map(|nested| match nested {
syn::NestedMeta::Meta(meta) => Some(meta),
_ => None,
})
.filter(|meta| meta.path().is_ident(WASM_IMPORT_MODULE_DIRECTIVE_NAME))
.map(extract_value)
.collect();
fn try_extract_namespace(
attr: Option<String>,
foreign_mod: &syn::ItemForeignMod,
) -> Result<String> {
match attr {
Some(namespace) if namespace.is_empty() => syn_error!(
foreign_mod.span(),
"import module name should be defined by 'wasm_import_module' directive"
),
Some(namespace) => Ok(namespace),
None => syn_error!(
foreign_mod.span(),
"import module name should be defined by 'wasm_import_module' directive"
),
}
}
match wasm_import_module {
Some(namespace) if namespace.is_empty() => syn_error!(
self_span,
"import module name should be defined by 'wasm_import_module' directive"
),
Some(namespace) => {
let extern_mod_item = fce_ast_types::AstExternModItem {
namespace,
imports,
original: Some(self),
};
Ok(FCEAst::ExternMod(extern_mod_item))
fn extract_import_functions(
foreign_mod: &syn::ItemForeignMod,
) -> Result<Vec<fce_ast_types::AstExternFnItem>> {
foreign_mod
.items
.iter()
.cloned()
.map(parse_raw_foreign_item)
.collect::<Result<_>>()
}
/// This function checks whether these imports contains inner references. In this case glue
/// code couldn't be generated.
fn check_imports<'i>(
extern_fns: impl ExactSizeIterator<Item = (&'i fce_ast_types::AstExternFnItem, proc_macro2::Span)>,
) -> Result<()> {
use super::utils::contain_inner_ref;
for (extern_fn, span) in extern_fns {
if let Some(output_type) = &extern_fn.signature.output_type {
if contain_inner_ref(output_type) {
return crate::syn_error!(
span,
"import function can't return a value with references"
);
}
None => syn_error!(
self_span,
"import module name should be defined by 'wasm_import_module' directive"
),
}
}
Ok(())
}
fn parse_raw_foreign_item(raw_item: syn::ForeignItem) -> Result<fce_ast_types::AstExternFnItem> {

View File

@ -0,0 +1,33 @@
/*
* 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::ParsedType;
use crate::parsed_type::PassingStyle;
use crate::parsed_type::passing_style_of;
/// Checks whether a type contains a reference in one of types.
pub(super) fn contain_inner_ref(ty: &ParsedType) -> bool {
let passing_style = passing_style_of(ty);
match passing_style {
PassingStyle::ByValue => {}
PassingStyle::ByRef | PassingStyle::ByMutRef => return true,
};
match ty {
ParsedType::Vector(ty, _) => contain_inner_ref(ty),
_ => false,
}
}

View File

@ -57,7 +57,7 @@ pub enum ParsedType {
Record(String, PassingStyle), // short type name
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum PassingStyle {
ByValue,
ByRef,

View File

@ -116,11 +116,14 @@ fn generate_epilog(ty: &Option<ParsedType>) -> proc_macro2::TokenStream {
fluence::internal::set_result_size(result.len() as _);
}
}
Some(ParsedType::Vector(ty, _)) => {
Some(ParsedType::Vector(ty, passing_style)) => {
let generated_serializer_name = "__fce_generated_vec_serializer";
let generated_serializer_ident = new_ident!(generated_serializer_name);
let vector_serializer =
super::vector_utils::generate_vector_serializer(ty, generated_serializer_name);
let vector_serializer = super::vector_utils::generate_vector_serializer(
ty,
*passing_style,
generated_serializer_name,
);
quote! {
#vector_serializer

View File

@ -81,11 +81,11 @@ impl ForeignModPrologGlueCodeGenerator for Vec<AstFuncArgument> {
arg_transforms.extend(quote::quote! { let mut #arg_ident = std::mem::ManuallyDrop::new(#arg_ident); });
arg_drops.extend(quote::quote! { std::mem::ManuallyDrop::drop(&mut #arg_ident); });
},
ParsedType::Vector(ty, _) => {
ParsedType::Vector(ty, passing_style) => {
let generated_serializer_name = format!("__fce_generated_vec_serializer_{}", arg_name).replace("&<>", "_");
let generated_serializer_ident = new_ident!(generated_serializer_name);
let vector_serializer = super::vector_utils::generate_vector_serializer(ty, &generated_serializer_name);
let vector_serializer = super::vector_utils::generate_vector_serializer(ty, *passing_style, &generated_serializer_name);
let arg_transform = quote::quote! {
#vector_serializer

View File

@ -15,21 +15,13 @@
*/
use super::ParsedType;
use super::PassingStyle;
use quote::quote;
pub(crate) fn generate_vector_serializer(
value_ty: &ParsedType,
arg_name: &str,
) -> proc_macro2::TokenStream {
let serializer_func = generate_vector_serializer_impl(value_ty, arg_name);
quote! {
#serializer_func
}
}
fn generate_vector_serializer_impl(
value_ty: &ParsedType,
vec_passing_style: PassingStyle,
arg_name: &str,
) -> proc_macro2::TokenStream {
let values_serializer = match value_ty {
@ -90,12 +82,13 @@ fn generate_vector_serializer_impl(
(result.as_ptr() as _, (4 * result.len()) as _)
}
}
ParsedType::Vector(ty, _) => {
ParsedType::Vector(ty, passing_style) => {
let serializer_name = format!("{}_{}", arg_name, ty)
.replace("<", "_")
.replace(">", "_")
.replace("&", "_");
let inner_vector_serializer = generate_vector_serializer(&*ty, &serializer_name);
let inner_vector_serializer =
generate_vector_serializer(&*ty, *passing_style, &serializer_name);
let serializer_ident = crate::new_ident!(serializer_name);
quote! {
@ -128,7 +121,7 @@ fn generate_vector_serializer_impl(
let arg = crate::new_ident!(arg_name);
quote! {
unsafe fn #arg(arg: Vec<#value_ty>) -> (u32, u32) {
unsafe fn #arg(arg: #vec_passing_style Vec<#value_ty>) -> (u32, u32) {
#values_serializer
}
}

View File

@ -44,7 +44,7 @@ impl RecordSerializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
std::mem::forget(#field_ident);
}
}
ParsedType::Vector(ty, _) => {
ParsedType::Vector(ty, passing_style) => {
let generated_serializer_name = format!(
"__fce_generated_vec_serializer_{}_{}",
field.name.as_ref().unwrap(),
@ -54,6 +54,7 @@ impl RecordSerializerGlueCodeGenerator for fce_ast_types::AstRecordItem {
let generated_serializer_ident = new_ident!(generated_serializer_name);
let vector_serializer = crate::parsed_type::generate_vector_serializer(
ty,
*passing_style,
&generated_serializer_name,
);
let serialized_field_ident = new_ident!(format!("serialized_arg_{}", id));

View File

@ -0,0 +1,27 @@
#![allow(improper_ctypes)]
use fluence::fce;
pub fn main() {}
#[fce]
#[link(wasm_import_module = "arrays_passing_effector")]
extern "C" {
#[fce]
pub fn func_1() -> &String;
#[fce]
pub fn func_2() -> &Vec<Vec<Vec<Vec<u8>>>>;
#[fce]
pub fn func_3() -> Vec<&Vec<Vec<Vec<u8>>>>;
#[fce]
pub fn func_4() -> Vec<Vec<&Vec<Vec<u8>>>>;
#[fce]
pub fn func_5() -> Vec<Vec<Vec<&Vec<u8>>>>;
#[fce]
pub fn func_6() -> Vec<Vec<Vec<Vec<&u8>>>>;
}

View File

@ -0,0 +1,6 @@
error: import function can't return a value with references
--> $DIR/arrays_out_inner_refs.rs:10:5
|
10 | / #[fce]
11 | | pub fn func_1() -> &String;
| |_______________________________^

View File

@ -8,6 +8,7 @@ fn test() {
tests.pass("tests/export_functions/ref_basic_types.rs");
tests.compile_fail("tests/export_functions/improper_types.rs");
tests.compile_fail("tests/import_functions/arrays_out_inner_refs.rs");
tests.pass("tests/import_functions/arrays.rs");
tests.pass("tests/import_functions/ref_arrays.rs");
tests.pass("tests/import_functions/basic_types.rs");