Changes in / [abcb393:1c80f20]
- Location:
- src
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Pass.proto.hpp
rabcb393 r1c80f20 18 18 19 19 #include "Common/Stats/Heap.h" 20 21 20 namespace ast { 22 template<typename core_t> 23 class Pass; 24 25 class TranslationUnit; 26 27 struct PureVisitor; 28 29 template<typename node_t> 30 node_t * deepCopy( const node_t * localRoot ); 31 32 namespace __pass { 33 typedef std::function<void( void * )> cleanup_func_t; 34 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t; 35 36 37 // boolean reference that may be null 38 // either refers to a boolean value or is null and returns true 39 class bool_ref { 40 public: 41 bool_ref() = default; 42 ~bool_ref() = default; 43 44 operator bool() { return m_ref ? *m_ref : true; } 45 bool operator=( bool val ) { assert(m_ref); return *m_ref = val; } 46 47 private: 48 49 friend class visit_children_guard; 50 51 bool * set( bool * val ) { 52 bool * prev = m_ref; 53 m_ref = val; 54 return prev; 55 } 56 57 bool * m_ref = nullptr; 21 template<typename core_t> class Pass; 22 class TranslationUnit; 23 struct PureVisitor; 24 template<typename node_t> node_t * deepCopy( const node_t * ); 25 } 26 27 namespace ast::__pass { 28 29 typedef std::function<void( void * )> cleanup_func_t; 30 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t; 31 32 // boolean reference that may be null 33 // either refers to a boolean value or is null and returns true 34 class bool_ref { 35 public: 36 bool_ref() = default; 37 ~bool_ref() = default; 38 39 operator bool() { return m_ref ? *m_ref : true; } 40 bool operator=( bool val ) { assert(m_ref); return *m_ref = val; } 41 42 private: 43 44 friend class visit_children_guard; 45 46 bool * set( bool * val ) { 47 bool * prev = m_ref; 48 m_ref = val; 49 return prev; 50 } 51 52 bool * m_ref = nullptr; 53 }; 54 55 // Implementation of the guard value 56 // Created inside the visit scope 57 class guard_value { 58 public: 59 /// Push onto the cleanup 60 guard_value( at_cleanup_t * at_cleanup ) { 61 if( at_cleanup ) { 62 *at_cleanup = [this]( cleanup_func_t && func, void* val ) { 63 push( std::move( func ), val ); 64 }; 65 } 66 } 67 68 ~guard_value() { 69 while( !cleanups.empty() ) { 70 auto& cleanup = cleanups.top(); 71 cleanup.func( cleanup.val ); 72 cleanups.pop(); 73 } 74 } 75 76 void push( cleanup_func_t && func, void* val ) { 77 cleanups.emplace( std::move(func), val ); 78 } 79 80 private: 81 struct cleanup_t { 82 cleanup_func_t func; 83 void * val; 84 85 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {} 58 86 }; 59 87 60 // Implementation of the guard value 61 // Created inside the visit scope 62 class guard_value { 63 public: 64 /// Push onto the cleanup 65 guard_value( at_cleanup_t * at_cleanup ) { 66 if( at_cleanup ) { 67 *at_cleanup = [this]( cleanup_func_t && func, void* val ) { 68 push( std::move( func ), val ); 69 }; 70 } 71 } 72 73 ~guard_value() { 74 while( !cleanups.empty() ) { 75 auto& cleanup = cleanups.top(); 76 cleanup.func( cleanup.val ); 77 cleanups.pop(); 78 } 79 } 80 81 void push( cleanup_func_t && func, void* val ) { 82 cleanups.emplace( std::move(func), val ); 83 } 84 85 private: 86 struct cleanup_t { 87 cleanup_func_t func; 88 void * val; 89 90 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {} 91 }; 92 93 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups; 88 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups; 89 }; 90 91 // Guard structure implementation for whether or not children should be visited 92 class visit_children_guard { 93 public: 94 95 visit_children_guard( bool_ref * ref ) 96 : m_val ( true ) 97 , m_prev( ref ? ref->set( &m_val ) : nullptr ) 98 , m_ref ( ref ) 99 {} 100 101 ~visit_children_guard() { 102 if( m_ref ) { 103 m_ref->set( m_prev ); 104 } 105 } 106 107 operator bool() { return m_val; } 108 109 private: 110 bool m_val; 111 bool * m_prev; 112 bool_ref * m_ref; 113 }; 114 115 /// "Short hand" to check if this is a valid previsit function 116 /// Mostly used to make the static_assert look (and print) prettier 117 template<typename core_t, typename node_t> 118 struct is_valid_previsit { 119 using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) ); 120 121 static constexpr bool value = std::is_void< ret_t >::value || 122 std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value; 123 }; 124 125 /// The result is a single node. 126 template< typename node_t > 127 struct result1 { 128 bool differs = false; 129 const node_t * value = nullptr; 130 131 template< typename object_t, typename super_t, typename field_t > 132 void apply( object_t *, field_t super_t::* field ); 133 }; 134 135 /// The result is a container of statements. 136 template< template<class...> class container_t > 137 struct resultNstmt { 138 /// The delta/change on a single node. 139 struct delta { 140 ptr<Stmt> new_val; 141 ssize_t old_idx; 142 bool is_old; 143 144 delta(const Stmt * s, ssize_t i, bool old) : 145 new_val(s), old_idx(i), is_old(old) {} 94 146 }; 95 147 96 // Guard structure implementation for whether or not children should be visited 97 class visit_children_guard { 98 public: 99 100 visit_children_guard( bool_ref * ref ) 101 : m_val ( true ) 102 , m_prev( ref ? ref->set( &m_val ) : nullptr ) 103 , m_ref ( ref ) 104 {} 105 106 ~visit_children_guard() { 107 if( m_ref ) { 108 m_ref->set( m_prev ); 109 } 110 } 111 112 operator bool() { return m_val; } 113 114 private: 115 bool m_val; 116 bool * m_prev; 117 bool_ref * m_ref; 118 }; 119 120 /// "Short hand" to check if this is a valid previsit function 121 /// Mostly used to make the static_assert look (and print) prettier 148 bool differs = false; 149 container_t< delta > values; 150 151 template< typename object_t, typename super_t, typename field_t > 152 void apply( object_t *, field_t super_t::* field ); 153 154 template< template<class...> class incontainer_t > 155 void take_all( incontainer_t<ptr<Stmt>> * stmts ); 156 157 template< template<class...> class incontainer_t > 158 void take_all( incontainer_t<ptr<Decl>> * decls ); 159 }; 160 161 /// The result is a container of nodes. 162 template< template<class...> class container_t, typename node_t > 163 struct resultN { 164 bool differs = false; 165 container_t<ptr<node_t>> values; 166 167 template< typename object_t, typename super_t, typename field_t > 168 void apply( object_t *, field_t super_t::* field ); 169 }; 170 171 /// Used by previsit implementation 172 /// We need to reassign the result to 'node', unless the function 173 /// returns void, then we just leave 'node' unchanged 174 template<bool is_void> 175 struct __assign; 176 177 template<> 178 struct __assign<true> { 122 179 template<typename core_t, typename node_t> 123 struct is_valid_previsit { 124 using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) ); 125 126 static constexpr bool value = std::is_void< ret_t >::value || 127 std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value; 128 }; 129 130 /// The result is a single node. 131 template< typename node_t > 132 struct result1 { 133 bool differs = false; 134 const node_t * value = nullptr; 135 136 template< typename object_t, typename super_t, typename field_t > 137 void apply( object_t *, field_t super_t::* field ); 138 }; 139 140 /// The result is a container of statements. 141 template< template<class...> class container_t > 142 struct resultNstmt { 143 /// The delta/change on a single node. 144 struct delta { 145 ptr<Stmt> new_val; 146 ssize_t old_idx; 147 bool is_old; 148 149 delta(const Stmt * s, ssize_t i, bool old) : 150 new_val(s), old_idx(i), is_old(old) {} 151 }; 152 153 bool differs = false; 154 container_t< delta > values; 155 156 template< typename object_t, typename super_t, typename field_t > 157 void apply( object_t *, field_t super_t::* field ); 158 159 template< template<class...> class incontainer_t > 160 void take_all( incontainer_t<ptr<Stmt>> * stmts ); 161 162 template< template<class...> class incontainer_t > 163 void take_all( incontainer_t<ptr<Decl>> * decls ); 164 }; 165 166 /// The result is a container of nodes. 167 template< template<class...> class container_t, typename node_t > 168 struct resultN { 169 bool differs = false; 170 container_t<ptr<node_t>> values; 171 172 template< typename object_t, typename super_t, typename field_t > 173 void apply( object_t *, field_t super_t::* field ); 174 }; 175 176 /// Used by previsit implementation 177 /// We need to reassign the result to 'node', unless the function 178 /// returns void, then we just leave 'node' unchanged 179 template<bool is_void> 180 struct __assign; 181 182 template<> 183 struct __assign<true> { 184 template<typename core_t, typename node_t> 185 static inline void result( core_t & core, const node_t * & node ) { 186 core.previsit( node ); 187 } 188 }; 189 190 template<> 191 struct __assign<false> { 192 template<typename core_t, typename node_t> 193 static inline void result( core_t & core, const node_t * & node ) { 194 node = core.previsit( node ); 195 assertf(node, "Previsit must not return NULL"); 196 } 197 }; 198 199 /// Used by postvisit implementation 200 /// We need to return the result unless the function 201 /// returns void, then we just return the original node 202 template<bool is_void> 203 struct __return; 204 205 template<> 206 struct __return<true> { 207 template<typename core_t, typename node_t> 208 static inline const node_t * result( core_t & core, const node_t * & node ) { 209 core.postvisit( node ); 210 return node; 211 } 212 }; 213 214 template<> 215 struct __return<false> { 216 template<typename core_t, typename node_t> 217 static inline auto result( core_t & core, const node_t * & node ) { 218 return core.postvisit( node ); 219 } 220 }; 221 222 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 223 // Deep magic (a.k.a template meta programming) to make the templated visitor work 224 // Basically the goal is to make 2 previsit 225 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 226 // 'pass.previsit( node )' that compiles will be used for that node for that type 227 // This requires that this option only compile for passes that actually define an appropriate visit. 228 // SFINAE will make sure the compilation errors in this function don't halt the build. 229 // See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE 230 // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing. 231 // This is needed only to eliminate the need for passes to specify any kind of handlers. 232 // The second implementation only works because it has a lower priority. This is due to the bogus last parameter. 233 // The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0 234 // the first implementation takes priority in regards to overloading. 235 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 236 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call 180 static inline void result( core_t & core, const node_t * & node ) { 181 core.previsit( node ); 182 } 183 }; 184 185 template<> 186 struct __assign<false> { 237 187 template<typename core_t, typename node_t> 238 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 239 static_assert( 240 is_valid_previsit<core_t, node_t>::value, 241 "Previsit may not change the type of the node. It must return its paremeter or void." 242 ); 243 244 __assign< 245 std::is_void< 246 decltype( core.previsit( node ) ) 247 >::value 248 >::result( core, node ); 249 } 250 188 static inline void result( core_t & core, const node_t * & node ) { 189 node = core.previsit( node ); 190 assertf(node, "Previsit must not return NULL"); 191 } 192 }; 193 194 /// Used by postvisit implementation 195 /// We need to return the result unless the function 196 /// returns void, then we just return the original node 197 template<bool is_void> 198 struct __return; 199 200 template<> 201 struct __return<true> { 251 202 template<typename core_t, typename node_t> 252 static inline auto previsit( core_t &, const node_t *, long ) {} 253 254 // PostVisit : never mutates the passed pointer but may return a different node 203 static inline const node_t * result( core_t & core, const node_t * & node ) { 204 core.postvisit( node ); 205 return node; 206 } 207 }; 208 209 template<> 210 struct __return<false> { 255 211 template<typename core_t, typename node_t> 256 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 257 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 258 { 259 return __return< 260 std::is_void< 261 decltype( core.postvisit( node ) ) 262 >::value 263 >::result( core, node ); 264 } 265 266 template<typename core_t, typename node_t> 267 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 268 269 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 270 // Deep magic (a.k.a template meta programming) continued 271 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit 272 // from in order to get extra functionallity for example 273 // class ErrorChecker : WithShortCircuiting { ... }; 274 // Pass<ErrorChecker> checker; 275 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting 276 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched 277 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 278 // For several accessories, the feature is enabled by detecting that a specific field is present 279 // Use a macro the encapsulate the logic of detecting a particular field 280 // The type is not strictly enforced but does match the accessory 281 #define FIELD_PTR( name, default_type ) \ 282 template< typename core_t > \ 283 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 212 static inline auto result( core_t & core, const node_t * & node ) { 213 return core.postvisit( node ); 214 } 215 }; 216 217 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 218 // Deep magic (a.k.a template meta programming) to make the templated visitor work 219 // Basically the goal is to make 2 previsit 220 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 221 // 'pass.previsit( node )' that compiles will be used for that node for that type 222 // This requires that this option only compile for passes that actually define an appropriate visit. 223 // SFINAE will make sure the compilation errors in this function don't halt the build. 224 // See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE 225 // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing. 226 // This is needed only to eliminate the need for passes to specify any kind of handlers. 227 // The second implementation only works because it has a lower priority. This is due to the bogus last parameter. 228 // The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0 229 // the first implementation takes priority in regards to overloading. 230 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 231 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call 232 template<typename core_t, typename node_t> 233 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 234 static_assert( 235 is_valid_previsit<core_t, node_t>::value, 236 "Previsit may not change the type of the node. It must return its paremeter or void." 237 ); 238 239 __assign< 240 std::is_void< 241 decltype( core.previsit( node ) ) 242 >::value 243 >::result( core, node ); 244 } 245 246 template<typename core_t, typename node_t> 247 static inline auto previsit( core_t &, const node_t *, long ) {} 248 249 // PostVisit : never mutates the passed pointer but may return a different node 250 template<typename core_t, typename node_t> 251 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 252 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 253 { 254 return __return< 255 std::is_void< 256 decltype( core.postvisit( node ) ) 257 >::value 258 >::result( core, node ); 259 } 260 261 template<typename core_t, typename node_t> 262 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 263 264 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 265 // Deep magic (a.k.a template meta programming) continued 266 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit 267 // from in order to get extra functionallity for example 268 // class ErrorChecker : WithShortCircuiting { ... }; 269 // Pass<ErrorChecker> checker; 270 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting 271 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched 272 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 273 // For several accessories, the feature is enabled by detecting that a specific field is present 274 // Use a macro the encapsulate the logic of detecting a particular field 275 // The type is not strictly enforced but does match the accessory 276 #define FIELD_PTR( name, default_type ) \ 277 template< typename core_t > \ 278 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 279 \ 280 template< typename core_t > \ 281 static inline default_type * name( core_t &, long ) { return nullptr; } 282 283 // List of fields and their expected types 284 FIELD_PTR( typeSubs, const ast::TypeSubstitution * ) 285 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > ) 286 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > ) 287 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > ) 288 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > ) 289 FIELD_PTR( visit_children, __pass::bool_ref ) 290 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 291 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 292 293 // Remove the macro to make sure we don't clash 294 #undef FIELD_PTR 295 296 template< typename core_t > 297 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 298 // Stats::Heap::stacktrace_push(core_t::traceId); 299 } 300 301 template< typename core_t > 302 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 303 // Stats::Heap::stacktrace_pop(); 304 } 305 306 template< typename core_t > 307 static void beginTrace(core_t &, long) {} 308 309 template< typename core_t > 310 static void endTrace(core_t &, long) {} 311 312 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error. 313 // If on_error() returns false, the error will be ignored. By default, it returns true. 314 315 template< typename core_t > 316 static bool on_error (core_t &, ptr<Decl> &, long) { return true; } 317 318 template< typename core_t > 319 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) { 320 return core.on_error(decl); 321 } 322 323 template< typename core_t, typename node_t > 324 static auto make_location_guard( core_t & core, node_t * node, int ) 325 -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) { 326 ValueGuardPtr<const CodeLocation *> guard( &core.location ); 327 core.location = &node->location; 328 return guard; 329 } 330 331 template< typename core_t, typename node_t > 332 static auto make_location_guard( core_t &, node_t *, long ) -> int { 333 return 0; 334 } 335 336 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. 337 // All passes which have such functions are assumed desire this behaviour 338 // detect it using the same strategy 339 namespace scope { 340 template<typename core_t> 341 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 342 core.beginScope(); 343 } 344 345 template<typename core_t> 346 static inline void enter( core_t &, long ) {} 347 348 template<typename core_t> 349 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 350 core.endScope(); 351 } 352 353 template<typename core_t> 354 static inline void leave( core_t &, long ) {} 355 } // namespace scope 356 357 // Certain passes desire an up to date symbol table automatically 358 // detect the presence of a member name `symtab` and call all the members appropriately 359 namespace symtab { 360 // Some simple scoping rules 361 template<typename core_t> 362 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 363 core.symtab.enterScope(); 364 } 365 366 template<typename core_t> 367 static inline auto enter( core_t &, long ) {} 368 369 template<typename core_t> 370 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 371 core.symtab.leaveScope(); 372 } 373 374 template<typename core_t> 375 static inline auto leave( core_t &, long ) {} 376 377 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 378 // Create macro to condense these common patterns 379 #define SYMTAB_FUNC1( func, type ) \ 380 template<typename core_t> \ 381 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 382 core.symtab.func( arg ); \ 383 } \ 284 384 \ 285 template< typename core_t > \ 286 static inline default_type * name( core_t &, long ) { return nullptr; } 287 288 // List of fields and their expected types 289 FIELD_PTR( typeSubs, const ast::TypeSubstitution * ) 290 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > ) 291 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > ) 292 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > ) 293 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > ) 294 FIELD_PTR( visit_children, __pass::bool_ref ) 295 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 296 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 297 298 // Remove the macro to make sure we don't clash 299 #undef FIELD_PTR 300 301 template< typename core_t > 302 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 303 // Stats::Heap::stacktrace_push(core_t::traceId); 304 } 305 306 template< typename core_t > 307 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 308 // Stats::Heap::stacktrace_pop(); 309 } 310 311 template< typename core_t > 312 static void beginTrace(core_t &, long) {} 313 314 template< typename core_t > 315 static void endTrace(core_t &, long) {} 316 317 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error. 318 // If onError() returns false, the error will be ignored. By default, it returns true. 319 320 template< typename core_t > 321 static bool on_error (core_t &, ptr<Decl> &, long) { return true; } 322 323 template< typename core_t > 324 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) { 325 return core.on_error(decl); 326 } 327 328 template< typename core_t, typename node_t > 329 static auto make_location_guard( core_t & core, node_t * node, int ) 330 -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) { 331 ValueGuardPtr<const CodeLocation *> guard( &core.location ); 332 core.location = &node->location; 333 return guard; 334 } 335 336 template< typename core_t, typename node_t > 337 static auto make_location_guard( core_t &, node_t *, long ) -> int { 338 return 0; 339 } 340 341 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. 342 // All passes which have such functions are assumed desire this behaviour 343 // detect it using the same strategy 344 namespace scope { 345 template<typename core_t> 346 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 347 core.beginScope(); 348 } 349 350 template<typename core_t> 351 static inline void enter( core_t &, long ) {} 352 353 template<typename core_t> 354 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 355 core.endScope(); 356 } 357 358 template<typename core_t> 359 static inline void leave( core_t &, long ) {} 360 } // namespace scope 361 362 // Certain passes desire an up to date symbol table automatically 363 // detect the presence of a member name `symtab` and call all the members appropriately 364 namespace symtab { 365 // Some simple scoping rules 366 template<typename core_t> 367 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 368 core.symtab.enterScope(); 369 } 370 371 template<typename core_t> 372 static inline auto enter( core_t &, long ) {} 373 374 template<typename core_t> 375 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 376 core.symtab.leaveScope(); 377 } 378 379 template<typename core_t> 380 static inline auto leave( core_t &, long ) {} 381 382 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 383 // Create macro to condense these common patterns 384 #define SYMTAB_FUNC1( func, type ) \ 385 template<typename core_t> \ 386 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 387 core.symtab.func( arg ); \ 388 } \ 389 \ 390 template<typename core_t> \ 391 static inline void func( core_t &, long, type ) {} 392 393 #define SYMTAB_FUNC2( func, type1, type2 ) \ 394 template<typename core_t> \ 395 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\ 396 core.symtab.func( arg1, arg2 ); \ 397 } \ 398 \ 399 template<typename core_t> \ 400 static inline void func( core_t &, long, type1, type2 ) {} 401 402 SYMTAB_FUNC1( addId , const DeclWithType * ); 403 SYMTAB_FUNC1( addType , const NamedTypeDecl * ); 404 SYMTAB_FUNC1( addStruct , const StructDecl * ); 405 SYMTAB_FUNC1( addEnum , const EnumDecl * ); 406 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 407 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 408 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 409 410 // A few extra functions have more complicated behaviour, they are hand written 411 template<typename core_t> 412 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) { 413 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name ); 414 for ( const auto & param : decl->params ) { 415 fwd->params.push_back( deepCopy( param.get() ) ); 416 } 417 core.symtab.addStruct( fwd ); 418 } 419 420 template<typename core_t> 421 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {} 422 423 template<typename core_t> 424 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) { 425 ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name ); 426 for ( const auto & param : decl->params ) { 427 fwd->params.push_back( deepCopy( param.get() ) ); 428 } 429 core.symtab.addUnion( fwd ); 430 } 431 432 template<typename core_t> 433 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {} 434 435 template<typename core_t> 436 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) { 437 if ( ! core.symtab.lookupStruct( str ) ) { 438 core.symtab.addStruct( str ); 439 } 440 } 441 442 template<typename core_t> 443 static inline void addStruct( core_t &, long, const std::string & ) {} 444 445 template<typename core_t> 446 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) { 447 if ( ! core.symtab.lookupUnion( str ) ) { 448 core.symtab.addUnion( str ); 449 } 450 } 451 452 template<typename core_t> 453 static inline void addUnion( core_t &, long, const std::string & ) {} 454 455 #undef SYMTAB_FUNC1 456 #undef SYMTAB_FUNC2 457 } // namespace symtab 458 459 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 460 // Detect the presence of a member name `subs` and call all members appropriately 461 namespace forall { 462 // Some simple scoping rules 463 template<typename core_t> 464 static inline auto enter( core_t & core, int, const ast::FunctionType * type ) 465 -> decltype( core.subs, void() ) { 466 if ( ! type->forall.empty() ) core.subs.beginScope(); 467 } 468 469 template<typename core_t> 470 static inline auto enter( core_t &, long, const ast::FunctionType * ) {} 471 472 template<typename core_t> 473 static inline auto leave( core_t & core, int, const ast::FunctionType * type ) 474 -> decltype( core.subs, void() ) { 475 if ( ! type->forall.empty() ) { core.subs.endScope(); } 476 } 477 478 template<typename core_t> 479 static inline auto leave( core_t &, long, const ast::FunctionType * ) {} 480 481 // Replaces a TypeInstType's base TypeDecl according to the table 482 template<typename core_t> 483 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 484 -> decltype( core.subs, void() ) { 485 inst = ast::mutate_field( 486 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 487 } 488 489 template<typename core_t> 490 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 491 } // namespace forall 492 493 // For passes that need access to the global context. Sreaches `translationUnit` 494 namespace translation_unit { 495 template<typename core_t> 496 static inline auto get_cptr( core_t & core, int ) 497 -> decltype( &core.translationUnit ) { 498 return &core.translationUnit; 499 } 500 501 template<typename core_t> 502 static inline const TranslationUnit ** get_cptr( core_t &, long ) { 503 return nullptr; 504 } 505 } 506 507 // For passes, usually utility passes, that have a result. 508 namespace result { 509 template<typename core_t> 510 static inline auto get( core_t & core, char ) -> decltype( core.result() ) { 511 return core.result(); 512 } 513 514 template<typename core_t> 515 static inline auto get( core_t & core, int ) -> decltype( core.result ) { 516 return core.result; 517 } 518 519 template<typename core_t> 520 static inline void get( core_t &, long ) {} 521 } 522 } // namespace __pass 523 } // namespace ast 385 template<typename core_t> \ 386 static inline void func( core_t &, long, type ) {} 387 388 #define SYMTAB_FUNC2( func, type1, type2 ) \ 389 template<typename core_t> \ 390 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\ 391 core.symtab.func( arg1, arg2 ); \ 392 } \ 393 \ 394 template<typename core_t> \ 395 static inline void func( core_t &, long, type1, type2 ) {} 396 397 SYMTAB_FUNC1( addId , const DeclWithType * ); 398 SYMTAB_FUNC1( addType , const NamedTypeDecl * ); 399 SYMTAB_FUNC1( addStruct , const StructDecl * ); 400 SYMTAB_FUNC1( addEnum , const EnumDecl * ); 401 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 402 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 403 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 404 405 // A few extra functions have more complicated behaviour, they are hand written 406 template<typename core_t> 407 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) { 408 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name ); 409 for ( const auto & param : decl->params ) { 410 fwd->params.push_back( deepCopy( param.get() ) ); 411 } 412 core.symtab.addStruct( fwd ); 413 } 414 415 template<typename core_t> 416 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {} 417 418 template<typename core_t> 419 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) { 420 ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name ); 421 for ( const auto & param : decl->params ) { 422 fwd->params.push_back( deepCopy( param.get() ) ); 423 } 424 core.symtab.addUnion( fwd ); 425 } 426 427 template<typename core_t> 428 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {} 429 430 template<typename core_t> 431 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) { 432 if ( ! core.symtab.lookupStruct( str ) ) { 433 core.symtab.addStruct( str ); 434 } 435 } 436 437 template<typename core_t> 438 static inline void addStruct( core_t &, long, const std::string & ) {} 439 440 template<typename core_t> 441 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) { 442 if ( ! core.symtab.lookupUnion( str ) ) { 443 core.symtab.addUnion( str ); 444 } 445 } 446 447 template<typename core_t> 448 static inline void addUnion( core_t &, long, const std::string & ) {} 449 450 #undef SYMTAB_FUNC1 451 #undef SYMTAB_FUNC2 452 } // namespace symtab 453 454 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 455 // Detect the presence of a member name `subs` and call all members appropriately 456 namespace forall { 457 // Some simple scoping rules 458 template<typename core_t> 459 static inline auto enter( core_t & core, int, const ast::FunctionType * type ) 460 -> decltype( core.subs, void() ) { 461 if ( ! type->forall.empty() ) core.subs.beginScope(); 462 } 463 464 template<typename core_t> 465 static inline auto enter( core_t &, long, const ast::FunctionType * ) {} 466 467 template<typename core_t> 468 static inline auto leave( core_t & core, int, const ast::FunctionType * type ) 469 -> decltype( core.subs, void() ) { 470 if ( ! type->forall.empty() ) { core.subs.endScope(); } 471 } 472 473 template<typename core_t> 474 static inline auto leave( core_t &, long, const ast::FunctionType * ) {} 475 476 // Replaces a TypeInstType's base TypeDecl according to the table 477 template<typename core_t> 478 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 479 -> decltype( core.subs, void() ) { 480 inst = ast::mutate_field( 481 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 482 } 483 484 template<typename core_t> 485 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 486 } // namespace forall 487 488 // For passes that need access to the global context. Searches `translationUnit` 489 namespace translation_unit { 490 template<typename core_t> 491 static inline auto get_cptr( core_t & core, int ) 492 -> decltype( &core.translationUnit ) { 493 return &core.translationUnit; 494 } 495 496 template<typename core_t> 497 static inline const TranslationUnit ** get_cptr( core_t &, long ) { 498 return nullptr; 499 } 500 } 501 502 // For passes, usually utility passes, that have a result. 503 namespace result { 504 template<typename core_t> 505 static inline auto get( core_t & core, char ) -> decltype( core.result() ) { 506 return core.result(); 507 } 508 509 template<typename core_t> 510 static inline auto get( core_t & core, int ) -> decltype( core.result ) { 511 return core.result; 512 } 513 514 template<typename core_t> 515 static inline void get( core_t &, long ) {} 516 } 517 518 } // namespace ast::__pass -
src/Common/utility.h
rabcb393 r1c80f20 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Apr 25 14:26:00 202213 // Update Count : 5 112 // Last Modified On : Thr Feb 16 12:35:00 2023 13 // Update Count : 52 14 14 // 15 15 … … 49 49 return 0; 50 50 } // if 51 }52 53 template< typename T, typename U >54 struct maybeBuild_t {55 static T * doit( const U *orig ) {56 if ( orig ) {57 return orig->build();58 } else {59 return 0;60 } // if61 }62 };63 64 template< typename T, typename U >65 static inline T * maybeBuild( const U *orig ) {66 return maybeBuild_t<T,U>::doit(orig);67 }68 69 template< typename T, typename U >70 static inline T * maybeMoveBuild( const U *orig ) {71 T* ret = maybeBuild<T>(orig);72 delete orig;73 return ret;74 51 } 75 52 -
src/Parser/ParseNode.h
rabcb393 r1c80f20 27 27 #include "Common/SemanticError.h" // for SemanticError 28 28 #include "Common/UniqueName.h" // for UniqueName 29 #include "Common/utility.h" // for maybeClone, maybeBuild 29 #include "Common/utility.h" // for maybeClone 30 #include "Parser/parserutility.h" // for maybeBuild 30 31 #include "SynTree/LinkageSpec.h" // for Spec 31 32 #include "SynTree/Declaration.h" // for Aggregate -
src/Parser/RunParser.cpp
rabcb393 r1c80f20 10 10 // Created On : Mon Dec 19 11:00:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Dec 22 10:18:00 202213 // Update Count : 112 // Last Modified On : Thr Feb 16 10:08:00 2023 13 // Update Count : 2 14 14 // 15 15 … … 24 24 25 25 // Variables global to the parsing code. 26 LinkageSpec::Spec linkage = LinkageSpec::Cforall;26 ast::Linkage::Spec linkage = ast::Linkage::Cforall; 27 27 TypedefTable typedefTable; 28 28 DeclarationNode * parseTree = nullptr; 29 29 30 void parse( FILE * input, LinkageSpec::Spec linkage, bool alwaysExit ) {30 void parse( FILE * input, ast::Linkage::Spec linkage, bool alwaysExit ) { 31 31 extern int yyparse( void ); 32 32 extern FILE * yyin; -
src/Parser/RunParser.hpp
rabcb393 r1c80f20 10 10 // Created On : Mon Dec 19 10:42:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Dec 22 10:23:00 202213 // Update Count : 112 // Last Modified On : Thr Feb 16 10:08:00 2023 13 // Update Count : 2 14 14 // 15 15 … … 18 18 #include <iosfwd> // for ostream 19 19 20 #include " SynTree/LinkageSpec.h"// for Spec20 #include "AST/LinkageSpec.hpp" // for Spec 21 21 namespace ast { 22 22 class TranslationUnit; … … 29 29 /// The input file is closed when complete. Exits instead of returning on 30 30 /// error or if alwaysExit is true. 31 void parse( FILE * input, LinkageSpec::Spec linkage, bool alwaysExit = false );31 void parse( FILE * input, ast::Linkage::Spec linkage, bool alwaysExit = false ); 32 32 33 33 /// Drain the internal accumulator of parsed code and build a translation -
src/Parser/parserutility.h
rabcb393 r1c80f20 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // parserutility.h -- 7 // parserutility.h -- Collected utilities for the parser. 8 8 // 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Sat May 16 15:31:46 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:32:58 201713 // Update Count : 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Feb 16 12:34:00 2023 13 // Update Count : 5 14 14 // 15 15 … … 20 20 Expression *notZeroExpr( Expression *orig ); 21 21 22 template< typename T, typename U > 23 struct maybeBuild_t { 24 static T * doit( const U *orig ) { 25 if ( orig ) { 26 return orig->build(); 27 } else { 28 return 0; 29 } 30 } 31 }; 32 33 template< typename T, typename U > 34 static inline T * maybeBuild( const U *orig ) { 35 return maybeBuild_t<T,U>::doit(orig); 36 } 37 38 template< typename T, typename U > 39 static inline T * maybeMoveBuild( const U *orig ) { 40 T* ret = maybeBuild<T>(orig); 41 delete orig; 42 return ret; 43 } 44 22 45 // Local Variables: // 23 46 // tab-width: 4 // -
src/main.cc
rabcb393 r1c80f20 10 10 // Created On : Fri May 15 23:12:02 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Oct 5 12:06:00 202213 // Update Count : 6 7912 // Last Modified On : Thr Feb 16 10:08:00 2023 13 // Update Count : 680 14 14 // 15 15 … … 272 272 FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf").c_str(), "r" ); 273 273 assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" ); 274 parse( gcc_builtins, LinkageSpec::Compiler );274 parse( gcc_builtins, ast::Linkage::Compiler ); 275 275 276 276 // read the extra prelude in, if not generating the cfa library 277 277 FILE * extras = fopen( (PreludeDirector + "/extras.cf").c_str(), "r" ); 278 278 assertf( extras, "cannot open extras.cf\n" ); 279 parse( extras, LinkageSpec::BuiltinC );279 parse( extras, ast::Linkage::BuiltinC ); 280 280 281 281 if ( ! libcfap ) { … … 283 283 FILE * prelude = fopen( (PreludeDirector + "/prelude.cfa").c_str(), "r" ); 284 284 assertf( prelude, "cannot open prelude.cfa\n" ); 285 parse( prelude, LinkageSpec::Intrinsic );285 parse( prelude, ast::Linkage::Intrinsic ); 286 286 287 287 // Read to cfa builtins, if not generating the cfa library 288 288 FILE * builtins = fopen( (PreludeDirector + "/builtins.cf").c_str(), "r" ); 289 289 assertf( builtins, "cannot open builtins.cf\n" ); 290 parse( builtins, LinkageSpec::BuiltinCFA );291 } // if 292 } // if 293 294 parse( input, libcfap ? LinkageSpec::Intrinsic : LinkageSpec::Cforall, yydebug );290 parse( builtins, ast::Linkage::BuiltinCFA ); 291 } // if 292 } // if 293 294 parse( input, libcfap ? ast::Linkage::Intrinsic : ast::Linkage::Cforall, yydebug ); 295 295 296 296 transUnit = buildUnit(); … … 340 340 PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) ); 341 341 342 PASS( "Implement Actors", Concurrency::implementActors( transUnit ) ); 343 342 PASS( "Implement Actors", Concurrency::implementActors( transUnit ) ); 344 343 PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) ); 345 344 PASS( "Implement Thread Start", Concurrency::implementThreadStarter( transUnit ) );
Note: See TracChangeset
for help on using the changeset viewer.