Mercurial > projects > ddmd
annotate dmd/TraitsExp.d @ 84:be2ab491772e
Expressions -> Vector!Expression
author | Eldar Insafutdinov <e.insafutdinov@gmail.com> |
---|---|
date | Mon, 30 Aug 2010 16:12:19 +0100 |
parents | 2e2a5c3f943a |
children | 39648eb578f6 |
rev | line source |
---|---|
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); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
59 p.exps.push(e); |
72 | 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 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
317 auto se = new StringExp(loc, str); |
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
72
diff
changeset
|
318 exps.push(se); |
72 | 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 } |