Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 Free Software Foundation, Inc.
2 : :
3 : : // This file is part of GCC.
4 : :
5 : : // GCC is free software; you can redistribute it and/or modify it under
6 : : // the terms of the GNU General Public License as published by the Free
7 : : // Software Foundation; either version 3, or (at your option) any later
8 : : // version.
9 : :
10 : : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : : // for more details.
14 : :
15 : : // You should have received a copy of the GNU General Public License
16 : : // along with GCC; see the file COPYING3. If not see
17 : : // <http://www.gnu.org/licenses/>.
18 : :
19 : : #ifndef RUST_MACRO_EXPAND_H
20 : : #define RUST_MACRO_EXPAND_H
21 : :
22 : : #include "optional.h"
23 : : #include "rust-buffered-queue.h"
24 : : #include "rust-parse.h"
25 : : #include "rust-token.h"
26 : : #include "rust-ast.h"
27 : : #include "rust-macro.h"
28 : : #include "rust-hir-map.h"
29 : : #include "rust-early-name-resolver.h"
30 : : #include "rust-name-resolver.h"
31 : : #include "rust-macro-invoc-lexer.h"
32 : : #include "rust-proc-macro-invoc-lexer.h"
33 : : #include "rust-token-converter.h"
34 : : #include "rust-ast-collector.h"
35 : : #include "rust-system.h"
36 : : #include "libproc_macro_internal/proc_macro.h"
37 : :
38 : : // Provides objects and method prototypes for macro expansion
39 : :
40 : : namespace Rust {
41 : : // forward decls for AST
42 : : namespace AST {
43 : : class MacroInvocation;
44 : : }
45 : :
46 : : // Object used to store configuration data for macro expansion.
47 : : // NOTE: Keep all these items complying with the latest rustc.
48 : 7238 : struct ExpansionCfg
49 : : {
50 : : // features?
51 : : // TODO: Add `features' when we have it.
52 : : unsigned int recursion_limit = 1024;
53 : : bool trace_mac = false; // trace macro
54 : : bool should_test = false; // strip #[test] nodes if false
55 : : bool keep_macs = false; // keep macro definitions
56 : : std::string crate_name = "";
57 : : };
58 : :
59 : 6546 : struct MatchedFragment
60 : : {
61 : : std::string fragment_ident;
62 : : size_t token_offset_begin;
63 : : size_t token_offset_end;
64 : :
65 : 6546 : MatchedFragment (std::string identifier, size_t token_offset_begin,
66 : : size_t token_offset_end)
67 : 6546 : : fragment_ident (identifier), token_offset_begin (token_offset_begin),
68 : 6546 : token_offset_end (token_offset_end)
69 : : {}
70 : :
71 : : /**
72 : : * Empty constructor for uninitialized fragments
73 : : */
74 : : MatchedFragment () : MatchedFragment ("", 0, 0) {}
75 : :
76 : 0 : std::string as_string () const
77 : : {
78 : 0 : return fragment_ident + "=" + std::to_string (token_offset_begin) + ":"
79 : 0 : + std::to_string (token_offset_end);
80 : : }
81 : : };
82 : :
83 : 8147 : class MatchedFragmentContainer
84 : : {
85 : : public:
86 : : // Does the container refer to a simple metavariable, different from a
87 : : // repetition repeated once
88 : : enum class Kind
89 : : {
90 : : MetaVar,
91 : : Repetition,
92 : : };
93 : :
94 : : virtual ~MatchedFragmentContainer () = default;
95 : :
96 : : virtual Kind get_kind () const = 0;
97 : :
98 : : virtual std::string as_string () const = 0;
99 : :
100 : : /**
101 : : * Create a valid fragment matched zero times. This is useful for repetitions
102 : : * which allow the absence of a fragment, such as * and ?
103 : : */
104 : : static std::unique_ptr<MatchedFragmentContainer> zero ();
105 : :
106 : : /**
107 : : * Create a valid fragment matched one time
108 : : */
109 : : static std::unique_ptr<MatchedFragmentContainer>
110 : : metavar (MatchedFragment fragment);
111 : :
112 : : /**
113 : : * Add a matched fragment to the container
114 : : */
115 : : void add_fragment (MatchedFragment fragment);
116 : :
117 : : /**
118 : : * Add a matched fragment to the container
119 : : */
120 : : void add_fragment (std::unique_ptr<MatchedFragmentContainer> fragment);
121 : :
122 : : // const std::string &get_fragment_name () const { return fragment_name; }
123 : :
124 : 29141 : bool is_single_fragment () const { return get_kind () == Kind::MetaVar; }
125 : :
126 : : MatchedFragment &get_single_fragment ();
127 : :
128 : : std::vector<std::unique_ptr<MatchedFragmentContainer>> &get_fragments ();
129 : : };
130 : :
131 : : class MatchedFragmentContainerMetaVar : public MatchedFragmentContainer
132 : : {
133 : : MatchedFragment fragment;
134 : :
135 : : public:
136 : 6546 : MatchedFragmentContainerMetaVar (const MatchedFragment &fragment)
137 : 6546 : : fragment (fragment)
138 : : {}
139 : :
140 : 6480 : MatchedFragment &get_fragment () { return fragment; }
141 : :
142 : 14493 : virtual Kind get_kind () const { return Kind::MetaVar; }
143 : :
144 : 0 : virtual std::string as_string () const { return fragment.as_string (); }
145 : : };
146 : :
147 : : class MatchedFragmentContainerRepetition : public MatchedFragmentContainer
148 : : {
149 : : std::vector<std::unique_ptr<MatchedFragmentContainer>> fragments;
150 : :
151 : : public:
152 : 1601 : MatchedFragmentContainerRepetition () {}
153 : :
154 : 1600 : size_t get_match_amount () const { return fragments.size (); }
155 : :
156 : 6455 : std::vector<std::unique_ptr<MatchedFragmentContainer>> &get_fragments ()
157 : : {
158 : 6455 : return fragments;
159 : : }
160 : :
161 : : /**
162 : : * Add a matched fragment to the container
163 : : */
164 : 0 : void add_fragment (MatchedFragment fragment)
165 : : {
166 : 0 : add_fragment (metavar (fragment));
167 : 0 : }
168 : :
169 : : /**
170 : : * Add a matched fragment to the container
171 : : */
172 : 3357 : void add_fragment (std::unique_ptr<MatchedFragmentContainer> fragment)
173 : : {
174 : 3357 : fragments.emplace_back (std::move (fragment));
175 : : }
176 : :
177 : 14648 : virtual Kind get_kind () const { return Kind::Repetition; }
178 : :
179 : 0 : virtual std::string as_string () const
180 : : {
181 : 0 : std::string acc = "[";
182 : 0 : for (size_t i = 0; i < fragments.size (); i++)
183 : : {
184 : 0 : if (i)
185 : 0 : acc += " ";
186 : 0 : acc += fragments[i]->as_string ();
187 : : }
188 : 0 : acc += "]";
189 : 0 : return acc;
190 : : }
191 : : };
192 : :
193 : 7238 : class SubstitutionScope
194 : : {
195 : : public:
196 : 3619 : SubstitutionScope () : stack () {}
197 : :
198 : 6635 : void push () { stack.push_back ({}); }
199 : :
200 : 6635 : std::map<std::string, std::unique_ptr<MatchedFragmentContainer>> pop ()
201 : : {
202 : 6635 : auto top = std::move (stack.back ());
203 : 6635 : stack.pop_back ();
204 : 6635 : return top;
205 : : }
206 : :
207 : 1601 : std::map<std::string, std::unique_ptr<MatchedFragmentContainer>> &peek ()
208 : : {
209 : 1601 : return stack.back ();
210 : : }
211 : :
212 : : /**
213 : : * Insert a new matched metavar into the current substitution map
214 : : */
215 : 6546 : void insert_metavar (MatchedFragment fragment)
216 : : {
217 : 6546 : auto ¤t_map = stack.back ();
218 : 6546 : auto it = current_map.find (fragment.fragment_ident);
219 : :
220 : 6546 : if (it == current_map.end ())
221 : 13092 : current_map.emplace (fragment.fragment_ident,
222 : 13092 : MatchedFragmentContainer::metavar (fragment));
223 : : else
224 : 0 : rust_unreachable ();
225 : 6546 : }
226 : :
227 : : /**
228 : : * Append a new matched fragment to a repetition into the current substitution
229 : : * map
230 : : */
231 : : void append_fragment (MatchedFragment fragment)
232 : : {
233 : : auto ¤t_map = stack.back ();
234 : : auto it = current_map.find (fragment.fragment_ident);
235 : :
236 : : if (it == current_map.end ())
237 : : it = current_map
238 : : .emplace (fragment.fragment_ident,
239 : : std::unique_ptr<MatchedFragmentContainer> (
240 : : new MatchedFragmentContainerRepetition ()))
241 : : .first;
242 : :
243 : : it->second->add_fragment (fragment);
244 : : }
245 : :
246 : : /**
247 : : * Append a new matched fragment to a repetition into the current substitution
248 : : * map
249 : : */
250 : 3357 : void append_fragment (std::string ident,
251 : : std::unique_ptr<MatchedFragmentContainer> fragment)
252 : : {
253 : 3357 : auto ¤t_map = stack.back ();
254 : 3357 : auto it = current_map.find (ident);
255 : :
256 : 3357 : if (it == current_map.end ())
257 : 3104 : it = current_map
258 : 1552 : .emplace (ident, std::unique_ptr<MatchedFragmentContainer> (
259 : 1552 : new MatchedFragmentContainerRepetition ()))
260 : : .first;
261 : :
262 : 3357 : it->second->add_fragment (std::move (fragment));
263 : 3357 : }
264 : :
265 : 49 : void insert_matches (std::string key,
266 : : std::unique_ptr<MatchedFragmentContainer> matches)
267 : : {
268 : 49 : auto ¤t_map = stack.back ();
269 : 49 : auto it = current_map.find (key);
270 : 49 : rust_assert (it == current_map.end ());
271 : :
272 : 49 : current_map.emplace (std::move (key), std::move (matches));
273 : 49 : }
274 : :
275 : : private:
276 : : std::vector<std::map<std::string, std::unique_ptr<MatchedFragmentContainer>>>
277 : : stack;
278 : : };
279 : :
280 : : // Object used to store shared data (between functions) for macro expansion.
281 : : struct MacroExpander
282 : : {
283 : : enum class ContextType
284 : : {
285 : : ITEM,
286 : : STMT,
287 : : EXPR,
288 : : EXTERN,
289 : : TYPE,
290 : : TRAIT,
291 : : IMPL,
292 : : TRAIT_IMPL,
293 : : };
294 : :
295 : : ExpansionCfg cfg;
296 : : unsigned int expansion_depth = 0;
297 : :
298 : 3619 : MacroExpander (AST::Crate &crate, ExpansionCfg cfg, Session &session)
299 : 3619 : : cfg (cfg), crate (crate), session (session),
300 : 3619 : sub_stack (SubstitutionScope ()),
301 : 3619 : expanded_fragment (AST::Fragment::create_error ()),
302 : 7238 : has_changed_flag (false), resolver (Resolver::Resolver::get ()),
303 : 3619 : mappings (Analysis::Mappings::get ())
304 : 3619 : {}
305 : :
306 : 7238 : ~MacroExpander () = default;
307 : :
308 : : // Expands all macros in the crate passed in.
309 : : void expand_crate ();
310 : :
311 : : /**
312 : : * Expand the eager invocations contained within a builtin macro invocation.
313 : : * Called by `expand_invoc` when expanding builtin invocations.
314 : : */
315 : : void expand_eager_invocations (AST::MacroInvocation &invoc);
316 : :
317 : : /* Expands a macro invocation - possibly make both
318 : : * have similar duck-typed interface and use templates?*/
319 : : // should this be public or private?
320 : : void expand_invoc (AST::MacroInvocation &invoc, bool has_semicolon);
321 : :
322 : : // Expands a single declarative macro.
323 : : AST::Fragment expand_decl_macro (location_t locus, AST::MacroInvocData &invoc,
324 : : AST::MacroRulesDefinition &rules_def,
325 : : bool semicolon);
326 : :
327 : : bool depth_exceeds_recursion_limit () const;
328 : :
329 : : bool try_match_rule (AST::MacroRule &match_rule,
330 : : AST::DelimTokenTree &invoc_token_tree);
331 : :
332 : : AST::Fragment transcribe_rule (
333 : : AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
334 : : std::map<std::string, MatchedFragmentContainer *> &matched_fragments,
335 : : bool semicolon, ContextType ctx);
336 : :
337 : : bool match_fragment (Parser<MacroInvocLexer> &parser,
338 : : AST::MacroMatchFragment &fragment);
339 : :
340 : : bool match_token (Parser<MacroInvocLexer> &parser, AST::Token &token);
341 : :
342 : : void match_repetition_skipped_metavars (AST::MacroMatch &);
343 : : void match_repetition_skipped_metavars (AST::MacroMatchFragment &);
344 : : void match_repetition_skipped_metavars (AST::MacroMatchRepetition &);
345 : : void match_repetition_skipped_metavars (AST::MacroMatcher &);
346 : :
347 : : bool match_repetition (Parser<MacroInvocLexer> &parser,
348 : : AST::MacroMatchRepetition &rep);
349 : :
350 : : bool match_matcher (Parser<MacroInvocLexer> &parser,
351 : : AST::MacroMatcher &matcher, bool in_repetition = false,
352 : : bool match_delim = true);
353 : :
354 : : /**
355 : : * Match any amount of matches
356 : : *
357 : : * @param parser Parser to use for matching
358 : : * @param rep Repetition to try and match
359 : : * @param match_amount Reference in which to store the ammount of succesful
360 : : * and valid matches
361 : : *
362 : : * @param lo_bound Lower bound of the matcher. When specified, the matcher
363 : : * will only succeed if it parses at *least* `lo_bound` fragments. If
364 : : * unspecified, the matcher could succeed when parsing 0 fragments.
365 : : *
366 : : * @param hi_bound Higher bound of the matcher. When specified, the matcher
367 : : * will only succeed if it parses *less than* `hi_bound` fragments. If
368 : : * unspecified, the matcher could succeed when parsing an infinity of
369 : : * fragments.
370 : : *
371 : : * @return true if matching was successful and within the given limits, false
372 : : * otherwise
373 : : */
374 : : bool match_n_matches (Parser<MacroInvocLexer> &parser,
375 : : AST::MacroMatchRepetition &rep, size_t &match_amount,
376 : : size_t lo_bound = 0, size_t hi_bound = 0);
377 : :
378 : 1167149 : void push_context (ContextType t) { context.push_back (t); }
379 : :
380 : 1167149 : ContextType pop_context ()
381 : : {
382 : 1167149 : rust_assert (!context.empty ());
383 : :
384 : 1167149 : ContextType t = context.back ();
385 : 1167149 : context.pop_back ();
386 : :
387 : 1167149 : return t;
388 : : }
389 : :
390 : 2046 : ContextType peek_context () { return context.back (); }
391 : :
392 : 2271 : void set_expanded_fragment (AST::Fragment &&fragment)
393 : : {
394 : 2271 : if (!fragment.is_error ())
395 : 2225 : has_changed_flag = true;
396 : :
397 : 2271 : expanded_fragment = std::move (fragment);
398 : 2271 : }
399 : :
400 : 1179278 : AST::Fragment take_expanded_fragment ()
401 : : {
402 : 1179278 : auto fragment = std::move (expanded_fragment);
403 : 1179278 : expanded_fragment = AST::Fragment::create_error ();
404 : :
405 : 1179278 : return fragment;
406 : : }
407 : :
408 : : void import_proc_macros (std::string extern_crate);
409 : :
410 : : template <typename T>
411 : 0 : AST::Fragment expand_derive_proc_macro (T &item, AST::SimplePath &path)
412 : : {
413 : : tl::optional<CustomDeriveProcMacro &> macro
414 : 0 : = mappings->lookup_derive_proc_macro_invocation (path);
415 : 0 : if (!macro.has_value ())
416 : : {
417 : 0 : rust_error_at (path.get_locus (), "macro not found");
418 : 0 : return AST::Fragment::create_error ();
419 : : }
420 : :
421 : 0 : AST::TokenCollector collector;
422 : :
423 : 0 : collector.visit (item);
424 : :
425 : 0 : auto c = collector.collect_tokens ();
426 : 0 : std::vector<const_TokenPtr> vec (c.cbegin (), c.cend ());
427 : :
428 : : return parse_proc_macro_output (
429 : 0 : macro.value ().get_handle () (convert (vec)));
430 : 0 : }
431 : :
432 : : template <typename T>
433 : : AST::Fragment expand_bang_proc_macro (T &item,
434 : : AST::MacroInvocation &invocation)
435 : : {
436 : : tl::optional<BangProcMacro &> macro
437 : : = mappings->lookup_bang_proc_macro_invocation (invocation);
438 : : if (!macro.has_value ())
439 : : {
440 : : rust_error_at (invocation.get_locus (), "macro not found");
441 : : return AST::Fragment::create_error ();
442 : : }
443 : :
444 : : AST::TokenCollector collector;
445 : :
446 : : collector.visit (item);
447 : :
448 : : auto c = collector.collect_tokens ();
449 : : std::vector<const_TokenPtr> vec (c.cbegin (), c.cend ());
450 : :
451 : : return parse_proc_macro_output (
452 : : macro.value ().get_handle () (convert (vec)));
453 : : }
454 : :
455 : : template <typename T>
456 : 1 : AST::Fragment expand_attribute_proc_macro (T &item, AST::SimplePath &path)
457 : : {
458 : : tl::optional<AttributeProcMacro &> macro
459 : 1 : = mappings->lookup_attribute_proc_macro_invocation (path);
460 : 1 : if (!macro.has_value ())
461 : : {
462 : 1 : rust_error_at (path.get_locus (), "macro not found");
463 : 1 : return AST::Fragment::create_error ();
464 : : }
465 : :
466 : 0 : AST::TokenCollector collector;
467 : :
468 : 0 : collector.visit (item);
469 : :
470 : 0 : auto c = collector.collect_tokens ();
471 : 0 : std::vector<const_TokenPtr> vec (c.cbegin (), c.cend ());
472 : :
473 : : // FIXME: Handle attributes
474 : : return parse_proc_macro_output (
475 : 0 : macro.value ().get_handle () (ProcMacro::TokenStream::make_tokenstream (),
476 : 0 : convert (vec)));
477 : 0 : }
478 : :
479 : : /**
480 : : * Has the MacroExpander expanded a macro since its state was last reset?
481 : : */
482 : 5280 : bool has_changed () const { return has_changed_flag; }
483 : :
484 : : /**
485 : : * Reset the expander's "changed" state. This function should be executed at
486 : : * each iteration in a fixed point loop
487 : : */
488 : 5280 : void reset_changed_state () { has_changed_flag = false; }
489 : :
490 : : tl::optional<AST::MacroRulesDefinition &> &get_last_definition ()
491 : : {
492 : : return last_def;
493 : : }
494 : :
495 : : tl::optional<AST::MacroInvocation &> &get_last_invocation ()
496 : : {
497 : : return last_invoc;
498 : : }
499 : :
500 : : private:
501 : : AST::Fragment parse_proc_macro_output (ProcMacro::TokenStream ts);
502 : :
503 : : AST::Crate &crate;
504 : : Session &session;
505 : : SubstitutionScope sub_stack;
506 : : std::vector<ContextType> context;
507 : : AST::Fragment expanded_fragment;
508 : : bool has_changed_flag;
509 : :
510 : : tl::optional<AST::MacroRulesDefinition &> last_def;
511 : : tl::optional<AST::MacroInvocation &> last_invoc;
512 : :
513 : : public:
514 : : Resolver::Resolver *resolver;
515 : : Analysis::Mappings *mappings;
516 : : };
517 : :
518 : : } // namespace Rust
519 : :
520 : : #endif
|