]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Make MatchedFragmentContainer a tree-like structure
authorOwen Avery <powerboat9.gamer@gmail.com>
Thu, 1 Jun 2023 17:37:35 +0000 (13:37 -0400)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 16 Jan 2024 17:46:29 +0000 (18:46 +0100)
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>
gcc/rust/expand/rust-macro-expand.cc
gcc/rust/expand/rust-macro-expand.h
gcc/rust/expand/rust-macro-substitute-ctx.cc
gcc/rust/expand/rust-macro-substitute-ctx.h

index 225049ad2e4ced80db2650f9d28e275542a9aed5..d14b3b3806a7170a92b3397c3c1af91f9731f6ef 100644 (file)
@@ -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
index 1e3da0b21721fbfb62b294c919ea06c7a3f5e744..ce8d0f2c7d4a36e46c6730654b00cd50a0bbcddf 100644 (file)
@@ -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,
index 60e9b63de9470100b2bc6de8d82d539928b4f566..6eeb82b10314a26d59be3f6697d73ee73cbc7468 100644 (file)
@@ -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);
index dd49bb1ddca1cf1458e80ca28e6f675c38f36ac7..835f48a3d98479f14c205de5b769c3668cb70828 100644 (file)
@@ -24,7 +24,7 @@ class 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;
 
   /**
    * 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)
   {}