source: src/AST/Pass.impl.hpp@ 204358b

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 204358b was 8a5530c, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

Fixed FunctionType cast, fixed maybe_accept, implemented statement visitation and fixed several nodes

  • Property mode set to 100644
File size: 25.9 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->location, 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 )
122 -> typename std::enable_if<
123 !std::is_base_of<ast::Expr, node_t>::value &&
124 !std::is_base_of<ast::Stmt, node_t>::value
125 , decltype( node->accept(*this) )
126 >::type
127
128 {
129 __pedantic_pass_assert( __visit_children() );
130 __pedantic_pass_assert( expr );
131
132 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
133 static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR");
134
135 return node->accept( *this );
136 }
137
138 template< typename pass_t >
139 const ast::Expr * Pass< pass_t >::call_accept( const ast::Expr * expr ) {
140 __pedantic_pass_assert( __visit_children() );
141 __pedantic_pass_assert( expr );
142
143 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
144 if ( env_ptr && expr->env ) {
145 *env_ptr = expr->env;
146 }
147
148 return expr->accept( *this );
149 }
150
151 template< typename pass_t >
152 const ast::Stmt * Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
153 __pedantic_pass_assert( __visit_children() );
154 __pedantic_pass_assert( stmt );
155
156 // add a few useful symbols to the scope
157 using __pass::empty;
158
159 // get the stmts/decls that will need to be spliced in
160 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
161 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);
162 auto decls_before = __pass::declsToAddBefore( pass, 0);
163 auto decls_after = __pass::declsToAddAfter ( pass, 0);
164
165 // These may be modified by subnode but most be restored once we exit this statemnet.
166 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::env( pass, 0) );
167 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
168 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after );
169 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
170 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after );
171
172 // Now is the time to actually visit the node
173 const ast::Stmt * nstmt = stmt->accept( *this );
174
175 // If the pass doesn't want to add anything then we are done
176 if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
177 return nstmt;
178 }
179
180 // Make sure that it is either adding statements or declartions but not both
181 // this is because otherwise the order would be awkward to predict
182 assert(( empty( stmts_before ) && empty( stmts_after ))
183 || ( empty( decls_before ) && empty( decls_after )) );
184
185 // Create a new Compound Statement to hold the new decls/stmts
186 ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location );
187
188 // Take all the declarations that go before
189 __pass::take_all( std::back_inserter( compound->kids ), decls_before );
190 __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
191
192 // Insert the original declaration
193 compound->kids.emplace_back( nstmt );
194
195 // Insert all the declarations that go before
196 __pass::take_all( std::back_inserter( compound->kids ), decls_after );
197 __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
198
199 return compound;
200 }
201
202 template< typename pass_t >
203 template< template <class...> class container_t >
204 container_t< ptr<Stmt> > Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
205 __pedantic_pass_assert( __visit_children() );
206 if( statements.empty() ) return {};
207
208 // We are going to aggregate errors for all these statements
209 SemanticErrorException errors;
210
211 // add a few useful symbols to the scope
212 using __pass::empty;
213
214 // get the stmts/decls that will need to be spliced in
215 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
216 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);
217 auto decls_before = __pass::declsToAddBefore( pass, 0);
218 auto decls_after = __pass::declsToAddAfter ( pass, 0);
219
220 // These may be modified by subnode but most be restored once we exit this statemnet.
221 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
222 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after );
223 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
224 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after );
225
226 // update pass statitistics
227 pass_visitor_stats.depth++;
228 pass_visitor_stats.max->push(pass_visitor_stats.depth);
229 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
230
231 bool mutated = false;
232 container_t< ptr<Stmt> > new_kids;
233 for( const Stmt * stmt : statements ) {
234 try {
235 __pedantic_pass_assert( stmt );
236 const ast::Stmt * new_stmt = stmt->accept( *this );
237 assert( new_stmt );
238 if(new_stmt != stmt ) mutated = true;
239
240 // Make sure that it is either adding statements or declartions but not both
241 // this is because otherwise the order would be awkward to predict
242 assert(( empty( stmts_before ) && empty( stmts_after ))
243 || ( empty( decls_before ) && empty( decls_after )) );
244
245
246
247 // Take all the statements which should have gone after, N/A for first iteration
248 __pass::take_all( std::back_inserter( new_kids ), decls_before, &mutated );
249 __pass::take_all( std::back_inserter( new_kids ), stmts_before, &mutated );
250
251 // Now add the statement if there is one
252 new_kids.emplace_back( new_stmt );
253
254 // Take all the declarations that go before
255 __pass::take_all( std::back_inserter( new_kids ), decls_after, &mutated );
256 __pass::take_all( std::back_inserter( new_kids ), stmts_after, &mutated );
257 }
258 catch ( SemanticErrorException &e ) {
259 errors.append( e );
260 }
261 }
262 pass_visitor_stats.depth--;
263 if ( !errors.isEmpty() ) { throw errors; }
264
265 return mutated ? new_kids : container_t< ptr<Stmt> >();
266 }
267
268 template< typename pass_t >
269 template< template <class...> class container_t, typename node_t >
270 container_t< ast::ptr<node_t> > Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
271 __pedantic_pass_assert( __visit_children() );
272 if( container.empty() ) return {};
273 SemanticErrorException errors;
274
275 pass_visitor_stats.depth++;
276 pass_visitor_stats.max->push(pass_visitor_stats.depth);
277 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
278
279 bool mutated = false;
280 container_t< ast::ptr<node_t> > new_kids;
281 for ( const node_t * node : container ) {
282 try {
283 __pedantic_pass_assert( node );
284 const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
285 if(new_stmt != node ) mutated = true;
286
287 new_kids.emplace_back( new_stmt );
288 }
289 catch( SemanticErrorException &e ) {
290 errors.append( e );
291 }
292 }
293 pass_visitor_stats.depth--;
294 if ( ! errors.isEmpty() ) { throw errors; }
295
296 return mutated ? new_kids : container_t< ast::ptr<node_t> >();
297 }
298
299 template< typename pass_t >
300 template<typename node_t, typename parent_t, typename child_t>
301 void Pass< pass_t >::maybe_accept(
302 const node_t * & parent,
303 child_t parent_t::*child
304 ) {
305 static_assert( std::is_base_of<parent_t, node_t>::value, "Error deducing member object" );
306
307 if(__pass::skip(parent->*child)) return;
308 const auto & old_val = __pass::get(parent->*child, 0);
309
310 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
311
312 auto new_val = call_accept( old_val );
313
314 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
315
316 if( __pass::differs(old_val, new_val) ) {
317 auto new_parent = mutate(parent);
318 new_parent->*child = new_val;
319 parent = new_parent;
320 }
321 }
322
323}
324
325//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
326//========================================================================================================================================================================
327//========================================================================================================================================================================
328//========================================================================================================================================================================
329//========================================================================================================================================================================
330//========================================================================================================================================================================
331//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
332
333template< typename pass_t >
334inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
335 // We are going to aggregate errors for all these statements
336 SemanticErrorException errors;
337
338 // add a few useful symbols to the scope
339 using __pass::empty;
340
341 // get the stmts/decls that will need to be spliced in
342 auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
343 auto decls_after = __pass::declsToAddAfter ( visitor.pass, 0);
344
345 // update pass statitistics
346 pass_visitor_stats.depth++;
347 pass_visitor_stats.max->push(pass_visitor_stats.depth);
348 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
349
350 for ( std::list< ast::ptr<ast::Decl> >::iterator i = decls.begin(); ; ++i ) {
351 // splice in new declarations after previous decl
352 if ( !empty( decls_after ) ) { decls.splice( i, *decls_after ); }
353
354 if ( i == decls.end() ) break;
355
356 try {
357 // run visitor on declaration
358 ast::ptr<ast::Decl> & node = *i;
359 assert( node );
360 node = node->accept( visitor );
361 }
362 catch( SemanticErrorException &e ) {
363 errors.append( e );
364 }
365
366 // splice in new declarations before current decl
367 if ( !empty( decls_before ) ) { decls.splice( i, *decls_before ); }
368 }
369 pass_visitor_stats.depth--;
370 if ( !errors.isEmpty() ) { throw errors; }
371}
372
373// A NOTE ON THE ORDER OF TRAVERSAL
374//
375// Types and typedefs have their base types visited before they are added to the type table. This is ok, since there is
376// no such thing as a recursive type or typedef.
377//
378// typedef struct { T *x; } T; // never allowed
379//
380// for structs/unions, it is possible to have recursion, so the decl should be added as if it's incomplete to begin, the
381// members are traversed, and then the complete type should be added (assuming the type is completed by this particular
382// declaration).
383//
384// struct T { struct T *x; }; // allowed
385//
386// It is important to add the complete type to the symbol table *after* the members/base has been traversed, since that
387// traversal may modify the definition of the type and these modifications should be visible when the symbol table is
388// queried later in this pass.
389
390//--------------------------------------------------------------------------
391// ObjectDecl
392template< typename pass_t >
393const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
394 VISIT_START( node );
395
396 VISIT(
397 {
398 guard_indexer guard { *this };
399 maybe_accept( node, &ObjectDecl::type );
400 }
401 maybe_accept( node, &ObjectDecl::init );
402 maybe_accept( node, &ObjectDecl::bitfieldWidth );
403 maybe_accept( node, &ObjectDecl::attributes );
404 )
405
406 __pass::indexer::addId( pass, 0, node );
407
408 VISIT_END( DeclWithType, node );
409}
410
411//--------------------------------------------------------------------------
412// FunctionDecl
413template< typename pass_t >
414const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {
415 VISIT_START( node );
416
417 __pass::indexer::addId( pass, 0, node );
418
419 VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
420 {
421 // with clause introduces a level of scope (for the with expression members).
422 // with clause exprs are added to the indexer before parameters so that parameters
423 // shadow with exprs and not the other way around.
424 guard_indexer guard { *this };
425 __pass::indexer::addWith( pass, 0, node->withExprs, node );
426 {
427 guard_indexer guard { *this };
428 // implicit add __func__ identifier as specified in the C manual 6.4.2.2
429 static ast::ObjectDecl func(
430 node->location, "__func__",
431 new ast::ArrayType(
432 new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
433 nullptr, VariableLen, DynamicDim
434 )
435 );
436 __pass::indexer::addId( pass, 0, &func );
437 VISIT(
438 maybe_accept( node, &FunctionDecl::type );
439 // function body needs to have the same scope as parameters - CompoundStmt will not enter
440 // a new scope if inFunction is true
441 ValueGuard< bool > oldInFunction( inFunction );
442 inFunction = true;
443 maybe_accept( node, &FunctionDecl::stmts );
444 maybe_accept( node, &FunctionDecl::attributes );
445 )
446 }
447 }
448
449 VISIT_END( DeclWithType, node );
450}
451
452//--------------------------------------------------------------------------
453// StructDecl
454template< typename pass_t >
455const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {
456 VISIT_START( node );
457
458 // make up a forward declaration and add it before processing the members
459 // needs to be on the heap because addStruct saves the pointer
460 __pass::indexer::addStructFwd( pass, 0, node );
461
462 VISIT({
463 guard_indexer guard { * this };
464 maybe_accept( node, &StructDecl::parameters );
465 maybe_accept( node, &StructDecl::members );
466 })
467
468 // this addition replaces the forward declaration
469 __pass::indexer::addStruct( pass, 0, node );
470
471 VISIT_END( Decl, node );
472}
473
474//--------------------------------------------------------------------------
475// UnionDecl
476template< typename pass_t >
477const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {
478 VISIT_START( node );
479
480 // make up a forward declaration and add it before processing the members
481 __pass::indexer::addUnionFwd( pass, 0, node );
482
483 VISIT({
484 guard_indexer guard { * this };
485 maybe_accept( node, &UnionDecl::parameters );
486 maybe_accept( node, &UnionDecl::members );
487 })
488
489 __pass::indexer::addUnion( pass, 0, node );
490
491 VISIT_END( Decl, node );
492}
493
494//--------------------------------------------------------------------------
495// EnumDecl
496template< typename pass_t >
497const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {
498 VISIT_START( node );
499
500 __pass::indexer::addEnum( pass, 0, node );
501
502 VISIT(
503 // unlike structs, traits, and unions, enums inject their members into the global scope
504 maybe_accept( node, &EnumDecl::parameters );
505 maybe_accept( node, &EnumDecl::members );
506 )
507
508 VISIT_END( Decl, node );
509}
510
511//--------------------------------------------------------------------------
512// TraitDecl
513template< typename pass_t >
514const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {
515 VISIT_START( node );
516
517 VISIT({
518 guard_indexer guard { *this };
519 maybe_accept( node, &TraitDecl::parameters );
520 maybe_accept( node, &TraitDecl::members );
521 })
522
523 __pass::indexer::addTrait( pass, 0, node );
524
525 VISIT_END( Decl, node );
526}
527
528//--------------------------------------------------------------------------
529// TypeDecl
530template< typename pass_t >
531const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {
532 VISIT_START( node );
533
534 VISIT({
535 guard_indexer guard { *this };
536 maybe_accept( node, &TypeDecl::parameters );
537 maybe_accept( node, &TypeDecl::base );
538 })
539
540 // see A NOTE ON THE ORDER OF TRAVERSAL, above
541 // note that assertions come after the type is added to the symtab, since they are not part of the type proper
542 // and may depend on the type itself
543 __pass::indexer::addType( pass, 0, node );
544
545 VISIT(
546 maybe_accept( node, &TypeDecl::assertions );
547
548 {
549 guard_indexer guard { *this };
550 maybe_accept( node, &TypeDecl::init );
551 }
552 )
553
554 VISIT_END( Decl, node );
555}
556
557//--------------------------------------------------------------------------
558// TypedefDecl
559template< typename pass_t >
560const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {
561 VISIT_START( node );
562
563 VISIT({
564 guard_indexer guard { *this };
565 maybe_accept( node, &TypedefDecl::parameters );
566 maybe_accept( node, &TypedefDecl::base );
567 })
568
569 __pass::indexer::addType( pass, 0, node );
570
571 maybe_accept( node, &TypedefDecl::assertions );
572
573 VISIT_END( Decl, node );
574}
575
576//--------------------------------------------------------------------------
577// AsmDecl
578template< typename pass_t >
579const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {
580 VISIT_START( node );
581
582 VISIT(
583 maybe_accept( node, &AsmDecl::stmt );
584 )
585
586 VISIT_END( AsmDecl, node );
587}
588
589//--------------------------------------------------------------------------
590// StaticAssertDecl
591template< typename pass_t >
592const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {
593 VISIT_START( node );
594
595 VISIT(
596 maybe_accept( node, &StaticAssertDecl::condition );
597 maybe_accept( node, &StaticAssertDecl::msg );
598 )
599
600 VISIT_END( StaticAssertDecl, node );
601}
602
603//--------------------------------------------------------------------------
604// CompoundStmt
605template< typename pass_t >
606const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {
607 VISIT_START( node );
608 VISIT({
609 // do not enter a new scope if inFunction is true - needs to check old state before the assignment
610 auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
611 if ( ! inFunction ) __pass::indexer::enter(pass, 0);
612 }, [this, inFunction = this->inFunction]() {
613 if ( ! inFunction ) __pass::indexer::leave(pass, 0);
614 });
615 ValueGuard< bool > guard2( inFunction );
616 guard_scope guard3 { *this };
617 inFunction = false;
618 maybe_accept( node, &CompoundStmt::kids );
619 })
620 VISIT_END( CompoundStmt, node );
621}
622
623//--------------------------------------------------------------------------
624// ExprStmt
625template< typename pass_t >
626const ast::Stmt * ast::Pass< pass_t >::visit( const ExprStmt * node ) {
627 VISIT_START( node );
628
629 VISIT(
630 maybe_accept( node, &ExprStmt::expr );
631 )
632
633 VISIT_END( Stmt, node );
634}
635
636//--------------------------------------------------------------------------
637// AsmStmt
638template< typename pass_t >
639const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {
640 VISIT_START( node )
641
642 VISIT(
643 maybe_accept( node, &AsmStmt::instruction );
644 maybe_accept( node, &AsmStmt::output );
645 maybe_accept( node, &AsmStmt::input );
646 maybe_accept( node, &AsmStmt::clobber );
647 )
648
649 VISIT_END( Stmt, node );
650}
651
652//--------------------------------------------------------------------------
653// DirectiveStmt
654template< typename pass_t >
655const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {
656 VISIT_START( node )
657
658 VISIT_END( Stmt, node );
659}
660
661//--------------------------------------------------------------------------
662// IfStmt
663template< typename pass_t >
664const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {
665 VISIT_START( node );
666 VISIT({
667 // if statements introduce a level of scope (for the initialization)
668 guard_indexer guard { *this };
669 maybe_accept( node, &IfStmt::inits );
670 maybe_accept( node, &IfStmt::cond );
671 maybe_accept( node, &IfStmt::thenPart );
672 maybe_accept( node, &IfStmt::elsePart );
673 })
674 VISIT_END( Stmt, node );
675}
676
677//--------------------------------------------------------------------------
678// WhileStmt
679template< typename pass_t >
680const ast::Stmt * ast::Pass< pass_t >::visit( const WhileStmt * node ) {
681 VISIT_START( node );
682
683 VISIT({
684 // while statements introduce a level of scope (for the initialization)
685 guard_indexer guard { *this };
686 maybe_accept( node, &WhileStmt::inits );
687 maybe_accept( node, &WhileStmt::cond );
688 maybe_accept( node, &WhileStmt::body );
689 })
690
691 VISIT_END( Stmt, node );
692}
693
694//--------------------------------------------------------------------------
695// SingleInit
696template< typename pass_t >
697const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
698 VISIT_START( node );
699
700 VISIT(
701 maybe_accept( node, &SingleInit::value );
702 )
703
704 VISIT_END( Init, node );
705}
706
707//--------------------------------------------------------------------------
708// ListInit
709template< typename pass_t >
710const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
711 VISIT_START( node );
712
713 VISIT(
714 maybe_accept( node, &ListInit::designations );
715 maybe_accept( node, &ListInit::initializers );
716 )
717
718 VISIT_END( Init, node );
719}
720
721//--------------------------------------------------------------------------
722// ConstructorInit
723template< typename pass_t >
724const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
725 VISIT_START( node );
726
727 VISIT(
728 maybe_accept( node, &ConstructorInit::ctor );
729 maybe_accept( node, &ConstructorInit::dtor );
730 maybe_accept( node, &ConstructorInit::init );
731 )
732
733 VISIT_END( Init, node );
734}
735
736//--------------------------------------------------------------------------
737// Attribute
738template< typename pass_t >
739const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node ) {
740 VISIT_START( node );
741
742 VISIT(
743 maybe_accept( node, &Attribute::parameters );
744 )
745
746 VISIT_END( Attribute, node );
747}
748
749//--------------------------------------------------------------------------
750// TypeSubstitution
751template< typename pass_t >
752const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
753 VISIT_START( node );
754
755 VISIT(
756 {
757 bool mutated = false;
758 std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
759 for ( const auto & p : node->typeEnv ) {
760 guard_indexer guard { *this };
761 auto new_node = p.second->accept( *this );
762 if (new_node != p.second) mutated = false;
763 new_map.insert({ p.first, new_node });
764 }
765 if (mutated) {
766 auto new_node = mutate( node );
767 new_node->typeEnv.swap( new_map );
768 node = new_node;
769 }
770 }
771
772 {
773 bool mutated = false;
774 std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
775 for ( const auto & p : node->varEnv ) {
776 guard_indexer guard { *this };
777 auto new_node = p.second->accept( *this );
778 if (new_node != p.second) mutated = false;
779 new_map.insert({ p.first, new_node });
780 }
781 if (mutated) {
782 auto new_node = mutate( node );
783 new_node->varEnv.swap( new_map );
784 node = new_node;
785 }
786 }
787 )
788
789 VISIT_END( TypeSubstitution, node );
790}
791
792#undef VISIT_START
793#undef VISIT
794#undef VISIT_END
Note: See TracBrowser for help on using the repository browser.