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