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