Changeset 1c80f20 for src


Ignore:
Timestamp:
Feb 16, 2023, 3:10:02 PM (15 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
ADT, ast-experimental, master
Children:
f5f2768
Parents:
abcb393 (diff), 4b60b28 (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' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
src
Files:
7 edited

Legend:

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

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

    rabcb393 r1c80f20  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Apr 25 14:26:00 2022
    13 // Update Count     : 51
     12// Last Modified On : Thr Feb 16 12:35:00 2023
     13// Update Count     : 52
    1414//
    1515
     
    4949                return 0;
    5050        } // if
    51 }
    52 
    53 template< typename T, typename U >
    54 struct maybeBuild_t {
    55         static T * doit( const U *orig ) {
    56                 if ( orig ) {
    57                         return orig->build();
    58                 } else {
    59                         return 0;
    60                 } // if
    61         }
    62 };
    63 
    64 template< typename T, typename U >
    65 static inline T * maybeBuild( const U *orig ) {
    66         return maybeBuild_t<T,U>::doit(orig);
    67 }
    68 
    69 template< typename T, typename U >
    70 static inline T * maybeMoveBuild( const U *orig ) {
    71         T* ret = maybeBuild<T>(orig);
    72         delete orig;
    73         return ret;
    7451}
    7552
  • src/Parser/ParseNode.h

    rabcb393 r1c80f20  
    2727#include "Common/SemanticError.h"  // for SemanticError
    2828#include "Common/UniqueName.h"     // for UniqueName
    29 #include "Common/utility.h"        // for maybeClone, maybeBuild
     29#include "Common/utility.h"        // for maybeClone
     30#include "Parser/parserutility.h"  // for maybeBuild
    3031#include "SynTree/LinkageSpec.h"   // for Spec
    3132#include "SynTree/Declaration.h"   // for Aggregate
  • src/Parser/RunParser.cpp

    rabcb393 r1c80f20  
    1010// Created On       : Mon Dec 19 11:00:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Dec 22 10:18:00 2022
    13 // Update Count     : 1
     12// Last Modified On : Thr Feb 16 10:08:00 2023
     13// Update Count     : 2
    1414//
    1515
     
    2424
    2525// Variables global to the parsing code.
    26 LinkageSpec::Spec linkage = LinkageSpec::Cforall;
     26ast::Linkage::Spec linkage = ast::Linkage::Cforall;
    2727TypedefTable typedefTable;
    2828DeclarationNode * parseTree = nullptr;
    2929
    30 void parse( FILE * input, LinkageSpec::Spec linkage, bool alwaysExit ) {
     30void parse( FILE * input, ast::Linkage::Spec linkage, bool alwaysExit ) {
    3131        extern int yyparse( void );
    3232        extern FILE * yyin;
  • src/Parser/RunParser.hpp

    rabcb393 r1c80f20  
    1010// Created On       : Mon Dec 19 10:42:00 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Dec 22 10:23:00 2022
    13 // Update Count     : 1
     12// Last Modified On : Thr Feb 16 10:08:00 2023
     13// Update Count     : 2
    1414//
    1515
     
    1818#include <iosfwd>                           // for ostream
    1919
    20 #include "SynTree/LinkageSpec.h"            // for Spec
     20#include "AST/LinkageSpec.hpp"              // for Spec
    2121namespace ast {
    2222        class TranslationUnit;
     
    2929/// The input file is closed when complete. Exits instead of returning on
    3030/// error or if alwaysExit is true.
    31 void parse( FILE * input, LinkageSpec::Spec linkage, bool alwaysExit = false );
     31void parse( FILE * input, ast::Linkage::Spec linkage, bool alwaysExit = false );
    3232
    3333/// Drain the internal accumulator of parsed code and build a translation
  • src/Parser/parserutility.h

    rabcb393 r1c80f20  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // parserutility.h --
     7// parserutility.h -- Collected utilities for the parser.
    88//
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 15:31:46 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:32:58 2017
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Feb 16 12:34:00 2023
     13// Update Count     : 5
    1414//
    1515
     
    2020Expression *notZeroExpr( Expression *orig );
    2121
     22template< typename T, typename U >
     23struct maybeBuild_t {
     24        static T * doit( const U *orig ) {
     25                if ( orig ) {
     26                        return orig->build();
     27                } else {
     28                        return 0;
     29                }
     30        }
     31};
     32
     33template< typename T, typename U >
     34static inline T * maybeBuild( const U *orig ) {
     35        return maybeBuild_t<T,U>::doit(orig);
     36}
     37
     38template< typename T, typename U >
     39static inline T * maybeMoveBuild( const U *orig ) {
     40        T* ret = maybeBuild<T>(orig);
     41        delete orig;
     42        return ret;
     43}
     44
    2245// Local Variables: //
    2346// tab-width: 4 //
  • src/main.cc

    rabcb393 r1c80f20  
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Oct  5 12:06:00 2022
    13 // Update Count     : 679
     12// Last Modified On : Thr Feb 16 10:08:00 2023
     13// Update Count     : 680
    1414//
    1515
     
    272272                        FILE * gcc_builtins = fopen( (PreludeDirector + "/gcc-builtins.cf").c_str(), "r" );
    273273                        assertf( gcc_builtins, "cannot open gcc-builtins.cf\n" );
    274                         parse( gcc_builtins, LinkageSpec::Compiler );
     274                        parse( gcc_builtins, ast::Linkage::Compiler );
    275275
    276276                        // read the extra prelude in, if not generating the cfa library
    277277                        FILE * extras = fopen( (PreludeDirector + "/extras.cf").c_str(), "r" );
    278278                        assertf( extras, "cannot open extras.cf\n" );
    279                         parse( extras, LinkageSpec::BuiltinC );
     279                        parse( extras, ast::Linkage::BuiltinC );
    280280
    281281                        if ( ! libcfap ) {
     
    283283                                FILE * prelude = fopen( (PreludeDirector + "/prelude.cfa").c_str(), "r" );
    284284                                assertf( prelude, "cannot open prelude.cfa\n" );
    285                                 parse( prelude, LinkageSpec::Intrinsic );
     285                                parse( prelude, ast::Linkage::Intrinsic );
    286286
    287287                                // Read to cfa builtins, if not generating the cfa library
    288288                                FILE * builtins = fopen( (PreludeDirector + "/builtins.cf").c_str(), "r" );
    289289                                assertf( builtins, "cannot open builtins.cf\n" );
    290                                 parse( builtins, LinkageSpec::BuiltinCFA );
    291                         } // if
    292                 } // if
    293 
    294                 parse( input, libcfap ? LinkageSpec::Intrinsic : LinkageSpec::Cforall, yydebug );
     290                                parse( builtins, ast::Linkage::BuiltinCFA );
     291                        } // if
     292                } // if
     293
     294                parse( input, libcfap ? ast::Linkage::Intrinsic : ast::Linkage::Cforall, yydebug );
    295295
    296296                transUnit = buildUnit();
     
    340340                PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) );
    341341
    342         PASS( "Implement Actors", Concurrency::implementActors( transUnit ) );
    343 
     342                PASS( "Implement Actors", Concurrency::implementActors( transUnit ) );
    344343                PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) );
    345344                PASS( "Implement Thread Start", Concurrency::implementThreadStarter( transUnit ) );
Note: See TracChangeset for help on using the changeset viewer.