72
|
1 module dmd.AssocArrayLiteralExp;
|
|
2
|
|
3 import dmd.Expression;
|
|
4 import dmd.GlobalExpressions;
|
|
5 import dmd.WANT;
|
|
6 import dmd.expression.Equal;
|
|
7 import dmd.backend.elem;
|
|
8 import dmd.InterState;
|
|
9 import dmd.MATCH;
|
|
10 import dmd.Type;
|
|
11 import dmd.TypeAArray;
|
|
12 import dmd.OutBuffer;
|
|
13 import dmd.Loc;
|
|
14 import dmd.Scope;
|
|
15 import dmd.InlineCostState;
|
|
16 import dmd.IRState;
|
|
17 import dmd.TY;
|
|
18 import dmd.InlineDoState;
|
|
19 import dmd.HdrGenState;
|
|
20 import dmd.InlineScanState;
|
|
21 import dmd.ArrayTypes;
|
|
22 import dmd.TOK;
|
|
23 import dmd.PREC;
|
|
24 import dmd.expression.Util;
|
|
25 import dmd.backend.Util;
|
|
26 import dmd.backend.TYM;
|
|
27 import dmd.backend.mTY;
|
|
28 import dmd.backend.OPER;
|
|
29 import dmd.backend.RTLSYM;
|
|
30
|
|
31 class AssocArrayLiteralExp : Expression
|
|
32 {
|
|
33 Expressions keys;
|
|
34 Expressions values;
|
|
35
|
|
36 this(Loc loc, Expressions keys, Expressions values)
|
|
37 {
|
|
38 super(loc, TOK.TOKassocarrayliteral, this.sizeof);
|
|
39 assert(keys.dim == values.dim);
|
|
40 this.keys = keys;
|
|
41 this.values = values;
|
|
42 }
|
|
43
|
|
44 override Expression syntaxCopy()
|
|
45 {
|
|
46 return new AssocArrayLiteralExp(loc,
|
|
47 arraySyntaxCopy(keys), arraySyntaxCopy(values));
|
|
48 }
|
|
49
|
|
50 override Expression semantic(Scope sc)
|
|
51 {
|
|
52 Expression e;
|
|
53 Type tkey = null;
|
|
54 Type tvalue = null;
|
|
55
|
|
56 version (LOGSEMANTIC) {
|
|
57 printf("AssocArrayLiteralExp.semantic('%s')\n", toChars());
|
|
58 }
|
|
59
|
|
60 // Run semantic() on each element
|
|
61 for (size_t i = 0; i < keys.dim; i++)
|
|
62 { Expression key = cast(Expression)keys.data[i];
|
|
63 Expression value = cast(Expression)values.data[i];
|
|
64
|
|
65 key = key.semantic(sc);
|
|
66 value = value.semantic(sc);
|
|
67
|
|
68 keys.data[i] = cast(void *)key;
|
|
69 values.data[i] = cast(void *)value;
|
|
70 }
|
|
71 expandTuples(keys);
|
|
72 expandTuples(values);
|
|
73 if (keys.dim != values.dim)
|
|
74 {
|
|
75 error("number of keys is %u, must match number of values %u", keys.dim, values.dim);
|
|
76 keys.setDim(0);
|
|
77 values.setDim(0);
|
|
78 }
|
|
79 for (size_t i = 0; i < keys.dim; i++)
|
|
80 { Expression key = cast(Expression)keys.data[i];
|
|
81 Expression value = cast(Expression)values.data[i];
|
|
82
|
|
83 if (!key.type)
|
|
84 error("%s has no value", key.toChars());
|
|
85 if (!value.type)
|
|
86 error("%s has no value", value.toChars());
|
|
87 key = resolveProperties(sc, key);
|
|
88 value = resolveProperties(sc, value);
|
|
89
|
|
90 if (!tkey)
|
|
91 tkey = key.type;
|
|
92 else
|
|
93 key = key.implicitCastTo(sc, tkey);
|
|
94 keys.data[i] = cast(void *)key;
|
|
95
|
|
96 if (!tvalue)
|
|
97 tvalue = value.type;
|
|
98 else
|
|
99 value = value.implicitCastTo(sc, tvalue);
|
|
100 values.data[i] = cast(void *)value;
|
|
101 }
|
|
102
|
|
103 if (!tkey)
|
|
104 tkey = Type.tvoid;
|
|
105 if (!tvalue)
|
|
106 tvalue = Type.tvoid;
|
|
107 type = new TypeAArray(tvalue, tkey);
|
|
108 type = type.semantic(loc, sc);
|
|
109 return this;
|
|
110 }
|
|
111
|
|
112 override bool isBool(bool result)
|
|
113 {
|
|
114 size_t dim = keys.dim;
|
|
115 return result ? (dim != 0) : (dim == 0);
|
|
116 }
|
|
117
|
|
118 override elem* toElem(IRState* irs)
|
|
119 {
|
|
120 elem* e;
|
|
121 size_t dim;
|
|
122
|
|
123 //printf("AssocArrayLiteralExp.toElem() %s\n", toChars());
|
|
124 dim = keys.dim;
|
|
125 e = el_long(TYint, dim);
|
|
126 for (size_t i = 0; i < dim; i++)
|
|
127 {
|
|
128 Expression el = cast(Expression)keys.data[i];
|
|
129
|
|
130 for (int j = 0; j < 2; j++)
|
|
131 {
|
|
132 elem* ep = el.toElem(irs);
|
|
133
|
|
134 if (tybasic(ep.Ety) == TYstruct || tybasic(ep.Ety) == TYarray)
|
|
135 {
|
|
136 ep = el_una(OPstrpar, TYstruct, ep);
|
|
137 ep.Enumbytes = cast(uint)el.type.size();
|
|
138 }
|
|
139 //printf("[%d] %s\n", i, el.toChars());
|
|
140 //elem_print(ep);
|
|
141 e = el_param(ep, e);
|
|
142 el = cast(Expression)values.data[i];
|
|
143 }
|
|
144 }
|
|
145
|
|
146 Type t = type.toBasetype().mutableOf();
|
|
147 assert(t.ty == Taarray);
|
|
148 TypeAArray ta = cast(TypeAArray)t;
|
|
149
|
|
150 /* Unfortunately, the hash function for Aa (array of chars) is custom and
|
|
151 * different from Axa and Aya, which get the generic hash function.
|
|
152 * So, rewrite the type of the AArray so that if it's key type
|
|
153 * is an array of const or invariant, make it an array of mutable.
|
|
154 */
|
|
155 Type tkey = ta.index.toBasetype();
|
|
156 if (tkey.ty == Tarray)
|
|
157 {
|
|
158 tkey = tkey.nextOf().mutableOf().arrayOf();
|
|
159 tkey = tkey.semantic(Loc(0), null);
|
|
160 ta = new TypeAArray(ta.nextOf(), tkey);
|
|
161 ta = cast(TypeAArray)ta.merge();
|
|
162 }
|
|
163
|
|
164 e = el_param(e, ta.getTypeInfo(null).toElem(irs));
|
|
165
|
|
166 // call _d_assocarrayliteralT(ti, dim, ...)
|
|
167 e = el_bin(OPcall,TYnptr,el_var(rtlsym[RTLSYM_ASSOCARRAYLITERALT]),e);
|
|
168
|
|
169 el_setLoc(e,loc);
|
|
170 return e;
|
|
171 }
|
|
172
|
|
173 override bool checkSideEffect(int flag)
|
|
174 {
|
|
175 bool f = false;
|
|
176
|
|
177 for (size_t i = 0; i < keys.dim; i++)
|
|
178 { Expression key = cast(Expression)keys.data[i];
|
|
179 Expression value = cast(Expression)values.data[i];
|
|
180
|
|
181 f |= key.checkSideEffect(2);
|
|
182 f |= value.checkSideEffect(2);
|
|
183 }
|
|
184 if (flag == 0 && f == 0)
|
|
185 Expression.checkSideEffect(0);
|
|
186 return f;
|
|
187 }
|
|
188
|
|
189 override void toCBuffer(OutBuffer buf, HdrGenState* hgs)
|
|
190 {
|
|
191 buf.writeByte('[');
|
|
192 for (size_t i = 0; i < keys.dim; i++)
|
|
193 { Expression key = cast(Expression)keys.data[i];
|
|
194 Expression value = cast(Expression)values.data[i];
|
|
195
|
|
196 if (i)
|
|
197 buf.writeByte(',');
|
|
198 expToCBuffer(buf, hgs, key, PREC.PREC_assign);
|
|
199 buf.writeByte(':');
|
|
200 expToCBuffer(buf, hgs, value, PREC.PREC_assign);
|
|
201 }
|
|
202 buf.writeByte(']');
|
|
203 }
|
|
204
|
|
205 override void toMangleBuffer(OutBuffer buf)
|
|
206 {
|
|
207 size_t dim = keys.dim;
|
|
208 buf.printf("A%u", dim);
|
|
209 for (size_t i = 0; i < dim; i++)
|
|
210 { Expression key = cast(Expression)keys.data[i];
|
|
211 Expression value = cast(Expression)values.data[i];
|
|
212
|
|
213 key.toMangleBuffer(buf);
|
|
214 value.toMangleBuffer(buf);
|
|
215 }
|
|
216 }
|
|
217
|
|
218 override void scanForNestedRef(Scope sc)
|
|
219 {
|
|
220 assert(false);
|
|
221 }
|
|
222
|
|
223 override Expression optimize(int result)
|
|
224 {
|
|
225 assert(keys.dim == values.dim);
|
|
226 for (size_t i = 0; i < keys.dim; i++)
|
|
227 {
|
|
228 Expression e = cast(Expression)keys.data[i];
|
|
229
|
|
230 e = e.optimize(WANTvalue | (result & WANTinterpret));
|
|
231 keys.data[i] = cast(void*)e;
|
|
232
|
|
233 e = cast(Expression)values.data[i];
|
|
234 e = e.optimize(WANTvalue | (result & WANTinterpret));
|
|
235 values.data[i] = cast(void*)e;
|
|
236 }
|
|
237 return this;
|
|
238 }
|
|
239
|
|
240 override Expression interpret(InterState istate)
|
|
241 {
|
|
242 Expressions keysx = keys;
|
|
243 Expressions valuesx = values;
|
|
244
|
|
245 version (LOG) {
|
|
246 printf("AssocArrayLiteralExp.interpret() %s\n", toChars());
|
|
247 }
|
|
248 for (size_t i = 0; i < keys.dim; i++)
|
|
249 {
|
|
250 Expression ekey = cast(Expression)keys.data[i];
|
|
251 Expression evalue = cast(Expression)values.data[i];
|
|
252 Expression ex;
|
|
253
|
|
254 ex = ekey.interpret(istate);
|
|
255 if (ex is EXP_CANT_INTERPRET)
|
|
256 goto Lerr;
|
|
257
|
|
258 /* If any changes, do Copy On Write
|
|
259 */
|
|
260 if (ex != ekey)
|
|
261 {
|
|
262 if (keysx == keys)
|
|
263 keysx = cast(Expressions)keys.copy();
|
|
264 keysx.data[i] = cast(void*)ex;
|
|
265 }
|
|
266
|
|
267 ex = evalue.interpret(istate);
|
|
268 if (ex is EXP_CANT_INTERPRET)
|
|
269 goto Lerr;
|
|
270
|
|
271 /* If any changes, do Copy On Write
|
|
272 */
|
|
273 if (ex != evalue)
|
|
274 {
|
|
275 if (valuesx == values)
|
|
276 valuesx = cast(Expressions)values.copy();
|
|
277 valuesx.data[i] = cast(void*)ex;
|
|
278 }
|
|
279 }
|
|
280
|
|
281 if (keysx != keys)
|
|
282 expandTuples(keysx);
|
|
283 if (valuesx != values)
|
|
284 expandTuples(valuesx);
|
|
285 if (keysx.dim != valuesx.dim)
|
|
286 goto Lerr;
|
|
287
|
|
288 /* Remove duplicate keys
|
|
289 */
|
|
290 for (size_t i = 1; i < keysx.dim; i++)
|
|
291 {
|
|
292 Expression ekey = cast(Expression)keysx.data[i - 1];
|
|
293
|
|
294 for (size_t j = i; j < keysx.dim; j++)
|
|
295 {
|
|
296 Expression ekey2 = cast(Expression)keysx.data[j];
|
|
297 Expression ex = Equal(TOKequal, Type.tbool, ekey, ekey2);
|
|
298 if (ex is EXP_CANT_INTERPRET)
|
|
299 goto Lerr;
|
|
300 if (ex.isBool(true)) // if a match
|
|
301 {
|
|
302 // Remove ekey
|
|
303 if (keysx == keys)
|
|
304 keysx = cast(Expressions)keys.copy();
|
|
305 if (valuesx == values)
|
|
306 valuesx = cast(Expressions)values.copy();
|
|
307 keysx.remove(i - 1);
|
|
308 valuesx.remove(i - 1);
|
|
309 i -= 1; // redo the i'th iteration
|
|
310 break;
|
|
311 }
|
|
312 }
|
|
313 }
|
|
314
|
|
315 if (keysx != keys || valuesx != values)
|
|
316 {
|
|
317 AssocArrayLiteralExp ae;
|
|
318 ae = new AssocArrayLiteralExp(loc, keysx, valuesx);
|
|
319 ae.type = type;
|
|
320 return ae;
|
|
321 }
|
|
322 return this;
|
|
323
|
|
324 Lerr:
|
|
325 if (keysx != keys)
|
|
326 delete keysx;
|
|
327 if (valuesx != values)
|
|
328 delete values;
|
|
329 return EXP_CANT_INTERPRET;
|
|
330 }
|
|
331
|
|
332 override MATCH implicitConvTo(Type t)
|
|
333 {
|
|
334 MATCH result = MATCHexact;
|
|
335
|
|
336 Type typeb = type.toBasetype();
|
|
337 Type tb = t.toBasetype();
|
|
338 if (tb.ty == Taarray && typeb.ty == Taarray)
|
|
339 {
|
|
340 for (size_t i = 0; i < keys.dim; i++)
|
|
341 {
|
|
342 Expression e = cast(Expression)keys.data[i];
|
|
343 MATCH m = cast(MATCH)e.implicitConvTo((cast(TypeAArray)tb).index);
|
|
344 if (m < result)
|
|
345 result = m; // remember worst match
|
|
346 if (result == MATCHnomatch)
|
|
347 break; // no need to check for worse
|
|
348 e = cast(Expression)values.data[i];
|
|
349 m = cast(MATCH)e.implicitConvTo(tb.nextOf());
|
|
350 if (m < result)
|
|
351 result = m; // remember worst match
|
|
352 if (result == MATCHnomatch)
|
|
353 break; // no need to check for worse
|
|
354 }
|
|
355 return result;
|
|
356 }
|
|
357 else
|
|
358 return Expression.implicitConvTo(t);
|
|
359 }
|
|
360
|
|
361 override Expression castTo(Scope sc, Type t)
|
|
362 {
|
|
363 if (type == t)
|
|
364 return this;
|
|
365 AssocArrayLiteralExp e = this;
|
|
366 Type typeb = type.toBasetype();
|
|
367 Type tb = t.toBasetype();
|
|
368 if (tb.ty == Taarray && typeb.ty == Taarray && tb.nextOf().toBasetype().ty != Tvoid)
|
|
369 {
|
|
370 e = cast(AssocArrayLiteralExp)copy();
|
|
371 e.keys = cast(Expressions)keys.copy();
|
|
372 e.values = cast(Expressions)values.copy();
|
|
373 assert(keys.dim == values.dim);
|
|
374 for (size_t i = 0; i < keys.dim; i++)
|
|
375 {
|
|
376 Expression ex = cast(Expression)values.data[i];
|
|
377 ex = ex.castTo(sc, tb.nextOf());
|
|
378 e.values.data[i] = cast(void*)ex;
|
|
379
|
|
380 ex = cast(Expression)keys.data[i];
|
|
381 ex = ex.castTo(sc, (cast(TypeAArray)tb).index);
|
|
382 e.keys.data[i] = cast(void*)ex;
|
|
383 }
|
|
384 e.type = t;
|
|
385 return e;
|
|
386 }
|
|
387 L1:
|
|
388 return e.Expression.castTo(sc, t);
|
|
389 }
|
|
390
|
|
391 override bool canThrow()
|
|
392 {
|
|
393 return true;
|
|
394 }
|
|
395
|
|
396 override int inlineCost(InlineCostState* ics)
|
|
397 {
|
|
398 assert(false);
|
|
399 }
|
|
400
|
|
401 override Expression doInline(InlineDoState ids)
|
|
402 {
|
|
403 assert(false);
|
|
404 }
|
|
405
|
|
406 override Expression inlineScan(InlineScanState* iss)
|
|
407 {
|
|
408 assert(false);
|
|
409 }
|
|
410 }
|