qzdoom-gpl/src/thingdef/thingdef_expression.cpp
Christoph Oelckers 7312e6a621 - Added a global symbol table and changed DECORATE parser to put its global
symbols there instead of into AActor.
- Changed the expression evaluator's floating point precision to double.
- Started rewriting the DECORATE expression evaluator to allow more flexibility.
  All the operators use the new functionality but functions, variables and
  constants are yet to be redone.
  While doing this rewrite I noticed that random2 was always evaluated as const.
  This got fixed automatically.


SVN r1264 (trunk)
2008-10-18 17:17:44 +00:00

1377 lines
32 KiB
C++

/*
** thingdef_expression.cpp
**
** Expression evaluation
**
**---------------------------------------------------------------------------
** Copyright 2008 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
** covered by the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or (at
** your option) any later version.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "actor.h"
#include "sc_man.h"
#include "tarray.h"
#include "templates.h"
#include "cmdlib.h"
#include "i_system.h"
#include "m_random.h"
#include "a_pickups.h"
#include "thingdef.h"
#include "p_lnspec.h"
#include "doomstat.h"
#include "thingdef_exp.h"
//==========================================================================
//
// FScriptPosition::Message
//
//==========================================================================
void STACK_ARGS FScriptPosition::Message (int severity, const char *message, ...)
{
FString composed;
if (message == NULL)
{
composed = "Bad syntax.";
}
else
{
va_list arglist;
va_start (arglist, message);
composed.VFormat (message, arglist);
va_end (arglist);
}
const char *type = "";
int level = PRINT_HIGH;
switch (severity)
{
default:
return;
case MSG_WARNING:
type = "warning";
break;
case MSG_ERROR:
type = "error";
break;
case MSG_DEBUG:
if (!developer) return;
type = "message";
break;
case MSG_LOG:
type = "message";
level = PRINT_LOG;
break;
case MSG_DEBUGLOG:
if (!developer) return;
type = "message";
level = PRINT_LOG;
break;
}
Printf (level, "Script %s, \"%s\" line %d:\n%s\n", type,
FileName.GetChars(), ScriptLine, composed.GetChars());
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxConstant::EvalExpression (AActor *self, const PClass *cls)
{
return value;
}
//==========================================================================
//
//
//
//==========================================================================
FxIntCast::FxIntCast(FxExpression *x)
: FxExpression(x->ScriptPosition)
{
basex=x;
ValueType = VAL_Int;
}
//==========================================================================
//
//
//
//==========================================================================
FxIntCast::~FxIntCast()
{
SAFE_DELETE(basex);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(basex, ctx);
if (basex->isConstant())
{
ExpVal constval = basex->EvalExpression(NULL, ctx.cls);
FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition);
delete this;
return x;
}
else if (basex->ValueType == VAL_Int)
{
FxExpression *x = basex;
basex = NULL;
delete this;
return x;
}
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxIntCast::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal baseval = basex->EvalExpression(self, cls);
baseval.Int = baseval.GetInt();
baseval.Type = VAL_Int;
return baseval;
}
//==========================================================================
//
//
//
//==========================================================================
FxPlusSign::FxPlusSign(FxExpression *operand)
: FxExpression(operand->ScriptPosition)
{
Operand=operand;
}
//==========================================================================
//
//
//
//==========================================================================
FxPlusSign::~FxPlusSign()
{
SAFE_DELETE(Operand);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxPlusSign::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(Operand, ctx);
FxExpression *e = Operand;
Operand = NULL;
delete this;
return e;
}
//==========================================================================
//
//
//
//==========================================================================
FxMinusSign::FxMinusSign(FxExpression *operand)
: FxExpression(operand->ScriptPosition)
{
Operand=operand;
}
//==========================================================================
//
//
//
//==========================================================================
FxMinusSign::~FxMinusSign()
{
SAFE_DELETE(Operand);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxMinusSign::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(Operand, ctx);
if (Operand->isConstant())
{
ExpVal val = Operand->EvalExpression(NULL, ctx.cls);
FxExpression *e = val.Type == VAL_Int?
new FxConstant(-val.Int, ScriptPosition) :
new FxConstant(-val.Float, ScriptPosition);
delete this;
return e;
}
ValueType = Operand->ValueType;
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxMinusSign::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal ret;
if (ValueType == VAL_Int)
{
ret.Int = -Operand->EvalExpression(self, cls).GetInt();
ret.Type = VAL_Int;
}
else
{
ret.Float = -Operand->EvalExpression(self, cls).GetFloat();
ret.Type = VAL_Float;
}
return ret;
}
//==========================================================================
//
//
//
//==========================================================================
FxUnaryNotBitwise::FxUnaryNotBitwise(FxExpression *operand)
: FxExpression(operand->ScriptPosition)
{
Operand=operand;
}
//==========================================================================
//
//
//
//==========================================================================
FxUnaryNotBitwise::~FxUnaryNotBitwise()
{
SAFE_DELETE(Operand);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(Operand, ctx);
/* DECORATE allows this.
if (Operand->ValueType != VAL_Int)
{
ScriptPosition.Message(MSG_ERROR, "Integer type expected");
delete this;
return NULL;
}
*/
if (Operand->isConstant())
{
int result = ~Operand->EvalExpression(NULL, ctx.cls).GetInt();
FxExpression *e = new FxConstant(result, ScriptPosition);
delete this;
return e;
}
ValueType = VAL_Int;
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxUnaryNotBitwise::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal ret;
ret.Int = ~Operand->EvalExpression(self, cls).GetInt();
ret.Type = VAL_Int;
return ret;
}
//==========================================================================
//
//
//
//==========================================================================
FxUnaryNotBoolean::FxUnaryNotBoolean(FxExpression *operand)
: FxExpression(operand->ScriptPosition)
{
Operand=operand;
}
//==========================================================================
//
//
//
//==========================================================================
FxUnaryNotBoolean::~FxUnaryNotBoolean()
{
SAFE_DELETE(Operand);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (Operand)
{
Operand = Operand->ResolveAsBoolean(ctx);
}
if (!Operand)
{
delete this;
return NULL;
}
if (Operand->isConstant())
{
bool result = !Operand->EvalExpression(NULL, ctx.cls).GetBool();
FxExpression *e = new FxConstant(result, ScriptPosition);
delete this;
return e;
}
ValueType = VAL_Int;
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxUnaryNotBoolean::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal ret;
ret.Int = !Operand->EvalExpression(self, cls).GetBool();
ret.Type = VAL_Int;
return ret;
}
//==========================================================================
//
//
//
//==========================================================================
FxBinary::FxBinary(int o, FxExpression *l, FxExpression *r)
: FxExpression(l->ScriptPosition)
{
Operator=o;
left=l;
right=r;
}
//==========================================================================
//
//
//
//==========================================================================
FxBinary::~FxBinary()
{
SAFE_DELETE(left);
SAFE_DELETE(right);
}
//==========================================================================
//
//
//
//==========================================================================
bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
{
RESOLVE(left, ctx);
RESOLVE(right, ctx);
if (!left || !right)
{
delete this;
return false;
}
ValueType = left->ValueType;
if (castnumeric && right->ValueType == VAL_Float)
{
ValueType = VAL_Float;
}
/* not for DECORATE - will be activated later
else if (left->ValueType != right->ValueType)
{
ScriptPosition.Message(MSG_ERROR, "Type mismatch in expression");
delete this;
return false;
}
*/
return true;
}
//==========================================================================
//
//
//
//==========================================================================
FxAddSub::FxAddSub(int o, FxExpression *l, FxExpression *r)
: FxBinary(o, l, r)
{
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxAddSub::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (!ResolveLR(ctx, true)) return NULL;
if (left->isConstant() && right->isConstant())
{
if (ValueType == VAL_Float)
{
double v;
double v1 = left->EvalExpression(NULL, ctx.cls).GetFloat();
double v2 = right->EvalExpression(NULL, ctx.cls).GetFloat();
v = Operator == '+'? v1 + v2 :
Operator == '-'? v1 - v2 : 0;
FxExpression *e = new FxConstant(v, ScriptPosition);
delete this;
return e;
}
else
{
int v;
int v1 = left->EvalExpression(NULL, ctx.cls).GetInt();
int v2 = right->EvalExpression(NULL, ctx.cls).GetInt();
v = Operator == '+'? v1 + v2 :
Operator == '-'? v1 - v2 : 0;
FxExpression *e = new FxConstant(v, ScriptPosition);
delete this;
return e;
}
}
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxAddSub::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal ret;
if (left->ValueType == VAL_Float || right->ValueType ==VAL_Float)
{
double v1 = left->EvalExpression(self, cls).GetFloat();
double v2 = right->EvalExpression(self, cls).GetFloat();
ret.Type = VAL_Float;
ret.Float = Operator == '+'? v1 + v2 :
Operator == '-'? v1 - v2 : 0;
}
else
{
int v1 = left->EvalExpression(self, cls).GetInt();
int v2 = right->EvalExpression(self, cls).GetInt();
ret.Type = VAL_Int;
ret.Int = Operator == '+'? v1 + v2 :
Operator == '-'? v1 - v2 : 0;
}
return ret;
}
//==========================================================================
//
//
//
//==========================================================================
FxMulDiv::FxMulDiv(int o, FxExpression *l, FxExpression *r)
: FxBinary(o, l, r)
{
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxMulDiv::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (!ResolveLR(ctx, true)) return NULL;
if (left->isConstant() && right->isConstant())
{
if (ValueType == VAL_Float)
{
double v;
double v1 = left->EvalExpression(NULL, ctx.cls).GetFloat();
double v2 = right->EvalExpression(NULL, ctx.cls).GetFloat();
if (Operator != '*' && v2 == 0)
{
ScriptPosition.Message(MSG_ERROR, "Division by 0");
delete this;
return NULL;
}
v = Operator == '*'? v1 * v2 :
Operator == '/'? v1 / v2 :
Operator == '%'? fmod(v1, v2) : 0;
FxExpression *e = new FxConstant(v, ScriptPosition);
delete this;
return e;
}
else
{
int v;
int v1 = left->EvalExpression(NULL, ctx.cls).GetInt();
int v2 = right->EvalExpression(NULL, ctx.cls).GetInt();
if (Operator != '*' && v2 == 0)
{
ScriptPosition.Message(MSG_ERROR, "Division by 0");
delete this;
return NULL;
}
v = Operator == '*'? v1 * v2 :
Operator == '/'? v1 / v2 :
Operator == '%'? v1 % v2 : 0;
FxExpression *e = new FxConstant(v, ScriptPosition);
delete this;
return e;
}
}
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxMulDiv::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal ret;
if (left->ValueType == VAL_Float || right->ValueType ==VAL_Float)
{
double v1 = left->EvalExpression(self, cls).GetFloat();
double v2 = right->EvalExpression(self, cls).GetFloat();
if (Operator != '*' && v2 == 0)
{
I_Error("Division by 0");
}
ret.Type = VAL_Float;
ret.Float = Operator == '*'? v1 * v2 :
Operator == '/'? v1 / v2 :
Operator == '%'? fmod(v1, v2) : 0;
}
else
{
int v1 = left->EvalExpression(self, cls).GetInt();
int v2 = right->EvalExpression(self, cls).GetInt();
if (Operator != '*' && v2 == 0)
{
I_Error("Division by 0");
}
ret.Type = VAL_Int;
ret.Int = Operator == '*'? v1 * v2 :
Operator == '/'? v1 / v2 :
Operator == '%'? v1 % v2 : 0;
}
return ret;
}
//==========================================================================
//
//
//
//==========================================================================
FxCompareRel::FxCompareRel(int o, FxExpression *l, FxExpression *r)
: FxBinary(o, l, r)
{
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (!ResolveLR(ctx, true)) return false;
if (left->isConstant() && right->isConstant())
{
int v;
if (ValueType == VAL_Float)
{
double v1 = left->EvalExpression(NULL, ctx.cls).GetFloat();
double v2 = right->EvalExpression(NULL, ctx.cls).GetFloat();
v = Operator == '<'? v1 < v2 :
Operator == '>'? v1 > v2 :
Operator == TK_Geq? v1 >= v2 :
Operator == TK_Leq? v1 <= v2 : 0;
}
else
{
int v1 = left->EvalExpression(NULL, ctx.cls).GetInt();
int v2 = right->EvalExpression(NULL, ctx.cls).GetInt();
v = Operator == '<'? v1 < v2 :
Operator == '>'? v1 > v2 :
Operator == TK_Geq? v1 >= v2 :
Operator == TK_Leq? v1 <= v2 : 0;
}
FxExpression *e = new FxConstant(v, ScriptPosition);
delete this;
return e;
}
ValueType = VAL_Int;
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxCompareRel::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal ret;
ret.Type = VAL_Int;
if (left->ValueType == VAL_Float || right->ValueType ==VAL_Float)
{
double v1 = left->EvalExpression(self, cls).GetFloat();
double v2 = right->EvalExpression(self, cls).GetFloat();
ret.Int = Operator == '<'? v1 < v2 :
Operator == '>'? v1 > v2 :
Operator == TK_Geq? v1 >= v2 :
Operator == TK_Leq? v1 <= v2 : 0;
}
else
{
int v1 = left->EvalExpression(self, cls).GetInt();
int v2 = right->EvalExpression(self, cls).GetInt();
ret.Int = Operator == '<'? v1 < v2 :
Operator == '>'? v1 > v2 :
Operator == TK_Geq? v1 >= v2 :
Operator == TK_Leq? v1 <= v2 : 0;
}
return ret;
}
//==========================================================================
//
//
//
//==========================================================================
FxCompareEq::FxCompareEq(int o, FxExpression *l, FxExpression *r)
: FxBinary(o, l, r)
{
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (!ResolveLR(ctx, true)) return false;
if (!left || !right)
{
delete this;
return NULL;
}
if (left->isConstant() && right->isConstant())
{
int v;
if (ValueType == VAL_Float)
{
double v1 = left->EvalExpression(NULL, ctx.cls).GetFloat();
double v2 = right->EvalExpression(NULL, ctx.cls).GetFloat();
v = Operator == TK_Eq? v1 == v2 : v1 != v2;
}
else
{
int v1 = left->EvalExpression(NULL, ctx.cls).GetInt();
int v2 = right->EvalExpression(NULL, ctx.cls).GetInt();
v = Operator == TK_Eq? v1 == v2 : v1 != v2;
}
FxExpression *e = new FxConstant(v, ScriptPosition);
delete this;
return e;
}
ValueType = VAL_Int;
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxCompareEq::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal ret;
ret.Type = VAL_Int;
if (left->ValueType == VAL_Float || right->ValueType ==VAL_Float)
{
double v1 = left->EvalExpression(self, cls).GetFloat();
double v2 = right->EvalExpression(self, cls).GetFloat();
ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2;
}
else
{
int v1 = left->EvalExpression(self, cls).GetInt();
int v2 = right->EvalExpression(self, cls).GetInt();
ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2;
}
return ret;
}
//==========================================================================
//
//
//
//==========================================================================
FxBinaryInt::FxBinaryInt(int o, FxExpression *l, FxExpression *r)
: FxBinary(o, l, r)
{
ValueType = VAL_Int;
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (!ResolveLR(ctx, false)) return false;
/* later! DECORATE doesn't do proper type checks
if (lax)
{
if (left->ValueType == VAL_Float) left = new FxIntCast(left);
if (right->ValueType == VAL_Float) right = new FxIntCast(right);
}
if (left->ValueType != VAL_Int || right->->ValueType != VAL_Int)
{
ScriptPosition.Message(MSG_ERROR, "Type mismatch in expression");
delete this;
return NULL;
}
*/
if (left->isConstant() && right->isConstant())
{
int v1 = left->EvalExpression(NULL, ctx.cls).GetInt();
int v2 = right->EvalExpression(NULL, ctx.cls).GetInt();
FxExpression *e = new FxConstant(
Operator == TK_LShift? v1 << v2 :
Operator == TK_RShift? v1 >> v2 :
Operator == TK_URShift? int(unsigned int(v1) >> v2) :
Operator == '&'? v1 & v2 :
Operator == '|'? v1 | v2 :
Operator == '^'? v1 ^ v2 : 0, ScriptPosition);
delete this;
return e;
}
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxBinaryInt::EvalExpression (AActor *self, const PClass *cls)
{
int v1 = left->EvalExpression(self, cls).GetInt();
int v2 = right->EvalExpression(self, cls).GetInt();
ExpVal ret;
ret.Type = VAL_Int;
ret.Int =
Operator == TK_LShift? v1 << v2 :
Operator == TK_RShift? v1 >> v2 :
Operator == TK_URShift? int(unsigned int(v1) >> v2) :
Operator == '&'? v1 & v2 :
Operator == '|'? v1 | v2 :
Operator == '^'? v1 ^ v2 : 0;
return ret;
}
//==========================================================================
//
//
//
//==========================================================================
FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r)
: FxExpression(l->ScriptPosition)
{
Operator=o;
left=l;
right=r;
ValueType = VAL_Int;
}
//==========================================================================
//
//
//
//==========================================================================
FxBinaryLogical::~FxBinaryLogical()
{
SAFE_DELETE(left);
SAFE_DELETE(right);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (left) left = left->ResolveAsBoolean(ctx);
if (right) right = right->ResolveAsBoolean(ctx);
if (!left || !right)
{
delete this;
return NULL;
}
int b_left=-1, b_right=-1;
if (left->isConstant()) b_left = left->EvalExpression(NULL, ctx.cls).GetBool();
if (right->isConstant()) b_right = right->EvalExpression(NULL, ctx.cls).GetBool();
// Do some optimizations. This will throw out all sub-expressions that are not
// needed to retrieve the final result.
if (Operator == TK_AndAnd)
{
if (b_left==0 || b_right==0)
{
FxExpression *x = new FxConstant(0, ScriptPosition);
delete this;
return x;
}
else if (b_left==1 && b_right==1)
{
FxExpression *x = new FxConstant(1, ScriptPosition);
delete this;
return x;
}
else if (b_left==1)
{
FxExpression *x = right;
right=NULL;
delete this;
return x;
}
else if (b_right==1)
{
FxExpression *x = left;
left=NULL;
delete this;
return x;
}
}
else if (Operator == TK_OrOr)
{
if (b_left==1 || b_right==1)
{
FxExpression *x = new FxConstant(1, ScriptPosition);
delete this;
return x;
}
if (b_left==0 && b_right==0)
{
FxExpression *x = new FxConstant(0, ScriptPosition);
delete this;
return x;
}
else if (b_left==0)
{
FxExpression *x = right;
right=NULL;
delete this;
return x;
}
else if (b_right==0)
{
FxExpression *x = left;
left=NULL;
delete this;
return x;
}
}
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxBinaryLogical::EvalExpression (AActor *self, const PClass *cls)
{
bool b_left = left->EvalExpression(self, cls).GetBool();
ExpVal ret;
ret.Type = VAL_Int;
ret.Int = false;
if (Operator == TK_AndAnd)
{
ret.Int = (b_left && right->EvalExpression(self, cls).GetBool());
}
else if (Operator == TK_OrOr)
{
ret.Int = (b_left || right->EvalExpression(self, cls).GetBool());
}
return ret;
}
//==========================================================================
//
//
//
//==========================================================================
FxConditional::FxConditional(FxExpression *c, FxExpression *t, FxExpression *f)
: FxExpression(c->ScriptPosition)
{
condition = c;
truex=t;
falsex=f;
}
//==========================================================================
//
//
//
//==========================================================================
FxConditional::~FxConditional()
{
SAFE_DELETE(condition);
SAFE_DELETE(truex);
SAFE_DELETE(falsex);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxConditional::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (condition) condition = condition->ResolveAsBoolean(ctx);
RESOLVE(truex, ctx);
RESOLVE(falsex, ctx);
ABORT(condition && truex && falsex);
if (truex->ValueType == VAL_Int && falsex->ValueType == VAL_Int)
ValueType = VAL_Int;
else
ValueType = VAL_Float;
if (condition->isConstant())
{
ExpVal condval = condition->EvalExpression(NULL, ctx.cls);
bool result = condval.GetBool();
FxExpression *e = result? truex:falsex;
delete (result? falsex:truex);
falsex = truex = NULL;
delete this;
return e;
}
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxConditional::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal condval = condition->EvalExpression(self, cls);
bool result = condval.GetBool();
FxExpression *e = result? truex:falsex;
return e->EvalExpression(self, cls);
}
//==========================================================================
//
//
//
//==========================================================================
FxAbs::FxAbs(FxExpression *v)
: FxExpression(v->ScriptPosition)
{
val = v;
Type = VAL_Int;
}
//==========================================================================
//
//
//
//==========================================================================
FxAbs::~FxAbs()
{
SAFE_DELETE(val);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxAbs::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(val, ctx);
if (val->isConstant())
{
ExpVal value = val->EvalExpression(NULL, ctx.cls);
switch (value.Type)
{
case VAL_Int:
value.Int = abs(value.Int);
break;
case VAL_Float:
value.Float = fabs(value.Float);
default:
// shouldn't happen
delete this;
return NULL;
}
FxExpression *x = new FxConstant(value, ScriptPosition);
delete this;
return x;
}
ValueType = val->ValueType;
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxAbs::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal value = val->EvalExpression(self, cls);
switch (value.Type)
{
default:
case VAL_Int:
value.Int = abs(value.Int);
break;
case VAL_Float:
value.Float = fabs(value.Float);
break;
}
return value;
}
//==========================================================================
//
//
//
//==========================================================================
FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos)
: FxExpression(pos)
{
rng = r;
if (min && max)
{
min = new FxIntCast(mi);
max = new FxIntCast(ma);
}
else
{
SAFE_DELETE(mi);
SAFE_DELETE(ma);
min = max = NULL;
}
ValueType = VAL_Int;
}
//==========================================================================
//
//
//
//==========================================================================
FxRandom::~FxRandom()
{
SAFE_DELETE(min);
SAFE_DELETE(max);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxRandom::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
if (min && max)
{
RESOLVE(min, ctx);
RESOLVE(max, ctx);
ABORT(min && max);
}
return this;
};
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxRandom::EvalExpression (AActor *self, const PClass *cls)
{
int minval = min->EvalExpression (self, cls).GetInt();
int maxval = max->EvalExpression (self, cls).GetInt();
ExpVal val;
val.Type = VAL_Int;
if (maxval < minval)
{
swap (maxval, minval);
}
val.Int = (*rng)(maxval - minval + 1) + minval;
return val;
}
//==========================================================================
//
//
//
//==========================================================================
FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos)
: FxExpression(pos)
{
rng = r;
if (m) mask = new FxIntCast(m);
else mask = new FxConstant(-1, pos);
ValueType = VAL_Int;
}
//==========================================================================
//
//
//
//==========================================================================
FxRandom2::~FxRandom2()
{
SAFE_DELETE(mask);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxRandom2::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(mask, ctx);
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxRandom2::EvalExpression (AActor *self, const PClass *cls)
{
ExpVal maskval = mask->EvalExpression(self, cls);
int imaskval = maskval.GetInt();
maskval.Type = VAL_Int;
maskval.Int = rng->Random2(imaskval);
return maskval;
}