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