Mercurial > projects > ddmd
diff dmd/SliceExp.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 832f71e6f96c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/SliceExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,518 @@ +module dmd.SliceExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.UnaExp; +import dmd.InterState; +import dmd.ScopeDsymbol; +import dmd.WANT; +import dmd.ArrayScopeSymbol; +import dmd.CallExp; +import dmd.DotIdExp; +import dmd.Id; +import dmd.expression.Util; +import dmd.TypeTuple; +import dmd.TupleExp; +import dmd.TypeStruct; +import dmd.TypeClass; +import dmd.TY; +import dmd.Type; +import dmd.AggregateDeclaration; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.VarDeclaration; +import dmd.ErrorExp; +import dmd.TypeExp; +import dmd.Argument; +import dmd.ExpInitializer; +import dmd.IRState; +import dmd.InlineDoState; +import dmd.ArrayTypes; +import dmd.HdrGenState; +import dmd.InlineScanState; +import dmd.TOK; +import dmd.TypeSArray; +import dmd.GlobalExpressions; +import dmd.Global; +import dmd.PREC; + +import dmd.expression.Slice; +import dmd.expression.Util; + +import dmd.backend.Util; +import dmd.backend.Symbol; +import dmd.backend.OPER; +import dmd.backend.TYM; +import dmd.codegen.Util; + +import core.stdc.string; + +class SliceExp : UnaExp +{ + Expression upr; // null if implicit 0 + Expression lwr; // null if implicit [length - 1] + + VarDeclaration lengthVar = null; + + this(Loc loc, Expression e1, Expression lwr, Expression upr) + { + super(loc, TOK.TOKslice, SliceExp.sizeof, e1); + this.upr = upr; + this.lwr = lwr; + } + + Expression syntaxCopy() + { + assert(false); + } + + Expression semantic(Scope sc) + { + Expression e; + AggregateDeclaration ad; + //FuncDeclaration fd; + ScopeDsymbol sym; + + version (LOGSEMANTIC) { + printf("SliceExp.semantic('%s')\n", toChars()); + } + if (type) + return this; + + UnaExp.semantic(sc); + e1 = resolveProperties(sc, e1); + + e = this; + + Type t = e1.type.toBasetype(); + if (t.ty == Tpointer) + { + if (!lwr || !upr) + error("need upper and lower bound to slice pointer"); + } + else if (t.ty == Tarray) + { + } + else if (t.ty == Tsarray) + { + } + else if (t.ty == Tclass) + { + ad = (cast(TypeClass)t).sym; + goto L1; + } + else if (t.ty == Tstruct) + { + ad = (cast(TypeStruct)t).sym; + + L1: + if (search_function(ad, Id.slice)) + { + // Rewrite as e1.slice(lwr, upr) + e = new DotIdExp(loc, e1, Id.slice); + + if (lwr) + { + assert(upr); + e = new CallExp(loc, e, lwr, upr); + } + else + { + assert(!upr); + e = new CallExp(loc, e); + } + e = e.semantic(sc); + return e; + } + goto Lerror; + } + else if (t.ty == Ttuple) + { + if (!lwr && !upr) + return e1; + if (!lwr || !upr) + { error("need upper and lower bound to slice tuple"); + goto Lerror; + } + } + else + goto Lerror; + + { + Scope sc2 = sc; + if (t.ty == Tsarray || t.ty == Tarray || t.ty == Ttuple) + { + sym = new ArrayScopeSymbol(sc, this); + sym.loc = loc; + sym.parent = sc.scopesym; + sc2 = sc.push(sym); + } + + if (lwr) + { + lwr = lwr.semantic(sc2); + lwr = resolveProperties(sc2, lwr); + lwr = lwr.implicitCastTo(sc2, Type.tsize_t); + } + if (upr) + { + upr = upr.semantic(sc2); + upr = resolveProperties(sc2, upr); + upr = upr.implicitCastTo(sc2, Type.tsize_t); + } + + if (sc2 != sc) + sc2.pop(); + } + + if (t.ty == Ttuple) + { + lwr = lwr.optimize(WANTvalue); + upr = upr.optimize(WANTvalue); + ulong i1 = lwr.toUInteger(); + ulong i2 = upr.toUInteger(); + + size_t length; + TupleExp te; + TypeTuple tup; + + if (e1.op == TOKtuple) // slicing an expression tuple + { + te = cast(TupleExp)e1; + length = te.exps.dim; + } + else if (e1.op == TOKtype) // slicing a type tuple + { + tup = cast(TypeTuple)t; + length = Argument.dim(tup.arguments); + } + else + assert(0); + + if (i1 <= i2 && i2 <= length) + { + size_t j1 = cast(size_t) i1; + size_t j2 = cast(size_t) i2; + + if (e1.op == TOKtuple) + { + Expressions exps = new Expressions; + exps.setDim(j2 - j1); + for (size_t i = 0; i < j2 - j1; i++) + { + Expression e2 = cast(Expression)te.exps.data[j1 + i]; + exps.data[i] = cast(void*)e2; + } + e = new TupleExp(loc, exps); + } + else + { + Arguments args = new Arguments; + args.reserve(j2 - j1); + for (size_t i = j1; i < j2; i++) + { + Argument arg = Argument.getNth(tup.arguments, i); + args.push(cast(void*)arg); + } + e = new TypeExp(e1.loc, new TypeTuple(args)); + } + e = e.semantic(sc); + } + else + { + error("string slice [%ju .. %ju] is out of bounds", i1, i2); + e = new ErrorExp(); + } + return e; + } + + if (t.ty == Tarray) + { + type = e1.type; + } + else + type = t.nextOf().arrayOf(); + return e; + + Lerror: + string s; + if (t.ty == Tvoid) + s = e1.toChars(); + else + s = t.toChars(); + error("%s cannot be sliced with []", s); + e = new ErrorExp(); + return e; + } + + void checkEscape() + { + e1.checkEscape(); + } + +version (DMDV2) { + int isLvalue() + { + return 1; + } +} + Expression toLvalue(Scope sc, Expression e) + { + return this; + } + + Expression modifiableLvalue(Scope sc, Expression e) + { + error("slice expression %s is not a modifiable lvalue", toChars()); + return this; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + expToCBuffer(buf, hgs, e1, precedence[op]); + buf.writeByte('['); + if (upr || lwr) + { + if (lwr) + expToCBuffer(buf, hgs, lwr, PREC.PREC_assign); + else + buf.writeByte('0'); + buf.writestring(".."); + if (upr) + expToCBuffer(buf, hgs, upr, PREC.PREC_assign); + else + buf.writestring("length"); // BUG: should be array.length + } + buf.writeByte(']'); + } + + Expression optimize(int result) + { + Expression e; + + //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); + e = this; + e1 = e1.optimize(WANTvalue | (result & WANTinterpret)); + if (!lwr) + { + if (e1.op == TOKstring) + { + // Convert slice of string literal into dynamic array + Type t = e1.type.toBasetype(); + if (t.nextOf()) + e = e1.castTo(null, t.nextOf().arrayOf()); + } + return e; + } + e1 = fromConstInitializer(result, e1); + lwr = lwr.optimize(WANTvalue | (result & WANTinterpret)); + upr = upr.optimize(WANTvalue | (result & WANTinterpret)); + e = Slice(type, e1, lwr, upr); + if (e is EXP_CANT_INTERPRET) + e = this; + //printf("-SliceExp::optimize() %s\n", e->toChars()); + return e; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void dump(int indent) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + Type t1; + + //printf("SliceExp.toElem()\n"); + t1 = e1.type.toBasetype(); + e = e1.toElem(irs); + if (lwr) + { + elem* elwr; + elem* elwr2; + elem* eupr; + elem* eptr; + elem* einit; + int sz; + + einit = resolveLengthVar(lengthVar, &e, t1); + + sz = cast(uint)t1.nextOf().size(); + + elwr = lwr.toElem(irs); + eupr = upr.toElem(irs); + + elwr2 = el_same(&elwr); + + // Create an array reference where: + // length is (upr - lwr) + // pointer is (ptr + lwr*sz) + // Combine as (length pair ptr) + + if (global.params.useArrayBounds) + { + // Checks (unsigned compares): + // upr <= array.length + // lwr <= upr + + elem *c1; + elem *c2; + elem *ea; + elem *eb; + elem *eupr2; + elem *elength; + + if (t1.ty == Tpointer) + { + // Just do lwr <= upr check + + eupr2 = el_same(&eupr); + eupr2.Ety = TYuint; // make sure unsigned comparison + c1 = el_bin(OPle, TYint, elwr2, eupr2); + c1 = el_combine(eupr, c1); + goto L2; + } + else 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) + { + if (lengthVar) + elength = el_var(lengthVar.toSymbol()); + else + { + elength = e; + e = el_same(&elength); + elength = el_una(OP64_32, TYuint, elength); + } + L1: + eupr2 = el_same(&eupr); + c1 = el_bin(OPle, TYint, eupr, elength); + eupr2.Ety = TYuint; // make sure unsigned comparison + c2 = el_bin(OPle, TYint, elwr2, eupr2); + c1 = el_bin(OPandand, TYint, c1, c2); // (c1 && c2) + + L2: + // Construct: (c1 || ModuleArray(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,c1,ea); + elwr = el_combine(elwr, eb); + + elwr2 = el_copytree(elwr2); + eupr = el_copytree(eupr2); + } + } + + eptr = array_toPtr(e1.type, e); + + elem *elength = el_bin(OPmin, TYint, eupr, elwr2); + eptr = el_bin(OPadd, TYnptr, eptr, el_bin(OPmul, TYint, el_copytree(elwr2), el_long(TYint, sz))); + + e = el_pair(TYullong, elength, eptr); + e = el_combine(elwr, e); + e = el_combine(einit, e); + } + else if (t1.ty == Tsarray) + { + e = sarray_toDarray(loc, t1, null, e); + } + + el_setLoc(e,loc); + return e; + } + + void scanForNestedRef(Scope sc) + { + assert(false); + } + + void buildArrayIdent(OutBuffer buf, Expressions arguments) + { + assert(false); + } + + Expression buildArrayLoop(Arguments fparams) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + int cost = 1 + e1.inlineCost(ics); + if (lwr) + cost += lwr.inlineCost(ics); + if (upr) + cost += upr.inlineCost(ics); + return cost; + } + + Expression doInline(InlineDoState ids) + { + SliceExp are = cast(SliceExp)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; + } + + if (lwr) + are.lwr = lwr.doInline(ids); + if (upr) + are.upr = upr.doInline(ids); + return are; + } + + Expression inlineScan(InlineScanState* iss) + { + e1 = e1.inlineScan(iss); + if (lwr) + lwr = lwr.inlineScan(iss); + if (upr) + upr = upr.inlineScan(iss); + return this; + } +} +