Skip to content

Commit

Permalink
Support implfn (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
llehtahw authored Mar 20, 2024
1 parent 56da633 commit 35e5dc2
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 85 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
workspace = { members = ["procs"] }
[package]
name = "statecs"
version = "0.1.0"
version = "0.2.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
193 changes: 110 additions & 83 deletions procs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use proc_macro2::Span;
use quote::quote;
use syn::{
fold::Fold, parse::Parse, parse_macro_input, parse_quote, punctuated::Punctuated,
spanned::Spanned, visit_mut::VisitMut, ExprTuple, Ident, ItemFn, Signature, Stmt, Token, Type,
spanned::Spanned, visit_mut::VisitMut, Block, ExprTuple, Ident, Signature, Stmt, Token, Type,
TypeParamBound, TypeTuple,
};

Expand Down Expand Up @@ -91,7 +91,7 @@ macro_rules! count {
}

fn expand_one_generic_for_inputs(
func: &mut ItemFn,
sig: &mut Signature,
inputs: &TypeTuple,
generic_id: &Ident,
) -> Ident {
Expand All @@ -109,8 +109,7 @@ fn expand_one_generic_for_inputs(
&std::format!("__EXPAND_{generic_id}_TAKE_ID"),
generic_id.span(),
);
func.sig
.generics
sig.generics
.params
.push(parse_quote!(#[allow(non_camel_case_types)] #id));
parse_quote!(#id)
Expand All @@ -120,10 +119,7 @@ fn expand_one_generic_for_inputs(
count!("__EXPAND_{generic_id}_TAKE_IDX_{}", idx_counter),
Span::mixed_site(),
);
func.sig
.generics
.params
.push(parse_quote!(const #idx: usize));
sig.generics.params.push(parse_quote!(const #idx: usize));
(
Some(parse_quote!(impl ComponentGet<#tp, #idx, Item=#tp, AfterTake=#item>)),
after,
Expand All @@ -132,14 +128,12 @@ fn expand_one_generic_for_inputs(
);
let take_bounds = take_bounds.unwrap_or_else(|| parse_quote!(TupleMerge));
let after_take_type_id = &after.unwrap_or(generic_id.clone());
func.sig
.generics
sig.generics
.make_where_clause()
.predicates
.push(parse_quote!(#after_take_type_id: TupleMerge));
fn find_param_bounds<'a>(func: &'a mut ItemFn, k: &Ident) -> &'a mut syn::TypeParam {
match func
.sig
fn find_param_bounds<'a>(sig: &'a mut Signature, k: &Ident) -> &'a mut syn::TypeParam {
match sig
.generics
.params
.iter_mut()
Expand All @@ -153,7 +147,7 @@ fn expand_one_generic_for_inputs(
_ => panic!(),
}
}
let k_bounds = &mut find_param_bounds(func, generic_id).bounds;
let k_bounds = &mut find_param_bounds(sig, generic_id).bounds;

match take_bounds {
Type::ImplTrait(impl_trait) => {
Expand All @@ -168,7 +162,7 @@ fn expand_one_generic_for_inputs(
}

fn generic_one_for_macro(
func: &mut ItemFn,
func_block: &mut Block,
generic_id: &Ident,
inputs: &TypeTuple,
_outputs: &TypeTuple,
Expand Down Expand Up @@ -235,7 +229,7 @@ fn generic_one_for_macro(
));
let mut block: syn::ExprBlock = parse_quote!({});
block.block.stmts.extend(stmts);
func.block.stmts.insert(
func_block.stmts.insert(
0,
parse_quote!(
#[allow(unused)]
Expand All @@ -248,7 +242,7 @@ fn generic_one_for_macro(
after_take.merge(res)
}
};
($expr:expr => $closure:expr, Option) => {
($expr:expr => $closure:expr => Option) => {
{
let #after_take_id = $expr;
let _closure = $closure;
Expand All @@ -261,71 +255,47 @@ fn generic_one_for_macro(

}
};
($expr:expr => $closure:expr => NoMerge) => {
{
let #after_take_id = $expr;
let _closure = $closure;
let (after_take, res) = #block;
(res, after_take)
}
};
}
),
)
}

fn replace_outof_macro(func: &mut ItemFn, map: &HashMap<Ident, Type>) {
struct ModifyOutOf<'a> {
modified: bool,
map: &'a HashMap<Ident, Type>,
}
impl<'a> syn::visit_mut::VisitMut for ModifyOutOf<'a> {
fn visit_type_mut(&mut self, i: &mut Type) {
syn::visit_mut::visit_type_mut(self, i);
if let Type::Macro(mc) = i {
let macro_ident = &mc.mac.path.segments.last().unwrap().ident;
let tokens = &mc.mac.tokens;
let id: Ident = parse_quote!(#tokens);
if macro_ident == "outof" {
if let Some(tp) = self.map.get(&id) {
self.modified = true;
*i = tp.clone();
}
}
}
}
}
let mut m = ModifyOutOf {
modified: true,
map,
};
// todo: check circle ref
while m.modified {
m.modified = false;
m.visit_item_fn_mut(func);
}
}

fn expand_transition_type_generics(
func: &mut ItemFn,
sig: &mut Signature,
func_block: Option<&mut Block>,
map: &HashMap<syn::Ident, (TypeTuple, Option<TypeTuple>)>,
) {
fn find_param_bounds<'a>(sig: &'a mut Signature, k: &Ident) -> &'a mut syn::TypeParam {
match sig
.generics
.params
.iter_mut()
.find(|x| match x {
syn::GenericParam::Type(tp) => &tp.ident == k,
_ => false,
})
.unwrap()
{
syn::GenericParam::Type(tp) => tp,
_ => panic!(),
}
}
let mut outof_map: HashMap<_, _> = Default::default();
for (k, (inputs, outputs)) in map {
let outputs = outputs.clone().unwrap_or_else(|| parse_quote!(()));
let iter_ref_input = inputs.elems.iter().filter_map(|x| match x {
Type::Reference(v) => Some(v),
_ => None,
});
fn find_param_bounds<'a>(func: &'a mut ItemFn, k: &Ident) -> &'a mut syn::TypeParam {
match func
.sig
.generics
.params
.iter_mut()
.find(|x| match x {
syn::GenericParam::Type(tp) => &tp.ident == k,
_ => false,
})
.unwrap()
{
syn::GenericParam::Type(tp) => tp,
_ => panic!(),
}
}
let after_take_type_id = &expand_one_generic_for_inputs(func, inputs, k);
let after_take_type_id = &expand_one_generic_for_inputs(sig, inputs, k);
// bounds for get as ref
let mut idx_counter = 0;
let appends = iter_ref_input
Expand All @@ -336,26 +306,59 @@ fn expand_transition_type_generics(
count!("__EXPAND_{after_take_type_id}_REF_IDX_{}", idx_counter),
Span::mixed_site(),
);
func.sig
.generics
.params
.push(parse_quote!(const #idx: usize));
sig.generics.params.push(parse_quote!(const #idx: usize));
parse_quote!(ComponentGet<#tp, #idx>)
})
.collect::<Vec<TypeParamBound>>();
find_param_bounds(func, after_take_type_id)
find_param_bounds(sig, after_take_type_id)
.bounds
.extend(appends);

// generate macro
generic_one_for_macro(func, k, inputs, &outputs, after_take_type_id);
// func_block.
if let Some(&mut ref mut func_block) = func_block {
generic_one_for_macro(func_block, k, inputs, &outputs, after_take_type_id);
}

outof_map.insert(
k.clone(),
parse_quote!(<#after_take_type_id as TupleMerge>::AfterMerge<(#outputs)>),
);
}
replace_outof_macro(func, &outof_map);

// replace outof![X]
struct ModifyOutOf<'a> {
modified: bool,
map: &'a HashMap<Ident, Type>,
}
impl<'a> syn::visit_mut::VisitMut for ModifyOutOf<'a> {
fn visit_type_mut(&mut self, i: &mut Type) {
syn::visit_mut::visit_type_mut(self, i);
if let Type::Macro(mc) = i {
let macro_ident = &mc.mac.path.segments.last().unwrap().ident;
let tokens = &mc.mac.tokens;
let id: Ident = parse_quote!(#tokens);
if macro_ident == "outof" {
if let Some(tp) = self.map.get(&id) {
self.modified = true;
*i = tp.clone();
}
}
}
}
}
let mut m = ModifyOutOf {
modified: true,
map: &mut outof_map,
};

while m.modified {
m.modified = false;
m.visit_signature_mut(sig);
if let Some(&mut ref mut block) = func_block {
m.visit_block_mut(block);
}
}
}

#[proc_macro_attribute]
Expand All @@ -365,21 +368,45 @@ pub fn system_wrap(_attr: TokenStream, item: TokenStream) -> TokenStream {
.into_iter()
.map(|x| (x.id, (x.inputs, x.outputs)))
.collect::<HashMap<_, _>>();
let mut func = parse_macro_input!(item as syn::ItemFn);
func.sig = transoform_impl_fnarg_to_generics(func.sig);
if let Some(mut func) = syn::parse::<syn::ItemFn>(item.clone()).ok() {
func.sig = transoform_impl_fnarg_to_generics(func.sig);

expand_transition_type_generics(&mut func, &map);
let _interface_name = func.sig.ident.clone();
let expanded = quote! {
#func
};
TokenStream::from(expanded)
expand_transition_type_generics(&mut func.sig, Some(&mut func.block), &map);
let _interface_name = func.sig.ident.clone();
let expanded = quote! {
#func
};
TokenStream::from(expanded)
} else if let Some(trait_item) = syn::parse::<syn::TraitItem>(item.clone()).ok() {
let mut func = match trait_item {
syn::TraitItem::Fn(func) => func,
_ => panic!("Not supported trait item"),
};
func.sig = transoform_impl_fnarg_to_generics(func.sig);
expand_transition_type_generics(&mut func.sig, func.default.as_mut(), &map);
TokenStream::from(quote! {#func})
} else if let Some(impl_item) = syn::parse::<syn::ImplItem>(item.clone()).ok() {
let mut func = match impl_item {
syn::ImplItem::Fn(func) => func,
_ => panic!("Not supported trait item"),
};
func.sig = transoform_impl_fnarg_to_generics(func.sig);
expand_transition_type_generics(&mut func.sig, Some(&mut func.block), &map);
TokenStream::from(quote! {#func})
} else {
panic!("cannot process");
}
}

#[proc_macro_attribute]
pub fn system(_attr: TokenStream, item: TokenStream) -> TokenStream {
let item_copy = item.clone();
let mut func = parse_macro_input!(item as syn::ItemFn);
let mut func = match syn::parse::<syn::ItemFn>(item) {
Ok(data) => data,
Err(err) => {
return TokenStream::from(err.to_compile_error());
}
};
let input_generic_id = Ident::new("_WRAPPER_ID", Span::mixed_site());
let mut input_tuple_type: TypeTuple = parse_quote!(());
func.sig = transoform_impl_fnarg_to_generics(func.sig);
Expand Down
2 changes: 1 addition & 1 deletion src/entity.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub trait TupleMerge {
pub trait TupleMerge: Sized {
type AfterMerge<U>
where
U: TupleExtend;
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod prelude {
pub use crate::component::{ComponentGet, ComponentPut};
pub use crate::entity::{TupleExtend, TupleMerge};
pub use crate::system::system;
pub use crate::system::system_wrap;

pub use crate::put;
pub use crate::take;
Expand Down
1 change: 1 addition & 0 deletions src/system.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
extern crate procs;
pub use procs::system;
pub use procs::system_wrap;

#[macro_export]
macro_rules! chain {
Expand Down

0 comments on commit 35e5dc2

Please sign in to comment.