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