source: src/AST/Pass.impl.hpp@ 23f99e1

ADT arm-eh ast-experimental cleanup-dtors enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 23f99e1 was 23f99e1, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

Finished implementing declarations

  • Property mode set to 100644
File size: 23.7 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// Pass.impl.hpp --
8//
9// Author : Thierry Delisle
10// Created On : Thu May 09 15::37::05 2019
11// Last Modified By :
12// Last Modified On :
13// Update Count :
14//
15
16#pragma once
17// IWYU pragma: private, include "AST/Pass.hpp"
18
19#include <type_traits>
20#include <unordered_map>
21
22#define VISIT_START( node ) \
23 using namespace ast; \
24 /* back-up the visit children */ \
25 __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
26 /* setup the scope for passes that want to run code at exit */ \
27 __attribute__((unused)) ast::__pass::guard_value guard2( ast::__pass::at_cleanup (pass, 0) ); \
28 /* call the implementation of the previsit of this pass */ \
29 __pass::previsit( pass, node, 0 );
30
31#define VISIT( code... ) \
32 /* if this node should visit its children */ \
33 if ( __visit_children() ) { \
34 /* visit the children */ \
35 code \
36 }
37
38#define VISIT_END( type, node ) \
39 /* call the implementation of the postvisit of this pass */ \
40 auto __return = __pass::postvisit( pass, node, 0 ); \
41 assertf(__return, "post visit should never return null"); \
42 return __return;
43
44#ifdef PEDANTIC_PASS_ASSERT
45#define __pedantic_pass_assert(...) assert (__VA_ARGS__)
46#define __pedantic_pass_assertf(...) assertf(__VA_ARGS__)
47#else
48#define __pedantic_pass_assert(...)
49#define __pedantic_pass_assertf(...)
50#endif
51
52namespace ast {
53 namespace __pass {
54 // Check if this is either a null pointer or a pointer to an empty container
55 template<typename T>
56 static inline bool empty( T * ptr ) {
57 return !ptr || ptr->empty();
58 }
59
60 //------------------------------
61 template<typename it_t, template <class...> class container_t>
62 static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) {
63 if(empty(decls)) return;
64
65 std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto {
66 return new DeclStmt( decl );
67 });
68 decls->clear();
69 if(mutated) *mutated = true;
70 }
71
72 template<typename it_t, template <class...> class container_t>
73 static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * decls, bool * mutated = nullptr ) {
74 if(empty(decls)) return;
75
76 std::move(decls->begin(), decls->end(), it);
77 decls->clear();
78 if(mutated) *mutated = true;
79 }
80
81 //------------------------------
82 /// Check if should be skipped, different for pointers and containers
83 template<typename node_t>
84 bool skip( const ast::ptr<node_t> & val) {
85 return !val;
86 }
87
88 template< template <class...> class container_t, typename node_t >
89 bool skip( const container_t<ast::ptr< node_t >> & val ) {
90 return val.empty();
91 }
92
93 //------------------------------
94 /// Get the value to visit, different for pointers and containers
95 template<typename node_t>
96 auto get( const ast::ptr<node_t> & val, int ) -> decltype(val.get()) {
97 return val.get();
98 }
99
100 template<typename node_t>
101 const node_t & get( const node_t & val, long) {
102 return val;
103 }
104
105
106 //------------------------------
107 /// Check if value was mutated, different for pointers and containers
108 template<typename lhs_t, typename rhs_t>
109 bool differs( const lhs_t * old_val, const rhs_t * new_val ) {
110 return old_val != new_val;
111 }
112
113 template< template <class...> class container_t, typename node_t >
114 bool differs( const container_t<ast::ptr< node_t >> &, const container_t<ast::ptr< node_t >> & new_val ) {
115 return !new_val.empty();
116 }
117 }
118
119 template< typename pass_t >
120 template< typename node_t >
121 auto Pass< pass_t >::call_accept( const node_t * node ) -> decltype( node->accept(*this) ) {
122 __pedantic_pass_assert( __visit_children() );
123 __pedantic_pass_assert( expr );
124
125 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
126 static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR");
127
128 return node->accept( *this );
129 }
130
131 template< typename pass_t >
132 const ast::Expr * Pass< pass_t >::call_accept( const ast::Expr * expr ) {
133 __pedantic_pass_assert( __visit_children() );
134 __pedantic_pass_assert( expr );
135
136 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
137 if ( env_ptr && expr->env ) {
138 *env_ptr = expr->env;
139 }
140
141 return expr->accept( *this );
142 }
143
144 template< typename pass_t >
145 const ast::Stmt * Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
146 __pedantic_pass_assert( __visit_children() );
147 __pedantic_pass_assert( stmt );
148
149 // add a few useful symbols to the scope
150 using __pass::empty;
151
152 // get the stmts/decls that will need to be spliced in
153 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
154 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);
155 auto decls_before = __pass::declsToAddBefore( pass, 0);
156 auto decls_after = __pass::declsToAddAfter ( pass, 0);
157
158 // These may be modified by subnode but most be restored once we exit this statemnet.
159 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::env( pass, 0) );
160 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
161 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after );
162 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
163 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after );
164
165 // Now is the time to actually visit the node
166 const ast::Stmt * nstmt = stmt->accept( *this );
167
168 // If the pass doesn't want to add anything then we are done
169 if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
170 return nstmt;
171 }
172
173 // Make sure that it is either adding statements or declartions but not both
174 // this is because otherwise the order would be awkward to predict
175 assert(( empty( stmts_before ) && empty( stmts_after ))
176 || ( empty( decls_before ) && empty( decls_after )) );
177
178 // Create a new Compound Statement to hold the new decls/stmts
179 ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location );
180
181 // Take all the declarations that go before
182 __pass::take_all( std::back_inserter( compound->kids ), decls_before );
183 __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
184
185 // Insert the original declaration
186 compound->kids.emplace_back( nstmt );
187
188 // Insert all the declarations that go before
189 __pass::take_all( std::back_inserter( compound->kids ), decls_after );
190 __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
191
192 return compound;
193 }
194
195 template< typename pass_t >
196 template< template <class...> class container_t >
197 container_t< ptr<Stmt> > Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
198 __pedantic_pass_assert( __visit_children() );
199 if( statements.empty() ) return {};
200
201 // We are going to aggregate errors for all these statements
202 SemanticErrorException errors;
203
204 // add a few useful symbols to the scope
205 using __pass::empty;
206
207 // get the stmts/decls that will need to be spliced in
208 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
209 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);
210 auto decls_before = __pass::declsToAddBefore( pass, 0);
211 auto decls_after = __pass::declsToAddAfter ( pass, 0);
212
213 // These may be modified by subnode but most be restored once we exit this statemnet.
214 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
215 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after );
216 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
217 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after );
218
219 // update pass statitistics
220 pass_visitor_stats.depth++;
221 pass_visitor_stats.max->push(pass_visitor_stats.depth);
222 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
223
224 bool mutated = false;
225 container_t< ptr<Stmt> > new_kids;
226 for( const Stmt * stmt : statements ) {
227 try {
228 __pedantic_pass_assert( stmt );
229 const ast::Stmt * new_stmt = stmt->accept( *this );
230 assert( new_stmt );
231 if(new_stmt != stmt ) mutated = true;
232
233 // Make sure that it is either adding statements or declartions but not both
234 // this is because otherwise the order would be awkward to predict
235 assert(( empty( stmts_before ) && empty( stmts_after ))
236 || ( empty( decls_before ) && empty( decls_after )) );
237
238
239
240 // Take all the statements which should have gone after, N/A for first iteration
241 __pass::take_all( std::back_inserter( new_kids ), decls_before, &mutated );
242 __pass::take_all( std::back_inserter( new_kids ), stmts_before, &mutated );
243
244 // Now add the statement if there is one
245 new_kids.emplace_back( new_stmt );
246
247 // Take all the declarations that go before
248 __pass::take_all( std::back_inserter( new_kids ), decls_after, &mutated );
249 __pass::take_all( std::back_inserter( new_kids ), stmts_after, &mutated );
250 }
251 catch ( SemanticErrorException &e ) {
252 errors.append( e );
253 }
254 }
255 pass_visitor_stats.depth--;
256 if ( !errors.isEmpty() ) { throw errors; }
257
258 return mutated ? new_kids : container_t< ptr<Stmt> >();
259 }
260
261 template< typename pass_t >
262 template< template <class...> class container_t, typename node_t >
263 container_t< ast::ptr<node_t> > Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
264 __pedantic_pass_assert( __visit_children() );
265 if( container.empty() ) return {};
266 SemanticErrorException errors;
267
268 pass_visitor_stats.depth++;
269 pass_visitor_stats.max->push(pass_visitor_stats.depth);
270 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
271
272 bool mutated = false;
273 container_t< ast::ptr<node_t> > new_kids;
274 for ( const node_t * node : container ) {
275 try {
276 __pedantic_pass_assert( node );
277 const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
278 if(new_stmt != node ) mutated = true;
279
280 new_kids.emplace_back( new_stmt );
281 }
282 catch( SemanticErrorException &e ) {
283 errors.append( e );
284 }
285 }
286 pass_visitor_stats.depth--;
287 if ( ! errors.isEmpty() ) { throw errors; }
288
289 return mutated ? new_kids : container_t< ast::ptr<node_t> >();
290 }
291
292 template< typename pass_t >
293 template<typename node_t, typename parent_t, typename child_t>
294 void Pass< pass_t >::maybe_accept(
295 const node_t * & parent,
296 child_t parent_t::*child
297 ) {
298 static_assert( std::is_base_of<parent_t, node_t>::value, "Error deductiing member object" );
299
300 if(__pass::skip(parent->*child)) return;
301 const auto & old_val = __pass::get(parent->*child, 0);
302
303 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
304
305 auto new_val = call_accept( old_val );
306
307 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
308
309 if( __pass::differs(old_val, new_val) ) {
310 auto new_parent = mutate(parent);
311 new_parent->*child = new_val;
312 parent = new_parent;
313 }
314 }
315
316}
317
318//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
319//========================================================================================================================================================================
320//========================================================================================================================================================================
321//========================================================================================================================================================================
322//========================================================================================================================================================================
323//========================================================================================================================================================================
324//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
325
326template< typename pass_t >
327inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
328 // We are going to aggregate errors for all these statements
329 SemanticErrorException errors;
330
331 // add a few useful symbols to the scope
332 using __pass::empty;
333
334 // get the stmts/decls that will need to be spliced in
335 auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
336 auto decls_after = __pass::declsToAddAfter ( visitor.pass, 0);
337
338 // update pass statitistics
339 pass_visitor_stats.depth++;
340 pass_visitor_stats.max->push(pass_visitor_stats.depth);
341 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
342
343 for ( std::list< ast::ptr<ast::Decl> >::iterator i = decls.begin(); ; ++i ) {
344 // splice in new declarations after previous decl
345 if ( !empty( decls_after ) ) { decls.splice( i, *decls_after ); }
346
347 if ( i == decls.end() ) break;
348
349 try {
350 // run visitor on declaration
351 ast::ptr<ast::Decl> & node = *i;
352 assert( node );
353 node = node->accept( visitor );
354 }
355 catch( SemanticErrorException &e ) {
356 errors.append( e );
357 }
358
359 // splice in new declarations before current decl
360 if ( !empty( decls_before ) ) { decls.splice( i, *decls_before ); }
361 }
362 pass_visitor_stats.depth--;
363 if ( !errors.isEmpty() ) { throw errors; }
364}
365
366// A NOTE ON THE ORDER OF TRAVERSAL
367//
368// Types and typedefs have their base types visited before they are added to the type table. This is ok, since there is
369// no such thing as a recursive type or typedef.
370//
371// typedef struct { T *x; } T; // never allowed
372//
373// for structs/unions, it is possible to have recursion, so the decl should be added as if it's incomplete to begin, the
374// members are traversed, and then the complete type should be added (assuming the type is completed by this particular
375// declaration).
376//
377// struct T { struct T *x; }; // allowed
378//
379// It is important to add the complete type to the symbol table *after* the members/base has been traversed, since that
380// traversal may modify the definition of the type and these modifications should be visible when the symbol table is
381// queried later in this pass.
382
383//--------------------------------------------------------------------------
384// ObjectDecl
385template< typename pass_t >
386const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
387 VISIT_START( node );
388
389 VISIT(
390 {
391 guard_indexer guard { *this };
392 maybe_accept( node, &ObjectDecl::type );
393 }
394 maybe_accept( node, &ObjectDecl::init );
395 maybe_accept( node, &ObjectDecl::bitfieldWidth );
396 maybe_accept( node, &ObjectDecl::attributes );
397 )
398
399 __pass::indexer::addId( pass, 0, node );
400
401 VISIT_END( DeclWithType, node );
402}
403
404//--------------------------------------------------------------------------
405// FunctionDecl
406template< typename pass_t >
407const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {
408 VISIT_START( node );
409
410 __pass::indexer::addId( pass, 0, node );
411
412 VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
413 {
414 // with clause introduces a level of scope (for the with expression members).
415 // with clause exprs are added to the indexer before parameters so that parameters
416 // shadow with exprs and not the other way around.
417 guard_indexer guard { *this };
418 __pass::indexer::addWith( pass, 0, node->withExprs, node );
419 {
420 guard_indexer guard { *this };
421 // implicit add __func__ identifier as specified in the C manual 6.4.2.2
422 static ast::ObjectDecl func(
423 node->location, "__func__",
424 new ast::ArrayType(
425 new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
426 nullptr, true, false
427 )
428 );
429 __pass::indexer::addId( pass, 0, &func );
430 VISIT(
431 maybe_accept( node, &FunctionDecl::type );
432 // function body needs to have the same scope as parameters - CompoundStmt will not enter
433 // a new scope if inFunction is true
434 ValueGuard< bool > oldInFunction( inFunction );
435 inFunction = true;
436 maybe_accept( node, &FunctionDecl::statements );
437 maybe_accept( node, &FunctionDecl::attributes );
438 )
439 }
440 }
441
442 VISIT_END( DeclWithType, node );
443}
444
445//--------------------------------------------------------------------------
446// StructDecl
447template< typename pass_t >
448const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {
449 VISIT_START( node );
450
451 // make up a forward declaration and add it before processing the members
452 // needs to be on the heap because addStruct saves the pointer
453 __pass::indexer::addStructFwd( pass, 0, node );
454
455 VISIT({
456 guard_indexer guard { * this };
457 maybe_accept( node, &StructDecl::parameters );
458 maybe_accept( node, &StructDecl::members );
459 })
460
461 // this addition replaces the forward declaration
462 __pass::indexer::addStruct( pass, 0, node );
463
464 VISIT_END( Decl, node );
465}
466
467//--------------------------------------------------------------------------
468// UnionDecl
469template< typename pass_t >
470const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {
471 VISIT_START( node );
472
473 // make up a forward declaration and add it before processing the members
474 __pass::indexer::addUnionFwd( pass, 0, node );
475
476 VISIT({
477 guard_indexer guard { * this };
478 maybe_accept( node, &UnionDecl::parameters );
479 maybe_accept( node, &UnionDecl::members );
480 })
481
482 __pass::indexer::addUnion( pass, 0, node );
483
484 VISIT_END( Decl, node );
485}
486
487//--------------------------------------------------------------------------
488// EnumDecl
489template< typename pass_t >
490const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {
491 VISIT_START( node );
492
493 __pass::indexer::addEnum( pass, 0, node );
494
495 VISIT(
496 // unlike structs, traits, and unions, enums inject their members into the global scope
497 maybe_accept( node, &EnumDecl::parameters );
498 maybe_accept( node, &EnumDecl::members );
499 )
500
501 VISIT_END( Decl, node );
502}
503
504//--------------------------------------------------------------------------
505// TraitDecl
506template< typename pass_t >
507const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {
508 VISIT_START( node );
509
510 VISIT({
511 guard_indexer guard { *this };
512 maybe_accept( node, &TraitDecl::parameters );
513 maybe_accept( node, &TraitDecl::members );
514 })
515
516 __pass::indexer::addTrait( pass, 0, node );
517
518 VISIT_END( Decl, node );
519}
520
521//--------------------------------------------------------------------------
522// TypeDecl
523template< typename pass_t >
524const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {
525 VISIT_START( node );
526
527 VISIT({
528 guard_indexer guard { *this };
529 maybe_accept( node, &TypeDecl::parameters );
530 maybe_accept( node, &TypeDecl::base );
531 })
532
533 // see A NOTE ON THE ORDER OF TRAVERSAL, above
534 // note that assertions come after the type is added to the symtab, since they are not part of the type proper
535 // and may depend on the type itself
536 __pass::indexer::addType( pass, 0, node );
537
538 VISIT(
539 maybe_accept( node, &TypeDecl::assertions, *this );
540
541 {
542 guard_indexer guard { *this };
543 maybe_accept( node, &TypeDecl::init );
544 }
545 )
546
547 VISIT_END( Decl, node );
548}
549
550//--------------------------------------------------------------------------
551// TypedefDecl
552template< typename pass_t >
553const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {
554 VISIT_START( node );
555
556 VISIT({
557 guard_indexer guard { *this };
558 maybe_accept( node, &TypedefDecl::parameters );
559 maybe_accept( node, &TypedefDecl::base );
560 })
561
562 __pass::indexer::addType( pass, 0, node );
563
564 maybe_accept( node, &TypedefDecl::assertions );
565
566 VISIT_END( Decl, node );
567}
568
569//--------------------------------------------------------------------------
570// AsmDecl
571template< typename pass_t >
572const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {
573 VISIT_START( node );
574
575 VISIT(
576 maybe_accept( node, &AsmDecl::stmt );
577 )
578
579 VISIT_END( AsmDecl, node );
580}
581
582//--------------------------------------------------------------------------
583// StaticAssertDecl
584template< typename pass_t >
585const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {
586 VISIT_START( node );
587
588 VISIT(
589 maybe_accept( node, &StaticAssertDecl::condition );
590 maybe_accept( node, &StaticAssertDecl::msg );
591 )
592
593 VISIT_END( StaticAssertDecl, node );
594}
595
596//--------------------------------------------------------------------------
597// CompoundStmt
598template< typename pass_t >
599const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {
600 VISIT_START( node );
601 VISIT({
602 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
603 auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
604 if ( ! inFunction ) __pass::indexer::enter(pass, 0);
605 }, [this, inFunction = this->inFunction]() {
606 if ( ! inFunction ) __pass::indexer::leave(pass, 0);
607 });
608 ValueGuard< bool > guard2( inFunction );
609 guard_scope guard3 { *this };
610 inFunction = false;
611 maybe_accept( node, &CompoundStmt::kids );
612 })
613 VISIT_END( CompoundStmt, node );
614}
615
616
617//--------------------------------------------------------------------------
618// SingleInit
619template< typename pass_t >
620const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
621 VISIT_START( node );
622
623 VISIT(
624 maybe_accept( node, &SingleInit::value );
625 )
626
627 VISIT_END( Init, node );
628}
629
630//--------------------------------------------------------------------------
631// ListInit
632template< typename pass_t >
633const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
634 VISIT_START( node );
635
636 VISIT(
637 maybe_accept( node, &ListInit::designations );
638 maybe_accept( node, &ListInit::initializers );
639 )
640
641 VISIT_END( Init, node );
642}
643
644//--------------------------------------------------------------------------
645// ConstructorInit
646template< typename pass_t >
647const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
648 VISIT_START( node );
649
650 VISIT(
651 maybe_accept( node, &ConstructorInit::ctor );
652 maybe_accept( node, &ConstructorInit::dtor );
653 maybe_accept( node, &ConstructorInit::init );
654 )
655
656 VISIT_END( Init, node );
657}
658
659//--------------------------------------------------------------------------
660// Attribute
661template< typename pass_t >
662const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node ) {
663 VISIT_START( node );
664
665 VISIT(
666 maybe_accept( node, &Attribute::parameters );
667 )
668
669 VISIT_END( Attribute *, node );
670}
671
672//--------------------------------------------------------------------------
673// TypeSubstitution
674template< typename pass_t >
675const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
676 VISIT_START( node );
677
678 VISIT(
679 {
680 bool mutated = false;
681 std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
682 for ( const auto & p : node->typeEnv ) {
683 guard_indexer guard { *this };
684 auto new_node = p.second->accept( *this );
685 if (new_node != p.second) mutated = false;
686 new_map.insert({ p.first, new_node });
687 }
688 if (mutated) {
689 auto new_node = mutate( node );
690 new_node->typeEnv.swap( new_map );
691 node = new_node;
692 }
693 }
694
695 {
696 bool mutated = false;
697 std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
698 for ( const auto & p : node->varEnv ) {
699 guard_indexer guard { *this };
700 auto new_node = p.second->accept( *this );
701 if (new_node != p.second) mutated = false;
702 new_map.insert({ p.first, new_node });
703 }
704 if (mutated) {
705 auto new_node = mutate( node );
706 new_node->varEnv.swap( new_map );
707 node = new_node;
708 }
709 }
710 )
711
712 VISIT_END( TypeSubstitution, node );
713}
714
715#undef VISIT_START
716#undef VISIT
717#undef VISIT_END
Note: See TracBrowser for help on using the repository browser.