// 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 ();
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
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
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
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
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 ();
}
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 ();
}
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 ¤t_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.
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,
// 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");
// 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++)
{
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;
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);
{
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
public:
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)
: input (input), macro (macro), fragments (fragments)
{}