Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Pass.proto.hpp

    refe89894 r95e5018  
    1717// IWYU pragma: private, include "Pass.hpp"
    1818
    19 #include "Common/Iterate.hpp"
    2019#include "Common/Stats/Heap.h"
     20
    2121namespace ast {
    22         template<typename core_t> class Pass;
    23         class TranslationUnit;
    24         struct PureVisitor;
    25         template<typename node_t> node_t * deepCopy( const node_t * );
    26 }
    27 
    28 #ifdef PEDANTIC_PASS_ASSERT
    29 #define __pedantic_pass_assert(...) assert(__VA_ARGS__)
    30 #define __pedantic_pass_assertf(...) assertf(__VA_ARGS__)
    31 #else
    32 #define __pedantic_pass_assert(...)
    33 #define __pedantic_pass_assertf(...)
    34 #endif
    35 
    36 namespace ast::__pass {
    37 
    38 typedef std::function<void( void * )> cleanup_func_t;
    39 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t;
    40 
    41 // boolean reference that may be null
    42 // either refers to a boolean value or is null and returns true
    43 class bool_ref {
    44 public:
    45         bool_ref() = default;
    46         ~bool_ref() = default;
    47 
    48         operator bool() { return m_ref ? *m_ref : true; }
    49         bool operator=( bool val ) { assert(m_ref); return *m_ref = val; }
    50 
    51 private:
    52 
    53         friend class visit_children_guard;
    54 
    55         bool * set( bool * val ) {
    56                 bool * prev = m_ref;
    57                 m_ref = val;
    58                 return prev;
    59         }
    60 
    61         bool * m_ref = nullptr;
    62 };
    63 
    64 // Implementation of the guard value
    65 // Created inside the visit scope
    66 class guard_value {
    67 public:
    68         /// Push onto the cleanup
    69         guard_value( at_cleanup_t * at_cleanup ) {
    70                 if( at_cleanup ) {
    71                         *at_cleanup = [this]( cleanup_func_t && func, void* val ) {
    72                                 push( std::move( func ), val );
    73                         };
    74                 }
    75         }
    76 
    77         ~guard_value() {
    78                 while( !cleanups.empty() ) {
    79                         auto& cleanup = cleanups.top();
    80                         cleanup.func( cleanup.val );
    81                         cleanups.pop();
    82                 }
    83         }
    84 
    85         void push( cleanup_func_t && func, void* val ) {
    86                 cleanups.emplace( std::move(func), val );
    87         }
    88 
    89 private:
    90         struct cleanup_t {
    91                 cleanup_func_t func;
    92                 void * val;
    93 
    94                 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {}
    95         };
    96 
    97         std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
    98 };
    99 
    100 // Guard structure implementation for whether or not children should be visited
    101 class visit_children_guard {
    102 public:
    103 
    104         visit_children_guard( bool_ref * ref )
    105                 : m_val ( true )
    106                 , m_prev( ref ? ref->set( &m_val ) : nullptr )
    107                 , m_ref ( ref )
    108         {}
    109 
    110         ~visit_children_guard() {
    111                 if( m_ref ) {
    112                         m_ref->set( m_prev );
    113                 }
    114         }
    115 
    116         operator bool() { return m_val; }
    117 
    118 private:
    119         bool       m_val;
    120         bool     * m_prev;
    121         bool_ref * m_ref;
    122 };
    123 
    124 /// "Short hand" to check if this is a valid previsit function
    125 /// Mostly used to make the static_assert look (and print) prettier
    126 template<typename core_t, typename node_t>
    127 struct is_valid_previsit {
    128         using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) );
    129 
    130         static constexpr bool value = std::is_void< ret_t >::value ||
    131                 std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value;
    132 };
    133 
    134 /// The result is a single node.
    135 template< typename node_t >
    136 struct result1 {
    137         bool differs = false;
    138         const node_t * value = nullptr;
    139 
    140         template< typename object_t, typename super_t, typename field_t >
    141         void apply( object_t * object, field_t super_t::* field ) {
    142                 object->*field = value;
    143         }
    144 };
    145 
    146 /// The result is a container of statements.
    147 template< template<class...> class container_t >
    148 struct resultNstmt {
    149         /// The delta/change on a single node.
    150         struct delta {
    151                 ptr<Stmt> new_val;
    152                 ssize_t old_idx;
    153                 bool is_old;
    154 
    155                 delta(const Stmt * s, ssize_t i, bool old) :
    156                         new_val(s), old_idx(i), is_old(old) {}
    157         };
    158 
    159         bool differs = false;
    160         container_t< delta > values;
    161 
    162         template< typename object_t, typename super_t, typename field_t >
    163         void apply( object_t * object, field_t super_t::* field ) {
    164                 field_t & container = object->*field;
    165                 __pedantic_pass_assert( container.size() <= values.size() );
    166 
    167                 auto cit = enumerate(container).begin();
    168 
    169                 container_t<ptr<Stmt>> nvals;
    170                 for ( delta & d : values ) {
    171                         if ( d.is_old ) {
    172                                 __pedantic_pass_assert( cit.idx <= d.old_idx );
    173                                 std::advance( cit, d.old_idx - cit.idx );
    174                                 nvals.push_back( std::move( (*cit).val ) );
    175                         } else {
    176                                 nvals.push_back( std::move( d.new_val ) );
    177                         }
    178                 }
    179 
    180                 container = std::move(nvals);
    181         }
    182 
    183         template< template<class...> class incontainer_t >
    184         void take_all( incontainer_t<ptr<Stmt>> * stmts ) {
    185                 if ( !stmts || stmts->empty() ) return;
    186 
    187                 std::transform( stmts->begin(), stmts->end(), std::back_inserter( values ),
    188                         [](ast::ptr<ast::Stmt>& stmt) -> delta {
    189                                 return delta( stmt.release(), -1, false );
    190                         });
    191                 stmts->clear();
    192                 differs = true;
    193         }
    194 
    195         template< template<class...> class incontainer_t >
    196         void take_all( incontainer_t<ptr<Decl>> * decls ) {
    197                 if ( !decls || decls->empty() ) return;
    198 
    199                 std::transform( decls->begin(), decls->end(), std::back_inserter( values ),
    200                         [](ast::ptr<ast::Decl>& decl) -> delta {
    201                                 ast::Decl const * d = decl.release();
    202                                 return delta( new DeclStmt( d->location, d ), -1, false );
    203                         });
    204                 decls->clear();
    205                 differs = true;
    206         }
    207 };
    208 
    209 /// The result is a container of nodes.
    210 template< template<class...> class container_t, typename node_t >
    211 struct resultN {
    212         bool differs = false;
    213         container_t<ptr<node_t>> values;
    214 
    215         template< typename object_t, typename super_t, typename field_t >
    216         void apply( object_t * object, field_t super_t::* field ) {
    217                 field_t & container = object->*field;
    218                 __pedantic_pass_assert( container.size() == values.size() );
    219 
    220                 for ( size_t i = 0; i < container.size(); ++i ) {
    221                         // Take all the elements that are different in 'values'
    222                         // and swap them into 'container'
    223                         if ( values[i] != nullptr ) swap(container[i], values[i]);
    224                 }
    225                 // Now the original containers should still have the unchanged values
    226                 // but also contain the new values.
    227         }
    228 };
    229 
    230 /// Used by previsit implementation
    231 /// We need to reassign the result to 'node', unless the function
    232 /// returns void, then we just leave 'node' unchanged
    233 template<bool is_void>
    234 struct __assign;
    235 
    236 template<>
    237 struct __assign<true> {
     22template<typename core_t>
     23class Pass;
     24
     25class TranslationUnit;
     26
     27struct PureVisitor;
     28
     29template<typename node_t>
     30node_t * deepCopy( const node_t * localRoot );
     31
     32namespace __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;
     58        };
     59
     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;
     94        };
     95
     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
    238122        template<typename core_t, typename node_t>
    239         static inline void result( core_t & core, const node_t * & node ) {
    240                 core.previsit( node );
    241         }
    242 };
    243 
    244 template<>
    245 struct __assign<false> {
     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
    246237        template<typename core_t, typename node_t>
    247         static inline void result( core_t & core, const node_t * & node ) {
    248                 node = core.previsit( node );
    249                 assertf(node, "Previsit must not return NULL");
    250         }
    251 };
    252 
    253 /// Used by postvisit implementation
    254 /// We need to return the result unless the function
    255 /// returns void, then we just return the original node
    256 template<bool is_void>
    257 struct __return;
    258 
    259 template<>
    260 struct __return<true> {
     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
    261251        template<typename core_t, typename node_t>
    262         static inline const node_t * result( core_t & core, const node_t * & node ) {
    263                 core.postvisit( node );
    264                 return node;
    265         }
    266 };
    267 
    268 template<>
    269 struct __return<false> {
     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
    270255        template<typename core_t, typename node_t>
    271         static inline auto result( core_t & core, const node_t * & node ) {
    272                 return core.postvisit( node );
    273         }
    274 };
    275 
    276 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    277 // Deep magic (a.k.a template meta programming) to make the templated visitor work
    278 // Basically the goal is to make 2 previsit
    279 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of
    280 //     'pass.previsit( node )' that compiles will be used for that node for that type
    281 //     This requires that this option only compile for passes that actually define an appropriate visit.
    282 //     SFINAE will make sure the compilation errors in this function don't halt the build.
    283 //     See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE
    284 // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing.
    285 //     This is needed only to eliminate the need for passes to specify any kind of handlers.
    286 //     The second implementation only works because it has a lower priority. This is due to the bogus last parameter.
    287 //     The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0
    288 //     the first implementation takes priority in regards to overloading.
    289 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    290 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    291 template<typename core_t, typename node_t>
    292 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) {
    293         static_assert(
    294                 is_valid_previsit<core_t, node_t>::value,
    295                 "Previsit may not change the type of the node. It must return its paremeter or void."
    296         );
    297 
    298         __assign<
    299                 std::is_void<
    300                         decltype( core.previsit( node ) )
    301                 >::value
    302         >::result( core, node );
    303 }
    304 
    305 template<typename core_t, typename node_t>
    306 static inline auto previsit( core_t &, const node_t *, long ) {}
    307 
    308 // PostVisit : never mutates the passed pointer but may return a different node
    309 template<typename core_t, typename node_t>
    310 static inline auto postvisit( core_t & core, const node_t * node, int ) ->
    311         decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
    312 {
    313         return __return<
    314                 std::is_void<
    315                         decltype( core.postvisit( node ) )
    316                 >::value
    317         >::result( core, node );
    318 }
    319 
    320 template<typename core_t, typename node_t>
    321 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; }
    322 
    323 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    324 // Deep magic (a.k.a template meta programming) continued
    325 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit
    326 // from in order to get extra functionallity for example
    327 // class ErrorChecker : WithShortCircuiting { ... };
    328 // Pass<ErrorChecker> checker;
    329 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting
    330 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched
    331 //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    332 // For several accessories, the feature is enabled by detecting that a specific field is present
    333 // Use a macro the encapsulate the logic of detecting a particular field
    334 // The type is not strictly enforced but does match the accessory
    335 #define FIELD_PTR( name, default_type ) \
    336 template< typename core_t > \
    337 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
    338 \
    339 template< typename core_t > \
    340 static inline default_type * name( core_t &, long ) { return nullptr; }
    341 
    342 // List of fields and their expected types
    343 FIELD_PTR( typeSubs, const ast::TypeSubstitution * )
    344 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
    345 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
    346 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
    347 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
    348 FIELD_PTR( visit_children, __pass::bool_ref )
    349 FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    350 FIELD_PTR( visitor, ast::Pass<core_t> * const )
    351 
    352 // Remove the macro to make sure we don't clash
    353 #undef FIELD_PTR
    354 
    355 template< typename core_t >
    356 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
    357         // Stats::Heap::stacktrace_push(core_t::traceId);
    358 }
    359 
    360 template< typename core_t >
    361 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
    362         // Stats::Heap::stacktrace_pop();
    363 }
    364 
    365 template< typename core_t >
    366 static void beginTrace(core_t &, long) {}
    367 
    368 template< typename core_t >
    369 static void endTrace(core_t &, long) {}
    370 
    371 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error.
    372 // If on_error() returns false, the error will be ignored. By default, it returns true.
    373 
    374 template< typename core_t >
    375 static bool on_error (core_t &, ptr<Decl> &, long) { return true; }
    376 
    377 template< typename core_t >
    378 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) {
    379         return core.on_error(decl);
    380 }
    381 
    382 template< typename core_t, typename node_t >
    383 static auto make_location_guard( core_t & core, node_t * node, int )
    384                 -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) {
    385         ValueGuardPtr<const CodeLocation *> guard( &core.location );
    386         core.location = &node->location;
    387         return guard;
    388 }
    389 
    390 template< typename core_t, typename node_t >
    391 static auto make_location_guard( core_t &, node_t *, long ) -> int {
    392         return 0;
    393 }
    394 
    395 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
    396 // All passes which have such functions are assumed desire this behaviour
    397 // detect it using the same strategy
    398 namespace scope {
     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; } \
     284        \
     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
     492        } // namespace forall
     493
     494        // For passes that need access to the global context. Sreaches `translationUnit`
     495        namespace translation_unit {
     496                template<typename core_t>
     497                static inline auto get_cptr( core_t & core, int )
     498                                -> decltype( &core.translationUnit ) {
     499                        return &core.translationUnit;
     500                }
     501
     502                template<typename core_t>
     503                static inline const TranslationUnit ** get_cptr( core_t &, long ) {
     504                        return nullptr;
     505                }
     506        }
     507
    399508        template<typename core_t>
    400         static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) {
    401                 core.beginScope();
     509        static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) {
     510                return core.result();
    402511        }
    403512
    404513        template<typename core_t>
    405         static inline void enter( core_t &, long ) {}
     514        static inline auto get_result( core_t & core, int ) -> decltype( core.result ) {
     515                return core.result;
     516        }
    406517
    407518        template<typename core_t>
    408         static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) {
    409                 core.endScope();
    410         }
    411 
    412         template<typename core_t>
    413         static inline void leave( core_t &, long ) {}
    414 } // namespace scope
    415 
    416 // Certain passes desire an up to date symbol table automatically
    417 // detect the presence of a member name `symtab` and call all the members appropriately
    418 namespace symtab {
    419         // Some simple scoping rules
    420         template<typename core_t>
    421         static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) {
    422                 core.symtab.enterScope();
    423         }
    424 
    425         template<typename core_t>
    426         static inline auto enter( core_t &, long ) {}
    427 
    428         template<typename core_t>
    429         static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) {
    430                 core.symtab.leaveScope();
    431         }
    432 
    433         template<typename core_t>
    434         static inline auto leave( core_t &, long ) {}
    435 
    436         // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments
    437         // Create macro to condense these common patterns
    438         #define SYMTAB_FUNC1( func, type ) \
    439         template<typename core_t> \
    440         static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\
    441                 core.symtab.func( arg ); \
    442         } \
    443         \
    444         template<typename core_t> \
    445         static inline void func( core_t &, long, type ) {}
    446 
    447         #define SYMTAB_FUNC2( func, type1, type2 ) \
    448         template<typename core_t> \
    449         static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\
    450                 core.symtab.func( arg1, arg2 ); \
    451         } \
    452         \
    453         template<typename core_t> \
    454         static inline void func( core_t &, long, type1, type2 ) {}
    455 
    456         SYMTAB_FUNC1( addId     , const DeclWithType *  );
    457         SYMTAB_FUNC1( addType   , const NamedTypeDecl * );
    458         SYMTAB_FUNC1( addStruct , const StructDecl *    );
    459         SYMTAB_FUNC1( addEnum   , const EnumDecl *      );
    460         SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
    461         SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
    462         SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Decl * );
    463 
    464         // A few extra functions have more complicated behaviour, they are hand written
    465         template<typename core_t>
    466         static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
    467                 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
    468                 for ( const auto & param : decl->params ) {
    469                         fwd->params.push_back( deepCopy( param.get() ) );
    470                 }
    471                 core.symtab.addStruct( fwd );
    472         }
    473 
    474         template<typename core_t>
    475         static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {}
    476 
    477         template<typename core_t>
    478         static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) {
    479                 ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name );
    480                 for ( const auto & param : decl->params ) {
    481                         fwd->params.push_back( deepCopy( param.get() ) );
    482                 }
    483                 core.symtab.addUnion( fwd );
    484         }
    485 
    486         template<typename core_t>
    487         static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {}
    488 
    489         template<typename core_t>
    490         static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {
    491                 if ( ! core.symtab.lookupStruct( str ) ) {
    492                         core.symtab.addStruct( str );
    493                 }
    494         }
    495 
    496         template<typename core_t>
    497         static inline void addStruct( core_t &, long, const std::string & ) {}
    498 
    499         template<typename core_t>
    500         static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {
    501                 if ( ! core.symtab.lookupUnion( str ) ) {
    502                         core.symtab.addUnion( str );
    503                 }
    504         }
    505 
    506         template<typename core_t>
    507         static inline void addUnion( core_t &, long, const std::string & ) {}
    508 
    509         #undef SYMTAB_FUNC1
    510         #undef SYMTAB_FUNC2
    511 } // namespace symtab
    512 
    513 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
    514 // Detect the presence of a member name `subs` and call all members appropriately
    515 namespace forall {
    516         // Some simple scoping rules
    517         template<typename core_t>
    518         static inline auto enter( core_t & core, int, const ast::FunctionType * type )
    519                         -> decltype( core.subs, void() ) {
    520                 if ( ! type->forall.empty() ) core.subs.beginScope();
    521         }
    522 
    523         template<typename core_t>
    524         static inline auto enter( core_t &, long, const ast::FunctionType * ) {}
    525 
    526         template<typename core_t>
    527         static inline auto leave( core_t & core, int, const ast::FunctionType * type )
    528                         -> decltype( core.subs, void() ) {
    529                 if ( ! type->forall.empty() ) { core.subs.endScope(); }
    530         }
    531 
    532         template<typename core_t>
    533         static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
    534 
    535         // Replaces a TypeInstType's base TypeDecl according to the table
    536         template<typename core_t>
    537         static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst )
    538                         -> decltype( core.subs, void() ) {
    539                 inst = ast::mutate_field(
    540                         inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) );
    541         }
    542 
    543         template<typename core_t>
    544         static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {}
    545 } // namespace forall
    546 
    547 // For passes that need access to the global context. Searches `translationUnit`
    548 namespace translation_unit {
    549         template<typename core_t>
    550         static inline auto get_cptr( core_t & core, int )
    551                         -> decltype( &core.translationUnit ) {
    552                 return &core.translationUnit;
    553         }
    554 
    555         template<typename core_t>
    556         static inline const TranslationUnit ** get_cptr( core_t &, long ) {
    557                 return nullptr;
    558         }
    559 }
    560 
    561 // For passes, usually utility passes, that have a result.
    562 namespace result {
    563         template<typename core_t>
    564         static inline auto get( core_t & core, char ) -> decltype( core.result() ) {
    565                 return core.result();
    566         }
    567 
    568         template<typename core_t>
    569         static inline auto get( core_t & core, int ) -> decltype( core.result ) {
    570                 return core.result;
    571         }
    572 
    573         template<typename core_t>
    574         static inline void get( core_t &, long ) {}
    575 }
    576 
    577 } // namespace ast::__pass
    578 
    579 #undef __pedantic_pass_assertf
    580 #undef __pedantic_pass_assert
     519        static inline void get_result( core_t &, long ) {}
     520} // namespace __pass
     521} // namespace ast
Note: See TracChangeset for help on using the changeset viewer.