source: src/SymTab/Indexer.cc @ b8665e3

arm-ehcleanup-dtorsenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpersistent-indexerpthread-emulationqualifiedEnum
Last change on this file since b8665e3 was b8665e3, checked in by Aaron Moss <a3moss@…>, 4 years ago

First build with persistent-map indexer

  • Property mode set to 100644
File size: 27.5 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// Indexer.cc --
8//
9// Author           : Richard C. Bilson
10// Created On       : Sun May 17 21:37:33 2015
11// Last Modified By : Aaron B. Moss
12// Last Modified On : Fri Mar  8 13:55:00 2019
13// Update Count     : 21
14//
15
16#include "Indexer.h"
17
18#include <cassert>                 // for assert, strict_dynamic_cast
19#include <iostream>                // for operator<<, basic_ostream, ostream
20#include <string>                  // for string, operator<<, operator!=
21#include <memory>                  // for shared_ptr, make_shared
22#include <unordered_map>           // for operator!=, unordered_map<>::const...
23#include <unordered_set>           // for unordered_set
24#include <utility>                 // for pair, make_pair, move
25
26#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
27#include "Common/SemanticError.h"  // for SemanticError
28#include "Common/utility.h"        // for cloneAll
29#include "Common/Stats/Counter.h"  // for counters
30#include "GenPoly/GenPoly.h"       // for getFunctionType
31#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
32#include "Mangler.h"               // for Mangler
33#include "Parser/LinkageSpec.h"    // for isMangled, isOverridable, Spec
34#include "ResolvExpr/typeops.h"    // for typesCompatible
35#include "SynTree/Constant.h"      // for Constant
36#include "SynTree/Declaration.h"   // for DeclarationWithType, FunctionDecl
37#include "SynTree/Expression.h"    // for Expression, ImplicitCopyCtorExpr
38#include "SynTree/Initializer.h"   // for Initializer
39#include "SynTree/Statement.h"     // for CompoundStmt, Statement, ForStmt (...
40#include "SynTree/Type.h"          // for Type, StructInstType, UnionInstType
41
42#define debugPrint(x) if ( doDebug ) { std::cerr << x; }
43
44namespace SymTab {
45
46        // Statistics block
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        // }
112
113        void Indexer::removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const {
114                // only need to perform this step for constructors, destructors, and assignment functions
115                if ( ! CodeGen::isCtorDtorAssign( id ) ) return;
116
117                // helpful data structure to organize properties for a type
118                struct ValueType {
119                        struct DeclBall { // properties for this particular decl
120                                IdData decl;
121                                bool isUserDefinedFunc;
122                                bool isCopyFunc;
123                        };
124                        // properties for this type
125                        bool existsUserDefinedCopyFunc = false;    // user-defined copy ctor found
126                        BaseSyntaxNode * deleteStmt = nullptr;     // non-null if a user-defined function is found
127                        std::list< DeclBall > decls;
128
129                        // another FunctionDecl for the current type was found - determine
130                        // if it has special properties and update data structure accordingly
131                        ValueType & operator+=( IdData data ) {
132                                DeclarationWithType * function = data.id;
133                                bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
134                                bool isCopyFunc = InitTweak::isCopyFunction( function, function->name );
135                                decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } );
136                                existsUserDefinedCopyFunc |= (isUserDefinedFunc && isCopyFunc);
137                                if ( isUserDefinedFunc && ! deleteStmt ) {
138                                        // any user-defined function can act as an implicit delete statement for generated constructors.
139                                        // a delete stmt should not act as an implicit delete statement.
140                                        deleteStmt = data.id;
141                                }
142                                return *this;
143                        }
144                }; // ValueType
145
146                std::list< IdData > copy;
147                copy.splice( copy.end(), out );
148
149                // organize discovered declarations by type
150                std::unordered_map< std::string, ValueType > funcMap;
151                for ( auto decl : copy ) {
152                        if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) {
153                                std::list< DeclarationWithType * > & params = function->type->parameters;
154                                assert( ! params.empty() );
155                                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
156                                Type * base = InitTweak::getPointerBase( params.front()->get_type() );
157                                assert( base );
158                                funcMap[ Mangler::mangle( base ) ] += decl;
159                        } else {
160                                out.push_back( decl );
161                        }
162                }
163
164                // if a type contains user defined ctor/dtor/assign, then special rules trigger, which determine
165                // the set of ctor/dtor/assign that can be used  by the requester. In particular, if the user defines
166                // a default ctor, then the generated default ctor is unavailable, likewise for copy ctor
167                // and dtor. If the user defines any ctor/dtor, then no generated field ctors are available.
168                // If the user defines any ctor then the generated default ctor is unavailable (intrinsic default
169                // ctor must be overridden exactly). If the user defines anything that looks like a copy constructor,
170                // then the generated copy constructor is unavailable, and likewise for the assignment operator.
171                for ( std::pair< const std::string, ValueType > & pair : funcMap ) {
172                        ValueType & val = pair.second;
173                        for ( ValueType::DeclBall ball : val.decls ) {
174                                bool isNotUserDefinedFunc = ! ball.isUserDefinedFunc && ball.decl.id->linkage != LinkageSpec::Intrinsic;
175                                bool isCopyFunc = ball.isCopyFunc;
176                                bool existsUserDefinedCopyFunc = val.existsUserDefinedCopyFunc;
177
178                                // only implicitly delete non-user defined functions that are not intrinsic, and are
179                                // not copy functions (assignment or copy constructor). If a  user-defined copy function exists,
180                                // do not pass along the non-user-defined copy functions since signatures do not have to match,
181                                // and the generated functions will often be cheaper.
182                                if ( isNotUserDefinedFunc ) {
183                                        if ( isCopyFunc ) {
184                                                // Skip over non-user-defined copy functions when there is a user-defined copy function.
185                                                // Since their signatures do not have to be exact, deleting them is the wrong choice.
186                                                if ( existsUserDefinedCopyFunc ) continue;
187                                        } else {
188                                                // delete non-user-defined non-copy functions if applicable.
189                                                // deleteStmt will be non-null only if a user-defined function is found.
190                                                ball.decl.deleteStmt = val.deleteStmt;
191                                        }
192                                }
193                                out.push_back( ball.decl );
194                        }
195                }
196        }
197
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;
227        }
228
229        void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
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               
239                // some special functions, e.g. constructors and destructors
240                // remove autogenerated functions when they are defined so that
241                // they can never be matched
242                removeSpecialOverrides( id, out );
243        }
244
245        NamedTypeDecl *Indexer::lookupType( const std::string &id ) const {
246                if ( ! typeTable ) return nullptr;
247                auto it = typeTable->find( id );
248                return it == typeTable->end() ? nullptr : it->second.decl;
249        }
250
251        StructDecl *Indexer::lookupStruct( const std::string &id ) const {
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        // }
370
371        NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
372                return atScope( 0 )->lookupType( id );
373        }
374
375        StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
376                return atScope( 0 )->lookupStruct( id );
377        }
378
379        UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
380                return atScope( 0 )->lookupUnion( id );
381        }
382
383        EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
384                return atScope( 0 )->lookupEnum( id );
385        }
386
387        bool isFunction( DeclarationWithType * decl ) {
388                return GenPoly::getFunctionType( decl->get_type() );
389        }
390
391        bool isObject( DeclarationWithType * decl ) {
392                return ! isFunction( decl );
393        }
394
395        bool isDefinition( DeclarationWithType * decl ) {
396                if ( FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl ) ) {
397                        // a function is a definition if it has a body
398                        return func->statements;
399                } else {
400                        // an object is a definition if it is not marked extern.
401                        // both objects must be marked extern
402                        return ! decl->get_storageClasses().is_extern;
403                }
404        }
405
406       
407        bool Indexer::addedIdConflicts( 
408                        const Indexer::IdData & existing, DeclarationWithType *added, 
409                        Indexer::OnConflict handleConflicts, BaseSyntaxNode * deleteStmt ) {
410                // if we're giving the same name mangling to things of different types then there is something wrong
411                assert( (isObject( added ) && isObject( existing.id ) )
412                        || ( isFunction( added ) && isFunction( existing.id ) ) );
413
414                if ( LinkageSpec::isOverridable( existing.id->linkage ) ) {
415                        // new definition shadows the autogenerated one, even at the same scope
416                        return false;
417                } else if ( LinkageSpec::isMangled( added->linkage ) 
418                                || ResolvExpr::typesCompatible( 
419                                        added->get_type(), existing.id->get_type(), Indexer() ) ) {
420
421                        // it is a conflict if one declaration is deleted and the other is not
422                        if ( deleteStmt && ! existing.deleteStmt ) {
423                                if ( handleConflicts.mode == OnConflict::Error ) {
424                                        SemanticError( added, "deletion of defined identifier " );
425                                }
426                                return true;
427                        } else if ( ! deleteStmt && existing.deleteStmt ) {
428                                if ( handleConflicts.mode == OnConflict::Error ) {
429                                        SemanticError( added, "definition of deleted identifier " );
430                                }
431                                return true;
432                        }
433
434                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
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;
442                        } // if
443                } else {
444                        if ( handleConflicts.mode == OnConflict::Error ) {
445                                SemanticError( added, "duplicate definition for " );
446                        }
447                        return true;
448                } // if
449
450                return true;
451        }
452
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 ) {
493                if ( decl->name == "" ) return;
494                // debugPrint( "Adding Id " << decl->name << std::endl );
495               
496                const std::string &name = decl->name;
497                std::string mangleName;
498                if ( LinkageSpec::isOverridable( decl->linkage ) ) {
499                        // mangle the name without including the appropriate suffix, so overridable routines
500                        // are placed into the same "bucket" as their user defined versions.
501                        mangleName = Mangler::mangle( decl, false );
502                } else {
503                        mangleName = Mangler::mangle( decl );
504                } // if
505
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 ) ) {
517                                SemanticError( decl, "conflicting overload of C function " );
518                        }
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 } ) );
556        }
557
558        void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
559                // default handling of conflicts is to raise an error
560                addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
561        }
562
563        void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
564                // default handling of conflicts is to raise an error
565                addId( decl, OnConflict::error(), nullptr, deleteStmt );
566        }
567
568        bool addedTypeConflicts( NamedTypeDecl *existing, NamedTypeDecl *added ) {
569                if ( existing->base == nullptr ) {
570                        return false;
571                } else if ( added->base == nullptr ) {
572                        return true;
573                } else {
574                        assert( existing->base && added->base );
575                        // typedef redeclarations are errors only if types are different
576                        if ( ! ResolvExpr::typesCompatible( existing->base, added->base, Indexer() ) ) {
577                                SemanticError( added->location, "redeclaration of " + added->name );
578                        }
579                }
580                // does not need to be added to the table if both existing and added have a base that are the same
581                return true;
582        }
583
584        void Indexer::addType( NamedTypeDecl *decl ) {
585                const std::string &id = decl->name;
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 } );
597        }
598
599        bool addedDeclConflicts( AggregateDecl *existing, AggregateDecl *added ) {
600                if ( ! existing->body ) {
601                        return false;
602                } else if ( added->body ) {
603                        SemanticError( added, "redeclaration of " );
604                } // if
605                return true;
606        }
607
608        void Indexer::addStruct( const std::string &id ) {
609                addStruct( new StructDecl( id ) );
610        }
611
612        void Indexer::addStruct( StructDecl *decl ) {
613                const std::string &id = decl->name;
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 } );
625        }
626
627        void Indexer::addEnum( EnumDecl *decl ) {
628                const std::string &id = decl->name;
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 } );
640        }
641
642        void Indexer::addUnion( const std::string &id ) {
643                addUnion( new UnionDecl( id ) );
644        }
645
646        void Indexer::addUnion( UnionDecl *decl ) {
647                const std::string &id = decl->name;
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 } );
659        }
660
661        void Indexer::addTrait( TraitDecl *decl ) {
662                const std::string &id = decl->name;
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 ) {
678                for ( Declaration * decl : aggr->members ) {
679                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
680                                addId( dwt, handleConflicts, expr );
681                                if ( dwt->name == "" ) {
682                                        Type * t = dwt->get_type()->stripReferences();
683                                        if ( dynamic_cast<StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {
684                                                Expression * base = expr->clone();
685                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
686                                                ResolvExpr::referenceToRvalueConversion( base, cost );
687                                                addMembers( t->getAggr(), new MemberExpr( dwt, base ), handleConflicts );
688                                        }
689                                }
690                        }
691                }
692        }
693
694        void Indexer::addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt ) {
695                for ( Expression * expr : withExprs ) {
696                        if ( expr->result ) {
697                                AggregateDecl * aggr = expr->result->stripReferences()->getAggr();
698                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
699
700                                addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
701                        }
702                }
703        }
704
705        void Indexer::addIds( const std::list< DeclarationWithType * > & decls ) {
706                for ( auto d : decls ) {
707                        addId( d );
708                }
709        }
710
711        void Indexer::addTypes( const std::list< TypeDecl * > & tds ) {
712                for ( auto td : tds ) {
713                        addType( td );
714                        addIds( td->assertions );
715                }
716        }
717
718        void Indexer::addFunctionType( FunctionType * ftype ) {
719                addTypes( ftype->forall );
720                addIds( ftype->returnVals );
721                addIds( ftype->parameters );
722        }
723
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        // }
748
749        Expression * Indexer::IdData::combine( ResolvExpr::Cost & cost ) const {
750                Expression * ret = nullptr;
751                if ( baseExpr ) {
752                        Expression * base = baseExpr->clone();
753                        ResolvExpr::referenceToRvalueConversion( base, cost );
754                        ret = new MemberExpr( id, base );
755                        // xxx - this introduces hidden environments, for now remove them.
756                        // std::swap( base->env, ret->env );
757                        delete base->env;
758                        base->env = nullptr;
759                } else {
760                        ret = new VariableExpr( id );
761                }
762                if ( deleteStmt ) ret = new DeletedExpr( ret, deleteStmt );
763                return ret;
764        }
765} // namespace SymTab
766
767// Local Variables: //
768// tab-width: 4 //
769// mode: c++ //
770// compile-command: "make install" //
771// End: //
Note: See TracBrowser for help on using the repository browser.