1:
2: // Compiler implementation of the D programming language
3: // Copyright (c) 1999-2011 by Digital Mars
4: // All Rights Reserved
5: // written by Walter Bright
6: // http://www.digitalmars.com
7: // License for redistribution is by either the Artistic License
8: // in artistic.txt, or the GNU General Public License in gnu.txt.
9: // See the included readme.txt for details.
10:
11: #include <stdio.h>
12: #include <stdlib.h>
13: #include <ctype.h>
14: static char __file__[] = __FILE__; /* for tassert.h */
15: #include "tassert.h"
16: #include <math.h>
17:
18: #include "rmem.h"
19:
20: //#include "port.h"
21: #include "mtype.h"
22: #include "init.h"
23: #include "expression.h"
24: #include "template.h"
25: #include "utf.h"
26: #include "enum.h"
27: #include "scope.h"
28: #include "statement.h"
29: #include "declaration.h"
30: #include "aggregate.h"
31: #include "import.h"
32: #include "id.h"
33: #include "dsymbol.h"
34: #include "module.h"
35: #include "attrib.h"
36: #include "hdrgen.h"
37: #include "parse.h"
38:
39: #define LOGSEMANTIC 0
40:
41: #if DMDV2
42:
43: /************************************************
44: * Delegate to be passed to overloadApply() that looks
45: * for functions matching a trait.
46: */
47:
48: struct Ptrait
49: {
50: Expression *e1;
51: Expressions *exps; // collected results
52: Identifier *ident; // which trait we're looking for
53: };
54:
55: static int fptraits(void *param, FuncDeclaration *f)
56: { Ptrait *p = (Ptrait *)param;
57:
58: if (p->ident == Id::getVirtualFunctions && !f->isVirtual())
59: return 0;
60:
61: Expression *e;
62:
63: if (p->e1->op == TOKdotvar)
64: { DotVarExp *dve = (DotVarExp *)p->e1;
65: e = new DotVarExp(0, dve->e1, f);
66: }
67: else
68: e = new DsymbolExp(0, f);
69: p->exps->push(e);
70: return 0;
71: }
72:
73: /************************ TraitsExp ************************************/
74:
75: Expression *TraitsExp::semantic(Scope *sc)
76: {
77: #if LOGSEMANTIC
78: printf("TraitsExp::semantic() %s\n", toChars());
79: #endif
80: if (ident != Id::compiles && ident != Id::isSame &&
81: ident != Id::identifier)
82: {
83: TemplateInstance::semanticTiargs(loc, sc, args, 1);
84: }
85: size_t dim = args ? args->dim : 0;
86: Object *o;
87: Declaration *d;
88: FuncDeclaration *f;
89:
90: #define ISTYPE(cond) \
91: for (size_t i = 0; i < dim; i++) \
92: { Type *t = getType(args->tdata()[i]); \
93: if (!t) \
94: goto Lfalse; \
95: if (!(cond)) \
96: goto Lfalse; \
97: } \
98: if (!dim) \
99: goto Lfalse; \
100: goto Ltrue;
101:
102: #define ISDSYMBOL(cond) \
103: for (size_t i = 0; i < dim; i++) \
104: { Dsymbol *s = getDsymbol(args->tdata()[i]); \
105: if (!s) \
106: goto Lfalse; \
107: if (!(cond)) \
108: goto Lfalse; \
109: } \
110: if (!dim) \
111: goto Lfalse; \
112: goto Ltrue;
113:
114:
115:
116: if (ident == Id::isArithmetic)
117: {
118: ISTYPE(t->isintegral() || t->isfloating())
119: }
120: else if (ident == Id::isFloating)
121: {
122: ISTYPE(t->isfloating())
123: }
124: else if (ident == Id::isIntegral)
125: {
126: ISTYPE(t->isintegral())
127: }
128: else if (ident == Id::isScalar)
129: {
130: ISTYPE(t->isscalar())
131: }
132: else if (ident == Id::isUnsigned)
133: {
134: ISTYPE(t->isunsigned())
135: }
136: else if (ident == Id::isAssociativeArray)
137: {
138: ISTYPE(t->toBasetype()->ty == Taarray)
139: }
140: else if (ident == Id::isStaticArray)
141: {
142: ISTYPE(t->toBasetype()->ty == Tsarray)
143: }
144: else if (ident == Id::isAbstractClass)
145: {
146: ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract())
147: }
148: else if (ident == Id::isFinalClass)
149: {
150: ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal)
151: }
152: else if (ident == Id::isAbstractFunction)
153: {
154: ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract())
155: }
156: else if (ident == Id::isVirtualFunction)
157: {
158: ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isVirtual())
159: }
160: else if (ident == Id::isFinalFunction)
161: {
162: ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isFinal())
163: }
164: #if DMDV2
165: else if (ident == Id::isStaticFunction)
166: {
167: ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && !f->needThis() && !f->isNested())
168: }
169: else if (ident == Id::isRef)
170: {
171: ISDSYMBOL((d = s->isDeclaration()) != NULL && d->isRef())
172: }
173: else if (ident == Id::isOut)
174: {
175: ISDSYMBOL((d = s->isDeclaration()) != NULL && d->isOut())
176: }
177: else if (ident == Id::isLazy)
178: {
179: ISDSYMBOL((d = s->isDeclaration()) != NULL && d->storage_class & STClazy)
180: }
181: else if (ident == Id::identifier)
182: { // Get identifier for symbol as a string literal
183:
184: // Specify 0 for the flags argument to semanticTiargs() so that
185: // a symbol should not be folded to a constant.
186: TemplateInstance::semanticTiargs(loc, sc, args, 0);
187:
188: if (dim != 1)
189: goto Ldimerror;
190: Object *o = args->tdata()[0];
warning C6246: Local declaration of 'o' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '86' of 'c:\projects\extern\d\dmd\src\traits.c': Lines: 86
191: Dsymbol *s = getDsymbol(o);
192: if (!s || !s->ident)
193: {
194: error("argument %s has no identifier", o->toChars());
195: goto Lfalse;
196: }
197: StringExp *se = new StringExp(loc, s->ident->toChars());
198: return se->semantic(sc);
199: }
200: else if (ident == Id::parent)
201: {
202: if (dim != 1)
203: goto Ldimerror;
204: Object *o = args->tdata()[0];
warning C6246: Local declaration of 'o' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '86' of 'c:\projects\extern\d\dmd\src\traits.c': Lines: 86
205: Dsymbol *s = getDsymbol(o);
206: if (s)
207: s = s->toParent();
208: if (!s)
209: {
210: error("argument %s has no parent", o->toChars());
211: goto Lfalse;
212: }
213: return (new DsymbolExp(loc, s))->semantic(sc);
214: }
215:
216: #endif
217: else if (ident == Id::hasMember ||
218: ident == Id::getMember ||
219: ident == Id::getOverloads ||
220: ident == Id::getVirtualFunctions)
221: {
222: if (dim != 2)
223: goto Ldimerror;
224: Object *o = args->tdata()[0];
warning C6246: Local declaration of 'o' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '86' of 'c:\projects\extern\d\dmd\src\traits.c': Lines: 86
225: Expression *e = isExpression(args->tdata()[1]);
226: if (!e)
227: { error("expression expected as second argument of __traits %s", ident->toChars());
228: goto Lfalse;
229: }
230: e = e->optimize(WANTvalue | WANTinterpret);
231: if (e->op != TOKstring)
232: { error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars());
233: goto Lfalse;
234: }
235: StringExp *se = (StringExp *)e;
236: se = se->toUTF8(sc);
237: if (se->sz != 1)
238: { error("string must be chars");
239: goto Lfalse;
240: }
241: Identifier *id = Lexer::idPool((char *)se->string);
242:
243: Type *t = isType(o);
244: e = isExpression(o);
245: Dsymbol *s = isDsymbol(o);
246: if (t)
247: e = typeDotIdExp(loc, t, id);
248: else if (e)
249: e = new DotIdExp(loc, e, id);
warning C6211: Leaking memory 'ex' due to an exception. Consider using a local catch block to clean up memory: Lines: 80, 85, 86, 87, 88, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 165, 169, 173, 177, 181, 200, 219, 222, 224, 225, 226, 230, 231, 235, 236, 237, 241, 243, 244, 245, 246, 248, 249, 259, 271, 276, 279, 280, 281, 282, 288
250: else if (s)
251: { e = new DsymbolExp(loc, s);
252: e = new DotIdExp(loc, e, id);
253: }
254: else
255: { error("invalid first argument");
256: goto Lfalse;
257: }
258:
259: if (ident == Id::hasMember)
260: { /* Take any errors as meaning it wasn't found
261: */
262: e = e->trySemantic(sc);
263: if (!e)
264: { if (global.gag)
265: global.errors++;
266: goto Lfalse;
267: }
268: else
269: goto Ltrue;
270: }
271: else if (ident == Id::getMember)
272: {
273: e = e->semantic(sc);
274: return e;
275: }
276: else if (ident == Id::getVirtualFunctions ||
277: ident == Id::getOverloads)
278: {
279: unsigned errors = global.errors;
280: Expression *ex = e;
281: e = e->semantic(sc);
282: if (errors < global.errors)
283: error("%s cannot be resolved", ex->toChars());
284:
285: /* Create tuple of functions of e
286: */
287: //e->dump(0);
288: Expressions *exps = new Expressions();
289: FuncDeclaration *f;
warning C6246: Local declaration of 'f' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '88' of 'c:\projects\extern\d\dmd\src\traits.c': Lines: 88
290: if (e->op == TOKvar)
291: { VarExp *ve = (VarExp *)e;
292: f = ve->var->isFuncDeclaration();
293: }
294: else if (e->op == TOKdotvar)
295: { DotVarExp *dve = (DotVarExp *)e;
296: f = dve->var->isFuncDeclaration();
297: }
298: else
299: f = NULL;
300: Ptrait p;
301: p.exps = exps;
302: p.e1 = e;
303: p.ident = ident;
304: overloadApply(f, fptraits, &p);
305:
306: TupleExp *tup = new TupleExp(loc, exps);
307: return tup->semantic(sc);
308: }
309: else
310: assert(0);
311: }
312: else if (ident == Id::classInstanceSize)
313: {
314: if (dim != 1)
315: goto Ldimerror;
316: Object *o = args->tdata()[0];
warning C6246: Local declaration of 'o' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '86' of 'c:\projects\extern\d\dmd\src\traits.c': Lines: 86
317: Dsymbol *s = getDsymbol(o);
318: ClassDeclaration *cd;
319: if (!s || (cd = s->isClassDeclaration()) == NULL)
320: {
321: error("first argument is not a class");
322: goto Lfalse;
323: }
324: return new IntegerExp(loc, cd->structsize, Type::tsize_t);
325: }
326: else if (ident == Id::allMembers || ident == Id::derivedMembers)
327: {
328: if (dim != 1)
329: goto Ldimerror;
330: Object *o = args->tdata()[0];
warning C6246: Local declaration of 'o' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '86' of 'c:\projects\extern\d\dmd\src\traits.c': Lines: 86
331: Dsymbol *s = getDsymbol(o);
332: ScopeDsymbol *sd;
333: if (!s)
334: {
335: error("argument has no members");
336: goto Lfalse;
337: }
338: if ((sd = s->isScopeDsymbol()) == NULL)
339: {
340: error("%s %s has no members", s->kind(), s->toChars());
341: goto Lfalse;
342: }
343: Expressions *exps = new Expressions;
warning C6211: Leaking memory 'exps' due to an exception. Consider using a local catch block to clean up memory: Lines: 80, 85, 86, 87, 88, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 165, 169, 173, 177, 181, 200, 219, 312, 326, 328, 330, 331, 332, 333, 338, 343, 344, 345, 346, 348, 350, 353, 357, 363
344: while (1)
345: { size_t dim = ScopeDsymbol::dim(sd->members);
warning C6246: Local declaration of 'dim' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '85' of 'c:\projects\extern\d\dmd\src\traits.c': Lines: 85
346: for (size_t i = 0; i < dim; i++)
347: {
348: Dsymbol *sm = ScopeDsymbol::getNth(sd->members, i);
349: //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
350: if (sm->ident)
351: {
352: //printf("\t%s\n", sm->ident->toChars());
353: char *str = sm->ident->toChars();
354:
355: /* Skip if already present in exps[]
356: */
357: for (size_t j = 0; j < exps->dim; j++)
358: { StringExp *se2 = (StringExp *)exps->tdata()[j];
359: if (strcmp(str, (char *)se2->string) == 0)
360: goto Lnext;
361: }
362:
363: StringExp *se = new StringExp(loc, str);
364: exps->push(se);
365: }
366: Lnext:
367: ;
368: }
369: ClassDeclaration *cd = sd->isClassDeclaration();
370: if (cd && cd->baseClass && ident == Id::allMembers)
371: sd = cd->baseClass; // do again with base class
372: else
373: break;
374: }
375: #if DMDV1
376: Expression *e = new ArrayLiteralExp(loc, exps);
377: #endif
378: #if DMDV2
379: /* Making this a tuple is more flexible, as it can be statically unrolled.
380: * To make an array literal, enclose __traits in [ ]:
381: * [ __traits(allMembers, ...) ]
382: */
383: Expression *e = new TupleExp(loc, exps);
384: #endif
385: e = e->semantic(sc);
386: return e;
387: }
388: else if (ident == Id::compiles)
389: {
390: /* Determine if all the objects - types, expressions, or symbols -
391: * compile without error
392: */
393: if (!dim)
394: goto Lfalse;
395:
396: for (size_t i = 0; i < dim; i++)
397: { Object *o = args->tdata()[i];
warning C6246: Local declaration of 'o' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '86' of 'c:\projects\extern\d\dmd\src\traits.c': Lines: 86
398: Expression *e;
399:
400: unsigned errors = global.errors;
401: global.gag++;
402:
403: Type *t = isType(o);
404: if (t)
405: { Dsymbol *s;
406: t->resolve(loc, sc, &e, &t, &s);
407: if (t)
408: t->semantic(loc, sc);
409: else if (e)
410: { e = e->semantic(sc);
411: e = e->optimize(WANTvalue);
412: }
413: }
414: else
415: { e = isExpression(o);
416: if (e)
417: { e = e->semantic(sc);
418: e = e->optimize(WANTvalue);
419: }
420: }
421:
422: global.gag--;
423: if (errors != global.errors)
424: {
425: global.errors = errors;
426: goto Lfalse;
427: }
428: }
429: goto Ltrue;
430: }
431: else if (ident == Id::isSame)
432: { /* Determine if two symbols are the same
433: */
434: if (dim != 2)
435: goto Ldimerror;
436: TemplateInstance::semanticTiargs(loc, sc, args, 0);
437: Object *o1 = args->tdata()[0];
438: Object *o2 = args->tdata()[1];
439: Dsymbol *s1 = getDsymbol(o1);
440: Dsymbol *s2 = getDsymbol(o2);
441:
442: //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
443: #if 0
444: printf("o1: %p\n", o1);
445: printf("o2: %p\n", o2);
446: if (!s1)
447: { Expression *ea = isExpression(o1);
448: if (ea)
449: printf("%s\n", ea->toChars());
450: Type *ta = isType(o1);
451: if (ta)
452: printf("%s\n", ta->toChars());
453: goto Lfalse;
454: }
455: else
456: printf("%s %s\n", s1->kind(), s1->toChars());
457: #endif
458: if (!s1 && !s2)
459: { Expression *ea1 = isExpression(o1);
460: Expression *ea2 = isExpression(o2);
461: if (ea1 && ea2)
462: {
463: if (ea1->equals(ea2))
464: goto Ltrue;
465: }
466: }
467:
468: if (!s1 || !s2)
469: goto Lfalse;
470:
471: s1 = s1->toAlias();
472: s2 = s2->toAlias();
473:
474: if (s1 == s2)
475: goto Ltrue;
476: else
477: goto Lfalse;
478: }
479: else
480: { error("unrecognized trait %s", ident->toChars());
481: goto Lfalse;
482: }
483:
484: return NULL;
485:
486: Lnottype:
warning C4102: 'Lnottype' : unreferenced label
487: error("%s is not a type", o->toChars());
488: goto Lfalse;
489:
490: Ldimerror:
491: error("wrong number of arguments %d", dim);
492: goto Lfalse;
493:
494:
495: Lfalse:
496: return new IntegerExp(loc, 0, Type::tbool);
497:
498: Ltrue:
499: return new IntegerExp(loc, 1, Type::tbool);
500: }
501:
502:
503: #endif
504: