Changeset b8665e3


Ignore:
Timestamp:
Mar 14, 2019, 11:53:28 AM (3 years ago)
Author:
Aaron Moss <a3moss@…>
Branches:
arm-eh, cleanup-dtors, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, persistent-indexer
Children:
b419abb
Parents:
fca6ca6
Message:

First build with persistent-map indexer

Location:
src
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • src/Common/PassVisitor.cc

    rfca6ca6 rb8665e3  
    1717
    1818PassVisitorStats pass_visitor_stats;
     19Stats::Counters::SimpleCounter* BaseSyntaxNode::new_nodes = nullptr;
  • src/Common/Stats/Counter.h

    rfca6ca6 rb8665e3  
    3737                        class SimpleCounter {
    3838                        public:
     39                                inline void operator++() {}
    3940                                inline void operator++(int) {}
    4041                                inline void operator+=(size_t) {}
     
    8485                                virtual void print(std::ostream & os) override { os << count; }
    8586
     87                                inline void operator++()             { if(!enabled) return; count++;        }
    8688                                inline void operator++(int)          { if(!enabled) return; count++;        }
    8789                                inline void operator+=(size_t value) { if(!enabled) return; count += value; }
  • src/SymTab/Indexer.cc

    rfca6ca6 rb8665e3  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:37:33 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 17 16:08:40 2017
    13 // Update Count     : 20
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Mar  8 13:55:00 2019
     13// Update Count     : 21
    1414//
    1515
     
    1919#include <iostream>                // for operator<<, basic_ostream, ostream
    2020#include <string>                  // for string, operator<<, operator!=
     21#include <memory>                  // for shared_ptr, make_shared
    2122#include <unordered_map>           // for operator!=, unordered_map<>::const...
    2223#include <unordered_set>           // for unordered_set
     
    2627#include "Common/SemanticError.h"  // for SemanticError
    2728#include "Common/utility.h"        // for cloneAll
    28 #include "Common/Stats/Counter.h" // for counters
    29 #include "GenPoly/GenPoly.h"
     29#include "Common/Stats/Counter.h"  // for counters
     30#include "GenPoly/GenPoly.h"       // for getFunctionType
    3031#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    3132#include "Mangler.h"               // for Mangler
     
    4445
    4546        // Statistics block
    46         namespace {
    47 
    48                 static inline auto stats_idtable() {
    49                         using namespace Stats::Counters;
    50                         static auto group = build<CounterGroup>("IdTable");
    51                         static struct {
    52                                 SimpleCounter * find;
    53                                 AverageCounter<double> * size;
    54                                 AverageCounter<double> * key;
    55                         } ret = {
    56                                 .find = build<SimpleCounter>("Find calls", group),
    57                                 .size = build<AverageCounter<double>>("Average Size", group),
    58                                 .key  = build<AverageCounter<double>>("Average Key Size", group),
    59                         };
    60                         return ret;
    61                 }
    62 
    63                 static inline auto stats_indexers() {
    64                         using namespace Stats::Counters;
    65                         static auto group   = build<CounterGroup>("Indexers");
    66                         static struct {
    67                                 SimpleCounter * count;
    68                                 AverageCounter<double> * size;
    69                                 AverageCounter<double> * depth_a;
    70                                 MaxCounter<size_t> * depth_m;
    71                         } ret = {
    72                                 .count   = build<SimpleCounter>("Count", group),
    73                                 .size    = build<AverageCounter<double>>("Average Size", group),
    74                                 .depth_a = build<AverageCounter<double>>("Average Depth", group),
    75                                 .depth_m = build<MaxCounter<size_t>>("Max Depth", group),
    76                         };
    77                         return ret;
    78                 }
    79         }
    80 
    81         std::ostream & operator<<( std::ostream & out, const Indexer::IdData & data ) {
    82                 return out << "(" << data.id << "," << data.baseExpr << ")";
    83         }
    84 
    85         typedef std::unordered_map< std::string, Indexer::IdData > MangleTable;
    86         typedef std::unordered_map< std::string, MangleTable > IdTable;
    87         typedef std::unordered_map< std::string, NamedTypeDecl* > TypeTable;
    88         typedef std::unordered_map< std::string, StructDecl* > StructTable;
    89         typedef std::unordered_map< std::string, EnumDecl* > EnumTable;
    90         typedef std::unordered_map< std::string, UnionDecl* > UnionTable;
    91         typedef std::unordered_map< std::string, TraitDecl* > TraitTable;
    92 
    93         void dump( const IdTable &table, std::ostream &os ) {
    94                 for ( IdTable::const_iterator id = table.begin(); id != table.end(); ++id ) {
    95                         for ( MangleTable::const_iterator mangle = id->second.begin(); mangle != id->second.end(); ++mangle ) {
    96                                 os << mangle->second << std::endl;
    97                         }
    98                 }
    99         }
    100 
    101         template< typename Decl >
    102         void dump( const std::unordered_map< std::string, Decl* > &table, std::ostream &os ) {
    103                 for ( typename std::unordered_map< std::string, Decl* >::const_iterator it = table.begin(); it != table.end(); ++it ) {
    104                         os << it->second << std::endl;
    105                 } // for
    106         }
    107 
    108         struct Indexer::Impl {
    109                 Impl( unsigned long _scope ) : refCount(1), scope( _scope ), size( 0 ), base(),
    110                                 idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {}
    111                 Impl( unsigned long _scope, Indexer &&_base ) : refCount(1), scope( _scope ), size( 0 ), base( _base ),
    112                                 idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {}
    113                 unsigned long refCount;   ///< Number of references to these tables
    114                 unsigned long scope;      ///< Scope these tables are associated with
    115                 unsigned long size;       ///< Number of elements stored in this table
    116                 const Indexer base;       ///< Base indexer this extends
    117 
    118                 IdTable idTable;          ///< Identifier namespace
    119                 TypeTable typeTable;      ///< Type namespace
    120                 StructTable structTable;  ///< Struct namespace
    121                 EnumTable enumTable;      ///< Enum namespace
    122                 UnionTable unionTable;    ///< Union namespace
    123                 TraitTable traitTable;    ///< Trait namespace
    124         };
    125 
    126         Indexer::Impl *Indexer::newRef( Indexer::Impl *toClone ) {
    127                 if ( ! toClone ) return 0;
    128 
    129                 // shorten the search chain by skipping empty links
    130                 Indexer::Impl *ret = toClone->size == 0 ? toClone->base.tables : toClone;
    131                 if ( ret ) { ++ret->refCount; }
    132 
    133                 return ret;
    134         }
    135 
    136         void Indexer::deleteRef( Indexer::Impl *toFree ) {
    137                 if ( ! toFree ) return;
    138 
    139                 if ( --toFree->refCount == 0 ) delete toFree;
    140         }
     47        // namespace {
     48
     49        //      static inline auto stats_idtable() {
     50        //              using namespace Stats::Counters;
     51        //              static auto group = build<CounterGroup>("IdTable");
     52        //              static struct {
     53        //                      SimpleCounter * find;
     54        //                      AverageCounter<double> * size;
     55        //                      AverageCounter<double> * key;
     56        //              } ret = {
     57        //                      .find = build<SimpleCounter>("Find calls", group),
     58        //                      .size = build<AverageCounter<double>>("Average Size", group),
     59        //                      .key  = build<AverageCounter<double>>("Average Key Size", group),
     60        //              };
     61        //              return ret;
     62        //      }
     63
     64        //      static inline auto stats_indexers() {
     65        //              using namespace Stats::Counters;
     66        //              static auto group   = build<CounterGroup>("Indexers");
     67        //              static struct {
     68        //                      SimpleCounter * count;
     69        //                      AverageCounter<double> * size;
     70        //                      AverageCounter<double> * depth_a;
     71        //                      MaxCounter<size_t> * depth_m;
     72        //                      SimpleCounter * new_scopes;
     73        //                      AverageCounter<double> * avg_scope_depth;
     74        //                      MaxCounter<size_t> * max_scope_depth;
     75        //                      SimpleCounter * add_calls;
     76        //                      SimpleCounter * lookup_calls;
     77        //                      SimpleCounter * map_lookups;
     78        //              } ret = {
     79        //                      .count   = build<SimpleCounter>("Count", group),
     80        //                      .size    = build<AverageCounter<double>>("Average Size", group),
     81        //                      .depth_a = build<AverageCounter<double>>("Average Depth", group),
     82        //                      .depth_m = build<MaxCounter<size_t>>("Max Depth", group),
     83        //                      .new_scopes = build<SimpleCounter>("Scopes", group),
     84        //                      .avg_scope_depth = build<AverageCounter<double>>("Average Scope", group),
     85        //                      .max_scope_depth = build<MaxCounter<size_t>>("Max Scope", group),
     86        //                      .add_calls = build<SimpleCounter>("Add Calls", group),
     87        //                      .lookup_calls = build<SimpleCounter>("Lookup Calls", group),
     88        //                      .map_lookups = build<SimpleCounter>("Map Lookups", group),
     89        //              };
     90        //              return ret;
     91        //      }
     92        // }
     93
     94        // std::ostream & operator<<( std::ostream & out, const Indexer::IdData & data ) {
     95        //      return out << "(" << data.id << "," << data.baseExpr << ")";
     96        // }
     97
     98        // void dump( const Indexer::IdTable &table, std::ostream &os ) {
     99        //      for ( IdTable::const_iterator id = table.begin(); id != table.end(); ++id ) {
     100        //              for ( MangleTable::const_iterator mangle = id->second.begin(); mangle != id->second.end(); ++mangle ) {
     101        //                      os << mangle->second << std::endl;
     102        //              }
     103        //      }
     104        // }
     105
     106        // template< typename Decl >
     107        // void dump( const PersistentMap< std::string, Decl* > &table, std::ostream &os ) {
     108        //      for ( auto decl : table ) {
     109        //              os << decl.second << std::endl;
     110        //      } // for
     111        // }
    141112
    142113        void Indexer::removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const {
     
    163134                                bool isCopyFunc = InitTweak::isCopyFunction( function, function->name );
    164135                                decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } );
    165                                 existsUserDefinedCopyFunc = existsUserDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc);
     136                                existsUserDefinedCopyFunc |= (isUserDefinedFunc && isCopyFunc);
    166137                                if ( isUserDefinedFunc && ! deleteStmt ) {
    167138                                        // any user-defined function can act as an implicit delete statement for generated constructors.
     
    225196        }
    226197
    227         void Indexer::makeWritable() {
    228                 if ( ! tables ) {
    229                         // create indexer if not yet set
    230                         tables = new Indexer::Impl( scope );
    231                 } else if ( tables->refCount > 1 || tables->scope != scope ) {
    232                         // make this indexer the base of a fresh indexer at the current scope
    233                         tables = new Indexer::Impl( scope, std::move( *this ) );
    234                 }
    235         }
    236 
    237         Indexer::Indexer() : tables( 0 ), scope( 0 ) {
    238                 (*stats_indexers().count)++;
    239         }
    240 
    241         Indexer::Indexer( const Indexer &that ) : doDebug( that.doDebug ), tables( newRef( that.tables ) ), scope( that.scope ) {
    242                 (*stats_indexers().count)++;
    243         }
    244 
    245         Indexer::Indexer( Indexer &&that ) : doDebug( that.doDebug ), tables( that.tables ), scope( that.scope ) {
    246                 that.tables = 0;
    247         }
    248 
    249         Indexer::~Indexer() {
    250                 if(tables) {
    251                         stats_indexers().size->push( tables->idTable.size() );
    252                         size_t depth = 1;
    253                         for( auto crnt = tables->base.tables; crnt; crnt = crnt->base.tables ) {
    254                                 ++depth;
    255                         }
    256                         stats_indexers().depth_a->push( depth );
    257                         stats_indexers().depth_m->push( depth );
    258                 }
    259                 deleteRef( tables );
    260         }
    261 
    262         Indexer& Indexer::operator= ( const Indexer &that ) {
    263                 deleteRef( tables );
    264 
    265                 tables = newRef( that.tables );
    266                 scope = that.scope;
    267                 doDebug = that.doDebug;
    268 
    269                 return *this;
    270         }
    271 
    272         Indexer& Indexer::operator= ( Indexer &&that ) {
    273                 deleteRef( tables );
    274 
    275                 tables = that.tables;
    276                 scope = that.scope;
    277                 doDebug = that.doDebug;
    278 
    279                 that.tables = 0;
    280 
    281                 return *this;
     198        Indexer::Indexer()
     199        : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
     200          prevScope(), scope( 0 ) {}
     201
     202        Indexer::~Indexer() {}
     203
     204        void Indexer::enterScope() {
     205                // save current state in prevScope and increment scope
     206                prevScope = std::make_shared<Indexer>( *this );
     207                ++scope;
     208
     209                // if ( doDebug ) {
     210                //      std::cerr << "--- Entering scope " << scope << std::endl;
     211                // }
     212        }
     213
     214        void Indexer::leaveScope() {
     215                // if ( doDebug ) {
     216                //      std::cerr << "--- Leaving scope " << scope << " containing" << std::endl;
     217                //      dump( idTable, std::cerr );
     218                //      dump( typeTable, std::cerr );
     219                //      dump( structTable, std::cerr );
     220                //      dump( enumTable, std::cerr );
     221                //      dump( unionTable, std::cerr );
     222                //      dump( traitTable, std::cerr );
     223                // }
     224
     225                // replace all maps and scope index with previous scope's versions
     226                *this = *prevScope;
    282227        }
    283228
    284229        void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
    285                 std::unordered_set< std::string > foundMangleNames;
    286 
    287                 Indexer::Impl *searchTables = tables;
    288                 while ( searchTables ) {
    289 
    290                         (*stats_idtable().find)++;
    291                         stats_idtable().key->push( id.size() );
    292                         stats_idtable().size->push( searchTables->idTable.size() );
    293                         IdTable::const_iterator decls = searchTables->idTable.find( id );
    294                         if ( decls != searchTables->idTable.end() ) {
    295                                 const MangleTable &mangleTable = decls->second;
    296                                 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    297                                         // mark the mangled name as found, skipping this insertion if a declaration for that name has already been found
    298                                         if ( foundMangleNames.insert( decl->first ).second == false ) continue;
    299 
    300                                         out.push_back( decl->second );
    301                                 }
    302                         }
    303 
    304                         // get declarations from base indexers
    305                         searchTables = searchTables->base.tables;
    306                 }
    307 
     230                if ( ! idTable ) return;
     231
     232                auto decls = idTable->find( id );
     233                if ( decls == idTable->end() ) return;
     234
     235                for ( auto decl : *(decls->second) ) {
     236                        out.push_back( decl.second );
     237                }
     238               
    308239                // some special functions, e.g. constructors and destructors
    309240                // remove autogenerated functions when they are defined so that
     
    313244
    314245        NamedTypeDecl *Indexer::lookupType( const std::string &id ) const {
    315                 if ( ! tables ) return 0;
    316 
    317                 TypeTable::const_iterator ret = tables->typeTable.find( id );
    318                 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupType( id );
     246                if ( ! typeTable ) return nullptr;
     247                auto it = typeTable->find( id );
     248                return it == typeTable->end() ? nullptr : it->second.decl;
    319249        }
    320250
    321251        StructDecl *Indexer::lookupStruct( const std::string &id ) const {
    322                 if ( ! tables ) return 0;
    323 
    324                 StructTable::const_iterator ret = tables->structTable.find( id );
    325                 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStruct( id );
    326         }
     252                if ( ! structTable ) return nullptr;
     253                auto it = structTable->find( id );
     254                return it == structTable->end() ? nullptr : it->second.decl;
     255        }
     256
     257        EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
     258                if ( ! enumTable ) return nullptr;
     259                auto it = enumTable->find( id );
     260                return it == enumTable->end() ? nullptr : it->second.decl;
     261        }
     262
     263        UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
     264                if ( ! unionTable ) return nullptr;
     265                auto it = unionTable->find( id );
     266                return it == unionTable->end() ? nullptr : it->second.decl;
     267        }
     268
     269        TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
     270                if ( ! traitTable ) return nullptr;
     271                auto it = traitTable->find( id );
     272                return it == traitTable->end() ? nullptr : it->second.decl;
     273        }
     274
     275        const Indexer* Indexer::atScope( unsigned long scope ) const {
     276                // scan back to scope; guaranteed one indexer per scope by construction of enterScope,
     277                // final indexer in list has scope 0, cannot be > scope
     278                const Indexer* indexer = this;
     279                while ( indexer->scope > scope ) {
     280                        indexer = indexer->prevScope.get();
     281                }
     282                return indexer;
     283        }
     284
     285        // const Indexer::IdData * Indexer::localLookupId(
     286        //              const std::string &id, const std::string &mangleName ) const {
     287        //      if ( ! idTable ) return nullptr;
     288
     289        //      // lookup name
     290        //      auto decls = idTable->find( id );
     291        //      if ( decls == idTable->end() ) return nullptr;
     292
     293        //      // lookup mangleName
     294        //      // assume any mangle-table pointer added is non-null
     295        //      const MangleTable& mangleTable = *(decls->second);
     296        //      auto decl = mangleTable.find( mangleName );
     297        //      if ( decl == mangleTable.end() ) return nullptr;
     298               
     299        //      // skip identifiers not defined in this scope
     300        //      if ( decl->second.scope != scope ) return nullptr;
     301        //      return &decl->second;
     302        // }
     303
     304        // Indexer::IdData * Indexer::lookupIdAtScope(
     305        //              const std::string &id, const std::string &mangleName, unsigned long scope ) {
     306        //      return const_cast<IdData *>(
     307        //              const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope ));
     308        // }
     309
     310        // NamedTypeDecl *Indexer::lookupTypeAtScope( const std::string &id, unsigned long scope ) const {
     311
     312        //      if ( ! tables ) return ++*stats_indexers().lookup_calls, nullptr;
     313        //      if ( tables->scope < scope ) return ++*stats_indexers().lookup_calls, nullptr;
     314        //      if ( tables->scope > scope ) return tables->base.lookupTypeAtScope( id, scope );
     315
     316        //      ++*stats_indexers().map_lookups;
     317        //      TypeTable::const_iterator ret = tables->typeTable.find( id );
     318        //      return ret != tables->typeTable.end() ?
     319        //              ++*stats_indexers().lookup_calls, ret->second :
     320        //              tables->base.lookupTypeAtScope( id, scope );
     321        // }
     322
     323        // StructDecl *Indexer::lookupStructAtScope( const std::string &id, unsigned long scope ) const {
     324        //      if ( ! tables ) return ++*stats_indexers().lookup_calls, nullptr;
     325        //      if ( tables->scope < scope ) return ++*stats_indexers().lookup_calls, nullptr;
     326        //      if ( tables->scope > scope ) return tables->base.lookupStructAtScope( id, scope );
     327
     328        //      ++*stats_indexers().map_lookups;
     329        //      StructTable::const_iterator ret = tables->structTable.find( id );
     330        //      return ret != tables->structTable.end() ?
     331        //              ++*stats_indexers().lookup_calls, ret->second :
     332        //              tables->base.lookupStructAtScope( id, scope );
     333        // }
     334
     335        // EnumDecl *Indexer::lookupEnumAtScope( const std::string &id, unsigned long scope ) const {
     336        //      if ( ! tables ) return ++*stats_indexers().lookup_calls, nullptr;
     337        //      if ( tables->scope < scope ) return ++*stats_indexers().lookup_calls, nullptr;
     338        //      if ( tables->scope > scope ) return tables->base.lookupEnumAtScope( id, scope );
     339
     340        //      ++*stats_indexers().map_lookups;
     341        //      EnumTable::const_iterator ret = tables->enumTable.find( id );
     342        //      return ret != tables->enumTable.end() ?
     343        //              ++*stats_indexers().lookup_calls, ret->second :
     344        //              tables->base.lookupEnumAtScope( id, scope );
     345        // }
     346
     347        // UnionDecl *Indexer::lookupUnionAtScope( const std::string &id, unsigned long scope ) const {
     348        //      if ( ! tables ) return ++*stats_indexers().lookup_calls, nullptr;
     349        //      if ( tables->scope < scope ) return ++*stats_indexers().lookup_calls, nullptr;
     350        //      if ( tables->scope > scope ) return tables->base.lookupUnionAtScope( id, scope );
     351
     352        //      ++*stats_indexers().map_lookups;
     353        //      UnionTable::const_iterator ret = tables->unionTable.find( id );
     354        //      return ret != tables->unionTable.end() ?
     355        //              ++*stats_indexers().lookup_calls, ret->second :
     356        //              tables->base.lookupUnionAtScope( id, scope );
     357        // }
     358
     359        // TraitDecl *Indexer::lookupTraitAtScope( const std::string &id, unsigned long scope ) const {
     360        //      if ( ! tables ) return ++*stats_indexers().lookup_calls, nullptr;
     361        //      if ( tables->scope < scope ) return ++*stats_indexers().lookup_calls, nullptr;
     362        //      if ( tables->scope > scope ) return tables->base.lookupTraitAtScope( id, scope );
     363
     364        //      ++*stats_indexers().map_lookups;
     365        //      TraitTable::const_iterator ret = tables->traitTable.find( id );
     366        //      return ret != tables->traitTable.end() ?
     367        //              ++*stats_indexers().lookup_calls, ret->second :
     368        //              tables->base.lookupTraitAtScope( id, scope );
     369        // }
    327370
    328371        NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
    329                 return lookupTypeAtScope( id, 0 );
     372                return atScope( 0 )->lookupType( id );
    330373        }
    331374
    332375        StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
    333                 return lookupStructAtScope( id, 0 );
     376                return atScope( 0 )->lookupStruct( id );
    334377        }
    335378
    336379        UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
    337                 return lookupUnionAtScope( id, 0 );
     380                return atScope( 0 )->lookupUnion( id );
    338381        }
    339382
    340383        EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
    341                 return lookupEnumAtScope( id, 0 );
    342         }
    343 
    344         EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
    345                 if ( ! tables ) return 0;
    346 
    347                 EnumTable::const_iterator ret = tables->enumTable.find( id );
    348                 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnum( id );
    349         }
    350 
    351         UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
    352                 if ( ! tables ) return 0;
    353 
    354                 UnionTable::const_iterator ret = tables->unionTable.find( id );
    355                 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnion( id );
    356         }
    357 
    358         TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
    359                 if ( ! tables ) return 0;
    360 
    361                 TraitTable::const_iterator ret = tables->traitTable.find( id );
    362                 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTrait( id );
    363         }
    364 
    365         const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    366                 if ( ! tables ) return nullptr;
    367                 if ( tables->scope < scope ) return nullptr;
    368 
    369                 (*stats_idtable().find)++;
    370                 stats_idtable().key->push( id.size() );
    371                 stats_idtable().size->push( tables->idTable.size() );
    372                 IdTable::const_iterator decls = tables->idTable.find( id );
    373                 if ( decls != tables->idTable.end() ) {
    374                         const MangleTable &mangleTable = decls->second;
    375                         MangleTable::const_iterator decl = mangleTable.find( mangleName );
    376                         if ( decl != mangleTable.end() ) return &decl->second;
    377                 }
    378 
    379                 return tables->base.lookupIdAtScope( id, mangleName, scope );
    380         }
    381 
    382         Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) {
    383                 return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope ));
    384         }
    385 
    386         bool Indexer::hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    387                 if ( ! tables ) return false;
    388                 if ( tables->scope < scope ) return false;
    389 
    390                 (*stats_idtable().find)++;
    391                 stats_idtable().key->push( id.size() );
    392                 stats_idtable().size->push( tables->idTable.size() );
    393                 IdTable::const_iterator decls = tables->idTable.find( id );
    394                 if ( decls != tables->idTable.end() ) {
    395                         const MangleTable &mangleTable = decls->second;
    396                         for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    397                                 // check for C decls with the same name, skipping those with a compatible type (by mangleName)
    398                                 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first != mangleName ) return true;
    399                         }
    400                 }
    401 
    402                 return tables->base.hasIncompatibleCDecl( id, mangleName, scope );
    403         }
    404 
    405         bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    406                 if ( ! tables ) return false;
    407                 if ( tables->scope < scope ) return false;
    408 
    409                 (*stats_idtable().find)++;
    410                 stats_idtable().key->push( id.size() );
    411                 stats_idtable().size->push( tables->idTable.size() );
    412                 IdTable::const_iterator decls = tables->idTable.find( id );
    413                 if ( decls != tables->idTable.end() ) {
    414                         const MangleTable &mangleTable = decls->second;
    415                         for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    416                                 // check for C decls with the same name, skipping
    417                                 // those with an incompatible type (by mangleName)
    418                                 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first == mangleName ) return true;
    419                         }
    420                 }
    421 
    422                 return tables->base.hasCompatibleCDecl( id, mangleName, scope );
    423         }
    424 
    425         NamedTypeDecl *Indexer::lookupTypeAtScope( const std::string &id, unsigned long scope ) const {
    426                 if ( ! tables ) return 0;
    427                 if ( tables->scope < scope ) return 0;
    428                 if ( tables->scope > scope ) return tables->base.lookupTypeAtScope( id, scope );
    429 
    430                 TypeTable::const_iterator ret = tables->typeTable.find( id );
    431                 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupTypeAtScope( id, scope );
    432         }
    433 
    434         StructDecl *Indexer::lookupStructAtScope( const std::string &id, unsigned long scope ) const {
    435                 if ( ! tables ) return 0;
    436                 if ( tables->scope < scope ) return 0;
    437                 if ( tables->scope > scope ) return tables->base.lookupStructAtScope( id, scope );
    438 
    439                 StructTable::const_iterator ret = tables->structTable.find( id );
    440                 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStructAtScope( id, scope );
    441         }
    442 
    443         EnumDecl *Indexer::lookupEnumAtScope( const std::string &id, unsigned long scope ) const {
    444                 if ( ! tables ) return 0;
    445                 if ( tables->scope < scope ) return 0;
    446                 if ( tables->scope > scope ) return tables->base.lookupEnumAtScope( id, scope );
    447 
    448                 EnumTable::const_iterator ret = tables->enumTable.find( id );
    449                 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnumAtScope( id, scope );
    450         }
    451 
    452         UnionDecl *Indexer::lookupUnionAtScope( const std::string &id, unsigned long scope ) const {
    453                 if ( ! tables ) return 0;
    454                 if ( tables->scope < scope ) return 0;
    455                 if ( tables->scope > scope ) return tables->base.lookupUnionAtScope( id, scope );
    456 
    457                 UnionTable::const_iterator ret = tables->unionTable.find( id );
    458                 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnionAtScope( id, scope );
    459         }
    460 
    461         TraitDecl *Indexer::lookupTraitAtScope( const std::string &id, unsigned long scope ) const {
    462                 if ( ! tables ) return 0;
    463                 if ( tables->scope < scope ) return 0;
    464                 if ( tables->scope > scope ) return tables->base.lookupTraitAtScope( id, scope );
    465 
    466                 TraitTable::const_iterator ret = tables->traitTable.find( id );
    467                 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTraitAtScope( id, scope );
     384                return atScope( 0 )->lookupEnum( id );
    468385        }
    469386
     
    487404        }
    488405
    489         bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) {
     406       
     407        bool Indexer::addedIdConflicts(
     408                        const Indexer::IdData & existing, DeclarationWithType *added,
     409                        Indexer::OnConflict handleConflicts, BaseSyntaxNode * deleteStmt ) {
    490410                // if we're giving the same name mangling to things of different types then there is something wrong
    491411                assert( (isObject( added ) && isObject( existing.id ) )
    492412                        || ( isFunction( added ) && isFunction( existing.id ) ) );
    493413
    494                 if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
     414                if ( LinkageSpec::isOverridable( existing.id->linkage ) ) {
    495415                        // new definition shadows the autogenerated one, even at the same scope
    496416                        return false;
    497                 } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) {
     417                } else if ( LinkageSpec::isMangled( added->linkage )
     418                                || ResolvExpr::typesCompatible(
     419                                        added->get_type(), existing.id->get_type(), Indexer() ) ) {
    498420
    499421                        // it is a conflict if one declaration is deleted and the other is not
    500422                        if ( deleteStmt && ! existing.deleteStmt ) {
    501                                 return handleConflicts( existing, "deletion of defined identifier " );
     423                                if ( handleConflicts.mode == OnConflict::Error ) {
     424                                        SemanticError( added, "deletion of defined identifier " );
     425                                }
     426                                return true;
    502427                        } else if ( ! deleteStmt && existing.deleteStmt ) {
    503                                 return handleConflicts( existing, "definition of deleted identifier " );
     428                                if ( handleConflicts.mode == OnConflict::Error ) {
     429                                        SemanticError( added, "definition of deleted identifier " );
     430                                }
     431                                return true;
    504432                        }
    505433
    506434                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    507                                 if ( isFunction( added ) ) {
    508                                         return handleConflicts( existing, "duplicate function definition for " );
    509                                 } else {
    510                                         return handleConflicts( existing, "duplicate object definition for " );
    511                                 } // if
     435                                if ( handleConflicts.mode == OnConflict::Error ) {
     436                                        SemanticError( added,
     437                                                isFunction( added ) ?
     438                                                        "duplicate function definition for " :
     439                                                        "duplicate object definition for " );
     440                                }
     441                                return true;
    512442                        } // if
    513443                } else {
    514                         return handleConflicts( existing, "duplicate definition for " );
     444                        if ( handleConflicts.mode == OnConflict::Error ) {
     445                                SemanticError( added, "duplicate definition for " );
     446                        }
     447                        return true;
    515448                } // if
    516449
     
    518451        }
    519452
    520         void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) {
     453        bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const {
     454                if ( ! idTable ) return false;
     455
     456                auto decls = idTable->find( id );
     457                if ( decls == idTable->end() ) return false;
     458
     459                for ( auto decl : *(decls->second) ) {
     460                        // skip other scopes (hidden by this decl)
     461                        if ( decl.second.scope != scope ) continue;
     462                        // check for C decl with compatible type (by mangleName)
     463                        if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first == mangleName ) {
     464                                return true;
     465                        }
     466                }
     467               
     468                return false;
     469        }
     470
     471        bool Indexer::hasIncompatibleCDecl(
     472                        const std::string &id, const std::string &mangleName ) const {
     473                if ( ! idTable ) return false;
     474
     475                auto decls = idTable->find( id );
     476                if ( decls == idTable->end() ) return false;
     477
     478                for ( auto decl : *(decls->second) ) {
     479                        // skip other scopes (hidden by this decl)
     480                        if ( decl.second.scope != scope ) continue;
     481                        // check for C decl with incompatible type (by manglename)
     482                        if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first != mangleName ) {
     483                                return true;
     484                        }
     485                }
     486
     487                return false;
     488        }
     489
     490        void Indexer::addId(
     491                        DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr,
     492                        BaseSyntaxNode * deleteStmt ) {
    521493                if ( decl->name == "" ) return;
    522                 debugPrint( "Adding Id " << decl->name << std::endl );
    523                 makeWritable();
    524 
     494                // debugPrint( "Adding Id " << decl->name << std::endl );
     495               
    525496                const std::string &name = decl->name;
    526497                std::string mangleName;
    527498                if ( LinkageSpec::isOverridable( decl->linkage ) ) {
    528                         // mangle the name without including the appropriate suffix, so overridable routines are placed into the
    529                         // same "bucket" as their user defined versions.
     499                        // mangle the name without including the appropriate suffix, so overridable routines
     500                        // are placed into the same "bucket" as their user defined versions.
    530501                        mangleName = Mangler::mangle( decl, false );
    531502                } else {
     
    533504                } // if
    534505
    535                 // this ensures that no two declarations with the same unmangled name at the same scope both have C linkage
    536                 if ( ! LinkageSpec::isMangled( decl->linkage ) ) {
    537                         // NOTE this is broken in Richard's original code in such a way that it never triggers (it
    538                         // doesn't check decls that have the same manglename, and all C-linkage decls are defined to
    539                         // have their name as their manglename, hence the error can never trigger).
    540                         // The code here is closer to correct, but name mangling would have to be completely
    541                         // isomorphic to C type-compatibility, which it may not be.
    542                         if ( hasIncompatibleCDecl( name, mangleName, scope ) ) {
     506                // this ensures that no two declarations with the same unmangled name at the same scope
     507                // both have C linkage
     508                if ( LinkageSpec::isMangled( decl->linkage ) ) {
     509                        // Check that a Cforall declaration doesn't override any C declaration
     510                        if ( hasCompatibleCDecl( name, mangleName ) ) {
     511                                SemanticError( decl, "Cforall declaration hides C function " );
     512                        }
     513                } else {
     514                        // NOTE: only correct if name mangling is completely isomorphic to C
     515                        // type-compatibility, which it may not be.
     516                        if ( hasIncompatibleCDecl( name, mangleName ) ) {
    543517                                SemanticError( decl, "conflicting overload of C function " );
    544518                        }
    545                 } else {
    546                         // Check that a Cforall declaration doesn't override any C declaration
    547                         if ( hasCompatibleCDecl( name, mangleName, scope ) ) {
    548                                 SemanticError( decl, "Cforall declaration hides C function " );
    549                         }
    550                 }
    551 
    552                 // Skip repeat declarations of the same identifier
    553                 IdData * existing = lookupIdAtScope( name, mangleName, scope );
    554                 if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return;
    555 
    556                 // add to indexer
    557                 tables->idTable[ name ][ mangleName ] = IdData{ decl, baseExpr, deleteStmt };
    558                 ++tables->size;
     519                }
     520
     521                // ensure tables exist and add identifier
     522                MangleTable::Ptr mangleTable;
     523                if ( ! idTable ) {
     524                        idTable = IdTable::new_ptr();
     525                        mangleTable = MangleTable::new_ptr();
     526                } else {
     527                        auto decls = idTable->find( name );
     528                        if ( decls == idTable->end() ) {
     529                                mangleTable = MangleTable::new_ptr();
     530                        } else {
     531                                mangleTable = decls->second;
     532                                // skip in-scope repeat declarations of same identifier
     533                                auto existing = mangleTable->find( mangleName );
     534                                if ( existing != mangleTable->end()
     535                                                && existing->second.scope == scope
     536                                                && existing->second.id ) {
     537                                        if ( addedIdConflicts( existing->second, decl, handleConflicts, deleteStmt ) ) {
     538                                                if ( handleConflicts.mode == OnConflict::Delete ) {
     539                                                        // set delete expression for conflicting identifier
     540                                                        idTable = idTable->set(
     541                                                                name,
     542                                                                mangleTable->set(
     543                                                                        mangleName,
     544                                                                        IdData{ existing->second, handleConflicts.deleteStmt } ) );
     545                                                }
     546                                                return;
     547                                        }
     548                                }
     549                        }
     550                }
     551
     552                // add/overwrite with new identifier
     553                idTable = idTable->set(
     554                        name,
     555                        mangleTable->set( mangleName, IdData{ decl, baseExpr, deleteStmt, scope } ) );
    559556        }
    560557
    561558        void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
    562559                // default handling of conflicts is to raise an error
    563                 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr );
     560                addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
    564561        }
    565562
    566563        void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
    567564                // default handling of conflicts is to raise an error
    568                 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
     565                addId( decl, OnConflict::error(), nullptr, deleteStmt );
    569566        }
    570567
     
    586583
    587584        void Indexer::addType( NamedTypeDecl *decl ) {
    588                 debugPrint( "Adding type " << decl->name << std::endl );
    589                 makeWritable();
    590 
    591585                const std::string &id = decl->name;
    592                 TypeTable::iterator existing = tables->typeTable.find( id );
    593                 if ( existing == tables->typeTable.end() ) {
    594                         NamedTypeDecl *parent = tables->base.lookupTypeAtScope( id, scope );
    595                         if ( ! parent || ! addedTypeConflicts( parent, decl ) ) {
    596                                 tables->typeTable.insert( existing, std::make_pair( id, decl ) );
    597                                 ++tables->size;
    598                         }
    599                 } else {
    600                         if ( ! addedTypeConflicts( existing->second, decl ) ) {
    601                                 existing->second = decl;
    602                         }
    603                 }
     586
     587                if ( ! typeTable ) {
     588                        typeTable = TypeTable::new_ptr();
     589                } else {
     590                        auto existing = typeTable->find( id );
     591                        if ( existing != typeTable->end()
     592                                && existing->second.scope == scope
     593                                && addedTypeConflicts( existing->second.decl, decl ) ) return;
     594                }
     595               
     596                typeTable = typeTable->set( id, Scoped<NamedTypeDecl>{ decl, scope } );
    604597        }
    605598
     
    614607
    615608        void Indexer::addStruct( const std::string &id ) {
    616                 debugPrint( "Adding fwd decl for struct " << id << std::endl );
    617609                addStruct( new StructDecl( id ) );
    618610        }
    619611
    620612        void Indexer::addStruct( StructDecl *decl ) {
    621                 debugPrint( "Adding struct " << decl->name << std::endl );
    622                 makeWritable();
    623 
    624613                const std::string &id = decl->name;
    625                 StructTable::iterator existing = tables->structTable.find( id );
    626                 if ( existing == tables->structTable.end() ) {
    627                         StructDecl *parent = tables->base.lookupStructAtScope( id, scope );
    628                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    629                                 tables->structTable.insert( existing, std::make_pair( id, decl ) );
    630                                 ++tables->size;
    631                         }
    632                 } else {
    633                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    634                                 existing->second = decl;
    635                         }
    636                 }
     614
     615                if ( ! structTable ) {
     616                        structTable = StructTable::new_ptr();
     617                } else {
     618                        auto existing = structTable->find( id );
     619                        if ( existing != structTable->end() 
     620                                && existing->second.scope == scope
     621                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     622                }
     623
     624                structTable = structTable->set( id, Scoped<StructDecl>{ decl, scope } );
    637625        }
    638626
    639627        void Indexer::addEnum( EnumDecl *decl ) {
    640                 debugPrint( "Adding enum " << decl->name << std::endl );
    641                 makeWritable();
    642 
    643628                const std::string &id = decl->name;
    644                 EnumTable::iterator existing = tables->enumTable.find( id );
    645                 if ( existing == tables->enumTable.end() ) {
    646                         EnumDecl *parent = tables->base.lookupEnumAtScope( id, scope );
    647                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    648                                 tables->enumTable.insert( existing, std::make_pair( id, decl ) );
    649                                 ++tables->size;
    650                         }
    651                 } else {
    652                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    653                                 existing->second = decl;
    654                         }
    655                 }
     629
     630                if ( ! enumTable ) {
     631                        enumTable = EnumTable::new_ptr();
     632                } else {
     633                        auto existing = enumTable->find( id );
     634                        if ( existing != enumTable->end() 
     635                                && existing->second.scope == scope
     636                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     637                }
     638               
     639                enumTable = enumTable->set( id, Scoped<EnumDecl>{ decl, scope } );
    656640        }
    657641
    658642        void Indexer::addUnion( const std::string &id ) {
    659                 debugPrint( "Adding fwd decl for union " << id << std::endl );
    660643                addUnion( new UnionDecl( id ) );
    661644        }
    662645
    663646        void Indexer::addUnion( UnionDecl *decl ) {
    664                 debugPrint( "Adding union " << decl->name << std::endl );
    665                 makeWritable();
    666 
    667647                const std::string &id = decl->name;
    668                 UnionTable::iterator existing = tables->unionTable.find( id );
    669                 if ( existing == tables->unionTable.end() ) {
    670                         UnionDecl *parent = tables->base.lookupUnionAtScope( id, scope );
    671                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    672                                 tables->unionTable.insert( existing, std::make_pair( id, decl ) );
    673                                 ++tables->size;
    674                         }
    675                 } else {
    676                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    677                                 existing->second = decl;
    678                         }
    679                 }
     648
     649                if ( ! unionTable ) {
     650                        unionTable = UnionTable::new_ptr();
     651                } else {
     652                        auto existing = unionTable->find( id );
     653                        if ( existing != unionTable->end()
     654                                && existing->second.scope == scope
     655                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     656                }
     657
     658                unionTable = unionTable->set( id, Scoped<UnionDecl>{ decl, scope } );
    680659        }
    681660
    682661        void Indexer::addTrait( TraitDecl *decl ) {
    683                 debugPrint( "Adding trait " << decl->name << std::endl );
    684                 makeWritable();
    685 
    686662                const std::string &id = decl->name;
    687                 TraitTable::iterator existing = tables->traitTable.find( id );
    688                 if ( existing == tables->traitTable.end() ) {
    689                         TraitDecl *parent = tables->base.lookupTraitAtScope( id, scope );
    690                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    691                                 tables->traitTable.insert( existing, std::make_pair( id, decl ) );
    692                                 ++tables->size;
    693                         }
    694                 } else {
    695                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    696                                 existing->second = decl;
    697                         }
    698                 }
    699         }
    700 
    701         void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) {
     663
     664                if ( ! traitTable ) {
     665                        traitTable = TraitTable::new_ptr();
     666                } else {
     667                        auto existing = traitTable->find( id );
     668                        if ( existing != traitTable->end()
     669                                && existing->second.scope == scope
     670                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     671                }
     672
     673                traitTable = traitTable->set( id, Scoped<TraitDecl>{ decl, scope } );
     674        }
     675
     676        void Indexer::addMembers( AggregateDecl * aggr, Expression * expr,
     677                        OnConflict handleConflicts ) {
    702678                for ( Declaration * decl : aggr->members ) {
    703679                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
     
    705681                                if ( dwt->name == "" ) {
    706682                                        Type * t = dwt->get_type()->stripReferences();
    707                                         if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) {
     683                                        if ( dynamic_cast<StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {
    708684                                                Expression * base = expr->clone();
    709685                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
     
    722698                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
    723699
    724                                 addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) {
    725                                         // on conflict, delete the identifier
    726                                         existing.deleteStmt = withStmt;
    727                                         return true;
    728                                 });
     700                                addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
    729701                        }
    730702                }
     
    750722        }
    751723
    752         void Indexer::enterScope() {
    753                 ++scope;
    754 
    755                 if ( doDebug ) {
    756                         std::cerr << "--- Entering scope " << scope << std::endl;
    757                 }
    758         }
    759 
    760         void Indexer::leaveScope() {
    761                 using std::cerr;
    762 
    763                 assert( scope > 0 && "cannot leave initial scope" );
    764                 if ( doDebug ) {
    765                         cerr << "--- Leaving scope " << scope << " containing" << std::endl;
    766                 }
    767                 --scope;
    768 
    769                 while ( tables && tables->scope > scope ) {
    770                         if ( doDebug ) {
    771                                 dump( tables->idTable, cerr );
    772                                 dump( tables->typeTable, cerr );
    773                                 dump( tables->structTable, cerr );
    774                                 dump( tables->enumTable, cerr );
    775                                 dump( tables->unionTable, cerr );
    776                                 dump( tables->traitTable, cerr );
    777                         }
    778 
    779                         // swap tables for base table until we find one at an appropriate scope
    780                         Indexer::Impl *base = newRef( tables->base.tables );
    781                         deleteRef( tables );
    782                         tables = base;
    783                 }
    784         }
    785 
    786         void Indexer::print( std::ostream &os, int indent ) const {
    787                 using std::cerr;
    788 
    789                 if ( tables ) {
    790                         os << "--- scope " << tables->scope << " ---" << std::endl;
    791 
    792                         os << "===idTable===" << std::endl;
    793                         dump( tables->idTable, os );
    794                         os << "===typeTable===" << std::endl;
    795                         dump( tables->typeTable, os );
    796                         os << "===structTable===" << std::endl;
    797                         dump( tables->structTable, os );
    798                         os << "===enumTable===" << std::endl;
    799                         dump( tables->enumTable, os );
    800                         os << "===unionTable===" << std::endl;
    801                         dump( tables->unionTable, os );
    802                         os << "===contextTable===" << std::endl;
    803                         dump( tables->traitTable, os );
    804 
    805                         tables->base.print( os, indent );
    806                 } else {
    807                         os << "--- end ---" << std::endl;
    808                 }
    809 
    810         }
     724        // void Indexer::print( std::ostream &os, int indent ) const {
     725        //      using std::cerr;
     726
     727        //      if ( tables ) {
     728        //              os << "--- scope " << tables->scope << " ---" << std::endl;
     729
     730        //              os << "===idTable===" << std::endl;
     731        //              dump( tables->idTable, os );
     732        //              os << "===typeTable===" << std::endl;
     733        //              dump( tables->typeTable, os );
     734        //              os << "===structTable===" << std::endl;
     735        //              dump( tables->structTable, os );
     736        //              os << "===enumTable===" << std::endl;
     737        //              dump( tables->enumTable, os );
     738        //              os << "===unionTable===" << std::endl;
     739        //              dump( tables->unionTable, os );
     740        //              os << "===contextTable===" << std::endl;
     741        //              dump( tables->traitTable, os );
     742
     743        //              tables->base.print( os, indent );
     744        //      } else {
     745        //              os << "--- end ---" << std::endl;
     746        //      }
     747        // }
    811748
    812749        Expression * Indexer::IdData::combine( ResolvExpr::Cost & cost ) const {
  • src/SymTab/Indexer.h

    rfca6ca6 rb8665e3  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:38:55 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 17 16:09:12 2017
    13 // Update Count     : 8
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Mar  8 13:55:00 2019
     13// Update Count     : 9
    1414//
    1515
    1616#pragma once
    1717
    18 #include <iosfwd>             // for ostream
    19 #include <list>               // for list
    20 #include <string>             // for string
    21 #include <functional>         // for function
    22 
    23 #include "SynTree/Visitor.h"  // for Visitor
    24 #include "SynTree/SynTree.h"  // for AST nodes
     18#include <functional>              // for function
     19#include <iosfwd>                  // for ostream
     20#include <list>                    // for list
     21#include <memory>                  // for shared_ptr, enable_shared_from_this
     22#include <string>                  // for string
     23
     24#include "Common/PersistentMap.h"  // for PersistentMap
     25#include "SynTree/SynTree.h"       // for AST nodes
    2526
    2627namespace ResolvExpr {
    27 class Cost;
     28        class Cost;
    2829}
    2930
    3031namespace SymTab {
    31         class Indexer {
    32           public:
     32        class Indexer : public std::enable_shared_from_this<SymTab::Indexer> {
     33        public:
    3334                explicit Indexer();
    34 
    35                 Indexer( const Indexer &that );
    36                 Indexer( Indexer &&that );
    3735                virtual ~Indexer();
    38                 Indexer& operator= ( const Indexer &that );
    39                 Indexer& operator= ( Indexer &&that );
    4036
    4137                // when using an indexer manually (e.g., within a mutator traversal), it is necessary to tell the indexer
     
    5046                        /// non-null if this declaration is deleted
    5147                        BaseSyntaxNode * deleteStmt = nullptr;
     48                        /// scope of identifier
     49                        unsigned long scope = 0;
    5250
    5351                        // NOTE: shouldn't need either of these constructors, but gcc-4 does not properly support initializer lists with default members.
    5452                        IdData() = default;
    55                         IdData( DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ) {}
     53                        IdData(
     54                                DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt,
     55                                unsigned long scope )
     56                                : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ), scope( scope ) {}
     57                        IdData( const IdData& o, BaseSyntaxNode * deleteStmt )
     58                                : id( o.id ), baseExpr( o.baseExpr ), deleteStmt( deleteStmt ), scope( o.scope ) {}
    5659
    5760                        Expression * combine( ResolvExpr::Cost & cost ) const;
     
    7174                TraitDecl *lookupTrait( const std::string &id ) const;
    7275
     76                // void print( std::ostream &os, int indent = 0 ) const;
     77
     78                /// looks up a specific mangled ID in local scope only
     79                // IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope );
     80                // const IdData * localLookupId( const std::string &id, const std::string &mangleName ) const;
     81                // equivalents to lookup functions that only look at tables at scope `scope` (which should be >= tables->scope)
     82                // NamedTypeDecl *lookupTypeAtScope( const std::string &id, unsigned long scope ) const;
     83                // StructDecl *lookupStructAtScope( const std::string &id, unsigned long scope ) const;
     84                // EnumDecl *lookupEnumAtScope( const std::string &id, unsigned long scope ) const;
     85                // UnionDecl *lookupUnionAtScope( const std::string &id, unsigned long scope ) const;
     86                // TraitDecl *lookupTraitAtScope( const std::string &id, unsigned long scope ) const;
     87
    7388                /// Gets the type declaration with the given ID at global scope
    7489                NamedTypeDecl *globalLookupType( const std::string &id ) const;
     
    8095                EnumDecl *globalLookupEnum( const std::string &id ) const;
    8196
    82                 void print( std::ostream &os, int indent = 0 ) const;
    83 
    84                 /// looks up a specific mangled ID at the given scope
    85                 IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope );
    86                 const IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
    87                 /// returns true if there exists a declaration with C linkage and the given name with a different mangled name
    88                 bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
    89                 /// returns true if there exists a declaration with C linkage and the given name with the same mangled name
    90                 bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
    91                 // equivalents to lookup functions that only look at tables at scope `scope` (which should be >= tables->scope)
    92                 NamedTypeDecl *lookupTypeAtScope( const std::string &id, unsigned long scope ) const;
    93                 StructDecl *lookupStructAtScope( const std::string &id, unsigned long scope ) const;
    94                 EnumDecl *lookupEnumAtScope( const std::string &id, unsigned long scope ) const;
    95                 UnionDecl *lookupUnionAtScope( const std::string &id, unsigned long scope ) const;
    96                 TraitDecl *lookupTraitAtScope( const std::string &id, unsigned long scope ) const;
    97 
    98                 typedef std::function<bool(IdData &, const std::string &)> ConflictFunction;
    99 
    10097                void addId( DeclarationWithType * decl, Expression * baseExpr = nullptr );
    10198                void addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt );
     
    112109                void addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt );
    113110
    114                 /// adds all of the members of the Aggregate (addWith helper)
    115                 void addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction );
    116 
    117111                /// convenience function for adding a list of Ids to the indexer
    118112                void addIds( const std::list< DeclarationWithType * > & decls );
     
    124118                void addFunctionType( FunctionType * ftype );
    125119
    126                 bool doDebug = false; ///< Display debugging trace?
     120                // bool doDebug = false; ///< Display debugging trace?
    127121          private:
    128                 struct Impl;
    129 
    130                 Impl *tables;         ///< Copy-on-write instance of table data structure
    131                 unsigned long scope;  ///< Scope index of this pointer
    132 
    133                 /// Takes a new ref to a table (returns null if null)
    134                 static Impl *newRef( Impl *toClone );
    135                 /// Clears a ref to a table (does nothing if null)
    136                 static void deleteRef( Impl *toFree );
    137 
    138                 // Removes matching autogenerated constructors and destructors
    139                 // so that they will not be selected
    140                 // void removeSpecialOverrides( FunctionDecl *decl );
     122                /// Wraps a Decl* with a scope
     123                template<typename Decl>
     124                struct Scoped {
     125                        Decl* decl;           ///< declaration
     126                        unsigned long scope;  ///< scope of this declaration
     127
     128                        Scoped(Decl* d, unsigned long s) : decl(d), scope(s) {}
     129                };
     130
     131                using Ptr = std::shared_ptr<const Indexer>;
     132
     133                using MangleTable = PersistentMap< std::string, IdData >;
     134                using IdTable = PersistentMap< std::string, MangleTable::Ptr >;
     135                using TypeTable = PersistentMap< std::string, Scoped<NamedTypeDecl> >;
     136                using StructTable = PersistentMap< std::string, Scoped<StructDecl> >;
     137                using EnumTable = PersistentMap< std::string, Scoped<EnumDecl> >;
     138                using UnionTable = PersistentMap< std::string, Scoped<UnionDecl> >;
     139                using TraitTable = PersistentMap< std::string, Scoped<TraitDecl> >;
     140
     141                IdTable::Ptr idTable;          ///< identifier namespace
     142                TypeTable::Ptr typeTable;      ///< type namespace
     143                StructTable::Ptr structTable;  ///< struct namespace
     144                EnumTable::Ptr enumTable;      ///< enum namespace
     145                UnionTable::Ptr unionTable;    ///< union namespace
     146                TraitTable::Ptr traitTable;    ///< trait namespace
     147
     148                Ptr prevScope;                 ///< reference to indexer for parent scope
     149                unsigned long scope;           ///< Scope index of this indexer
     150
     151                /// Gets the indexer at the given scope
     152                const Indexer* atScope( unsigned long scope ) const;
     153
     154                /// Removes matching autogenerated constructors and destructors
     155                /// so that they will not be selected
     156                /// void removeSpecialOverrides( FunctionDecl *decl );
    141157                void removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const;
    142158
    143                 /// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope)
    144                 void makeWritable();
     159                /// Options for handling identifier conflicts
     160                struct OnConflict {
     161                        enum {
     162                                Error,  ///< Throw a semantic error
     163                                Delete  ///< Delete the earlier version with the delete statement
     164                        } mode;
     165                        BaseSyntaxNode * deleteStmt;  ///< Statement that deletes this expression
     166
     167                private:
     168                        OnConflict() : mode(Error), deleteStmt(nullptr) {}
     169                        OnConflict( BaseSyntaxNode * d ) : mode(Delete), deleteStmt(d) {}
     170                public:
     171                        OnConflict( const OnConflict& ) = default;
     172
     173                        static OnConflict error() { return {}; }
     174                        static OnConflict deleteWith( BaseSyntaxNode * d ) { return { d }; }
     175                };
     176
     177                /// true if the existing identifier conflicts with the added identifier
     178                bool addedIdConflicts(
     179                        const IdData& existing, DeclarationWithType * added, OnConflict handleConflicts,
     180                        BaseSyntaxNode * deleteStmt );
    145181
    146182                /// common code for addId, addDeletedId, etc.
    147                 void addId( DeclarationWithType * decl, ConflictFunction, Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
     183                void addId(
     184                        DeclarationWithType * decl, OnConflict handleConflicts,
     185                        Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
     186
     187                /// adds all of the members of the Aggregate (addWith helper)
     188                void addMembers( AggregateDecl * aggr, Expression * expr, OnConflict handleConflicts );
     189
     190                /// returns true if there exists a declaration with C linkage and the given name with the same mangled name
     191                bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const;
     192                /// returns true if there exists a declaration with C linkage and the given name with a different mangled name
     193                bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName ) const;
    148194        };
    149195} // namespace SymTab
  • src/SynTree/BaseSyntaxNode.h

    rfca6ca6 rb8665e3  
    1818#include "Common/CodeLocation.h"
    1919#include "Common/Indenter.h"
     20#include "Common/Stats.h"
     21
    2022class Visitor;
    2123class Mutator;
     
    2325class BaseSyntaxNode {
    2426  public:
     27  static Stats::Counters::SimpleCounter* new_nodes;
     28
    2529        CodeLocation location;
     30
     31  BaseSyntaxNode() { ++*new_nodes; }
     32  BaseSyntaxNode( const BaseSyntaxNode& ) { ++*new_nodes; }
    2633
    2734        virtual ~BaseSyntaxNode() {}
  • src/main.cc

    rfca6ca6 rb8665e3  
    6565using namespace std;
    6666
    67 
    6867void NewPass(const char * const name) {
    6968        Stats::Heap::newPass(name);
    7069        using namespace Stats::Counters;
    71         static auto pass_visitor_group = build<CounterGroup>("Pass Visitor");
    72         auto pass = build<CounterGroup>(name, pass_visitor_group);
    73         pass_visitor_stats.depth = 0;
    74         pass_visitor_stats.avg = build<AverageCounter<double>>("Average Depth", pass);
    75         pass_visitor_stats.max = build<MaxCounter<double>>("Max Depth", pass);
     70       
     71        {
     72                static auto group = build<CounterGroup>("Pass Visitor");
     73                auto pass = build<CounterGroup>(name, group);
     74                pass_visitor_stats.depth = 0;
     75                pass_visitor_stats.avg = build<AverageCounter<double>>("Average Depth", pass);
     76                pass_visitor_stats.max = build<MaxCounter<double>>("Max Depth", pass);
     77        }
     78
     79        {
     80                static auto group = build<CounterGroup>("Syntax Node");
     81                auto pass = build<CounterGroup>(name, group);
     82                BaseSyntaxNode::new_nodes = build<SimpleCounter>("Allocs", pass);
     83        }
    7684}
    7785
Note: See TracChangeset for help on using the changeset viewer.