Mercurial > projects > ddmd
diff dmd/InterfaceDeclaration.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 427f8aa74d28 fd4acc376c45 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/InterfaceDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,511 @@ +module dmd.InterfaceDeclaration; + +import dmd.ClassDeclaration; +import dmd.Loc; +import dmd.DsymbolTable; +import dmd.STC; +import dmd.Type; +import dmd.TY; +import dmd.LINK; +import dmd.Argument; +import dmd.Util; +import dmd.TypeTuple; +import dmd.PROT; +import dmd.TypeClass; +import dmd.Identifier; +import dmd.ArrayTypes; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.Global; +import dmd.BaseClass; +import dmd.Id; + +import dmd.backend.Symbol; +import dmd.backend.TYM; +import dmd.backend.dt_t; +import dmd.backend.Util; +import dmd.codegen.Util; +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.LIST; +import dmd.backend.SFL; + +class InterfaceDeclaration : ClassDeclaration +{ +version (DMDV2) { + bool cpp; // true if this is a C++ interface +} + this(Loc loc, Identifier id, BaseClasses baseclasses) + { + super(loc, id, baseclasses); + + if (id is Id.IUnknown) // IUnknown is the root of all COM interfaces + { + com = true; + cpp = true; // IUnknown is also a C++ interface + } + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void semantic(Scope sc) + { + int i; + + //printf("InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type); + if (inuse) + return; + + if (!sc) + sc = scope_; + if (!parent && sc.parent && !sc.parent.isModule()) + parent = sc.parent; + + type = type.semantic(loc, sc); + handle = type; + + if (!members) // if forward reference + { + //printf("\tinterface '%s' is forward referenced\n", toChars()); + return; + } + if (symtab) // if already done + { + if (!scope_) + return; + } + else + symtab = new DsymbolTable(); + + Scope scx = null; + if (scope_) + { + sc = scope_; + scx = scope_; // save so we don't make redundant copies + scope_ = null; + } + + if (sc.stc & STC.STCdeprecated) + { + isdeprecated = true; + } + + // Expand any tuples in baseclasses[] + for (i = 0; i < baseclasses.dim; ) + { + BaseClass b = cast(BaseClass)baseclasses.data[0]; + b.type = b.type.semantic(loc, sc); + Type tb = b.type.toBasetype(); + + if (tb.ty == TY.Ttuple) + { TypeTuple tup = cast(TypeTuple)tb; + PROT protection = b.protection; + baseclasses.remove(i); + size_t dim = Argument.dim(tup.arguments); + for (size_t j = 0; j < dim; j++) + { Argument arg = Argument.getNth(tup.arguments, j); + b = new BaseClass(arg.type, protection); + baseclasses.insert(i + j, cast(void*)b); + } + } + else + i++; + } + + if (!baseclasses.dim && sc.linkage == LINK.LINKcpp) + cpp = 1; + + // Check for errors, handle forward references + for (i = 0; i < baseclasses.dim; ) + { + TypeClass tc; + BaseClass b; + Type tb; + + b = cast(BaseClass)baseclasses.data[i]; + b.type = b.type.semantic(loc, sc); + tb = b.type.toBasetype(); + if (tb.ty == TY.Tclass) + tc = cast(TypeClass)tb; + else + tc = null; + if (!tc || !tc.sym.isInterfaceDeclaration()) + { + error("base type must be interface, not %s", b.type.toChars()); + baseclasses.remove(i); + continue; + } + else + { + // Check for duplicate interfaces + for (size_t j = 0; j < i; j++) + { + BaseClass b2 = cast(BaseClass)baseclasses.data[j]; + if (b2.base is tc.sym) + error("inherits from duplicate interface %s", b2.base.toChars()); + } + + b.base = tc.sym; + if (b.base == this || isBaseOf2(b.base)) + { + error("circular inheritance of interface"); + baseclasses.remove(i); + continue; + } + if (!b.base.symtab) + { + // Try to resolve forward reference + if (sc.mustsemantic && b.base.scope_) + b.base.semantic(null); + } + if (!b.base.symtab || b.base.scope_ || b.base.inuse) + { + //error("forward reference of base class %s", baseClass.toChars()); + // Forward reference of base, try again later + //printf("\ttry later, forward reference of base %s\n", b.base.toChars()); + scope_ = scx ? scx : new Scope(sc); + scope_.setNoFree(); + scope_.module_.addDeferredSemantic(this); + return; + } + } +static if (false) { + // Inherit const/invariant from base class + storage_class |= b.base.storage_class & STC.STC_TYPECTOR; +} + i++; + } + + interfaces_dim = baseclasses.dim; + interfaces = cast(BaseClass*)baseclasses.data; + + interfaceSemantic(sc); + + if (vtblOffset()) + vtbl.push(cast(void*)this); // leave room at vtbl[0] for classinfo + + // Cat together the vtbl[]'s from base interfaces + for (i = 0; i < interfaces_dim; i++) + { + BaseClass b = interfaces[i]; + + // Skip if b has already appeared + for (int k = 0; k < i; k++) + { + if (b == interfaces[i]) + goto Lcontinue; + } + + // Copy vtbl[] from base class + if (b.base.vtblOffset()) + { int d = b.base.vtbl.dim; + if (d > 1) + { + vtbl.reserve(d - 1); + for (int j = 1; j < d; j++) + vtbl.push(b.base.vtbl.data[j]); + } + } + else + { + vtbl.append(b.base.vtbl); + } + + Lcontinue: + ; + } + + protection = sc.protection; + storage_class |= sc.stc & STC.STC_TYPECTOR; + + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.addMember(sc, this, 1); + } + + sc = sc.push(this); + sc.stc &= ~(STC.STCfinal | STC.STCauto | STC.STCscope | STC.STCstatic | + STC.STCabstract | STC.STCdeprecated | STC.STC_TYPECTOR | STC.STCtls | STC.STCgshared); + sc.stc |= storage_class & STC.STC_TYPECTOR; + sc.parent = this; + if (isCOMinterface()) + sc.linkage = LINK.LINKwindows; + else if (isCPPinterface()) + sc.linkage = LINK.LINKcpp; + sc.structalign = 8; + structalign = sc.structalign; + sc.offset = PTRSIZE * 2; + inuse++; + for (i = 0; i < members.dim; i++) + { + Dsymbol s = cast(Dsymbol)members.data[i]; + s.semantic(sc); + } + inuse--; + //members.print(); + sc.pop(); + //printf("-InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type); + } + + bool isBaseOf(ClassDeclaration cd, int* poffset) + { + uint j; + + //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars()); + assert(!baseClass); + for (j = 0; j < cd.interfaces_dim; j++) + { + BaseClass b = cd.interfaces[j]; + + //printf("\tbase %s\n", b.base.toChars()); + if (this == b.base) + { + //printf("\tfound at offset %d\n", b.offset); + if (poffset) + { + *poffset = b.offset; + if (j && cd.isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + } + return true; + } + if (isBaseOf(b, poffset)) + { + if (j && poffset && cd.isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + return true; + } + } + + if (cd.baseClass && isBaseOf(cd.baseClass, poffset)) + return true; + + if (poffset) + *poffset = 0; + return false; + } + + bool isBaseOf(BaseClass bc, int* poffset) + { + assert(false); + } + + string kind() + { + assert(false); + } + + /**************************************** + * Determine if slot 0 of the vtbl[] is reserved for something else. + * For class objects, yes, this is where the ClassInfo ptr goes. + * For COM interfaces, no. + * For non-COM interfaces, yes, this is where the Interface ptr goes. + */ + int vtblOffset() + { + if (isCOMinterface() || isCPPinterface()) + return 0; + return 1; + } + +version (DMDV2) { + bool isCPPinterface() + { + return cpp; + } +} + bool isCOMinterface() + { + return com; + } + + void toObjFile(int multiobj) // compile to .obj file + { + uint i; + uint offset; + Symbol* sinit; + SC scclass; + + //printf("InterfaceDeclaration.toObjFile('%s')\n", toChars()); + + if (!members) + return; + + if (global.params.symdebug) + toDebug(); + + scclass = SCglobal; + if (inTemplateInstance()) + scclass = SCcomdat; + + // Put out the members + for (i = 0; i < members.dim; i++) + { + Dsymbol member; + + member = cast(Dsymbol)members.data[i]; + if (!member.isFuncDeclaration()) + member.toObjFile(0); + } + + // Generate C symbols + toSymbol(); + + ////////////////////////////////////////////// + + // Put out the TypeInfo + type.getTypeInfo(null); + type.vtinfo.toObjFile(multiobj); + + ////////////////////////////////////////////// + + // Put out the ClassInfo + csym.Sclass = scclass; + csym.Sfl = FLdata; + + /* The layout is: + { + void **vptr; + monitor_t monitor; + byte[] initializer; // static initialization data + char[] name; // class name + void *[] vtbl; + Interface[] interfaces; + Object *base; // base class + void *destructor; + void *invariant; // class invariant + uint flags; + void *deallocator; + OffsetTypeInfo[] offTi; + void *defaultConstructor; + #if DMDV2 + const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function + #endif + TypeInfo typeinfo; + } + */ + dt_t *dt = null; + + if (classinfo) + dtxoff(&dt, classinfo.toVtblSymbol(), 0, TYnptr); // vtbl for ClassInfo + else + dtdword(&dt, 0); // BUG: should be an assert() + dtdword(&dt, 0); // monitor + + // initializer[] + dtdword(&dt, 0); // size + dtdword(&dt, 0); // initializer + + // name[] + string name = toPrettyChars(); + size_t namelen = name.length; + dtdword(&dt, namelen); + dtabytes(&dt, TYnptr, 0, namelen + 1, toStringz(name)); + + // vtbl[] + dtdword(&dt, 0); + dtdword(&dt, 0); + + // vtblInterfaces.data[] + dtdword(&dt, vtblInterfaces.dim); + if (vtblInterfaces.dim) + { + if (classinfo) + assert(classinfo.structsize == CLASSINFO_SIZE); + offset = CLASSINFO_SIZE; + dtxoff(&dt, csym, offset, TYnptr); // (*) + } + else + dtdword(&dt, 0); + + // base + assert(!baseClass); + dtdword(&dt, 0); + + // dtor + dtdword(&dt, 0); + + // invariant + dtdword(&dt, 0); + + // flags + dtdword(&dt, 4 | isCOMinterface() | 32); + + // deallocator + dtdword(&dt, 0); + + // offTi[] + dtdword(&dt, 0); + dtdword(&dt, 0); // null for now, fix later + + // defaultConstructor + dtdword(&dt, 0); + + version (DMDV2) { + // xgetMembers + dtdword(&dt, 0); + } + + dtxoff(&dt, type.vtinfo.toSymbol(), 0, TYnptr); // typeinfo + + ////////////////////////////////////////////// + + // Put out vtblInterfaces.data[]. Must immediately follow csym, because + // of the fixup (*) + + offset += vtblInterfaces.dim * (4 * PTRSIZE); + for (i = 0; i < vtblInterfaces.dim; i++) + { + BaseClass b = cast(BaseClass)vtblInterfaces.data[i]; + ClassDeclaration id = b.base; + + // ClassInfo + dtxoff(&dt, id.toSymbol(), 0, TYnptr); + + // vtbl[] + dtdword(&dt, 0); + dtdword(&dt, 0); + + // this offset + dtdword(&dt, b.offset); + } + + csym.Sdt = dt; + version (ELFOBJ) { + csym.Sseg = CDATA; + } + version (MACHOBJ) { + csym.Sseg = DATA; + } + outdata(csym); + if (isExport()) + obj_export(csym,0); + } + + /************************************* + * Create the "InterfaceInfo" symbol + */ + Symbol* toSymbol() + { + if (!csym) + { + Symbol *s; + + if (!scc) + scc = fake_classsym(Id.ClassInfo); + + s = toSymbolX("__Interface", SCextern, scc.Stype, "Z"); + s.Sfl = FLextern; + s.Sflags |= SFLnodebug; + csym = s; + slist_add(s); + } + return csym; + } + + InterfaceDeclaration isInterfaceDeclaration() { return this; } +} \ No newline at end of file