Mercurial > projects > ddmd
diff dmd/IndexExp.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | cab4c37afb89 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/IndexExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,427 @@ +module dmd.IndexExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.VarDeclaration; +import dmd.InlineDoState; +import dmd.Type; +import dmd.ScopeDsymbol; +import dmd.TY; +import dmd.ArrayScopeSymbol; +import dmd.TypeNext; +import dmd.TypeSArray; +import dmd.TypeAArray; +import dmd.UnaExp; +import dmd.IRState; +import dmd.BinExp; +import dmd.HdrGenState; +import dmd.TOK; +import dmd.WANT; +import dmd.TupleExp; +import dmd.TypeTuple; +import dmd.Argument; +import dmd.TypeExp; +import dmd.VarExp; +import dmd.STC; +import dmd.GlobalExpressions; +import dmd.ExpInitializer; +import dmd.Global; + +import dmd.expression.util.arrayTypeCompatible; +import dmd.expression.Util; +import dmd.expression.Index; + +import dmd.backend.Symbol; +import dmd.backend.Util; +import dmd.codegen.Util; +import dmd.backend.OPER; +import dmd.backend.mTY; +import dmd.backend.TYM; + +import core.stdc.string; + +class IndexExp : BinExp +{ + VarDeclaration lengthVar; + int modifiable = 0; // assume it is an rvalue + + this(Loc loc, Expression e1, Expression e2) + { + super(loc, TOK.TOKindex, IndexExp.sizeof, e1, e2); + //printf("IndexExp.IndexExp('%s')\n", toChars()); + } + + Expression semantic(Scope sc) + { + Expression e; + BinExp b; + UnaExp u; + Type t1; + ScopeDsymbol sym; + + version (LOGSEMANTIC) { + printf("IndexExp.semantic('%s')\n", toChars()); + } + if (type) + return this; + if (!e1.type) + e1 = e1.semantic(sc); + assert(e1.type); // semantic() should already be run on it + e = this; + + // Note that unlike C we do not implement the int[ptr] + + t1 = e1.type.toBasetype(); + + if (t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Ttuple) + { + // Create scope for 'length' variable + sym = new ArrayScopeSymbol(sc, this); + sym.loc = loc; + sym.parent = sc.scopesym; + sc = sc.push(sym); + } + + e2 = e2.semantic(sc); + if (!e2.type) + { + error("%s has no value", e2.toChars()); + e2.type = Type.terror; + } + e2 = resolveProperties(sc, e2); + + if (t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Ttuple) + sc = sc.pop(); + + switch (t1.ty) + { + case Tpointer: + case Tarray: + e2 = e2.implicitCastTo(sc, Type.tsize_t); + e.type = (cast(TypeNext)t1).next; + break; + + case Tsarray: + { + e2 = e2.implicitCastTo(sc, Type.tsize_t); + + TypeSArray tsa = cast(TypeSArray)t1; + + static if (false) { + // Don't do now, because it might be short-circuit evaluated + // Do compile time array bounds checking if possible + e2 = e2.optimize(WANTvalue); + if (e2.op == TOKint64) + { + ulong index = e2.toInteger(); + ulong length = tsa.dim.toInteger(); + if (index < 0 || index >= length) + error("array index [%lld] is outside array bounds [0 .. %lld]", index, length); + } + } + e.type = t1.nextOf(); + break; + } + + case Taarray: + { + TypeAArray taa = cast(TypeAArray)t1; + if (!arrayTypeCompatible(e2.loc, e2.type, taa.index)) + { + e2 = e2.implicitCastTo(sc, taa.index); // type checking + } + type = taa.next; + break; + } + + case Ttuple: + { + e2 = e2.implicitCastTo(sc, Type.tsize_t); + e2 = e2.optimize(WANTvalue | WANTinterpret); + ulong index = e2.toUInteger(); + size_t length; + TupleExp te; + TypeTuple tup; + + if (e1.op == TOKtuple) + { + te = cast(TupleExp)e1; + length = te.exps.dim; + } + else if (e1.op == TOKtype) + { + tup = cast(TypeTuple)t1; + length = Argument.dim(tup.arguments); + } + else + assert(0); + + if (index < length) + { + if (e1.op == TOKtuple) + e = cast(Expression)te.exps.data[cast(size_t)index]; + else + e = new TypeExp(e1.loc, Argument.getNth(tup.arguments, cast(size_t)index).type); + } + else + { + error("array index [%ju] is outside array bounds [0 .. %zu]", index, length); + e = e1; + } + break; + } + + default: + error("%s must be an array or pointer type, not %s", e1.toChars(), e1.type.toChars()); + type = Type.tint32; + break; + } + + return e; + } + + int isLvalue() + { + assert(false); + } + + Expression toLvalue(Scope sc, Expression e) + { + // if (type && type.toBasetype().ty == Tvoid) + // error("voids have no value"); + return this; + } + + Expression modifiableLvalue(Scope sc, Expression e) + { + //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); + modifiable = 1; + if (e1.op == TOKstring) + error("string literals are immutable"); + if (type && !type.isMutable()) + error("%s isn't mutable", e.toChars()); + if (e1.type.toBasetype().ty == Taarray) + e1 = e1.modifiableLvalue(sc, e1); + return toLvalue(sc, e); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Expression optimize(int result) + { + Expression e; + + //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); + Expression e1 = this.e1.optimize(WANTvalue | (result & WANTinterpret)); + e1 = fromConstInitializer(result, e1); + if (this.e1.op == TOKvar) + { + VarExp ve = cast(VarExp)this.e1; + if (ve.var.storage_class & STCmanifest) + { + /* We generally don't want to have more than one copy of an + * array literal, but if it's an enum we have to because the + * enum isn't stored elsewhere. See Bugzilla 2559 + */ + this.e1 = e1; + } + } + + e2 = e2.optimize(WANTvalue | (result & WANTinterpret)); + e = Index(type, e1, e2); + if (e is EXP_CANT_INTERPRET) + e = this; + + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + Expression doInline(InlineDoState ids) + { + IndexExp are = cast(IndexExp)copy(); + + are.e1 = e1.doInline(ids); + + if (lengthVar) + { //printf("lengthVar\n"); + VarDeclaration vd = lengthVar; + ExpInitializer ie; + ExpInitializer ieto; + VarDeclaration vto; + + vto = new VarDeclaration(vd.loc, vd.type, vd.ident, vd.init); + ///*vto = *vd; + memcpy(cast(void*)vto, cast(void*)vd, VarDeclaration.classinfo.init.length); + vto.parent = ids.parent; + vto.csym = null; + vto.isym = null; + + ids.from.push(cast(void*)vd); + ids.to.push(cast(void*)vto); + + if (vd.init) + { + ie = vd.init.isExpInitializer(); + assert(ie); + ieto = new ExpInitializer(ie.loc, ie.exp.doInline(ids)); + vto.init = ieto; + } + + are.lengthVar = vto; + } + are.e2 = e2.doInline(ids); + return are; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + elem* n1 = e1.toElem(irs); + elem* n2; + elem* eb = null; + Type t1; + + //printf("IndexExp.toElem() %s\n", toChars()); + t1 = e1.type.toBasetype(); + if (t1.ty == Taarray) + { + // set to: + // *aaGet(aa, keyti, valuesize, index); + + TypeAArray taa = cast(TypeAArray)t1; + elem* keyti; + elem* ep; + int vsize = cast(int)taa.next.size(); + elem* valuesize; + Symbol* s; + + // n2 becomes the index, also known as the key + n2 = e2.toElem(irs); + if (tybasic(n2.Ety) == TYstruct || tybasic(n2.Ety) == TYarray) + { + n2 = el_una(OPstrpar, TYstruct, n2); + n2.Enumbytes = n2.E1.Enumbytes; + //printf("numbytes = %d\n", n2.Enumbytes); + assert(n2.Enumbytes); + } + valuesize = el_long(TYuint, vsize); // BUG: should be TYsize_t + //printf("valuesize: "); elem_print(valuesize); + if (modifiable) + { + n1 = el_una(OPaddr, TYnptr, n1); + s = taa.aaGetSymbol("Get", 1); + } + else + { + s = taa.aaGetSymbol("GetRvalue", 1); + } + //printf("taa.index = %s\n", taa.index.toChars()); + keyti = taa.index.getInternalTypeInfo(null).toElem(irs); + //keyti = taa.index.getTypeInfo(null).toElem(irs); + //printf("keyti:\n"); + //elem_print(keyti); + ep = el_params(n2, valuesize, keyti, n1, null); + e = el_bin(OPcall, TYnptr, el_var(s), ep); + if (global.params.useArrayBounds) + { + elem* n; + elem* ea; + + n = el_same(&e); + + // Construct: ((e || ModuleAssert(line)),n) + Symbol* sassert; + + sassert = irs.blx.module_.toModuleArray(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), + el_long(TYint, loc.linnum)); + e = el_bin(OPoror,TYvoid,e,ea); + e = el_bin(OPcomma, TYnptr, e, n); + } + e = el_una(OPind, type.totym(), e); + if (tybasic(e.Ety) == TYstruct) + e.Enumbytes = cast(uint)type.size(); + } + else + { + elem* einit; + + einit = resolveLengthVar(lengthVar, &n1, t1); + n2 = e2.toElem(irs); + + if (global.params.useArrayBounds) + { + elem* elength; + elem* n2x; + elem* ea; + + if (t1.ty == Tsarray) + { + TypeSArray tsa = cast(TypeSArray)t1; + ulong length = tsa.dim.toInteger(); + + elength = el_long(TYuint, length); + goto L1; + } + else if (t1.ty == Tarray) + { + elength = n1; + n1 = el_same(&elength); + elength = el_una(OP64_32, TYuint, elength); + L1: + n2x = n2; + n2 = el_same(&n2x); + n2x = el_bin(OPlt, TYint, n2x, elength); + + // Construct: (n2x || ModuleAssert(line)) + Symbol* sassert; + + sassert = irs.blx.module_.toModuleArray(); + ea = el_bin(OPcall,TYvoid,el_var(sassert), + el_long(TYint, loc.linnum)); + eb = el_bin(OPoror,TYvoid,n2x,ea); + } + } + + n1 = array_toPtr(t1, n1); + + { + elem* escale; + + escale = el_long(TYint, t1.nextOf().size()); + n2 = el_bin(OPmul, TYint, n2, escale); + e = el_bin(OPadd, TYnptr, n1, n2); + e = el_una(OPind, type.totym(), e); + if (tybasic(e.Ety) == TYstruct || tybasic(e.Ety) == TYarray) + { + e.Ety = TYstruct; + e.Enumbytes = cast(uint)type.size(); + } + } + + eb = el_combine(einit, eb); + e = el_combine(eb, e); + } + + el_setLoc(e,loc); + + return e; + } +} +