diff options
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.cc | 31 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.h | 95 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-substitute-ctx.cc | 19 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-substitute-ctx.h | 4 |
4 files changed, 99 insertions, 50 deletions
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index 84a526c..0031679 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -3102,7 +3102,7 @@ MacroExpander::expand_decl_macro (Location invoc_locus, // find matching arm AST::MacroRule *matched_rule = nullptr; - std::map<std::string, std::vector<MatchedFragment>> matched_fragments; + std::map<std::string, MatchedFragmentContainer> matched_fragments; for (auto &rule : rules_def.get_rules ()) { sub_stack.push (); @@ -3111,9 +3111,10 @@ MacroExpander::expand_decl_macro (Location invoc_locus, if (did_match_rule) { - for (auto &kv : matched_fragments) - rust_debug ("[fragment]: %s (%ld)", kv.first.c_str (), - kv.second.size ()); + // Debugging + // for (auto &kv : matched_fragments) + // rust_debug ("[fragment]: %s (%ld)", kv.first.c_str (), + // kv.second.get_fragments ().size ()); matched_rule = &rule; break; @@ -3726,7 +3727,10 @@ MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser, rust_debug_loc (rep.get_match_locus (), "%s matched %lu times", res ? "successfully" : "unsuccessfully", match_amount); - // We can now set the amount to each fragment we matched in the substack + // We have to handle zero fragments differently: They will not have been + // "matched" but they are still valid and should be inserted as a special + // case. So we go through the stack map, and for every fragment which doesn't + // exist, insert a zero-matched fragment. auto &stack_map = sub_stack.peek (); for (auto &match : rep.get_matches ()) { @@ -3736,20 +3740,9 @@ MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser, auto fragment = static_cast<AST::MacroMatchFragment *> (match.get ()); auto it = stack_map.find (fragment->get_ident ()); - // If we can't find the fragment, but the result was valid, then - // it's a zero-matched fragment and we can insert it if (it == stack_map.end ()) - { - sub_stack.insert_fragment ( - MatchedFragment::zero (fragment->get_ident ())); - } - else - { - // We can just set the repetition amount on the first match - // FIXME: Make this more ergonomic and similar to what we fetch - // in `substitute_repetition` - it->second[0].set_match_amount (match_amount); - } + sub_stack.insert_matches (fragment->get_ident (), + MatchedFragmentContainer::zero ()); } } @@ -3759,7 +3752,7 @@ MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser, AST::ASTFragment MacroExpander::transcribe_rule ( AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree, - std::map<std::string, std::vector<MatchedFragment>> &matched_fragments, + std::map<std::string, MatchedFragmentContainer> &matched_fragments, bool semicolon, ContextType ctx) { // we can manipulate the token tree to substitute the dollar identifiers so diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h index 88d0e6e..dd48cbd 100644 --- a/gcc/rust/expand/rust-macro-expand.h +++ b/gcc/rust/expand/rust-macro-expand.h @@ -54,32 +54,78 @@ struct MatchedFragment std::string fragment_ident; size_t token_offset_begin; size_t token_offset_end; - size_t match_amount; MatchedFragment (std::string identifier, size_t token_offset_begin, - size_t token_offset_end, size_t match_amount = 1) + size_t token_offset_end) : fragment_ident (identifier), token_offset_begin (token_offset_begin), - token_offset_end (token_offset_end), match_amount (match_amount) + token_offset_end (token_offset_end) + {} + + /** + * Empty constructor for uninitialized fragments + */ + MatchedFragment () : MatchedFragment ("", 0, 0) {} + + std::string as_string () const + { + return fragment_ident + "=" + std::to_string (token_offset_begin) + ":" + + std::to_string (token_offset_end); + } +}; + +class MatchedFragmentContainer +{ +public: + MatchedFragmentContainer (std::vector<MatchedFragment> fragments) + : fragments (fragments) {} /** * Create a valid fragment matched zero times. This is useful for repetitions * which allow the absence of a fragment, such as * and ? */ - static MatchedFragment zero (std::string identifier) + static MatchedFragmentContainer zero () { - // We don't need offsets since there is "no match" - return MatchedFragment (identifier, 0, 0, 0); + return MatchedFragmentContainer ({}); } - std::string as_string () const + /** + * Create a valid fragment matched one time + */ + static MatchedFragmentContainer one (MatchedFragment fragment) { - return fragment_ident + "=" + std::to_string (token_offset_begin) + ":" - + std::to_string (token_offset_end) + " (matched " - + std::to_string (match_amount) + " times)"; + return MatchedFragmentContainer ({fragment}); } - void set_match_amount (size_t new_amount) { match_amount = new_amount; } + /** + * Add a matched fragment to the container + */ + void add_fragment (MatchedFragment fragment) + { + fragments.emplace_back (fragment); + } + + size_t get_match_amount () const { return fragments.size (); } + const std::vector<MatchedFragment> &get_fragments () const + { + return fragments; + } + // const std::string &get_fragment_name () const { return fragment_name; } + + bool is_single_fragment () const { return get_match_amount () == 1; } + const MatchedFragment get_single_fragment () const + { + rust_assert (get_match_amount () == 1); + + return fragments[0]; + } + +private: + /** + * Fragments matched `match_amount` times. This can be an empty vector + * in case having zero matches is allowed (i.e ? or * operators) + */ + std::vector<MatchedFragment> fragments; }; class SubstitutionScope @@ -89,18 +135,21 @@ public: void push () { stack.push_back ({}); } - std::map<std::string, std::vector<MatchedFragment>> pop () + std::map<std::string, MatchedFragmentContainer> pop () { auto top = stack.back (); stack.pop_back (); return top; } - std::map<std::string, std::vector<MatchedFragment>> &peek () + std::map<std::string, MatchedFragmentContainer> &peek () { return stack.back (); } + /** + * Insert a new matched fragment into the current substitution map + */ void insert_fragment (MatchedFragment fragment) { auto ¤t_map = stack.back (); @@ -108,19 +157,27 @@ public: if (it == current_map.end ()) { - auto new_frags = std::vector<MatchedFragment> (); - new_frags.emplace_back (fragment); - current_map.insert ({fragment.fragment_ident, new_frags}); + current_map.insert ( + {fragment.fragment_ident, MatchedFragmentContainer::one (fragment)}); } else { auto &frags = it->second; - frags.emplace_back (fragment); + frags.add_fragment (fragment); } } + void insert_matches (std::string key, MatchedFragmentContainer matches) + { + auto ¤t_map = stack.back (); + auto it = current_map.find (key); + rust_assert (it == current_map.end ()); + + current_map.insert ({key, matches}); + } + private: - std::vector<std::map<std::string, std::vector<MatchedFragment>>> stack; + std::vector<std::map<std::string, MatchedFragmentContainer>> stack; }; // Object used to store shared data (between functions) for macro expansion. @@ -174,7 +231,7 @@ struct MacroExpander AST::ASTFragment transcribe_rule ( AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree, - std::map<std::string, std::vector<MatchedFragment>> &matched_fragments, + std::map<std::string, MatchedFragmentContainer> &matched_fragments, bool semicolon, ContextType ctx); bool match_fragment (Parser<MacroInvocLexer> &parser, diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.cc b/gcc/rust/expand/rust-macro-substitute-ctx.cc index 61ab626..392a9fe 100644 --- a/gcc/rust/expand/rust-macro-substitute-ctx.cc +++ b/gcc/rust/expand/rust-macro-substitute-ctx.cc @@ -16,11 +16,9 @@ SubstituteCtx::substitute_metavar (std::unique_ptr<AST::Token> &metavar) } else { - // Replace // We only care about the vector when expanding repetitions. // Just access the first element of the vector. - // FIXME: Clean this up so it makes more sense - auto &frag = it->second[0]; + auto &frag = it->second.get_single_fragment (); for (size_t offs = frag.token_offset_begin; offs < frag.token_offset_end; offs++) { @@ -66,7 +64,7 @@ SubstituteCtx::substitute_repetition ( } // FIXME: Refactor, ugly - repeat_amount = it->second[0].match_amount; + repeat_amount = it->second.get_match_amount (); } } } @@ -98,19 +96,20 @@ SubstituteCtx::substitute_repetition ( for (size_t i = 0; i < repeat_amount; i++) { - std::map<std::string, std::vector<MatchedFragment>> sub_map; + std::map<std::string, MatchedFragmentContainer> sub_map; for (auto &kv_match : fragments) { - std::vector<MatchedFragment> sub_vec; + MatchedFragment sub_fragment; // FIXME: Hack: If a fragment is not repeated, how does it fit in the // submap? Do we really want to expand it? Is this normal behavior? - if (kv_match.second.size () == 1) - sub_vec.emplace_back (kv_match.second[0]); + if (kv_match.second.is_single_fragment ()) + sub_fragment = kv_match.second.get_single_fragment (); else - sub_vec.emplace_back (kv_match.second[i]); + sub_fragment = kv_match.second.get_fragments ()[i]; - sub_map.insert ({kv_match.first, sub_vec}); + sub_map.insert ( + {kv_match.first, MatchedFragmentContainer::one (sub_fragment)}); } auto substitute_context = SubstituteCtx (input, new_macro, sub_map); diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.h b/gcc/rust/expand/rust-macro-substitute-ctx.h index ed83926..e89f9d7 100644 --- a/gcc/rust/expand/rust-macro-substitute-ctx.h +++ b/gcc/rust/expand/rust-macro-substitute-ctx.h @@ -24,12 +24,12 @@ class SubstituteCtx { std::vector<std::unique_ptr<AST::Token>> &input; std::vector<std::unique_ptr<AST::Token>> ¯o; - std::map<std::string, std::vector<MatchedFragment>> &fragments; + std::map<std::string, MatchedFragmentContainer> &fragments; public: SubstituteCtx (std::vector<std::unique_ptr<AST::Token>> &input, std::vector<std::unique_ptr<AST::Token>> ¯o, - std::map<std::string, std::vector<MatchedFragment>> &fragments) + std::map<std::string, MatchedFragmentContainer> &fragments) : input (input), macro (macro), fragments (fragments) {} |