// // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // Indexer.cc -- // // Author : Richard C. Bilson // Created On : Sun May 17 21:37:33 2015 // Last Modified By : Peter A. Buhr // Last Modified On : Wed Mar 2 17:31:29 2016 // Update Count : 11 // #include "Indexer.h" #include "IdTable.h" #include "AggregateTable.h" #include "TypeTable.h" #include "SynTree/Declaration.h" #include "SynTree/Type.h" #include "SynTree/Expression.h" #include "SynTree/Initializer.h" #include "SynTree/Statement.h" #include #include #include "Common/utility.h" #define debugPrint(x) if ( doDebug ) { std::cout << x; } namespace SymTab { template< typename Container, typename VisitorType > inline void acceptAllNewScope( Container &container, VisitorType &visitor ) { visitor.enterScope(); acceptAll( container, visitor ); visitor.leaveScope(); } struct Indexer::Impl { Impl() : refCount(1), size(0), base(), idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {} Impl( const Indexer &_base ) : refCount(1), size(0), base( _base ), idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {} unsigned long refCount; ///< Number of references to these tables unsigned long size; ///< Number of elements stored in this table const Indexer base; ///< Base indexer this extends IdTable idTable; ///< Identifier namespace TypeTable typeTable; ///< Type namespace StructTable structTable; ///< Struct namespace EnumTable enumTable; ///< Enum namespace UnionTable unionTable; ///< Union namespace TraitTable traitTable; ///< Trait namespace }; Indexer::Impl *Indexer::newRef( Indexer::Impl *toClone ) { if ( ! toClone ) return 0; // shorten the search chain by skipping empty links Indexer::Impl *ret = toClone->size == 0 ? toClone->base.tables : toClone; if ( ret ) { ++ret->refCount; } return ret; } void Indexer::deleteRef( Indexer::Impl *toFree ) { if ( ! toFree ) return; if ( --toFree->refCount == 0 ) delete toFree; } void Indexer::makeWritable() { if ( ! tables ) { tables = new Indexer::Impl; } else if ( tables->refCount > 1 ) { // tables->base inherits the ref that used to belong to this indexer // this is basically equivalent to std::move( *this ) as the argument tables = new Indexer::Impl( Indexer( tables, doDebug ) ); } } Indexer::Indexer( bool _doDebug ) : tables(0), doDebug( _doDebug ) {} Indexer::Indexer( const Indexer &that ) : tables( newRef( that.tables ) ), doDebug( that.doDebug ) {} Indexer::Indexer( Indexer &&that ) : tables( that.tables ), doDebug( that.doDebug ) { that.tables = 0; } Indexer::~Indexer() { deleteRef( tables ); } Indexer& Indexer::operator= ( const Indexer &that ) { deleteRef( tables ); tables = newRef( that.tables ); doDebug = that.doDebug; return *this; } Indexer& Indexer::operator= ( Indexer &&that ) { deleteRef( tables ); tables = that.tables; doDebug = that.doDebug; that.tables = 0; return *this; } void Indexer::visit( ObjectDecl *objectDecl ) { enterScope(); maybeAccept( objectDecl->get_type(), *this ); leaveScope(); maybeAccept( objectDecl->get_init(), *this ); maybeAccept( objectDecl->get_bitfieldWidth(), *this ); if ( objectDecl->get_name() != "" ) { debugPrint( "Adding object " << objectDecl->get_name() << std::endl ); addId( objectDecl ); } // if } void Indexer::visit( FunctionDecl *functionDecl ) { if ( functionDecl->get_name() == "" ) return; debugPrint( "Adding function " << functionDecl->get_name() << std::endl ); addId( functionDecl ); enterScope(); maybeAccept( functionDecl->get_functionType(), *this ); acceptAll( functionDecl->get_oldDecls(), *this ); maybeAccept( functionDecl->get_statements(), *this ); leaveScope(); } // A NOTE ON THE ORDER OF TRAVERSAL // // Types and typedefs have their base types visited before they are added to the type table. This is ok, since there is // no such thing as a recursive type or typedef. // // typedef struct { T *x; } T; // never allowed // // for structs/unions, it is possible to have recursion, so the decl should be added as if it's incomplete to begin, the // members are traversed, and then the complete type should be added (assuming the type is completed by this particular // declaration). // // struct T { struct T *x; }; // allowed // // It is important to add the complete type to the symbol table *after* the members/base has been traversed, since that // traversal may modify the definition of the type and these modifications should be visible when the symbol table is // queried later in this pass. // // TODO: figure out whether recursive contexts are sensible/possible/reasonable. void Indexer::visit( TypeDecl *typeDecl ) { // see A NOTE ON THE ORDER OF TRAVERSAL, above // note that assertions come after the type is added to the symtab, since they are not part of the type proper // and may depend on the type itself enterScope(); acceptAll( typeDecl->get_parameters(), *this ); maybeAccept( typeDecl->get_base(), *this ); leaveScope(); debugPrint( "Adding type " << typeDecl->get_name() << std::endl ); addType( typeDecl ); acceptAll( typeDecl->get_assertions(), *this ); } void Indexer::visit( TypedefDecl *typeDecl ) { enterScope(); acceptAll( typeDecl->get_parameters(), *this ); maybeAccept( typeDecl->get_base(), *this ); leaveScope(); debugPrint( "Adding typedef " << typeDecl->get_name() << std::endl ); addType( typeDecl ); } void Indexer::visit( StructDecl *aggregateDecl ) { // make up a forward declaration and add it before processing the members StructDecl fwdDecl( aggregateDecl->get_name() ); cloneAll( aggregateDecl->get_parameters(), fwdDecl.get_parameters() ); debugPrint( "Adding fwd decl for struct " << fwdDecl.get_name() << std::endl ); addStruct( &fwdDecl ); enterScope(); acceptAll( aggregateDecl->get_parameters(), *this ); acceptAll( aggregateDecl->get_members(), *this ); leaveScope(); debugPrint( "Adding struct " << aggregateDecl->get_name() << std::endl ); // this addition replaces the forward declaration addStruct( aggregateDecl ); } void Indexer::visit( UnionDecl *aggregateDecl ) { // make up a forward declaration and add it before processing the members UnionDecl fwdDecl( aggregateDecl->get_name() ); cloneAll( aggregateDecl->get_parameters(), fwdDecl.get_parameters() ); debugPrint( "Adding fwd decl for union " << fwdDecl.get_name() << std::endl ); addUnion( &fwdDecl ); enterScope(); acceptAll( aggregateDecl->get_parameters(), *this ); acceptAll( aggregateDecl->get_members(), *this ); leaveScope(); debugPrint( "Adding union " << aggregateDecl->get_name() << std::endl ); addUnion( aggregateDecl ); } void Indexer::visit( EnumDecl *aggregateDecl ) { debugPrint( "Adding enum " << aggregateDecl->get_name() << std::endl ); addEnum( aggregateDecl ); // unlike structs, contexts, and unions, enums inject their members into the global scope acceptAll( aggregateDecl->get_members(), *this ); } void Indexer::visit( TraitDecl *aggregateDecl ) { enterScope(); acceptAll( aggregateDecl->get_parameters(), *this ); acceptAll( aggregateDecl->get_members(), *this ); leaveScope(); debugPrint( "Adding context " << aggregateDecl->get_name() << std::endl ); addTrait( aggregateDecl ); } void Indexer::visit( CompoundStmt *compoundStmt ) { enterScope(); acceptAll( compoundStmt->get_kids(), *this ); leaveScope(); } void Indexer::visit( ApplicationExpr *applicationExpr ) { acceptAllNewScope( applicationExpr->get_results(), *this ); maybeAccept( applicationExpr->get_function(), *this ); acceptAll( applicationExpr->get_args(), *this ); } void Indexer::visit( UntypedExpr *untypedExpr ) { acceptAllNewScope( untypedExpr->get_results(), *this ); acceptAll( untypedExpr->get_args(), *this ); } void Indexer::visit( NameExpr *nameExpr ) { acceptAllNewScope( nameExpr->get_results(), *this ); } void Indexer::visit( AddressExpr *addressExpr ) { acceptAllNewScope( addressExpr->get_results(), *this ); maybeAccept( addressExpr->get_arg(), *this ); } void Indexer::visit( LabelAddressExpr *labAddressExpr ) { acceptAllNewScope( labAddressExpr->get_results(), *this ); maybeAccept( labAddressExpr->get_arg(), *this ); } void Indexer::visit( CastExpr *castExpr ) { acceptAllNewScope( castExpr->get_results(), *this ); maybeAccept( castExpr->get_arg(), *this ); } void Indexer::visit( UntypedMemberExpr *memberExpr ) { acceptAllNewScope( memberExpr->get_results(), *this ); maybeAccept( memberExpr->get_aggregate(), *this ); } void Indexer::visit( MemberExpr *memberExpr ) { acceptAllNewScope( memberExpr->get_results(), *this ); maybeAccept( memberExpr->get_aggregate(), *this ); } void Indexer::visit( VariableExpr *variableExpr ) { acceptAllNewScope( variableExpr->get_results(), *this ); } void Indexer::visit( ConstantExpr *constantExpr ) { acceptAllNewScope( constantExpr->get_results(), *this ); maybeAccept( constantExpr->get_constant(), *this ); } void Indexer::visit( SizeofExpr *sizeofExpr ) { acceptAllNewScope( sizeofExpr->get_results(), *this ); if ( sizeofExpr->get_isType() ) { maybeAccept( sizeofExpr->get_type(), *this ); } else { maybeAccept( sizeofExpr->get_expr(), *this ); } } void Indexer::visit( AlignofExpr *alignofExpr ) { acceptAllNewScope( alignofExpr->get_results(), *this ); if ( alignofExpr->get_isType() ) { maybeAccept( alignofExpr->get_type(), *this ); } else { maybeAccept( alignofExpr->get_expr(), *this ); } } void Indexer::visit( UntypedOffsetofExpr *offsetofExpr ) { acceptAllNewScope( offsetofExpr->get_results(), *this ); maybeAccept( offsetofExpr->get_type(), *this ); } void Indexer::visit( OffsetofExpr *offsetofExpr ) { acceptAllNewScope( offsetofExpr->get_results(), *this ); maybeAccept( offsetofExpr->get_type(), *this ); maybeAccept( offsetofExpr->get_member(), *this ); } void Indexer::visit( AttrExpr *attrExpr ) { acceptAllNewScope( attrExpr->get_results(), *this ); if ( attrExpr->get_isType() ) { maybeAccept( attrExpr->get_type(), *this ); } else { maybeAccept( attrExpr->get_expr(), *this ); } } void Indexer::visit( LogicalExpr *logicalExpr ) { acceptAllNewScope( logicalExpr->get_results(), *this ); maybeAccept( logicalExpr->get_arg1(), *this ); maybeAccept( logicalExpr->get_arg2(), *this ); } void Indexer::visit( ConditionalExpr *conditionalExpr ) { acceptAllNewScope( conditionalExpr->get_results(), *this ); maybeAccept( conditionalExpr->get_arg1(), *this ); maybeAccept( conditionalExpr->get_arg2(), *this ); maybeAccept( conditionalExpr->get_arg3(), *this ); } void Indexer::visit( CommaExpr *commaExpr ) { acceptAllNewScope( commaExpr->get_results(), *this ); maybeAccept( commaExpr->get_arg1(), *this ); maybeAccept( commaExpr->get_arg2(), *this ); } void Indexer::visit( TupleExpr *tupleExpr ) { acceptAllNewScope( tupleExpr->get_results(), *this ); acceptAll( tupleExpr->get_exprs(), *this ); } void Indexer::visit( SolvedTupleExpr *tupleExpr ) { acceptAllNewScope( tupleExpr->get_results(), *this ); acceptAll( tupleExpr->get_exprs(), *this ); } void Indexer::visit( TypeExpr *typeExpr ) { acceptAllNewScope( typeExpr->get_results(), *this ); maybeAccept( typeExpr->get_type(), *this ); } void Indexer::visit( AsmExpr *asmExpr ) { maybeAccept( asmExpr->get_inout(), *this ); maybeAccept( asmExpr->get_constraint(), *this ); maybeAccept( asmExpr->get_operand(), *this ); } void Indexer::visit( UntypedValofExpr *valofExpr ) { acceptAllNewScope( valofExpr->get_results(), *this ); maybeAccept( valofExpr->get_body(), *this ); } void Indexer::visit( TraitInstType *contextInst ) { acceptAll( contextInst->get_parameters(), *this ); acceptAll( contextInst->get_members(), *this ); } void Indexer::visit( StructInstType *structInst ) { if ( ! lookupStruct( structInst->get_name() ) ) { debugPrint( "Adding struct " << structInst->get_name() << " from implicit forward declaration" << std::endl ); addStruct( structInst->get_name() ); } enterScope(); acceptAll( structInst->get_parameters(), *this ); leaveScope(); } void Indexer::visit( UnionInstType *unionInst ) { if ( ! lookupUnion( unionInst->get_name() ) ) { debugPrint( "Adding union " << unionInst->get_name() << " from implicit forward declaration" << std::endl ); addUnion( unionInst->get_name() ); } enterScope(); acceptAll( unionInst->get_parameters(), *this ); leaveScope(); } void Indexer::visit( ForStmt *forStmt ) { // for statements introduce a level of scope enterScope(); Visitor::visit( forStmt ); leaveScope(); } void Indexer::lookupId( const std::string &id, std::list< DeclarationWithType* > &list ) const { if ( ! tables ) return; tables->idTable.lookupId( id, list ); tables->base.lookupId( id, list ); } DeclarationWithType* Indexer::lookupId( const std::string &id) const { if ( ! tables ) return 0; DeclarationWithType *ret = tables->idTable.lookupId(id); return ret ? ret : tables->base.lookupId(id); } NamedTypeDecl *Indexer::lookupType( const std::string &id ) const { if ( ! tables ) return 0; NamedTypeDecl *ret = tables->typeTable.lookup( id ); return ret ? ret : tables->base.lookupType( id ); } StructDecl *Indexer::lookupStruct( const std::string &id ) const { if ( ! tables ) return 0; StructDecl *ret = tables->structTable.lookup( id ); return ret ? ret : tables->base.lookupStruct( id ); } EnumDecl *Indexer::lookupEnum( const std::string &id ) const { if ( ! tables ) return 0; EnumDecl *ret = tables->enumTable.lookup( id ); return ret ? ret : tables->base.lookupEnum( id ); } UnionDecl *Indexer::lookupUnion( const std::string &id ) const { if ( ! tables ) return 0; UnionDecl *ret = tables->unionTable.lookup( id ); return ret ? ret : tables->base.lookupUnion( id ); } TraitDecl *Indexer::lookupTrait( const std::string &id ) const { if ( ! tables ) return 0; TraitDecl *ret = tables->traitTable.lookup( id ); return ret ? ret : tables->base.lookupTrait( id ); } void Indexer::addId( DeclarationWithType *decl ) { makeWritable(); tables->idTable.addDecl( decl ); ++tables->size; } void Indexer::addType( NamedTypeDecl *decl ) { makeWritable(); tables->typeTable.add( decl ); ++tables->size; } void Indexer::addStruct( const std::string &id ) { makeWritable(); tables->structTable.add( id ); ++tables->size; } void Indexer::addStruct( StructDecl *decl ) { makeWritable(); tables->structTable.add( decl ); ++tables->size; } void Indexer::addEnum( EnumDecl *decl ) { makeWritable(); tables->enumTable.add( decl ); ++tables->size; } void Indexer::addUnion( const std::string &id ) { makeWritable(); tables->unionTable.add( id ); ++tables->size; } void Indexer::addUnion( UnionDecl *decl ) { makeWritable(); tables->unionTable.add( decl ); ++tables->size; } void Indexer::addTrait( TraitDecl *decl ) { makeWritable(); tables->traitTable.add( decl ); ++tables->size; } void Indexer::enterScope() { makeWritable(); if ( doDebug ) { std::cout << "--- Entering scope" << std::endl; } tables->idTable.enterScope(); tables->typeTable.enterScope(); tables->structTable.enterScope(); tables->enumTable.enterScope(); tables->unionTable.enterScope(); tables->traitTable.enterScope(); } void Indexer::leaveScope() { using std::cout; makeWritable(); if ( doDebug ) { cout << "--- Leaving scope containing" << std::endl; tables->idTable.dump( cout ); tables->typeTable.dump( cout ); tables->structTable.dump( cout ); tables->enumTable.dump( cout ); tables->unionTable.dump( cout ); tables->traitTable.dump( cout ); } tables->idTable.leaveScope(); tables->typeTable.leaveScope(); tables->structTable.leaveScope(); tables->enumTable.leaveScope(); tables->unionTable.leaveScope(); tables->traitTable.leaveScope(); } void Indexer::print( std::ostream &os, int indent ) const { using std::cerr; cerr << "===idTable===" << std::endl; if ( tables ) tables->idTable.dump( os ); cerr << "===typeTable===" << std::endl; if ( tables ) tables->typeTable.dump( os ); cerr << "===structTable===" << std::endl; if ( tables ) tables->structTable.dump( os ); cerr << "===enumTable===" << std::endl; if ( tables ) tables->enumTable.dump( os ); cerr << "===unionTable===" << std::endl; if ( tables ) tables->unionTable.dump( os ); cerr << "===contextTable===" << std::endl; if ( tables ) tables->traitTable.dump( os ); } } // namespace SymTab // Local Variables: // // tab-width: 4 // // mode: c++ // // compile-command: "make install" // // End: //