Skip to content

Commit b5f78be

Browse files
committed
feat momo: Support parsing pattern in params
So that we can slap it on more functions. Signed-off-by: Jiahao XU <[email protected]>
1 parent 86b8e50 commit b5f78be

File tree

2 files changed

+91
-46
lines changed

2 files changed

+91
-46
lines changed

gix-macros/src/lib.rs

Lines changed: 72 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ enum Conversion<'a> {
1313
}
1414

1515
impl<'a> Conversion<'a> {
16-
fn conversion_expr(&self, i: Ident) -> Expr {
16+
fn conversion_expr(&self, i: &Ident) -> Expr {
1717
match *self {
1818
Conversion::Into(_) => parse_quote!(#i.into()),
1919
Conversion::AsRef(_) => parse_quote!(#i.as_ref()),
@@ -23,12 +23,10 @@ impl<'a> Conversion<'a> {
2323
}
2424

2525
fn parse_bounded_type(ty: &Type) -> Option<Ident> {
26-
if let Type::Path(TypePath { qself: None, ref path }) = ty {
27-
if path.segments.len() == 1 {
28-
return Some(path.segments[0].ident.clone());
29-
}
26+
match &ty {
27+
Type::Path(TypePath { qself: None, path }) if path.segments.len() == 1 => Some(path.segments[0].ident.clone()),
28+
_ => None,
3029
}
31-
None
3230
}
3331

3432
fn parse_bounds(bounds: &Punctuated<TypeParamBound, Token![+]>) -> Option<Conversion> {
@@ -60,7 +58,6 @@ fn parse_generics(decl: &Signature) -> HashMap<Ident, Conversion<'_>> {
6058
if let GenericParam::Type(ref tp) = gp {
6159
if let Some(conversion) = parse_bounds(&tp.bounds) {
6260
ty_conversions.insert(tp.ident.clone(), conversion);
63-
continue;
6461
}
6562
}
6663
}
@@ -70,7 +67,6 @@ fn parse_generics(decl: &Signature) -> HashMap<Ident, Conversion<'_>> {
7067
if let Some(ident) = parse_bounded_type(&pt.bounded_ty) {
7168
if let Some(conversion) = parse_bounds(&pt.bounds) {
7269
ty_conversions.insert(ident, conversion);
73-
continue;
7470
}
7571
}
7672
}
@@ -79,51 +75,76 @@ fn parse_generics(decl: &Signature) -> HashMap<Ident, Conversion<'_>> {
7975
ty_conversions
8076
}
8177

82-
fn pat_to_ident(pat: &Pat) -> Ident {
83-
if let Pat::Ident(ref pat_ident) = *pat {
84-
return pat_ident.ident.clone();
85-
}
86-
unimplemented!("No non-ident patterns for now!");
87-
}
88-
89-
fn pat_to_expr(pat: &Pat) -> Expr {
90-
let ident = pat_to_ident(pat);
91-
parse_quote!(#ident)
92-
}
93-
9478
fn convert<'a>(
9579
inputs: &'a Punctuated<FnArg, Token![,]>,
9680
ty_conversions: &HashMap<Ident, Conversion<'a>>,
97-
) -> (Punctuated<Expr, Token![,]>, bool) {
81+
) -> (Punctuated<FnArg, Token![,]>, Punctuated<Expr, Token![,]>, bool) {
82+
let mut argtypes = Punctuated::new();
9883
let mut argexprs = Punctuated::new();
9984
let mut has_self = false;
100-
inputs.iter().for_each(|input| match input {
101-
FnArg::Receiver(..) => {
85+
inputs.iter().enumerate().for_each(|(i, input)| match input.clone() {
86+
FnArg::Receiver(receiver) => {
10287
has_self = true;
88+
argtypes.push(FnArg::Receiver(receiver));
10389
}
104-
FnArg::Typed(PatType { ref pat, ref ty, .. }) => match **ty {
105-
Type::ImplTrait(TypeImplTrait { ref bounds, .. }) => {
106-
if let Some(conv) = parse_bounds(bounds) {
107-
let ident = pat_to_ident(pat);
108-
argexprs.push(conv.conversion_expr(ident));
109-
} else {
110-
argexprs.push(pat_to_expr(pat));
90+
FnArg::Typed(mut pat_type) => {
91+
let pat_ident = match &mut *pat_type.pat {
92+
Pat::Ident(pat_ident) if pat_ident.by_ref.is_none() && pat_ident.subpat.is_none() => pat_ident,
93+
_ => {
94+
pat_type.pat = Box::new(Pat::Ident(PatIdent {
95+
ident: Ident::new(&format!("arg_{i}_gen_by_momo_"), proc_macro2::Span::call_site()),
96+
attrs: Default::default(),
97+
by_ref: None,
98+
mutability: None,
99+
subpat: None,
100+
}));
101+
102+
if let Pat::Ident(pat_ident) = &mut *pat_type.pat {
103+
pat_ident
104+
} else {
105+
panic!()
106+
}
111107
}
112-
}
113-
Type::Path(..) => {
114-
if let Some(conv) = parse_bounded_type(ty).and_then(|ident| ty_conversions.get(&ident)) {
115-
let ident = pat_to_ident(pat);
116-
argexprs.push(conv.conversion_expr(ident));
117-
} else {
118-
argexprs.push(pat_to_expr(pat));
108+
};
109+
// Outer function type argument pat does not need mut unless its
110+
// type is `impl AsMut`.
111+
pat_ident.mutability = None;
112+
113+
let ident = &pat_ident.ident;
114+
115+
let to_expr = || parse_quote!(#ident);
116+
117+
match *pat_type.ty {
118+
Type::ImplTrait(TypeImplTrait { ref bounds, .. }) => {
119+
if let Some(conv) = parse_bounds(bounds) {
120+
argexprs.push(conv.conversion_expr(ident));
121+
if let Conversion::AsMut(_) = conv {
122+
pat_ident.mutability = Some(Default::default());
123+
}
124+
} else {
125+
argexprs.push(to_expr());
126+
}
127+
}
128+
Type::Path(..) => {
129+
if let Some(conv) = parse_bounded_type(&pat_type.ty).and_then(|ident| ty_conversions.get(&ident)) {
130+
argexprs.push(conv.conversion_expr(ident));
131+
if let Conversion::AsMut(_) = conv {
132+
pat_ident.mutability = Some(Default::default());
133+
}
134+
} else {
135+
argexprs.push(to_expr());
136+
}
137+
}
138+
_ => {
139+
argexprs.push(to_expr());
119140
}
120141
}
121-
_ => {
122-
argexprs.push(pat_to_expr(pat));
123-
}
124-
},
142+
143+
// Now that mutability is decided, push the type into argtypes
144+
argtypes.push(FnArg::Typed(pat_type));
145+
}
125146
});
126-
(argexprs, has_self)
147+
(argtypes, argexprs, has_self)
127148
}
128149

129150
fn contains_self_type_path(path: &Path) -> bool {
@@ -199,7 +220,7 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
199220

200221
if let Item::Fn(item_fn) = fn_item {
201222
let ty_conversions = parse_generics(&item_fn.sig);
202-
let (argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions);
223+
let (argtypes, argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions);
203224

204225
let uses_self = has_self
205226
|| item_fn.sig.inputs.iter().any(has_self_type)
@@ -211,6 +232,11 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
211232
proc_macro2::Span::call_site(),
212233
);
213234

235+
let outer_sig = Signature {
236+
inputs: argtypes,
237+
..item_fn.sig.clone()
238+
};
239+
214240
let new_inner_item = Item::Fn(ItemFn {
215241
// Remove doc comment since they will increase compile-time and
216242
// also generates duplicate warning/error messages for the doc,
@@ -226,7 +252,7 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
226252
vis: Visibility::Inherited,
227253
sig: Signature {
228254
ident: inner_ident.clone(),
229-
..item_fn.sig.clone()
255+
..item_fn.sig
230256
},
231257
block: item_fn.block,
232258
});
@@ -243,7 +269,7 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
243269
let new_item = Item::Fn(ItemFn {
244270
attrs: item_fn.attrs,
245271
vis: item_fn.vis,
246-
sig: item_fn.sig,
272+
sig: outer_sig,
247273
block: if has_self {
248274
parse_quote!({ self.#inner_ident(#argexprs) })
249275
} else {
@@ -258,7 +284,7 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
258284
let new_item = Item::Fn(ItemFn {
259285
attrs: item_fn.attrs,
260286
vis: item_fn.vis,
261-
sig: item_fn.sig,
287+
sig: outer_sig,
262288
block: parse_quote!({
263289
#[allow(unused_mut)]
264290
#new_inner_item

gix-macros/tests/test.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,25 @@ impl TryInto<String> for S {
192192
}
193193
}
194194

195+
#[allow(unused)]
196+
#[momo]
197+
fn test_fn_pat<E>(
198+
a: impl Into<String>,
199+
b: impl AsRef<str>,
200+
mut c: impl AsMut<str>,
201+
d: impl TryInto<String, Error = E>,
202+
S(_g): S,
203+
) -> Result<(), E> {
204+
let mut s = a.into();
205+
s += b.as_ref();
206+
s += c.as_mut();
207+
s += &d.try_into()?;
208+
209+
drop(s);
210+
211+
Ok(())
212+
}
213+
195214
#[test]
196215
fn test_basic_fn() {
197216
assert_eq!(

0 commit comments

Comments
 (0)