/* * Copyright 2007-2018 Adrian Thurston * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include "compiler.h" /* * Variable Lookup */ using std::cout; using std::cerr; using std::endl; ObjectDef *UniqueType::objectDef() { if ( typeId == TYPE_TREE || typeId == TYPE_REF ) { return langEl->objectDef; } else if ( typeId == TYPE_STRUCT ) { return structEl->structDef->objectDef; } else if ( typeId == TYPE_GENERIC ) { return generic->objDef; } /* This should have generated a compiler error. */ assert( false ); } /* Recurisve find through a single object def's scope. */ ObjectField *ObjectDef::findFieldInScope( const NameScope *inScope, const String &name ) const { FieldMapEl *objDefMapEl = inScope->fieldMap.find( name ); if ( objDefMapEl != 0 ) return objDefMapEl->value; if ( inScope->parentScope != 0 ) return findFieldInScope( inScope->parentScope, name ); return 0; } ObjectField *NameScope::findField( const String &name ) const { return owningObj->findFieldInScope( this, name ); } ObjectMethod *NameScope::findMethod( const String &name ) const { MethodMapEl *methodMapEl = methodMap.find( name ); if ( methodMapEl != 0 ) return methodMapEl->value; if ( parentScope != 0 ) return parentScope->findMethod( name ); return 0; } VarRefLookup LangVarRef::lookupQualification( Compiler *pd, NameScope *rootScope ) const { int lastPtrInQual = -1; NameScope *searchScope = rootScope; int firstConstPart = -1; for ( QualItemVect::Iter qi = *qual; qi.lte(); qi++ ) { /* Lookup the field int the current qualification. */ ObjectField *el = searchScope->findField( qi->data ); if ( el == 0 ) error(qi->loc) << "cannot resolve qualification " << qi->data << endp; /* Lookup the type of the field. */ el->typeRef->resolveType( pd ); UniqueType *qualUT = el->typeRef->uniqueType; /* If we are dealing with an iterator then dereference it. */ if ( qualUT->typeId == TYPE_ITER ) qualUT = el->typeRef->searchUniqueType; /* Is it const? */ if ( firstConstPart < 0 && el->isConst ) firstConstPart = qi.pos(); /* Check for references. When loop is done we will have the last one * present, if any. */ if ( qualUT->ptr() ) lastPtrInQual = qi.pos(); if ( qi->form == QualItem::Dot ) { /* Cannot dot a reference. Iterator yes (access of the iterator * not the current) */ if ( qualUT->ptr() ) error(loc) << "dot cannot be used to access a pointer" << endp; } else if ( qi->form == QualItem::Arrow ) { if ( qualUT->typeId == TYPE_ITER ) qualUT = el->typeRef->searchUniqueType; } ObjectDef *searchObjDef = qualUT->objectDef(); if ( searchObjDef == 0 ) error(qi->loc) << "left hand side of qual has no object definition" << endp; searchScope = searchObjDef->rootScope; } return VarRefLookup( lastPtrInQual, firstConstPart, searchScope->owningObj, searchScope ); } bool LangVarRef::isLocalRef() const { if ( qual->length() > 0 ) { if ( scope->findField( qual->data[0].data ) != 0 ) return true; } else if ( scope->findField( name ) != 0 ) return true; else if ( scope->findMethod( name ) != 0 ) return true; return false; } /* For accesing production RHS values inside a switch case that limits our * search to a particular productions. */ bool LangVarRef::isProdRef( Compiler *pd ) const { if ( scope->caseClauseVarRef != 0 ) { UniqueType *varUt = scope->caseClauseVarRef->lookup( pd ); ObjectDef *searchObjDef = varUt->objectDef(); if ( qual->length() > 0 ) { if ( searchObjDef->rootScope->findField( qual->data[0].data ) != 0 ) return true; } else if ( searchObjDef->rootScope->findField( name ) != 0 ) return true; else if ( searchObjDef->rootScope->findMethod( name ) != 0 ) return true; } return false; } bool LangVarRef::isStructRef() const { if ( structDef != 0 ) { if ( qual->length() > 0 ) { if ( structDef->objectDef->rootScope->findField( qual->data[0].data ) != 0 ) return true; } else if ( structDef->objectDef->rootScope->findField( name ) != 0 ) return true; else if ( structDef->objectDef->rootScope->findMethod( name ) != 0 ) return true; } return false; } bool LangVarRef::isInbuiltObject() const { if ( qual->length() > 0 ) { ObjectField *field = scope->findField( qual->data[0].data ); if ( field != 0 && field->isInbuiltObject() ) return true; } else { ObjectField *field = scope->findField( name ); if ( field != 0 ) { if ( field->isInbuiltObject() ) return true; } } return false; } VarRefLookup LangVarRef::lookupObj( Compiler *pd ) const { NameScope *rootScope; if ( nspaceQual != 0 && nspaceQual->qualNames.length() > 0 ) { Namespace *nspace = pd->rootNamespace->findNamespace( nspaceQual->qualNames[0] ); rootScope = nspace->rootScope; } else if ( isLocalRef() ) rootScope = scope; else if ( isProdRef( pd ) ) { UniqueType *varUt = scope->caseClauseVarRef->lookup( pd ); ObjectDef *searchObjDef = varUt->objectDef(); rootScope = searchObjDef->rootScope; } else if ( isStructRef() ) rootScope = structDef->objectDef->rootScope; else rootScope = nspace != 0 ? nspace->rootScope : pd->rootNamespace->rootScope; return lookupQualification( pd, rootScope ); } VarRefLookup LangVarRef::lookupMethodObj( Compiler *pd ) const { NameScope *rootScope; if ( nspaceQual != 0 && nspaceQual->qualNames.length() > 0 ) { Namespace *nspace = pd->rootNamespace->findNamespace( nspaceQual->qualNames[0] ); rootScope = nspace->rootScope; } else if ( isLocalRef() ) rootScope = scope; else if ( isStructRef() ) rootScope = structDef->objectDef->rootScope; else rootScope = nspace != 0 ? nspace->rootScope : pd->rootNamespace->rootScope; return lookupQualification( pd, rootScope ); } VarRefLookup LangVarRef::lookupField( Compiler *pd ) const { /* Lookup the object that the field is in. */ VarRefLookup lookup = lookupObj( pd ); /* Lookup the field. */ ObjectField *field = lookup.inScope->findField( name ); if ( field == 0 ) error(loc) << "cannot find name " << name << " in object" << endp; lookup.objField = field; lookup.uniqueType = field->typeRef->uniqueType; if ( field->typeRef->searchUniqueType != 0 ) lookup.iterSearchUT = field->typeRef->searchUniqueType; return lookup; } UniqueType *LangVarRef::lookup( Compiler *pd ) const { /* Lookup the loadObj. */ VarRefLookup lookup = lookupField( pd ); ObjectField *el = lookup.objField; UniqueType *elUT = el->typeRef->resolveType( pd ); /* Deref iterators. */ if ( elUT->typeId == TYPE_ITER ) elUT = el->typeRef->searchUniqueType; return elUT; } VarRefLookup LangVarRef::lookupMethod( Compiler *pd ) const { /* Lookup the object that the field is in. */ VarRefLookup lookup = lookupMethodObj( pd ); /* Find the method. */ ObjectMethod *method = lookup.inScope->findMethod( name ); if ( method == 0 ) { /* Not found as a method, try it as an object on which we will call a * default function. */ qual->append( QualItem( QualItem::Dot, loc, name ) ); /* Lookup the object that the field is in. */ VarRefLookup lookup = lookupObj( pd ); /* Find the method. */ method = lookup.inScope->findMethod( "finish" ); if ( method == 0 ) error(loc) << "cannot find " << name << "(...) in object" << endp; } lookup.objMethod = method; lookup.uniqueType = method->returnUT; return lookup; } VarRefLookup LangVarRef::lookupIterCall( Compiler *pd ) const { /* Lookup the object that the field is in. */ VarRefLookup lookup = lookupObj( pd ); /* Find the method. */ ObjectMethod *method = lookup.inScope->findMethod( name ); if ( method == 0 ) { /* Not found as a method, try it as an object on which we will call a * default function. */ qual->append( QualItem( QualItem::Dot, loc, name ) ); /* Lookup the object that the field is in. */ VarRefLookup lookup = lookupObj( pd ); /* Find the method. */ method = lookup.inScope->findMethod( "finish" ); if ( method == 0 ) error(loc) << "cannot find " << name << "(...) in object" << endp; } lookup.objMethod = method; lookup.uniqueType = method->returnUT; return lookup; }