1: 
  2: // Compiler implementation of the D programming language
  3: // Copyright (c) 1999-2008 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: static char __file__[] = __FILE__;      /* for tassert.h                */
 13: #include        "tassert.h"
 14: 
 15: #include "id.h"
 16: #include "init.h"
 17: #include "declaration.h"
 18: #include "identifier.h"
 19: #include "expression.h"
 20: #include "cond.h"
 21: #include "module.h"
 22: #include "template.h"
 23: #include "lexer.h"
 24: #include "mtype.h"
 25: #include "scope.h"
 26: 
 27: int findCondition(Strings *ids, Identifier *ident)
 28: {
 29:     if (ids)
 30:     {
 31:         for (int i = 0; i < ids->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
32: { 33: const char *id = ids->tdata()[i]; 34: 35: if (strcmp(id, ident->toChars()) == 0) 36: return TRUE; 37: } 38: } 39: 40: return FALSE; 41: } 42: 43: /* ============================================================ */ 44: 45: Condition::Condition(Loc loc) 46: { 47: this->loc = loc; 48: inc = 0; 49: } 50: 51: /* ============================================================ */ 52: 53: DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident) 54: : Condition(0) 55: { 56: this->mod = mod; 57: this->level = level; 58: this->ident = ident; 59: } 60: 61: Condition *DVCondition::syntaxCopy() 62: { 63: return this; // don't need to copy 64: } 65: 66: /* ============================================================ */ 67: 68: void DebugCondition::setGlobalLevel(unsigned level) 69: { 70: global.params.debuglevel = level; 71: } 72: 73: void DebugCondition::addGlobalIdent(const char *ident) 74: { 75: if (!global.params.debugids) 76: global.params.debugids = new Strings(); 77: global.params.debugids->push((char *)ident); 78: } 79: 80: 81: DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) 82: : DVCondition(mod, level, ident) 83: { 84: } 85: 86: int DebugCondition::include(Scope *sc, ScopeDsymbol *s) 87: { 88: //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); 89: if (inc == 0) 90: { 91: inc = 2; 92: if (ident) 93: { 94: if (findCondition(mod->debugids, ident)) 95: inc = 1; 96: else if (findCondition(global.params.debugids, ident)) 97: inc = 1; 98: else 99: { if (!mod->debugidsNot) 100: mod->debugidsNot = new Strings(); 101: mod->debugidsNot->push(ident->toChars()); 102: } 103: } 104: else if (level <= global.params.debuglevel || level <= mod->debuglevel) 105: inc = 1; 106: } 107: return (inc == 1); 108: } 109: 110: void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) 111: { 112: if (ident) 113: buf->printf("debug (%s)", ident->toChars()); 114: else 115: buf->printf("debug (%u)", level); 116: } 117: 118: /* ============================================================ */ 119: 120: void VersionCondition::setGlobalLevel(unsigned level) 121: { 122: global.params.versionlevel = level; 123: } 124: 125: void VersionCondition::checkPredefined(Loc loc, const char *ident) 126: { 127: static const char* reserved[] = 128: { 129: "DigitalMars", "X86", "X86_64", 130: "Windows", "Win32", "Win64", 131: "linux", 132: #if DMDV2 133: /* Although Posix is predefined by D1, disallowing its 134: * redefinition breaks makefiles and older builds. 135: */ 136: "Posix", 137: "D_NET", 138: #endif 139: "OSX", "FreeBSD", 140: "OpenBSD", 141: "Solaris", 142: "LittleEndian", "BigEndian", 143: "all", 144: "none", 145: }; 146: 147: for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) 148: { 149: if (strcmp(ident, reserved[i]) == 0) 150: goto Lerror; 151: } 152: 153: if (ident[0] == 'D' && ident[1] == '_') 154: goto Lerror; 155: 156: return; 157: 158: Lerror: 159: error(loc, "version identifier '%s' is reserved and cannot be set", ident); 160: } 161: 162: void VersionCondition::addGlobalIdent(const char *ident) 163: { 164: checkPredefined(0, ident); 165: addPredefinedGlobalIdent(ident); 166: } 167: 168: void VersionCondition::addPredefinedGlobalIdent(const char *ident) 169: { 170: if (!global.params.versionids) 171: global.params.versionids = new Strings(); 172: global.params.versionids->push((char *)ident); 173: } 174: 175: 176: VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) 177: : DVCondition(mod, level, ident) 178: { 179: } 180: 181: int VersionCondition::include(Scope *sc, ScopeDsymbol *s) 182: { 183: //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); 184: //if (ident) printf("\tident = '%s'\n", ident->toChars()); 185: if (inc == 0) 186: { 187: inc = 2; 188: if (ident) 189: { 190: if (findCondition(mod->versionids, ident)) 191: inc = 1; 192: else if (findCondition(global.params.versionids, ident)) 193: inc = 1; 194: else 195: { 196: if (!mod->versionidsNot) 197: mod->versionidsNot = new Strings(); 198: mod->versionidsNot->push(ident->toChars()); 199: } 200: } 201: else if (level <= global.params.versionlevel || level <= mod->versionlevel) 202: inc = 1; 203: } 204: return (inc == 1); 205: } 206: 207: void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) 208: { 209: if (ident) 210: buf->printf("version (%s)", ident->toChars()); 211: else 212: buf->printf("version (%u)", level); 213: } 214: 215: 216: /**************************** StaticIfCondition *******************************/ 217: 218: StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) 219: : Condition(loc) 220: { 221: this->exp = exp; 222: } 223: 224: Condition *StaticIfCondition::syntaxCopy() 225: { 226: return new StaticIfCondition(loc, exp->syntaxCopy()); 227: } 228: 229: int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) 230: { 231: #if 0 232: printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s); 233: if (s) 234: { 235: printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); 236: } 237: #endif 238: if (inc == 0) 239: { 240: if (!sc) 241: { 242: error(loc, "static if conditional cannot be at global scope"); 243: inc = 2; 244: return 0; 245: } 246: 247: sc = sc->push(sc->scopesym); 248: sc->sd = s; // s gets any addMember() 249: sc->flags |= SCOPEstaticif; 250: Expression *e = exp->semantic(sc); 251: sc->pop(); 252: e = e->optimize(WANTvalue | WANTinterpret); 253: if (e->isBool(TRUE)) 254: inc = 1; 255: else if (e->isBool(FALSE)) 256: inc = 2; 257: else 258: { 259: e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); 260: inc = 2; 261: } 262: } 263: return (inc == 1); 264: } 265: 266: void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) 267: { 268: buf->writestring("static if("); 269: exp->toCBuffer(buf, hgs); 270: buf->writeByte(')'); 271: } 272: 273: 274: /**************************** IftypeCondition *******************************/ 275: 276: IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec) 277: : Condition(loc) 278: { 279: this->targ = targ; 280: this->id = id; 281: this->tok = tok; 282: this->tspec = tspec; 283: } 284: 285: Condition *IftypeCondition::syntaxCopy() 286: { 287: return new IftypeCondition(loc, 288: targ->syntaxCopy(), 289: id, 290: tok, 291: tspec ? tspec->syntaxCopy() : NULL); 292: } 293: 294: int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) 295: { 296: //printf("IftypeCondition::include()\n"); 297: if (inc == 0) 298: { 299: if (!sc) 300: { 301: error(loc, "iftype conditional cannot be at global scope"); 302: inc = 2; 303: return 0; 304: } 305: Type *t = targ->trySemantic(loc, sc); 306: if (t) 307: targ = t; 308: else 309: inc = 2; // condition is false 310: 311: if (!t) 312: { 313: } 314: else if (id && tspec) 315: { 316: /* Evaluate to TRUE if targ matches tspec. 317: * If TRUE, declare id as an alias for the specialized type. 318: */ 319: 320: MATCH m; 321: TemplateTypeParameter tp(loc, id, NULL, NULL); 322: 323: TemplateParameters parameters; 324: parameters.setDim(1); 325: parameters.tdata()[0] = &tp; 326: 327: Objects dedtypes; 328: dedtypes.setDim(1); 329: 330: m = targ->deduceType(sc, tspec, &parameters, &dedtypes); 331: if (m == MATCHnomatch || 332: (m != MATCHexact && tok == TOKequal)) 333: inc = 2; 334: else 335: { 336: inc = 1; 337: Type *tded = (Type *)dedtypes.tdata()[0]; 338: if (!tded) 339: tded = targ; 340: Dsymbol *s = new AliasDeclaration(loc, id, tded); 341: s->semantic(sc); 342: sc->insert(s); 343: if (sd) 344: s->addMember(sc, sd, 1); 345: } 346: } 347: else if (id) 348: { 349: /* Declare id as an alias for type targ. Evaluate to TRUE 350: */ 351: Dsymbol *s = new AliasDeclaration(loc, id, targ); 352: s->semantic(sc); 353: sc->insert(s); 354: if (sd) 355: s->addMember(sc, sd, 1); 356: inc = 1; 357: } 358: else if (tspec) 359: { 360: /* Evaluate to TRUE if targ matches tspec 361: */ 362: tspec = tspec->semantic(loc, sc); 363: //printf("targ = %s\n", targ->toChars()); 364: //printf("tspec = %s\n", tspec->toChars()); 365: if (tok == TOKcolon) 366: { if (targ->implicitConvTo(tspec)) 367: inc = 1; 368: else 369: inc = 2; 370: } 371: else /* == */ 372: { if (targ->equals(tspec)) 373: inc = 1; 374: else 375: inc = 2; 376: } 377: } 378: else 379: inc = 1; 380: //printf("inc = %d\n", inc); 381: } 382: return (inc == 1); 383: } 384: 385: void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) 386: { 387: buf->writestring("iftype("); 388: targ->toCBuffer(buf, id, hgs); 389: if (tspec) 390: { 391: if (tok == TOKcolon) 392: buf->writestring(" : "); 393: else 394: buf->writestring(" == "); 395: tspec->toCBuffer(buf, NULL, hgs); 396: } 397: buf->writeByte(')'); 398: } 399: 400: 401: