view dmd/ArrayInitializer.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 10317f0c89a5
children 35afd9294854
line wrap: on
line source

module dmd.ArrayInitializer;

import dmd.ArrayTypes;
import dmd.Type;
import dmd.TypeNext;
import dmd.Array;
import dmd.Loc;
import dmd.Initializer;
import dmd.WANT;
import dmd.Util;
import dmd.TY;
import dmd.TypeSArray;
import dmd.IntegerExp;
import dmd.Expression;
import dmd.ArrayLiteralExp;
import dmd.Scope;
import dmd.ErrorExp;
import dmd.OutBuffer;
import dmd.HdrGenState;

import dmd.backend.dt_t;
import dmd.backend.Util;
import dmd.codegen.Util;
import dmd.backend.TYM;
import dmd.backend.Symbol;

class ArrayInitializer : Initializer
{
    Expressions index;	// indices
    Initializers value;	// of Initializer *'s
    uint dim = 0;		// length of array being initialized
    Type type = null;	// type that array will be used to initialize
    int sem = 0;		// !=0 if semantic() is run

    this(Loc loc)
	{
		super(loc);
		index = new Expressions();
		value = new Initializers();
	}
	
    Initializer syntaxCopy()
	{
		//printf("ArrayInitializer.syntaxCopy()\n");

		ArrayInitializer ai = new ArrayInitializer(loc);

		assert(index.dim == value.dim);
		ai.index.setDim(index.dim);
		ai.value.setDim(value.dim);
		for (int i = 0; i < ai.value.dim; i++)
		{	
			Expression e = cast(Expression)index.data[i];
			if (e)
				e = e.syntaxCopy();
			ai.index.data[i] = cast(void*)e;

			Initializer init = cast(Initializer)value.data[i];
			init = init.syntaxCopy();
			ai.value.data[i] = cast(void*)init;
		}
		return ai;
	}
	
    void addInit(Expression index, Initializer value)
	{
		this.index.push(cast(void*)index);
		this.value.push(cast(void*)value);
		dim = 0;
		type = null;
	}
	
    Initializer semantic(Scope sc, Type t)
	{
		uint i;
		uint length;

		//printf("ArrayInitializer.semantic(%s)\n", t.toChars());
		if (sem)				// if semantic() already run
			return this;

		sem = 1;
		type = t;
		t = t.toBasetype();
		switch (t.ty)
		{
			case Tpointer:
			case Tsarray:
			case Tarray:
				break;

			default:
				error(loc, "cannot use array to initialize %s", type.toChars());
				return this;
		}

		length = 0;
		for (i = 0; i < index.dim; i++)
		{	
			Expression idx;
			Initializer val;

			idx = cast(Expression)index.data[i];
			if (idx)
			{   
				idx = idx.semantic(sc);
				idx = idx.optimize(WANTvalue | WANTinterpret);
				index.data[i] = cast(void*)idx;
				length = cast(uint)idx.toInteger();
			}

			val = cast(Initializer)value.data[i];
			val = val.semantic(sc, t.nextOf());
			value.data[i] = cast(void*)val;
			length++;
			if (length == 0)
				error(loc, "array dimension overflow");
			if (length > dim)
				dim = length;
		}
		uint amax = 0x80000000;
		if (cast(uint) (dim * t.nextOf().size()) >= amax)
			error(loc, "array dimension %u exceeds max of %ju", dim, amax / t.nextOf().size());

		return this;
	}
	
    Type inferType(Scope sc)
	{
		//printf("ArrayInitializer.inferType() %s\n", toChars());
		type = Type.terror;
		for (size_t i = 0; i < value.dim; i++)
		{
			if (index.data[i])
				goto Lno;
		}

		for (size_t i = 0; i < value.dim; i++)
		{
			Initializer iz = cast(Initializer)value.data[i];
			if (iz)
			{   
				Type t = iz.inferType(sc);
				if (i == 0)
				{	
					t = new TypeSArray(t, new IntegerExp(value.dim));
					t = t.semantic(loc, sc);
					type = t;
				}
			}
		}
		return type;

	Lno:
		error(loc, "cannot infer type from this array initializer");
		return Type.terror;
	}

