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