Changeset 62d62db for src/AST


Ignore:
Timestamp:
Jun 12, 2023, 6:06:26 PM (3 years ago)
Author:
caparsons <caparson@…>
Branches:
ast-experimental, master
Children:
e172f42
Parents:
24d6572 (diff), 38e266ca (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into ast-experimental

Location:
src/AST
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • src/AST/DeclReplacer.hpp

    r24d6572 r62d62db  
    1818#include <unordered_map>
    1919
    20 #include "Node.hpp"
     20namespace ast {
     21        class DeclWithType;
     22        class Expr;
     23        class Node;
     24        class TypeDecl;
     25}
    2126
    2227namespace ast {
    23         class DeclWithType;
    24         class TypeDecl;
    25         class Expr;
    2628
    27         namespace DeclReplacer {
    28                 using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >;
    29                 using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >;
    30                 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >;
     29namespace DeclReplacer {
    3130
    32                 const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false );
    33                 const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false );
    34                 const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false );
    35                 const Node * replace( const Node * node, const ExprMap & exprMap);
    36         }
     31using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >;
     32using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >;
     33using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >;
     34
     35const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false );
     36const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false );
     37const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false );
     38const Node * replace( const Node * node, const ExprMap & exprMap);
     39
     40}
     41
    3742}
    3843
  • src/AST/Pass.hpp

    r24d6572 r62d62db  
    414414};
    415415
    416 /// Use when the templated visitor should update the symbol table
     416/// Use when the templated visitor should update the symbol table,
     417/// that is, when your pass core needs to query the symbol table.
     418/// Expected setups:
     419/// - For master passes that kick off at the compilation unit
     420///   - before resolver: extend WithSymbolTableX<IgnoreErrors>
     421///   - after resolver: extend WithSymbolTable and use defaults
     422///   - (FYI, for completeness, the resolver's main pass uses ValidateOnAdd when it kicks off)
     423/// - For helper passes that kick off at arbitrary points in the AST:
     424///   - take an existing symbol table as a parameter, extend WithSymbolTable,
     425///     and construct with WithSymbolTable(const SymbolTable &)
    417426struct WithSymbolTable {
    418         SymbolTable symtab;
     427        WithSymbolTable(const ast::SymbolTable & from) : symtab(from) {}
     428        WithSymbolTable(ast::SymbolTable::ErrorDetection errorMode = ast::SymbolTable::ErrorDetection::AssertClean) : symtab(errorMode) {}
     429        ast::SymbolTable symtab;
     430};
     431template <ast::SymbolTable::ErrorDetection errorMode>
     432struct WithSymbolTableX : WithSymbolTable {
     433        WithSymbolTableX() : WithSymbolTable(errorMode) {}
    419434};
    420435
  • src/AST/Pass.impl.hpp

    r24d6572 r62d62db  
    7272                template<typename it_t, template <class...> class container_t>
    7373                static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) {
    74                         if(empty(decls)) return;
     74                        if ( empty( decls ) ) return;
    7575
    7676                        std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto {
     
    7878                                });
    7979                        decls->clear();
    80                         if(mutated) *mutated = true;
     80                        if ( mutated ) *mutated = true;
    8181                }
    8282
    8383                template<typename it_t, template <class...> class container_t>
    8484                static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * stmts, bool * mutated = nullptr ) {
    85                         if(empty(stmts)) return;
     85                        if ( empty( stmts ) ) return;
    8686
    8787                        std::move(stmts->begin(), stmts->end(), it);
    8888                        stmts->clear();
    89                         if(mutated) *mutated = true;
     89                        if ( mutated ) *mutated = true;
    9090                }
    9191
     
    9393                /// Check if should be skipped, different for pointers and containers
    9494                template<typename node_t>
    95                 bool skip( const ast::ptr<node_t> & val) {
     95                bool skip( const ast::ptr<node_t> & val ) {
    9696                        return !val;
    9797                }
     
    110110
    111111                template<typename node_t>
    112                 const node_t & get( const node_t & val, long) {
     112                const node_t & get( const node_t & val, long ) {
    113113                        return val;
    114114                }
     
    126126                }
    127127        }
    128 
    129         template< typename core_t >
    130         template< typename node_t >
    131         auto ast::Pass< core_t >::call_accept( const node_t * node )
    132                 -> typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type
    133         {
    134                 __pedantic_pass_assert( __visit_children() );
    135                 __pedantic_pass_assert( node );
    136 
    137                 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
    138                 static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR");
    139 
    140                 auto nval = node->accept( *this );
    141                 __pass::result1<
    142                         typename std::remove_pointer< decltype( node->accept(*this) ) >::type
    143                 > res;
    144                 res.differs = nval != node;
    145                 res.value = nval;
    146                 return res;
    147         }
    148 
    149         template< typename core_t >
    150         __pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
    151                 __pedantic_pass_assert( __visit_children() );
    152                 __pedantic_pass_assert( expr );
    153 
    154                 auto nval = expr->accept( *this );
    155                 return { nval != expr, nval };
    156         }
    157 
    158         template< typename core_t >
    159         __pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
    160                 __pedantic_pass_assert( __visit_children() );
    161                 __pedantic_pass_assert( stmt );
    162 
    163                 const ast::Stmt * nval = stmt->accept( *this );
    164                 return { nval != stmt, nval };
    165         }
    166 
    167         template< typename core_t >
    168         __pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept_top( const ast::Expr * expr ) {
    169                 __pedantic_pass_assert( __visit_children() );
    170                 __pedantic_pass_assert( expr );
    171 
    172                 const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 );
    173                 if ( typeSubs_ptr && expr->env ) {
    174                         *typeSubs_ptr = expr->env;
    175                 }
    176 
    177                 auto nval = expr->accept( *this );
    178                 return { nval != expr, nval };
    179         }
    180 
    181         template< typename core_t >
    182         __pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) {
    183                 __pedantic_pass_assert( __visit_children() );
    184                 __pedantic_pass_assert( stmt );
    185 
    186                 // add a few useful symbols to the scope
    187                 using __pass::empty;
    188 
    189                 // get the stmts/decls that will need to be spliced in
    190                 auto stmts_before = __pass::stmtsToAddBefore( core, 0 );
    191                 auto stmts_after  = __pass::stmtsToAddAfter ( core, 0 );
    192                 auto decls_before = __pass::declsToAddBefore( core, 0 );
    193                 auto decls_after  = __pass::declsToAddAfter ( core, 0 );
    194 
    195                 // These may be modified by subnode but most be restored once we exit this statemnet.
    196                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::typeSubs( core, 0 ) );
    197                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    198                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
    199                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
    200                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after  );
    201 
    202                 // Now is the time to actually visit the node
    203                 const ast::Stmt * nstmt = stmt->accept( *this );
    204 
    205                 // If the pass doesn't want to add anything then we are done
    206                 if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
    207                         return { nstmt != stmt, nstmt };
    208                 }
    209 
    210                 // Make sure that it is either adding statements or declartions but not both
    211                 // this is because otherwise the order would be awkward to predict
    212                 assert(( empty( stmts_before ) && empty( stmts_after ))
    213                     || ( empty( decls_before ) && empty( decls_after )) );
    214 
    215                 // Create a new Compound Statement to hold the new decls/stmts
    216                 ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location );
    217 
    218                 // Take all the declarations that go before
    219                 __pass::take_all( std::back_inserter( compound->kids ), decls_before );
    220                 __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
    221 
    222                 // Insert the original declaration
    223                 compound->kids.emplace_back( nstmt );
    224 
    225                 // Insert all the declarations that go before
    226                 __pass::take_all( std::back_inserter( compound->kids ), decls_after );
    227                 __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
    228 
    229                 return {true, compound};
    230         }
    231 
    232         template< typename core_t >
    233         template< template <class...> class container_t >
    234         __pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    235                 __pedantic_pass_assert( __visit_children() );
    236                 if( statements.empty() ) return {};
    237 
    238                 // We are going to aggregate errors for all these statements
    239                 SemanticErrorException errors;
    240 
    241                 // add a few useful symbols to the scope
    242                 using __pass::empty;
    243 
    244                 // get the stmts/decls that will need to be spliced in
    245                 auto stmts_before = __pass::stmtsToAddBefore( core, 0 );
    246                 auto stmts_after  = __pass::stmtsToAddAfter ( core, 0 );
    247                 auto decls_before = __pass::declsToAddBefore( core, 0 );
    248                 auto decls_after  = __pass::declsToAddAfter ( core, 0 );
    249 
    250                 // These may be modified by subnode but most be restored once we exit this statemnet.
    251                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    252                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
    253                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
    254                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after  );
    255 
    256                 // update pass statitistics
    257                 pass_visitor_stats.depth++;
    258                 pass_visitor_stats.max->push(pass_visitor_stats.depth);
    259                 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    260 
    261                 __pass::resultNstmt<container_t> new_kids;
    262                 for( auto value : enumerate( statements ) ) {
    263                         try {
    264                                 size_t i = value.idx;
    265                                 const Stmt * stmt = value.val;
    266                                 __pedantic_pass_assert( stmt );
    267                                 const ast::Stmt * new_stmt = stmt->accept( *this );
    268                                 assert( new_stmt );
    269                                 if(new_stmt != stmt ) { new_kids.differs = true; }
    270 
    271                                 // Make sure that it is either adding statements or declartions but not both
    272                                 // this is because otherwise the order would be awkward to predict
    273                                 assert(( empty( stmts_before ) && empty( stmts_after ))
    274                                     || ( empty( decls_before ) && empty( decls_after )) );
    275 
    276                                 // Take all the statements which should have gone after, N/A for first iteration
    277                                 new_kids.take_all( decls_before );
    278                                 new_kids.take_all( stmts_before );
    279 
    280                                 // Now add the statement if there is one
    281                                 if(new_stmt != stmt) {
    282                                         new_kids.values.emplace_back( new_stmt, i, false );
    283                                 } else {
    284                                         new_kids.values.emplace_back( nullptr, i, true );
    285                                 }
    286 
    287                                 // Take all the declarations that go before
    288                                 new_kids.take_all( decls_after );
    289                                 new_kids.take_all( stmts_after );
     128}
     129
     130template< typename core_t >
     131template< typename node_t >
     132auto ast::Pass< core_t >::call_accept( const node_t * node ) ->
     133        typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type
     134{
     135        __pedantic_pass_assert( __visit_children() );
     136        __pedantic_pass_assert( node );
     137
     138        static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR" );
     139        static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR" );
     140
     141        auto nval = node->accept( *this );
     142        __pass::result1<
     143                typename std::remove_pointer< decltype( node->accept(*this) ) >::type
     144        > res;
     145        res.differs = nval != node;
     146        res.value = nval;
     147        return res;
     148}
     149
     150template< typename core_t >
     151ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
     152        __pedantic_pass_assert( __visit_children() );
     153        __pedantic_pass_assert( expr );
     154
     155        auto nval = expr->accept( *this );
     156        return { nval != expr, nval };
     157}
     158
     159template< typename core_t >
     160ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
     161        __pedantic_pass_assert( __visit_children() );
     162        __pedantic_pass_assert( stmt );
     163
     164        const ast::Stmt * nval = stmt->accept( *this );
     165        return { nval != stmt, nval };
     166}
     167
     168template< typename core_t >
     169ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept_top( const ast::Expr * expr ) {
     170        __pedantic_pass_assert( __visit_children() );
     171        __pedantic_pass_assert( expr );
     172
     173        const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 );
     174        if ( typeSubs_ptr && expr->env ) {
     175                *typeSubs_ptr = expr->env;
     176        }
     177
     178        auto nval = expr->accept( *this );
     179        return { nval != expr, nval };
     180}
     181
     182template< typename core_t >
     183ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) {
     184        __pedantic_pass_assert( __visit_children() );
     185        __pedantic_pass_assert( stmt );
     186
     187        // add a few useful symbols to the scope
     188        using __pass::empty;
     189
     190        // get the stmts/decls that will need to be spliced in
     191        auto stmts_before = __pass::stmtsToAddBefore( core, 0 );
     192        auto stmts_after  = __pass::stmtsToAddAfter ( core, 0 );
     193        auto decls_before = __pass::declsToAddBefore( core, 0 );
     194        auto decls_after  = __pass::declsToAddAfter ( core, 0 );
     195
     196        // These may be modified by subnode but most be restored once we exit this statemnet.
     197        ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::typeSubs( core, 0 ) );
     198        ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
     199        ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     200        ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
     201        ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after  );
     202
     203        // Now is the time to actually visit the node
     204        const ast::Stmt * nstmt = stmt->accept( *this );
     205
     206        // If the pass doesn't want to add anything then we are done
     207        if ( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
     208                return { nstmt != stmt, nstmt };
     209        }
     210
     211        // Make sure that it is either adding statements or declartions but not both
     212        // this is because otherwise the order would be awkward to predict
     213        assert(( empty( stmts_before ) && empty( stmts_after ))
     214            || ( empty( decls_before ) && empty( decls_after )) );
     215
     216        // Create a new Compound Statement to hold the new decls/stmts
     217        ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location );
     218
     219        // Take all the declarations that go before
     220        __pass::take_all( std::back_inserter( compound->kids ), decls_before );
     221        __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
     222
     223        // Insert the original declaration
     224        compound->kids.emplace_back( nstmt );
     225
     226        // Insert all the declarations that go before
     227        __pass::take_all( std::back_inserter( compound->kids ), decls_after );
     228        __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
     229
     230        return { true, compound };
     231}
     232
     233template< typename core_t >
     234template< template <class...> class container_t >
     235ast::__pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
     236        __pedantic_pass_assert( __visit_children() );
     237        if ( statements.empty() ) return {};
     238
     239        // We are going to aggregate errors for all these statements
     240        SemanticErrorException errors;
     241
     242        // add a few useful symbols to the scope
     243        using __pass::empty;
     244
     245        // get the stmts/decls that will need to be spliced in
     246        auto stmts_before = __pass::stmtsToAddBefore( core, 0 );
     247        auto stmts_after  = __pass::stmtsToAddAfter ( core, 0 );
     248        auto decls_before = __pass::declsToAddBefore( core, 0 );
     249        auto decls_after  = __pass::declsToAddAfter ( core, 0 );
     250
     251        // These may be modified by subnode but most be restored once we exit this statemnet.
     252        ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
     253        ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     254        ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
     255        ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after  );
     256
     257        // update pass statitistics
     258        pass_visitor_stats.depth++;
     259        pass_visitor_stats.max->push(pass_visitor_stats.depth);
     260        pass_visitor_stats.avg->push(pass_visitor_stats.depth);
     261
     262        __pass::resultNstmt<container_t> new_kids;
     263        for ( auto value : enumerate( statements ) ) {
     264                try {
     265                        size_t i = value.idx;
     266                        const Stmt * stmt = value.val;
     267                        __pedantic_pass_assert( stmt );
     268                        const ast::Stmt * new_stmt = stmt->accept( *this );
     269                        assert( new_stmt );
     270                        if ( new_stmt != stmt ) { new_kids.differs = true; }
     271
     272                        // Make sure that it is either adding statements or declartions but not both
     273                        // this is because otherwise the order would be awkward to predict
     274                        assert(( empty( stmts_before ) && empty( stmts_after ))
     275                            || ( empty( decls_before ) && empty( decls_after )) );
     276
     277                        // Take all the statements which should have gone after, N/A for first iteration
     278                        new_kids.take_all( decls_before );
     279                        new_kids.take_all( stmts_before );
     280
     281                        // Now add the statement if there is one
     282                        if ( new_stmt != stmt ) {
     283                                new_kids.values.emplace_back( new_stmt, i, false );
     284                        } else {
     285                                new_kids.values.emplace_back( nullptr, i, true );
    290286                        }
    291                         catch ( SemanticErrorException &e ) {
    292                                 errors.append( e );
     287
     288                        // Take all the declarations that go before
     289                        new_kids.take_all( decls_after );
     290                        new_kids.take_all( stmts_after );
     291                } catch ( SemanticErrorException &e ) {
     292                        errors.append( e );
     293                }
     294        }
     295        pass_visitor_stats.depth--;
     296        if ( !errors.isEmpty() ) { throw errors; }
     297
     298        return new_kids;
     299}
     300
     301template< typename core_t >
     302template< template <class...> class container_t, typename node_t >
     303ast::__pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
     304        __pedantic_pass_assert( __visit_children() );
     305        if ( container.empty() ) return {};
     306        SemanticErrorException errors;
     307
     308        pass_visitor_stats.depth++;
     309        pass_visitor_stats.max->push(pass_visitor_stats.depth);
     310        pass_visitor_stats.avg->push(pass_visitor_stats.depth);
     311
     312        bool mutated = false;
     313        container_t<ptr<node_t>> new_kids;
     314        for ( const node_t * node : container ) {
     315                try {
     316                        __pedantic_pass_assert( node );
     317                        const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
     318                        if ( new_stmt != node ) {
     319                                mutated = true;
     320                                new_kids.emplace_back( new_stmt );
     321                        } else {
     322                                new_kids.emplace_back( nullptr );
    293323                        }
    294                 }
    295                 pass_visitor_stats.depth--;
    296                 if ( !errors.isEmpty() ) { throw errors; }
    297 
    298                 return new_kids;
    299         }
    300 
    301         template< typename core_t >
    302         template< template <class...> class container_t, typename node_t >
    303         __pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    304                 __pedantic_pass_assert( __visit_children() );
    305                 if( container.empty() ) return {};
    306                 SemanticErrorException errors;
    307 
    308                 pass_visitor_stats.depth++;
    309                 pass_visitor_stats.max->push(pass_visitor_stats.depth);
    310                 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    311 
    312                 bool mutated = false;
    313                 container_t<ptr<node_t>> new_kids;
    314                 for ( const node_t * node : container ) {
    315                         try {
    316                                 __pedantic_pass_assert( node );
    317                                 const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
    318                                 if(new_stmt != node ) {
    319                                         mutated = true;
    320                                         new_kids.emplace_back( new_stmt );
    321                                 } else {
    322                                         new_kids.emplace_back( nullptr );
    323                                 }
    324 
    325                         }
    326                         catch( SemanticErrorException &e ) {
    327                                 errors.append( e );
    328                         }
    329                 }
    330 
    331                 __pedantic_pass_assert( new_kids.size() == container.size() );
    332                 pass_visitor_stats.depth--;
    333                 if ( ! errors.isEmpty() ) { throw errors; }
    334 
    335                 return ast::__pass::resultN<container_t, node_t>{ mutated, new_kids };
    336         }
    337 
    338         template< typename core_t >
    339         template<typename node_t, typename super_t, typename field_t>
    340         void ast::Pass< core_t >::maybe_accept(
    341                 const node_t * & parent,
    342                 field_t super_t::*field
    343         ) {
    344                 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
    345 
    346                 if(__pass::skip(parent->*field)) return;
    347                 const auto & old_val = __pass::get(parent->*field, 0);
    348 
    349                 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
    350 
    351                 auto new_val = call_accept( old_val );
    352 
    353                 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR");
    354 
    355                 if( new_val.differs ) {
    356                         auto new_parent = __pass::mutate<core_t>(parent);
    357                         new_val.apply(new_parent, field);
    358                         parent = new_parent;
    359                 }
    360         }
    361 
    362         template< typename core_t >
    363         template<typename node_t, typename super_t, typename field_t>
    364         void ast::Pass< core_t >::maybe_accept_top(
    365                 const node_t * & parent,
    366                 field_t super_t::*field
    367         ) {
    368                 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
    369 
    370                 if(__pass::skip(parent->*field)) return;
    371                 const auto & old_val = __pass::get(parent->*field, 0);
    372 
    373                 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
    374 
    375                 auto new_val = call_accept_top( old_val );
    376 
    377                 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR");
    378 
    379                 if( new_val.differs ) {
    380                         auto new_parent = __pass::mutate<core_t>(parent);
    381                         new_val.apply(new_parent, field);
    382                         parent = new_parent;
    383                 }
    384         }
    385 
    386         template< typename core_t >
    387         template<typename node_t, typename super_t, typename field_t>
    388         void ast::Pass< core_t >::maybe_accept_as_compound(
    389                 const node_t * & parent,
    390                 field_t super_t::*child
    391         ) {
    392                 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
    393 
    394                 if(__pass::skip(parent->*child)) return;
    395                 const auto & old_val = __pass::get(parent->*child, 0);
    396 
    397                 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
    398 
    399                 auto new_val = call_accept_as_compound( old_val );
    400 
    401                 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
    402 
    403                 if( new_val.differs ) {
    404                         auto new_parent = __pass::mutate<core_t>(parent);
    405                         new_val.apply( new_parent, child );
    406                         parent = new_parent;
    407                 }
    408         }
    409 
     324                } catch ( SemanticErrorException &e ) {
     325                        errors.append( e );
     326                }
     327        }
     328
     329        __pedantic_pass_assert( new_kids.size() == container.size() );
     330        pass_visitor_stats.depth--;
     331        if ( !errors.isEmpty() ) { throw errors; }
     332
     333        return ast::__pass::resultN<container_t, node_t>{ mutated, new_kids };
     334}
     335
     336template< typename core_t >
     337template<typename node_t, typename super_t, typename field_t>
     338void ast::Pass< core_t >::maybe_accept(
     339        const node_t * & parent,
     340        field_t super_t::*field
     341) {
     342        static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
     343
     344        if ( __pass::skip( parent->*field ) ) return;
     345        const auto & old_val = __pass::get(parent->*field, 0);
     346
     347        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
     348
     349        auto new_val = call_accept( old_val );
     350
     351        static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" );
     352
     353        if ( new_val.differs ) {
     354                auto new_parent = __pass::mutate<core_t>(parent);
     355                new_val.apply(new_parent, field);
     356                parent = new_parent;
     357        }
     358}
     359
     360template< typename core_t >
     361template<typename node_t, typename super_t, typename field_t>
     362void ast::Pass< core_t >::maybe_accept_top(
     363        const node_t * & parent,
     364        field_t super_t::*field
     365) {
     366        static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
     367
     368        if ( __pass::skip( parent->*field ) ) return;
     369        const auto & old_val = __pass::get(parent->*field, 0);
     370
     371        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
     372
     373        auto new_val = call_accept_top( old_val );
     374
     375        static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" );
     376
     377        if ( new_val.differs ) {
     378                auto new_parent = __pass::mutate<core_t>(parent);
     379                new_val.apply(new_parent, field);
     380                parent = new_parent;
     381        }
     382}
     383
     384template< typename core_t >
     385template<typename node_t, typename super_t, typename field_t>
     386void ast::Pass< core_t >::maybe_accept_as_compound(
     387        const node_t * & parent,
     388        field_t super_t::*child
     389) {
     390        static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
     391
     392        if ( __pass::skip( parent->*child ) ) return;
     393        const auto & old_val = __pass::get(parent->*child, 0);
     394
     395        static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
     396
     397        auto new_val = call_accept_as_compound( old_val );
     398
     399        static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR" );
     400
     401        if ( new_val.differs ) {
     402                auto new_parent = __pass::mutate<core_t>(parent);
     403                new_val.apply( new_parent, child );
     404                parent = new_parent;
     405        }
    410406}
    411407
     
    761757
    762758        if ( __visit_children() ) {
    763                 // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result.
    764                 auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() {
    765                         if ( enterScope ) {
    766                                 __pass::symtab::enter(core, 0);
    767                         }
    768                 }, [this, leaveScope = !this->atFunctionTop]() {
    769                         if ( leaveScope ) {
    770                                 __pass::symtab::leave(core, 0);
    771                         }
    772                 });
    773                 ValueGuard< bool > guard2( atFunctionTop );
    774                 atFunctionTop = false;
    775                 guard_scope guard3 { *this };
    776                 maybe_accept( node, &CompoundStmt::kids );
     759                // Do not enter (or leave) a new symbol table scope if atFunctionTop.
     760                // But always enter (and leave) a new general scope.
     761                if ( atFunctionTop ) {
     762                        ValueGuard< bool > guard1( atFunctionTop );
     763                        atFunctionTop = false;
     764                        guard_scope guard2( *this );
     765                        maybe_accept( node, &CompoundStmt::kids );
     766                } else {
     767                        guard_symtab guard1( *this );
     768                        guard_scope guard2( *this );
     769                        maybe_accept( node, &CompoundStmt::kids );
     770                }
    777771        }
    778772
  • src/AST/SymbolTable.cpp

    r24d6572 r62d62db  
    9191}
    9292
    93 SymbolTable::SymbolTable()
     93SymbolTable::SymbolTable( ErrorDetection errorMode )
    9494: idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
    95   prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }
     95  prevScope(), scope( 0 ), repScope( 0 ), errorMode(errorMode) { ++*stats().count; }
    9696
    9797SymbolTable::~SymbolTable() { stats().size->push( idTable ? idTable->size() : 0 ); }
     98
     99void SymbolTable::OnFindError( CodeLocation location, std::string error ) const {
     100        assertf( errorMode != AssertClean, "Name collision/redefinition, found during a compilation phase where none should be possible.  Detail: %s", error.c_str() );
     101        if (errorMode == ValidateOnAdd) {
     102                SemanticError(location, error);
     103        }
     104        assertf( errorMode == IgnoreErrors, "Unrecognized symbol-table error mode %d", errorMode );
     105}
    98106
    99107void SymbolTable::enterScope() {
     
    274282}
    275283
    276 namespace {
    277         /// true if redeclaration conflict between two types
    278         bool addedTypeConflicts( const NamedTypeDecl * existing, const NamedTypeDecl * added ) {
    279                 if ( existing->base == nullptr ) {
    280                         return false;
    281                 } else if ( added->base == nullptr ) {
    282                         return true;
    283                 } else {
    284                         // typedef redeclarations are errors only if types are different
    285                         if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) {
    286                                 SemanticError( added->location, "redeclaration of " + added->name );
    287                         }
    288                 }
    289                 // does not need to be added to the table if both existing and added have a base that are
    290                 // the same
     284bool SymbolTable::addedTypeConflicts(
     285                const NamedTypeDecl * existing, const NamedTypeDecl * added ) const {
     286        if ( existing->base == nullptr ) {
     287                return false;
     288        } else if ( added->base == nullptr ) {
    291289                return true;
    292         }
    293 
    294         /// true if redeclaration conflict between two aggregate declarations
    295         bool addedDeclConflicts( const AggregateDecl * existing, const AggregateDecl * added ) {
    296                 if ( ! existing->body ) {
    297                         return false;
    298                 } else if ( added->body ) {
    299                         SemanticError( added, "redeclaration of " );
    300                 }
    301                 return true;
    302         }
     290        } else {
     291                // typedef redeclarations are errors only if types are different
     292                if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) {
     293                        OnFindError( added->location, "redeclaration of " + added->name );
     294                }
     295        }
     296        // does not need to be added to the table if both existing and added have a base that are
     297        // the same
     298        return true;
     299}
     300
     301bool SymbolTable::addedDeclConflicts(
     302                const AggregateDecl * existing, const AggregateDecl * added ) const {
     303        if ( ! existing->body ) {
     304                return false;
     305        } else if ( added->body ) {
     306                OnFindError( added, "redeclaration of " );
     307        }
     308        return true;
    303309}
    304310
     
    653659                if ( deleter && ! existing.deleter ) {
    654660                        if ( handleConflicts.mode == OnConflict::Error ) {
    655                                 SemanticError( added, "deletion of defined identifier " );
     661                                OnFindError( added, "deletion of defined identifier " );
    656662                        }
    657663                        return true;
    658664                } else if ( ! deleter && existing.deleter ) {
    659665                        if ( handleConflicts.mode == OnConflict::Error ) {
    660                                 SemanticError( added, "definition of deleted identifier " );
     666                                OnFindError( added, "definition of deleted identifier " );
    661667                        }
    662668                        return true;
     
    666672                if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    667673                        if ( handleConflicts.mode == OnConflict::Error ) {
    668                                 SemanticError( added,
     674                                OnFindError( added,
    669675                                        isFunction( added ) ?
    670676                                                "duplicate function definition for " :
     
    675681        } else {
    676682                if ( handleConflicts.mode == OnConflict::Error ) {
    677                         SemanticError( added, "duplicate definition for " );
     683                        OnFindError( added, "duplicate definition for " );
    678684                }
    679685                return true;
     
    727733                // Check that a Cforall declaration doesn't override any C declaration
    728734                if ( hasCompatibleCDecl( name, mangleName ) ) {
    729                         SemanticError( decl, "Cforall declaration hides C function " );
     735                        OnFindError( decl, "Cforall declaration hides C function " );
    730736                }
    731737        } else {
     
    733739                // type-compatibility, which it may not be.
    734740                if ( hasIncompatibleCDecl( name, mangleName ) ) {
    735                         SemanticError( decl, "conflicting overload of C function " );
     741                        OnFindError( decl, "conflicting overload of C function " );
    736742                }
    737743        }
  • src/AST/SymbolTable.hpp

    r24d6572 r62d62db  
    9393
    9494public:
    95         SymbolTable();
     95
     96        /// Mode to control when (during which pass) user-caused name-declaration errors get reported.
     97        /// The default setting `AssertClean` supports, "I expect all user-caused errors to have been
     98        /// reported by now," or, "I wouldn't know what to do with an error; are there even any here?"
     99        enum ErrorDetection {
     100                AssertClean,               ///< invalid user decls => assert fails during addFoo (default)
     101                ValidateOnAdd,             ///< invalid user decls => calls SemanticError during addFoo
     102                IgnoreErrors               ///< acts as if unspecified decls were removed, forcing validity
     103        };
     104
     105        explicit SymbolTable(
     106                ErrorDetection             ///< mode for the lifetime of the symbol table (whole pass)
     107        );
     108        SymbolTable() : SymbolTable(AssertClean) {}
    96109        ~SymbolTable();
     110
     111        ErrorDetection getErrorMode() const {
     112                return errorMode;
     113        }
    97114
    98115        // when using an indexer manually (e.g., within a mutator traversal), it is necessary to
     
    158175
    159176private:
     177        void OnFindError( CodeLocation location, std::string error ) const;
     178
     179        template< typename T >
     180        void OnFindError( const T * obj, const std::string & error ) const {
     181                OnFindError( obj->location, toString( error, obj ) );
     182        }
     183
     184        template< typename T >
     185        void OnFindError( CodeLocation location, const T * obj, const std::string & error ) const {
     186                OnFindError( location, toString( error, obj ) );
     187        }
     188
    160189        /// Ensures that a proper backtracking scope exists before a mutation
    161190        void lazyInitScope();
     
    168197        bool removeSpecialOverrides( IdData & decl, MangleTable::Ptr & mangleTable );
    169198
    170         /// Options for handling identifier conflicts
     199        /// Error detection mode given at construction (pass-specific).
     200        /// Logically const, except that the symbol table's push-pop is achieved by autogenerated
     201        /// assignment onto self.  The feield is left motuable to keep this code-gen simple.
     202        /// Conceptual constness is preserved by all SymbolTable in a stack sharing the same mode.
     203        ErrorDetection errorMode;
     204
     205        /// Options for handling identifier conflicts.
     206        /// Varies according to AST location during traversal: captures semantics of the construct
     207        /// being visited as "would shadow" vs "must not collide."
     208        /// At a given AST location, is the same for every pass.
    171209        struct OnConflict {
    172210                enum {
    173                         Error,  ///< Throw a semantic error
     211                        Error,  ///< Follow the current pass's ErrorDetection mode (may throw a semantic error)
    174212                        Delete  ///< Delete the earlier version with the delete statement
    175213                } mode;
     
    191229                const Decl * deleter );
    192230
     231        /// true if redeclaration conflict between two types
     232        bool addedTypeConflicts( const NamedTypeDecl * existing, const NamedTypeDecl * added ) const;
     233
     234        /// true if redeclaration conflict between two aggregate declarations
     235        bool addedDeclConflicts( const AggregateDecl * existing, const AggregateDecl * added ) const;
     236
    193237        /// common code for addId, addDeletedId, etc.
    194238        void addIdCommon(
     
    213257}
    214258
     259
    215260// Local Variables: //
    216261// tab-width: 4 //
  • src/AST/Util.cpp

    r24d6572 r62d62db  
    8383}
    8484
     85/// Check that the MemberExpr has an aggregate type and matching member.
     86void memberMatchesAggregate( const MemberExpr * expr ) {
     87        const Type * aggrType = expr->aggregate->result->stripReferences();
     88        const AggregateDecl * decl = nullptr;
     89        if ( auto inst = dynamic_cast<const StructInstType *>( aggrType ) ) {
     90                decl = inst->base;
     91        } else if ( auto inst = dynamic_cast<const UnionInstType *>( aggrType ) ) {
     92                decl = inst->base;
     93        }
     94        assertf( decl, "Aggregate of member not correct type." );
     95
     96        for ( auto aggrMember : decl->members ) {
     97                if ( expr->member == aggrMember ) {
     98                        return;
     99                }
     100        }
     101        assertf( false, "Member not found." );
     102}
     103
    85104struct InvariantCore {
    86105        // To save on the number of visits: this is a kind of composed core.
     
    108127        }
    109128
     129        void previsit( const MemberExpr * node ) {
     130                previsit( (const ParseNode *)node );
     131                memberMatchesAggregate( node );
     132        }
     133
    110134        void postvisit( const Node * node ) {
    111135                no_strong_cycles.postvisit( node );
Note: See TracChangeset for help on using the changeset viewer.