Mercurial > projects > ddmd
annotate dmd/StructInitializer.d @ 130:60bb0fe4563e
dmdfe 2.037 first main iteration
author | Eldar Insafutdinov <e.insafutdinov@gmail.com> |
---|---|
date | Thu, 09 Sep 2010 22:51:44 +0100 |
parents | e6e542f37b94 |
children | af1bebfd96a4 |
rev | line source |
---|---|
0 | 1 module dmd.StructInitializer; |
2 | |
114 | 3 import dmd.common; |
0 | 4 import dmd.Initializer; |
2 | 5 import dmd.TOK; |
67 | 6 import dmd.TypeSArray; |
2 | 7 import dmd.FuncLiteralDeclaration; |
8 import dmd.TypeFunction; | |
56 | 9 import dmd.StructDeclaration; |
10 import dmd.StructLiteralExp; | |
0 | 11 import dmd.ArrayTypes; |
12 import dmd.Array; | |
13 import dmd.Loc; | |
14 import dmd.Type; | |
15 import dmd.Scope; | |
16 import dmd.Identifier; | |
2 | 17 import dmd.CompoundStatement; |
0 | 18 import dmd.AggregateDeclaration; |
19 import dmd.OutBuffer; | |
20 import dmd.HdrGenState; | |
21 import dmd.Expression; | |
2 | 22 import dmd.TypeStruct; |
23 import dmd.TY; | |
24 import dmd.VarDeclaration; | |
25 import dmd.Dsymbol; | |
26 import dmd.Util; | |
27 import dmd.ExpInitializer; | |
28 import dmd.FuncExp; | |
29 import dmd.LINK; | |
0 | 30 |
31 import dmd.backend.dt_t; | |
67 | 32 import dmd.backend.Util; |
0 | 33 |
34 class StructInitializer : Initializer | |
35 { | |
36 Identifiers field; // of Identifier *'s | |
37 Initializers value; // parallel array of Initializer *'s | |
38 | |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
39 VarDeclarations vars; // parallel array of VarDeclaration *'s |
0 | 40 AggregateDeclaration ad; // which aggregate this is for |
41 | |
42 this(Loc loc) | |
43 { | |
44 super(loc); | |
2 | 45 ad = null; |
46 | |
47 field = new Identifiers(); | |
48 value = new Initializers(); | |
51 | 49 |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
50 vars = new VarDeclarations(); |
0 | 51 } |
52 | |
72 | 53 override Initializer syntaxCopy() |
0 | 54 { |
127
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
55 auto ai = new StructInitializer(loc); |
2 | 56 |
57 assert(field.dim == value.dim); | |
58 ai.field.setDim(field.dim); | |
59 ai.value.setDim(value.dim); | |
60 for (int i = 0; i < field.dim; i++) | |
61 { | |
127
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
62 ai.field[i] = field[i]; |
2 | 63 |
127
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
64 auto init = value[i]; |
2 | 65 init = init.syntaxCopy(); |
127
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
66 ai.value[i] = init; |
2 | 67 } |
68 | |
69 return ai; | |
0 | 70 } |
71 | |
72 void addInit(Identifier field, Initializer value) | |
73 { | |
2 | 74 //printf("StructInitializer.addInit(field = %p, value = %p)\n", field, value); |
127
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
75 this.field.push(field); |
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
76 this.value.push(value); |
0 | 77 } |
78 | |
72 | 79 override Initializer semantic(Scope sc, Type t) |
0 | 80 { |
2 | 81 TypeStruct ts; |
82 int errors = 0; | |
83 | |
84 //printf("StructInitializer.semantic(t = %s) %s\n", t.toChars(), toChars()); | |
85 vars.setDim(field.dim); | |
86 t = t.toBasetype(); | |
87 if (t.ty == Tstruct) | |
88 { | |
89 uint i; | |
90 uint fieldi = 0; | |
91 | |
92 ts = cast(TypeStruct)t; | |
93 ad = ts.sym; | |
94 for (i = 0; i < field.dim; i++) | |
95 { | |
127
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
96 Identifier id = field[i]; |
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
97 Initializer val = value[i]; |
2 | 98 Dsymbol s; |
99 VarDeclaration v; | |
100 | |
101 if (id is null) | |
102 { | |
103 if (fieldi >= ad.fields.dim) | |
104 { | |
105 error(loc, "too many initializers for %s", ad.toChars()); | |
106 field.remove(i); | |
107 i--; | |
108 continue; | |
109 } | |
110 else | |
111 { | |
79 | 112 s = ad.fields[fieldi]; |
2 | 113 } |
114 } | |
115 else | |
116 { | |
117 //s = ad.symtab.lookup(id); | |
118 s = ad.search(loc, id, 0); | |
119 if (!s) | |
120 { | |
121 error(loc, "'%s' is not a member of '%s'", id.toChars(), t.toChars()); | |
122 continue; | |
123 } | |
124 | |
125 // Find out which field index it is | |
126 for (fieldi = 0; 1; fieldi++) | |
127 { | |
128 if (fieldi >= ad.fields.dim) | |
129 { | |
130 s.error("is not a per-instance initializable field"); | |
131 break; | |
132 } | |
79 | 133 if (s == ad.fields[fieldi]) |
2 | 134 break; |
135 } | |
136 } | |
137 if (s && (v = s.isVarDeclaration()) !is null) | |
138 { | |
139 val = val.semantic(sc, v.type); | |
127
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
140 value[i] = val; |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
141 vars[i] = v; |
2 | 142 } |
143 else | |
144 { | |
145 error(loc, "%s is not a field of %s", id ? id.toChars() : s.toChars(), ad.toChars()); | |
146 errors = 1; | |
147 } | |
148 fieldi++; | |
149 } | |
150 } | |
151 else if (t.ty == Tdelegate && value.dim == 0) | |
152 { | |
153 /* Rewrite as empty delegate literal { } | |
154 */ | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
128
diff
changeset
|
155 auto arguments = new Parameters; |
2 | 156 Type tf = new TypeFunction(arguments, null, 0, LINK.LINKd); |
157 FuncLiteralDeclaration fd = new FuncLiteralDeclaration(loc, Loc(0), tf, TOK.TOKdelegate, null); | |
158 fd.fbody = new CompoundStatement(loc, new Statements()); | |
159 fd.endloc = loc; | |
160 Expression e = new FuncExp(loc, fd); | |
161 ExpInitializer ie = new ExpInitializer(loc, e); | |
162 return ie.semantic(sc, t); | |
163 } | |
164 else | |
165 { | |
166 error(loc, "a struct is not a valid initializer for a %s", t.toChars()); | |
167 errors = 1; | |
168 } | |
169 if (errors) | |
170 { | |
171 field.setDim(0); | |
172 value.setDim(0); | |
173 vars.setDim(0); | |
174 } | |
175 return this; | |
0 | 176 } |
177 | |
56 | 178 /*************************************** |
179 * This works by transforming a struct initializer into | |
180 * a struct literal. In the future, the two should be the | |
181 * same thing. | |
182 */ | |
72 | 183 override Expression toExpression() |
0 | 184 { |
56 | 185 Expression e; |
186 | |
187 //printf("StructInitializer.toExpression() %s\n", toChars()); | |
188 if (!ad) // if fwd referenced | |
189 { | |
190 return null; | |
191 } | |
192 StructDeclaration sd = ad.isStructDeclaration(); | |
193 if (!sd) | |
194 return null; | |
195 Expressions elements = new Expressions(); | |
196 for (size_t i = 0; i < value.dim; i++) | |
197 { | |
127
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
198 if (field[i]) |
56 | 199 goto Lno; |
127
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
200 Initializer iz = value[i]; |
56 | 201 if (!iz) |
202 goto Lno; | |
203 Expression ex = iz.toExpression(); | |
204 if (!ex) | |
205 goto Lno; | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
206 elements.push(ex); |
56 | 207 } |
208 e = new StructLiteralExp(loc, sd, elements); | |
209 e.type = sd.type; | |
210 return e; | |
211 | |
212 Lno: | |
213 delete elements; | |
214 //error(loc, "struct initializers as expressions are not allowed"); | |
215 return null; | |
0 | 216 } |
217 | |
72 | 218 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 219 { |
220 assert(false); | |
221 } | |
222 | |
72 | 223 override dt_t* toDt() |
0 | 224 { |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
225 scope dts = new Vector!(dt_t*); |
67 | 226 uint i; |
227 uint j; | |
228 dt_t* dt; | |
229 dt_t* d; | |
230 dt_t** pdtend; | |
231 uint offset; | |
232 | |
233 //printf("StructInitializer.toDt('%s')\n", toChars()); | |
234 dts.setDim(ad.fields.dim); | |
235 dts.zero(); | |
236 | |
237 for (i = 0; i < vars.dim; i++) | |
238 { | |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
239 VarDeclaration v = vars[i]; |
127
9ee9b55452cb
Identifiers, Initializers -> Vector
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
240 Initializer val = value[i]; |
67 | 241 |
242 //printf("vars[%d] = %s\n", i, v.toChars()); | |
243 | |
244 for (j = 0; 1; j++) | |
245 { | |
246 assert(j < dts.dim); | |
79 | 247 //printf(" adfield[%d] = %s\n", j, ((VarDeclaration *)ad.fields[j]).toChars()); |
248 if (cast(VarDeclaration)ad.fields[j] == v) // TODO: check if 'is' needs to be used here | |
67 | 249 { |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
250 if (dts[j]) |
67 | 251 error(loc, "field %s of %s already initialized", v.toChars(), ad.toChars()); |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
252 dts[j] = val.toDt(); |
67 | 253 break; |
254 } | |
255 } | |
256 } | |
257 | |
258 dt = null; | |
259 pdtend = &dt; | |
260 offset = 0; | |
261 for (j = 0; j < dts.dim; j++) | |
262 { | |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
263 VarDeclaration v = ad.fields[j]; |
67 | 264 |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
265 d = dts[j]; |
67 | 266 if (!d) |
267 { | |
268 // An instance specific initializer was not provided. | |
269 // Look to see if there's a default initializer from the | |
270 // struct definition | |
271 if (v.init) | |
272 { | |
273 d = v.init.toDt(); | |
274 } | |
275 else if (v.offset >= offset) | |
276 { | |
277 uint k; | |
278 uint offset2 = v.offset + cast(uint)v.type.size(); | |
279 // Make sure this field does not overlap any explicitly | |
280 // initialized field. | |
281 for (k = j + 1; 1; k++) | |
282 { | |
283 if (k == dts.dim) // didn't find any overlap | |
284 { | |
285 v.type.toDt(&d); | |
286 break; | |
287 } | |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
288 VarDeclaration v2 = ad.fields[k]; |
67 | 289 |
128
e6e542f37b94
Some more Array -> Vector conversions
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
127
diff
changeset
|
290 if (v2.offset < offset2 && dts[k]) |
67 | 291 break; // overlap |
292 } | |
293 } | |
294 } | |
295 if (d) | |
296 { | |
297 if (v.offset < offset) | |
298 error(loc, "duplicate union initialization for %s", v.toChars()); | |
299 else | |
300 { | |
301 uint sz = dt_size(d); | |
302 uint vsz = cast(uint)v.type.size(); | |
303 uint voffset = v.offset; | |
304 | |
305 uint dim = 1; | |
306 for (Type vt = v.type.toBasetype(); | |
307 vt.ty == Tsarray; | |
308 vt = vt.nextOf().toBasetype()) | |
309 { | |
310 TypeSArray tsa = cast(TypeSArray)vt; | |
311 dim *= tsa.dim.toInteger(); | |
312 } | |
313 assert(sz == vsz || sz * dim <= vsz); | |
314 | |
315 for (size_t k = 0; k < dim; k++) | |
316 { | |
317 if (offset < voffset) | |
318 pdtend = dtnzeros(pdtend, voffset - offset); | |
319 if (!d) | |
320 { | |
321 if (v.init) | |
322 d = v.init.toDt(); | |
323 else | |
324 v.type.toDt(&d); | |
325 } | |
326 pdtend = dtcat(pdtend, d); | |
327 d = null; | |
328 offset = voffset + sz; | |
329 voffset += vsz / dim; | |
330 if (sz == vsz) | |
331 break; | |
332 } | |
333 } | |
334 } | |
335 } | |
336 | |
337 if (offset < ad.structsize) | |
338 dtnzeros(pdtend, ad.structsize - offset); | |
339 | |
340 return dt; | |
0 | 341 } |
342 | |
72 | 343 override StructInitializer isStructInitializer() { return this; } |
344 } |