blob: 5ace8236511a85b628c742f35b678321b805e2f3 [file] [log] [blame]
/* Compiler implementation of the D programming language
* Copyright (C) 1999-2019 by The D Language Foundation, 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
* https://github.com/D-Programming-Language/dmd/blob/master/src/staticcond.c
*/
#include "mars.h"
#include "expression.h"
#include "mtype.h"
#include "scope.h"
Expression *semantic(Expression *e, Scope *sc);
/********************************************
* Semantically analyze and then evaluate a static condition at compile time.
* This is special because short circuit operators &&, || and ?: at the top
* level are not semantically analyzed if the result of the expression is not
* necessary.
* Params:
* exp = original expression, for error messages
* Returns:
* true if evaluates to true
*/
bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors)
{
if (e->op == TOKandand)
{
AndAndExp *aae = (AndAndExp *)e;
bool result = evalStaticCondition(sc, exp, aae->e1, errors);
if (errors || !result)
return false;
result = evalStaticCondition(sc, exp, aae->e2, errors);
return !errors && result;
}
if (e->op == TOKoror)
{
OrOrExp *ooe = (OrOrExp *)e;
bool result = evalStaticCondition(sc, exp, ooe->e1, errors);
if (errors)
return false;
if (result)
return true;
result = evalStaticCondition(sc, exp, ooe->e2, errors);
return !errors && result;
}
if (e->op == TOKquestion)
{
CondExp *ce = (CondExp *)e;
bool result = evalStaticCondition(sc, exp, ce->econd, errors);
if (errors)
return false;
Expression *leg = result ? ce->e1 : ce->e2;
result = evalStaticCondition(sc, exp, leg, errors);
return !errors && result;
}
unsigned nerrors = global.errors;
sc = sc->startCTFE();
sc->flags |= SCOPEcondition;
e = semantic(e, sc);
e = resolveProperties(sc, e);
sc = sc->endCTFE();
e = e->optimize(WANTvalue);
if (nerrors != global.errors ||
e->op == TOKerror ||
e->type->toBasetype() == Type::terror)
{
errors = true;
return false;
}
if (!e->type->isBoolean())
{
exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars());
errors = true;
return false;
}
e = e->ctfeInterpret();
if (e->isBool(true))
return true;
else if (e->isBool(false))
return false;
e->error("expression %s is not constant", e->toChars());
errors = true;
return false;
}