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: