source: src/AST/Pass.impl.hpp @ f47f887

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

First draft of Pass.hpp and some updates to node.hpp

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