|
17 | 17 | // <http://www.gnu.org/licenses/>.
|
18 | 18 |
|
19 | 19 | #include "rust-macro-expand.h"
|
| 20 | +#include "rust-macro-substitute-ctx.h" |
20 | 21 | #include "rust-ast-full.h"
|
21 | 22 | #include "rust-ast-visitor.h"
|
22 | 23 | #include "rust-diagnostics.h"
|
@@ -3773,8 +3774,10 @@ MacroExpander::transcribe_rule (
|
3773 | 3774 | auto invoc_stream = invoc_token_tree.to_token_stream ();
|
3774 | 3775 | auto macro_rule_tokens = transcribe_tree.to_token_stream ();
|
3775 | 3776 |
|
| 3777 | + auto substitute_context |
| 3778 | + = SubstituteCtx (invoc_stream, macro_rule_tokens, matched_fragments); |
3776 | 3779 | std::vector<std::unique_ptr<AST::Token>> substituted_tokens
|
3777 |
| - = substitute_tokens (invoc_stream, macro_rule_tokens, matched_fragments); |
| 3780 | + = substitute_context.substitute_tokens (); |
3778 | 3781 |
|
3779 | 3782 | // // handy for debugging
|
3780 | 3783 | // for (auto &tok : substituted_tokens)
|
@@ -3896,220 +3899,4 @@ MacroExpander::transcribe_rule (
|
3896 | 3899 |
|
3897 | 3900 | return AST::ASTFragment (std::move (nodes));
|
3898 | 3901 | }
|
3899 |
| - |
3900 |
| -std::vector<std::unique_ptr<AST::Token>> |
3901 |
| -MacroExpander::substitute_metavar ( |
3902 |
| - std::vector<std::unique_ptr<AST::Token>> &input, |
3903 |
| - std::map<std::string, std::vector<MatchedFragment>> &fragments, |
3904 |
| - std::unique_ptr<AST::Token> &metavar) |
3905 |
| -{ |
3906 |
| - auto metavar_name = metavar->get_str (); |
3907 |
| - |
3908 |
| - std::vector<std::unique_ptr<AST::Token>> expanded; |
3909 |
| - auto it = fragments.find (metavar_name); |
3910 |
| - if (it == fragments.end ()) |
3911 |
| - { |
3912 |
| - // Return a copy of the original token |
3913 |
| - expanded.push_back (metavar->clone_token ()); |
3914 |
| - } |
3915 |
| - else |
3916 |
| - { |
3917 |
| - // Replace |
3918 |
| - // We only care about the vector when expanding repetitions. Just access |
3919 |
| - // the first element of the vector. |
3920 |
| - // FIXME: Clean this up so it makes more sense |
3921 |
| - auto &frag = it->second[0]; |
3922 |
| - for (size_t offs = frag.token_offset_begin; offs < frag.token_offset_end; |
3923 |
| - offs++) |
3924 |
| - { |
3925 |
| - auto &tok = input.at (offs); |
3926 |
| - expanded.push_back (tok->clone_token ()); |
3927 |
| - } |
3928 |
| - } |
3929 |
| - |
3930 |
| - return expanded; |
3931 |
| -} |
3932 |
| - |
3933 |
| -std::vector<std::unique_ptr<AST::Token>> |
3934 |
| -MacroExpander::substitute_repetition ( |
3935 |
| - std::vector<std::unique_ptr<AST::Token>> &input, |
3936 |
| - std::vector<std::unique_ptr<AST::Token>> ¯o, |
3937 |
| - std::map<std::string, std::vector<MatchedFragment>> &fragments, |
3938 |
| - size_t pattern_start, size_t pattern_end) |
3939 |
| -{ |
3940 |
| - rust_assert (pattern_end < macro.size ()); |
3941 |
| - |
3942 |
| - rust_debug ("pattern start: %lu", pattern_start); |
3943 |
| - rust_debug ("pattern end: %lu", pattern_end); |
3944 |
| - |
3945 |
| - std::vector<std::unique_ptr<AST::Token>> expanded; |
3946 |
| - |
3947 |
| - // Find the first fragment and get the amount of repetitions that we should |
3948 |
| - // perform |
3949 |
| - size_t repeat_amount = 0; |
3950 |
| - for (size_t i = pattern_start; i < pattern_end; i++) |
3951 |
| - { |
3952 |
| - if (macro.at (i)->get_id () == DOLLAR_SIGN) |
3953 |
| - { |
3954 |
| - auto &frag_token = macro.at (i + 1); |
3955 |
| - if (frag_token->get_id () == IDENTIFIER) |
3956 |
| - { |
3957 |
| - auto it = fragments.find (frag_token->get_str ()); |
3958 |
| - if (it == fragments.end ()) |
3959 |
| - { |
3960 |
| - // If the repetition is not anything we know (ie no declared |
3961 |
| - // metavars, or metavars which aren't present in the |
3962 |
| - // fragment), we can just error out. No need to paste the |
3963 |
| - // tokens as if nothing had happened. |
3964 |
| - rust_error_at (frag_token->get_locus (), |
3965 |
| - "metavar %s used in repetition does not exist", |
3966 |
| - frag_token->get_str ().c_str ()); |
3967 |
| - // FIXME: |
3968 |
| - return expanded; |
3969 |
| - } |
3970 |
| - |
3971 |
| - // FIXME: Refactor, ugly |
3972 |
| - repeat_amount = it->second[0].match_amount; |
3973 |
| - } |
3974 |
| - } |
3975 |
| - } |
3976 |
| - |
3977 |
| - rust_debug ("repetition amount to use: %lu", repeat_amount); |
3978 |
| - std::vector<std::unique_ptr<AST::Token>> new_macro; |
3979 |
| - |
3980 |
| - // We want to generate a "new macro" to substitute with. This new macro |
3981 |
| - // should contain only the tokens inside the pattern |
3982 |
| - for (size_t tok_idx = pattern_start; tok_idx < pattern_end; tok_idx++) |
3983 |
| - new_macro.emplace_back (macro.at (tok_idx)->clone_token ()); |
3984 |
| - |
3985 |
| - // Then, we want to create a subset of the matches so that |
3986 |
| - // `substitute_tokens()` can only see one fragment per metavar. Let's say we |
3987 |
| - // have the following user input: (1 145 'h') |
3988 |
| - // on the following match arm: ($($lit:literal)*) |
3989 |
| - // which causes the following matches: { "lit": [1, 145, 'h'] } |
3990 |
| - // |
3991 |
| - // The pattern (new_macro) is `$lit:literal` |
3992 |
| - // The first time we expand it, we want $lit to have the following token: 1 |
3993 |
| - // The second time, 145 |
3994 |
| - // The third and final time, 'h' |
3995 |
| - // |
3996 |
| - // In order to do so we must create "sub maps", which only contain parts of |
3997 |
| - // the original matches |
3998 |
| - // sub-maps: [ { "lit": 1 }, { "lit": 145 }, { "lit": 'h' } ] |
3999 |
| - // |
4000 |
| - // and give them to `substitute_tokens` one by one. |
4001 |
| - |
4002 |
| - for (size_t i = 0; i < repeat_amount; i++) |
4003 |
| - { |
4004 |
| - std::map<std::string, std::vector<MatchedFragment>> sub_map; |
4005 |
| - for (auto &kv_match : fragments) |
4006 |
| - { |
4007 |
| - std::vector<MatchedFragment> sub_vec; |
4008 |
| - sub_vec.emplace_back (kv_match.second[i]); |
4009 |
| - |
4010 |
| - sub_map.insert ({kv_match.first, sub_vec}); |
4011 |
| - } |
4012 |
| - |
4013 |
| - auto new_tokens = substitute_tokens (input, new_macro, sub_map); |
4014 |
| - |
4015 |
| - for (auto &new_token : new_tokens) |
4016 |
| - expanded.emplace_back (new_token->clone_token ()); |
4017 |
| - } |
4018 |
| - |
4019 |
| - // FIXME: We also need to make sure that all subsequent fragments |
4020 |
| - // contain the same amount of repetitions as the first one |
4021 |
| - |
4022 |
| - return expanded; |
4023 |
| -} |
4024 |
| - |
4025 |
| -std::pair<std::vector<std::unique_ptr<AST::Token>>, size_t> |
4026 |
| -MacroExpander::substitute_token ( |
4027 |
| - std::vector<std::unique_ptr<AST::Token>> &input, |
4028 |
| - std::vector<std::unique_ptr<AST::Token>> ¯o, |
4029 |
| - std::map<std::string, std::vector<MatchedFragment>> &fragments, |
4030 |
| - size_t token_idx) |
4031 |
| -{ |
4032 |
| - auto &token = macro.at (token_idx); |
4033 |
| - switch (token->get_id ()) |
4034 |
| - { |
4035 |
| - case IDENTIFIER: |
4036 |
| - rust_debug ("expanding metavar: %s", token->get_str ().c_str ()); |
4037 |
| - return {substitute_metavar (input, fragments, token), 1}; |
4038 |
| - case LEFT_PAREN: { |
4039 |
| - // We need to parse up until the closing delimiter and expand this |
4040 |
| - // fragment->n times. |
4041 |
| - rust_debug ("expanding repetition"); |
4042 |
| - std::vector<std::unique_ptr<AST::Token>> repetition_pattern; |
4043 |
| - size_t pattern_start = token_idx + 1; |
4044 |
| - size_t pattern_end = pattern_start; |
4045 |
| - for (; pattern_end < macro.size () |
4046 |
| - && macro.at (pattern_end)->get_id () != RIGHT_PAREN; |
4047 |
| - pattern_end++) |
4048 |
| - ; |
4049 |
| - |
4050 |
| - // FIXME: This skips whitespaces... Is that okay?? |
4051 |
| - // FIXME: Is there any existing parsing function that allows us to parse |
4052 |
| - // a macro pattern? |
4053 |
| - |
4054 |
| - // FIXME: Add error handling in the case we haven't found a matching |
4055 |
| - // closing delimiter |
4056 |
| - |
4057 |
| - // FIXME: We need to parse the repetition token now |
4058 |
| - |
4059 |
| - return { |
4060 |
| - substitute_repetition (input, macro, fragments, pattern_start, |
4061 |
| - pattern_end), |
4062 |
| - // + 2 for the opening and closing parentheses which are mandatory |
4063 |
| - // + 1 for the repetitor (+, *, ?) |
4064 |
| - pattern_end - pattern_start + 3}; |
4065 |
| - } |
4066 |
| - // TODO: We need to check if the $ was alone. In that case, do |
4067 |
| - // not error out: Simply act as if there was an empty identifier |
4068 |
| - // with no associated fragment and paste the dollar sign in the |
4069 |
| - // transcription. Unsure how to do that since we always have at |
4070 |
| - // least the closing curly brace after an empty $... |
4071 |
| - default: |
4072 |
| - rust_error_at (token->get_locus (), |
4073 |
| - "unexpected token in macro transcribe: expected " |
4074 |
| - "%<(%> or identifier after %<$%>, got %<%s%>", |
4075 |
| - get_token_description (token->get_id ())); |
4076 |
| - } |
4077 |
| - |
4078 |
| - // FIXME: gcc_unreachable() error case? |
4079 |
| - return {std::vector<std::unique_ptr<AST::Token>> (), 0}; |
4080 |
| -} |
4081 |
| - |
4082 |
| -std::vector<std::unique_ptr<AST::Token>> |
4083 |
| -MacroExpander::substitute_tokens ( |
4084 |
| - std::vector<std::unique_ptr<AST::Token>> &input, |
4085 |
| - std::vector<std::unique_ptr<AST::Token>> ¯o, |
4086 |
| - std::map<std::string, std::vector<MatchedFragment>> &fragments) |
4087 |
| -{ |
4088 |
| - std::vector<std::unique_ptr<AST::Token>> replaced_tokens; |
4089 |
| - |
4090 |
| - for (size_t i = 0; i < macro.size (); i++) |
4091 |
| - { |
4092 |
| - auto &tok = macro.at (i); |
4093 |
| - if (tok->get_id () == DOLLAR_SIGN) |
4094 |
| - { |
4095 |
| - // Aaaaah, if only we had C++17 :) |
4096 |
| - // auto [expanded, tok_to_skip] = ... |
4097 |
| - auto p = substitute_token (input, macro, fragments, i + 1); |
4098 |
| - auto expanded = std::move (p.first); |
4099 |
| - auto tok_to_skip = p.second; |
4100 |
| - |
4101 |
| - i += tok_to_skip; |
4102 |
| - |
4103 |
| - for (auto &token : expanded) |
4104 |
| - replaced_tokens.emplace_back (token->clone_token ()); |
4105 |
| - } |
4106 |
| - else |
4107 |
| - { |
4108 |
| - replaced_tokens.emplace_back (tok->clone_token ()); |
4109 |
| - } |
4110 |
| - } |
4111 |
| - |
4112 |
| - return replaced_tokens; |
4113 |
| -} |
4114 |
| - |
4115 | 3902 | } // namespace Rust
|
0 commit comments