[gcc r14-7685] gccrs: Make MatchedFragmentContainer a tree-like structure

Arthur Cohen cohenarthur@gcc.gnu.org
Tue Jan 16 17:53:37 GMT 2024


https://gcc.gnu.org/g:f1dbdb63dc78378aa91fb9e8bc1ff9401ef81c42

commit r14-7685-gf1dbdb63dc78378aa91fb9e8bc1ff9401ef81c42
Author: Owen Avery <powerboat9.gamer@gmail.com>
Date:   Thu Jun 1 13:37:35 2023 -0400

    gccrs: Make MatchedFragmentContainer a tree-like structure
    
    gcc/rust/ChangeLog:
    
            * expand/rust-macro-expand.cc
            (MacroExpander::expand_decl_macro):
            Use pointers/smart pointers to refer to MatchedFragmentContainer instances.
            (MacroExpander::transcribe_rule): Likewise.
            (MatchedFragmentContainer::get_single_fragment): New implementation.
            (MatchedFragmentContainer::get_fragments): Likewise.
            (MatchedFragmentContainer::add_fragment): Likewise.
            (MatchedFragmentContainer::zero): Likewise.
            (MatchedFragmentContainer::metavar): Likewise.
            * expand/rust-macro-expand.h
            (class MatchedFragmentContainer): Make abstract.
            (class MatchedFragmentContainerMetaVar): New.
            (class MatchedFragmentContainerRepetition): New.
            (class SubstitutionScope):
            Use pointers/smart pointers to refer to MatchedFragmentContainer instances.
            (MacroExpander::transcribe_rule): Likewise.
            * expand/rust-macro-substitute-ctx.cc
            (SubstituteCtx::substitute_metavar): Likewise.
            (SubstituteCtx::check_repetition_amount): Likewise.
            (SubstituteCtx::substitute_repetition): Likewise.
            * expand/rust-macro-substitute-ctx.h
            (class SubstituteCtx): Likewise.
    
    Signed-off-by: Owen Avery <powerboat9.gamer@gmail.com>

Diff:
---
 gcc/rust/expand/rust-macro-expand.cc         |  54 +++++++++++-
 gcc/rust/expand/rust-macro-expand.h          | 123 ++++++++++++++++-----------
 gcc/rust/expand/rust-macro-substitute-ctx.cc |  37 +++-----
 gcc/rust/expand/rust-macro-substitute-ctx.h  |   4 +-
 4 files changed, 140 insertions(+), 78 deletions(-)

diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index 225049ad2e4..d14b3b3806a 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -78,7 +78,8 @@ MacroExpander::expand_decl_macro (Location invoc_locus,
 
   // find matching arm
   AST::MacroRule *matched_rule = nullptr;
-  std::map<std::string, MatchedFragmentContainer> matched_fragments;
+  std::map<std::string, std::unique_ptr<MatchedFragmentContainer>>
+    matched_fragments;
   for (auto &rule : rules_def.get_rules ())
     {
       sub_stack.push ();
@@ -109,8 +110,13 @@ MacroExpander::expand_decl_macro (Location invoc_locus,
       return AST::Fragment::create_error ();
     }
 
-  return transcribe_rule (*matched_rule, invoc_token_tree, matched_fragments,
-			  semicolon, peek_context ());
+  std::map<std::string, MatchedFragmentContainer *> matched_fragments_ptr;
+
+  for (auto &ent : matched_fragments)
+    matched_fragments_ptr.emplace (ent.first, ent.second.get ());
+
+  return transcribe_rule (*matched_rule, invoc_token_tree,
+			  matched_fragments_ptr, semicolon, peek_context ());
 }
 
 void
@@ -961,7 +967,7 @@ tokens_to_str (std::vector<std::unique_ptr<AST::Token>> &tokens)
 AST::Fragment
 MacroExpander::transcribe_rule (
   AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
-  std::map<std::string, MatchedFragmentContainer> &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
@@ -1129,4 +1135,44 @@ MacroExpander::parse_proc_macro_output (ProcMacro::TokenStream ts)
     return {nodes, std::vector<std::unique_ptr<AST::Token>> ()};
 }
 
+MatchedFragment &
+MatchedFragmentContainer::get_single_fragment ()
+{
+  rust_assert (is_single_fragment ());
+
+  return static_cast<MatchedFragmentContainerMetaVar &> (*this).get_fragment ();
+}
+
+std::vector<std::unique_ptr<MatchedFragmentContainer>> &
+MatchedFragmentContainer::get_fragments ()
+{
+  rust_assert (!is_single_fragment ());
+
+  return static_cast<MatchedFragmentContainerRepetition &> (*this)
+    .get_fragments ();
+}
+
+void
+MatchedFragmentContainer::add_fragment (MatchedFragment fragment)
+{
+  rust_assert (!is_single_fragment ());
+
+  return static_cast<MatchedFragmentContainerRepetition &> (*this)
+    .add_fragment (fragment);
+}
+
+std::unique_ptr<MatchedFragmentContainer>
+MatchedFragmentContainer::zero ()
+{
+  return std::unique_ptr<MatchedFragmentContainer> (
+    new MatchedFragmentContainerRepetition ());
+}
+
+std::unique_ptr<MatchedFragmentContainer>
+MatchedFragmentContainer::metavar (MatchedFragment fragment)
+{
+  return std::unique_ptr<MatchedFragmentContainer> (
+    new MatchedFragmentContainerMetaVar (fragment));
+}
+
 } // namespace Rust
diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h
index 1e3da0b2172..ce8d0f2c7d4 100644
--- a/gcc/rust/expand/rust-macro-expand.h
+++ b/gcc/rust/expand/rust-macro-expand.h
@@ -90,66 +90,88 @@ public:
     Repetition,
   };
 
-  MatchedFragmentContainer (std::vector<MatchedFragment> fragments,
-			    Kind kind = Kind::Repetition)
-    : fragments (fragments), kind (kind)
-  {}
+  virtual Kind get_kind () const = 0;
+
+  virtual std::string as_string () const = 0;
 
   /**
    * Create a valid fragment matched zero times. This is useful for repetitions
    * which allow the absence of a fragment, such as * and ?
    */
-  static MatchedFragmentContainer zero ()
-  {
-    return MatchedFragmentContainer ({});
-  }
+  static std::unique_ptr<MatchedFragmentContainer> zero ();
 
   /**
    * Create a valid fragment matched one time
    */
-  static MatchedFragmentContainer metavar (MatchedFragment fragment)
-  {
-    return MatchedFragmentContainer ({fragment}, Kind::MetaVar);
-  }
+  static std::unique_ptr<MatchedFragmentContainer>
+  metavar (MatchedFragment fragment);
 
   /**
    * Add a matched fragment to the container
    */
