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