	/********************************
	 * If possible, convert array initializer to array literal.
	 */	
    Expression toExpression()
	{
		Expression e;

		//printf("ArrayInitializer.toExpression(), dim = %d\n", dim);
		//static int i; if (++i == 2) halt();

		size_t edim;
		Type t = null;
		if (type)
		{
			t = type.toBasetype();
			switch (t.ty)
			{
				case Tsarray:
					edim = cast(uint)(cast(TypeSArray)t).dim.toInteger();
					break;

				case Tpointer:
				case Tarray:
					edim = dim;
					break;

				default:
					assert(0);
			}
		}
		else
		{
			edim = value.dim;
			for (size_t i = 0, j = 0; i < value.dim; i++, j++)
			{
				if (index.data[i])
					j = cast(uint)(cast(Expression)index.data[i]).toInteger();
				if (j >= edim)
					edim = j + 1;
			}
		}

		Expressions elements = new Expressions();
		elements.setDim(edim);
		for (size_t i = 0, j = 0; i < value.dim; i++, j++)
		{
			if (index.data[i])
				j = cast(uint)(cast(Expression)index.data[i]).toInteger();
			assert(j < edim);
			Initializer iz = cast(Initializer)value.data[i];
			if (!iz)
				goto Lno;
			Expression ex = iz.toExpression();
			if (!ex)
			{
				goto Lno;
			}
			elements.data[j] = cast(void*)ex;
		}

		/* Fill in any missing elements with the default initializer
		 */
		{
			Expression init = null;
			for (size_t i = 0; i < edim; i++)
			{
				if (!elements.data[i])
				{
					if (!type)
						goto Lno;
					if (!init)
						init = (cast(TypeNext)t).next.defaultInit(Loc(0));
					elements.data[i] = cast(void*)init;
				}
			}

			Expression e2 = new ArrayLiteralExp(loc, elements);
			e2.type = type;
			return e2;
		}

	Lno:
		delete elements;
		error(loc, "array initializers as expressions are not allowed");
		return new ErrorExp();
	}
	
    Initializer toAssocArrayInitializer()
	{
		assert(false);
	}
	
    void toCBuffer(OutBuffer buf, HdrGenState* hgs)
	{
		assert(false);
	}

    dt_t* toDt()
	{
		//printf("ArrayInitializer.toDt('%s')\n", toChars());
		Type tb = type.toBasetype();
		Type tn = tb.nextOf().toBasetype();

		scope Array dts = new Array();
		uint size;
		uint length;
		uint i;
		dt_t* dt;
		dt_t* d;
		dt_t** pdtend;

		//printf("\tdim = %d\n", dim);
		dts.setDim(dim);
		dts.zero();

		size = cast(uint)tn.size();

		length = 0;
		for (i = 0; i < index.dim; i++)
		{
			Expression idx;
			Initializer val;

			idx = cast(Expression)index.data[i];
			if (idx)
				length = cast(uint)idx.toInteger();
			//printf("\tindex[%d] = %p, length = %u, dim = %u\n", i, idx, length, dim);

			assert(length < dim);
			val = cast(Initializer)value.data[i];
			dt = val.toDt();
			if (dts.data[length])
				error(loc, "duplicate initializations for index %d", length);
			dts.data[length] = cast(void*)dt;
			length++;
		}

		Expression edefault = tb.nextOf().defaultInit(Loc(0));

		uint n = 1;
		for (Type tbn = tn; tbn.ty == Tsarray; tbn = tbn.nextOf().toBasetype())
		{	
			TypeSArray tsa = cast(TypeSArray)tbn;
			n *= tsa.dim.toInteger();
		}

		d = null;
		pdtend = &d;
		for (i = 0; i < dim; i++)
		{
			dt = cast(dt_t*)dts.data[i];
			if (dt)
				pdtend = dtcat(pdtend, dt);
			else
			{
				for (int j = 0; j < n; j++)
					pdtend = edefault.toDt(pdtend);
			}
		}
		switch (tb.ty)
		{
			case Tsarray:
			{   
				uint tadim;
				TypeSArray ta = cast(TypeSArray)tb;

				tadim = cast(uint)ta.dim.toInteger();
				if (dim < tadim)
				{
					if (edefault.isBool(false))
						// pad out end of array
						pdtend = dtnzeros(pdtend, size * (tadim - dim));
					else
					{
						for (i = dim; i < tadim; i++)
						{	
							for (int j = 0; j < n; j++)
								pdtend = edefault.toDt(pdtend);
						}
					}
				}
				else if (dim > tadim)
				{
					debug writef("1: ");
					assert(false);
					error(loc, "too many initializers, %d, for array[%d]", dim, tadim);
				}
				break;
			}

			case Tpointer:
			case Tarray:
				// Create symbol, and then refer to it
				Symbol* s = static_sym();
				s.Sdt = d;
				outdata(s);

				d = null;
				if (tb.ty == Tarray)
					dtdword(&d, dim);
				dtxoff(&d, s, 0, TYnptr);
				break;

			default:
				assert(0);
		}
		return d;
	}
	
    dt_t* toDtBit()	// for bit arrays
	{
		assert(false);
	}

    ArrayInitializer isArrayInitializer() { return this; }
}