Mercurial > projects > ddmd
annotate dmd/SliceExp.d @ 63:cab4c37afb89
A bunch of implementations
author | korDen |
---|---|
date | Mon, 23 Aug 2010 16:52:24 +0400 |
parents | a8b50ff7f201 |
children | 4290d870944a |
rev | line source |
---|---|
0 | 1 module dmd.SliceExp; |
2 | |
3 import dmd.Expression; | |
63 | 4 import dmd.expression.ArrayLength; |
0 | 5 import dmd.backend.elem; |
6 import dmd.UnaExp; | |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
7 import dmd.Identifier; |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
8 import dmd.IdentifierExp; |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
9 import dmd.ArrayExp; |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
10 import dmd.STC; |
0 | 11 import dmd.InterState; |
12 import dmd.ScopeDsymbol; | |
13 import dmd.WANT; | |
14 import dmd.ArrayScopeSymbol; | |
15 import dmd.CallExp; | |
16 import dmd.DotIdExp; | |
17 import dmd.Id; | |
18 import dmd.expression.Util; | |
19 import dmd.TypeTuple; | |
20 import dmd.TupleExp; | |
21 import dmd.TypeStruct; | |
22 import dmd.TypeClass; | |
23 import dmd.TY; | |
24 import dmd.Type; | |
25 import dmd.AggregateDeclaration; | |
26 import dmd.OutBuffer; | |
27 import dmd.Loc; | |
28 import dmd.Scope; | |
29 import dmd.InlineCostState; | |
30 import dmd.VarDeclaration; | |
31 import dmd.ErrorExp; | |
32 import dmd.TypeExp; | |
33 import dmd.Argument; | |
34 import dmd.ExpInitializer; | |
35 import dmd.IRState; | |
36 import dmd.InlineDoState; | |
37 import dmd.ArrayTypes; | |
38 import dmd.HdrGenState; | |
39 import dmd.InlineScanState; | |
40 import dmd.TOK; | |
41 import dmd.TypeSArray; | |
42 import dmd.GlobalExpressions; | |
43 import dmd.Global; | |
44 import dmd.PREC; | |
45 | |
46 import dmd.expression.Slice; | |
47 import dmd.expression.Util; | |
48 | |
49 import dmd.backend.Util; | |
50 import dmd.backend.Symbol; | |
51 import dmd.backend.OPER; | |
52 import dmd.backend.TYM; | |
53 import dmd.codegen.Util; | |
54 | |
55 import core.stdc.string; | |
56 | |
57 class SliceExp : UnaExp | |
58 { | |
59 Expression upr; // null if implicit 0 | |
60 Expression lwr; // null if implicit [length - 1] | |
61 | |
62 VarDeclaration lengthVar = null; | |
63 | |
64 this(Loc loc, Expression e1, Expression lwr, Expression upr) | |
65 { | |
66 super(loc, TOK.TOKslice, SliceExp.sizeof, e1); | |
67 this.upr = upr; | |
68 this.lwr = lwr; | |
69 } | |
70 | |
71 Expression syntaxCopy() | |
72 { | |
53 | 73 Expression lwr = null; |
74 if (this.lwr) | |
75 lwr = this.lwr.syntaxCopy(); | |
76 | |
77 Expression upr = null; | |
78 if (this.upr) | |
79 upr = this.upr.syntaxCopy(); | |
80 | |
81 return new SliceExp(loc, e1.syntaxCopy(), lwr, upr); | |
0 | 82 } |
83 | |
84 Expression semantic(Scope sc) | |
85 { | |
86 Expression e; | |
87 AggregateDeclaration ad; | |
88 //FuncDeclaration fd; | |
89 ScopeDsymbol sym; | |
90 | |
91 version (LOGSEMANTIC) { | |
92 printf("SliceExp.semantic('%s')\n", toChars()); | |
93 } | |
94 if (type) | |
95 return this; | |
96 | |
97 UnaExp.semantic(sc); | |
98 e1 = resolveProperties(sc, e1); | |
99 | |
100 e = this; | |
101 | |
102 Type t = e1.type.toBasetype(); | |
103 if (t.ty == Tpointer) | |
104 { | |
105 if (!lwr || !upr) | |
106 error("need upper and lower bound to slice pointer"); | |
107 } | |
108 else if (t.ty == Tarray) | |
109 { | |
110 } | |
111 else if (t.ty == Tsarray) | |
112 { | |
113 } | |
114 else if (t.ty == Tclass) | |
115 { | |
116 ad = (cast(TypeClass)t).sym; | |
117 goto L1; | |
118 } | |
119 else if (t.ty == Tstruct) | |
120 { | |
121 ad = (cast(TypeStruct)t).sym; | |
122 | |
123 L1: | |
124 if (search_function(ad, Id.slice)) | |
125 { | |
126 // Rewrite as e1.slice(lwr, upr) | |
127 e = new DotIdExp(loc, e1, Id.slice); | |
128 | |
129 if (lwr) | |
130 { | |
131 assert(upr); | |
132 e = new CallExp(loc, e, lwr, upr); | |
133 } | |
134 else | |
135 { | |
136 assert(!upr); | |
137 e = new CallExp(loc, e); | |
138 } | |
139 e = e.semantic(sc); | |
140 return e; | |
141 } | |
142 goto Lerror; | |
143 } | |
144 else if (t.ty == Ttuple) | |
145 { | |
146 if (!lwr && !upr) | |
147 return e1; | |
148 if (!lwr || !upr) | |
149 { error("need upper and lower bound to slice tuple"); | |
150 goto Lerror; | |
151 } | |
152 } | |
153 else | |
154 goto Lerror; | |
155 | |
156 { | |
157 Scope sc2 = sc; | |
158 if (t.ty == Tsarray || t.ty == Tarray || t.ty == Ttuple) | |
159 { | |
160 sym = new ArrayScopeSymbol(sc, this); | |
161 sym.loc = loc; | |
162 sym.parent = sc.scopesym; | |
163 sc2 = sc.push(sym); | |
164 } | |
165 | |
166 if (lwr) | |
167 { | |
168 lwr = lwr.semantic(sc2); | |
169 lwr = resolveProperties(sc2, lwr); | |
170 lwr = lwr.implicitCastTo(sc2, Type.tsize_t); | |
171 } | |
172 if (upr) | |
173 { | |
174 upr = upr.semantic(sc2); | |
175 upr = resolveProperties(sc2, upr); | |
176 upr = upr.implicitCastTo(sc2, Type.tsize_t); | |
177 } | |
178 | |
179 if (sc2 != sc) | |
180 sc2.pop(); | |
181 } | |
182 | |
183 if (t.ty == Ttuple) | |
184 { | |
185 lwr = lwr.optimize(WANTvalue); | |
186 upr = upr.optimize(WANTvalue); | |
187 ulong i1 = lwr.toUInteger(); | |
188 ulong i2 = upr.toUInteger(); | |
189 | |
190 size_t length; | |
191 TupleExp te; | |
192 TypeTuple tup; | |
193 | |
194 if (e1.op == TOKtuple) // slicing an expression tuple | |
195 { | |
196 te = cast(TupleExp)e1; | |
197 length = te.exps.dim; | |
198 } | |
199 else if (e1.op == TOKtype) // slicing a type tuple | |
200 { | |
201 tup = cast(TypeTuple)t; | |
202 length = Argument.dim(tup.arguments); | |
203 } | |
204 else | |
205 assert(0); | |
206 | |
207 if (i1 <= i2 && i2 <= length) | |
208 { | |
209 size_t j1 = cast(size_t) i1; | |
210 size_t j2 = cast(size_t) i2; | |
211 | |
212 if (e1.op == TOKtuple) | |
213 { | |
214 Expressions exps = new Expressions; | |
215 exps.setDim(j2 - j1); | |
216 for (size_t i = 0; i < j2 - j1; i++) | |
217 { | |
218 Expression e2 = cast(Expression)te.exps.data[j1 + i]; | |
219 exps.data[i] = cast(void*)e2; | |
220 } | |
221 e = new TupleExp(loc, exps); | |
222 } | |
223 else | |
224 { | |
225 Arguments args = new Arguments; | |
226 args.reserve(j2 - j1); | |
227 for (size_t i = j1; i < j2; i++) | |
228 { | |
229 Argument arg = Argument.getNth(tup.arguments, i); | |
230 args.push(cast(void*)arg); | |
231 } | |
232 e = new TypeExp(e1.loc, new TypeTuple(args)); | |
233 } | |
234 e = e.semantic(sc); | |
235 } | |
236 else | |
237 { | |
238 error("string slice [%ju .. %ju] is out of bounds", i1, i2); | |
239 e = new ErrorExp(); | |
240 } | |
241 return e; | |
242 } | |
243 | |
244 if (t.ty == Tarray) | |
245 { | |
246 type = e1.type; | |
247 } | |
248 else | |
249 type = t.nextOf().arrayOf(); | |
250 return e; | |
251 | |
252 Lerror: | |
253 string s; | |
254 if (t.ty == Tvoid) | |
255 s = e1.toChars(); | |
256 else | |
257 s = t.toChars(); | |
258 error("%s cannot be sliced with []", s); | |
259 e = new ErrorExp(); | |
260 return e; | |
261 } | |
262 | |
263 void checkEscape() | |
264 { | |
265 e1.checkEscape(); | |
266 } | |
267 | |
268 version (DMDV2) { | |
269 int isLvalue() | |
270 { | |
271 return 1; | |
272 } | |
273 } | |
274 Expression toLvalue(Scope sc, Expression e) | |
275 { | |
276 return this; | |
277 } | |
278 | |
279 Expression modifiableLvalue(Scope sc, Expression e) | |
280 { | |
281 error("slice expression %s is not a modifiable lvalue", toChars()); | |
282 return this; | |
283 } | |
284 | |
285 void toCBuffer(OutBuffer buf, HdrGenState* hgs) | |
286 { | |
287 expToCBuffer(buf, hgs, e1, precedence[op]); | |
288 buf.writeByte('['); | |
289 if (upr || lwr) | |
290 { | |
291 if (lwr) | |
292 expToCBuffer(buf, hgs, lwr, PREC.PREC_assign); | |
293 else | |
294 buf.writeByte('0'); | |
295 buf.writestring(".."); | |
296 if (upr) | |
297 expToCBuffer(buf, hgs, upr, PREC.PREC_assign); | |
298 else | |
299 buf.writestring("length"); // BUG: should be array.length | |
300 } | |
301 buf.writeByte(']'); | |
302 } | |
303 | |
304 Expression optimize(int result) | |
305 { | |
306 Expression e; | |
307 | |
308 //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); | |
309 e = this; | |
310 e1 = e1.optimize(WANTvalue | (result & WANTinterpret)); | |
311 if (!lwr) | |
312 { | |
313 if (e1.op == TOKstring) | |
314 { | |
315 // Convert slice of string literal into dynamic array | |
316 Type t = e1.type.toBasetype(); | |
317 if (t.nextOf()) | |
318 e = e1.castTo(null, t.nextOf().arrayOf()); | |
319 } | |
320 return e; | |
321 } | |
322 e1 = fromConstInitializer(result, e1); | |
323 lwr = lwr.optimize(WANTvalue | (result & WANTinterpret)); | |
324 upr = upr.optimize(WANTvalue | (result & WANTinterpret)); | |
325 e = Slice(type, e1, lwr, upr); | |
326 if (e is EXP_CANT_INTERPRET) | |
327 e = this; | |
328 //printf("-SliceExp::optimize() %s\n", e->toChars()); | |
329 return e; | |
330 } | |
331 | |
63 | 332 Expression interpret(InterState istate) |
0 | 333 { |
63 | 334 Expression e; |
335 Expression e1; | |
336 Expression lwr; | |
337 Expression upr; | |
338 | |
339 version (LOG) { | |
340 printf("SliceExp.interpret() %s\n", toChars()); | |
341 } | |
342 e1 = this.e1.interpret(istate); | |
343 if (e1 is EXP_CANT_INTERPRET) | |
344 goto Lcant; | |
345 if (!this.lwr) | |
346 { | |
347 e = e1.castTo(null, type); | |
348 return e.interpret(istate); | |
349 } | |
350 | |
351 /* Set the $ variable | |
352 */ | |
353 e = ArrayLength(Type.tsize_t, e1); | |
354 if (e is EXP_CANT_INTERPRET) | |
355 goto Lcant; | |
356 if (lengthVar) | |
357 lengthVar.value = e; | |
358 | |
359 /* Evaluate lower and upper bounds of slice | |
360 */ | |
361 lwr = this.lwr.interpret(istate); | |
362 if (lwr is EXP_CANT_INTERPRET) | |
363 goto Lcant; | |
364 upr = this.upr.interpret(istate); | |
365 if (upr is EXP_CANT_INTERPRET) | |
366 goto Lcant; | |
367 | |
368 return Slice(type, e1, lwr, upr); | |
369 | |
370 Lcant: | |
371 return EXP_CANT_INTERPRET; | |
0 | 372 } |
373 | |
374 void dump(int indent) | |
375 { | |
376 assert(false); | |
377 } | |
378 | |
379 elem* toElem(IRState* irs) | |
380 { | |
381 elem* e; | |
382 Type t1; | |
383 | |
384 //printf("SliceExp.toElem()\n"); | |
385 t1 = e1.type.toBasetype(); | |
386 e = e1.toElem(irs); | |
387 if (lwr) | |
388 { | |
389 elem* elwr; | |
390 elem* elwr2; | |
391 elem* eupr; | |
392 elem* eptr; | |
393 elem* einit; | |
394 int sz; | |
395 | |
396 einit = resolveLengthVar(lengthVar, &e, t1); | |
397 | |
398 sz = cast(uint)t1.nextOf().size(); | |
399 | |
400 elwr = lwr.toElem(irs); | |
401 eupr = upr.toElem(irs); | |
402 | |
403 elwr2 = el_same(&elwr); | |
404 | |
405 // Create an array reference where: | |
406 // length is (upr - lwr) | |
407 // pointer is (ptr + lwr*sz) | |
408 // Combine as (length pair ptr) | |
409 | |
410 if (global.params.useArrayBounds) | |
411 { | |
412 // Checks (unsigned compares): | |
413 // upr <= array.length | |
414 // lwr <= upr | |
415 | |
416 elem *c1; | |
417 elem *c2; | |
418 elem *ea; | |
419 elem *eb; | |
420 elem *eupr2; | |
421 elem *elength; | |
422 | |
423 if (t1.ty == Tpointer) | |
424 { | |
425 // Just do lwr <= upr check | |
426 | |
427 eupr2 = el_same(&eupr); | |
428 eupr2.Ety = TYuint; // make sure unsigned comparison | |
429 c1 = el_bin(OPle, TYint, elwr2, eupr2); | |
430 c1 = el_combine(eupr, c1); | |
431 goto L2; | |
432 } | |
433 else if (t1.ty == Tsarray) | |
434 { | |
435 TypeSArray tsa = cast(TypeSArray)t1; | |
436 ulong length = tsa.dim.toInteger(); | |
437 | |
438 elength = el_long(TYuint, length); | |
439 goto L1; | |
440 } | |
441 else if (t1.ty == Tarray) | |
442 { | |
443 if (lengthVar) | |
444 elength = el_var(lengthVar.toSymbol()); | |
445 else | |
446 { | |
447 elength = e; | |
448 e = el_same(&elength); | |
449 elength = el_una(OP64_32, TYuint, elength); | |
450 } | |
451 L1: | |
452 eupr2 = el_same(&eupr); | |
453 c1 = el_bin(OPle, TYint, eupr, elength); | |
454 eupr2.Ety = TYuint; // make sure unsigned comparison | |
455 c2 = el_bin(OPle, TYint, elwr2, eupr2); | |
456 c1 = el_bin(OPandand, TYint, c1, c2); // (c1 && c2) | |
457 | |
458 L2: | |
459 // Construct: (c1 || ModuleArray(line)) | |
460 Symbol* sassert; | |
461 | |
462 sassert = irs.blx.module_.toModuleArray(); | |
463 ea = el_bin(OPcall,TYvoid,el_var(sassert), el_long(TYint, loc.linnum)); | |
464 eb = el_bin(OPoror,TYvoid,c1,ea); | |
465 elwr = el_combine(elwr, eb); | |
466 | |
467 elwr2 = el_copytree(elwr2); | |
468 eupr = el_copytree(eupr2); | |
469 } | |
470 } | |
471 | |
472 eptr = array_toPtr(e1.type, e); | |
473 | |
474 elem *elength = el_bin(OPmin, TYint, eupr, elwr2); | |
475 eptr = el_bin(OPadd, TYnptr, eptr, el_bin(OPmul, TYint, el_copytree(elwr2), el_long(TYint, sz))); | |
476 | |
477 e = el_pair(TYullong, elength, eptr); | |
478 e = el_combine(elwr, e); | |
479 e = el_combine(einit, e); | |
480 } | |
481 else if (t1.ty == Tsarray) | |
482 { | |
483 e = sarray_toDarray(loc, t1, null, e); | |
484 } | |
485 | |
486 el_setLoc(e,loc); | |
487 return e; | |
488 } | |
489 | |
490 void scanForNestedRef(Scope sc) | |
491 { | |
492 assert(false); | |
493 } | |
494 | |
495 void buildArrayIdent(OutBuffer buf, Expressions arguments) | |
496 { | |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
497 buf.writestring("Slice"); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
498 arguments.shift(cast(void*)this); |
0 | 499 } |
500 | |
501 Expression buildArrayLoop(Arguments fparams) | |
502 { | |
12
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
503 Identifier id = Identifier.generateId("p", fparams.dim); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
504 Argument param = new Argument(STCconst, type, id, null); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
505 fparams.shift(cast(void*)param); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
506 Expression e = new IdentifierExp(Loc(0), id); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
507 Expressions arguments = new Expressions(); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
508 Expression index = new IdentifierExp(Loc(0), Id.p); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
509 arguments.push(cast(void*)index); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
510 e = new ArrayExp(Loc(0), e, arguments); |
832f71e6f96c
*Exp and *AssignExp arrayOp implementation added (might be a bit incomplete)
korDen
parents:
0
diff
changeset
|
511 return e; |
0 | 512 } |
513 | |
514 int inlineCost(InlineCostState* ics) | |
515 { | |
516 int cost = 1 + e1.inlineCost(ics); | |
517 if (lwr) | |
518 cost += lwr.inlineCost(ics); | |
519 if (upr) | |
520 cost += upr.inlineCost(ics); | |
521 return cost; | |
522 } | |
523 | |
524 Expression doInline(InlineDoState ids) | |
525 { | |
526 SliceExp are = cast(SliceExp)copy(); | |
527 | |
528 are.e1 = e1.doInline(ids); | |
529 | |
530 if (lengthVar) | |
531 { | |
532 //printf("lengthVar\n"); | |
533 VarDeclaration vd = lengthVar; | |
534 ExpInitializer ie; | |
535 ExpInitializer ieto; | |
536 VarDeclaration vto; | |
537 | |
538 vto = new VarDeclaration(vd.loc, vd.type, vd.ident, vd.init); | |
539 ///*vto = *vd; | |
540 memcpy(cast(void*)vto, cast(void*)vd, VarDeclaration.classinfo.init.length); | |
541 | |
542 vto.parent = ids.parent; | |
543 vto.csym = null; | |
544 vto.isym = null; | |
545 | |
546 ids.from.push(cast(void*)vd); | |
547 ids.to.push(cast(void*)vto); | |
548 | |
549 if (vd.init) | |
550 { | |
551 ie = vd.init.isExpInitializer(); | |
552 assert(ie); | |
553 ieto = new ExpInitializer(ie.loc, ie.exp.doInline(ids)); | |
554 vto.init = ieto; | |
555 } | |
556 | |
557 are.lengthVar = vto; | |
558 } | |
559 | |
560 if (lwr) | |
561 are.lwr = lwr.doInline(ids); | |
562 if (upr) | |
563 are.upr = upr.doInline(ids); | |
564 return are; | |
565 } | |
566 | |
567 Expression inlineScan(InlineScanState* iss) | |
568 { | |
569 e1 = e1.inlineScan(iss); | |
570 if (lwr) | |
571 lwr = lwr.inlineScan(iss); | |
572 if (upr) | |
573 upr = upr.inlineScan(iss); | |
574 return this; | |
575 } | |
576 } | |
577 |