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