@@ -93,15 +93,83 @@ extract_module_path (const AST::AttrVec &inner_attrs,
93
93
return path;
94
94
}
95
95
96
+ template <typename T>
97
+ static bool
98
+ contains (std::vector<T> &vec, T elm)
99
+ {
100
+ return std::find (vec.begin (), vec.end (), elm) != vec.end ();
101
+ }
102
+
103
+ static bool
104
+ peculiar_fragment_match_compatible_fragment (
105
+ const AST::MacroFragSpec &last_spec, const AST::MacroFragSpec &spec,
106
+ Location match_locus)
107
+ {
108
+ static std::unordered_map<AST::MacroFragSpec::Kind,
109
+ std::vector<AST::MacroFragSpec::Kind>>
110
+ fragment_follow_set
111
+ = {{AST::MacroFragSpec::PATH, {AST::MacroFragSpec::BLOCK}},
112
+ {AST::MacroFragSpec::TY, {AST::MacroFragSpec::BLOCK}},
113
+ {AST::MacroFragSpec::VIS,
114
+ {AST::MacroFragSpec::IDENT, AST::MacroFragSpec::TY,
115
+ AST::MacroFragSpec::PATH}}};
116
+
117
+ auto is_valid
118
+ = contains (fragment_follow_set[last_spec.get_kind ()], spec.get_kind ());
119
+
120
+ if (!is_valid)
121
+ rust_error_at (
122
+ match_locus,
123
+ " fragment specifier %<%s%> is not allowed after %<%s%> fragments" ,
124
+ spec.as_string ().c_str (), last_spec.as_string ().c_str ());
125
+
126
+ return is_valid;
127
+ }
128
+
96
129
static bool
97
130
peculiar_fragment_match_compatible (AST::MacroMatchFragment &last_match,
98
131
AST::MacroMatch &match)
99
132
{
100
133
static std::unordered_map<AST::MacroFragSpec::Kind, std::vector<TokenId>>
101
- follow_set = {
102
- {AST::MacroFragSpec::EXPR, {MATCH_ARROW, COMMA, SEMICOLON}},
103
- {AST::MacroFragSpec::STMT, {MATCH_ARROW, COMMA, SEMICOLON}},
104
- };
134
+ follow_set
135
+ = {{AST::MacroFragSpec::EXPR, {MATCH_ARROW, COMMA, SEMICOLON}},
136
+ {AST::MacroFragSpec::STMT, {MATCH_ARROW, COMMA, SEMICOLON}},
137
+ {AST::MacroFragSpec::PAT, {MATCH_ARROW, COMMA, EQUAL, PIPE, IF, IN}},
138
+ {AST::MacroFragSpec::PATH,
139
+ {MATCH_ARROW, COMMA, EQUAL, PIPE, SEMICOLON, COLON, RIGHT_ANGLE,
140
+ RIGHT_SHIFT, LEFT_SQUARE, LEFT_CURLY, AS, WHERE}},
141
+ {AST::MacroFragSpec::TY,
142
+ {MATCH_ARROW, COMMA, EQUAL, PIPE, SEMICOLON, COLON, RIGHT_ANGLE,
143
+ RIGHT_SHIFT, LEFT_SQUARE, LEFT_CURLY, AS, WHERE}},
144
+ {AST::MacroFragSpec::VIS,
145
+ {
146
+ COMMA,
147
+ IDENTIFIER /* FIXME: Other than `priv` */ ,
148
+ LEFT_PAREN,
149
+ LEFT_SQUARE,
150
+ EXCLAM,
151
+ ASTERISK,
152
+ AMP,
153
+ LOGICAL_AND,
154
+ QUESTION_MARK,
155
+ LIFETIME,
156
+ LEFT_ANGLE,
157
+ LEFT_SHIFT,
158
+ SUPER,
159
+ SELF,
160
+ SELF_ALIAS,
161
+ EXTERN_TOK,
162
+ CRATE,
163
+ UNDERSCORE,
164
+ FOR,
165
+ IMPL,
166
+ FN_TOK,
167
+ UNSAFE,
168
+ TYPEOF,
169
+ DYN
170
+ // FIXME: Add Non kw identifiers
171
+ // FIXME: Add $crate as valid
172
+ }}};
105
173
106
174
Location error_locus = match.get_match_locus ();
107
175
@@ -117,9 +185,7 @@ peculiar_fragment_match_compatible (AST::MacroMatchFragment &last_match,
117
185
auto tok = static_cast <AST::Token *> (&match);
118
186
auto &allowed_toks
119
187
= follow_set[last_match.get_frag_spec ().get_kind ()];
120
- auto is_valid = std::find (allowed_toks.begin (), allowed_toks.end (),
121
- tok->get_id ())
122
- != allowed_toks.end ();
188
+ auto is_valid = contains (allowed_toks, tok->get_id ());
123
189
if (!is_valid)
124
190
// FIXME: Add hint about allowed fragments
125
191
rust_error_at (tok->get_match_locus (),
@@ -143,10 +209,17 @@ peculiar_fragment_match_compatible (AST::MacroMatchFragment &last_match,
143
209
error_locus = matches.front ()->get_match_locus ();
144
210
break ;
145
211
}
146
- default :
212
+ case AST::MacroMatch::Fragment: {
213
+ auto last_spec = last_match.get_frag_spec ();
214
+ auto fragment = static_cast <AST::MacroMatchFragment *> (&match);
215
+ if (last_spec.has_follow_set_fragment_restrictions ())
216
+ return peculiar_fragment_match_compatible_fragment (
217
+ last_spec, fragment->get_frag_spec (), match.get_match_locus ());
218
+ }
147
219
break ;
148
220
}
149
221
222
+ // FIXME: Improve error message
150
223
rust_error_at (error_locus, " fragment not allowed after %<%s%> fragment" ,
151
224
last_match.get_frag_spec ().as_string ().c_str ());
152
225
@@ -213,16 +286,7 @@ is_match_compatible (AST::MacroMatch &last_match, AST::MacroMatch &match)
213
286
return true ;
214
287
break ;
215
288
}
216
- case AST::MacroMatch::Matcher: {
217
- // Likewise for another matcher
218
- auto matcher = static_cast <AST::MacroMatcher *> (&last_match);
219
- new_last = get_back_ptr (matcher->get_matches ());
220
- // If there are no matches in the matcher, then it can be followed by
221
- // anything
222
- if (!new_last)
223
- return true ;
224
- break ;
225
- }
289
+ case AST::MacroMatch::Matcher:
226
290
case AST::MacroMatch::Tok:
227
291
return true ;
228
292
}
0 commit comments