0
|
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 } |