Skip to content

Commit ad390bd

Browse files
committed
Modify algorithm to allow repetitions after NTs.
1 parent 2356418 commit ad390bd

File tree

1 file changed

+27
-23
lines changed

1 file changed

+27
-23
lines changed

text/0550-macro-future-proofing.md

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -74,31 +74,35 @@ The algorithm for recognizing valid matchers `M` follows. Note that a matcher
7474
is merely a token tree. A "simple NT" is an NT without repetitions. That is,
7575
`$foo:ty` is a simple NT but `$($foo:ty)+` is not. `FOLLOW(NT)` is the set of
7676
allowed tokens for the given NT's fragment specifier, and is defined below.
77-
`F` is used for representing the separator in complex NTs. In `$($foo:ty),+`,
78-
`F` would be `,`, and for `$($foo:ty)+`, `F` would be `EOF`.
7977

80-
*input*: a token tree `M` representing a matcher and a token `F`
81-
82-
*output*: whether M is valid
83-
84-
For each token `T` in `M`:
85-
86-
1. If `T` is not an NT, continue.
87-
2. If `T` is a simple NT, look ahead to the next token `T'` in `M`. If
88-
`T'` is `EOF` or a close delimiter of a token tree, replace `T'` with
89-
`F`. If `T'` is in the set `FOLLOW(NT)`, `T'` is EOF, or `T'` is any close
90-
delimiter, continue. Otherwise, reject.
91-
3. Else, `T` is a complex NT.
92-
1. If `T` has the form `$(...)+` or `$(...)*`, run the algorithm on the
93-
contents with `F` set to the token following `T`. If it accepts,
94-
continue, else, reject.
95-
2. If `T` has the form `$(...)U+` or `$(...)U*` for some token `U`, run
96-
the algorithm on the contents with `F` set to `U`. If it accepts,
97-
check that the last token in the sequence can be followed by `F`. If
98-
so, accept. Otherwise, reject.
78+
`CHECK(M, F):` *input*: a sequence of tokens `M` and a set of tokens `F`; *output*: whether M is valid.
79+
1. If `M` is empty, accept.
80+
2. Set `t = HEAD(M)`
81+
3. If `t` is not an NT, skip to #6.
82+
4. If `t` is a simple NT:
83+
1. If `TAIL(M)` is empty, check that parameter `F` is a subset of `FOLLOW(t)`. If so, skip to #6, else, reject.
84+
2. Otherwise, find `G`, the set of possible successors of `t` in `M`: `G = LEADERS(TAIL(M))`
85+
Check that `G` is a subset of `FOLLOW(t)`. If so, skip to #6, else, reject.
86+
5. Else, `t` is a complex NT.
87+
1. If `t` has the form `$(Q)+` or `$(Q)*`, run `CHECK(Q, LEADERS(TAIL(M))`, i.e. with `F`
88+
being the set of all possible successors of `t` in `M`. If it accepts, continue, else, reject.
89+
2. If `t` has the form `$(Q)u+` or `$(Q)u*` for some token `u`, run
90+
`CHECK(Q, {u})`. If it accepts, continue, else, reject.
91+
6. Set `M = TAIL(M)`.
92+
93+
`LEADERS(S):` Returns the set of all possible tokens that may begin input sequence matched by `S`.
94+
1. If `S` is empty, return `{}`.
95+
2. Set `t = HEAD(S)`
96+
3. If `t` is not a complex NT, return `{t}`.
97+
4. If `t` is a complex NT:
98+
1. If `t` has the form `$(Q)+` or `$(Q)u+`, return `LEADERS(Q)`.
99+
2. If `t` has the form `$(Q)*` or `$(Q)u*`, return `LEADERS(Q) U LEADERS(TAIL(S))`.
100+
101+
`HEAD(M)` Returns the first token in sequence `M`.
102+
`TAIL(M)` Returns sequence `M` with the first token removed.
99103

100104
This algorithm should be run on every matcher in every `macro_rules`
101-
invocation, with `F` as `EOF`. If it rejects a matcher, an error should be
105+
invocation, with `F` as `{}`. If it rejects a matcher, an error should be
102106
emitted and compilation should not complete.
103107

104108
The current legal fragment specifiers are: `item`, `block`, `stmt`, `pat`,
@@ -115,7 +119,7 @@ The current legal fragment specifiers are: `item`, `block`, `stmt`, `pat`,
115119
- `FOLLOW(item)` = any token
116120
- `FOLLOW(meta)` = any token
117121

118-
(Note that close delimiters are valid following any NT.)
122+
(Note that open and close delimiters are valid following any NT.)
119123

120124
# Drawbacks
121125

0 commit comments

Comments
 (0)