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