Let's simplify the testcase a little:
test!(Any(All(Base, Base), Base))
Let's say we're now transforming the top-level Any, and we're in this branch:
(Any($( $x:expr ),*)) => {
Any(&[ $(test!( $x )),* ])
};
So now our $x is a "list" of two expressions: All(Base, Base) and Base. What's important is that you've explicitely marked that the $x:expr should be parsed as a regular Rust expression, so All(Base, Base) is a regular function call! When you pass it to the test!( $x ), it's not passed as a stream of tokens, but rather as a one single "thing" – an expression.
Because of that, the nested test! doesn't see All ..., but rather a single expression, and executes the ($x:expr) => { $x }; arm.
To avoid this eager parsing as expression, you need to change the $e:expr into something like $($x:tt)*. Unfortunately, a comma that you split on is also considered a tt, so it won't work. You can further wrap everything in [] to avoid ambiguity, but it gets ugly to use (playground):
(Any($( [ $($x:tt)* ] ),*)) => {
Any(&[ $(test!( $($x)* )),* ])
};
If you assume that all your "sub-expressions" take the form of Ident(...) (so the Base is now written as Base()), you can get rid of [] using something like that (playground):
(Any($( $x:ident $y:tt ),*)) => {
Any(&[ $(test!( $x $y )),* ])
};
If you want a general solution for "parsing the stream of tokens as $($x:tt)* until a given delimiter" (in your case comma), there's a technique called "tt munching", explained somewhere in The Little Book of Rust Macros.
edit: Here's a playground with the final version (it's not the simplest one though).