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

ADT arm-eh ast-experimental cleanup-dtors enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since b96d7c1 was f47f887, checked in by Thierry Delisle <tdelisle@…>, 6 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.