diff options
Diffstat (limited to 'gcc/rust/expand/rust-macro-expand.cc')
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.cc | 87 |
1 files changed, 53 insertions, 34 deletions
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index fe20560..e7407a4 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -18,15 +18,17 @@ #include "rust-macro-expand.h" #include "optional.h" +#include "rust-ast-fragment.h" #include "rust-macro-substitute-ctx.h" #include "rust-ast-full.h" #include "rust-ast-visitor.h" #include "rust-diagnostics.h" +#include "rust-macro.h" #include "rust-parse.h" #include "rust-cfg-strip.h" #include "rust-early-name-resolver.h" -#include "rust-session-manager.h" #include "rust-proc-macro.h" +#include "rust-token-tree-desugar.h" namespace Rust { @@ -34,7 +36,7 @@ AST::Fragment MacroExpander::expand_decl_macro (location_t invoc_locus, AST::MacroInvocData &invoc, AST::MacroRulesDefinition &rules_def, - bool semicolon) + AST::InvocKind semicolon) { // ensure that both invocation and rules are in a valid state rust_assert (!invoc.is_marked_for_strip ()); @@ -43,9 +45,10 @@ MacroExpander::expand_decl_macro (location_t invoc_locus, /* probably something here about parsing invoc and rules def token trees to * token stream. if not, how would parser handle the captures of exprs and - * stuff? on the other hand, token trees may be kind of useful in rules def as - * creating a point where recursion can occur (like having - * "compare_macro_match" and then it calling itself when it finds delimiters) + * stuff? on the other hand, token trees may be kind of useful in rules def + * as creating a point where recursion can occur (like having + * "compare_macro_match" and then it calling itself when it finds + * delimiters) */ /* find matching rule to invoc token tree, based on macro rule's matcher. if @@ -70,12 +73,16 @@ MacroExpander::expand_decl_macro (location_t invoc_locus, /* TODO: it is probably better to modify AST::Token to store a pointer to a * Lexer::Token (rather than being converted) - i.e. not so much have - * AST::Token as a Token but rather a TokenContainer (as it is another type of - * TokenTree). This will prevent re-conversion of Tokens between each type - * all the time, while still allowing the heterogenous storage of token trees. + * AST::Token as a Token but rather a TokenContainer (as it is another type + * of TokenTree). This will prevent re-conversion of Tokens between each + * type all the time, while still allowing the heterogenous storage of token + * trees. */ - AST::DelimTokenTree &invoc_token_tree = invoc.get_delim_tok_tree (); + AST::DelimTokenTree &invoc_token_tree_sugar = invoc.get_delim_tok_tree (); + + // We must first desugar doc comments into proper attributes + auto invoc_token_tree = AST::TokenTreeDesugar ().go (invoc_token_tree_sugar); // find matching arm AST::MacroRule *matched_rule = nullptr; @@ -116,7 +123,7 @@ MacroExpander::expand_decl_macro (location_t invoc_locus, for (auto &ent : matched_fragments) matched_fragments_ptr.emplace (ent.first, ent.second.get ()); - return transcribe_rule (*matched_rule, invoc_token_tree, + return transcribe_rule (rules_def, *matched_rule, invoc_token_tree, matched_fragments_ptr, semicolon, peek_context ()); } @@ -199,7 +206,7 @@ MacroExpander::expand_eager_invocations (AST::MacroInvocation &invoc) for (auto kv : substitution_map) { auto &to_expand = kv.second; - expand_invoc (*to_expand, false); + expand_invoc (*to_expand, AST::InvocKind::Expr); auto fragment = take_expanded_fragment (); auto &new_tokens = fragment.get_tokens (); @@ -237,7 +244,8 @@ MacroExpander::expand_eager_invocations (AST::MacroInvocation &invoc) } void -MacroExpander::expand_invoc (AST::MacroInvocation &invoc, bool has_semicolon) +MacroExpander::expand_invoc (AST::MacroInvocation &invoc, + AST::InvocKind semicolon) { if (depth_exceeds_recursion_limit ()) { @@ -246,7 +254,12 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc, bool has_semicolon) } if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin) - expand_eager_invocations (invoc); + { + // Eager expansions are always expressions + push_context (ContextType::EXPR); + expand_eager_invocations (invoc); + pop_context (); + } AST::MacroInvocData &invoc_data = invoc.get_invoc_data (); @@ -272,26 +285,28 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc, bool has_semicolon) invoc_data.set_expander (this); // lookup the rules - AST::MacroRulesDefinition *rules_def = nullptr; - bool ok = mappings->lookup_macro_invocation (invoc, &rules_def); + auto rules_def = mappings.lookup_macro_invocation (invoc); // If there's no rule associated with the invocation, we can simply return // early. The early name resolver will have already emitted an error. - if (!ok) + if (!rules_def) return; + auto rdef = rules_def.value (); + // We store the last expanded invocation and macro definition for error // reporting in case the recursion limit is reached last_invoc = *invoc.clone_macro_invocation_impl (); - last_def = *rules_def; + last_def = *rdef; - if (rules_def->is_builtin ()) - fragment - = rules_def->get_builtin_transcriber () (invoc.get_locus (), invoc_data) - .value_or (AST::Fragment::create_empty ()); + if (rdef->is_builtin ()) + fragment = rdef + ->get_builtin_transcriber () (invoc.get_locus (), invoc_data, + semicolon) + .value_or (AST::Fragment::create_empty ()); else - fragment = expand_decl_macro (invoc.get_locus (), invoc_data, *rules_def, - has_semicolon); + fragment + = expand_decl_macro (invoc.get_locus (), invoc_data, *rdef, semicolon); set_expanded_fragment (std::move (fragment)); } @@ -610,9 +625,10 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser, // matched fragment get the offset in the token stream size_t offs_end = source.get_offs (); - sub_stack.insert_metavar ( - MatchedFragment (fragment->get_ident ().as_string (), - offs_begin, offs_end)); + if (valid_current_match) + sub_stack.insert_metavar ( + MatchedFragment (fragment->get_ident ().as_string (), + offs_begin, offs_end)); } break; @@ -639,15 +655,15 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser, } auto old_stack = sub_stack.pop (); - // nest metavars into repetitions - for (auto &ent : old_stack) - sub_stack.append_fragment (ent.first, std::move (ent.second)); - // If we've encountered an error once, stop trying to match more // repetitions if (!valid_current_match) break; + // nest metavars into repetitions + for (auto &ent : old_stack) + sub_stack.append_fragment (ent.first, std::move (ent.second)); + match_amount++; // Break early if we notice there's too many expressions already @@ -1013,10 +1029,13 @@ 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, + AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule, + AST::DelimTokenTree &invoc_token_tree, std::map<std::string, MatchedFragmentContainer *> &matched_fragments, - bool semicolon, ContextType ctx) + AST::InvocKind invoc_kind, ContextType ctx) { + bool semicolon = invoc_kind == AST::InvocKind::Semicoloned; + // we can manipulate the token tree to substitute the dollar identifiers so // that when we call parse its already substituted for us AST::MacroTranscriber &transcriber = match_rule.get_transcriber (); @@ -1025,8 +1044,8 @@ MacroExpander::transcribe_rule ( auto invoc_stream = invoc_token_tree.to_token_stream (); auto macro_rule_tokens = transcribe_tree.to_token_stream (); - auto substitute_context - = SubstituteCtx (invoc_stream, macro_rule_tokens, matched_fragments); + auto substitute_context = SubstituteCtx (invoc_stream, macro_rule_tokens, + matched_fragments, definition); std::vector<std::unique_ptr<AST::Token>> substituted_tokens = substitute_context.substitute_tokens (); |