Skip to content

Commit 08b7516

Browse files
macros: Parse macro patterns properly in repetition
Co-authored-by: philberty <philip.herron@embecosm.com>
1 parent 865b609 commit 08b7516

File tree

1 file changed

+47
-21
lines changed

1 file changed

+47
-21
lines changed

gcc/rust/expand/rust-macro-substitute-ctx.cc

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ SubstituteCtx::substitute_repetition (
3939
{
4040
rust_assert (pattern_end < macro.size ());
4141

42-
rust_debug ("pattern start: %lu", pattern_start);
43-
rust_debug ("pattern end: %lu", pattern_end);
44-
4542
std::vector<std::unique_ptr<AST::Token>> expanded;
4643

4744
// Find the first fragment and get the amount of repetitions that we should
@@ -154,19 +151,57 @@ SubstituteCtx::substitute_token (size_t token_idx)
154151
// We need to parse up until the closing delimiter and expand this
155152
// fragment->n times.
156153
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+
158175
size_t pattern_start = token_idx + 1;
159176
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);
164197

165198
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+
}
170205

171206
// Amount of tokens to skip
172207
auto to_skip = 0;
@@ -178,15 +213,6 @@ SubstituteCtx::substitute_token (size_t token_idx)
178213
if (separator_token)
179214
to_skip += 1;
180215

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-
190216
return {substitute_repetition (pattern_start, pattern_end,
191217
std::move (separator_token)),
192218
pattern_end - pattern_start + to_skip};

0 commit comments

Comments
 (0)