# Simplifying macro rules

I have a simple macro with three very similar rules:

``````macro_rules! c {

(\$exp:expr, for \$i:ident in \$iter:expr) => (
{
let mut r = vec![];
for \$i in \$iter {
r.push(\$exp);
}
r
}
);
(\$exp:expr, for \$i:ident in \$iter:expr, for \$i2:ident in \$iter2:expr) => (
{
let mut r = vec![];
for \$i2 in \$iter2 {
for \$i in \$iter {
r.push(\$exp);
}
}
r
}
);
(\$exp:expr, for \$i:ident in \$iter:expr, for \$i2:ident in \$iter2:expr, for \$i3:ident in \$iter3:expr) => (
{
let mut r = vec![];
for \$i in \$iter {
for \$i2 in \$iter2 {
for \$i3 in \$iter3 {
r.push(\$exp);
}
}
}
r
}
);

}
``````

Each rule differs from the others by the number of `for \$i:ident in \$iter:exp` being matched. The logic is similarly the same.

Is there a way to simplify these rules into one using repetition patterns such as `\$(...)*` or `\$(...)+` and still be able to express the nested looping in the macro logic?

In my attempts I kept getting an error `error: variable 'i' is still repeating at this depth`.

1 Like

I don’t know if this is what you would consider “simpler” but a recursive macro would work, where it builds up the layers of `for` loops one at a time.

``````macro_rules! c {
(\$e:expr \$(, for \$i:ident in \$iter:expr)+) => {{
let mut r = vec![];
c!(@loop r.push(\$e) \$(, for \$i in \$iter)*);
r
}};
(@loop \$e:expr, for \$i:ident in \$iter:expr \$(, for \$j:ident in \$rest:expr)*) => {
c!(@loop for \$i in \$iter { \$e } \$(, for \$j in \$rest)*);
};
(@loop \$e:expr) => {
\$e
};
}
``````
2 Likes

Thanks @dtolnay, this seems to do the trick 