Skip to content

Commit ded1aca

Browse files
committed
substitute_repetition: Substitute repetitions properly
1 parent 143aad6 commit ded1aca

File tree

2 files changed

+81
-23
lines changed

2 files changed

+81
-23
lines changed

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

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3882,7 +3882,6 @@ MacroExpander::substitute_metavar (
38823882
{
38833883
auto metavar_name = metavar->get_str ();
38843884

3885-
rust_debug ("expanding metavar: %s", metavar_name.c_str ());
38863885
std::vector<std::unique_ptr<AST::Token>> expanded;
38873886
auto it = fragments.find (metavar_name);
38883887
if (it == fragments.end ())
@@ -3908,40 +3907,95 @@ MacroExpander::substitute_metavar (
39083907
std::vector<std::unique_ptr<AST::Token>>
39093908
MacroExpander::substitute_repetition (
39103909
std::vector<std::unique_ptr<AST::Token>> &input,
3911-
std::map<std::string, MatchedFragment> &fragments,
3912-
std::vector<std::unique_ptr<AST::Token>> &pattern)
3910+
std::vector<std::unique_ptr<AST::Token>> &macro,
3911+
std::map<std::string, MatchedFragment> &fragments, size_t pattern_start,
3912+
size_t pattern_end)
39133913
{
3914-
// If the repetition is not anything we know (ie no declared metavars, or
3915-
// metavars which aren't present in the fragment), we can just error out. No
3916-
// need to paste the tokens as if nothing had happened.
3917-
for (auto &token : pattern)
3918-
rust_debug ("[repetition pattern]: %s", token->as_string ().c_str ());
3914+
rust_assert (pattern_end < macro.size ());
3915+
3916+
rust_debug ("pattern start: %lu", pattern_start);
3917+
rust_debug ("pattern end: %lu", pattern_end);
3918+
3919+
std::vector<std::unique_ptr<AST::Token>> expanded;
3920+
3921+
for (size_t i = pattern_start; i < pattern_end; i++)
3922+
rust_debug ("[repetition pattern]: %s",
3923+
macro.at (i)->as_string ().c_str ());
3924+
3925+
// Find the first fragment and get the amount of repetitions that we should
3926+
// perform
3927+
size_t repeat_amount = 0;
3928+
for (size_t i = pattern_start; i < pattern_end; i++)
3929+
{
3930+
if (macro.at (i)->get_id () == DOLLAR_SIGN)
3931+
{
3932+
auto &frag_token = macro.at (i + 1);
3933+
if (frag_token->get_id () == IDENTIFIER)
3934+
{
3935+
auto it = fragments.find (frag_token->get_str ());
3936+
if (it == fragments.end ())
3937+
{
3938+
// If the repetition is not anything we know (ie no declared
3939+
// metavars, or metavars which aren't present in the
3940+
// fragment), we can just error out. No need to paste the
3941+
// tokens as if nothing had happened.
3942+
rust_error_at (frag_token->get_locus (),
3943+
"metavar used in repetition does not exist");
3944+
return expanded;
3945+
}
39193946

3920-
return std::vector<std::unique_ptr<AST::Token>> ();
3947+
repeat_amount = it->second.match_amount;
3948+
}
3949+
}
3950+
}
3951+
3952+
std::vector<std::unique_ptr<AST::Token>> new_macro;
3953+
for (size_t tok_idx = pattern_start; tok_idx < pattern_end; tok_idx++)
3954+
{
3955+
new_macro.emplace_back (macro.at (tok_idx)->clone_token ());
3956+
rust_debug ("new macro token: %s",
3957+
macro.at (tok_idx)->as_string ().c_str ());
3958+
}
3959+
3960+
// FIXME: We have to be careful and not push the repetition token
3961+
auto new_tokens = substitute_tokens (input, new_macro, fragments);
3962+
3963+
rust_debug ("repetition amount to use: %lu", repeat_amount);
3964+
for (size_t i = 0; i < repeat_amount; i++)
3965+
{
3966+
for (auto &new_token : new_tokens)
3967+
expanded.emplace_back (new_token->clone_token ());
3968+
}
3969+
3970+
// FIXME: We also need to make sure that all subsequent fragments
3971+
// contain the same amount of repetitions as the first one
3972+
3973+
return expanded;
39213974
}
39223975

39233976
std::pair<std::vector<std::unique_ptr<AST::Token>>, size_t>
39243977
MacroExpander::substitute_token (
3925-
std::vector<std::unique_ptr<AST::Token>> &macro,
39263978
std::vector<std::unique_ptr<AST::Token>> &input,
3979+
std::vector<std::unique_ptr<AST::Token>> &macro,
39273980
std::map<std::string, MatchedFragment> &fragments, size_t token_idx)
39283981
{
39293982
auto &token = macro.at (token_idx);
39303983
switch (token->get_id ())
39313984
{
39323985
case IDENTIFIER:
3933-
rust_debug ("expanding metavar");
3986+
rust_debug ("expanding metavar: %s", token->get_str ().c_str ());
39343987
return {substitute_metavar (input, fragments, token), 1};
39353988
case LEFT_PAREN: {
39363989
// We need to parse up until the closing delimiter and expand this
39373990
// fragment->n times.
39383991
rust_debug ("expanding repetition");
39393992
std::vector<std::unique_ptr<AST::Token>> repetition_pattern;
3940-
for (size_t rep_idx = token_idx + 1;
3941-
rep_idx < macro.size ()
3942-
&& macro.at (rep_idx)->get_id () != RIGHT_PAREN;
3943-
rep_idx++)
3944-
repetition_pattern.emplace_back (macro.at (rep_idx)->clone_token ());
3993+
size_t pattern_start = token_idx + 1;
3994+
size_t pattern_end = pattern_start;
3995+
for (; pattern_end < macro.size ()
3996+
&& macro.at (pattern_end)->get_id () != RIGHT_PAREN;
3997+
pattern_end++)
3998+
;
39453999

39464000
// FIXME: This skips whitespaces... Is that okay??
39474001
// FIXME: Is there any existing parsing function that allows us to parse
@@ -3953,9 +4007,11 @@ MacroExpander::substitute_token (
39534007
// FIXME: We need to parse the repetition token now
39544008

39554009
return {
3956-
substitute_repetition (input, fragments, repetition_pattern),
4010+
substitute_repetition (input, macro, fragments, pattern_start,
4011+
pattern_end),
39574012
// + 2 for the opening and closing parenthesis which are mandatory
3958-
repetition_pattern.size () + 2};
4013+
// + 1 for the repetitor (+, *, ?)
4014+
pattern_end - pattern_start + 3};
39594015
}
39604016
// TODO: We need to check if the $ was alone. In that case, do
39614017
// not error out: Simply act as if there was an empty identifier
@@ -3996,7 +4052,7 @@ MacroExpander::substitute_tokens (
39964052
{
39974053
// Aaaaah, if only we had C++17 :)
39984054
// auto [expanded, tok_to_skip] = ...
3999-
auto p = substitute_token (macro, input, fragments, i + 1);
4055+
auto p = substitute_token (input, macro, fragments, i + 1);
40004056
auto expanded = std::move (p.first);
40014057
auto tok_to_skip = p.second;
40024058

gcc/rust/expand/rust-macro-expand.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,14 +204,16 @@ struct MacroExpander
204204
*
205205
* @param input Tokens given to the transcribing context
206206
* @param fragments Fragments given to the macro substitution
207-
* @param repetition Set of tokens to substitute and replace
207+
* @param pattern_start Start index of the pattern tokens
208+
* @param pattern_end Index Amount of tokens in the pattern
208209
*
209210
* @return A vector containing the repeated pattern
210211
*/
211212
static std::vector<std::unique_ptr<AST::Token>>
212213
substitute_repetition (std::vector<std::unique_ptr<AST::Token>> &input,
214+
std::vector<std::unique_ptr<AST::Token>> &macro,
213215
std::map<std::string, MatchedFragment> &fragments,
214-
std::vector<std::unique_ptr<AST::Token>> &pattern);
216+
size_t pattern_start, size_t pattern_end);
215217

216218
/**
217219
* Substitute a given token by its appropriate representation
@@ -228,8 +230,8 @@ struct MacroExpander
228230
* ahead of the input to avoid mis-substitutions
229231
*/
230232
static std::pair<std::vector<std::unique_ptr<AST::Token>>, size_t>
231-
substitute_token (std::vector<std::unique_ptr<AST::Token>> &macro,
232-
std::vector<std::unique_ptr<AST::Token>> &input,
233+
substitute_token (std::vector<std::unique_ptr<AST::Token>> &input,
234+
std::vector<std::unique_ptr<AST::Token>> &macro,
233235
std::map<std::string, MatchedFragment> &fragments,
234236
size_t token_idx);
235237

0 commit comments

Comments
 (0)