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

arm-ehcleanup-dtorsjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-expr
Last change on this file since 23f99e1 was 23f99e1, checked in by Thierry Delisle <tdelisle@…>, 3 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.