Skip to content

Commit

Permalink
✨ Support auto! expressions' expand.
Browse files Browse the repository at this point in the history
  • Loading branch information
langyo committed Dec 28, 2024
1 parent 421029a commit d81e794
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 33 deletions.
55 changes: 41 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ pub fn auto(input: TokenStream) -> TokenStream {

let macro_ident = Ident::new(&format!("__auto_{}", input.ident), input.ident.span());
match body {
AutoMacrosType::Struct(items) => {
AutoMacrosType::Struct {
items,
expand_exprs,
} => {
let list = items
.iter()
.map(|(key, value)| {
Expand All @@ -161,19 +164,33 @@ pub fn auto(input: TokenStream) -> TokenStream {
})
.collect::<Vec<_>>();

quote! {
#ident {
#( #list ),*
if let Some(expand_exprs) = expand_exprs {
quote! {
#ident {
#( #list ),*,
..#expand_exprs
}
}
.into()
} else {
quote! {
#ident {
#( #list ),*
}
}
.into()
}
.into()
}

AutoMacrosType::EnumEmpty(key) => quote! {
AutoMacrosType::EnumEmpty { key } => quote! {
#ident::#key
}
.into(),
AutoMacrosType::EnumStruct((key, items)) => {
AutoMacrosType::EnumStruct {
key,
items,
expand_exprs,
} => {
let list = items
.iter()
.map(|(item_key, value)| {
Expand All @@ -183,14 +200,24 @@ pub fn auto(input: TokenStream) -> TokenStream {
})
.collect::<Vec<_>>();

quote! {
#ident::#key {
#( #list ),*
if let Some(expand_exprs) = expand_exprs {
quote! {
#ident::#key {
#( #list ),*,
..#expand_exprs
}
}
.into()
} else {
quote! {
#ident::#key {
#( #list ),*
}
}
.into()
}
.into()
}
AutoMacrosType::EnumTuple((key, items)) => {
AutoMacrosType::EnumTuple { key, items } => {
if items.len() == 1 {
let first_item = items.first().expect("Failed to get first item");
quote! {
Expand All @@ -214,12 +241,12 @@ pub fn auto(input: TokenStream) -> TokenStream {
.into()
}
}
AutoMacrosType::EnumSinglePath((key, next_key)) => quote! {
AutoMacrosType::EnumSinglePath { key, next_key } => quote! {
#ident::#key(#macro_ident!(#key 0 #next_key))
}
.into(),

AutoMacrosType::Value(items) => {
AutoMacrosType::Value { items } => {
if items.len() == 1 {
let first_item = items.first().expect("Failed to get first item");
quote! {
Expand Down
92 changes: 75 additions & 17 deletions src/tools/auto_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,29 @@ use syn::{

#[derive(Debug, Clone)]
pub enum AutoMacrosType {
Struct(Vec<(Ident, TokenStream)>),
EnumEmpty(Ident),
EnumStruct((Ident, Vec<(Ident, TokenStream)>)),
EnumTuple((Ident, Vec<TokenStream>)),
EnumSinglePath((Ident, TokenStream)),
Value(Vec<Expr>),
Struct {
items: Vec<(Ident, TokenStream)>,
expand_exprs: Option<Expr>,
},
EnumEmpty {
key: Ident,
},
EnumStruct {
key: Ident,
items: Vec<(Ident, TokenStream)>,
expand_exprs: Option<Expr>,
},
EnumTuple {
key: Ident,
items: Vec<TokenStream>,
},
EnumSinglePath {
key: Ident,
next_key: TokenStream,
},
Value {
items: Vec<Expr>,
},
}

#[derive(Debug, Clone)]
Expand All @@ -31,16 +48,33 @@ impl Parse for AutoMacros {
let content;
braced!(content in input);

let mut tokens = vec![];
let mut items = vec![];
let mut expand_exprs = None;

while !content.is_empty() {
if content.peek(Token![..]) {
if expand_exprs.is_some() {
return Err(content.error("Expand expression is already set"));
}

content.parse::<Token![..]>()?;
let value: Expr = content.parse()?;
expand_exprs = Some(value);

if !content.is_empty() {
return Err(content.error("Expand expression should be the last"));
}
break;
}

let key: Ident = content.parse()?;
content.parse::<Token![:]>()?;

if content.peek(token::Brace) {
let inner_content;
braced!(inner_content in content);
let inner_content: TokenStream = inner_content.parse()?;
tokens.push((
items.push((
key,
quote! {
{ #inner_content }
Expand All @@ -50,7 +84,7 @@ impl Parse for AutoMacros {
let inner_content;
bracketed!(inner_content in content);
let inner_content: TokenStream = inner_content.parse()?;
tokens.push((
items.push((
key,
quote! {
[ #inner_content ]
Expand All @@ -60,15 +94,15 @@ impl Parse for AutoMacros {
let inner_content;
parenthesized!(inner_content in content);
let inner_content: TokenStream = inner_content.parse()?;
tokens.push((
items.push((
key,
quote! {
( #inner_content )
},
));
} else {
let value: Expr = content.parse()?;
tokens.push((
items.push((
key,
quote! {
#value
Expand All @@ -83,7 +117,10 @@ impl Parse for AutoMacros {

Ok(AutoMacros {
ident,
body: AutoMacrosType::Struct(tokens),
body: AutoMacrosType::Struct {
items,
expand_exprs,
},
})
} else if input.peek(Token![::]) {
// Sth::...
Expand All @@ -98,7 +135,24 @@ impl Parse for AutoMacros {
braced!(content in input);

let mut items = vec![];
let mut expand_exprs = None;

while !content.is_empty() {
if content.peek(Token![..]) {
if expand_exprs.is_some() {
return Err(content.error("Expand expression is already set"));
}

content.parse::<Token![..]>()?;
let value: Expr = content.parse()?;
expand_exprs = Some(value);

if !content.is_empty() {
return Err(content.error("Expand expression should be the last"));
}
break;
}

let key: Ident = content.parse()?;
content.parse::<Token![:]>()?;

Expand Down Expand Up @@ -149,7 +203,11 @@ impl Parse for AutoMacros {

Ok(AutoMacros {
ident,
body: AutoMacrosType::EnumStruct((key, items)),
body: AutoMacrosType::EnumStruct {
key,
items,
expand_exprs,
},
})
} else if input.peek(token::Paren) {
// Sth::Sth(key, ...)
Expand All @@ -171,7 +229,7 @@ impl Parse for AutoMacros {

Ok(AutoMacros {
ident,
body: AutoMacrosType::EnumTuple((key, items)),
body: AutoMacrosType::EnumTuple { key, items },
})
} else if input.peek(Token![::]) {
// Sth::Sth::Sth
Expand All @@ -181,14 +239,14 @@ impl Parse for AutoMacros {

Ok(AutoMacros {
ident,
body: AutoMacrosType::EnumSinglePath((key, next_key)),
body: AutoMacrosType::EnumSinglePath { key, next_key },
})
} else {
// Sth::Sth

Ok(AutoMacros {
ident,
body: AutoMacrosType::EnumEmpty(key),
body: AutoMacrosType::EnumEmpty { key },
})
}
} else {
Expand All @@ -209,7 +267,7 @@ impl Parse for AutoMacros {

Ok(AutoMacros {
ident,
body: AutoMacrosType::Value(items),
body: AutoMacrosType::Value { items },
})
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/auto_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn basic_struct() {
c: std::f64::consts::PI,
d: {
f: 24,
..Default::default(),
..Default::default()
}
});
assert_eq!(obj.a, "hello");
Expand Down Expand Up @@ -162,7 +162,7 @@ fn default_struct_auto() {
c: std::f64::consts::PI,
d: {
f: 24,
..Default::default(),
..Default::default()
}
});
assert_eq!(obj.a, "hello");
Expand Down

0 comments on commit d81e794

Please sign in to comment.