diff dmd/TraitsExp.d @ 17:ddae60498573

Implemented mixin statements, DefaultInitExps, FileInitExps, LineInitExps and __traits.
author Robert Clipsham <robert@octarineparrot.com>
date Mon, 05 Apr 2010 03:24:08 +0100
parents 10317f0c89a5
children 460959608115
line wrap: on
line diff
--- a/dmd/TraitsExp.d	Sun Apr 04 22:41:11 2010 +0100
+++ b/dmd/TraitsExp.d	Mon Apr 05 03:24:08 2010 +0100
@@ -8,32 +8,448 @@
 import dmd.Scope;
 import dmd.HdrGenState;
 import dmd.TOK;
+import dmd.TY;
+import dmd.STC;
+import dmd.WANT;
+import dmd.Id;
+import dmd.Global;
+import dmd.Lexer;
+import dmd.ArrayLiteralExp;
+import dmd.VarExp;
+import dmd.StringExp;
+import dmd.DotIdExp;
+import dmd.DotVarExp;
+import dmd.IntegerExp;
+import dmd.TupleExp;
+import dmd.Type;
+import dmd.Dsymbol;
+import dmd.DsymbolExp;
+import dmd.ScopeDsymbol;
+import dmd.FuncDeclaration;
+import dmd.ClassDeclaration;
+import dmd.TemplateDeclaration;
+import dmd.TemplateInstance;
+import dmd.TypeClass;
+import dmd.Util;
+import dmd.expression.Util;
 
