Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upnested macros don't allow repetitions in binding patterns #35853
Comments
This comment has been minimized.
This comment has been minimized.
|
It appears to be non-trivial to distinguish expansions and binding patterns, because they can both appear in the same position, like this: macro_rules! foo {
( $( $some:tt )* ) => {
macro_rules! bar {
( $( $some )* $( foo )* $( $any:tt bar )* ) => { $( $any )* };
}
};
}Note that These distinctions seem to be very delicate and subtle and prone to error. I wonder if it would be better to have explicit escaping (as suggested in #6994 (comment)). PS: And something like this should be detected as invalid: macro_rules! foo {
( $( $some:tt )* ) => {
macro_rules! bar {
( $( $some foo $any:tt )* ) => { $( $any )* };
}
};
} |
This comment has been minimized.
This comment has been minimized.
|
And another possible problem, this time on the most inner expansion macro_rules! foo {
( $( $some:tt )* ) => {
macro_rules! bar {
( $( $any:tt )* ) => { $( $some $any )* };
}
};
}I have the feeling, that it's not possible to address all these questions without new syntax. Other opinions? |
This comment has been minimized.
This comment has been minimized.
|
If matching and expansion syntax were different, this would not be a problem. @nrc fyi - maybe relevant for macros 2.0? |
This comment has been minimized.
This comment has been minimized.
|
cc @jseyfried |
This comment has been minimized.
This comment has been minimized.
|
This error also occurs for macro definitions inside macro invocations, not just other definitions: macro_rules! foo {
($($a:tt)*) => ($($a)*)
}
foo! {
macro_rules! bar { // same as foo
($($a:tt)*) => ($($a)*)
}
}Definitely no ambiguity in this case. |
This comment has been minimized.
This comment has been minimized.
tobia
commented
Jan 14, 2017
•
|
@colin-kiegel How would that help? Consider this silly example: macro_rules! make_println {
($name:ident, $fmt:expr) => {
macro_rules! $name {
($($args:expr),*) => { // (1)
println!($fmt, $($args),*); // (2)
}
}
};
}If matching and expansion syntax were different, then (1) wouldn't trigger an error, but the "args" part in (2) would still do, because it's intentionally written to look like expansion syntax, except it's not intended for the macro being parsed. I can only see two solutions:
Or:
macro_rules! make_println {
($name:ident, $fmt:expr) => {
macro_rules! $name {
($$($$args:expr),*) => { // (1)
println!($fmt, $$($$args),*); // (2)
}
}
};
}I would go with 2. because it's good to have explicit error messages about common mistakes and misplacing repeater variables is a common mistake. If someone wants to write a (macro-generating)ⁿ-macro, using 2ⁿ dollars instead of one seems like a small price to pay. Backslashes in string constants already work this way. (I've seen up to 8 consecutive backslashes in real-world code; 4 is not uncommon; 2 are everywhere.) |
Mark-Simulacrum
added
the
A-macros
label
May 19, 2017
Mark-Simulacrum
added
the
C-feature-request
label
Jul 26, 2017
TimNN
referenced this issue
Feb 6, 2018
Closed
Why I can not attempted to repeat an expression #48037
Nemo157
referenced this issue
Apr 11, 2018
Merged
Generate different storage types macros based on features #62
This comment has been minimized.
This comment has been minimized.
jjpe
commented
Aug 25, 2018
|
I have found myself today wishing this was an implemented feature in Rust. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
For the second problem (@tobia), there exists a workaround, though it kinda sucks: pass in the dollar sign as a token, so you get kind of a "private escape sequence". macro_rules! make_println {
($d:tt $name:ident, $fmt:expr) => {
macro_rules! $name {
($d($d args:expr),*) => { // (1)
println!($fmt, $d($d args),*); // (2)
}
}
};
}
make_println!($ dbg, "{:?}");
You can wrap this to avoid making the ugliness visible at the top level: macro_rules! with_dollar_sign {
($($body:tt)*) => {
macro_rules! __with_dollar_sign { $($body)* }
__with_dollar_sign!($);
}
}
macro_rules! make_println {
($name:ident, $fmt:expr) => {
with_dollar_sign! {
($d:tt) => {
macro_rules! $name {
($d($d args:expr),*) => { // (1)
println!($fmt, $d($d args),*); // (2)
}
}
}
}
};
}
make_println!(my_dbg, "{:?}");
fn main() {
my_dbg!(42);
} |
This comment has been minimized.
This comment has been minimized.
|
It can be passed from inside the macro with ($) See https://github.com/bluss/defmac/blob/6886f04d412e1ee2b6d4d240feb51e51a9caf808/src/lib.rs |
This comment has been minimized.
This comment has been minimized.
Avi-D-coder
commented
Dec 10, 2018
•
|
Does @tobia's option 2 need an RFC or just a pull request? |
This comment has been minimized.
This comment has been minimized.
|
I think that would need an RFC. I edited my comment above to include @bluss' workaround. |
This comment has been minimized.
This comment has been minimized.
|
@durka didn't you teach me the workaround? :) |
colin-kiegel commentedAug 20, 2016
Example:
https://play.rust-lang.org/?gist=f7355a6828cc2af68cc17f280a982ad8&version=beta&backtrace=0
results in:
Note
If the repetition is removed, i.e. the offending part
( $( $any:tt )* ) => { $( $any )* };is changed to( $any:tt ) => { $any };, the error disappears on rustc 1.12+ due to the fix of #6994: macros should be parsed more lazily. I find it a bit inconsistent, that nested macros now support binding patterns, but no repetitions.Meta