Allow "(" and "!" to follow path fragment in macro


#1

I recently tried to write a pipe macro that looked something like this:

macro_rules! pipe {
    ($it:expr,) => { $it };
    ($it:expr) => { $it };
    ($it:expr, $f:path($args:tt) $rest:tt) => {
        pipe!($f($it, $args), $rest)
    };
    ($it:expr, $m:path!($args:tt) $rest:tt) => {
        let it = $it;
        pipe!($m!:(it, $args), $rest)
    };
}

which would allow you to write something like:

pipe!(item, foo(1,2) bar!("hi") a::b::baz())

that would expand to

a::b::baz(bar!(foo(item, 1, 2), "hi"))

but to my chagrin I discovered that neither “(” nor “!” are allowed to follow a path. I either have to use ident instead, which would require the user to use any functions (and macros in 2018 edition), and could possibly not work at all for some situations involving generics, or add one of the legal tokens between the path and the argument list, which isn’t very natural from the user’s point of view.

ex:

pipe!(item, foo|(1,2) bar|!("hi") a::b::baz|())

Is there a compelling reason not to allow ! or ( after a path? As far as I know, those aren’t legal characters in a path fragment.


#2

A path can contain parentheses and exclamation marks.

macro_rules! path {
    ($p:path) => {};
}

fn main() {
    path!(Fn(A) -> !);
}

#3

oh. It seems rather surprising to me that Fn(A) -> ! is a path. It seems like there should be a way to match against the name of a function in a function-call-like expression, if path isn’t the right typ for that what is?


#4

Well Fn(A)->! is a path because it’s actually sugar for (the unstable) std::ops::Fn<(A,), Output=!>.


#5

I’m afraid it’s spelled

proc-macro = true

[dependencies]
syn = { version = "0.14", features = ["full"] }

where I believe the best equivalent is ExprPath.