view dmd/TemplateMixin.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 96c0fff6897d
children b0d41ff5e0df
line wrap: on
line source

module dmd.TemplateMixin;

import dmd.common;
import dmd.TemplateInstance;
import dmd.Array;
import dmd.Type;
import dmd.ArrayTypes;
import dmd.Loc;
import dmd.Identifier;
import dmd.Dsymbol;
import dmd.Scope;
import dmd.OutBuffer;
import dmd.HdrGenState;
import dmd.DYNCAST;
import dmd.AggregateDeclaration;
import dmd.TemplateDeclaration;
import dmd.Expression;
import dmd.DsymbolTable;
import dmd.PROT;
import dmd.ScopeDsymbol;
import dmd.Global;
import dmd.Util;

extern(C++) void util_progress();

class TemplateMixin : TemplateInstance
{
	Array idents;
	Type tqual;

	this(Loc loc, Identifier ident, Type tqual, Array idents, Objects tiargs)
	{
		register();
		super(loc, cast(Identifier)idents.data[idents.dim - 1]);
		//printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
		this.ident = ident;
		this.tqual = tqual;
		this.idents = idents;
		this.tiargs = tiargs ? tiargs : new Objects();
	}

	override Dsymbol syntaxCopy(Dsymbol s)
	{
		TemplateMixin tm;

		Array ids = new Array();
		ids.setDim(idents.dim);
		for (int i = 0; i < idents.dim; i++)
		{	// Matches TypeQualified.syntaxCopyHelper()
			Identifier id = cast(Identifier)idents.data[i];
			if (id.dyncast() == DYNCAST.DYNCAST_DSYMBOL)
			{
				TemplateInstance ti = cast(TemplateInstance)id;

				ti = cast(TemplateInstance)ti.syntaxCopy(null);
				id = cast(Identifier)ti;
			}
			ids.data[i] = cast(void*)id;
		}

		tm = new TemplateMixin(loc, ident,
				cast(Type)(tqual ? tqual.syntaxCopy() : null),
				ids, tiargs);
		TemplateInstance.syntaxCopy(tm);
		return tm;
	}

