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