-  void add_fragment (MatchedFragment fragment)
-  {
-    rust_assert (!is_single_fragment ());
+  void add_fragment (MatchedFragment fragment);
 
-    fragments.emplace_back (fragment);
-  }
+  // const std::string &get_fragment_name () const { return fragment_name; }
+
+  bool is_single_fragment () const { return get_kind () == Kind::MetaVar; }
+
+  MatchedFragment &get_single_fragment ();
+
+  std::vector<std::unique_ptr<MatchedFragmentContainer>> &get_fragments ();
+};
+
+class MatchedFragmentContainerMetaVar : public MatchedFragmentContainer
+{
+  MatchedFragment fragment;
+
+public:
+  MatchedFragmentContainerMetaVar (const MatchedFragment &fragment)
+    : fragment (fragment)
+  {}
+
+  MatchedFragment &get_fragment () { return fragment; }
+
+  virtual Kind get_kind () const { return Kind::MetaVar; }
+
+  virtual std::string as_string () const { return fragment.as_string (); }
+};
+
+class MatchedFragmentContainerRepetition : public MatchedFragmentContainer
+{
+  std::vector<std::unique_ptr<MatchedFragmentContainer>> fragments;
+
+public:
+  MatchedFragmentContainerRepetition () {}
 
   size_t get_match_amount () const { return fragments.size (); }
-  const std::vector<MatchedFragment> &get_fragments () const
+
+  std::vector<std::unique_ptr<MatchedFragmentContainer>> &get_fragments ()
   {
     return fragments;
   }
-  // const std::string &get_fragment_name () const { return fragment_name; }
 
-  bool is_single_fragment () const
+  /**
+   * Add a matched fragment to the container
+   */
+  void add_fragment (MatchedFragment fragment)
   {
-    return get_match_amount () == 1 && kind == Kind::MetaVar;
+    fragments.emplace_back (metavar (fragment));
   }
 
-  const MatchedFragment get_single_fragment () const
-  {
-    rust_assert (is_single_fragment ());
+  virtual Kind get_kind () const { return Kind::Repetition; }
 
-    return fragments[0];
+  virtual std::string as_string () const
+  {
+    std::string acc = "[";
+    for (size_t i = 0; i < fragments.size (); i++)
+      {
+	if (i)
+	  acc += " ";
+	acc += fragments[i]->as_string ();
+      }
+    acc += "]";
+    return acc;
   }
-
-  const Kind &get_kind () const { return kind; }
-
-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;
-  Kind kind;
 };
 
 class SubstitutionScope
@@ -159,14 +181,14 @@ public:
 
   void push () { stack.push_back ({}); }
 
-  std::map<std::string, MatchedFragmentContainer> pop ()
+  std::map<std::string, std::unique_ptr<MatchedFragmentContainer>> pop ()
   {
-    auto top = stack.back ();
+    auto top = std::move (stack.back ());
     stack.pop_back ();
     return top;
   }
 
-  std::map<std::string, MatchedFragmentContainer> &peek ()
+  std::map<std::string, std::unique_ptr<MatchedFragmentContainer>> &peek ()
   {
     return stack.back ();
   }
@@ -180,8 +202,8 @@ public:
     auto it = current_map.find (fragment.fragment_ident);
 
     if (it == current_map.end ())
-      current_map.insert ({fragment.fragment_ident,
-			   MatchedFragmentContainer::metavar (fragment)});
+      current_map.emplace (fragment.fragment_ident,
+			   MatchedFragmentContainer::metavar (fragment));
     else
       gcc_unreachable ();
   }
@@ -196,23 +218,28 @@ public:
     auto it = current_map.find (fragment.fragment_ident);
 
     if (it == current_map.end ())
-      current_map.insert (
-	{fragment.fragment_ident, MatchedFragmentContainer ({fragment})});
-    else
-      it->second.add_fragment (fragment);
+      it = current_map
+	     .emplace (fragment.fragment_ident,
+		       std::unique_ptr<MatchedFragmentContainer> (
+			 new MatchedFragmentContainerRepetition ()))
+	     .first;
+
+    it->second->add_fragment (fragment);
   }
 
-  void insert_matches (std::string key, MatchedFragmentContainer matches)
+  void insert_matches (std::string key,
+		       std::unique_ptr<MatchedFragmentContainer> matches)
   {
     auto &current_map = stack.back ();
     auto it = current_map.find (key);
     rust_assert (it == current_map.end ());
 
-    current_map.insert ({key, matches});
+    current_map.emplace (std::move (key), std::move (matches));
   }
 
 private:
-  std::vector<std::map<std::string, MatchedFragmentContainer>> stack;
+  std::vector<std::map<std::string, std::unique_ptr<MatchedFragmentContainer>>>
+    stack;
 };
 
 // Object used to store shared data (between functions) for macro expansion.
