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