view dmd/TraitsExp.d @ 178:e3afd1303184

Many small bugs fixed Made all classes derive from TObject to detect memory leaks (functionality is disabled for now) Began work on overriding backend memory allocations (to avoid memory leaks)
author korDen
date Sun, 17 Oct 2010 07:42:00 +0400
parents 80f4806ffa13
children cd48cb899aee
line wrap: on
line source

module dmd.TraitsExp;

import dmd.common;
import dmd.Expression;
import dmd.Identifier;
import dmd.ArrayTypes;
import dmd.OutBuffer;
import dmd.Loc;
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.Declaration;
import dmd.Util;
import dmd.expression.Util;

import core.stdc.string : strcmp;

/************************************************
 * Delegate to be passed to overloadApply() that looks
 * for virtual functions.
 */

struct Pvirtuals
{
	Expression e1;
	Expressions exps;
	
	bool visit(FuncDeclaration f)
	{
		Pvirtuals* p = &this;

		if (f.isVirtual())
		{	
			Expression e;

			if (p.e1.op == 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(e);
		}
		return false;
	}
}



class TraitsExp : Expression
{
	Identifier ident;

	Objects args;

	this(Loc loc, Identifier ident, Objects args)
	{
		register();
		super(loc, TOK.TOKtraits, this.sizeof);
		this.ident = ident;
		this.args = args;
	}

	override Expression syntaxCopy()
	{
		return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
	}

	override 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;
        Declaration d;
		FuncDeclaration f;

		string ISTYPE(string cond)
		{
			return `
				for (size_t i = 0; i < dim; i++)
				{   Type t = getType(args[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(args[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()}));
		}
//version(DMDV2) {
        else if (ident == Id.isRef)
        {
	        mixin(ISDSYMBOL(q{(d = s.isDeclaration()) !is null && d.isRef()}));
        }
        else if (ident == Id.isOut)
        {
            mixin(ISDSYMBOL(q{(d = s.isDeclaration()) !is null && d.isOut()}));
        }
        else if (ident == Id.isLazy)
        {
	        mixin(ISDSYMBOL(q{(d = s.isDeclaration()) !is null && d.storage_class & STClazy}));
        }
//}
		else if (ident == Id.hasMember ||
				ident == Id.getMember ||
				ident == Id.getVirtualFunctions)
		{
			if (dim != 2)
				goto Ldimerror;
			auto o_ = args[0];
			Expression e = isExpression(args[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;
			}
			auto 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);

				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_ = args[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_ = args[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++)
						{   auto se2 = cast(StringExp)exps[j];
							if (strcmp(toStringz(str), cast(char*)se2.string_) == 0)
								goto Lnext;
						}

						auto se = new StringExp(loc, str);
						exps.push(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_ = args[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 = args[0];
			Object o2 = args[1];
			Dsymbol s1 = getDsymbol(o1);
			Dsymbol s2 = getDsymbol(o2);

			// writef("isSame: %s, %s\n", o1.toChars(), o2.toChars());
			static if (0)
			{
				writef("o1: %p\n", o1);
				writef("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);
	}

	override 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 = args[i];
				ObjectToCBuffer(buf, hgs, oarg);
			}
		}
		buf.writeByte(')');
	}
}