-
-
Notifications
You must be signed in to change notification settings - Fork 6
Procedural macro reimplementation of quote!
to resolve longstanding limitations
#8
Comments
I do agree we need a procedural macro alternative. However I discovered this trick a few years ago and created a lisp-style language using it. macro_rules! tt_eq {
// remove the extra block to run this in item-context
($a:tt $b:tt) => {{
macro_rules! __tt_eq_internal {
($a) => { true };
($b) => { false };
}
__tt_eq_internal!($b)
}}
}
macro_rules! tt_match {
// wrap the result in extra block to run in expression-context
($left:tt in $( ($($right:tt)|*) => $result:tt );+ $(; _ => $default:tt)* $(;)* ) => {
macro_rules! __tt_match_internal {
$( $( ($right) => $result; )* )+
$( ($left) => $default )*
}
__tt_match_internal!{ $left }
}
}
tt_match!{ c in
(a | b | c | d) => {
struct Foo;
};
(e) => {
struct Bar;
};
_ => {
struct Baz;
}
}
fn main() {
let _foo = Foo;
assert!(tt_eq!(a a));
assert!(!tt_eq!(a b));
} |
I created the repository proc-quote in order to work on this new library. |
Besides the already existent I created this because sometimes I feel the need to call a function or access an inner element of a struct inside With @dtolnay what are your thoughts on this feature? |
I strongly prefer not to have that feature and I believe the library is worse off for providing it. Some existing discussion in dtolnay/quote#88 and numerous other threads on the quote repo. |
I'm sorry, it was silly on my part not to check if this had been proposed before. It seemed such a simple and straightforward addition that I felt compelled to add it. Thanks for pointing me to the existing discussion. I will remove this functionality from my crate. |
Thanks! To be clear, plenty of people think I am wrong on this. Let me know once your existing TODO items are either implemented or have issues filed to track them, and the crate has been published to crates.io, and then we can close out this thread and mark it off the list. :) |
For the record, this is implementation of the (unstable) It's very simple, but it could be used as a starting point for someone else. However, it can't just be copied verbatim to a proc macro, as it uses the unstable |
It is up! https://crates.io/crates/proc-quote :) |
Nicely done! I will go ahead and close this thread. I added a link to your crate in the readme. If you'd like to explore ways to address the other limitation (involving non-repeating variables inside of a repeating block) I would be interested to see what you come up with. |
If the only thing blocking this in quote is the incorrect assumption that macro_rules! tt_match {
($left:tt in
$( ($($right:tt)|*) => $cb:tt!$cba:tt );+
$(; _ => $de:tt!$fault:tt)?
$(;)?
) => {{
macro_rules! __tt_match_internal {
$( $( ($right) => { $cb!$cba }; )* )+
$( ($left) => { $de!$fault } )*
}
__tt_match_internal!{ $left }
}}
}
macro_rules! uniq {
(($($xs:tt)*) () $cb:tt!($($tt:tt)*)) => {
$cb!( $($tt:tt)* $($xs)* )
};
(($($xs:tt)*) ($y:tt $($ys:tt)*) $cb:tt!$cba:tt) => {
tt_match!{
$y in
($($xs)|*) => uniq!(($($xs)*) ($($ys)*) $cb!$cba);
_ => uniq!(($($xs)* $y) ($($ys)*) $cb!$cba);
}
};
}
fn main() {
println!("{}", uniq!(() (a a b c c) stringify!()));
} |
Thanks! The relevant performance comparison would be between proc-quote vs quote-with-uniq-trick, not quote without uniq trick.. |
@dtolnay Naturally. I already removed the note for speed as the remaining limitation regarding mixing non-repeating with repeating args remains unresolved and may be the selling point for proc-quote that this would have been. |
Originally filed as dtolnay/quote#82 but I would like this to begin its life as a separate library.
The current macro_rules-based quote macro has the limitation that duplicate interpolations inside of a repetition are not allowed.
quote! { #a #a }
works butquote! { #(#a #a)* }
does not work. The reason boils down to macro_rules macros having no way to determine that two identifiers are equal.Some background on the quote macro:
quote! { #a #a }
expands to:quote! { #(#a)* }
expands to:quote! { #(#a #b)* }
expands to:quote! { #(#a #a)* }
expands to:That last expansion is illegal so the quote invocation fails.
In an implementation as a procedural macro we would want that invocation to expand instead as:
The text was updated successfully, but these errors were encountered: