@@ -39,9 +39,6 @@ SubstituteCtx::substitute_repetition (
39
39
{
40
40
rust_assert (pattern_end < macro.size ());
41
41
42
- rust_debug (" pattern start: %lu" , pattern_start);
43
- rust_debug (" pattern end: %lu" , pattern_end);
44
-
45
42
std::vector<std::unique_ptr<AST::Token>> expanded;
46
43
47
44
// Find the first fragment and get the amount of repetitions that we should
@@ -154,19 +151,57 @@ SubstituteCtx::substitute_token (size_t token_idx)
154
151
// We need to parse up until the closing delimiter and expand this
155
152
// fragment->n times.
156
153
rust_debug (" expanding repetition" );
157
- std::vector<std::unique_ptr<AST::Token>> repetition_pattern;
154
+
155
+ // We're in a context where macro repetitions have already been
156
+ // parsed and validated: This means that
157
+ // 1/ There will be no delimiters as that is an error
158
+ // 2/ There are no fragment specifiers anymore, which prevents us
159
+ // from reusing parser functions.
160
+ //
161
+ // Repetition patterns are also special in that they cannot contain
162
+ // "rogue" delimiters: For example, this is invalid, as they are
163
+ // parsed as MacroMatches and must contain a correct amount of
164
+ // delimiters.
165
+ // `$($e:expr ) )`
166
+ // ^ rogue closing parenthesis
167
+ //
168
+ // With all of that in mind, we can simply skip ahead from one
169
+ // parenthesis to the other to find the pattern to expand. Of course,
170
+ // pairs of delimiters, including parentheses, are allowed.
171
+ // `$($e:expr ( ) )`
172
+ // Parentheses are the sole delimiter for which we need a special
173
+ // behavior since they delimit the repetition pattern
174
+
158
175
size_t pattern_start = token_idx + 1 ;
159
176
size_t pattern_end = pattern_start;
160
- for (; pattern_end < macro.size ()
161
- && macro.at (pattern_end)->get_id () != RIGHT_PAREN;
162
- pattern_end++)
163
- ;
177
+ auto parentheses_stack = 0 ;
178
+ for (size_t idx = pattern_start; idx < macro.size (); idx++)
179
+ {
180
+ if (macro.at (idx)->get_id () == LEFT_PAREN)
181
+ {
182
+ parentheses_stack++;
183
+ }
184
+ else if (macro.at (idx)->get_id () == RIGHT_PAREN)
185
+ {
186
+ if (parentheses_stack == 0 )
187
+ {
188
+ pattern_end = idx;
189
+ break ;
190
+ }
191
+ parentheses_stack--;
192
+ }
193
+ }
194
+
195
+ // Unreachable case, but let's make sure we don't ever run into it
196
+ rust_assert (pattern_end != pattern_start);
164
197
165
198
std::unique_ptr<AST::Token> separator_token = nullptr ;
166
- // FIXME: Can this go out of bounds?
167
- auto &post_pattern_token = macro.at (pattern_end + 1 );
168
- if (!is_rep_op (post_pattern_token))
169
- separator_token = post_pattern_token->clone_token ();
199
+ if (pattern_end + 1 <= macro.size ())
200
+ {
201
+ auto &post_pattern_token = macro.at (pattern_end + 1 );
202
+ if (!is_rep_op (post_pattern_token))
203
+ separator_token = post_pattern_token->clone_token ();
204
+ }
170
205
171
206
// Amount of tokens to skip
172
207
auto to_skip = 0 ;
@@ -178,15 +213,6 @@ SubstituteCtx::substitute_token (size_t token_idx)
178
213
if (separator_token)
179
214
to_skip += 1 ;
180
215
181
- // FIXME: This skips whitespaces... Is that okay??
182
- // FIXME: Is there any existing parsing function that allows us to
183
- // parse a macro pattern?
184
-
185
- // FIXME: Add error handling in the case we haven't found a matching
186
- // closing delimiter
187
-
188
- // FIXME: We need to parse the repetition token now
189
-
190
216
return {substitute_repetition (pattern_start, pattern_end,
191
217
std::move (separator_token)),
192
218
pattern_end - pattern_start + to_skip};
0 commit comments