72
|
1 module dmd.TraitsExp;
|
|
2
|
|
3 import dmd.Expression;
|
|
4 import dmd.Identifier;
|
|
5 import dmd.ArrayTypes;
|
|
6 import dmd.OutBuffer;
|
|
7 import dmd.Loc;
|
|
8 import dmd.Scope;
|
|
9 import dmd.HdrGenState;
|
|
10 import dmd.TOK;
|
|
11 import dmd.TY;
|
|
12 import dmd.STC;
|
|
13 import dmd.WANT;
|
|
14 import dmd.Id;
|
|
15 import dmd.Global;
|
|
16 import dmd.Lexer;
|
|
17 import dmd.ArrayLiteralExp;
|
|
18 import dmd.VarExp;
|
|
19 import dmd.StringExp;
|
|
20 import dmd.DotIdExp;
|
|
21 import dmd.DotVarExp;
|
|
22 import dmd.IntegerExp;
|
|
23 import dmd.TupleExp;
|
|
24 import dmd.Type;
|
|
25 import dmd.Dsymbol;
|
|
26 import dmd.DsymbolExp;
|
|
27 import dmd.ScopeDsymbol;
|
|
28 import dmd.FuncDeclaration;
|
|
29 import dmd.ClassDeclaration;
|
|
30 import dmd.TemplateDeclaration;
|
|
31 import dmd.TemplateInstance;
|
|
32 import dmd.TypeClass;
|
|
33 import dmd.Util;
|
|
34 import dmd.expression.Util;
|
|
35
|
|
36 import core.stdc.string : strcmp;
|
|
37
|
|
38 /************************************************
|
|
39 * Delegate to be passed to overloadApply() that looks
|
|
40 * for virtual functions.
|
|
41 */
|
|
42
|
|
43 struct Pvirtuals
|
|
44 {
|
|
45 Expression e1;
|
|
46 Expressions exps;
|
|
47 int fpvirtuals(void* param, FuncDeclaration f)
|
|
48 { Pvirtuals p = *cast(Pvirtuals*)param;
|
|
49
|
|
50 if (f.isVirtual())
|
|
51 { Expression e;
|
|
52
|
|
53 if (p.e1.op == TOK.TOKdotvar)
|
|
54 { DotVarExp dve = cast(DotVarExp)p.e1;
|
|
55 e = new DotVarExp(Loc(0), dve.e1, f);
|
|
56 }
|
|
57 else
|
|
58 e = new DsymbolExp(Loc(0), f);
|
|
59 p.exps.push(cast(void*)e);
|
|
60 }
|
|
61 return 0;
|
|
62 }
|
|
63 }
|
|
64
|
|
65
|
|
66
|
|
67 class TraitsExp : Expression
|
|
68 {
|
|
69 Identifier ident;
|
|
70
|
|
71 Objects args;
|
|
72
|
|
73 this(Loc loc, Identifier ident, Objects args)
|
|
74 {
|
|
75 super(loc, TOK.TOKtraits, this.sizeof);
|
|
76 this.ident = ident;
|
|
77 this.args = args;
|
|
78 }
|
|
79
|
|
80 override Expression syntaxCopy()
|
|
81 {
|
|
82 return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
|
|
83 }
|
|
84
|
|
85 override Expression semantic(Scope sc)
|
|
86 {
|
|
87 version (LOGSEMANTIC) {
|
|
88 printf("TraitsExp.semantic() %s\n", toChars());
|
|
89 }
|
|
90 if (ident != Id.compiles && ident != Id.isSame)
|
|
91 TemplateInstance.semanticTiargs(loc, sc, args, 1);
|
|
92 size_t dim = args ? args.dim : 0;
|
|
93 Object o;
|
|
94 FuncDeclaration f;
|
|
95
|
|
96 string ISTYPE(string cond)
|
|
97 {
|
|
98 return `
|
|
99 for (size_t i = 0; i < dim; i++)
|
|
100 { Type t = getType(cast(Object)args.data[i]);
|
|
101 if (!t)
|
|
102 goto Lfalse;
|
|
103 if (!(`~cond~`))
|
|
104 goto Lfalse;
|
|
105 }
|
|
106 if (!dim)
|
|
107 goto Lfalse;
|
|
108 goto Ltrue;
|
|
109 `;
|
|
110 }
|
|
111
|
|
112 string ISDSYMBOL(string cond)
|
|
113 {
|
|
114 return `for (size_t i = 0; i < dim; i++)
|
|
115 { Dsymbol s = getDsymbol(cast(Object)args.data[i]);
|
|
116 if (!s)
|
|
117 goto Lfalse;
|
|
118 if (!(`~cond~`))
|
|
119 goto Lfalse;
|
|
120 }
|
|
121 if (!dim)
|
|
122 goto Lfalse;
|
|
123 goto Ltrue;`;
|
|
124 }
|
|
125
|
|
126 if (ident == Id.isArithmetic)
|
|
127 {
|
|
128 mixin(ISTYPE(`t.isintegral() || t.isfloating()`));
|
|
129 }
|
|
130 else if (ident == Id.isFloating)
|
|
131 {
|
|
132 mixin(ISTYPE(q{t.isfloating()}));
|
|
133 }
|
|
134 else if (ident == Id.isIntegral)
|
|
135 {
|
|
136 mixin(ISTYPE(q{t.isintegral()}));
|
|
137 }
|
|
138 else if (ident == Id.isScalar)
|
|
139 {
|
|
140 mixin(ISTYPE(q{t.isscalar()}));
|
|
141 }
|
|
142 else if (ident == Id.isUnsigned)
|
|
143 {
|
|
144 mixin(ISTYPE(q{t.isunsigned()}));
|
|
145 }
|
|
146 else if (ident == Id.isAssociativeArray)
|
|
147 {
|
|
148 mixin(ISTYPE(q{t.toBasetype().ty == TY.Taarray}));
|
|
149 }
|
|
150 else if (ident == Id.isStaticArray)
|
|
151 {
|
|
152 mixin(ISTYPE(q{t.toBasetype().ty == TY.Tsarray}));
|
|
153 }
|
|
154 else if (ident == Id.isAbstractClass)
|
|
155 {
|
|
156 mixin(ISTYPE(q{t.toBasetype().ty == TY.Tclass && (cast(TypeClass)t.toBasetype()).sym.isAbstract()}));
|
|
157 }
|
|
158 else if (ident == Id.isFinalClass)
|
|
159 {
|
|
160 mixin(ISTYPE(q{t.toBasetype().ty == TY.Tclass && (cast(TypeClass)t.toBasetype()).sym.storage_class & STC.STCfinal}));
|
|
161 }
|
|
162 else if (ident == Id.isAbstractFunction)
|
|
163 {
|
|
164 mixin(ISDSYMBOL(q{(f = s.isFuncDeclaration()) !is null && f.isAbstract()}));
|
|
165 }
|
|
166 else if (ident == Id.isVirtualFunction)
|
|
167 {
|
|
168 mixin(ISDSYMBOL(q{(f = s.isFuncDeclaration()) !is null && f.isVirtual()}));
|
|
169 }
|
|
170 else if (ident == Id.isFinalFunction)
|
|
171 {
|
|
172 mixin(ISDSYMBOL(q{(f = s.isFuncDeclaration()) !is null && f.isFinal()}));
|
|
173 }
|
|
174 else if (ident == Id.hasMember ||
|
|
175 ident == Id.getMember ||
|
|
176 ident == Id.getVirtualFunctions)
|
|
177 {
|
|
178 if (dim != 2)
|
|
179 goto Ldimerror;
|
|
180 Object o_ = cast(Object)args.data[0];
|
|
181 Expression e = isExpression(cast(Object)args.data[1]);
|
|
182 if (!e)
|
|
183 { error("expression expected as second argument of __traits %s", ident.toChars());
|
|
184 goto Lfalse;
|
|
185 }
|
|
186 e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret);
|
|
187 if (e.op != TOKstring)
|
|
188 { error("string expected as second argument of __traits %s instead of %s", ident.toChars(), e.toChars());
|
|
189 goto Lfalse;
|
|
190 }
|
|
191 StringExp se = cast(StringExp)e;
|
|
192 se = se.toUTF8(sc);
|
|
193 if (se.sz != 1)
|
|
194 { error("string must be chars");
|
|
195 goto Lfalse;
|
|
196 }
|
|
197 Identifier id = Lexer.idPool(fromStringz(cast(char*)se.string_));
|
|
198
|
|
199 Type t = isType(o_);
|
|
200 e = isExpression(o_);
|
|
201 Dsymbol s = isDsymbol(o_);
|
|
202 if (t)
|
|
203 e = typeDotIdExp(loc, t, id);
|
|
204 else if (e)
|
|
205 e = new DotIdExp(loc, e, id);
|
|
206 else if (s)
|
|
207 { e = new DsymbolExp(loc, s);
|
|
208 e = new DotIdExp(loc, e, id);
|
|
209 }
|
|
210 else
|
|
211 { error("invalid first argument");
|
|
212 goto Lfalse;
|
|
213 }
|
|
214
|
|
215 if (ident == Id.hasMember)
|
|
216 { /* Take any errors as meaning it wasn't found
|
|
217 */
|
|
218 e = e.trySemantic(sc);
|
|
219 if (!e)
|
|
220 { if (global.gag)
|
|
221 global.errors++;
|
|
222 goto Lfalse;
|
|
223 }
|
|
224 else
|
|
225 goto Ltrue;
|
|
226 }
|
|
227 else if (ident == Id.getMember)
|
|
228 {
|
|
229 e = e.semantic(sc);
|
|
230 return e;
|
|
231 }
|
|
232 else if (ident == Id.getVirtualFunctions)
|
|
233 {
|
|
234 uint errors = global.errors;
|
|
235 Expression ex = e;
|
|
236 e = e.semantic(sc);
|
|
237 if (errors < global.errors)
|
|
238 error("%s cannot be resolved", ex.toChars());
|
|
239
|
|
240 /* Create tuple of virtual function overloads of e
|
|
241 */
|
|
242 //e.dump(0);
|
|
243 Expressions exps = new Expressions();
|
|
244 FuncDeclaration f_;
|
|
245 if (e.op == TOKvar)
|
|
246 { VarExp ve = cast(VarExp)e;
|
|
247 f_ = ve.var.isFuncDeclaration();
|
|
248 }
|
|
249 else if (e.op == TOKdotvar)
|
|
250 { DotVarExp dve = cast(DotVarExp)e;
|
|
251 f_ = dve.var.isFuncDeclaration();
|
|
252 }
|
|
253 else
|
|
254 f_ = null;
|
|
255 Pvirtuals p;
|
|
256 p.exps = exps;
|
|
257 p.e1 = e;
|
|
258 overloadApply(f_, &p.fpvirtuals, &p);
|
|
259
|
|
260 TupleExp tup = new TupleExp(loc, exps);
|
|
261 return tup.semantic(sc);
|
|
262 }
|
|
263 else
|
|
264 assert(0);
|
|
265 }
|
|
266 else if (ident == Id.classInstanceSize)
|
|
267 {
|
|
268 if (dim != 1)
|
|
269 goto Ldimerror;
|
|
270 Object o_ = cast(Object)args.data[0];
|
|
271 Dsymbol s = getDsymbol(o_);
|
|
272 ClassDeclaration cd;
|
|
273 if (!s || (cd = s.isClassDeclaration()) is null)
|
|
274 {
|
|
275 error("first argument is not a class");
|
|
276 goto Lfalse;
|
|
277 }
|
|
278 return new IntegerExp(loc, cd.structsize, Type.tsize_t);
|
|
279 }
|
|
280 else if (ident == Id.allMembers || ident == Id.derivedMembers)
|
|
281 {
|
|
282 if (dim != 1)
|
|
283 goto Ldimerror;
|
|
284 Object o_ = cast(Object)args.data[0];
|
|
285 Dsymbol s = getDsymbol(o_);
|
|
286 ScopeDsymbol sd;
|
|
287 if (!s)
|
|
288 {
|
|
289 error("argument has no members");
|
|
290 goto Lfalse;
|
|
291 }
|
|
292 if ((sd = s.isScopeDsymbol()) is null)
|
|
293 {
|
|
294 error("%s %s has no members", s.kind(), s.toChars());
|
|
295 goto Lfalse;
|
|
296 }
|
|
297 Expressions exps = new Expressions;
|
|
298 while (1)
|
|
299 { size_t dim_ = ScopeDsymbol.dim(sd.members);
|
|
300 for (size_t i = 0; i < dim_; i++)
|
|
301 {
|
|
302 Dsymbol sm = ScopeDsymbol.getNth(sd.members, i);
|
|
303 //printf("\t[%i] %s %s\n", i, sm.kind(), sm.toChars());
|
|
304 if (sm.ident)
|
|
305 {
|
|
306 //printf("\t%s\n", sm.ident.toChars());
|
|
307 auto str = sm.ident.toChars();
|
|
308
|
|
309 /* Skip if already present in exps[]
|
|
310 */
|
|
311 for (size_t j = 0; j < exps.dim; j++)
|
|
312 { StringExp se2 = cast(StringExp)exps.data[j];
|
|
313 if (strcmp(toStringz(str), cast(char*)se2.string_) == 0)
|
|
314 goto Lnext;
|
|
315 }
|
|
316
|
|
317 StringExp se = new StringExp(loc, str);
|
|
318 exps.push(cast(void*)se);
|
|
319 }
|
|
320 Lnext:
|
|
321 ;
|
|
322 }
|
|
323 ClassDeclaration cd = sd.isClassDeclaration();
|
|
324 if (cd && cd.baseClass && ident == Id.allMembers)
|
|
325 sd = cd.baseClass; // do again with base class
|
|
326 else
|
|
327 break;
|
|
328 }
|
|
329 Expression e = new ArrayLiteralExp(loc, exps);
|
|
330 e = e.semantic(sc);
|
|
331 return e;
|
|
332 }
|
|
333 else if (ident == Id.compiles)
|
|
334 {
|
|
335 /* Determine if all the objects - types, expressions, or symbols -
|
|
336 * compile without error
|
|
337 */
|
|
338 if (!dim)
|
|
339 goto Lfalse;
|
|
340
|
|
341 for (size_t i = 0; i < dim; i++)
|
|
342 { Object o_ = cast(Object)args.data[i];
|
|
343 Expression e;
|
|
344
|
|
345 uint errors = global.errors;
|
|
346 global.gag++;
|
|
347
|
|
348 Type t = isType(o_);
|
|
349 if (t)
|
|
350 { Dsymbol s;
|
|
351 t.resolve(loc, sc, &e, &t, &s);
|
|
352 if (t)
|
|
353 t.semantic(loc, sc);
|
|
354 else if (e)
|
|
355 e.semantic(sc);
|
|
356 }
|
|
357 else
|
|
358 { e = isExpression(o);
|
|
359 if (e)
|
|
360 e.semantic(sc);
|
|
361 }
|
|
362
|
|
363 global.gag--;
|
|
364 if (errors != global.errors)
|
|
365 { if (global.gag == 0)
|
|
366 global.errors = errors;
|
|
367 goto Lfalse;
|
|
368 }
|
|
369 }
|
|
370 goto Ltrue;
|
|
371 }
|
|
372 else if (ident == Id.isSame)
|
|
373 { /* Determine if two symbols are the same
|
|
374 */
|
|
375 if (dim != 2)
|
|
376 goto Ldimerror;
|
|
377 TemplateInstance.semanticTiargs(loc, sc, args, 0);
|
|
378 Object o1 = cast(Object)args.data[0];
|
|
379 Object o2 = cast(Object)args.data[1];
|
|
380 Dsymbol s1 = getDsymbol(o1);
|
|
381 Dsymbol s2 = getDsymbol(o2);
|
|
382
|
|
383 static if (0) {
|
|
384 printf("o1: %p\n", o1);
|
|
385 printf("o2: %p\n", o2);
|
|
386 if (!s1)
|
|
387 { Expression ea = isExpression(o1);
|
|
388 if (ea)
|
|
389 printf("%s\n", ea.toChars());
|
|
390 Type ta = isType(o1);
|
|
391 if (ta)
|
|
392 printf("%s\n", ta.toChars());
|
|
393 goto Lfalse;
|
|
394 }
|
|
395 else
|
|
396 printf("%s %s\n", s1.kind(), s1.toChars());
|
|
397 }
|
|
398 if (!s1 && !s2)
|
|
399 { Expression ea1 = isExpression(o1);
|
|
400 Expression ea2 = isExpression(o2);
|
|
401 if (ea1 && ea2 && ea1.equals(ea2))
|
|
402 goto Ltrue;
|
|
403 }
|
|
404
|
|
405 if (!s1 || !s2)
|
|
406 goto Lfalse;
|
|
407
|
|
408 s1 = s1.toAlias();
|
|
409 s2 = s2.toAlias();
|
|
410
|
|
411 if (s1 == s2)
|
|
412 goto Ltrue;
|
|
413 else
|
|
414 goto Lfalse;
|
|
415 }
|
|
416 else
|
|
417 { error("unrecognized trait %s", ident.toChars());
|
|
418 goto Lfalse;
|
|
419 }
|
|
420
|
|
421 return null;
|
|
422
|
|
423 Lnottype:
|
|
424 error("%s is not a type", o/*.toChars()*/); // BUG: o is Object, no member toChars()
|
|
425 goto Lfalse;
|
|
426
|
|
427 Ldimerror:
|
|
428 error("wrong number of arguments %d", dim);
|
|
429 goto Lfalse;
|
|
430
|
|
431
|
|
432 Lfalse:
|
|
433 return new IntegerExp(loc, 0, Type.tbool);
|
|
434
|
|
435 Ltrue:
|
|
436 return new IntegerExp(loc, 1, Type.tbool);
|
|
437 }
|
|
438
|
|
439 override void toCBuffer(OutBuffer buf, HdrGenState* hgs)
|
|
440 {
|
|
441 buf.writestring("__traits(");
|
|
442 buf.writestring(ident.toChars());
|
|
443 if (args)
|
|
444 {
|
|
445 for (int i = 0; i < args.dim; i++)
|
|
446 {
|
|
447 buf.writeByte(',');
|
|
448 Object oarg = cast(Object)args.data[i];
|
|
449 ObjectToCBuffer(buf, hgs, oarg);
|
|
450 }
|
|
451 }
|
|
452 buf.writeByte(')');
|
|
453 }
|
|
454 }
|