Ignore:
Timestamp:
Jun 12, 2023, 2:45:32 PM (2 years ago)
Author:
Fangren Yu <f37yu@…>
Branches:
ast-experimental, master
Children:
62d62db
Parents:
34b4268 (diff), 251ce80 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into ast-experimental

File:
1 edited

Legend:

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

    r34b4268 r24d6572  
    1717// IWYU pragma: private, include "Pass.hpp"
    1818
     19#include "Common/Iterate.hpp"
    1920#include "Common/Stats/Heap.h"
    20 
    2121namespace 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;
     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
     36namespace ast::__pass {
     37
     38typedef std::function<void( void * )> cleanup_func_t;
     39typedef 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
     43class bool_ref {
     44public:
     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
     51private:
     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
     66class guard_value {
     67public:
     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
     89private:
     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) {}
    5895        };
    5996
    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                                 };
     97        std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
     98};
     99
     100// Guard structure implementation for whether or not children should be visited
     101class visit_children_guard {
     102public:
     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
     118private:
     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
     126template<typename core_t, typename node_t>
     127struct 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.
     135template< typename node_t >
     136struct 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.
     147template< template<class...> class container_t >
     148struct 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 ) );
    70177                        }
    71178                }
    72179
    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
     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.
     210template< template<class...> class container_t, typename node_t >
     211struct 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
     233template<bool is_void>
     234struct __assign;
     235
     236template<>
     237struct __assign<true> {
    122238        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
     239        static inline void result( core_t & core, const node_t * & node ) {
     240                core.previsit( node );
     241        }
     242};
     243
     244template<>
     245struct __assign<false> {
    237246        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 
     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
     256template<bool is_void>
     257struct __return;
     258
     259template<>
     260struct __return<true> {
    251261        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
     262        static inline const node_t * result( core_t & core, const node_t * & node ) {
     263                core.postvisit( node );
     264                return node;
     265        }
     266};
     267
     268template<>
     269struct __return<false> {
    255270        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; } \
     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
     291template<typename core_t, typename node_t>
     292static 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
     305template<typename core_t, typename node_t>
     306static inline auto previsit( core_t &, const node_t *, long ) {}
     307
     308// PostVisit : never mutates the passed pointer but may return a different node
     309template<typename core_t, typename node_t>
     310static 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
     320template<typename core_t, typename node_t>
     321static 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 ) \
     336template< typename core_t > \
     337static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
     338\
     339template< typename core_t > \
     340static inline default_type * name( core_t &, long ) { return nullptr; }
     341
     342// List of fields and their expected types
     343FIELD_PTR( typeSubs, const ast::TypeSubstitution * )
     344FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
     345FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
     346FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
     347FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
     348FIELD_PTR( visit_children, __pass::bool_ref )
     349FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
     350FIELD_PTR( visitor, ast::Pass<core_t> * const )
     351
     352// Remove the macro to make sure we don't clash
     353#undef FIELD_PTR
     354
     355template< typename core_t >
     356static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     357        // Stats::Heap::stacktrace_push(core_t::traceId);
     358}
     359
     360template< typename core_t >
     361static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     362        // Stats::Heap::stacktrace_pop();
     363}
     364
     365template< typename core_t >
     366static void beginTrace(core_t &, long) {}
     367
     368template< typename core_t >
     369static 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
     374template< typename core_t >
     375static bool on_error (core_t &, ptr<Decl> &, long) { return true; }
     376
     377template< typename core_t >
     378static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) {
     379        return core.on_error(decl);
     380}
     381
     382template< typename core_t, typename node_t >
     383static 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
     390template< typename core_t, typename node_t >
     391static 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
     398namespace scope {
     399        template<typename core_t>
     400        static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) {
     401                core.beginScope();
     402        }
     403
     404        template<typename core_t>
     405        static inline void enter( core_t &, long ) {}
     406
     407        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
     418namespace 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        } \
    284443        \
    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 
    508         template<typename core_t>
    509         static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) {
     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
     515namespace 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`
     548namespace 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.
     562namespace result {
     563        template<typename core_t>
     564        static inline auto get( core_t & core, char ) -> decltype( core.result() ) {
    510565                return core.result();
    511566        }
    512567
    513568        template<typename core_t>
    514         static inline auto get_result( core_t & core, int ) -> decltype( core.result ) {
     569        static inline auto get( core_t & core, int ) -> decltype( core.result ) {
    515570                return core.result;
    516571        }
    517572
    518573        template<typename core_t>
    519         static inline void get_result( core_t &, long ) {}
    520 } // namespace __pass
    521 } // namespace ast
     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
Note: See TracChangeset for help on using the changeset viewer.