	override void semantic(Scope sc)
	{
		version (LOG)
		{
			printf("+TemplateMixin.semantic('%s', this=%p)\n", toChars(), this);
			fflush(stdout);
		}
		if (semanticRun)
		{
			// This for when a class/struct contains mixin members, and
			// is done over because of forward references
			if (parent && toParent().isAggregateDeclaration())
				semanticRun = 1;		// do over
			else
			{
version (LOG)
{
				writef("\tsemantic done\n");
}
				return;
			}
		}
		if (!semanticRun)
			semanticRun = 1;
		version (LOG) {
			printf("\tdo semantic\n");
		}
		util_progress();

		Scope scx = null;
		if (scope_)
		{	sc = scope_;
			scx = scope_;		// save so we don't make redundant copies
			scope_ = null;
		}

		// Follow qualifications to find the TemplateDeclaration
		if (!tempdecl)
		{	Dsymbol s;
			int i;
			Identifier id;

			if (tqual)
			{   s = tqual.toDsymbol(sc);
				i = 0;
			}
			else
			{
				i = 1;
				id = cast(Identifier)idents.data[0];
				switch (id.dyncast())
				{
					case DYNCAST.DYNCAST_IDENTIFIER:
						s = sc.search(loc, id, null);
						break;

					case DYNCAST.DYNCAST_DSYMBOL:
						{
							TemplateInstance ti = cast(TemplateInstance)id;
							ti.semantic(sc);
							s = ti;
							break;
						}
					default:
						assert(0);
				}
			}

			for (; i < idents.dim; i++)
			{
				if (!s)
					break;
				id = cast(Identifier)idents.data[i];
				s = s.searchX(loc, sc, id);
			}
			if (!s)
			{
				error("is not defined");
				inst = this;
				return;
			}
			tempdecl = s.toAlias().isTemplateDeclaration();
			if (!tempdecl)
			{
				error("%s isn't a template", s.toChars());
				inst = this;
				return;
			}
		}

		// Look for forward reference
		assert(tempdecl);
		for (TemplateDeclaration td = tempdecl; td; td = td.overnext)
		{
			if (!td.semanticRun)
			{
				/* Cannot handle forward references if mixin is a struct member,
				 * because addField must happen during struct's semantic, not
				 * during the mixin semantic.
				 * runDeferred will re-run mixin's semantic outside of the struct's
				 * semantic.
				 */
				semanticRun = 0;
				AggregateDeclaration ad = toParent().isAggregateDeclaration();
				if (ad)
					ad.sizeok = 2;
				else
				{
					// Forward reference
					//printf("forward reference - deferring\n");
					scope_ = scx ? scx : sc.clone();
					scope_.setNoFree();
					scope_.module_.addDeferredSemantic(this);
				}
				return;
			}
		}

		// Run semantic on each argument, place results in tiargs[]
		semanticTiargs(sc);
		if (errors)
			return;

		tempdecl = findBestMatch(sc);
		if (!tempdecl)
		{	inst = this;
			return;		// error recovery
		}

		if (!ident)
			ident = genIdent();

		inst = this;
		parent = sc.parent;

		/* Detect recursive mixin instantiations.
		 */
		for (Dsymbol s = parent; s; s = s.parent)
		{
			//printf("\ts = '%s'\n", s.toChars());
			TemplateMixin tm = s.isTemplateMixin();
			if (!tm || tempdecl != tm.tempdecl)
				continue;

			/* Different argument list lengths happen with variadic args
			 */
			if (tiargs.dim != tm.tiargs.dim)
				continue;

			foreach (size_t i, Object o; tiargs)
			{
				Type ta = isType(o);
				Expression ea = isExpression(o);
				Dsymbol sa = isDsymbol(o);
				Object tmo = tm.tiargs[i];
				if (ta)
				{
					Type tmta = isType(tmo);
					if (!tmta)
						goto Lcontinue;
					if (!ta.equals(tmta))
						goto Lcontinue;
				}
				else if (ea)
				{	Expression tme = isExpression(tmo);
					if (!tme || !ea.equals(tme))
						goto Lcontinue;
				}
				else if (sa)
				{
					Dsymbol tmsa = isDsymbol(tmo);
					if (sa != tmsa)
						goto Lcontinue;
				}
				else
					assert(0);
			}
			error("recursive mixin instantiation");
			return;

Lcontinue:
			continue;
		}


		// Copy the syntax trees from the TemplateDeclaration
		members = Dsymbol.arraySyntaxCopy(tempdecl.members);
		if (!members)
			return;

		symtab = new DsymbolTable();

		for (Scope sce = sc; 1; sce = sce.enclosing)
		{
			ScopeDsymbol sds = cast(ScopeDsymbol)sce.scopesym;
			if (sds)
			{
				sds.importScope(this, PROT.PROTpublic);
				break;
			}
		}

		version (LOG) {
			printf("\tcreate scope for template parameters '%s'\n", toChars());
		}
		Scope scy = sc;
		scy = sc.push(this);
		scy.parent = this;

		argsym = new ScopeDsymbol();
		argsym.parent = scy.parent;
		Scope argscope = scy.push(argsym);

		uint errorsave = global.errors;

		// Declare each template parameter as an alias for the argument type
		declareParameters(argscope);

		// Add members to enclosing scope, as well as this scope
		foreach(size_t i, Dsymbol s; members)
		{
			s.addMember(argscope, this, cast(bool)i);
			//sc.insert(s);
			//printf("sc.parent = %p, sc.scopesym = %p\n", sc.parent, sc.scopesym);
			//printf("s.parent = %s\n", s.parent.toChars());
		}

		// Do semantic() analysis on template instance members
		version (LOG) {
			printf("\tdo semantic() on template instance members '%s'\n", toChars());
		}
		Scope sc2;
		sc2 = argscope.push(this);
		sc2.offset = sc.offset;

		//printf("%d\n", global.nest);
		if (++global.nest > 500)
		{
			global.gag = 0;			// ensure error message gets printed
			error("recursive expansion");
			fatal();
		}

		foreach(Dsymbol s; members)
			s.semantic(sc2);

		global.nest--;

		sc.offset = sc2.offset;

		/* The problem is when to parse the initializer for a variable.
		 * Perhaps VarDeclaration.semantic() should do it like it does
		 * for initializers inside a function.
		 */
		//    if (sc.parent.isFuncDeclaration())

		semantic2(sc2);

		if (sc.func)
		{
			semantic3(sc2);
		}

		// Give additional context info if error occurred during instantiation
		if (global.errors != errorsave)
		{
			error("error instantiating");
		}

		sc2.pop();

		argscope.pop();

		//    if (!isAnonymous())
		{
			scy.pop();
		}
		version (LOG) {
			printf("-TemplateMixin.semantic('%s', this=%p)\n", toChars(), this);
		}
	}

