/* * DECL.C * * (c)Copyright 1993-2014, Matthew Dillon, All Rights Reserved. See the * COPYRIGHT file at the base of the distribution. */ #include "defs.h" #include #define DHSIZE 4096 #define DHMASK (DHSIZE - 1) static Declaration *DeclHashAry[DHSIZE]; static Declaration *OperHashAry[DHSIZE]; void InitDecls(void) { } /* * Allocate a declaration and add it to the tail of the sg's declaration * list. */ Declaration * AllocDeclaration(SemGroup *sg, int dop, Scope *scope) { Parse *p = sg->sg_Parse; Declaration *d = zalloc(sizeof(Declaration)); if ((scope->s_Flags & SCOPE_ALL_VISIBLE) == 0) scope->s_Flags |= SCOPE_LIBRARY; d->d_Parse = p; d->d_Op = dop; d->d_MyGroup = sg; d->d_Index = sg->sg_DeclCount++; d->d_Scope = *scope; d->d_Level = sg; d->d_Offset = -1; d->d_DynIndex = -1; d->d_BackendId = -1; RUNE_INSERT_TAIL(&sg->sg_DeclList, d, d_Node); if (p->p_Format == PFMT_SOURCE) LexInitRef(&d->d_LexRef, &p->p_Token); return(d); } void FreeDeclaration(Parse *p __unused, Declaration *d) { /* XXX free the Type */ /* XXX free d_AssExp */ /* XXX free d_ProcBody */ /* XXX free d_OrigBody */ if (d->d_Id != NULL) { string_t id = UnHashDecl(d); RelStrTable(&id); } if (d->d_Op == DOP_PROC && d->d_ProcDecl.ed_OperId != NULL) { string_t id = UnHashOper(d); RelStrTable(&id); } if (d->d_MyGroup) { RUNE_REMOVE(&d->d_MyGroup->sg_DeclList, d, d_Node); d->d_MyGroup = NULL; } zfree(d, sizeof(Declaration)); } Declaration * AllocImportDecl(Stmt *st, Scope *scope) { Declaration *d; dassert(st->st_Op == ST_Import); d = AllocDeclaration(st->st_MyGroup, DOP_IMPORT, scope); LexDupRef(&st->st_LexRef, &d->d_LexRef); /* * st_MyGroup may be empty if the import is shared. Use the SemGroup * initialized by the parser. (If the import is not shared es_SemGroup * will be the same as st_MyGroup). * * Note that ParseModule() will handle the d->d_ImportDecl.ed_SemGroup * and st->st_ImportStmt.es_SemGroup glue. */ StrTableDup(st->st_ImportStmt.es_AsId); HashDecl(d, st->st_ImportStmt.es_AsId); return(d); } Declaration * AllocClassDecl(Stmt *st, string_t id, Type *super, Scope *scope) { Declaration *d; dassert(st->st_Op == ST_Class); d = AllocDeclaration(st->st_MyGroup->sg_Parent, DOP_CLASS, scope); LexDupRef(&st->st_LexRef, &d->d_LexRef); d->d_ClassDecl.ed_Super = super; d->d_ClassDecl.ed_SemGroup = st->st_MyGroup; HashDecl(d, id); return(d); } SemGroup * AllocSemGroup(sg_type_t type, Parse *p, SemGroup *par, Stmt *st) { SemGroup *sg = zalloc(sizeof(SemGroup)); if (par) { sg->sg_Parent = par; sg->sg_NestLevel = par->sg_NestLevel; sg->sg_NestSize = par->sg_NestSize; RUNE_INSERT_TAIL(&par->sg_SemList, sg, sg_Node); } sg->sg_Type = type; sg->sg_Parse = p; sg->sg_Stmt = st; sg->sg_Level = -1; RUNE_INIT(&sg->sg_SemList); RUNE_INIT(&sg->sg_DeclList); RUNE_INIT(&sg->sg_ClassList); return(sg); } void FreeSemGroup(SemGroup *sg) { if (sg->sg_Parent) { RUNE_REMOVE(&sg->sg_Parent->sg_SemList, sg, sg_Node); sg->sg_Parent = NULL; } dassert(RUNE_EMPTY(&sg->sg_DeclList)); /* XXX zfree? */ } #if 0 /* * Allocate a declaration block from a compound expression */ SemGroup * AllocSemGroupFromCompoundExp(SemGroup *par, Exp *exp) { SemGroup *sg; sg = AllocSemGroup(SG_COMPOUND, par->sg_Parse, par, NULL); while (exp) { Declaration *d; Scope tscope = INIT_SCOPE(SCOPE_PUBLIC); d = AllocDeclaration(sg, DOP_GROUP_STORAGE, &tscope); LexDupRef(&exp->ex_LexRef, &d->d_LexRef); d->d_StorDecl.ed_Type = exp->ex_Type; } return(sg); } #endif /* * DupSemGroup() - duplicate a semantic group * * Duplicate ssg. sg is the new parent. * * This routine guarentees that the d_Index's and * ordering will match up (because it forces it). */ SemGroup * DupSemGroup(SemGroup *sg, Stmt *st, SemGroup *ssg, int dupDecls) { Declaration *d; SemGroup *nsg = AllocSemGroup(ssg->sg_Type, ssg->sg_Parse, sg, st); dassert(RUNE_EMPTY(&nsg->sg_DeclList)); nsg->sg_Flags = ssg->sg_Flags & SGF_INHERIT_BASE; if (dupDecls) { int hiindex = -1; RUNE_FOREACH(d, &ssg->sg_DeclList, d_Node) { Declaration *nd; nd = DupDeclaration(nsg, d); nd->d_Index = d->d_Index; if (hiindex < d->d_Index) /* sanity */ hiindex = d->d_Index; /* sanity */ } dassert(hiindex == nsg->sg_DeclCount - 1); nsg->sg_VarCount = ssg->sg_VarCount; } nsg->sg_NestLevel = ssg->sg_NestLevel; nsg->sg_NestSize = ssg->sg_NestSize; nsg->sg_AltContext = ssg->sg_AltContext; return(nsg); } static int hashid(SemGroup *sg, string_t id) { return((((int)(intptr_t)sg + (int)(intptr_t)id) >> 7) & DHMASK); } /* * findDecl() - find declaration relative to class level N * * FindDecl() will find the highest identifier less then or equal to * the specified level. When multple identifiers are found at the * same (highest) level, FindDecl() will return the last, which is * first entered. This allows us to bring certain types of * declarations, such as superclass methods, into a subclass and only * access them under special circumstances. See ResolveClasses(). */ static Declaration * findDecl(SemGroup *sg, string_t id, int visibility, int level, int *eno) { Declaration *d; /* * private visibility is usually lost first, then library, then * public. But some searches want to initially restrict to within * the current library or private space in which case we must still * match against public declarations, etc. This typically happens * at parse time. */ if (visibility & SCOPE_LIBRARY) visibility |= SCOPE_PUBLIC; if (visibility & SCOPE_PRIVATE) visibility |= SCOPE_LIBRARY|SCOPE_PUBLIC; for (d = DeclHashAry[hashid(sg, id)]; d; d = d->d_HNext) { Declaration *bd; if (d->d_MyGroup != sg || d->d_Id != id) continue; if (level >= 0 && d->d_Level->sg_Level > level) continue; /* * Find the closest matching level. */ if (level >= 0) { bd = d; for (d = d->d_HNext; d; d = d->d_HNext) { if (d->d_MyGroup != sg || d->d_Id != id) continue; if (d->d_Level->sg_Level <= level && d->d_Level->sg_Level >= bd->d_Level->sg_Level ) { bd = d; /* first, highest id < level */ } } d = bd; } /* * Check visibility. We may have to recurse through d_Super * to be able to check visibility from the point of view of * the superclass. */ if (level >= 0) { bd = d; while (bd->d_MyGroup->sg_Level != level) { dassert(bd->d_Super != NULL); bd = bd->d_Super; } if ((bd->d_ScopeFlags & visibility) == 0) { *eno = TOK_ERR_SCOPE_NOT_VISIBLE; break; } } else { if ((d->d_ScopeFlags & visibility) == 0) { *eno = TOK_ERR_SCOPE_NOT_VISIBLE; break; } } /* * Yahh */ *eno = 0; return(d); } *eno = TOK_ERR_ID_NOT_FOUND; return(NULL); } Declaration * FindOperId(SemGroup *sg, string_t id, int args) { Declaration *d; for (d = OperHashAry[hashid(sg, id)]; d; d = d->d_ONext) { if (d->d_MyGroup == sg && d->d_Op == DOP_PROC && d->d_ProcDecl.ed_OperId == id) { if (d->d_ProcDecl.ed_Type->ty_ProcType.et_ArgCount == (runesize_t)args) { break; } } } return(d); } /* * Associate an identifier with the declaration. We eat the caller's * reference to the identifier. * * Return 1 if a duplicate declaration has been detected. Such detection is * only useful during the parsing phase since we overload identifiers in the * resolution phase. * * NOTE! we depend on inserting at the base of the hash chain. See * findDecl() for more information. */ int HashDecl(Declaration *d, string_t id) { Declaration **pd; SemGroup *sg = d->d_MyGroup; dassert(d != NULL); dassert_decl(d, id != NULL && d->d_Id == NULL && d->d_MyGroup != NULL); d->d_Id = id; pd = &DeclHashAry[hashid(d->d_MyGroup, id)]; d->d_HNext = *pd; *pd = d; if (id != String_Self) { while ((d = d->d_HNext) != NULL) { if (d->d_Id == id && d->d_MyGroup == sg) return(1); } } return(0); } /* * Remove the identifier associated with the declaration. */ string_t UnHashDecl(Declaration *d) { string_t id; if ((id = d->d_Id) != NULL) { Declaration **pd; pd = &DeclHashAry[hashid(d->d_MyGroup, id)]; while (*pd != d) { dassert(*pd != NULL); pd = &(*pd)->d_HNext; } *pd = d->d_HNext; d->d_HNext = NULL; d->d_Id = NULL; } return(id); } void HashOper(Declaration *d, string_t id) { Declaration **pd; dassert(d != NULL); dassert_decl(d, id != NULL && d->d_MyGroup != NULL && d->d_Op == DOP_PROC && d->d_ProcDecl.ed_OperId == NULL); d->d_ProcDecl.ed_OperId = id; pd = &OperHashAry[hashid(d->d_MyGroup, id)]; d->d_ONext = *pd; *pd = d; } string_t UnHashOper(Declaration *d) { string_t id; dassert_decl(d, d->d_Op == DOP_PROC); if ((id = d->d_ProcDecl.ed_OperId) != NULL) { Declaration **pd; pd = &OperHashAry[hashid(d->d_MyGroup, id)]; while (*pd != d) { dassert(*pd != NULL); pd = &(*pd)->d_ONext; } *pd = d->d_ONext; d->d_ONext = NULL; d->d_ProcDecl.ed_OperId = NULL; } return(id); } /* * Rename a declaration, fixup the hash tables appropriately. Used when * making contextual declarations such 'Fd.setfd ...' outside the Fd class. * * NOTE: The original SemGroup will have holes in its index now. */ void RenameDecl(Declaration *d, SemGroup *nsg) { string_t id; string_t operId; id = UnHashDecl(d); if (d->d_Op == DOP_PROC) operId = UnHashOper(d); else operId = NULL; RUNE_REMOVE(&d->d_MyGroup->sg_DeclList, d, d_Node); RUNE_INSERT_TAIL(&nsg->sg_DeclList, d, d_Node); d->d_Index = nsg->sg_DeclCount++; d->d_MyGroup = nsg; if (id) HashDecl(d, id); if (operId) HashOper(d, operId); } /* * MatchOperatorTypes() - Match left and right hand types to the operator * procedure. * * The op decl is a procedure definition. Access the procedure * arguments and match them against the Lhs and Rhs types of the exp, * returning 0 on failure, 1 on match. * * If the op decl is an internal operator, match pointers to void * against any pointer. */ int MatchOperatorTypes(Declaration *d, Type *ltype, Type *rtype) { Type *type; SemGroup *sg; int r; int isInternal; int matchVoidPtr; /* * Pull the procedure argument type, which must be a compound type. */ dassert_decl(d, d->d_Op == DOP_PROC && d->d_ProcDecl.ed_Type->ty_Op == TY_PROC); type = d->d_ProcDecl.ed_Type->ty_ProcType.et_ArgsType; dassert_decl(d, type->ty_Op == TY_ARGS); sg = type->ty_ArgsType.et_SemGroup; isInternal = 0; matchVoidPtr = 0; if (d->d_ScopeFlags & SCOPE_INTERNAL) isInternal = 1; if (d->d_ScopeFlags & SCOPE_INTERNAL2) matchVoidPtr = 1; /* * Obtain first argument */ RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) { if (d->d_Op == DOP_ARGS_STORAGE) break; } /* * Match types. For an internal operator, void * matches * any pointer. */ if (d == NULL) return(0); if (isInternal && (ltype->ty_Op == TY_PTRTO || ltype->ty_Op == TY_REFTO || ltype->ty_Op == TY_CPTRTO) && SimilarType(&VoidRefType, d->d_StorDecl.ed_Type) ) { isInternal = 2; } else if (MatchType(d->d_StorDecl.ed_Type, ltype) > SG_COMPAT_SUBCLASS) { return(0); } /* * Obtain the second argument */ while ((d = RUNE_NEXT(d, d_Node)) && d->d_Op != DOP_ARGS_STORAGE) ; /* * Match types. */ if (rtype) { if (d == NULL) return(0); /* * Special case for internal pointer ops. In the * (ptr op ptr) case, the rhs pointer must match the * lhs pointer. As an exception if matchVoidPtr is non-zero, * one of the two pointers may match VoidPtr. */ if (isInternal == 2 && (rtype->ty_Op == TY_PTRTO || rtype->ty_Op == TY_REFTO || rtype->ty_Op == TY_CPTRTO) && (d->d_StorDecl.ed_Type->ty_Op == TY_PTRTO || d->d_StorDecl.ed_Type->ty_Op == TY_REFTO || d->d_StorDecl.ed_Type->ty_Op == TY_CPTRTO) ) { r = MatchType(ltype, rtype); if (matchVoidPtr && r > SG_COMPAT_SUBCLASS) r = MatchType(&VoidPtrType, rtype); if (matchVoidPtr && r > SG_COMPAT_SUBCLASS) r = MatchType(&VoidPtrType, ltype); } else { r = MatchType(d->d_StorDecl.ed_Type, rtype); } r = (r <= SG_COMPAT_SUBCLASS); } else if (d) { r = 0; } else { r = 1; } return(r); } /* * MatchCastTypes() - Match the return type and argument for a cast * * The cast decl is a procedure definition. Access the procedure * arguments and match them against the Lhs and Rhs types of the exp, * returning 0 on failure, 1 on match. * * XXX allow internal bindings of subclasses to super classes. */ int MatchCastTypes(Declaration *d, Type *ltype, Type *rtype) { Declaration *d2; Type *type; SemGroup *sg; int r; dassert_decl(d, d->d_Op == DOP_PROC && d->d_ProcDecl.ed_Type->ty_Op == TY_PROC); /* * Pull the procedure return type, which must match ltype */ type = d->d_ProcDecl.ed_Type->ty_ProcType.et_RetType; dassert(type->ty_Op != TY_UNRESOLVED); if (MatchType(type, ltype) > SG_COMPAT_SUBCLASS) return(0); /* * Pull the procedure argument type, which must be a compound type. */ type = d->d_ProcDecl.ed_Type->ty_ProcType.et_ArgsType; dassert_decl(d, type->ty_Op == TY_ARGS); sg = type->ty_ArgsType.et_SemGroup; /* * Obtain first argument and match against the cast argument (rtype). */ RUNE_FOREACH(d2, &sg->sg_DeclList, d_Node) { if (d2->d_Op == DOP_ARGS_STORAGE) break; } /* * Match types */ if (d2 == NULL) return(0); if ((d->d_ScopeFlags & SCOPE_INTERNAL) && (rtype->ty_Op == TY_PTRTO || rtype->ty_Op == TY_REFTO || rtype->ty_Op == TY_CPTRTO) && SimilarType(&VoidRefType, d2->d_StorDecl.ed_Type) ) { r = 0; } else { r = MatchType(d2->d_StorDecl.ed_Type, rtype); } if (r > SG_COMPAT_SUBCLASS) return(0); /* * Obtain the second argument .. that is, make sure there * isn't a second argument. */ while ((d2 = RUNE_NEXT(d2, d_Node)) && d->d_Op != DOP_ARGS_STORAGE) ; if (d2) return(0); return(1); } /* * FindDLLSymbol() * * Find the requested DLL symbol by recursing through our SemGroup's * looking for DLL imports. If found, return its value. */ void * FindDLLSymbol(SemGroup *osg, SemGroup *sg, string_t id) { while (sg) { /* * Look for the declaration in this SemGroup */ Declaration *d; RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) { if (d->d_Op == DOP_IMPORT) { Stmt *st; void (*func)(void); st = d->d_Stmt; dassert(st && st->st_Op == ST_Import); if (st->st_ImportStmt.es_DLL) { func = dlsym(st->st_ImportStmt.es_DLL, id); if (func) return(func); } } } if (osg && sg->sg_Stmt && sg->sg_Stmt->st_Op == ST_Class) { sg = osg; osg = NULL; } else { if (sg->sg_Flags & SGF_SELFCONTAINED) break; sg = sg->sg_Parent; } } return(NULL); } /* * FindDeclPath() * * Find the declaration associated with the array of identifiers * representing id.id.id... * * We are allowed to recurse backwards in order to locate the first * id in the array, and to recurse downwards through 'self' or * explicitly named mounts. Once the first identifier matches, * however, we can only recurse downwards. We do not try to * overload our searches. * * When recursing backwards it is not possible to access non-global * storage elements of a class, because there is no context in which * to get at those variables (you have to go through "." or "->" via * 'this' or something like that). But it is ok to access globals * and types. * * Note that typedef's do not match their own identifier, so something * like 'typedef int int' works to create a qualified type that hides * the original. XXX remove * * 'level' is used when resolving identifiers in a subclass that were * pulled in from the superclass. Also, if we have to go backwards * (the identifier can't be found in the subclass), we have to switch * to the original superclass's semgroup. LEVEL IS ONLY USED WHEN * RESOLVING IDENTIFIERS RELATIVE TO A "." OR "->" EXPRESSION, OR * WHEN THE 'CURRENT' SEMGROUP IS THE CLASS ITSELF (I.E. DEFAULT * ASSIGNMENTS AND THE DECLARATION ITSELF, BUT NOT A PROCEDURE BODY). * * On success *visibility will be set to the base visibility required * if any further searches are made relative to the returned declaration. * * On failure *visibility is garbage. */ Declaration * FindDeclPath(LexRef *lexRef, SemGroup *osg, SemGroup *sg, Type *nomatch, string_t *ary, int mask, int *visibility, int level, int *eno) { int i; int noLocalStorage = 0; Declaration *d = NULL; i = 0; while (ary[i] && sg) { /* * Look for the declaration in this SemGroup */ d = findDecl(sg, ary[i], *visibility, level, eno); if (d != NULL) { if (nomatch && d->d_Op == DOP_TYPEDEF && nomatch == d->d_TypedefDecl.ed_Type) { d = NULL; } } /* * Look for the declaration in the procedure arguments if this * is the top level of a procedure. */ if (d == NULL && sg->sg_Stmt && sg->sg_Stmt->st_Op == ST_Proc) { Type *argsType; SemGroup *sg2; d = sg->sg_Stmt->st_ProcStmt.es_Decl; dassert_decl(d, d->d_Op == DOP_PROC); argsType = d->d_ProcDecl.ed_Type->ty_ProcType.et_ArgsType; dassert_decl(d, argsType->ty_Op == TY_ARGS); sg2 = argsType->ty_ArgsType.et_SemGroup; d = findDecl(sg2, ary[i], *visibility, level, eno); } /* * Look for the declaration by recursing down into "self" * imports. We do not overload on partial matches.. a * partial match is considered to be a failure. * * If crossing a self-contained boundary only public scope can * be searched. Otherwise both public and library scope * (but not private scope) can be searched. */ if (d == NULL) { d = findDecl(sg, String_Self, *visibility, sg->sg_Level, eno); while (d) { Declaration *d2; int visibility2; if (d->d_MyGroup != sg || d->d_Id != String_Self || d->d_Op != DOP_IMPORT ) { d = d->d_HNext; continue; } dassert_decl(d, d->d_ImportDecl.ed_SemGroup != NULL); if (d->d_ImportDecl.ed_SemGroup->sg_Flags & SGF_SELFCONTAINED) { visibility2 = *visibility & ~(SCOPE_LIBRARY | SCOPE_PRIVATE); } else { visibility2 = *visibility & ~SCOPE_PRIVATE; } d2 = FindDeclPath(lexRef, NULL, d->d_ImportDecl.ed_SemGroup, nomatch, ary + i, (mask & ~FDC_NULL) | FDC_NOBACK, &visibility2, -1, eno); if (d2 == (void *)-1) { if (mask & FDC_NULL) d2 = NULL; return (d2); } /* * This was a complete search of all remaining * array elements, so return on success. */ if (d2) { *visibility = visibility2; return (d2); } d = d->d_HNext; } } /* * If still not found then go back a level. If we cross an * import boundary we lose private-scope (and do not regain * it even if we cross back into the same library). If we * cross a class boundary we may have to locate the * superclass's SG. */ if (d == NULL) { /* * If we are leaving a procedure context */ if (sg && sg->sg_Stmt && sg->sg_Stmt->st_Op == ST_Proc) { if ((sg->sg_Stmt->st_Flags & STF_NESTED) == 0) noLocalStorage = 1; } /* * If we are crossing a class statement boundary we * have to jump to the original import semantic * context. For example, when a procedure is pulled * in from a superclass we want to jump to its * original semantic context, not the context our * subclass is defined in. * * XXX I really wanted the 'original semantic context * of the statement' but it's a mess. This works * just as well. */ if (osg && sg->sg_Stmt && sg->sg_Stmt->st_Op == ST_Class) { sg = osg; osg = NULL; *visibility = SCOPE_ALL_VISIBLE; } else { if ((mask & FDC_NOBACK) || (sg->sg_Flags & SGF_SELFCONTAINED)) { return(NULL); } if (sg->sg_Flags & SGF_SEMTOP) *visibility &= ~SCOPE_PRIVATE; /* * If SGF_ALTPRIORITY is set this was an * inlined procedure and the sg_Parent link * is not the proper semantic path (it isn't * visible namespace-wise). In this situation * the inliner in resolve.c has set * sg_Altcontext to the proper group for * searching. */ if (sg->sg_Flags & SGF_ALTPRIORITY) sg = sg->sg_AltContext; else sg = sg->sg_Parent; } /* * You can't back into a class's local storage (from * a process). */ if (sg && sg->sg_Stmt && sg->sg_Stmt->st_Op == ST_Class) noLocalStorage = 1; continue; } /* * FOUND! No going backwards now, only recurse downwards * through imports and classes from this point on. * * We lose private scope when we go through an import, and * we loose library scope when we cross a selfcontained * (library) boundary. Also, when pushing into a class * semantically there is no context in which to access * local storage. */ mask |= FDC_NOBACK; switch(d->d_Op) { case DOP_IMPORT: sg = d->d_ImportDecl.ed_SemGroup; dassert_decl(d, sg != NULL); if (sg->sg_Flags & SGF_SELFCONTAINED) *visibility &= ~(SCOPE_LIBRARY|SCOPE_PRIVATE); else *visibility &= ~SCOPE_PRIVATE; break; case DOP_CLASS: /* * pushdown into a class. Visibility remains the same. */ sg = d->d_ClassDecl.ed_SemGroup; noLocalStorage = 1; break; case DOP_GROUP_STORAGE: case DOP_ARGS_STORAGE: case DOP_STACK_STORAGE: if (noLocalStorage) { fprintf(stderr, "You cannot access instantiated " "storage this way, there is " "no context.\n" "Perhaps you meant to " "use 'this.'.\n"); LexPrintRef(lexRef, 0); exit(1); } /* fall through */ default: dassert_decl(d, ary[i+1] == NULL); sg = NULL; break; } ++i; } return(d); } /* * Look for the declaration via an alternative context. sg_AltContext is * temporarily set while resolving the expression tree, primarily to get * more direct access to type globals when making method calls (otherwise * the code has to prefix each one with the type or object which can be * messy). */ Declaration * FindDeclPathAltContext(LexRef *lexRef, SemGroup *osg, SemGroup *sg, Type *nomatch, string_t *ary, int mask, int *visibility, int level, int *eno) { Declaration *d; while (sg) { if (sg->sg_AltContext) { d = FindDeclPath(lexRef, osg, sg->sg_AltContext, nomatch, ary, mask, visibility, level, eno); if (d && (d->d_ScopeFlags & SCOPE_GLOBAL)) return d; } if ((sg->sg_Flags & (SGF_SEMTOP|SGF_NESTED)) == SGF_SEMTOP) break; sg = sg->sg_Parent; } return NULL; } Declaration * FindDeclId(SemGroup *sg, string_t id, int *eno) { Declaration *d; d = findDecl(sg, id, SCOPE_ALL_VISIBLE, sg->sg_Level, eno); return(d); } Declaration * FindDeclIdLevel(SemGroup *sg, string_t id, int level, int *eno) { Declaration *d; d = findDecl(sg, id, SCOPE_ALL_VISIBLE, level, eno); return(d); } /* * RefineDeclaration() - rd is a refinement of sd. Fixup rd. * * sg is the semgroup representing our subclass (in the middle of * being built). Refinements can be: * * - Completely compatible, such as a simple change in defaults * * - Partially compatible, such as compatible method overrides * (means can still be directly accessed via a superclass @ref). * * - Incompatible, when refinements change the underlying type, * arguments, or return values in incompatible ways. * * XXX YYY * * NOTE: May be called multiple times with the same argument. */ void RefineDeclaration(SemGroup *sg, Declaration *sd, Declaration *rd) { int compat = MatchDeclTypes(sd, rd); if (compat < SG_COMPAT_PART && sd->d_Op == DOP_PROC) compat = SG_COMPAT_PART; if (sg->sg_Compat < compat) sg->sg_Compat = compat; if (compat == SG_COMPAT_FAIL) { fprintf(stderr, "Refinement is illegal\n"); dassert_decl(rd, 0); } } /* * DupDeclaration() - duplicate a declaration (called during resolve) * * Note: When you dup a resolved declaration, it becomes unresolved. * The semGroup the decl's is being dup'd into must be resolved * afterwords. Note that the d_Index's will not necessarily match up. * * Note: d_Level and d_Search are inherited from sd. d_Level should be * non-NULL if sd is a declaration within a class, and NULL otherwise. * d_Search will be non-NULL when we integrate a declaration into a * subclass recursively. That is, if you have class A and subclass B of A, * and subclass C of B, then when C pulls in a declaration from B that was * originally from A, it will see a non-NULL d_Search in b's version of * the declaration. */ Declaration * DupDeclaration(SemGroup *sg, Declaration *sd) { Declaration *d = AllocDeclaration(sg, sd->d_Op, &sd->d_Scope); SemGroup *xsg; LexDupRef(&sd->d_LexRef, &d->d_LexRef); if (sd->d_Id) HashDecl(d, sd->d_Id); d->d_Flags = sd->d_Flags & ~(DF_RESOLVED | DF_RESOLVING | DF_TMPRESOLVED | DF_LAYOUT | DF_DIDEXPDUP | DF_ONCLIST | DF_ONDLIST | DF_ONGLIST | DF_ONSRLIST | DF_DIDPULLDOWN | DF_ADDROF | DF_ADDRUSED); d->d_Level = sd->d_Level; d->d_Search = sd->d_Search; d->d_ImportSemGroup = sd->d_ImportSemGroup; d->d_Super = sd; d->d_Level = sd->d_Level; d->d_Stmt = sd->d_Stmt; /* do not dup d_DynIndex */ /* * We do not need to re-evaluate types for the new SemGroup unless * the change of venue would cause them to change (such as a refined * typedef). */ switch(sg->sg_Type) { case SG_CLASS: case SG_COMPOUND: case SG_PROCARGS: xsg = sg; break; default: xsg = NULL; break; } /* * XXX decl may be resolved if dup'ing a semgroup for a varargs call. * See libd/resolve.d 'Too many arg' */ #if 0 dassert_decl(d, (d->d_Flags & (DF_RESOLVED|DF_RESOLVING)) == 0); #endif switch(d->d_Op) { case DOP_CLASS: case DOP_IMPORT: /* * Only occurs inside import, so dup() should never be * called on it. */ dassert_decl(d, 0); break; case DOP_ARGS_STORAGE: case DOP_STACK_STORAGE: case DOP_GLOBAL_STORAGE: case DOP_GROUP_STORAGE: d->d_StorDecl.ed_Type = DupType(xsg, sd->d_StorDecl.ed_Type); d->d_StorDecl.ed_AssExp = DupExp(sg, sd->d_StorDecl.ed_AssExp); break; case DOP_TYPEDEF: d->d_TypedefDecl.ed_Type = DupType(xsg, sd->d_TypedefDecl.ed_Type); d->d_TypedefDecl.ed_AssExp = DupExp(sg, sd->d_TypedefDecl.ed_AssExp); break; case DOP_ALIAS: d->d_AliasDecl.ed_Type = DupType(xsg, sd->d_AliasDecl.ed_Type); d->d_AliasDecl.ed_AssExp = DupExp(sg, sd->d_AliasDecl.ed_AssExp); break; case DOP_PROC: /* * We do not duplicate the procedure body here. If we were to * it would result in X*Y copies of the procedure whether they * were used or not. Instead this is done at resolve time * in resolveDecl(). */ d->d_ProcDecl.ed_Type = DupType(xsg, sd->d_ProcDecl.ed_Type); if (sd->d_ProcDecl.ed_OperId) HashOper(d, sd->d_ProcDecl.ed_OperId); break; default: dassert_decl(d, 0); } return(d); } void DeclPrintError(Declaration *d, int type) { LexPrintRef(&d->d_LexRef, type); } void AdjustProcArgsNestingLevel(Declaration *d, SemGroup *fromSg) { Type *type; SemGroup *sg; dassert_decl(d, d->d_Op == DOP_PROC && d->d_ProcDecl.ed_Type->ty_Op == TY_PROC); type = d->d_ProcDecl.ed_Type->ty_ProcType.et_ArgsType; dassert_decl(d, type->ty_Op == TY_ARGS); sg = type->ty_ArgsType.et_SemGroup; sg->sg_NestLevel = fromSg->sg_NestLevel; sg->sg_NestSize = fromSg->sg_NestSize; } void AdjustNestSize(SemGroup *sg, int size) { for (;;) { sg->sg_NestSize = size; if ((sg->sg_Flags & (SGF_SEMTOP|SGF_NESTED)) == SGF_SEMTOP) break; sg = sg->sg_Parent; } } /* * Extra cacheability under certain circumstances. Is not all-encompassing. * Used to determine if an inline procedure argument can be cached. */ int DeclarationCacheable(Declaration *d) { Type *type; dassert_decl(d, d->d_Op & DOPF_STORAGE); type = d->d_StorDecl.ed_Type; if (d->d_Flags & DF_ADDRUSED) return 0; if (d->d_Scope.s_Flags & SCOPE_LVALUE) return 0; if (type->ty_Flags & (TF_ISINTEGER | TF_ISFLOATING | TF_ISBOOL)) return 1; return 0; }