@@ -3118,7 +3118,7 @@ MacroExpander::expand_decl_macro (Location invoc_locus,
3118
3118
3119
3119
// find matching arm
3120
3120
AST::MacroRule *matched_rule = nullptr ;
3121
- std::map<std::string, MatchedFragment> matched_fragments;
3121
+ std::map<std::string, std::vector< MatchedFragment> > matched_fragments;
3122
3122
for (auto &rule : rules_def.get_rules ())
3123
3123
{
3124
3124
sub_stack.push ();
@@ -3127,9 +3127,9 @@ MacroExpander::expand_decl_macro (Location invoc_locus,
3127
3127
3128
3128
if (did_match_rule)
3129
3129
{
3130
- for (auto &frag : matched_fragments)
3131
- rust_debug (" matched fragment: %s" ,
3132
- frag .second .as_string (). c_str ());
3130
+ for (auto &kv : matched_fragments)
3131
+ rust_debug (" [ fragment] : %s (%ld) " , kv. first . c_str () ,
3132
+ kv .second .size ());
3133
3133
3134
3134
matched_rule = &rule;
3135
3135
break ;
@@ -3535,9 +3535,8 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser,
3535
3535
3536
3536
// matched fragment get the offset in the token stream
3537
3537
size_t offs_end = source.get_offs ();
3538
- sub_stack.peek ().insert (
3539
- {fragment->get_ident (),
3540
- MatchedFragment (fragment->get_ident (), offs_begin, offs_end)});
3538
+ sub_stack.insert_fragment (
3539
+ MatchedFragment (fragment->get_ident (), offs_begin, offs_end));
3541
3540
}
3542
3541
break ;
3543
3542
@@ -3632,10 +3631,9 @@ MacroExpander::match_n_matches (
3632
3631
3633
3632
// matched fragment get the offset in the token stream
3634
3633
size_t offs_end = source.get_offs ();
3635
- sub_stack.peek ().insert (
3636
- {fragment->get_ident (),
3637
- MatchedFragment (fragment->get_ident (), offs_begin,
3638
- offs_end)});
3634
+ sub_stack.insert_fragment (
3635
+ MatchedFragment (fragment->get_ident (), offs_begin,
3636
+ offs_end));
3639
3637
}
3640
3638
break ;
3641
3639
@@ -3729,17 +3727,19 @@ MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser,
3729
3727
auto fragment = static_cast <AST::MacroMatchFragment *> (match.get ());
3730
3728
auto it = stack_map.find (fragment->get_ident ());
3731
3729
3732
- // If we can't find the fragment, but the result was valid, then it's
3733
- // a zero-matched fragment and we can insert it
3730
+ // If we can't find the fragment, but the result was valid, then
3731
+ // it's a zero-matched fragment and we can insert it
3734
3732
if (it == stack_map.end ())
3735
3733
{
3736
- stack_map.insert (
3737
- {fragment->get_ident (),
3738
- MatchedFragment::zero (fragment->get_ident ())});
3734
+ sub_stack.insert_fragment (
3735
+ MatchedFragment::zero (fragment->get_ident ()));
3739
3736
}
3740
3737
else
3741
3738
{
3742
- it->second .set_match_amount (match_amount);
3739
+ // We can just set the repetition amount on the first match
3740
+ // FIXME: Make this more ergonomic and similar to what we fetch
3741
+ // in `substitute_repetition`
3742
+ it->second [0 ].set_match_amount (match_amount);
3743
3743
}
3744
3744
}
3745
3745
}
@@ -3750,8 +3750,8 @@ MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser,
3750
3750
AST::ASTFragment
3751
3751
MacroExpander::transcribe_rule (
3752
3752
AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
3753
- std::map<std::string, MatchedFragment> &matched_fragments, bool semicolon ,
3754
- ContextType ctx)
3753
+ std::map<std::string, std::vector< MatchedFragment>> &matched_fragments,
3754
+ bool semicolon, ContextType ctx)
3755
3755
{
3756
3756
// we can manipulate the token tree to substitute the dollar identifiers so
3757
3757
// that when we call parse its already substituted for us
@@ -3765,10 +3765,10 @@ MacroExpander::transcribe_rule (
3765
3765
= substitute_tokens (invoc_stream, macro_rule_tokens, matched_fragments);
3766
3766
3767
3767
// // handy for debugging
3768
- for (auto &tok : substituted_tokens)
3769
- {
3770
- rust_debug (" tok: [%s]" , tok->as_string ().c_str ());
3771
- }
3768
+ // for (auto &tok : substituted_tokens)
3769
+ // {
3770
+ // rust_debug ("tok: [%s]", tok->as_string ().c_str ());
3771
+ // }
3772
3772
3773
3773
// parse it to an ASTFragment
3774
3774
MacroInvocLexer lex (std::move (substituted_tokens));
@@ -3888,7 +3888,7 @@ MacroExpander::transcribe_rule (
3888
3888
std::vector<std::unique_ptr<AST::Token>>
3889
3889
MacroExpander::substitute_metavar (
3890
3890
std::vector<std::unique_ptr<AST::Token>> &input,
3891
- std::map<std::string, MatchedFragment> &fragments,
3891
+ std::map<std::string, std::vector< MatchedFragment> > &fragments,
3892
3892
std::unique_ptr<AST::Token> &metavar)
3893
3893
{
3894
3894
auto metavar_name = metavar->get_str ();
@@ -3903,7 +3903,10 @@ MacroExpander::substitute_metavar (
3903
3903
else
3904
3904
{
3905
3905
// Replace
3906
- MatchedFragment &frag = it->second ;
3906
+ // We only care about the vector when expanding repetitions. Just access
3907
+ // the first element of the vector.
3908
+ // FIXME: Clean this up so it makes more sense
3909
+ auto &frag = it->second [0 ];
3907
3910
for (size_t offs = frag.token_offset_begin ; offs < frag.token_offset_end ;
3908
3911
offs++)
3909
3912
{
@@ -3919,8 +3922,8 @@ std::vector<std::unique_ptr<AST::Token>>
3919
3922
MacroExpander::substitute_repetition (
3920
3923
std::vector<std::unique_ptr<AST::Token>> &input,
3921
3924
std::vector<std::unique_ptr<AST::Token>> ¯o,
3922
- std::map<std::string, MatchedFragment> &fragments, size_t pattern_start ,
3923
- size_t pattern_end)
3925
+ std::map<std::string, std::vector< MatchedFragment>> &fragments,
3926
+ size_t pattern_start, size_t pattern_end)
3924
3927
{
3925
3928
rust_assert (pattern_end < macro.size ());
3926
3929
@@ -3929,10 +3932,6 @@ MacroExpander::substitute_repetition (
3929
3932
3930
3933
std::vector<std::unique_ptr<AST::Token>> expanded;
3931
3934
3932
- for (size_t i = pattern_start; i < pattern_end; i++)
3933
- rust_debug (" [repetition pattern]: %s" ,
3934
- macro.at (i)->as_string ().c_str ());
3935
-
3936
3935
// Find the first fragment and get the amount of repetitions that we should
3937
3936
// perform
3938
3937
size_t repeat_amount = 0 ;
@@ -3951,29 +3950,56 @@ MacroExpander::substitute_repetition (
3951
3950
// fragment), we can just error out. No need to paste the
3952
3951
// tokens as if nothing had happened.
3953
3952
rust_error_at (frag_token->get_locus (),
3954
- " metavar used in repetition does not exist" );
3953
+ " metavar %s used in repetition does not exist" ,
3954
+ frag_token->get_str ().c_str ());
3955
+ // FIXME:
3955
3956
return expanded;
3956
3957
}
3957
3958
3958
- repeat_amount = it->second .match_amount ;
3959
+ // FIXME: Refactor, ugly
3960
+ repeat_amount = it->second [0 ].match_amount ;
3959
3961
}
3960
3962
}
3961
3963
}
3962
3964
3965
+ rust_debug (" repetition amount to use: %lu" , repeat_amount);
3963
3966
std::vector<std::unique_ptr<AST::Token>> new_macro;
3964
- for (size_t tok_idx = pattern_start; tok_idx < pattern_end; tok_idx++)
3965
- {
3966
- new_macro.emplace_back (macro.at (tok_idx)->clone_token ());
3967
- rust_debug (" new macro token: %s" ,
3968
- macro.at (tok_idx)->as_string ().c_str ());
3969
- }
3970
3967
3971
- // FIXME: We have to be careful and not push the repetition token
3972
- auto new_tokens = substitute_tokens (input, new_macro, fragments);
3968
+ // We want to generate a "new macro" to substitute with. This new macro
3969
+ // should contain only the tokens inside the pattern
3970
+ for (size_t tok_idx = pattern_start; tok_idx < pattern_end; tok_idx++)
3971
+ new_macro.emplace_back (macro.at (tok_idx)->clone_token ());
3972
+
3973
+ // Then, we want to create a subset of the matches so that
3974
+ // `substitute_tokens()` can only see one fragment per metavar. Let's say we
3975
+ // have the following user input: (1 145 'h')
3976
+ // on the following match arm: ($($lit:literal)*)
3977
+ // which causes the following matches: { "lit": [1, 145, 'h'] }
3978
+ //
3979
+ // The pattern (new_macro) is `$lit:literal`
3980
+ // The first time we expand it, we want $lit to have the following token: 1
3981
+ // The second time, 145
3982
+ // The third and final time, 'h'
3983
+ //
3984
+ // In order to do so we must create "sub maps", which only contain parts of
3985
+ // the original matches
3986
+ // sub-maps: [ { "lit": 1 }, { "lit": 145 }, { "lit": 'h' } ]
3987
+ //
3988
+ // and give them to `substitute_tokens` one by one.
3973
3989
3974
- rust_debug (" repetition amount to use: %lu" , repeat_amount);
3975
3990
for (size_t i = 0 ; i < repeat_amount; i++)
3976
3991
{
3992
+ std::map<std::string, std::vector<MatchedFragment>> sub_map;
3993
+ for (auto &kv_match : fragments)
3994
+ {
3995
+ std::vector<MatchedFragment> sub_vec;
3996
+ sub_vec.emplace_back (kv_match.second [i]);
3997
+
3998
+ sub_map.insert ({kv_match.first , sub_vec});
3999
+ }
4000
+
4001
+ auto new_tokens = substitute_tokens (input, new_macro, sub_map);
4002
+
3977
4003
for (auto &new_token : new_tokens)
3978
4004
expanded.emplace_back (new_token->clone_token ());
3979
4005
}
@@ -3988,7 +4014,8 @@ std::pair<std::vector<std::unique_ptr<AST::Token>>, size_t>
3988
4014
MacroExpander::substitute_token (
3989
4015
std::vector<std::unique_ptr<AST::Token>> &input,
3990
4016
std::vector<std::unique_ptr<AST::Token>> ¯o,
3991
- std::map<std::string, MatchedFragment> &fragments, size_t token_idx)
4017
+ std::map<std::string, std::vector<MatchedFragment>> &fragments,
4018
+ size_t token_idx)
3992
4019
{
3993
4020
auto &token = macro.at (token_idx);
3994
4021
switch (token->get_id ())
@@ -4020,7 +4047,7 @@ MacroExpander::substitute_token (
4020
4047
return {
4021
4048
substitute_repetition (input, macro, fragments, pattern_start,
4022
4049
pattern_end),
4023
- // + 2 for the opening and closing parenthesis which are mandatory
4050
+ // + 2 for the opening and closing parentheses which are mandatory
4024
4051
// + 1 for the repetitor (+, *, ?)
4025
4052
pattern_end - pattern_start + 3 };
4026
4053
}
@@ -4044,7 +4071,7 @@ std::vector<std::unique_ptr<AST::Token>>
4044
4071
MacroExpander::substitute_tokens (
4045
4072
std::vector<std::unique_ptr<AST::Token>> &input,
4046
4073
std::vector<std::unique_ptr<AST::Token>> ¯o,
4047
- std::map<std::string, MatchedFragment> &fragments)
4074
+ std::map<std::string, std::vector< MatchedFragment> > &fragments)
4048
4075
{
4049
4076
std::vector<std::unique_ptr<AST::Token>> replaced_tokens;
4050
4077
0 commit comments