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