source: src/AST/Pass.impl.hpp @ 712348a

ADTarm-ehast-experimentalcleanup-dtorsenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 712348a was 04124c4, checked in by Thierry Delisle <tdelisle@…>, 6 years ago

More comments and naming conventions fix

  • Property mode set to 100644
File size: 14.2 KB
RevLine 
[04124c4]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
[f47f887]16#pragma once
[04124c4]17// IWYU pragma: private, include "AST/Pass.hpp"
[f47f887]18
19#define VISIT_START( node ) \
[04124c4]20        using namespace ast; \
[f47f887]21        /* back-up the visit children */ \
[04124c4]22        __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
[f47f887]23        /* setup the scope for passes that want to run code at exit */ \
[04124c4]24        __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (pass, 0) ); \
[f47f887]25        /* call the implementation of the previsit of this pass */ \
[04124c4]26        __pass::previsit( pass, node, 0 );
[f47f887]27
28#define VISIT( code ) \
29        /* if this node should visit its children */ \
30        if ( __visit_children() ) { \
31                /* visit the children */ \
32                code \
33        }
34
35#define VISIT_END( type, node ) \
36        /* call the implementation of the postvisit of this pass */ \
37        auto __return = __pass::postvisit< type * >( node ); \
38        assertf(__return, "post visit should never return null"); \
39        return __return;
40
41#ifdef PEDANTIC_PASS_ASSERT
42#define __pedantic_pass_assert (...) assert (__VAR_ARGS__)
43#define __pedantic_pass_assertf(...) assertf(__VAR_ARGS__)
44#else
45#define __pedantic_pass_assert (...)
46#define __pedantic_pass_assertf(...)
47#endif
48
49namespace ast {
50        namespace __pass {
51                // Check if this is either a null pointer or a pointer to an empty container
52                template<typename T>
53                static inline bool empty( T * ptr ) {
54                        return !ptr || ptr->empty();
55                }
56
57                template<typename it_t, template <class> class container_t>
58                static inline void take_all( it_t it, container_t<ast::ptr<ast::Declaration>> * decls, bool * mutated = nullptr ) {
59                        if(empty(decls)) return;
60
61                        std::transform(decls->begin(), decls->end(), it, [](Declaration * decl) -> auto {
62                                        return new DeclStmt( decl );
63                                });
64                        decls->clear();
65                        if(mutated) *mutated = true;
66                }
67
68                template<typename it_t, template <class> class container_t>
69                static inline void take_all( it_t it, container_t<ast::ptr<ast::Statement>> * decls, bool * mutated = nullptr ) {
70                        if(empty(decls)) return;
71
72                        std::move(decls->begin(), decls->end(), it);
73                        decls->clear();
74                        if(mutated) *mutated = true;
75                }
76
77                template<typename node_t>
78                bool differs( const node_t * old_val, const node_t * new_val ) {
79                        return old_val != new_val;
80                }
81
82                template< template <class> class container_t >
83                bool differs( const container_t<ast::ptr< ast::Statement >> &, const container_t<ast::ptr< ast::Statement >> & new_val ) {
84                        return !new_val.empty();
85                }
86        }
87
88        template<typename parent_t, typename child_t>
89        template< typename pass_t >
90        void Pass< pass_t >::maybe_accept(
91                const parent_t * & parent,
92                const typename parent_t::child_t * child
93        ) {
94                const auto & old_val = parent->*child;
95                if(!old_val) return;
96
97                auto new_val = call_accept(old_val);
98
99                if( __pass::differs(old_val, new_val) ) {
100                        auto new_parent = mutate(parent);
101                        new_parent->*child = new_val;
102                        parent = new_parent;
103                }
104        }
105
106        template< typename pass_t >
107        template< typename node_t >
108        auto Pass< pass_t >::call_accept( const node_t * node ) {
109                __pedantic_pass_assert( __visit_children() );
110                __pedantic_pass_assert( expr );
111
112                return node->accept( *this );
113        }
114
115        template< typename pass_t >
[04124c4]116        ast::Expr * Pass< pass_t >::call_accept( const ast::Expr * expr ) {
[f47f887]117                __pedantic_pass_assert( __visit_children() );
118                __pedantic_pass_assert( expr );
119
[04124c4]120                const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
[f47f887]121                if ( env_ptr && expr->env ) {
122                        *env_ptr = expr->env;
123                }
124
125                return expr->accept( *this );
126        }
127
128        template< typename pass_t >
[04124c4]129        Stmt * Pass< pass_t >::call_accept( const Stmt * stmt ) {
[f47f887]130                __pedantic_pass_assert( __visit_children() );
131                __pedantic_pass_assert( stmt );
132
133                // add a few useful symbols to the scope
134                using __pass::empty;
135
136                // get the stmts/decls that will need to be spliced in
[04124c4]137                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
138                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
139                auto decls_before = __pass::declsToAddBefore( pass, 0);
140                auto decls_after  = __pass::declsToAddAfter ( pass, 0);
[f47f887]141
142                // These may be modified by subnode but most be restored once we exit this statemnet.
[04124c4]143                ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0);  );
[f47f887]144                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
145                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after  );
146                ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > __old_stmts_before( decls_before );
147                ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after  );
148
149                // Now is the time to actually visit the node
150                ast::Statement * nstmt = stmt->accept( *this );
151
152                // If the pass doesn't want to add anything then we are done
153                if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
154                        return nstmt;
155                }
156
157                // Make sure that it is either adding statements or declartions but not both
158                // this is because otherwise the order would be awkward to predict
159                assert(( empty( stmts_before ) && empty( stmts_after ))
160                    || ( empty( decls_before ) && empty( decls_after )) );
161
162                // Create a new Compound Statement to hold the new decls/stmts
163                ast::CompoundStmt * compound = new ast::CompoundStmt( parent->*child.location );
164
165                // Take all the declarations that go before
166                __pass::take_all( std::back_inserter( compound->kids ), decls_before );
167                __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
168
169                // Insert the original declaration
170                compound->kids.push_back( nstmt );
171
172                // Insert all the declarations that go before
173                __pass::take_all( std::back_inserter( compound->kids ), decls_after );
174                __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
175
176                return compound;
177        }
178
179        template< typename pass_t >
180        template< template <class> class container_t >
[04124c4]181        container_t< ptr<Stmt> > Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
[f47f887]182                __pedantic_pass_assert( __visit_children() );
183                if( statements.empty() ) return {};
184
185                // We are going to aggregate errors for all these statements
186                SemanticErrorException errors;
187
188                // add a few useful symbols to the scope
189                using __pass::empty;
190
191                // get the stmts/decls that will need to be spliced in
192                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
193                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
194                auto decls_before = __pass::declsToAddBefore( pass, 0);
195                auto decls_after  = __pass::declsToAddAfter ( pass, 0);
196
197                // These may be modified by subnode but most be restored once we exit this statemnet.
198                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
199                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after  );
200                ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > __old_stmts_before( decls_before );
201                ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after  );
202
203                // update pass statitistics
204                pass_visitor_stats.depth++;
205                pass_visitor_stats.max->push(pass_visitor_stats.depth);
206                pass_visitor_stats.avg->push(pass_visitor_stats.depth);
207
208                bool mutated = false;
[04124c4]209                container_t< ptr<Stmt> > new_kids;
210                for( const Stmt * stmt : statements ) {
[f47f887]211                        try {
212                                __pedantic_pass_assert( stmt );
213                                const ast::Statment * new_stmt = stmt->accept( visitor );
214                                assert( new_stmt );
215                                if(new_stmt != stmt ) mutated = true;
216
217                                // Make sure that it is either adding statements or declartions but not both
218                                // this is because otherwise the order would be awkward to predict
219                                assert(( empty( stmts_before ) && empty( stmts_after ))
220                                    || ( empty( decls_before ) && empty( decls_after )) );
221
222
223
224                                // Take all the statements which should have gone after, N/A for first iteration
225                                __pass::take_all( std::back_inserter( new_kids ), decls_before, &mutated );
226                                __pass::take_all( std::back_inserter( new_kids ), stmts_before, &mutated );
227
228                                // Now add the statement if there is one
229                                new_kids.emplace_back( new_stmt );
230
231                                // Take all the declarations that go before
232                                __pass::take_all( std::back_inserter( new_kids ), decls_after, &mutated );
233                                __pass::take_all( std::back_inserter( new_kids ), stmts_after, &mutated );
234                        }
235                        catch ( SemanticErrorException &e ) {
236                                errors.append( e );
237                        }
238                }
239                pass_visitor_stats.depth--;
240                if ( !errors.isEmpty() ) { throw errors; }
241
242                return mutated ? new_kids : {};
243        }
244
245        template< typename pass_t >
246        template< template <class> class container_t, typename node_t >
247        container_t< ast::ptr<node_t> > Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
248                __pedantic_pass_assert( __visit_children() );
249                if( container.empty() ) return {};
250                SemanticErrorException errors;
251
252                pass_visitor_stats.depth++;
253                pass_visitor_stats.max->push(pass_visitor_stats.depth);
254                pass_visitor_stats.avg->push(pass_visitor_stats.depth);
255
256                bool mutated = false;
257                container_t< ast::ptr<node_t> > new_kids;
258                for ( const node_t * node : container ) {
259                        try {
260                                __pedantic_pass_assert( node );
261                                const node_t * new_node = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
262                                if(new_stmt != stmt ) mutated = true;
263
264                                new_kids.emplace_back( new_stmt );
265                        }
266                        catch( SemanticErrorException &e ) {
267                                errors.append( e );
268                        }
269                }
270                pass_visitor_stats.depth--;
271                if ( ! errors.isEmpty() ) { throw errors; }
272
273                return mutated ? new_kids : {};
274        }
275}
276
277//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
278//========================================================================================================================================================================
279//========================================================================================================================================================================
280//========================================================================================================================================================================
281//========================================================================================================================================================================
282//========================================================================================================================================================================
283//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
284
[04124c4]285template< typename pass_t >
286inline void ast::acceptAll( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
287        // We are going to aggregate errors for all these statements
288        SemanticErrorException errors;
289
290        // add a few useful symbols to the scope
291        using __pass::empty;
292
293        // get the stmts/decls that will need to be spliced in
294        auto decls_before = __pass::declsToAddBefore( pass, 0);
295        auto decls_after  = __pass::declsToAddAfter ( pass, 0);
296
297        // update pass statitistics
298        pass_visitor_stats.depth++;
299        pass_visitor_stats.max->push(pass_visitor_stats.depth);
300        pass_visitor_stats.avg->push(pass_visitor_stats.depth);
301
302        for ( std::list< ast::ptr<ast::Decl> >::iterator i = decls.begin(); ; ++i ) {
303                // splice in new declarations after previous decl
304                if ( !empty( decls_after ) ) { decls.splice( i, *decls_after ); }
305
306                if ( i == decls.end() ) break;
307
308                try {
309                        // run visitor on declaration
310                        ast::ptr<ast::Decl> & node = *i;
311                        assert( node );
312                        node = node->accept( visitor );
313                }
314                catch( SemanticErrorException &e ) {
315                        errors.append( e );
316                }
317
318                // splice in new declarations before current decl
319                if ( !empty( decls_before ) ) { decls.splice( i, *decls_before ); }
320        }
321        pass_visitor_stats.depth--;
322        if ( !errors.isEmpty() ) { throw errors; }
323}
324
[f47f887]325// A NOTE ON THE ORDER OF TRAVERSAL
326//
327// Types and typedefs have their base types visited before they are added to the type table.  This is ok, since there is
328// no such thing as a recursive type or typedef.
329//
330//             typedef struct { T *x; } T; // never allowed
331//
332// for structs/unions, it is possible to have recursion, so the decl should be added as if it's incomplete to begin, the
333// members are traversed, and then the complete type should be added (assuming the type is completed by this particular
334// declaration).
335//
336//             struct T { struct T *x; }; // allowed
337//
338// It is important to add the complete type to the symbol table *after* the members/base has been traversed, since that
339// traversal may modify the definition of the type and these modifications should be visible when the symbol table is
340// queried later in this pass.
341
342//--------------------------------------------------------------------------
343// ObjectDecl
344template< typename pass_t >
[04124c4]345ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
[f47f887]346        VISIT_START( node );
347
348        VISIT(
349                {
[04124c4]350                        indexer_guard guard { *this };
351                        maybe_accept( node, ObjectDecl::type );
[f47f887]352                }
[04124c4]353                maybe_accept( node, ObjectDecl::init          );
354                maybe_accept( node, ObjectDecl::bitfieldWidth );
355                maybe_accept( node, ObjectDecl::attributes    );
[f47f887]356        )
357
[04124c4]358        __pass::indexer::AddId( pass, 0, node );
[f47f887]359
[04124c4]360        VISIT_END( DeclWithType, node );
[f47f887]361}
362
363//--------------------------------------------------------------------------
364// Attribute
365template< typename pass_type >
[04124c4]366ast::Attribute * ast::Pass< pass_type >::visit( const ast::Attribute * node  )  {
[f47f887]367        VISIT_START(node);
368
369        VISIT(
370                maybe_accept( node, ast::Attribute::parameters );
371        )
372
373        VISIT_END(ast::Attribute *, node );
374}
375
376//--------------------------------------------------------------------------
377// TypeSubstitution
378template< typename pass_type >
[04124c4]379TypeSubstitution * PassVisitor< pass_type >::mutate( const TypeSubstitution * node ) {
[f47f887]380        MUTATE_START( node );
381
382        #error this is broken
383
384        for ( auto & p : node->typeEnv ) {
385                indexerScopedMutate( p.second, *this );
386        }
387        for ( auto & p : node->varEnv ) {
388                indexerScopedMutate( p.second, *this );
389        }
390
391        MUTATE_END( TypeSubstitution, node );
392}
393
394#undef VISIT_START
395#undef VISIT
396#undef VISIT_END
Note: See TracBrowser for help on using the repository browser.