diff dmd/TypeClass.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 51605de93870
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/TypeClass.d	Sat Oct 24 08:42:06 2009 +0400
@@ -0,0 +1,637 @@
+module dmd.TypeClass;
+
+import dmd.Type;
+import dmd.ClassDeclaration;
+import dmd.Loc;
+import dmd.Dsymbol;
+import dmd.Scope;
+import dmd.OutBuffer;
+import dmd.HdrGenState;
+import dmd.Expression;
+import dmd.Identifier;
+import dmd.MATCH;
+import dmd.CppMangleState;
+import dmd.ArrayTypes;
+import dmd.TypeInfoDeclaration;
+import dmd.TY;
+import dmd.MOD;
+import dmd.Global;
+import dmd.TypePointer;
+import dmd.Declaration;
+import dmd.VarDeclaration;
+import dmd.TOK;
+import dmd.DotExp;
+import dmd.Id;
+import dmd.ScopeExp;
+import dmd.DotVarExp;
+import dmd.VarExp;
+import dmd.PtrExp;
+import dmd.AddExp;
+import dmd.IntegerExp;
+import dmd.DotIdExp;
+import dmd.EnumMember;
+import dmd.TemplateMixin;
+import dmd.TemplateDeclaration;
+import dmd.TemplateInstance;
+import dmd.OverloadSet;
+import dmd.DotTypeExp;
+import dmd.TupleExp;
+import dmd.ClassInfoDeclaration;
+import dmd.TypeInfoInterfaceDeclaration;
+import dmd.TypeInfoClassDeclaration;
+import dmd.Util;
+import dmd.NullExp;
+import dmd.TypeExp;
+import dmd.DotTemplateExp;
+import dmd.ErrorExp;
+import dmd.ThisExp;
+import dmd.CommaExp;
+
+import dmd.expression.Util;
+import dmd.backend.Symbol;
+import dmd.backend.TYPE;
+import dmd.backend.Util;
+import dmd.backend.SC;
+import dmd.backend.STR;
+import dmd.backend.TYM;
+import dmd.backend.LIST;
+import dmd.backend.Classsym;
+
+import std.string : toStringz;
+
+class TypeClass : Type
+{
+    ClassDeclaration sym;
+
+    this(ClassDeclaration sym)
+	{
+		super(TY.Tclass);
+		this.sym = sym;
+	}
+
+version (DumbClone) {
+} else {
+	Type clone()
+	{
+		assert(false);
+	}
+}
+    ulong size(Loc loc)
+	{
+		return PTRSIZE;
+	}
+	
+    string toChars()
+	{
+		if (mod)
+			return Type.toChars();
+		return sym.toPrettyChars();
+	}
+	
+    Type syntaxCopy()
+	{
+		assert(false);
+	}
+	
+    Type semantic(Loc loc, Scope sc)
+	{
+		//printf("TypeClass.semantic(%s)\n", sym.toChars());
+		if (deco)
+			return this;
+		//printf("\t%s\n", merge().deco);
+		return merge();
+	}
+	
+    Dsymbol toDsymbol(Scope sc)
+	{
+		return sym;
+	}
+	
+    void toDecoBuffer(OutBuffer buf, int flag)
+	{
+		string name = sym.mangle();
+		//printf("TypeClass.toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name);
+		Type.toDecoBuffer(buf, flag);
+		buf.printf("%s", name);
+	}
+	
+    void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod)
+	{
+		if (mod != this.mod)
+		{	
+			toCBuffer3(buf, hgs, mod);
+			return;
+		}
+		buf.writestring(sym.toChars());
+	}
+
+    Expression dotExp(Scope sc, Expression e, Identifier ident)
+	{
+		uint offset;
+
+		Expression b;
+		VarDeclaration v;
+		Dsymbol s;
+
+version (LOGDOTEXP) {
+		printf("TypeClass.dotExp(e='%s', ident='%s')\n", e.toChars(), ident.toChars());
+}
+
+		if (e.op == TOK.TOKdotexp)
+		{
+			DotExp de = cast(DotExp)e;
+
+			if (de.e1.op == TOK.TOKimport)
+			{
+				ScopeExp se = cast(ScopeExp)de.e1;
+
+				s = se.sds.search(e.loc, ident, 0);
+				e = de.e1;
+				goto L1;
+			}
+		}
+
+		if (ident is Id.tupleof_)
+		{
+			/* Create a TupleExp
+			 */
+			e = e.semantic(sc);	// do this before turning on noaccesscheck
+			Expressions exps = new Expressions;
+			exps.reserve(sym.fields.dim);
+			for (size_t i = 0; i < sym.fields.dim; i++)
+			{   
+				VarDeclaration v2 = cast(VarDeclaration)sym.fields.data[i];
+				Expression fe = new DotVarExp(e.loc, e, v2);
+				exps.push(cast(void*)fe);
+			}
+			e = new TupleExp(e.loc, exps);
+			sc = sc.push();
+			sc.noaccesscheck = 1;
+			e = e.semantic(sc);
+			sc.pop();
+			return e;
+		}
+
+		s = sym.search(e.loc, ident, 0);
+	L1:
+		if (!s)
+		{
+			// See if it's a base class
+			ClassDeclaration cbase;
+			for (cbase = sym.baseClass; cbase; cbase = cbase.baseClass)
+			{
+				if (cbase.ident.equals(ident))
+				{
+					e = new DotTypeExp(Loc(0), e, cbase);
+					return e;
+				}
+			}
+
+			if (ident is Id.classinfo_)
+			{
+				assert(ClassDeclaration.classinfo);
+				Type t = ClassDeclaration.classinfo.type;
+				if (e.op == TOK.TOKtype || e.op == TOK.TOKdottype)
+				{
+					/* For type.classinfo, we know the classinfo
+					 * at compile time.
+					 */
+					if (!sym.vclassinfo)
+						sym.vclassinfo = new ClassInfoDeclaration(sym);
+
+					e = new VarExp(e.loc, sym.vclassinfo);
+					e = e.addressOf(sc);
+					e.type = t;	// do this so we don't get redundant dereference
+				}
+				else
+				{	
+					/* For class objects, the classinfo reference is the first
+					 * entry in the vtbl[]
+					 */
+					e = new PtrExp(e.loc, e);
+					e.type = t.pointerTo();
+					if (sym.isInterfaceDeclaration())
+					{
+						if (sym.isCPPinterface())
+						{	
+							/* C++ interface vtbl[]s are different in that the
+							 * first entry is always pointer to the first virtual
+							 * function, not classinfo.
+							 * We can't get a .classinfo for it.
+							 */
+							error(e.loc, "no .classinfo for C++ interface objects");
+						}
+						/* For an interface, the first entry in the vtbl[]
+						 * is actually a pointer to an instance of struct Interface.
+						 * The first member of Interface is the .classinfo,
+						 * so add an extra pointer indirection.
+						 */
+						e.type = e.type.pointerTo();
+						e = new PtrExp(e.loc, e);
+						e.type = t.pointerTo();
+					}
+					e = new PtrExp(e.loc, e, t);
+				}
+				return e;
+			}
+
+			if (ident is Id.__vptr)
+			{   
+				/* The pointer to the vtbl[]
+				 * *cast(invariant(void*)**)e
+				 */
+				e = e.castTo(sc, tvoidptr.invariantOf().pointerTo().pointerTo());
+				e = new PtrExp(e.loc, e);
+				e = e.semantic(sc);
+				return e;
+			}
+
+			if (ident is Id.__monitor)
+			{   /* The handle to the monitor (call it a void*)
+				 * *(cast(void**)e + 1)
+				 */
+				e = e.castTo(sc, tvoidptr.pointerTo());
+				e = new AddExp(e.loc, e, new IntegerExp(1));
+				e = new PtrExp(e.loc, e);
+				e = e.semantic(sc);
+				return e;
+			}
+
+			if (ident is Id.typeinfo_)
+			{
+				if (!global.params.useDeprecated)
+					error(e.loc, ".typeinfo deprecated, use typeid(type)");
+
+				return getTypeInfo(sc);
+			}
+			if (ident is Id.outer && sym.vthis)
+			{
+				s = sym.vthis;
+			}
+			else
+			{
+				if (ident !is Id.__sizeof	 &&
+					ident !is Id.alignof_ &&
+					ident !is Id.init_ &&
+					ident !is Id.mangleof_ &&
+					ident !is Id.stringof_ &&
+					ident !is Id.offsetof)
+				{
+					/* See if we should forward to the alias this.
+					 */
+					if (sym.aliasthis)
+					{   
+						/* Rewrite e.ident as:
+						 *	e.aliasthis.ident
+						 */
+						e = new DotIdExp(e.loc, e, sym.aliasthis.ident);
+						e = new DotIdExp(e.loc, e, ident);
+						return e.semantic(sc);
+					}
+
+					/* Look for overloaded opDot() to see if we should forward request
+					 * to it.
+					 */
+					Dsymbol fd = search_function(sym, Id.opDot);
+					if (fd)
+					{   
+						/* Rewrite e.ident as:
+						 *	e.opId().ident
+						 */
+						e = build_overload(e.loc, sc, e, null, fd.ident);
+						e = new DotIdExp(e.loc, e, ident);
+						return e.semantic(sc);
+					}
+				}
+
+				return Type.dotExp(sc, e, ident);
+			}
+		}
+
+		if (!s.isFuncDeclaration())	// because of overloading
+			s.checkDeprecated(e.loc, sc);
+		
+		s = s.toAlias();
+		v = s.isVarDeclaration();
+		
+		if (v && !v.isDataseg())
+		{	
+			Expression ei = v.getConstInitializer();
+
+			if (ei)
+			{   
+				e = ei.copy();	// need to copy it if it's a StringExp
+				e = e.semantic(sc);
+				return e;
+			}
+		}
+
+		if (s.getType())
+		{
+		//	if (e.op == TOKtype)
+				return new TypeExp(e.loc, s.getType());
+		//	return new DotTypeExp(e.loc, e, s);
+		}
+
+		EnumMember em = s.isEnumMember();
+		if (em)
+		{
+			assert(em.value);
+			return em.value.copy();
+		}
+
+		TemplateMixin tm = s.isTemplateMixin();
+		if (tm)
+		{
+			Expression de = new DotExp(e.loc, e, new ScopeExp(e.loc, tm));
+			de.type = e.type;
+			return de;
+		}
+
+		TemplateDeclaration td = s.isTemplateDeclaration();
+		if (td)
+		{
+			e = new DotTemplateExp(e.loc, e, td);
+			e.semantic(sc);
+			return e;
+		}
+
+		TemplateInstance ti = s.isTemplateInstance();
+		if (ti)
+		{	
+			if (!ti.semanticRun)
+				ti.semantic(sc);
+			s = ti.inst.toAlias();
+			if (!s.isTemplateInstance())
+				goto L1;
+			Expression de = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
+			de.type = e.type;
+			return de;
+		}
+
+		OverloadSet o = s.isOverloadSet();
+		if (o)
+		{	
+			/* We really should allow this
+			 */
+			error(e.loc, "overload set for %s.%s not allowed in struct declaration", e.toChars(), ident.toChars());
+			return new ErrorExp();
+		}
+
+		Declaration d = s.isDeclaration();
+		if (!d)
+		{
+			e.error("%s.%s is not a declaration", e.toChars(), ident.toChars());
+			return new ErrorExp();
+		}
+
+		if (e.op == TOK.TOKtype)
+		{
+			/* It's:
+			 *    Class.d
+			 */
+			if (d.isTupleDeclaration())
+			{
+				e = new TupleExp(e.loc, d.isTupleDeclaration());
+				e = e.semantic(sc);
+				return e;
+			}
+			else if (d.needThis() && (hasThis(sc) || !d.isFuncDeclaration()))
+			{
+				if (sc.func)
+				{
+					ClassDeclaration thiscd;
+					thiscd = sc.func.toParent().isClassDeclaration();
+
+					if (thiscd)
+					{
+						ClassDeclaration cd = e.type.isClassHandle();
+
+						if (cd is thiscd)
+						{
+							e = new ThisExp(e.loc);
+							e = new DotTypeExp(e.loc, e, cd);
+							DotVarExp de = new DotVarExp(e.loc, e, d);
+							e = de.semantic(sc);
+							return e;
+						}
+						else if ((!cd || !cd.isBaseOf(thiscd, null)) && !d.isFuncDeclaration())
+							e.error("'this' is required, but %s is not a base class of %s", e.type.toChars(), thiscd.toChars());
+					}
+				}
+
+				/* Rewrite as:
+				 *	this.d
+				 */
+				DotVarExp de = new DotVarExp(e.loc, new ThisExp(e.loc), d);
+				e = de.semantic(sc);
+				return e;
+			}
+			else
+			{
+				VarExp ve = new VarExp(e.loc, d, 1);
+				return ve;
+			}
+		}
+
+		if (d.isDataseg())
+		{
+			// (e, d)
+			accessCheck(e.loc, sc, e, d);
+			VarExp ve = new VarExp(e.loc, d);
+			e = new CommaExp(e.loc, e, ve);
+			e.type = d.type;
+			return e;
+		}
+
+		if (d.parent && d.toParent().isModule())
+		{
+			// (e, d)
+			VarExp ve = new VarExp(e.loc, d, 1);
+			e = new CommaExp(e.loc, e, ve);
+			e.type = d.type;
+			return e;
+		}
+
+		DotVarExp de = new DotVarExp(e.loc, e, d);
+		return de.semantic(sc);
+	}
+	
+    ClassDeclaration isClassHandle()
+	{
+		return sym;
+	}
+	
+    bool isBaseOf(Type t, int* poffset)
+	{
+		assert(false);
+	}
+	
+    MATCH implicitConvTo(Type to)
+	{
+		//printf("TypeClass.implicitConvTo(to = '%s') %s\n", to.toChars(), toChars());
+		MATCH m = constConv(to);
+		if (m != MATCH.MATCHnomatch)
+			return m;
+
+		ClassDeclaration cdto = to.isClassHandle();
+		if (cdto && cdto.isBaseOf(sym, null))
+		{	
+			//printf("'to' is base\n");
+			return MATCH.MATCHconvert;
+		}
+
+		if (global.params.Dversion == 1)
+		{
+			// Allow conversion to (void *)
+			if (to.ty == TY.Tpointer && (cast(TypePointer)to).next.ty == TY.Tvoid)
+				return MATCH.MATCHconvert;
+		}
+
+		m = MATCH.MATCHnomatch;
+		if (sym.aliasthis)
+		{
+			Declaration d = sym.aliasthis.isDeclaration();
+			if (d)
+			{   
+				assert(d.type);
+				Type t = d.type.addMod(mod);
+				m = t.implicitConvTo(to);
+			}
+		}
+
+		return m;
+	}
+	
+    Expression defaultInit(Loc loc)
+	{
+version (LOGDEFAULTINIT) {
+		printf("TypeClass::defaultInit() '%s'\n", toChars());
+}
+		Expression e = new NullExp(loc);
+		e.type = this;
+		return e;
+	}
+	
+    bool isZeroInit(Loc loc)
+	{
+		return true;
+	}
+	
+    MATCH deduceType(Scope sc, Type tparam, TemplateParameters parameters, Objects dedtypes)
+	{
+		assert(false);
+	}
+	
+    bool isauto()
+	{
+		return sym.isauto;
+	}
+	
+    bool checkBoolean()
+	{
+		return true;
+	}
+	
+    TypeInfoDeclaration getTypeInfoDeclaration()
+	{
+		if (sym.isInterfaceDeclaration())
+			return new TypeInfoInterfaceDeclaration(this);
+		else
+			return new TypeInfoClassDeclaration(this);
+	}
+	
+    bool hasPointers()
+	{
+		return true;
+	}
+	
+    bool builtinTypeInfo()
+	{
+		/* This is statically put out with the ClassInfo, so
+		 * claim it is built in so it isn't regenerated by each module.
+		 */
+	version (DMDV2) {
+		return mod ? false : true;
+	} else {
+		return true;
+	}
+	}
+	
+version (DMDV2) {
+    Type toHeadMutable()
+	{
+		assert(false);
+	}
+	
+    MATCH constConv(Type to)
+	{
+		if (equals(to))
+			return MATCH.MATCHexact;
+
+		if (ty == to.ty && sym == (cast(TypeClass)to).sym && to.mod == MOD.MODconst)
+			return MATCH.MATCHconst;
+
+		return MATCH.MATCHnomatch;
+	}
+	
+version (CPP_MANGLE) {
+    void toCppMangle(OutBuffer buf, CppMangleState* cms)
+	{
+		assert(false);
+	}
+}
+}
+
+    type* toCtype()
+	{
+		type* t;
+		Symbol* s;
+
+		//printf("TypeClass.toCtype() %s\n", toChars());
+		if (ctype)
+			return ctype;
+
+		/* Need this symbol to do C++ name mangling
+		 */
+		string name = sym.isCPPinterface() ? sym.ident.toChars() : sym.toPrettyChars();
+		s = symbol_calloc(toStringz(name));
+		s.Sclass = SC.SCstruct;
+		s.Sstruct = struct_calloc();
+		s.Sstruct.Sflags |= STR.STRclass;
+		s.Sstruct.Salignsize = sym.alignsize;
+		s.Sstruct.Sstructalign = cast(ubyte)sym.structalign;
+		s.Sstruct.Sstructsize = sym.structsize;
+
+		t = type_alloc(TYM.TYstruct);
+		t.Ttag = cast(Classsym*)s;		// structure tag name
+		t.Tcount++;
+		s.Stype = t;
+		slist_add(s);
+
+		t = type_allocn(TYM.TYnptr, t);
+
+		t.Tcount++;
+		ctype = t;
+
+		/* Add in fields of the class
+		 * (after setting ctype to avoid infinite recursion)
+		 */
+		if (global.params.symdebug)
+			for (int i = 0; i < sym.fields.dim; i++)
+			{   
+				VarDeclaration v = cast(VarDeclaration)sym.fields.data[i];
+
+				Symbol* s2 = symbol_name(toStringz(v.ident.toChars()), SC.SCmember, v.type.toCtype());
+				s2.Smemoff = v.offset;
+				list_append(&s.Sstruct.Sfldlst, s2);
+			}
+
+		return t;
+	}
+	
+    Symbol* toSymbol()
+	{
+		return sym.toSymbol();
+	}
+}
\ No newline at end of file