Mercurial > projects > ddmd
annotate dmd/ForeachStatement.d @ 122:c77e9f4f1793
Statements -> Vector
author | Eldar Insafutdinov <e.insafutdinov@gmail.com> |
---|---|
date | Thu, 02 Sep 2010 23:37:49 +0100 |
parents | e28b18c23469 |
children | 1765f3ef917d |
rev | line source |
---|---|
0 | 1 module dmd.ForeachStatement; |
2 | |
114 | 3 import dmd.common; |
0 | 4 import dmd.Statement; |
5 import dmd.TOK; | |
66 | 6 import dmd.Token; |
0 | 7 import dmd.Loc; |
8 import dmd.LINK; | |
9 import dmd.ArrayTypes; | |
10 import dmd.Expression; | |
11 import dmd.VarDeclaration; | |
12 import dmd.FuncDeclaration; | |
13 import dmd.Array; | |
14 import dmd.Scope; | |
15 import dmd.InterState; | |
16 import dmd.InlineScanState; | |
17 import dmd.OutBuffer; | |
18 import dmd.HdrGenState; | |
19 import dmd.IRState; | |
20 import dmd.BE; | |
21 import dmd.ScopeDsymbol; | |
22 import dmd.TypeAArray; | |
23 import dmd.Type; | |
24 import dmd.CallExp; | |
25 import dmd.WANT; | |
26 import dmd.TY; | |
27 import dmd.TypeTuple; | |
28 import dmd.TupleExp; | |
29 import dmd.Global; | |
30 import dmd.Initializer; | |
31 import dmd.ExpInitializer; | |
32 import dmd.IntegerExp; | |
33 import dmd.ExpStatement; | |
34 import dmd.DeclarationExp; | |
35 import dmd.Dsymbol; | |
36 import dmd.BreakStatement; | |
37 import dmd.DefaultStatement; | |
38 import dmd.CaseStatement; | |
39 import dmd.SwitchStatement; | |
40 import dmd.VarExp; | |
41 import dmd.AliasDeclaration; | |
42 import dmd.CompoundStatement; | |
43 import dmd.ScopeStatement; | |
44 import dmd.UnrolledLoopStatement; | |
45 import dmd.Identifier; | |
46 import dmd.Lexer; | |
47 import dmd.DeclarationStatement; | |
48 import dmd.CompoundDeclarationStatement; | |
49 import dmd.AggregateDeclaration; | |
50 import dmd.TypeClass; | |
51 import dmd.NotExp; | |
52 import dmd.TypeStruct; | |
53 import dmd.FuncLiteralDeclaration; | |
54 import dmd.IdentifierExp; | |
55 import dmd.TypeFunction; | |
56 import dmd.GotoStatement; | |
57 import dmd.FuncExp; | |
58 import dmd.ReturnStatement; | |
59 import dmd.IndexExp; | |
60 import dmd.ForStatement; | |
61 import dmd.SliceExp; | |
62 import dmd.DotIdExp; | |
63 import dmd.PostExp; | |
64 import dmd.AddAssignExp; | |
65 import dmd.CmpExp; | |
66 import dmd.Id; | |
67 import dmd.Argument; | |
68 import dmd.STC; | |
69 | |
70 import dmd.expression.Util; | |
71 | |
72 import core.stdc.stdio; | |
73 | |
74 class ForeachStatement : Statement | |
75 { | |
76 TOK op; // TOKforeach or TOKforeach_reverse | |
77 Arguments arguments; // array of Argument*'s | |
78 Expression aggr; | |
79 Statement body_; | |
80 | |
81 VarDeclaration key; | |
82 VarDeclaration value; | |
83 | |
84 FuncDeclaration func; // function we're lexically in | |
85 | |
86 Array cases; // put breaks, continues, gotos and returns here | |
87 Array gotos; // forward referenced goto's go here | |
88 | |
89 this(Loc loc, TOK op, Arguments arguments, Expression aggr, Statement body_) | |
90 { | |
91 super(loc); | |
92 | |
93 this.op = op; | |
94 this.arguments = arguments; | |
95 this.aggr = aggr; | |
96 this.body_ = body_; | |
97 | |
98 gotos = new Array(); | |
99 cases = new Array(); | |
100 } | |
101 | |
72 | 102 override Statement syntaxCopy() |
0 | 103 { |
53 | 104 Arguments args = Argument.arraySyntaxCopy(arguments); |
105 Expression exp = aggr.syntaxCopy(); | |
106 ForeachStatement s = new ForeachStatement(loc, op, args, exp, | |
107 body_ ? body_.syntaxCopy() : null); | |
108 return s; | |
0 | 109 } |
110 | |
72 | 111 override Statement semantic(Scope sc) |
0 | 112 { |
113 //printf("ForeachStatement.semantic() %p\n", this); | |
114 ScopeDsymbol sym; | |
115 Statement s = this; | |
116 size_t dim = arguments.dim; | |
117 TypeAArray taa = null; | |
118 | |
119 Type tn = null; | |
120 Type tnv = null; | |
121 | |
122 func = sc.func; | |
123 if (func.fes) | |
124 func = func.fes.func; | |
125 | |
126 aggr = aggr.semantic(sc); | |
127 aggr = resolveProperties(sc, aggr); | |
128 aggr = aggr.optimize(WANT.WANTvalue); | |
129 if (!aggr.type) | |
130 { | |
131 error("invalid foreach aggregate %s", aggr.toChars()); | |
132 return this; | |
133 } | |
134 | |
135 inferApplyArgTypes(op, arguments, aggr); | |
136 | |
137 /* Check for inference errors | |
138 */ | |
139 if (dim != arguments.dim) | |
140 { | |
141 //printf("dim = %d, arguments.dim = %d\n", dim, arguments.dim); | |
142 error("cannot uniquely infer foreach argument types"); | |
143 return this; | |
144 } | |
145 | |
146 Type tab = aggr.type.toBasetype(); | |
147 | |
148 if (tab.ty == TY.Ttuple) // don't generate new scope for tuple loops | |
149 { | |
150 if (dim < 1 || dim > 2) | |
151 { | |
152 error("only one (value) or two (key,value) arguments for tuple foreach"); | |
153 return s; | |
154 } | |
155 | |
156 TypeTuple tuple = cast(TypeTuple)tab; | |
157 Statements statements = new Statements(); | |
158 //printf("aggr: op = %d, %s\n", aggr.op, aggr.toChars()); | |
159 size_t n; | |
160 TupleExp te = null; | |
161 if (aggr.op == TOK.TOKtuple) // expression tuple | |
162 { | |
163 te = cast(TupleExp)aggr; | |
164 n = te.exps.dim; | |
165 } | |
166 else if (aggr.op == TOK.TOKtype) // type tuple | |
167 { | |
168 n = Argument.dim(tuple.arguments); | |
169 } | |
170 else | |
171 assert(0); | |
172 | |
173 for (size_t j = 0; j < n; j++) | |
174 { | |
175 size_t k = (op == TOK.TOKforeach) ? j : n - 1 - j; | |
176 Expression e; | |
177 Type t; | |
178 if (te) | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
179 e = te.exps[k]; |
0 | 180 else |
181 t = Argument.getNth(tuple.arguments, k).type; | |
182 | |
183 Argument arg = cast(Argument)arguments.data[0]; | |
184 Statements st = new Statements(); | |
185 | |
186 if (dim == 2) | |
187 { | |
188 // Declare key | |
189 if (arg.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) | |
190 error("no storage class for key %s", arg.ident.toChars()); | |
191 TY keyty = arg.type.ty; | |
192 if (keyty != TY.Tint32 && keyty != TY.Tuns32) | |
193 { | |
194 if (global.params.isX86_64) | |
195 { | |
196 if (keyty != TY.Tint64 && keyty != TY.Tuns64) | |
197 error("foreach: key type must be int or uint, long or ulong, not %s", arg.type.toChars()); | |
198 } | |
199 else | |
200 error("foreach: key type must be int or uint, not %s", arg.type.toChars()); | |
201 } | |
202 Initializer ie = new ExpInitializer(Loc(0), new IntegerExp(k)); | |
203 VarDeclaration var = new VarDeclaration(loc, arg.type, arg.ident, ie); | |
204 var.storage_class |= STC.STCmanifest; | |
205 DeclarationExp de = new DeclarationExp(loc, var); | |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
206 st.push(new ExpStatement(loc, de)); |
0 | 207 arg = cast(Argument)arguments.data[1]; // value |
208 } | |
209 // Declare value | |
210 if (arg.storageClass & (STC.STCout | STC.STCref | STC.STClazy)) | |
211 error("no storage class for value %s", arg.ident.toChars()); | |
212 Dsymbol var; | |
213 if (te) | |
214 { | |
215 Type tb = e.type.toBasetype(); | |
216 if ((tb.ty == TY.Tfunction || tb.ty == TY.Tsarray) && e.op == TOK.TOKvar) | |
217 { | |
218 VarExp ve = cast(VarExp)e; | |
219 var = new AliasDeclaration(loc, arg.ident, ve.var); | |
220 } | |
221 else | |
222 { | |
223 arg.type = e.type; | |
224 Initializer ie = new ExpInitializer(Loc(0), e); | |
225 VarDeclaration v = new VarDeclaration(loc, arg.type, arg.ident, ie); | |
226 if (e.isConst()) | |
227 v.storage_class |= STC.STCconst; | |
228 | |
229 var = v; | |
230 } | |
231 } | |
232 else | |
233 { | |
234 var = new AliasDeclaration(loc, arg.ident, t); | |
235 } | |
236 | |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
237 auto de = new DeclarationExp(loc, var); |
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
238 st.push(new ExpStatement(loc, de)); |
0 | 239 |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
240 st.push(body_.syntaxCopy()); |
0 | 241 s = new CompoundStatement(loc, st); |
242 s = new ScopeStatement(loc, s); | |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
243 statements.push(s); |
0 | 244 } |
245 | |
246 s = new UnrolledLoopStatement(loc, statements); | |
247 s = s.semantic(sc); | |
248 return s; | |
249 } | |
250 | |
251 sym = new ScopeDsymbol(); | |
252 sym.parent = sc.scopesym; | |
253 sc = sc.push(sym); | |
254 | |
255 sc.noctor++; | |
256 | |
96 | 257 Lagain: |
0 | 258 switch (tab.ty) |
259 { | |
260 case TY.Tarray: | |
261 case TY.Tsarray: | |
262 if (!checkForArgTypes()) | |
263 return this; | |
264 | |
265 if (dim < 1 || dim > 2) | |
266 { | |
267 error("only one or two arguments for array foreach"); | |
268 break; | |
269 } | |
270 | |
271 /* Look for special case of parsing char types out of char type | |
272 * array. | |
273 */ | |
274 tn = tab.nextOf().toBasetype(); | |
275 if (tn.ty == TY.Tchar || tn.ty == TY.Twchar || tn.ty == TY.Tdchar) | |
276 { | |
277 Argument arg; | |
278 | |
279 int i = (dim == 1) ? 0 : 1; // index of value | |
280 arg = cast(Argument)arguments.data[i]; | |
281 arg.type = arg.type.semantic(loc, sc); | |
282 tnv = arg.type.toBasetype(); | |
283 if (tnv.ty != tn.ty && (tnv.ty == TY.Tchar || tnv.ty == TY.Twchar || tnv.ty == TY.Tdchar)) | |
284 { | |
285 if (arg.storageClass & STC.STCref) | |
286 error("foreach: value of UTF conversion cannot be ref"); | |
287 if (dim == 2) | |
288 { | |
289 arg = cast(Argument)arguments.data[0]; | |
290 if (arg.storageClass & STC.STCref) | |
291 error("foreach: key cannot be ref"); | |
292 } | |
293 goto Lapply; | |
294 } | |
295 } | |
296 | |
297 for (size_t i = 0; i < dim; i++) | |
298 { | |
299 // Declare args | |
300 Argument arg = cast(Argument)arguments.data[i]; | |
301 Type argtype = arg.type.semantic(loc, sc); | |
302 VarDeclaration var = new VarDeclaration(loc, argtype, arg.ident, null); | |
303 var.storage_class |= STC.STCforeach; | |
304 var.storage_class |= arg.storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STC_TYPECTOR); | |
305 if (var.storage_class & (STC.STCref | STC.STCout)) | |
306 var.storage_class |= STC.STCnodtor; | |
307 | |
308 if (dim == 2 && i == 0) | |
309 { | |
310 key = var; | |
311 //var.storage_class |= STCfinal; | |
312 } | |
313 else | |
314 { | |
315 value = var; | |
316 /* Reference to immutable data should be marked as const | |
317 */ | |
318 if (var.storage_class & STC.STCref && !tn.isMutable()) | |
319 { | |
320 var.storage_class |= STC.STCconst; | |
321 } | |
322 } | |
96 | 323 static if (false) |
324 { | |
0 | 325 DeclarationExp de = new DeclarationExp(loc, var); |
326 de.semantic(sc); | |
327 } | |
328 } | |
329 | |
96 | 330 static if (true) |
331 { | |
0 | 332 { |
333 /* Convert to a ForStatement | |
334 * foreach (key, value; a) body => | |
335 * for (T[] tmp = a[], size_t key; key < tmp.length; ++key) | |
336 * { T value = tmp[k]; body } | |
337 * | |
338 * foreach_reverse (key, value; a) body => | |
339 * for (T[] tmp = a[], size_t key = tmp.length; key--; ) | |
340 * { T value = tmp[k]; body } | |
341 */ | |
342 Identifier id = Lexer.uniqueId("__aggr"); | |
343 ExpInitializer ie = new ExpInitializer(loc, new SliceExp(loc, aggr, null, null)); | |
344 VarDeclaration tmp = new VarDeclaration(loc, aggr.type.nextOf().arrayOf(), id, ie); | |
345 | |
346 Expression tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id.length); | |
347 | |
348 if (!key) | |
349 { | |
350 Identifier id2 = Lexer.uniqueId("__key"); | |
351 key = new VarDeclaration(loc, Type.tsize_t, id2, null); | |
352 } | |
353 | |
354 if (op == TOK.TOKforeach_reverse) | |
355 key.init = new ExpInitializer(loc, tmp_length); | |
356 else | |
357 key.init = new ExpInitializer(loc, new IntegerExp(0)); | |
358 | |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
359 auto cs = new Statements(); |
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
360 cs.push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); |
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
361 cs.push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); |
0 | 362 Statement forinit = new CompoundDeclarationStatement(loc, cs); |
363 | |
364 Expression cond; | |
365 if (op == TOK.TOKforeach_reverse) | |
366 // key-- | |
367 cond = new PostExp(TOK.TOKminusminus, loc, new VarExp(loc, key)); | |
368 else | |
369 // key < tmp.length | |
370 cond = new CmpExp(TOK.TOKlt, loc, new VarExp(loc, key), tmp_length); | |
371 | |
372 Expression increment = null; | |
373 if (op == TOK.TOKforeach) | |
374 // key += 1 | |
375 increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); | |
376 | |
377 // T value = tmp[key]; | |
378 value.init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key))); | |
379 Statement ds = new DeclarationStatement(loc, new DeclarationExp(loc, value)); | |
380 | |
381 body_ = new CompoundStatement(loc, ds, body_); | |
382 | |
383 ForStatement fs = new ForStatement(loc, forinit, cond, increment, body_); | |
384 s = fs.semantic(sc); | |
385 break; | |
386 } | |
387 } else { | |
388 if (tab.nextOf().implicitConvTo(value.type) < MATCH.MATCHconst) | |
389 { | |
390 if (aggr.op == TOK.TOKstring) | |
391 aggr = aggr.implicitCastTo(sc, value.type.arrayOf()); | |
392 else | |
393 error("foreach: %s is not an array of %s", | |
394 tab.toChars(), value.type.toChars()); | |
395 } | |
396 | |
397 if (key) | |
398 { | |
399 if (key.type.ty != Tint32 && key.type.ty != Tuns32) | |
400 { | |
401 if (global.params.isX86_64) | |
402 { | |
403 if (key.type.ty != Tint64 && key.type.ty != Tuns64) | |
404 error("foreach: key type must be int or uint, long or ulong, not %s", key.type.toChars()); | |
405 } | |
406 else | |
407 error("foreach: key type must be int or uint, not %s", key.type.toChars()); | |
408 } | |
409 | |
410 if (key.storage_class & (STCout | STCref)) | |
411 error("foreach: key cannot be out or ref"); | |
412 } | |
413 | |
414 sc.sbreak = this; | |
415 sc.scontinue = this; | |
416 body_ = body_.semantic(sc); | |
417 break; | |
418 } | |
419 | |
420 case TY.Taarray: | |
421 if (!checkForArgTypes()) | |
422 return this; | |
423 | |
424 taa = cast(TypeAArray)tab; | |
425 if (dim < 1 || dim > 2) | |
426 { | |
427 error("only one or two arguments for associative array foreach"); | |
428 break; | |
429 } | |
96 | 430 version(SARRAYVALUE) |
431 { | |
432 /* This only works if Key or Value is a static array. | |
433 */ | |
434 tab = taa.getImpl().type; | |
435 goto Lagain; | |
436 } | |
437 else | |
438 { | |
0 | 439 if (op == TOK.TOKforeach_reverse) |
440 { | |
441 error("no reverse iteration on associative arrays"); | |
442 } | |
443 goto Lapply; | |
96 | 444 } |
0 | 445 case TY.Tclass: |
446 case TY.Tstruct: | |
447 version (DMDV2) { | |
448 { /* Look for range iteration, i.e. the properties | |
449 * .empty, .next, .retreat, .head and .rear | |
450 * foreach (e; aggr) { ... } | |
451 * translates to: | |
452 * for (auto __r = aggr[]; !__r.empty; __r.next) | |
453 * { auto e = __r.head; | |
454 * ... | |
455 * } | |
456 */ | |
457 if (dim != 1) // only one argument allowed with ranges | |
458 goto Lapply; | |
459 | |
460 AggregateDeclaration ad = (tab.ty == TY.Tclass) | |
461 ? cast(AggregateDeclaration)(cast(TypeClass)tab).sym | |
462 : cast(AggregateDeclaration)(cast(TypeStruct)tab).sym; | |
463 | |
464 Identifier idhead; | |
465 Identifier idnext; | |
466 if (op == TOK.TOKforeach) | |
467 { | |
468 idhead = Id.Fhead; | |
469 idnext = Id.Fnext; | |
470 } | |
471 else | |
472 { | |
473 idhead = Id.Ftoe; | |
474 idnext = Id.Fretreat; | |
475 } | |
476 | |
477 Dsymbol shead = search_function(ad, idhead); | |
478 if (!shead) | |
479 goto Lapply; | |
480 | |
481 /* Generate a temporary __r and initialize it with the aggregate. | |
482 */ | |
483 Identifier id = Identifier.generateId("__r"); | |
484 Expression rinit = new SliceExp(loc, aggr, null, null); | |
485 rinit = rinit.trySemantic(sc); | |
486 if (!rinit) // if application of [] failed | |
487 rinit = aggr; | |
488 | |
489 VarDeclaration r = new VarDeclaration(loc, null, id, new ExpInitializer(loc, rinit)); | |
490 | |
491 // r.semantic(sc); | |
492 //printf("r: %s, init: %s\n", r.toChars(), r.init.toChars()); | |
493 Statement init = new DeclarationStatement(loc, r); | |
494 //printf("init: %s\n", init.toChars()); | |
495 | |
496 // !__r.empty | |
497 Expression e = new VarExp(loc, r); | |
498 e = new DotIdExp(loc, e, Id.Fempty); | |
499 Expression condition = new NotExp(loc, e); | |
500 | |
501 // __r.next | |
502 e = new VarExp(loc, r); | |
503 Expression increment = new DotIdExp(loc, e, idnext); | |
504 | |
505 /* Declaration statement for e: | |
506 * auto e = __r.idhead; | |
507 */ | |
508 e = new VarExp(loc, r); | |
509 Expression einit = new DotIdExp(loc, e, idhead); | |
510 // einit = einit.semantic(sc); | |
511 Argument arg = cast(Argument)arguments.data[0]; | |
512 VarDeclaration ve = new VarDeclaration(loc, arg.type, arg.ident, new ExpInitializer(loc, einit)); | |
513 ve.storage_class |= STC.STCforeach; | |
514 ve.storage_class |= arg.storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STC_TYPECTOR); | |
515 | |
516 DeclarationExp de = new DeclarationExp(loc, ve); | |
517 | |
518 Statement body2 = new CompoundStatement(loc, new DeclarationStatement(loc, de), this.body_); | |
519 s = new ForStatement(loc, init, condition, increment, body2); | |
520 | |
521 static if (false) { | |
522 printf("init: %s\n", init.toChars()); | |
523 printf("condition: %s\n", condition.toChars()); | |
524 printf("increment: %s\n", increment.toChars()); | |
525 printf("body: %s\n", body2.toChars()); | |
526 } | |
527 s = s.semantic(sc); | |
528 break; | |
529 } | |
530 } | |
531 case TY.Tdelegate: | |
532 Lapply: | |
533 { | |
534 FuncDeclaration fdapply; | |
535 Arguments args; | |
536 Expression ec; | |
537 Expression e; | |
538 FuncLiteralDeclaration fld; | |
539 Argument a; | |
540 Type t; | |
541 Expression flde; | |
542 Identifier id; | |
543 Type tret; | |
544 | |
545 if (!checkForArgTypes()) | |
546 { | |
547 body_ = body_.semantic(sc); | |
548 return this; | |
549 } | |
550 | |
551 tret = func.type.nextOf(); | |
552 | |
553 // Need a variable to hold value from any return statements in body. | |
554 if (!sc.func.vresult && tret && tret != Type.tvoid) | |
555 { | |
556 VarDeclaration v = new VarDeclaration(loc, tret, Id.result, null); | |
557 v.noauto = true; | |
558 v.semantic(sc); | |
559 if (!sc.insert(v)) | |
560 assert(0); | |
561 | |
562 v.parent = sc.func; | |
563 sc.func.vresult = v; | |
564 } | |
565 | |
566 /* Turn body into the function literal: | |
567 * int delegate(ref T arg) { body } | |
568 */ | |
569 args = new Arguments(); | |
570 for (size_t i = 0; i < dim; i++) | |
571 { | |
572 Argument arg = cast(Argument)arguments.data[i]; | |
573 | |
574 arg.type = arg.type.semantic(loc, sc); | |
575 if (arg.storageClass & STC.STCref) | |
576 id = arg.ident; | |
577 else | |
578 { // Make a copy of the ref argument so it isn't | |
579 // a reference. | |
580 VarDeclaration v; | |
581 Initializer ie; | |
582 | |
583 id = Lexer.uniqueId("__applyArg", i); | |
584 | |
585 ie = new ExpInitializer(Loc(0), new IdentifierExp(Loc(0), id)); | |
586 v = new VarDeclaration(Loc(0), arg.type, arg.ident, ie); | |
587 s = new DeclarationStatement(Loc(0), v); | |
588 body_ = new CompoundStatement(loc, s, body_); | |
589 } | |
590 a = new Argument(STC.STCref, arg.type, id, null); | |
591 args.push(cast(void*)a); | |
592 } | |
593 t = new TypeFunction(args, Type.tint32, 0, LINK.LINKd); | |
594 fld = new FuncLiteralDeclaration(loc, Loc(0), t, TOK.TOKdelegate, this); | |
595 fld.fbody = body_; | |
596 flde = new FuncExp(loc, fld); | |
597 flde = flde.semantic(sc); | |
598 fld.tookAddressOf = 0; | |
599 | |
600 // Resolve any forward referenced goto's | |
601 for (int i = 0; i < gotos.dim; i++) | |
602 { | |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
603 auto cs = cast(CompoundStatement)gotos.data[i]; |
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
604 auto gs = cast(GotoStatement)cs.statements[0]; |
0 | 605 |
606 if (!gs.label.statement) | |
607 { | |
608 // 'Promote' it to this scope, and replace with a return | |
609 cases.push(cast(void*)gs); | |
610 s = new ReturnStatement(Loc(0), new IntegerExp(cases.dim + 1)); | |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
611 cs.statements[0] = s; |
0 | 612 } |
613 } | |
614 | |
615 if (tab.ty == TY.Taarray) | |
616 { | |
617 // Check types | |
618 Argument arg = cast(Argument)arguments.data[0]; | |
619 if (dim == 2) | |
620 { | |
621 if (arg.storageClass & STC.STCref) | |
622 error("foreach: index cannot be ref"); | |
623 if (!arg.type.equals(taa.index)) | |
624 error("foreach: index must be type %s, not %s", taa.index.toChars(), arg.type.toChars()); | |
625 | |
626 arg = cast(Argument)arguments.data[1]; | |
627 } | |
628 if (!arg.type.equals(taa.nextOf())) | |
629 error("foreach: value must be type %s, not %s", taa.nextOf().toChars(), arg.type.toChars()); | |
630 | |
631 /* Call: | |
632 * _aaApply(aggr, keysize, flde) | |
633 */ | |
634 if (dim == 2) | |
635 fdapply = FuncDeclaration.genCfunc(Type.tindex, "_aaApply2"); | |
636 else | |
637 fdapply = FuncDeclaration.genCfunc(Type.tindex, "_aaApply"); | |
638 | |
639 ec = new VarExp(Loc(0), fdapply); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
640 auto exps = new Expressions(); |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
641 exps.push(aggr); |
0 | 642 size_t keysize = cast(uint)taa.index.size(); |
643 keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
644 exps.push(new IntegerExp(Loc(0), keysize, Type.tsize_t)); |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
645 exps.push(flde); |
0 | 646 e = new CallExp(loc, ec, exps); |
647 e.type = Type.tindex; // don't run semantic() on e | |
648 } | |
649 else if (tab.ty == TY.Tarray || tab.ty == TY.Tsarray) | |
650 { | |
651 /* Call: | |
652 * _aApply(aggr, flde) | |
653 */ | |
654 static char fntab[9][3] = | |
655 [ "cc","cw","cd", | |
656 "wc","cc","wd", | |
657 "dc","dw","dd" | |
658 ]; | |
659 char fdname[7+1+2+ dim.sizeof*3 + 1]; | |
660 int flag; | |
661 | |
662 switch (tn.ty) | |
663 { | |
664 case TY.Tchar: flag = 0; break; | |
665 case TY.Twchar: flag = 3; break; | |
666 case TY.Tdchar: flag = 6; break; | |
667 } | |
668 switch (tnv.ty) | |
669 { | |
670 case TY.Tchar: flag += 0; break; | |
671 case TY.Twchar: flag += 1; break; | |
672 case TY.Tdchar: flag += 2; break; | |
673 } | |
674 string r = (op == TOK.TOKforeach_reverse) ? "R" : ""; | |
73 | 675 int j = sprintf(fdname.ptr, "_aApply%.*s%.*s%zd".ptr, r, 2, fntab[flag].ptr, dim); |
0 | 676 assert(j < fdname.sizeof); |
677 fdapply = FuncDeclaration.genCfunc(Type.tindex, fdname[0..j].idup); | |
678 | |
679 ec = new VarExp(Loc(0), fdapply); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
680 auto exps = new Expressions(); |
0 | 681 if (tab.ty == TY.Tsarray) |
682 aggr = aggr.castTo(sc, tn.arrayOf()); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
683 exps.push(aggr); |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
684 exps.push(flde); |
0 | 685 e = new CallExp(loc, ec, exps); |
686 e.type = Type.tindex; // don't run semantic() on e | |
687 } | |
688 else if (tab.ty == TY.Tdelegate) | |
689 { | |
690 /* Call: | |
691 * aggr(flde) | |
692 */ | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
693 auto exps = new Expressions(); |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
694 exps.push(flde); |
0 | 695 e = new CallExp(loc, aggr, exps); |
696 e = e.semantic(sc); | |
697 if (e.type != Type.tint32) | |
698 error("opApply() function for %s must return an int", tab.toChars()); | |
699 } | |
700 else | |
701 { | |
702 assert(tab.ty == TY.Tstruct || tab.ty == TY.Tclass); | |
703 Identifier idapply = (op == TOK.TOKforeach_reverse) | |
704 ? Id.applyReverse : Id.apply; | |
705 Dsymbol sapply = search_function(cast(AggregateDeclaration)tab.toDsymbol(sc), idapply); | |
706 Expressions exps = new Expressions(); | |
707 static if (false) { | |
708 TemplateDeclaration td; | |
709 if (sapply && (td = sapply.isTemplateDeclaration()) !is null) | |
710 { | |
711 /* Call: | |
712 * aggr.apply!(fld)() | |
713 */ | |
714 TemplateInstance ti = new TemplateInstance(loc, idapply); | |
715 Objects tiargs = new Objects(); | |
716 tiargs.push(cast(void*)fld); | |
717 ti.tiargs = tiargs; | |
718 ec = new DotTemplateInstanceExp(loc, aggr, ti); | |
719 } | |
720 else | |
721 { | |
722 /* Call: | |
723 * aggr.apply(flde) | |
724 */ | |
725 ec = new DotIdExp(loc, aggr, idapply); | |
726 exps.push(cast(void*)flde); | |
727 } | |
728 } else { | |
729 ec = new DotIdExp(loc, aggr, idapply); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
73
diff
changeset
|
730 exps.push(flde); |
0 | 731 } |
732 e = new CallExp(loc, ec, exps); | |
733 e = e.semantic(sc); | |
734 if (e.type != Type.tint32) { | |
735 error("opApply() function for %s must return an int", tab.toChars()); | |
736 } | |
737 } | |
738 | |
739 if (!cases.dim) | |
740 { | |
741 // Easy case, a clean exit from the loop | |
742 s = new ExpStatement(loc, e); | |
743 } | |
744 else | |
745 { // Construct a switch statement around the return value | |
746 // of the apply function. | |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
747 auto a2 = new Statements(); |
0 | 748 |
749 // default: break; takes care of cases 0 and 1 | |
750 s = new BreakStatement(Loc(0), null); | |
751 s = new DefaultStatement(Loc(0), s); | |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
752 a2.push(s); |
0 | 753 |
754 // cases 2... | |
755 for (int i = 0; i < cases.dim; i++) | |
756 { | |
757 s = cast(Statement)cases.data[i]; | |
758 s = new CaseStatement(Loc(0), new IntegerExp(i + 2), s); | |
122
c77e9f4f1793
Statements -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
759 a2.push(s); |
0 | 760 } |
761 | |
762 s = new CompoundStatement(loc, a2); | |
763 s = new SwitchStatement(loc, e, s, false); | |
764 s = s.semantic(sc); | |
765 } | |
766 break; | |
767 } | |
768 | |
769 default: | |
770 error("foreach: %s is not an aggregate type", aggr.type.toChars()); | |
771 s = null; // error recovery | |
772 break; | |
773 } | |
774 | |
775 sc.noctor--; | |
776 sc.pop(); | |
777 return s; | |
778 } | |
779 | |
780 bool checkForArgTypes() | |
781 { | |
782 bool result = true; | |
783 | |
784 for (size_t i = 0; i < arguments.dim; i++) | |
785 { | |
786 Argument arg = cast(Argument)arguments.data[i]; | |
787 if (!arg.type) | |
788 { | |
789 error("cannot infer type for %s", arg.ident.toChars()); | |
790 arg.type = Type.terror; | |
791 result = false; | |
792 } | |
793 } | |
794 return result; | |
795 } | |
796 | |
72 | 797 override bool hasBreak() |
0 | 798 { |
66 | 799 return true; |
0 | 800 } |
801 | |
72 | 802 override bool hasContinue() |
0 | 803 { |
66 | 804 return true; |
0 | 805 } |
806 | |
72 | 807 override bool usesEH() |
0 | 808 { |
66 | 809 return body_.usesEH(); |
0 | 810 } |
811 | |
72 | 812 override BE blockExit() |
0 | 813 { |
66 | 814 BE result = BEfallthru; |
815 | |
816 if (aggr.canThrow()) | |
817 result |= BEthrow; | |
818 | |
819 if (body_) | |
820 { | |
821 result |= body_.blockExit() & ~(BEbreak | BEcontinue); | |
822 } | |
823 return result; | |
0 | 824 } |
825 | |
72 | 826 override bool comeFrom() |
0 | 827 { |
66 | 828 if (body_) |
829 return body_.comeFrom(); | |
830 | |
831 return false; | |
0 | 832 } |
833 | |
72 | 834 override Expression interpret(InterState istate) |
0 | 835 { |
836 assert(false); | |
837 } | |
838 | |
72 | 839 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 840 { |
66 | 841 buf.writestring(Token.toChars(op)); |
842 buf.writestring(" ("); | |
843 for (int i = 0; i < arguments.dim; i++) | |
844 { | |
845 Argument a = cast(Argument)arguments.data[i]; | |
846 if (i) | |
847 buf.writestring(", "); | |
848 if (a.storageClass & STCref) | |
849 buf.writestring((global.params.Dversion == 1) ? "inout " : "ref "); | |
850 if (a.type) | |
851 a.type.toCBuffer(buf, a.ident, hgs); | |
852 else | |
853 buf.writestring(a.ident.toChars()); | |
854 } | |
855 buf.writestring("; "); | |
856 aggr.toCBuffer(buf, hgs); | |
857 buf.writebyte(')'); | |
858 buf.writenl(); | |
859 buf.writebyte('{'); | |
860 buf.writenl(); | |
861 if (body_) | |
862 body_.toCBuffer(buf, hgs); | |
863 buf.writebyte('}'); | |
864 buf.writenl(); | |
0 | 865 } |
866 | |
72 | 867 override Statement inlineScan(InlineScanState* iss) |
0 | 868 { |
869 aggr = aggr.inlineScan(iss); | |
870 if (body_) | |
871 body_ = body_.inlineScan(iss); | |
872 return this; | |
873 } | |
874 | |
72 | 875 override void toIR(IRState* irs) |
0 | 876 { |
877 assert(false); | |
878 } | |
72 | 879 } |