(Or its equivalent Macros 2.0 syntax. expand_rules! could be used to match macro_rules! more closely and also allow a transition period to a decl_macro-accompanying expand)
Multiple patterns and recursion could also still be accomplished with some more syntax. Example:
I am not particularly worried about the specific syntax, of course, as long as there is a solution to stop avoiding writing one-time use intermediary macros. It would make the code more succinct and clear.
Certainly a crate with a macro like this would be a good prototype at least, if not a solution. I guess I'd need to use it for a while to see if it gets the job done. It can probably be expanded to accomplish multiple patterns, altho recursion would require a proc macro with a explicit "def_site()" Span. (altho if we're only talking one-level-deep recursion then naming the macro as recurse or something, it could be treated as a custom keyword. There's a feature like this in clojure where loops are done via recursion with a recur command)
So far I've found a couple limitations with the macro implementation. It cannot be used inside trait or type definitions, impls, and it cannot expand into a type. This is because none of those contexts accept a macro definition, it must be done outside. Ideally expand would be treated as a singular macro-call that could be used anywhere a macro could.
struct X;
impl X {
// will cause an error
expand! {
(x,y,z) in ($($f:ident)) {
fn $f() -> usize { 10 }
}
}
}
So far I've found a couple limitations with the macro implementation. It cannot be used inside trait or type definitions, impls, and it cannot expand into a type.
With regards to call site limitations, this can be dealt with by creating an attribute macro.
#[expand_inline]
impl X {
expand!(...) // syn macro call item
}
#[expand_inline]
type expand!(...) = expand!(...);
It would probably require some special handling in the second case as syn might not recognize the second expression as a type declaration, but these edge cases could be handled with a wrapper parser like:
pub enum Expandable<T> {
Expand(ExpandMacro),
Other(T)
}
impl Parser for Expandable<T> {
// test if expand!, if not try T, else error as "not T"
}
and then I guess some expressions for those edge cases would have to be copied from syn and augmented with Expandable<T>. The only issue with that approach is having to play catch-up with syn/Rust syntax.
I really like this idea btw. I would definitely use it some times (probably a lot).