Mercurial > projects > ddmd
annotate dmd/StructLiteralExp.d @ 109:ceda59b4d255
expression.c changes, now only ddoc should be left
author | Trass3r |
---|---|
date | Tue, 31 Aug 2010 22:08:52 +0200 |
parents | 39648eb578f6 |
children | e28b18c23469 |
rev | line source |
---|---|
72 | 1 module dmd.StructLiteralExp; |
2 | |
3 import dmd.Expression; | |
4 import dmd.MOD; | |
5 import dmd.TypeStruct; | |
6 import dmd.TypeSArray; | |
7 import dmd.expression.Util; | |
8 import dmd.ErrorExp; | |
9 import dmd.Dsymbol; | |
10 import dmd.VarDeclaration; | |
11 import dmd.StructDeclaration; | |
12 import dmd.FuncDeclaration; | |
13 import dmd.ThisDeclaration; | |
14 import dmd.backend.elem; | |
15 import dmd.InterState; | |
16 import dmd.MATCH; | |
17 import dmd.WANT; | |
18 import dmd.TY; | |
19 import dmd.Type; | |
20 import dmd.OutBuffer; | |
21 import dmd.Loc; | |
22 import dmd.Scope; | |
109 | 23 import dmd.Initializer; |
72 | 24 import dmd.InlineCostState; |
25 import dmd.IRState; | |
26 import dmd.InlineDoState; | |
27 import dmd.backend.Symbol; | |
28 import dmd.HdrGenState; | |
29 import dmd.backend.dt_t; | |
30 import dmd.InlineScanState; | |
79 | 31 import dmd.ArrayLiteralExp; |
72 | 32 import dmd.ArrayTypes; |
33 import dmd.TOK; | |
34 | |
35 import dmd.codegen.Util; | |
36 import dmd.backend.Util; | |
37 import dmd.backend.RTLSYM; | |
38 import dmd.backend.TYM; | |
39 import dmd.backend.mTY; | |
40 import dmd.backend.OPER; | |
41 | |
42 | |
0 | 43 class StructLiteralExp : Expression |
44 { | |
72 | 45 StructDeclaration sd; // which aggregate this is for |
79 | 46 Expressions elements; // parallels sd.fields[] with |
72 | 47 // NULL entries for fields to skip |
48 | |
49 Symbol* sym; // back end symbol to initialize with literal | |
50 size_t soffset; // offset from start of s | |
0 | 51 int fillHoles; // fill alignment 'holes' with zero |
52 | |
53 this(Loc loc, StructDeclaration sd, Expressions elements) | |
54 { | |
72 | 55 super(loc, TOKstructliteral, StructLiteralExp.sizeof); |
56 this.sd = sd; | |
57 this.elements = elements; | |
58 this.sym = null; | |
59 this.soffset = 0; | |
60 this.fillHoles = 1; | |
0 | 61 } |
62 | |
72 | 63 override Expression syntaxCopy() |
0 | 64 { |
65 assert(false); | |
66 } | |
67 | |
72 | 68 override Expression semantic(Scope sc) |
0 | 69 { |
72 | 70 Expression e; |
71 int nfields = sd.fields.dim - sd.isnested; | |
72 | |
73 version (LOGSEMANTIC) { | |
74 printf("StructLiteralExp.semantic('%s')\n", toChars()); | |
75 } | |
76 if (type) | |
77 return this; | |
78 | |
79 // Run semantic() on each element | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
80 foreach(size_t i, Expression e; elements) |
72 | 81 { |
82 if (!e) | |
83 continue; | |
84 e = e.semantic(sc); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
85 elements[i] = e; |
72 | 86 } |
87 expandTuples(elements); | |
88 size_t offset = 0; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
89 foreach(size_t i, Expression e; elements) |
72 | 90 { |
91 if (!e) | |
92 continue; | |
93 | |
94 if (!e.type) | |
95 error("%s has no value", e.toChars()); | |
96 e = resolveProperties(sc, e); | |
97 if (i >= nfields) | |
98 { | |
99 error("more initializers than fields of %s", sd.toChars()); | |
100 return new ErrorExp(); | |
101 } | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
102 auto s = sd.fields[i]; |
72 | 103 VarDeclaration v = s.isVarDeclaration(); |
104 assert(v); | |
105 if (v.offset < offset) | |
106 error("overlapping initialization for %s", v.toChars()); | |
107 offset = v.offset + cast(uint)v.type.size(); | |
108 | |
109 Type telem = v.type; | |
110 while (!e.implicitConvTo(telem) && telem.toBasetype().ty == Tsarray) | |
111 { | |
112 /* Static array initialization, as in: | |
113 * T[3][5] = e; | |
114 */ | |
115 telem = telem.toBasetype().nextOf(); | |
116 } | |
117 | |
118 e = e.implicitCastTo(sc, telem); | |
119 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
120 elements[i] = e; |
72 | 121 } |
122 | |
123 /* Fill out remainder of elements[] with default initializers for fields[] | |
124 */ | |
125 for (size_t i = elements.dim; i < nfields; i++) | |
126 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
127 VarDeclaration v = sd.fields[i]; |
72 | 128 assert(v); |
129 assert(!v.isThisDeclaration()); | |
130 | |
131 if (v.offset < offset) | |
132 { | |
133 e = null; | |
134 sd.hasUnions = 1; | |
135 } | |
136 else | |
137 { | |
138 if (v.init) | |
139 { | |
140 e = v.init.toExpression(); | |
141 if (!e) | |
109 | 142 { |
72 | 143 error("cannot make expression out of initializer for %s", v.toChars()); |
109 | 144 e = new ErrorExp(); |
145 } | |
146 else if (v.scope_) | |
147 { | |
148 // Do deferred semantic anaylsis | |
149 Initializer i2 = v.init.syntaxCopy(); | |
150 i2 = i2.semantic(v.scope_, v.type); | |
151 e = i2.toExpression(); | |
152 v.scope_ = null; | |
153 } | |
72 | 154 } |
155 else | |
156 { | |
157 e = v.type.defaultInit(Loc(0)); | |
158 e.loc = loc; | |
159 } | |
160 offset = v.offset + cast(uint)v.type.size(); | |
161 } | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
162 elements.push(e); |
72 | 163 } |
164 | |
165 type = sd.type; | |
63 | 166 return this; |
0 | 167 } |
168 | |
109 | 169 /************************************** |
170 * Gets expression at offset of type. | |
171 * Returns null if not found. | |
172 */ | |
0 | 173 Expression getField(Type type, uint offset) |
174 { | |
79 | 175 //printf("StructLiteralExp.getField(this = %s, type = %s, offset = %u)\n", |
176 // /*toChars()*/"", type.toChars(), offset); | |
177 Expression e = null; | |
178 int i = getFieldIndex(type, offset); | |
179 | |
180 if (i != -1) | |
181 { | |
182 //printf("\ti = %d\n", i); | |
183 assert(i < elements.dim); | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
85
diff
changeset
|
184 e = elements[i]; |
79 | 185 if (e) |
186 { | |
187 //writef("e = %s, e.type = %s\n", e.toChars(), e.type.toChars()); | |
188 | |
189 /* If type is a static array, and e is an initializer for that array, | |
190 * then the field initializer should be an array literal of e. | |
191 */ | |
192 if (e.type != type && type.ty == Tsarray) | |
193 { | |
194 TypeSArray tsa = cast(TypeSArray)type; | |
195 size_t length = cast(size_t) tsa.dim.toInteger(); | |
196 Expressions z = new Expressions; | |
197 z.setDim(length); | |
198 for (int q = 0; q < length; ++q) | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
85
diff
changeset
|
199 z[q] = e.copy(); |
79 | 200 e = new ArrayLiteralExp(loc, z); |
201 e.type = type; | |
202 } | |
203 else | |
204 { | |
205 e = e.copy(); | |
206 e.type = type; | |
207 } | |
208 } | |
209 } | |
210 return e; | |
0 | 211 } |
212 | |
213 int getFieldIndex(Type type, uint offset) | |
214 { | |
79 | 215 /* Find which field offset is by looking at the field offsets |
216 */ | |
217 if (elements.dim) | |
218 { | |
85
8e69d041a99d
Previous commit didn't compile. Fixed.
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
219 foreach (size_t i, VarDeclaration v; sd.fields) |
79 | 220 { |
221 assert(v); | |
222 | |
223 if (offset == v.offset && type.size() == v.type.size()) | |
224 { | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
85
diff
changeset
|
225 auto e = elements[i]; |
79 | 226 if (e) |
227 { | |
228 return i; | |
229 } | |
230 break; | |
231 } | |
232 } | |
233 } | |
234 return -1; | |
0 | 235 } |
236 | |
72 | 237 override elem* toElem(IRState* irs) |
0 | 238 { |
72 | 239 elem* e; |
240 size_t dim; | |
241 | |
242 //printf("StructLiteralExp.toElem() %s\n", toChars()); | |
243 | |
244 // struct symbol to initialize with the literal | |
245 Symbol* stmp = sym ? sym : symbol_genauto(sd.type.toCtype()); | |
246 | |
247 e = null; | |
248 | |
249 if (fillHoles) | |
250 { | |
251 /* Initialize all alignment 'holes' to zero. | |
252 * Do before initializing fields, as the hole filling process | |
253 * can spill over into the fields. | |
254 */ | |
255 size_t offset = 0; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
256 foreach (VarDeclaration v; sd.fields) |
72 | 257 { |
258 assert(v); | |
259 | |
260 e = el_combine(e, fillHole(stmp, &offset, v.offset, sd.structsize)); | |
261 size_t vend = v.offset + cast(uint)v.type.size(); | |
262 if (offset < vend) | |
263 offset = vend; | |
264 } | |
265 e = el_combine(e, fillHole(stmp, &offset, sd.structsize, sd.structsize)); | |
266 } | |
267 | |
268 if (elements) | |
269 { | |
270 dim = elements.dim; | |
271 assert(dim <= sd.fields.dim); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
272 foreach (size_t i, Expression el; elements) |
72 | 273 { |
274 if (!el) | |
275 continue; | |
276 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
277 VarDeclaration v = sd.fields[i]; |
72 | 278 assert(v); |
279 assert(!v.isThisDeclaration()); | |
280 | |
281 elem* e1; | |
282 if (tybasic(stmp.Stype.Tty) == TYnptr) | |
283 { | |
284 e1 = el_var(stmp); | |
285 e1.EV.sp.Voffset = soffset; | |
286 } | |
287 else | |
288 { | |
289 e1 = el_ptr(stmp); | |
290 if (soffset) | |
291 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset)); | |
292 } | |
293 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); | |
294 elem* ec = e1; // pointer to destination | |
295 | |
296 elem* ep = el.toElem(irs); | |
297 | |
298 Type t1b = v.type.toBasetype(); | |
299 Type t2b = el.type.toBasetype(); | |
300 if (t1b.ty == Tsarray) | |
301 { | |
302 if (t2b.implicitConvTo(t1b)) | |
303 { | |
304 ///version (DMDV2) { | |
305 // Determine if postblit is needed | |
306 int postblit = 0; | |
307 if (needsPostblit(t1b)) | |
308 postblit = 1; | |
309 | |
310 if (postblit) | |
311 { | |
312 /* Generate: | |
313 * _d_arrayctor(ti, From: ep, To: e1) | |
314 */ | |
315 Expression ti = t1b.nextOf().toBasetype().getTypeInfo(null); | |
316 elem* esize = el_long(TYsize_t, (cast(TypeSArray)t1b).dim.toInteger()); | |
317 e1 = el_pair(TYdarray, esize, e1); | |
318 ep = el_pair(TYdarray, el_copytree(esize), array_toPtr(el.type, ep)); | |
319 ep = el_params(e1, ep, ti.toElem(irs), null); | |
320 int rtl = RTLSYM_ARRAYCTOR; | |
321 e1 = el_bin(OPcall, type.totym(), el_var(rtlsym[rtl]), ep); | |
322 } | |
323 else | |
324 ///} | |
325 { | |
326 elem* esize = el_long(TYsize_t, t1b.size()); | |
327 ep = array_toPtr(el.type, ep); | |
328 e1 = el_bin(OPmemcpy, TYnptr, e1, el_param(ep, esize)); | |
329 } | |
330 } | |
331 else | |
332 { | |
333 elem* edim = el_long(TYsize_t, t1b.size() / t2b.size()); | |
334 e1 = setArray(e1, edim, t2b, ep, irs, TOKconstruct); | |
335 } | |
336 } | |
337 else | |
338 { | |
339 tym_t ty = v.type.totym(); | |
340 e1 = el_una(OPind, ty, e1); | |
341 if (tybasic(ty) == TYstruct) | |
342 e1.Enumbytes = cast(uint)v.type.size(); | |
343 e1 = el_bin(OPeq, ty, e1, ep); | |
344 if (tybasic(ty) == TYstruct) | |
345 { | |
346 e1.Eoper = OPstreq; | |
347 e1.Enumbytes = cast(uint)v.type.size(); | |
348 } | |
349 version (DMDV2) { | |
350 /* Call postblit() on e1 | |
351 */ | |
352 StructDeclaration sd = needsPostblit(v.type); | |
353 if (sd) | |
354 { | |
355 FuncDeclaration fd = sd.postblit; | |
356 ec = el_copytree(ec); | |
357 ec = callfunc(loc, irs, 1, Type.tvoid, ec, sd.type.pointerTo(), fd, fd.type, null, null); | |
358 e1 = el_bin(OPcomma, ec.Ety, e1, ec); | |
359 } | |
360 } | |
361 } | |
362 e = el_combine(e, e1); | |
363 } | |
364 } | |
365 | |
79 | 366 version (DMDV2) |
367 { | |
72 | 368 if (sd.isnested) |
369 { // Initialize the hidden 'this' pointer | |
370 assert(sd.fields.dim); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
371 auto s = sd.fields[sd.fields.dim - 1]; |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
372 auto v = s.isThisDeclaration(); |
72 | 373 assert(v); |
374 | |
375 elem* e1; | |
376 if (tybasic(stmp.Stype.Tty) == TYnptr) | |
377 { | |
378 e1 = el_var(stmp); | |
379 e1.EV.sp.Voffset = soffset; | |
380 } | |
381 else | |
382 { | |
383 e1 = el_ptr(stmp); | |
384 if (soffset) | |
385 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset)); | |
386 } | |
387 e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); | |
388 e1 = setEthis(loc, irs, e1, sd); | |
389 | |
390 e = el_combine(e, e1); | |
391 } | |
392 } | |
393 | |
394 elem* ev = el_var(stmp); | |
395 ev.Enumbytes = sd.structsize; | |
396 e = el_combine(e, ev); | |
397 el_setLoc(e,loc); | |
67 | 398 return e; |
0 | 399 } |
400 | |
72 | 401 override bool checkSideEffect(int flag) |
0 | 402 { |
79 | 403 bool f = 0; |
404 | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
85
diff
changeset
|
405 foreach (e; elements) |
79 | 406 { |
407 if (!e) | |
408 continue; | |
409 | |
410 f |= e.checkSideEffect(2); | |
411 } | |
412 if (flag == 0 && f == 0) | |
413 Expression.checkSideEffect(0); | |
414 return f; | |
0 | 415 } |
416 | |
72 | 417 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 418 { |
79 | 419 buf.writestring(sd.toChars()); |
420 buf.writeByte('('); | |
421 argsToCBuffer(buf, elements, hgs); | |
422 buf.writeByte(')'); | |
0 | 423 } |
424 | |
72 | 425 override void toMangleBuffer(OutBuffer buf) |
0 | 426 { |
79 | 427 size_t dim = elements ? elements.dim : 0; |
428 buf.printf("S%u", dim); | |
429 for (size_t i = 0; i < dim; i++) | |
430 { | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
85
diff
changeset
|
431 auto e = elements[i]; |
79 | 432 if (e) |
433 e.toMangleBuffer(buf); | |
434 else | |
435 buf.writeByte('v'); // 'v' for void | |
436 } | |
0 | 437 } |
438 | |
72 | 439 override void scanForNestedRef(Scope sc) |
0 | 440 { |
441 assert(false); | |
442 } | |
443 | |
72 | 444 override Expression optimize(int result) |
0 | 445 { |
72 | 446 if (elements) |
447 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
448 foreach (size_t i, Expression e; elements) |
72 | 449 { |
450 if (!e) | |
451 continue; | |
452 e = e.optimize(WANTvalue | (result & WANTinterpret)); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
453 elements[i] = e; |
72 | 454 } |
455 } | |
56 | 456 return this; |
0 | 457 } |
458 | |
72 | 459 override Expression interpret(InterState istate) |
0 | 460 { |
461 assert(false); | |
462 } | |
463 | |
72 | 464 override dt_t** toDt(dt_t** pdt) |
0 | 465 { |
466 assert(false); | |
467 } | |
468 | |
79 | 469 version(DMDV2) |
470 { | |
72 | 471 override int isLvalue() |
0 | 472 { |
79 | 473 return 1; |
0 | 474 } |
79 | 475 } |
0 | 476 |
72 | 477 override Expression toLvalue(Scope sc, Expression e) |
0 | 478 { |
79 | 479 return this; |
0 | 480 } |
481 | |
79 | 482 version(DMDV2) |
483 { | |
72 | 484 override bool canThrow() |
0 | 485 { |
64 | 486 return arrayExpressionCanThrow(elements); |
0 | 487 } |
79 | 488 } |
0 | 489 |
72 | 490 override MATCH implicitConvTo(Type t) |
0 | 491 { |
72 | 492 static if (false) { |
493 printf("StructLiteralExp.implicitConvTo(this=%.*s, type=%.*s, t=%.*s)\n", | |
494 toChars(), type.toChars(), t.toChars()); | |
495 } | |
496 MATCH m = Expression.implicitConvTo(t); | |
497 if (m != MATCHnomatch) | |
498 return m; | |
499 if (type.ty == t.ty && type.ty == Tstruct && (cast(TypeStruct)type).sym == (cast(TypeStruct)t).sym) | |
500 { | |
501 m = MATCHconst; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
502 foreach(e; elements) |
72 | 503 { |
504 Type te = e.type; | |
505 if (t.mod == 0) | |
506 te = te.mutableOf(); | |
507 else | |
508 { | |
509 assert(t.mod == MODinvariant); | |
510 te = te.invariantOf(); | |
511 } | |
512 MATCH m2 = e.implicitConvTo(te); | |
513 //printf("\t%s => %s, match = %d\n", e.toChars(), te.toChars(), m2); | |
514 if (m2 < m) | |
515 m = m2; | |
516 } | |
517 } | |
64 | 518 return m; |
0 | 519 } |
520 | |
72 | 521 override int inlineCost(InlineCostState* ics) |
0 | 522 { |
523 assert(false); | |
524 } | |
525 | |
72 | 526 override Expression doInline(InlineDoState ids) |
0 | 527 { |
528 assert(false); | |
529 } | |
530 | |
72 | 531 override Expression inlineScan(InlineScanState* iss) |
0 | 532 { |
533 assert(false); | |
534 } | |
535 } | |
536 |