	override void semantic2(Scope sc)
	{
		if (semanticRun >= 2)
			return;
		semanticRun = 2;
		version (LOG) {
			printf("+TemplateMixin.semantic2('%s')\n", toChars());
		}
		if (members)
		{
			assert(sc);
			sc = sc.push(argsym);
			sc = sc.push(this);
			foreach(Dsymbol s; members)
			{
				version (LOG) {
					printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
				}
				s.semantic2(sc);
			}
			sc = sc.pop();
			sc.pop();
		}
		version (LOG) {
			printf("-TemplateMixin.semantic2('%s')\n", toChars());
		}
	}

	override void semantic3(Scope sc)
	{
		if (semanticRun >= 3)
			return;
		semanticRun = 3;
		version (LOG) {
			printf("TemplateMixin.semantic3('%s')\n", toChars());
		}
		if (members)
		{
			sc = sc.push(argsym);
			sc = sc.push(this);
			foreach(Dsymbol s; members)
				s.semantic3(sc);
			sc = sc.pop();
			sc.pop();
		}
	}

	override void inlineScan()
	{
		TemplateInstance.inlineScan();
	}

	override string kind()
	{
		return "mixin";
	}

	override bool oneMember(Dsymbol* ps)
	{
		return Dsymbol.oneMember(ps);
	}

	override bool hasPointers()
	{
		//printf("TemplateMixin.hasPointers() %s\n", toChars());
		foreach(Dsymbol s; members)
		{
			//printf(" s = %s %s\n", s.kind(), s.toChars());
			if (s.hasPointers())
			{
				return 1;
			}
		}
		return 0;
	}

	override string toChars()
	{
		OutBuffer buf = new OutBuffer();
		HdrGenState hgs;
		string s;

		TemplateInstance.toCBuffer(buf, &hgs);
		s = buf.toChars();
		buf.data = null;
		return s;
	}

	override void toCBuffer(OutBuffer buf, HdrGenState* hgs)
	{
		buf.writestring("mixin ");

		for (int i = 0; i < idents.dim; i++)
		{   Identifier id = cast(Identifier)idents.data[i];

			if (i)
				buf.writeByte('.');
			buf.writestring(id.toChars());
		}
		buf.writestring("!(");
		if (tiargs)
		{
			for (int i = 0; i < tiargs.dim; i++)
			{   if (i)
				buf.writebyte(',');
				Object oarg = tiargs[i];
				Type t = isType(oarg);
				Expression e = isExpression(oarg);
				Dsymbol s = isDsymbol(oarg);
				if (t)
					t.toCBuffer(buf, null, hgs);
				else if (e)
					e.toCBuffer(buf, hgs);
				else if (s)
				{
					string p = s.ident ? s.ident.toChars() : s.toChars();
					buf.writestring(p);
				}
				else if (!oarg)
				{
					buf.writestring("null");
				}
				else
				{
					assert(0);
				}
			}
		}
		buf.writebyte(')');
		if (ident)
		{
			buf.writebyte(' ');
			buf.writestring(ident.toChars());
		}
		buf.writebyte(';');
		buf.writenl();
	}

	override void toObjFile(int multiobj)			// compile to .obj file
	{
		//printf("TemplateMixin.toObjFile('%s')\n", toChars());
		TemplateInstance.toObjFile(multiobj);
	}

	override TemplateMixin isTemplateMixin() { return this; }
}