@@ -3882,7 +3882,6 @@ MacroExpander::substitute_metavar (
3882
3882
{
3883
3883
auto metavar_name = metavar->get_str ();
3884
3884
3885
- rust_debug (" expanding metavar: %s" , metavar_name.c_str ());
3886
3885
std::vector<std::unique_ptr<AST::Token>> expanded;
3887
3886
auto it = fragments.find (metavar_name);
3888
3887
if (it == fragments.end ())
@@ -3908,40 +3907,95 @@ MacroExpander::substitute_metavar (
3908
3907
std::vector<std::unique_ptr<AST::Token>>
3909
3908
MacroExpander::substitute_repetition (
3910
3909
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>> ¯o,
3911
+ std::map<std::string, MatchedFragment> &fragments, size_t pattern_start,
3912
+ size_t pattern_end)
3913
3913
{
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
+ }
3919
3946
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;
3921
3974
}
3922
3975
3923
3976
std::pair<std::vector<std::unique_ptr<AST::Token>>, size_t >
3924
3977
MacroExpander::substitute_token (
3925
- std::vector<std::unique_ptr<AST::Token>> ¯o,
3926
3978
std::vector<std::unique_ptr<AST::Token>> &input,
3979
+ std::vector<std::unique_ptr<AST::Token>> ¯o,
3927
3980
std::map<std::string, MatchedFragment> &fragments, size_t token_idx)
3928
3981
{
3929
3982
auto &token = macro.at (token_idx);
3930
3983
switch (token->get_id ())
3931
3984
{
3932
3985
case IDENTIFIER:
3933
- rust_debug (" expanding metavar" );
3986
+ rust_debug (" expanding metavar: %s " , token-> get_str (). c_str () );
3934
3987
return {substitute_metavar (input, fragments, token), 1 };
3935
3988
case LEFT_PAREN: {
3936
3989
// We need to parse up until the closing delimiter and expand this
3937
3990
// fragment->n times.
3938
3991
rust_debug (" expanding repetition" );
3939
3992
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
+ ;
3945
3999
3946
4000
// FIXME: This skips whitespaces... Is that okay??
3947
4001
// FIXME: Is there any existing parsing function that allows us to parse
@@ -3953,9 +4007,11 @@ MacroExpander::substitute_token (
3953
4007
// FIXME: We need to parse the repetition token now
3954
4008
3955
4009
return {
3956
- substitute_repetition (input, fragments, repetition_pattern),
4010
+ substitute_repetition (input, macro, fragments, pattern_start,
4011
+ pattern_end),
3957
4012
// + 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 };
3959
4015
}
3960
4016
// TODO: We need to check if the $ was alone. In that case, do
3961
4017
// not error out: Simply act as if there was an empty identifier
@@ -3996,7 +4052,7 @@ MacroExpander::substitute_tokens (
3996
4052
{
3997
4053
// Aaaaah, if only we had C++17 :)
3998
4054
// 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 );
4000
4056
auto expanded = std::move (p.first );
4001
4057
auto tok_to_skip = p.second ;
4002
4058
0 commit comments