As I understand it, there is a high incentive to have macros be
tokenizable and parseable without needing to expand them - it's a
necessarily if we ever want importable macros (Can't resolve macro
imports if you can't parse the source).
Hence the requirement to have explicit brackets and the need to have
properly nested and paired brackets in them.
On 10/17/2013 06:30 AM, Oren Ben-Kiki wrote:
In general I'd favor anything that would help with
https://github.com/mozilla/rust/issues/9358 - that is, allow more
eDSL-ish macros. Writing `foo!!(...) { ... }` has the cost of the
extra `!` but that really isn't too bad.
That said, I wonder why do macro invocations require the outer set of
parenthesis? Since a macro is expressed in terms of parser rules
(expressions, identifiers, tokens, etc.), isn't it unambiguous to
allow macros to be invoked without the outer `()`? E.g.:
macro_rules! foo (
(bar: $expr :<: baz: $expr) => ...,
)
Today, one would use it as in `f(foo!(1 :<: 2), 3)`. But suppose one
could somehow indicate the outer `()` were never to be used for this
macro (say writing `syntax_rules!` instead of `macro_rules!`, or by
some other extension of the `macro_rules!` notation), then parsing
`f(foo! 1 :<: 2, 3)` would be unambiguous - assuming we (1) strictly
use greedy parsing of $expr etc. and (2) always expand a later macro
before parsing and expanding earlier macros, where later and earlier
are in source text order. This strategy makes irrelevant the issue of
determining the nesting of such macros while "doing the right thing"
with a simple deterministic rule.
This would probably be more complex to implement than the multiple-`!`
proposal, but would allow for more generic patterns. For example,
allowing to omit the outer `()` would allow invoking `my_match!
pattern => action`; if I understand it correctly, using `!!` would
only allow for writing `my_match!! pattern action`.
At any rate, this is just as an idea - like I said, I'd like anything
that would allow me to write `foo!(...) { ... }` (or `foo!!(...) { ...
}`, or something along these lines). Writing `foo!(..., { ... })` just
seems ugly to me...
On Thu, Oct 17, 2013 at 2:10 AM, Marvin Löbel <[email protected]
<mailto:[email protected]>> wrote:
Hello! I was thinking a bit about macros, and I had an idea for a
kind of syntactic sugar that might be useful to have. I also
posted this to the issue tracker at
https://github.com/mozilla/rust/issues/9894.
# Current situation
Right now, rust knows about two kinds of macro invocation:
IDENT!(...)
IDENT! IDENT (...)
The latter one is just used by `macro_rules!` right now, and seems
kinda out of place because of that.
Additionally, just being restricted to `IDENT!(...)` means that,
while you can define macros just fine, the resulting invocation
syntax often looks a bit weird because of the need for the outer
`()` pair.
For example, if you want to write some kind of custom `match`
macro you ideally want a syntax like `macro! EXPR { CASES... }`,
but in practice are forced to decide between redundant, deeply
nested brackets or weird syntax if you want to reduce the brackets:
~~~
my_match!(
foo().bar().baz() {
case 1 => ...
case 2 => ...
...
}
)
my_match!(foo().bar().baz() cases:
case 1 => ...
case 2 => ...
...
)
~~~
# Proposal
We can't just allow macros to accept different syntax like `IDENT!
EXPR ( ... )`, because it would create ambiguity in the parser,
but it occurred to me that we _can_ provide syntactic sugar for
transforming 'nicer looking' variants into the regular
`IDENT!(...)` syntax.
Basically, I'm thinking of leveraging the bang in a macro
invocation to annotate how many following bracket pairs to group
into one regular macro invocation:
~~~
IDENT!! (...) (...) => desugaring => IDENT!((...) (...))
IDENT!!! (...) (...) (...) => desugaring => IDENT!((...) (...) (...))
... etc
~~~
The number of bangs could become confusing fast, but I don't
expect that macros with more than two bracket groups are going to
be common. And because it would just be sugar, you could always
write it as the regular form.
# Advantages
There are a number of advantages I see with this proposal:
1. The two macro invocation forms can be folded into one:
~~~
IDENT!(...) => IDENT!(...)
IDENT! IDENT (...) => IDENT!! (IDENT) (...) == IDENT!((IDENT)
(...))
~~~
2. Custom syntax can become nicer looking, especially for control
structures.
Looking at the `my_match` example:
~~~
my_match!! (foo().bar().baz()) {
case 1 => ...
case 2 => ...
...
}
~~~
... which looks more natural than any the two options outlined
above.
3. It's pure syntactic sugar, which means it's easy to implement
and reason about.
All `libsyntax` needs to do is to consume a list of
bracket-counted token trees
equal to the number of bangs, and introduce an artificial outer
bracket pair if
the number is higher than one.
4. It's just invocation sugar, which means there is no difference
between defining a
macro that uses this vs one that doesn't - you just declare
them all assuming the
explicit outer `()` pair.
# Potential issues
The possible issues I can see with this are confusing error
messages if the number of bangs is wrong, and uncertainty about
which brackets belong to a macro invocation and which are regular
rust code if their contents become big and/or their number become
high.
However, in theory rust might be able to provide good error
messages for the first one, because if the macro name is right
you'd get an `No rules expected this ...` error, and there could
be some heuristics for recognizing cases where the user has do
add/remove bangs to match the macro definition.
And the second one can likely be managed by syntax highlighting,
and by the usual convention of not abusing the syntax to the point
where it becomes illegible.
# Backwards compatibility
Adding this sugar would be backwards compatible because it doesn't
change any existing macro syntax, however if `IDENT! IDENT (...)`
ends up obsolete through this, that would break existing uses of
`macro_rules!` - but macros are behind a feature flag anyway at
this point, so it wouldn't matter as much.
_______________________________________________
Rust-dev mailing list
[email protected] <mailto:[email protected]>
https://mail.mozilla.org/listinfo/rust-dev
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev