comparison dmd/ForeachStatement.d @ 0:10317f0c89a5

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