ldc/ddmd/cond.d
Pursche 9e953d46f1 Add PS4 version identifier
Add the identifiers that just got added to upstream DMD.
2016-06-13 11:41:17 +02:00

474 lines
12 KiB
D

// Compiler implementation of the D programming language
// Copyright (c) 1999-2015 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
module ddmd.cond;
import core.stdc.string;
import ddmd.arraytypes;
import ddmd.dmodule;
import ddmd.dmodule;
import ddmd.dscope;
import ddmd.dsymbol;
import ddmd.errors;
import ddmd.expression;
import ddmd.globals;
import ddmd.hdrgen;
import ddmd.identifier;
import ddmd.mars;
import ddmd.mtype;
import ddmd.root.outbuffer;
import ddmd.tokens;
import ddmd.visitor;
private __gshared Identifier idUnitTest;
private __gshared Identifier idAssert;
static this()
{
const(char)* s;
s = Token.toChars(TOKunittest);
idUnitTest = Identifier.idPool(s, strlen(s));
s = Token.toChars(TOKassert);
idAssert = Identifier.idPool(s, strlen(s));
}
/***********************************************************
*/
extern (C++) class Condition
{
public:
Loc loc;
// 0: not computed yet
// 1: include
// 2: do not include
int inc;
final extern (D) this(Loc loc)
{
this.loc = loc;
}
abstract Condition syntaxCopy();
abstract int include(Scope* sc, ScopeDsymbol sds);
DebugCondition isDebugCondition()
{
return null;
}
void accept(Visitor v)
{
v.visit(this);
}
}
/***********************************************************
*/
extern (C++) class DVCondition : Condition
{
public:
uint level;
Identifier ident;
Module mod;
final extern (D) this(Module mod, uint level, Identifier ident)
{
super(Loc());
this.mod = mod;
this.level = level;
this.ident = ident;
}
override final Condition syntaxCopy()
{
return this; // don't need to copy
}
override void accept(Visitor v)
{
v.visit(this);
}
}
/***********************************************************
*/
extern (C++) final class DebugCondition : DVCondition
{
public:
static void setGlobalLevel(uint level)
{
global.params.debuglevel = level;
}
static void addGlobalIdent(const(char)* ident)
{
if (!global.params.debugids)
global.params.debugids = new Strings();
global.params.debugids.push(cast(char*)ident);
}
extern (D) this(Module mod, uint level, Identifier ident)
{
super(mod, level, ident);
}
override int include(Scope* sc, ScopeDsymbol sds)
{
//printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
if (inc == 0)
{
inc = 2;
bool definedInModule = false;
if (ident)
{
if (findCondition(mod.debugids, ident))
{
inc = 1;
definedInModule = true;
}
else if (findCondition(global.params.debugids, ident))
inc = 1;
else
{
if (!mod.debugidsNot)
mod.debugidsNot = new Strings();
mod.debugidsNot.push(ident.toChars());
}
}
else if (level <= global.params.debuglevel || level <= mod.debuglevel)
inc = 1;
if (!definedInModule)
printDepsConditional(sc, this, "depsDebug ");
}
return (inc == 1);
}
override DebugCondition isDebugCondition()
{
return this;
}
override void accept(Visitor v)
{
v.visit(this);
}
}
/***********************************************************
*/
extern (C++) final class VersionCondition : DVCondition
{
public:
static void setGlobalLevel(uint level)
{
global.params.versionlevel = level;
}
static bool isPredefined(const(char)* ident)
{
static __gshared const(char)** reserved =
[
"DigitalMars",
"GNU",
"LDC",
"SDC",
"Windows",
"Win32",
"Win64",
"linux",
"OSX",
"iOS",
"TVOS",
"WatchOS",
"FreeBSD",
"OpenBSD",
"NetBSD",
"DragonFlyBSD",
"BSD",
"Solaris",
"Posix",
"AIX",
"Haiku",
"SkyOS",
"SysV3",
"SysV4",
"Hurd",
"Android",
"PlayStation",
"PlayStation4",
"Cygwin",
"MinGW",
"FreeStanding",
"X86",
"X86_64",
"ARM",
"ARM_Thumb",
"ARM_SoftFloat",
"ARM_SoftFP",
"ARM_HardFloat",
"AArch64",
"Epiphany",
"PPC",
"PPC_SoftFloat",
"PPC_HardFloat",
"PPC64",
"IA64",
"MIPS32",
"MIPS64",
"MIPS_O32",
"MIPS_N32",
"MIPS_O64",
"MIPS_N64",
"MIPS_EABI",
"MIPS_SoftFloat",
"MIPS_HardFloat",
"NVPTX",
"NVPTX64",
"SPARC",
"SPARC_V8Plus",
"SPARC_SoftFloat",
"SPARC_HardFloat",
"SPARC64",
"S390",
"S390X",
"SystemZ",
"HPPA",
"HPPA64",
"SH",
"SH64",
"Alpha",
"Alpha_SoftFloat",
"Alpha_HardFloat",
"LittleEndian",
"BigEndian",
"ELFv1",
"ELFv2",
"CRuntime_Bionic",
"CRuntime_DigitalMars",
"CRuntime_Glibc",
"CRuntime_Microsoft",
"D_Coverage",
"D_Ddoc",
"D_InlineAsm_X86",
"D_InlineAsm_X86_64",
"D_LP64",
"D_X32",
"D_HardFloat",
"D_SoftFloat",
"D_PIC",
"D_SIMD",
"D_Version2",
"D_NoBoundsChecks",
"unittest",
"assert",
"all",
"none",
null
];
for (uint i = 0; reserved[i]; i++)
{
if (strcmp(ident, reserved[i]) == 0)
return true;
}
if (ident[0] == 'D' && ident[1] == '_')
return true;
return false;
}
static void checkPredefined(Loc loc, const(char)* ident)
{
if (isPredefined(ident))
error(loc, "version identifier '%s' is reserved and cannot be set", ident);
}
static void addGlobalIdent(const(char)* ident)
{
checkPredefined(Loc(), ident);
addPredefinedGlobalIdent(ident);
}
static void addPredefinedGlobalIdent(const(char)* ident)
{
if (!global.params.versionids)
global.params.versionids = new Strings();
global.params.versionids.push(cast(char*)ident);
}
extern (D) this(Module mod, uint level, Identifier ident)
{
super(mod, level, ident);
}
override int include(Scope* sc, ScopeDsymbol sds)
{
//printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
//if (ident) printf("\tident = '%s'\n", ident->toChars());
if (inc == 0)
{
inc = 2;
bool definedInModule = false;
if (ident)
{
if (findCondition(mod.versionids, ident))
{
inc = 1;
definedInModule = true;
}
else if (findCondition(global.params.versionids, ident))
inc = 1;
else
{
if (!mod.versionidsNot)
mod.versionidsNot = new Strings();
mod.versionidsNot.push(ident.toChars());
}
}
else if (level <= global.params.versionlevel || level <= mod.versionlevel)
inc = 1;
if (!definedInModule &&
(!ident || (!isPredefined(ident.toChars()) && ident != idUnitTest && ident != idAssert)))
{
printDepsConditional(sc, this, "depsVersion ");
}
}
return (inc == 1);
}
override void accept(Visitor v)
{
v.visit(this);
}
}
/***********************************************************
*/
extern (C++) final class StaticIfCondition : Condition
{
public:
Expression exp;
int nest; // limit circular dependencies
extern (D) this(Loc loc, Expression exp)
{
super(loc);
this.exp = exp;
}
override Condition syntaxCopy()
{
return new StaticIfCondition(loc, exp.syntaxCopy());
}
override int include(Scope* sc, ScopeDsymbol sds)
{
version (none)
{
printf("StaticIfCondition::include(sc = %p, sds = %p) this=%p inc = %d\n", sc, sds, this, inc);
if (sds)
{
printf("\ts = '%s', kind = %s\n", sds.toChars(), sds.kind());
}
}
if (inc == 0)
{
if (exp.op == TOKerror || nest > 100)
{
error(loc, (nest > 1000) ? "unresolvable circular static if expression" : "error evaluating static if expression");
goto Lerror;
}
if (!sc)
{
error(loc, "static if conditional cannot be at global scope");
inc = 2;
return 0;
}
++nest;
sc = sc.push(sc.scopesym);
sc.sds = sds; // sds gets any addMember()
//sc->speculative = true; // TODO: static if (is(T U)) { /* U is available */ }
sc.flags |= SCOPEcondition;
sc = sc.startCTFE();
Expression e = exp.semantic(sc);
e = resolveProperties(sc, e);
sc = sc.endCTFE();
sc.pop();
--nest;
// Prevent repeated condition evaluation.
// See: fail_compilation/fail7815.d
if (inc != 0)
return (inc == 1);
if (!e.type.isBoolean())
{
if (e.type.toBasetype() != Type.terror)
exp.error("expression %s of type %s does not have a boolean value", exp.toChars(), e.type.toChars());
goto Lerror;
}
e = e.ctfeInterpret();
if (e.op == TOKerror)
{
goto Lerror;
}
else if (e.isBool(true))
inc = 1;
else if (e.isBool(false))
inc = 2;
else
{
e.error("expression %s is not constant or does not evaluate to a bool", e.toChars());
goto Lerror;
}
}
return (inc == 1);
Lerror:
if (!global.gag)
inc = 2; // so we don't see the error message again
return 0;
}
override void accept(Visitor v)
{
v.visit(this);
}
}
extern (C++) int findCondition(Strings* ids, Identifier ident)
{
if (ids)
{
for (size_t i = 0; i < ids.dim; i++)
{
const(char)* id = (*ids)[i];
if (strcmp(id, ident.toChars()) == 0)
return true;
}
}
return false;
}
// Helper for printing dependency information
extern (C++) void printDepsConditional(Scope* sc, DVCondition condition, const(char)* depType)
{
if (!global.params.moduleDeps || global.params.moduleDepsFile)
return;
OutBuffer* ob = global.params.moduleDeps;
Module imod = sc ? sc.instantiatingModule() : condition.mod;
if (!imod)
return;
ob.writestring(depType);
ob.writestring(imod.toPrettyChars());
ob.writestring(" (");
escapePath(ob, imod.srcfile.toChars());
ob.writestring(") : ");
if (condition.ident)
ob.printf("%s\n", condition.ident.toChars());
else
ob.printf("%d\n", condition.level);
}