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