-class TraitsExp : Expression
-{
-	Identifier ident;
-
-	Objects args;
-
-	this(Loc loc, Identifier ident, Objects args)
-	{
-		assert(false);
-		super(loc, TOK.init, 0);
-	}
-
-	Expression syntaxCopy()
-	{
-		assert(false);
-	}
-
-	Expression semantic(Scope sc)
-	{
-		assert(false);
-	}
-
-	void toCBuffer(OutBuffer buf, HdrGenState* hgs)
-	{
-		assert(false);
-	}
-}
-
+import core.stdc.string : strcmp;
+
+/************************************************
+ * Delegate to be passed to overloadApply() that looks
+ * for virtual functions.
+ */
+
+struct Pvirtuals
+{
+	Expression e1;
+	Expressions exps;
+	int fpvirtuals(void* param, FuncDeclaration f)
+	{   Pvirtuals p = *cast(Pvirtuals*)param;
+
+		if (f.isVirtual())
+		{	Expression e;
+
+			if (p.e1.op == TOK.TOKdotvar)
+			{   DotVarExp dve = cast(DotVarExp)p.e1;
+				e = new DotVarExp(Loc(0), dve.e1, f);
+			}
+			else
+				e = new DsymbolExp(Loc(0), f);
+			p.exps.push(cast(void*)e);
+		}
+		return 0;
+	}
+}
+
+
+
+class TraitsExp : Expression
+{
+	Identifier ident;
+
+	Objects args;
+
+	this(Loc loc, Identifier ident, Objects args)
+	{
+		super(loc, TOK.TOKtraits, this.sizeof);
+		this.ident = ident;
+		this.args = args;
+	}
+
+	Expression syntaxCopy()
+	{
+		return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
+	}
+
+	Expression semantic(Scope sc)
+	{
+		version (LOGSEMANTIC) {
+			printf("TraitsExp.semantic() %s\n", toChars());
+		}
+		if (ident != Id.compiles && ident != Id.isSame)
+			TemplateInstance.semanticTiargs(loc, sc, args, 1);
+		size_t dim = args ? args.dim : 0;
+		Object o;
+		FuncDeclaration f;
+
+		string ISTYPE(string cond)
+		{
+			return `
+				for (size_t i = 0; i < dim; i++)
+				{   Type t = getType(cast(Object)args.data[i]);
+					if (!t)
+						goto Lfalse;
+					if (!(`~cond~`))
+						goto Lfalse;
+				}
+			if (!dim)
+				goto Lfalse;
+			goto Ltrue;
+			`;
+		}
+
+		string ISDSYMBOL(string cond)
+		{
+			return `for (size_t i = 0; i < dim; i++)
+			{   Dsymbol s = getDsymbol(cast(Object)args.data[i]);
+				if (!s)
+					goto Lfalse;
+				if (!(`~cond~`))
+					goto Lfalse;
+			}
+			if (!dim)
+				goto Lfalse;
+			goto Ltrue;`;
+		}
+
+		if (ident == Id.isArithmetic)
+		{
+			mixin(ISTYPE(`t.isintegral() || t.isfloating()`));
+		}
+		else if (ident == Id.isFloating)
+		{
+			mixin(ISTYPE(q{t.isfloating()}));
+		}
+		else if (ident == Id.isIntegral)
+		{
+			mixin(ISTYPE(q{t.isintegral()}));
+		}
+		else if (ident == Id.isScalar)
+		{
+			mixin(ISTYPE(q{t.isscalar()}));
+		}
+		else if (ident == Id.isUnsigned)
+		{
+			mixin(ISTYPE(q{t.isunsigned()}));
+		}
+		else if (ident == Id.isAssociativeArray)
+		{
+			mixin(ISTYPE(q{t.toBasetype().ty == TY.Taarray}));
+		}
+		else if (ident == Id.isStaticArray)
+		{
+			mixin(ISTYPE(q{t.toBasetype().ty == TY.Tsarray}));
+		}
+		else if (ident == Id.isAbstractClass)
+		{
+			mixin(ISTYPE(q{t.toBasetype().ty == TY.Tclass && (cast(TypeClass)t.toBasetype()).sym.isAbstract()}));
+		}
+		else if (ident == Id.isFinalClass)
+		{
+			mixin(ISTYPE(q{t.toBasetype().ty == TY.Tclass && (cast(TypeClass)t.toBasetype()).sym.storage_class & STC.STCfinal}));
+		}
+		else if (ident == Id.isAbstractFunction)
+		{
+			mixin(ISDSYMBOL(q{(f = s.isFuncDeclaration()) !is null && f.isAbstract()}));
+		}
+		else if (ident == Id.isVirtualFunction)
+		{
+			mixin(ISDSYMBOL(q{(f = s.isFuncDeclaration()) !is null && f.isVirtual()}));
+		}
+		else if (ident == Id.isFinalFunction)
+		{
+			mixin(ISDSYMBOL(q{(f = s.isFuncDeclaration()) !is null && f.isFinal()}));
+		}
+		else if (ident == Id.hasMember ||
+				ident == Id.getMember ||
+				ident == Id.getVirtualFunctions)
+		{
+			if (dim != 2)
+				goto Ldimerror;
+			Object o_ = cast(Object)args.data[0];
+			Expression e = isExpression(cast(Object)args.data[1]);
+			if (!e)
+			{   error("expression expected as second argument of __traits %s", ident.toChars());
+				goto Lfalse;
+			}
+			e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret);
+			if (e.op != TOKstring)
+			{   error("string expected as second argument of __traits %s instead of %s", ident.toChars(), e.toChars());
+				goto Lfalse;
+			}
+			StringExp se = cast(StringExp)e;
+			se = se.toUTF8(sc);
+			if (se.sz != 1)
+			{   error("string must be chars");
+				goto Lfalse;
+			}
+			Identifier id = Lexer.idPool(fromStringz(cast(char*)se.string_));
+
+			Type t = isType(o_);
+			e = isExpression(o_);
+			Dsymbol s = isDsymbol(o_);
+			if (t)
+				e = typeDotIdExp(loc, t, id);
+			else if (e)
+				e = new DotIdExp(loc, e, id);
+			else if (s)
+			{   e = new DsymbolExp(loc, s);
+				e = new DotIdExp(loc, e, id);
+			}
+			else
+			{   error("invalid first argument");
+				goto Lfalse;
+			}
+
+			if (ident == Id.hasMember)
+			{   /* Take any errors as meaning it wasn't found
+			     */
+				e = e.trySemantic(sc);
+				if (!e)
+				{	if (global.gag)
+					global.errors++;
+					goto Lfalse;
+				}
+				else
+					goto Ltrue;
+			}
+			else if (ident == Id.getMember)
+			{
+				e = e.semantic(sc);
+				return e;
+			}
+			else if (ident == Id.getVirtualFunctions)
+			{
+				uint errors = global.errors;
+				Expression ex = e;
+				e = e.semantic(sc);
+				if (errors < global.errors)
+					error("%s cannot be resolved", ex.toChars());
+
+				/* Create tuple of virtual function overloads of e
+				 */
+				//e.dump(0);
+				Expressions exps = new Expressions();
+				FuncDeclaration f_;
+				if (e.op == TOKvar)
+				{	VarExp ve = cast(VarExp)e;
+					f_ = ve.var.isFuncDeclaration();
+				}
+				else if (e.op == TOKdotvar)
+				{	DotVarExp dve = cast(DotVarExp)e;
+					f_ = dve.var.isFuncDeclaration();
+				}
+				else
+					f_ = null;
+				Pvirtuals p;
+				p.exps = exps;
+				p.e1 = e;
+				overloadApply(f_, &p.fpvirtuals, &p);
+
+				TupleExp tup = new TupleExp(loc, exps);
+				return tup.semantic(sc);
+			}
+			else
+				assert(0);
+		}
+		else if (ident == Id.classInstanceSize)
+		{
+			if (dim != 1)
+				goto Ldimerror;
+			Object o_ = cast(Object)args.data[0];
+			Dsymbol s = getDsymbol(o_);
+			ClassDeclaration cd;
+			if (!s || (cd = s.isClassDeclaration()) is null)
+			{
+				error("first argument is not a class");
+				goto Lfalse;
+			}
+			return new IntegerExp(loc, cd.structsize, Type.tsize_t);
+		}
+		else if (ident == Id.allMembers || ident == Id.derivedMembers)
+		{
+			if (dim != 1)
+				goto Ldimerror;
+			Object o_ = cast(Object)args.data[0];
+			Dsymbol s = getDsymbol(o_);
+			ScopeDsymbol sd;
+			if (!s)
+			{
+				error("argument has no members");
+				goto Lfalse;
+			}
+			if ((sd = s.isScopeDsymbol()) is null)
+			{
+				error("%s %s has no members", s.kind(), s.toChars());
+				goto Lfalse;
+			}
+			Expressions exps = new Expressions;
+			while (1)
+			{   size_t dim_ = ScopeDsymbol.dim(sd.members);
+				for (size_t i = 0; i < dim_; i++)
+				{
+					Dsymbol sm = ScopeDsymbol.getNth(sd.members, i);
+					//printf("\t[%i] %s %s\n", i, sm.kind(), sm.toChars());
+					if (sm.ident)
+					{
+						//printf("\t%s\n", sm.ident.toChars());
+						auto str = sm.ident.toChars();
+
+						/* Skip if already present in exps[]
+						 */
+						for (size_t j = 0; j < exps.dim; j++)
+						{   StringExp se2 = cast(StringExp)exps.data[j];
+							if (strcmp(toStringz(str), cast(char*)se2.string_) == 0)
+								goto Lnext;
+						}
+
+						StringExp se = new StringExp(loc, str);
+						exps.push(cast(void*)se);
+					}
+Lnext:
+					;
+				}
+				ClassDeclaration cd = sd.isClassDeclaration();
+				if (cd && cd.baseClass && ident == Id.allMembers)
+					sd = cd.baseClass;	// do again with base class
+				else
+					break;
+			}
+			Expression e = new ArrayLiteralExp(loc, exps);
+			e = e.semantic(sc);
+			return e;
+		}
+		else if (ident == Id.compiles)
+		{
+			/* Determine if all the objects - types, expressions, or symbols -
+			 * compile without error
+			 */
+			if (!dim)
+				goto Lfalse;
+
+			for (size_t i = 0; i < dim; i++)
+			{   Object o_ = cast(Object)args.data[i];
+				Expression e;
+
+				uint errors = global.errors;
+				global.gag++;
+
+				Type t = isType(o_);
+				if (t)
+				{	Dsymbol s;
+					t.resolve(loc, sc, &e, &t, &s);
+					if (t)
+						t.semantic(loc, sc);
+					else if (e)
+						e.semantic(sc);
+				}
+				else
+				{	e = isExpression(o);
+					if (e)
+						e.semantic(sc);
+				}
+
+				global.gag--;
+				if (errors != global.errors)
+				{   if (global.gag == 0)
+					global.errors = errors;
+					goto Lfalse;
+				}
+			}
+			goto Ltrue;
+		}
+		else if (ident == Id.isSame)
+		{	/* Determine if two symbols are the same
+			 */
+			if (dim != 2)
+				goto Ldimerror;
+			TemplateInstance.semanticTiargs(loc, sc, args, 0);
+			Object o1 = cast(Object)args.data[0];
+			Object o2 = cast(Object)args.data[1];
+			Dsymbol s1 = getDsymbol(o1);
+			Dsymbol s2 = getDsymbol(o2);
+
+			static if (0) {
+				printf("o1: %p\n", o1);
+				printf("o2: %p\n", o2);
+				if (!s1)
+				{   Expression ea = isExpression(o1);
+					if (ea)
+						printf("%s\n", ea.toChars());
+					Type ta = isType(o1);
+					if (ta)
+						printf("%s\n", ta.toChars());
+					goto Lfalse;
+				}
+				else
+					printf("%s %s\n", s1.kind(), s1.toChars());
+			}
+			if (!s1 && !s2)
+			{   Expression ea1 = isExpression(o1);
+				Expression ea2 = isExpression(o2);
+				if (ea1 && ea2 && ea1.equals(ea2))
+					goto Ltrue;
+			}
+
+			if (!s1 || !s2)
+				goto Lfalse;
+
+			s1 = s1.toAlias();
+			s2 = s2.toAlias();
+
+			if (s1 == s2)
+				goto Ltrue;
+			else
+				goto Lfalse;
+		}
+		else
+		{	error("unrecognized trait %s", ident.toChars());
+			goto Lfalse;
+		}
+
+		return null;
+
+Lnottype:
+		error("%s is not a type", o/*.toChars()*/); // BUG: o is Object, no member toChars()
+		goto Lfalse;
+
+Ldimerror:
+		error("wrong number of arguments %d", dim);
+		goto Lfalse;
+
+
+Lfalse:
+		return new IntegerExp(loc, 0, Type.tbool);
+
+Ltrue:
+		return new IntegerExp(loc, 1, Type.tbool);
+	}
+
+	void toCBuffer(OutBuffer buf, HdrGenState* hgs)
+	{
+		buf.writestring("__traits(");
+		buf.writestring(ident.toChars());
+		if (args)
+		{
+			for (int i = 0; i < args.dim; i++)
+			{
+				buf.writeByte(',');
+				Object oarg = cast(Object)args.data[i];
+				ObjectToCBuffer(buf, hgs, oarg);
+			}
+		}
+		buf.writeByte(')');
+	}
+}
+