Ignore:
Timestamp:
Feb 16, 2023, 11:30:02 AM (14 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
ADT, ast-experimental, master
Children:
4b60b28
Parents:
cad9edb
Message:

Updated indentation in Pass.proto.hpp.

File:
1 edited

Legend:

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

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