source: src/AST/Pass.impl.hpp @ 10248ae0

ADTarm-ehast-experimentalcleanup-dtorsenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 10248ae0 was 8a5530c, checked in by Thierry Delisle <tdelisle@…>, 5 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.