Properly use the boolean type in expressions

This fixes things like 'if (GetCVar(x))' not working
This commit is contained in:
Leonard2 2016-07-04 02:19:52 +02:00 committed by Christoph Oelckers
parent 7d1dc46665
commit 371896b2cc
3 changed files with 189 additions and 186 deletions

View file

@ -331,11 +331,11 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
} }
else if (sc.CheckToken(TK_True)) else if (sc.CheckToken(TK_True))
{ {
return new FxConstant(1, scpos); return new FxConstant(true, scpos);
} }
else if (sc.CheckToken(TK_False)) else if (sc.CheckToken(TK_False))
{ {
return new FxConstant(0, scpos); return new FxConstant(false, scpos);
} }
else if (sc.CheckToken(TK_IntConst)) else if (sc.CheckToken(TK_IntConst))
{ {

View file

@ -203,7 +203,6 @@ protected:
public: public:
virtual ~FxExpression() {} virtual ~FxExpression() {}
virtual FxExpression *Resolve(FCompileContext &ctx); virtual FxExpression *Resolve(FCompileContext &ctx);
FxExpression *ResolveAsBoolean(FCompileContext &ctx);
virtual bool isConstant() const; virtual bool isConstant() const;
virtual void RequestAddress(); virtual void RequestAddress();
@ -280,6 +279,13 @@ class FxConstant : public FxExpression
ExpVal value; ExpVal value;
public: public:
FxConstant(bool val, const FScriptPosition &pos) : FxExpression(pos)
{
ValueType = value.Type = TypeBool;
value.Int = val;
isresolved = true;
}
FxConstant(int val, const FScriptPosition &pos) : FxExpression(pos) FxConstant(int val, const FScriptPosition &pos) : FxExpression(pos)
{ {
ValueType = value.Type = TypeSInt32; ValueType = value.Type = TypeSInt32;
@ -358,6 +364,19 @@ public:
// //
//========================================================================== //==========================================================================
class FxBoolCast : public FxExpression
{
FxExpression *basex;
public:
FxBoolCast(FxExpression *x);
~FxBoolCast();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
class FxIntCast : public FxExpression class FxIntCast : public FxExpression
{ {
FxExpression *basex; FxExpression *basex;
@ -384,18 +403,6 @@ public:
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
class FxCastStateToBool : public FxExpression
{
FxExpression *basex;
public:
FxCastStateToBool(FxExpression *x);
~FxCastStateToBool();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//========================================================================== //==========================================================================
// //
// FxSign // FxSign

View file

@ -177,38 +177,6 @@ FxExpression *FxExpression::Resolve(FCompileContext &ctx)
return this; return this;
} }
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxExpression::ResolveAsBoolean(FCompileContext &ctx)
{
///FIXME: Use an actual boolean type
FxExpression *x = Resolve(ctx);
if (x != NULL)
{
if (x->ValueType->GetRegType() == REGT_INT)
{
x->ValueType = TypeSInt32;
}
else if (x->ValueType == TypeState)
{
x = new FxCastStateToBool(x);
x = x->Resolve(ctx);
}
else
{
ScriptPosition.Message(MSG_ERROR, "Not an integral type");
delete this;
return NULL;
}
}
return x;
}
//========================================================================== //==========================================================================
// //
// //
@ -327,6 +295,104 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
// //
//========================================================================== //==========================================================================
FxBoolCast::FxBoolCast(FxExpression *x)
: FxExpression(x->ScriptPosition)
{
basex = x;
ValueType = TypeBool;
}
//==========================================================================
//
//
//
//==========================================================================
FxBoolCast::~FxBoolCast()
{
SAFE_DELETE(basex);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxBoolCast::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(basex, ctx);
if (basex->ValueType == TypeBool)
{
FxExpression *x = basex;
basex = nullptr;
delete this;
return x;
}
else if (basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER)
{
if (basex->isConstant())
{
assert(basex->ValueType != TypeState && "We shouldn't be able to generate a constant state ref");
ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
FxExpression *x = new FxConstant(constval.GetBool(), ScriptPosition);
delete this;
return x;
}
return this;
}
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
return nullptr;
}
//==========================================================================
//
//
//
//==========================================================================
ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build)
{
ExpEmit from = basex->Emit(build);
assert(!from.Konst);
assert(basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER);
ExpEmit to(build, REGT_INT);
from.Free(build);
// Preload result with 0.
build->Emit(OP_LI, to.RegNum, 0);
// Check source against 0.
if (from.RegType == REGT_INT)
{
build->Emit(OP_EQ_R, 1, from.RegNum, to.RegNum);
}
else if (from.RegType == REGT_FLOAT)
{
build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.));
}
else if (from.RegNum == REGT_POINTER)
{
build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
}
build->Emit(OP_JMP, 1);
// Reload result with 1 if the comparison fell through.
build->Emit(OP_LI, to.RegNum, 1);
return to;
}
//==========================================================================
//
//
//
//==========================================================================
FxIntCast::FxIntCast(FxExpression *x) FxIntCast::FxIntCast(FxExpression *x)
: FxExpression(x->ScriptPosition) : FxExpression(x->ScriptPosition)
{ {
@ -504,67 +570,6 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build)
// //
//========================================================================== //==========================================================================
FxCastStateToBool::FxCastStateToBool(FxExpression *x)
: FxExpression(x->ScriptPosition)
{
basex = x;
ValueType = TypeSInt32;
}
//==========================================================================
//
//
//
//==========================================================================
FxCastStateToBool::~FxCastStateToBool()
{
SAFE_DELETE(basex);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxCastStateToBool::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(basex, ctx);
assert(basex->ValueType == TypeState);
assert(!basex->isConstant() && "We shouldn't be able to generate a constant state ref");
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpEmit FxCastStateToBool::Emit(VMFunctionBuilder *build)
{
ExpEmit from = basex->Emit(build);
assert(from.RegType == REGT_POINTER);
from.Free(build);
ExpEmit to(build, REGT_INT);
// If from is NULL, produce 0. Otherwise, produce 1.
build->Emit(OP_LI, to.RegNum, 0);
build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC));
build->Emit(OP_JMP, 1);
build->Emit(OP_LI, to.RegNum, 1);
return to;
}
//==========================================================================
//
//
//
//==========================================================================
FxPlusSign::FxPlusSign(FxExpression *operand) FxPlusSign::FxPlusSign(FxExpression *operand)
: FxExpression(operand->ScriptPosition) : FxExpression(operand->ScriptPosition)
{ {
@ -765,10 +770,9 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build) ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build)
{ {
assert(ValueType == Operand->ValueType); assert(Operand->ValueType->GetRegType() == REGT_INT);
assert(ValueType == TypeSInt32);
ExpEmit from = Operand->Emit(build); ExpEmit from = Operand->Emit(build);
assert(from.Konst == 0); assert(!from.Konst);
// Do it in-place. // Do it in-place.
build->Emit(OP_NOT, from.RegNum, from.RegNum, 0); build->Emit(OP_NOT, from.RegNum, from.RegNum, 0);
return from; return from;
@ -806,33 +810,23 @@ FxUnaryNotBoolean::~FxUnaryNotBoolean()
FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
{ {
CHECKRESOLVED(); CHECKRESOLVED();
if (Operand) SAFE_RESOLVE(Operand, ctx);
if (Operand->ValueType != TypeBool)
{ {
Operand = Operand->ResolveAsBoolean(ctx); Operand = new FxBoolCast(Operand);
} SAFE_RESOLVE(Operand, ctx);
if (!Operand)
{
delete this;
return NULL;
} }
if (Operand->IsNumeric() || Operand->IsPointer()) if (Operand->isConstant())
{ {
if (Operand->isConstant()) bool result = !static_cast<FxConstant *>(Operand)->GetValue().GetBool();
{ FxExpression *e = new FxConstant(result, ScriptPosition);
bool result = !static_cast<FxConstant *>(Operand)->GetValue().GetBool();
FxExpression *e = new FxConstant(result, ScriptPosition);
delete this;
return e;
}
}
else
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this; delete this;
return NULL; return e;
} }
ValueType = TypeSInt32;
ValueType = TypeBool;
return this; return this;
} }
@ -844,32 +838,14 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
{ {
assert(Operand->ValueType == ValueType);
assert(ValueType == TypeBool);
ExpEmit from = Operand->Emit(build); ExpEmit from = Operand->Emit(build);
assert(!from.Konst); assert(!from.Konst);
ExpEmit to(build, REGT_INT); // ~x & 1
from.Free(build); build->Emit(OP_NOT, from.RegNum, from.RegNum, 0);
build->Emit(OP_AND_RK, from.RegNum, from.RegNum, build->GetConstantInt(1));
// Preload result with 0. return from;
build->Emit(OP_LI, to.RegNum, 0, 0);
// Check source against 0.
if (from.RegType == REGT_INT)
{
build->Emit(OP_EQ_R, 0, from.RegNum, to.RegNum);
}
else if (from.RegType == REGT_FLOAT)
{
build->Emit(OP_EQF_K, 0, from.RegNum, build->GetConstantFloat(0));
}
else if (from.RegNum == REGT_POINTER)
{
build->Emit(OP_EQA_K, 0, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC));
}
build->Emit(OP_JMP, 1);
// Reload result with 1 if the comparison fell through.
build->Emit(OP_LI, to.RegNum, 1);
return to;
} }
//========================================================================== //==========================================================================
@ -914,6 +890,10 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
return false; return false;
} }
if (left->ValueType == TypeBool && right->ValueType == TypeBool)
{
ValueType = TypeBool;
}
if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT) if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT)
{ {
ValueType = TypeSInt32; ValueType = TypeSInt32;
@ -1276,7 +1256,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
return e; return e;
} }
Promote(ctx); Promote(ctx);
ValueType = TypeSInt32; ValueType = TypeBool;
return this; return this;
} }
@ -1327,7 +1307,7 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
op1.Free(build); op1.Free(build);
} }
// See FxUnaryNotBoolean for comments, since it's the same thing. // See FxBoolCast for comments, since it's the same thing.
build->Emit(OP_LI, to.RegNum, 0, 0); build->Emit(OP_LI, to.RegNum, 0, 0);
build->Emit(instr, check, op1.RegNum, op2.RegNum); build->Emit(instr, check, op1.RegNum, op2.RegNum);
build->Emit(OP_JMP, 1); build->Emit(OP_JMP, 1);
@ -1392,7 +1372,7 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
return e; return e;
} }
Promote(ctx); Promote(ctx);
ValueType = TypeSInt32; ValueType = TypeBool;
return this; return this;
} }
@ -1600,7 +1580,7 @@ FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r)
Operator=o; Operator=o;
left=l; left=l;
right=r; right=r;
ValueType = TypeSInt32; ValueType = TypeBool;
} }
//========================================================================== //==========================================================================
@ -1624,16 +1604,22 @@ FxBinaryLogical::~FxBinaryLogical()
FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx) FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
{ {
CHECKRESOLVED(); CHECKRESOLVED();
if (left) left = left->ResolveAsBoolean(ctx); RESOLVE(left, ctx);
if (right) right = right->ResolveAsBoolean(ctx); RESOLVE(right, ctx);
if (!left || !right) ABORT(right && left);
if (left->ValueType != TypeBool)
{ {
delete this; left = new FxBoolCast(left);
return NULL; SAFE_RESOLVE(left, ctx);
}
if (right->ValueType != TypeBool)
{
right = new FxBoolCast(right);
SAFE_RESOLVE(right, ctx);
} }
int b_left=-1, b_right=-1; int b_left=-1, b_right=-1;
if (left->isConstant()) b_left = static_cast<FxConstant *>(left)->GetValue().GetBool(); if (left->isConstant()) b_left = static_cast<FxConstant *>(left)->GetValue().GetBool();
if (right->isConstant()) b_right = static_cast<FxConstant *>(right)->GetValue().GetBool(); if (right->isConstant()) b_right = static_cast<FxConstant *>(right)->GetValue().GetBool();
@ -1643,13 +1629,13 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
{ {
if (b_left==0 || b_right==0) if (b_left==0 || b_right==0)
{ {
FxExpression *x = new FxConstant(0, ScriptPosition); FxExpression *x = new FxConstant(true, ScriptPosition);
delete this; delete this;
return x; return x;
} }
else if (b_left==1 && b_right==1) else if (b_left==1 && b_right==1)
{ {
FxExpression *x = new FxConstant(1, ScriptPosition); FxExpression *x = new FxConstant(false, ScriptPosition);
delete this; delete this;
return x; return x;
} }
@ -1672,13 +1658,13 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
{ {
if (b_left==1 || b_right==1) if (b_left==1 || b_right==1)
{ {
FxExpression *x = new FxConstant(1, ScriptPosition); FxExpression *x = new FxConstant(true, ScriptPosition);
delete this; delete this;
return x; return x;
} }
if (b_left==0 && b_right==0) if (b_left==0 && b_right==0)
{ {
FxExpression *x = new FxConstant(0, ScriptPosition); FxExpression *x = new FxConstant(false, ScriptPosition);
delete this; delete this;
return x; return x;
} }
@ -1697,14 +1683,6 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
return x; return x;
} }
} }
if (left->ValueType->GetRegType() != REGT_INT)
{
left = new FxIntCast(left);
}
if (right->ValueType->GetRegType() != REGT_INT)
{
right = new FxIntCast(right);
}
return this; return this;
} }
@ -1804,17 +1782,25 @@ FxConditional::~FxConditional()
FxExpression *FxConditional::Resolve(FCompileContext& ctx) FxExpression *FxConditional::Resolve(FCompileContext& ctx)
{ {
CHECKRESOLVED(); CHECKRESOLVED();
if (condition) condition = condition->ResolveAsBoolean(ctx); RESOLVE(condition, ctx);
RESOLVE(truex, ctx); RESOLVE(truex, ctx);
RESOLVE(falsex, ctx); RESOLVE(falsex, ctx);
ABORT(condition && truex && falsex); ABORT(condition && truex && falsex);
if (truex->ValueType->GetRegType() == REGT_INT && falsex->ValueType->GetRegType() == REGT_INT) if (truex->ValueType == TypeBool && falsex->ValueType == TypeBool)
ValueType = TypeBool;
else if (truex->ValueType->GetRegType() == REGT_INT && falsex->ValueType->GetRegType() == REGT_INT)
ValueType = TypeSInt32; ValueType = TypeSInt32;
else if (truex->IsNumeric() && falsex->IsNumeric()) else if (truex->IsNumeric() && falsex->IsNumeric())
ValueType = TypeFloat64; ValueType = TypeFloat64;
//else if (truex->ValueType != falsex->ValueType) //else if (truex->ValueType != falsex->ValueType)
if (condition->ValueType != TypeBool)
{
condition = new FxBoolCast(condition);
SAFE_RESOLVE(condition, ctx);
}
if (condition->isConstant()) if (condition->isConstant())
{ {
ExpVal condval = static_cast<FxConstant *>(condition)->GetValue(); ExpVal condval = static_cast<FxConstant *>(condition)->GetValue();
@ -3735,23 +3721,32 @@ FxIfStatement::~FxIfStatement()
FxExpression *FxIfStatement::Resolve(FCompileContext &ctx) FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
{ {
CHECKRESOLVED(); CHECKRESOLVED();
if (WhenTrue == NULL && WhenFalse == NULL)
if (WhenTrue == nullptr && WhenFalse == nullptr)
{ // We don't do anything either way, so disappear { // We don't do anything either way, so disappear
delete this; delete this;
return NULL; return nullptr;
} }
Condition = Condition->ResolveAsBoolean(ctx);
ABORT(Condition); SAFE_RESOLVE(Condition, ctx);
if (WhenTrue != NULL)
if (Condition->ValueType != TypeBool)
{
Condition = new FxBoolCast(Condition);
SAFE_RESOLVE(Condition, ctx);
}
if (WhenTrue != nullptr)
{ {
WhenTrue = WhenTrue->Resolve(ctx); WhenTrue = WhenTrue->Resolve(ctx);
ABORT(WhenTrue); ABORT(WhenTrue);
} }
if (WhenFalse != NULL) if (WhenFalse != nullptr)
{ {
WhenFalse = WhenFalse->Resolve(ctx); WhenFalse = WhenFalse->Resolve(ctx);
ABORT(WhenFalse); ABORT(WhenFalse);
} }
ValueType = TypeVoid; ValueType = TypeVoid;
if (Condition->isConstant()) if (Condition->isConstant())
@ -3766,6 +3761,7 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
delete this; delete this;
return e; return e;
} }
return this; return this;
} }