aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc31
-rw-r--r--gcc/rust/expand/rust-macro-expand.h95
-rw-r--r--gcc/rust/expand/rust-macro-substitute-ctx.cc19
-rw-r--r--gcc/rust/expand/rust-macro-substitute-ctx.h4
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 fab7f56..4c6e897 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -3190,7 +3190,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 ();
@@ -3199,9 +3199,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;
@@ -3825,7 +3826,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 ())
{
@@ -3835,20 +3839,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 ());
}
}
@@ -3925,7 +3918,7 @@ transcribe_expression (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 3433e64..4efcd7b 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 &current_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 &current_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.
@@ -176,7 +233,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>> &macro;
- 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>> &macro,
- std::map<std::string, std::vector<MatchedFragment>> &fragments)
+ std::map<std::string, MatchedFragmentContainer> &fragments)
: input (input), macro (macro), fragments (fragments)
{}