Mercurial > projects > ddmd
view dmd/StructLiteralExp.d @ 109:ceda59b4d255
expression.c changes, now only ddoc should be left
author | Trass3r |
---|---|
date | Tue, 31 Aug 2010 22:08:52 +0200 |
parents | 39648eb578f6 |
children | e28b18c23469 |
line wrap: on
line source
module dmd.StructLiteralExp; import dmd.Expression; import dmd.MOD; import dmd.TypeStruct; import dmd.TypeSArray; import dmd.expression.Util; import dmd.ErrorExp; import dmd.Dsymbol; import dmd.VarDeclaration; import dmd.StructDeclaration; import dmd.FuncDeclaration; import dmd.ThisDeclaration; import dmd.backend.elem; import dmd.InterState; import dmd.MATCH; import dmd.WANT; import dmd.TY; import dmd.Type; import dmd.OutBuffer; import dmd.Loc; import dmd.Scope; import dmd.Initializer; import dmd.InlineCostState; import dmd.IRState; import dmd.InlineDoState; import dmd.backend.Symbol; import dmd.HdrGenState; import dmd.backend.dt_t; import dmd.InlineScanState; import dmd.ArrayLiteralExp; import dmd.ArrayTypes; import dmd.TOK; import dmd.codegen.Util; import dmd.backend.Util; import dmd.backend.RTLSYM; import dmd.backend.TYM; import dmd.backend.mTY; import dmd.backend.OPER; class StructLiteralExp : Expression { StructDeclaration sd; // which aggregate this is for Expressions elements; // parallels sd.fields[] with // NULL entries for fields to skip Symbol* sym; // back end symbol to initialize with literal size_t soffset; // offset from start of s int fillHoles; // fill alignment 'holes' with zero this(Loc loc, StructDeclaration sd, Expressions elements) { super(loc, TOKstructliteral, StructLiteralExp.sizeof); this.sd = sd; this.elements = elements; this.sym = null; this.soffset = 0; this.fillHoles = 1; } override Expression syntaxCopy() { assert(false); } override Expression semantic(Scope sc) { Expression e; int nfields = sd.fields.dim - sd.isnested; version (LOGSEMANTIC) { printf("StructLiteralExp.semantic('%s')\n", toChars()); } if (type) return this; // Run semantic() on each element foreach(size_t i, Expression e; elements) { if (!e) continue; e = e.semantic(sc); elements[i] = e; } expandTuples(elements); size_t offset = 0; foreach(size_t i, Expression e; elements) { if (!e) continue; if (!e.type) error("%s has no value", e.toChars()); e = resolveProperties(sc, e); if (i >= nfields) { error("more initializers than fields of %s", sd.toChars()); return new ErrorExp(); } auto s = sd.fields[i]; VarDeclaration v = s.isVarDeclaration(); assert(v); if (v.offset < offset) error("overlapping initialization for %s", v.toChars()); offset = v.offset + cast(uint)v.type.size(); Type telem = v.type; while (!e.implicitConvTo(telem) && telem.toBasetype().ty == Tsarray) { /* Static array initialization, as in: * T[3][5] = e; */ telem = telem.toBasetype().nextOf(); } e = e.implicitCastTo(sc, telem); elements[i] = e; } /* Fill out remainder of elements[] with default initializers for fields[] */ for (size_t i = elements.dim; i < nfields; i++) { VarDeclaration v = sd.fields[i]; assert(v); assert(!v.isThisDeclaration()); if (v.offset < offset) { e = null; sd.hasUnions = 1; } else { if (v.init) { e = v.init.toExpression(); if (!e) { error("cannot make expression out of initializer for %s", v.toChars()); e = new ErrorExp(); } else if (v.scope_) { // Do deferred semantic anaylsis Initializer i2 = v.init.syntaxCopy(); i2 = i2.semantic(v.scope_, v.type); e = i2.toExpression(); v.scope_ = null; } } else { e = v.type.defaultInit(Loc(0)); e.loc = loc; } offset = v.offset + cast(uint)v.type.size(); } elements.push(e); } type = sd.type; return this; } /************************************** * Gets expression at offset of type. * Returns null if not found. */ Expression getField(Type type, uint offset) { //printf("StructLiteralExp.getField(this = %s, type = %s, offset = %u)\n", // /*toChars()*/"", type.toChars(), offset); Expression e = null; int i = getFieldIndex(type, offset); if (i != -1) { //printf("\ti = %d\n", i); assert(i < elements.dim); e = elements[i]; if (e) { //writef("e = %s, e.type = %s\n", e.toChars(), e.type.toChars()); /* If type is a static array, and e is an initializer for that array, * then the field initializer should be an array literal of e. */ if (e.type != type && type.ty == Tsarray) { TypeSArray tsa = cast(TypeSArray)type; size_t length = cast(size_t) tsa.dim.toInteger(); Expressions z = new Expressions; z.setDim(length); for (int q = 0; q < length; ++q) z[q] = e.copy(); e = new ArrayLiteralExp(loc, z); e.type = type; } else { e = e.copy(); e.type = type; } } } return e; } int getFieldIndex(Type type, uint offset) { /* Find which field offset is by looking at the field offsets */ if (elements.dim) { foreach (size_t i, VarDeclaration v; sd.fields) { assert(v); if (offset == v.offset && type.size() == v.type.size()) { auto e = elements[i]; if (e) { return i; } break; } } } return -1; } override elem* toElem(IRState* irs) { elem* e; size_t dim; //printf("StructLiteralExp.toElem() %s\n", toChars()); // struct symbol to initialize with the literal Symbol* stmp = sym ? sym : symbol_genauto(sd.type.toCtype()); e = null; if (fillHoles) { /* Initialize all alignment 'holes' to zero. * Do before initializing fields, as the hole filling process * can spill over into the fields. */ size_t offset = 0; foreach (VarDeclaration v; sd.fields) { assert(v); e = el_combine(e, fillHole(stmp, &offset, v.offset, sd.structsize)); size_t vend = v.offset + cast(uint)v.type.size(); if (offset < vend) offset = vend; } e = el_combine(e, fillHole(stmp, &offset, sd.structsize, sd.structsize)); } if (elements) { dim = elements.dim; assert(dim <= sd.fields.dim); foreach (size_t i, Expression el; elements) { if (!el) continue; VarDeclaration v = sd.fields[i]; assert(v); assert(!v.isThisDeclaration()); elem* e1; if (tybasic(stmp.Stype.Tty) == TYnptr) { e1 = el_var(stmp); e1.EV.sp.Voffset = soffset; } else { e1 = el_ptr(stmp); if (soffset) e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset)); } e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); elem* ec = e1; // pointer to destination elem* ep = el.toElem(irs); Type t1b = v.type.toBasetype(); Type t2b = el.type.toBasetype(); if (t1b.ty == Tsarray) { if (t2b.implicitConvTo(t1b)) { ///version (DMDV2) { // Determine if postblit is needed int postblit = 0; if (needsPostblit(t1b)) postblit = 1; if (postblit) { /* Generate: * _d_arrayctor(ti, From: ep, To: e1) */ Expression ti = t1b.nextOf().toBasetype().getTypeInfo(null); elem* esize = el_long(TYsize_t, (cast(TypeSArray)t1b).dim.toInteger()); e1 = el_pair(TYdarray, esize, e1); ep = el_pair(TYdarray, el_copytree(esize), array_toPtr(el.type, ep)); ep = el_params(e1, ep, ti.toElem(irs), null); int rtl = RTLSYM_ARRAYCTOR; e1 = el_bin(OPcall, type.totym(), el_var(rtlsym[rtl]), ep); } else ///} { elem* esize = el_long(TYsize_t, t1b.size()); ep = array_toPtr(el.type, ep); e1 = el_bin(OPmemcpy, TYnptr, e1, el_param(ep, esize)); } } else { elem* edim = el_long(TYsize_t, t1b.size() / t2b.size()); e1 = setArray(e1, edim, t2b, ep, irs, TOKconstruct); } } else { tym_t ty = v.type.totym(); e1 = el_una(OPind, ty, e1); if (tybasic(ty) == TYstruct) e1.Enumbytes = cast(uint)v.type.size(); e1 = el_bin(OPeq, ty, e1, ep); if (tybasic(ty) == TYstruct) { e1.Eoper = OPstreq; e1.Enumbytes = cast(uint)v.type.size(); } version (DMDV2) { /* Call postblit() on e1 */ StructDeclaration sd = needsPostblit(v.type); if (sd) { FuncDeclaration fd = sd.postblit; ec = el_copytree(ec); ec = callfunc(loc, irs, 1, Type.tvoid, ec, sd.type.pointerTo(), fd, fd.type, null, null); e1 = el_bin(OPcomma, ec.Ety, e1, ec); } } } e = el_combine(e, e1); } } version (DMDV2) { if (sd.isnested) { // Initialize the hidden 'this' pointer assert(sd.fields.dim); auto s = sd.fields[sd.fields.dim - 1]; auto v = s.isThisDeclaration(); assert(v); elem* e1; if (tybasic(stmp.Stype.Tty) == TYnptr) { e1 = el_var(stmp); e1.EV.sp.Voffset = soffset; } else { e1 = el_ptr(stmp); if (soffset) e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset)); } e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); e1 = setEthis(loc, irs, e1, sd); e = el_combine(e, e1); } } elem* ev = el_var(stmp); ev.Enumbytes = sd.structsize; e = el_combine(e, ev); el_setLoc(e,loc); return e; } override bool checkSideEffect(int flag) { bool f = 0; foreach (e; elements) { if (!e) continue; f |= e.checkSideEffect(2); } if (flag == 0 && f == 0) Expression.checkSideEffect(0); return f; } override void toCBuffer(OutBuffer buf, HdrGenState* hgs) { buf.writestring(sd.toChars()); buf.writeByte('('); argsToCBuffer(buf, elements, hgs); buf.writeByte(')'); } override void toMangleBuffer(OutBuffer buf) { size_t dim = elements ? elements.dim : 0; buf.printf("S%u", dim); for (size_t i = 0; i < dim; i++) { auto e = elements[i]; if (e) e.toMangleBuffer(buf); else buf.writeByte('v'); // 'v' for void } } override void scanForNestedRef(Scope sc) { assert(false); } override Expression optimize(int result) { if (elements) { foreach (size_t i, Expression e; elements) { if (!e) continue; e = e.optimize(WANTvalue | (result & WANTinterpret)); elements[i] = e; } } return this; } override Expression interpret(InterState istate) { assert(false); } override dt_t** toDt(dt_t** pdt) { assert(false); } version(DMDV2) { override int isLvalue() { return 1; } } override Expression toLvalue(Scope sc, Expression e) { return this; } version(DMDV2) { override bool canThrow() { return arrayExpressionCanThrow(elements); } } override MATCH implicitConvTo(Type t) { static if (false) { printf("StructLiteralExp.implicitConvTo(this=%.*s, type=%.*s, t=%.*s)\n", toChars(), type.toChars(), t.toChars()); } MATCH m = Expression.implicitConvTo(t); if (m != MATCHnomatch) return m; if (type.ty == t.ty && type.ty == Tstruct && (cast(TypeStruct)type).sym == (cast(TypeStruct)t).sym) { m = MATCHconst; foreach(e; elements) { Type te = e.type; if (t.mod == 0) te = te.mutableOf(); else { assert(t.mod == MODinvariant); te = te.invariantOf(); } MATCH m2 = e.implicitConvTo(te); //printf("\t%s => %s, match = %d\n", e.toChars(), te.toChars(), m2); if (m2 < m) m = m2; } } return m; } override int inlineCost(InlineCostState* ics) { assert(false); } override Expression doInline(InlineDoState ids) { assert(false); } override Expression inlineScan(InlineScanState* iss) { assert(false); } }