comparison dmd/IndexExp.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children cab4c37afb89
comparison
equal deleted inserted replaced
-1:000000000000 0:10317f0c89a5
1 module dmd.IndexExp;
2
3 import dmd.Expression;
4 import dmd.backend.elem;
5 import dmd.InterState;
6 import dmd.OutBuffer;
7 import dmd.Loc;
8 import dmd.Scope;
9 import dmd.VarDeclaration;
10 import dmd.InlineDoState;
11 import dmd.Type;
12 import dmd.ScopeDsymbol;
13 import dmd.TY;
14 import dmd.ArrayScopeSymbol;
15 import dmd.TypeNext;
16 import dmd.TypeSArray;
17 import dmd.TypeAArray;
18 import dmd.UnaExp;
19 import dmd.IRState;
20 import dmd.BinExp;
21 import dmd.HdrGenState;
22 import dmd.TOK;
23 import dmd.WANT;
24 import dmd.TupleExp;
25 import dmd.TypeTuple;
26 import dmd.Argument;
27 import dmd.TypeExp;
28 import dmd.VarExp;
29 import dmd.STC;
30 import dmd.GlobalExpressions;
31 import dmd.ExpInitializer;
32 import dmd.Global;
33
34 import dmd.expression.util.arrayTypeCompatible;
35 import dmd.expression.Util;
36 import dmd.expression.Index;
37
38 import dmd.backend.Symbol;
39 import dmd.backend.Util;
40 import dmd.codegen.Util;
41 import dmd.backend.OPER;
42 import dmd.backend.mTY;
43 import dmd.backend.TYM;
44
45 import core.stdc.string;
46
47 class IndexExp : BinExp
48 {
49 VarDeclaration lengthVar;
50 int modifiable = 0; // assume it is an rvalue
51
52 this(Loc loc, Expression e1, Expression e2)
53 {
54 super(loc, TOK.TOKindex, IndexExp.sizeof, e1, e2);
55 //printf("IndexExp.IndexExp('%s')\n", toChars());
56 }
57
58 Expression semantic(Scope sc)
59 {
60 Expression e;
61 BinExp b;
62 UnaExp u;
63 Type t1;
64 ScopeDsymbol sym;
65
66 version (LOGSEMANTIC) {
67 printf("IndexExp.semantic('%s')\n", toChars());
68 }
69 if (type)
70 return this;
71 if (!e1.type)
72 e1 = e1.semantic(sc);
73 assert(e1.type); // semantic() should already be run on it
74 e = this;
75
76 // Note that unlike C we do not implement the int[ptr]
77
78 t1 = e1.type.toBasetype();
79
80 if (t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Ttuple)
81 {
82 // Create scope for 'length' variable
83 sym = new ArrayScopeSymbol(sc, this);
84 sym.loc = loc;
85 sym.parent = sc.scopesym;
86 sc = sc.push(sym);
87 }
88
89 e2 = e2.semantic(sc);
90 if (!e2.type)
91 {
92 error("%s has no value", e2.toChars());
93 e2.type = Type.terror;
94 }
95 e2 = resolveProperties(sc, e2);
96
97 if (t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Ttuple)
98 sc = sc.pop();
99
100 switch (t1.ty)
101 {
102 case Tpointer:
103 case Tarray:
104 e2 = e2.implicitCastTo(sc, Type.tsize_t);
105 e.type = (cast(TypeNext)t1).next;
106 break;
107
108 case Tsarray:
109 {
110 e2 = e2.implicitCastTo(sc, Type.tsize_t);
111
112 TypeSArray tsa = cast(TypeSArray)t1;
113
114 static if (false) {
115 // Don't do now, because it might be short-circuit evaluated
116 // Do compile time array bounds checking if possible
117 e2 = e2.optimize(WANTvalue);
118 if (e2.op == TOKint64)
119 {
120 ulong index = e2.toInteger();
121 ulong length = tsa.dim.toInteger();
122 if (index < 0 || index >= length)
123 error("array index [%lld] is outside array bounds [0 .. %lld]", index, length);
124 }
125 }
126 e.type = t1.nextOf();
127 break;
128 }
129
130 case Taarray:
131 {
132 TypeAArray taa = cast(TypeAArray)t1;
133 if (!arrayTypeCompatible(e2.loc, e2.type, taa.index))
134 {
135 e2 = e2.implicitCastTo(sc, taa.index); // type checking
136 }
137 type = taa.next;
138 break;
139 }
140
141 case Ttuple:
142 {
143 e2 = e2.implicitCastTo(sc, Type.tsize_t);
144 e2 = e2.optimize(WANTvalue | WANTinterpret);
145 ulong index = e2.toUInteger();
146 size_t length;
147 TupleExp te;
148 TypeTuple tup;
149
150 if (e1.op == TOKtuple)
151 {
152 te = cast(TupleExp)e1;
153 length = te.exps.dim;
154 }
155 else if (e1.op == TOKtype)
156 {
157 tup = cast(TypeTuple)t1;
158 length = Argument.dim(tup.arguments);
159 }
160 else
161 assert(0);
162
163 if (index < length)
164 {
165 if (e1.op == TOKtuple)
166 e = cast(Expression)te.exps.data[cast(size_t)index];
167 else
168 e = new TypeExp(e1.loc, Argument.getNth(tup.arguments, cast(size_t)index).type);
169 }
170 else
171 {
172 error("array index [%ju] is outside array bounds [0 .. %zu]", index, length);
173 e = e1;
174 }
175 break;
176 }
177
178 default:
179 error("%s must be an array or pointer type, not %s", e1.toChars(), e1.type.toChars());
180 type = Type.tint32;
181 break;
182 }
183
184 return e;
185 }
186
187 int isLvalue()
188 {
189 assert(false);
190 }
191
192 Expression toLvalue(Scope sc, Expression e)
193 {
194 // if (type && type.toBasetype().ty == Tvoid)
195 // error("voids have no value");
196 return this;
197 }
198
199 Expression modifiableLvalue(Scope sc, Expression e)
200 {
201 //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
202 modifiable = 1;
203 if (e1.op == TOKstring)
204 error("string literals are immutable");
205 if (type && !type.isMutable())
206 error("%s isn't mutable", e.toChars());
207 if (e1.type.toBasetype().ty == Taarray)
208 e1 = e1.modifiableLvalue(sc, e1);
209 return toLvalue(sc, e);
210 }
211
212 void toCBuffer(OutBuffer buf, HdrGenState* hgs)
213 {
214 assert(false);
215 }
216
217 Expression optimize(int result)
218 {
219 Expression e;
220
221 //printf("IndexExp::optimize(result = %d) %s\n", result, toChars());
222 Expression e1 = this.e1.optimize(WANTvalue | (result & WANTinterpret));
223 e1 = fromConstInitializer(result, e1);
224 if (this.e1.op == TOKvar)
225 {
226 VarExp ve = cast(VarExp)this.e1;
227 if (ve.var.storage_class & STCmanifest)
228 {
229 /* We generally don't want to have more than one copy of an
230 * array literal, but if it's an enum we have to because the
231 * enum isn't stored elsewhere. See Bugzilla 2559
232 */
233 this.e1 = e1;
234 }
235 }
236
237 e2 = e2.optimize(WANTvalue | (result & WANTinterpret));
238 e = Index(type, e1, e2);
239 if (e is EXP_CANT_INTERPRET)
240 e = this;
241
242 return e;
243 }
244
245 Expression interpret(InterState* istate)
246 {
247 assert(false);
248 }
249
250 Expression doInline(InlineDoState ids)
251 {
252 IndexExp are = cast(IndexExp)copy();
253
254 are.e1 = e1.doInline(ids);
255
256 if (lengthVar)
257 { //printf("lengthVar\n");
258 VarDeclaration vd = lengthVar;
259 ExpInitializer ie;
260 ExpInitializer ieto;
261 VarDeclaration vto;
262
263 vto = new VarDeclaration(vd.loc, vd.type, vd.ident, vd.init);
264 ///*vto = *vd;
265 memcpy(cast(void*)vto, cast(void*)vd, VarDeclaration.classinfo.init.length);
266 vto.parent = ids.parent;
267 vto.csym = null;
268 vto.isym = null;
269
270 ids.from.push(cast(void*)vd);
271 ids.to.push(cast(void*)vto);
272
273 if (vd.init)
274 {
275 ie = vd.init.isExpInitializer();
276 assert(ie);
277 ieto = new ExpInitializer(ie.loc, ie.exp.doInline(ids));
278 vto.init = ieto;
279 }
280
281 are.lengthVar = vto;
282 }
283 are.e2 = e2.doInline(ids);
284 return are;
285 }
286
287 void scanForNestedRef(Scope sc)
288 {
289 assert(false);
290 }
291
292 elem* toElem(IRState* irs)
293 {
294 elem* e;
295 elem* n1 = e1.toElem(irs);
296 elem* n2;
297 elem* eb = null;
298 Type t1;
299
300 //printf("IndexExp.toElem() %s\n", toChars());
301 t1 = e1.type.toBasetype();
302 if (t1.ty == Taarray)
303 {
304 // set to:
305 // *aaGet(aa, keyti, valuesize, index);
306
307 TypeAArray taa = cast(TypeAArray)t1;
308 elem* keyti;
309 elem* ep;
310 int vsize = cast(int)taa.next.size();
311 elem* valuesize;
312 Symbol* s;
313
314 // n2 becomes the index, also known as the key
315 n2 = e2.toElem(irs);
316 if (tybasic(n2.Ety) == TYstruct || tybasic(n2.Ety) == TYarray)
317 {
318 n2 = el_una(OPstrpar, TYstruct, n2);
319 n2.Enumbytes = n2.E1.Enumbytes;
320 //printf("numbytes = %d\n", n2.Enumbytes);
321 assert(n2.Enumbytes);
322 }
323 valuesize = el_long(TYuint, vsize); // BUG: should be TYsize_t
324 //printf("valuesize: "); elem_print(valuesize);
325 if (modifiable)
326 {
327 n1 = el_una(OPaddr, TYnptr, n1);
328 s = taa.aaGetSymbol("Get", 1);
329 }
330 else
331 {
332 s = taa.aaGetSymbol("GetRvalue", 1);
333 }
334 //printf("taa.index = %s\n", taa.index.toChars());
335 keyti = taa.index.getInternalTypeInfo(null).toElem(irs);
336 //keyti = taa.index.getTypeInfo(null).toElem(irs);
337 //printf("keyti:\n");
338 //elem_print(keyti);
339 ep = el_params(n2, valuesize, keyti, n1, null);
340 e = el_bin(OPcall, TYnptr, el_var(s), ep);
341 if (global.params.useArrayBounds)
342 {
343 elem* n;
344 elem* ea;
345
346 n = el_same(&e);
347
348 // Construct: ((e || ModuleAssert(line)),n)
349 Symbol* sassert;
350
351 sassert = irs.blx.module_.toModuleArray();
352 ea = el_bin(OPcall,TYvoid,el_var(sassert),
353 el_long(TYint, loc.linnum));
354 e = el_bin(OPoror,TYvoid,e,ea);
355 e = el_bin(OPcomma, TYnptr, e, n);
356 }
357 e = el_una(OPind, type.totym(), e);
358 if (tybasic(e.Ety) == TYstruct)
359 e.Enumbytes = cast(uint)type.size();
360 }
361 else
362 {
363 elem* einit;
364
365 einit = resolveLengthVar(lengthVar, &n1, t1);
366 n2 = e2.toElem(irs);
367
368 if (global.params.useArrayBounds)
369 {
370 elem* elength;
371 elem* n2x;
372 elem* ea;
373
374 if (t1.ty == Tsarray)
375 {
376 TypeSArray tsa = cast(TypeSArray)t1;
377 ulong length = tsa.dim.toInteger();
378
379 elength = el_long(TYuint, length);
380 goto L1;
381 }
382 else if (t1.ty == Tarray)
383 {
384 elength = n1;
385 n1 = el_same(&elength);
386 elength = el_una(OP64_32, TYuint, elength);
387 L1:
388 n2x = n2;
389 n2 = el_same(&n2x);
390 n2x = el_bin(OPlt, TYint, n2x, elength);
391
392 // Construct: (n2x || ModuleAssert(line))
393 Symbol* sassert;
394
395 sassert = irs.blx.module_.toModuleArray();
396 ea = el_bin(OPcall,TYvoid,el_var(sassert),
397 el_long(TYint, loc.linnum));
398 eb = el_bin(OPoror,TYvoid,n2x,ea);
399 }
400 }
401
402 n1 = array_toPtr(t1, n1);
403
404 {
405 elem* escale;
406
407 escale = el_long(TYint, t1.nextOf().size());
408 n2 = el_bin(OPmul, TYint, n2, escale);
409 e = el_bin(OPadd, TYnptr, n1, n2);
410 e = el_una(OPind, type.totym(), e);
411 if (tybasic(e.Ety) == TYstruct || tybasic(e.Ety) == TYarray)
412 {
413 e.Ety = TYstruct;
414 e.Enumbytes = cast(uint)type.size();
415 }
416 }
417
418 eb = el_combine(einit, eb);
419 e = el_combine(eb, e);
420 }
421
422 el_setLoc(e,loc);
423
424 return e;
425 }
426 }
427