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