view dmd/StructInitializer.d @ 56:51605de93870

TupleExp.optimize UnrolledLoopStatement.ctor UnrolledLoopStatement.semantic UnrolledLoopStatement.blockExit OrOrExp.checkSideEffect FuncExp.syntaxCopy FuncLiteralDeclaration.syntaxCopy WhileStatement.hasBreak StructInitializer.toExpression StructLiteralExp.ctor StructLiteralExp.optimize BinExp.commonSemanticAssign ModAssignExp.opId Argument.isLazyArray CommaExp.implicitConvTo CommaExp.castTo TypeClass.isBaseOf createTypeInfoArray TypeTuple.getTypeInfoDeclaration TypeInfoTupleDeclaration.ctor TypeNext.constConv XorExp.implicitConvTo TemplateParameter.isTemplateValueParameter
author korDen
date Sat, 21 Aug 2010 14:16:53 +0400
parents b7d29f613539
children f708f0452e81
line wrap: on
line source

module dmd.StructInitializer;

import dmd.Initializer;
import dmd.TOK;
import dmd.FuncLiteralDeclaration;
import dmd.TypeFunction;
import dmd.StructDeclaration;
import dmd.StructLiteralExp;
import dmd.ArrayTypes;
import dmd.Array;
import dmd.Loc;
import dmd.Type;
import dmd.Scope;
import dmd.Identifier;
import dmd.CompoundStatement;
import dmd.AggregateDeclaration;
import dmd.OutBuffer;
import dmd.HdrGenState;
import dmd.Expression;
import dmd.TypeStruct;
import dmd.TY;
import dmd.VarDeclaration;
import dmd.Dsymbol;
import dmd.Util;
import dmd.ExpInitializer;
import dmd.FuncExp;
import dmd.LINK;

import dmd.backend.dt_t;

class StructInitializer : Initializer
{
    Identifiers field;	// of Identifier *'s
    Initializers value;	// parallel array of Initializer *'s

    Array vars;		// parallel array of VarDeclaration *'s
    AggregateDeclaration ad;	// which aggregate this is for

    this(Loc loc)
	{
		super(loc);
		ad = null;
		
		field = new Identifiers();
		value = new Initializers();
		
		vars = new Array();
	}
	
    Initializer syntaxCopy()
	{
		StructInitializer ai = new StructInitializer(loc);

		assert(field.dim == value.dim);
		ai.field.setDim(field.dim);
		ai.value.setDim(value.dim);
		for (int i = 0; i < field.dim; i++)
		{    
			ai.field.data[i] = field.data[i];

			Initializer init = cast(Initializer)value.data[i];
			init = init.syntaxCopy();
			ai.value.data[i] = cast(void*)init;
		}

		return ai;
	}
	
    void addInit(Identifier field, Initializer value)
	{
		//printf("StructInitializer.addInit(field = %p, value = %p)\n", field, value);
		this.field.push(cast(void*)field);
		this.value.push(cast(void*)value);
	}
	
    Initializer semantic(Scope sc, Type t)
	{
		TypeStruct ts;
		int errors = 0;

		//printf("StructInitializer.semantic(t = %s) %s\n", t.toChars(), toChars());
		vars.setDim(field.dim);
		t = t.toBasetype();
		if (t.ty == Tstruct)
		{	
			uint i;
			uint fieldi = 0;

			ts = cast(TypeStruct)t;
			ad = ts.sym;
			for (i = 0; i < field.dim; i++)
			{
				Identifier id = cast(Identifier)field.data[i];
				Initializer val = cast(Initializer)value.data[i];
				Dsymbol s;
				VarDeclaration v;

				if (id is null)
				{
					if (fieldi >= ad.fields.dim)
					{   
						error(loc, "too many initializers for %s", ad.toChars());
						field.remove(i);
						i--;
						continue;
					}
					else
					{
						s = cast(Dsymbol)ad.fields.data[fieldi];
					}
				}
				else
				{
					//s = ad.symtab.lookup(id);
					s = ad.search(loc, id, 0);
					if (!s)
					{
						error(loc, "'%s' is not a member of '%s'", id.toChars(), t.toChars());
						continue;
					}

					// Find out which field index it is
					for (fieldi = 0; 1; fieldi++)
					{
						if (fieldi >= ad.fields.dim)
						{
							s.error("is not a per-instance initializable field");
							break;
						}
						if (s == cast(Dsymbol)ad.fields.data[fieldi])
							break;
					}
				}
				if (s && (v = s.isVarDeclaration()) !is null)
				{
					val = val.semantic(sc, v.type);
					value.data[i] = cast(void*)val;
					vars.data[i] = cast(void*)v;
				}
				else
				{
					error(loc, "%s is not a field of %s", id ? id.toChars() : s.toChars(), ad.toChars());
					errors = 1;
				}
				fieldi++;
			}
		}
		else if (t.ty == Tdelegate && value.dim == 0)
		{	
			/* Rewrite as empty delegate literal { }
			 */
			Arguments arguments = new Arguments;
			Type tf = new TypeFunction(arguments, null, 0, LINK.LINKd);
			FuncLiteralDeclaration fd = new FuncLiteralDeclaration(loc, Loc(0), tf, TOK.TOKdelegate, null);
			fd.fbody = new CompoundStatement(loc, new Statements());
			fd.endloc = loc;
			Expression e = new FuncExp(loc, fd);
			ExpInitializer ie = new ExpInitializer(loc, e);
			return ie.semantic(sc, t);
		}
		else
		{
			error(loc, "a struct is not a valid initializer for a %s", t.toChars());
			errors = 1;
		}
		if (errors)
		{
			field.setDim(0);
			value.setDim(0);
			vars.setDim(0);
		}
		return this;
	}
	
	/***************************************
	 * This works by transforming a struct initializer into
	 * a struct literal. In the future, the two should be the
	 * same thing.
	 */
    Expression toExpression()
	{
		Expression e;

		//printf("StructInitializer.toExpression() %s\n", toChars());
		if (!ad)				// if fwd referenced
		{
			return null;
		}
		StructDeclaration sd = ad.isStructDeclaration();
		if (!sd)
			return null;
		Expressions elements = new Expressions();
		for (size_t i = 0; i < value.dim; i++)
		{
			if (field.data[i])
				goto Lno;
			Initializer iz = cast(Initializer)value.data[i];
			if (!iz)
				goto Lno;
			Expression ex = iz.toExpression();
			if (!ex)
				goto Lno;
			elements.push(cast(void*)ex);
		}
		e = new StructLiteralExp(loc, sd, elements);
		e.type = sd.type;
		return e;

	Lno:
		delete elements;
		//error(loc, "struct initializers as expressions are not allowed");
		return null;
	}
	
    void toCBuffer(OutBuffer buf, HdrGenState* hgs)
	{
		assert(false);
	}

    dt_t* toDt()
	{
		assert(false);
	}

    StructInitializer isStructInitializer() { return this; }
}