@@ -269,7 +296,7 @@ struct MacroExpander
 
   AST::Fragment transcribe_rule (
     AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
-    std::map<std::string, MatchedFragmentContainer> &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 60e9b63de94..6eeb82b1031 100644
--- a/gcc/rust/expand/rust-macro-substitute-ctx.cc
+++ b/gcc/rust/expand/rust-macro-substitute-ctx.cc
@@ -45,7 +45,7 @@ SubstituteCtx::substitute_metavar (
       // currently expanding a repetition metavar - not a simple metavar. We
       // need to error out and inform the user.
       // Associated test case for an example: compile/macro-issue1224.rs
-      if (it->second.get_match_amount () != 1)
+      if (!it->second->is_single_fragment ())
 	{
 	  rust_error_at (metavar->get_locus (),
 			 "metavariable is still repeating at this depth");
@@ -58,7 +58,7 @@ SubstituteCtx::substitute_metavar (
 
       // We only care about the vector when expanding repetitions.
       // Just access the first element of the vector.
-      auto &frag = it->second.get_single_fragment ();
+      auto &frag = it->second->get_single_fragment ();
       for (size_t offs = frag.token_offset_begin; offs < frag.token_offset_end;
 	   offs++)
 	{
@@ -100,11 +100,14 @@ SubstituteCtx::check_repetition_amount (size_t pattern_start,
 		  is_valid = false;
 		}
 
-	      auto &fragment = it->second;
+	      auto &fragment = *it->second;
 
 	      if (!fragment.is_single_fragment ())
 		{
-		  size_t repeat_amount = fragment.get_match_amount ();
+		  auto &fragment_rep
+		    = static_cast<MatchedFragmentContainerRepetition &> (
+		      fragment);
+		  size_t repeat_amount = fragment_rep.get_match_amount ();
 		  if (!first_fragment_found)
 		    {
 		      first_fragment_found = true;
@@ -170,32 +173,18 @@ SubstituteCtx::substitute_repetition (
 
   for (size_t i = 0; i < repeat_amount; i++)
     {
-      std::map<std::string, MatchedFragmentContainer> sub_map;
+      std::map<std::string, MatchedFragmentContainer *> sub_map;
       for (auto &kv_match : fragments)
 	{
-	  MatchedFragment sub_fragment;
-
+	  if (kv_match.second->is_single_fragment ())
+	    sub_map.emplace (kv_match.first, kv_match.second);
 	  // Hack: A repeating meta variable might not be present in the new
 	  // macro. Don't include this match if the fragment doesn't have enough
 	  // items, as check_repetition_amount should prevent repetition amount
 	  // mismatches anyway.
-	  bool is_used = true;
-
-	  // 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.is_single_fragment ())
-	    sub_fragment = kv_match.second.get_single_fragment ();
-	  else
-	    {
-	      if (kv_match.second.get_fragments ().size () > i)
-		sub_fragment = kv_match.second.get_fragments ().at (i);
-	      else
-		is_used = false;
-	    }
-
-	  if (is_used)
-	    sub_map.insert ({kv_match.first,
-			     MatchedFragmentContainer::metavar (sub_fragment)});
+	  else if (kv_match.second->get_fragments ().size () > i)
+	    sub_map.emplace (kv_match.first,
+			     kv_match.second->get_fragments ().at (i).get ());
 	}
 
       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 dd49bb1ddca..835f48a3d98 100644
--- a/gcc/rust/expand/rust-macro-substitute-ctx.h
+++ b/gcc/rust/expand/rust-macro-substitute-ctx.h
@@ -24,7 +24,7 @@ class SubstituteCtx
 {
   std::vector<std::unique_ptr<AST::Token>> &input;
   std::vector<std::unique_ptr<AST::Token>> ¯o;
-  std::map<std::string, MatchedFragmentContainer> &fragments;
+  std::map<std::string, MatchedFragmentContainer *> &fragments;
 
   /**
    * Find the repetition amount to use when expanding a repetition, and
@@ -40,7 +40,7 @@ class SubstituteCtx
 public:
   SubstituteCtx (std::vector<std::unique_ptr<AST::Token>> &input,
 		 std::vector<std::unique_ptr<AST::Token>> &macro,
-		 std::map<std::string, MatchedFragmentContainer> &fragments)
+		 std::map<std::string, MatchedFragmentContainer *> &fragments)
     : input (input), macro (macro), fragments (fragments)
   {}


More information about the Gcc-cvs mailing list