/* ** 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" #include "m_fixed.h" int testglobalvar = 1337; // just for having one global variable to test with DEFINE_GLOBAL_VARIABLE(testglobalvar) // Accessible actor member variables DEFINE_MEMBER_VARIABLE(alpha, AActor) DEFINE_MEMBER_VARIABLE(angle, AActor) DEFINE_MEMBER_VARIABLE(args, AActor) DEFINE_MEMBER_VARIABLE(ceilingz, AActor) DEFINE_MEMBER_VARIABLE(floorz, AActor) DEFINE_MEMBER_VARIABLE(health, AActor) DEFINE_MEMBER_VARIABLE(pitch, AActor) DEFINE_MEMBER_VARIABLE(special, AActor) DEFINE_MEMBER_VARIABLE(special1, AActor) DEFINE_MEMBER_VARIABLE(special2, AActor) DEFINE_MEMBER_VARIABLE(tid, AActor) DEFINE_MEMBER_VARIABLE(TIDtoHate, AActor) DEFINE_MEMBER_VARIABLE(waterlevel, AActor) DEFINE_MEMBER_VARIABLE(x, AActor) DEFINE_MEMBER_VARIABLE(y, AActor) DEFINE_MEMBER_VARIABLE(z, AActor) DEFINE_MEMBER_VARIABLE(velx, AActor) DEFINE_MEMBER_VARIABLE(vely, AActor) DEFINE_MEMBER_VARIABLE(velz, AActor) DEFINE_MEMBER_VARIABLE_ALIAS(momx, velx, AActor) DEFINE_MEMBER_VARIABLE_ALIAS(momy, vely, AActor) DEFINE_MEMBER_VARIABLE_ALIAS(momz, velz, AActor) DEFINE_MEMBER_VARIABLE(scaleX, AActor) DEFINE_MEMBER_VARIABLE(scaleY, AActor) DEFINE_MEMBER_VARIABLE(Damage, AActor) DEFINE_MEMBER_VARIABLE(Score, AActor) //========================================================================== // // EvalExpression // [GRB] Evaluates previously stored expression // //========================================================================== int EvalExpressionI (DWORD xi, AActor *self) { FxExpression *x = StateParams.Get(xi); if (x == NULL) return 0; return x->EvalExpression (self).GetInt(); } int EvalExpressionCol (DWORD xi, AActor *self) { FxExpression *x = StateParams.Get(xi); if (x == NULL) return 0; return x->EvalExpression (self).GetColor(); } FSoundID EvalExpressionSnd (DWORD xi, AActor *self) { FxExpression *x = StateParams.Get(xi); if (x == NULL) return 0; return x->EvalExpression (self).GetSoundID(); } double EvalExpressionF (DWORD xi, AActor *self) { FxExpression *x = StateParams.Get(xi); if (x == NULL) return 0; return x->EvalExpression (self).GetFloat(); } fixed_t EvalExpressionFix (DWORD xi, AActor *self) { FxExpression *x = StateParams.Get(xi); if (x == NULL) return 0; ExpVal val = x->EvalExpression (self); switch (val.Type) { default: return 0; case VAL_Int: return val.Int << FRACBITS; case VAL_Float: return fixed_t(val.Float*FRACUNIT); } } FName EvalExpressionName (DWORD xi, AActor *self) { FxExpression *x = StateParams.Get(xi); if (x == NULL) return 0; return x->EvalExpression (self).GetName(); } const PClass * EvalExpressionClass (DWORD xi, AActor *self) { FxExpression *x = StateParams.Get(xi); if (x == NULL) return 0; return x->EvalExpression (self).GetClass(); } FState *EvalExpressionState (DWORD xi, AActor *self) { FxExpression *x = StateParams.Get(xi); if (x == NULL) return 0; return x->EvalExpression (self).GetState(); } //========================================================================== // // // //========================================================================== static ExpVal GetVariableValue (void *address, FExpressionType &type) { // NOTE: This cannot access native variables of types // char, short and float. These need to be redefined if necessary! ExpVal ret; switch(type.Type) { case VAL_Int: ret.Type = VAL_Int; ret.Int = *(int*)address; break; case VAL_Sound: ret.Type = VAL_Sound; ret.Int = *(FSoundID*)address; break; case VAL_Name: ret.Type = VAL_Name; ret.Int = *(FName*)address; break; case VAL_Color: ret.Type = VAL_Color; ret.Int = *(int*)address; break; case VAL_Bool: ret.Type = VAL_Int; ret.Int = *(bool*)address; break; case VAL_Float: ret.Type = VAL_Float; ret.Float = *(double*)address; break; case VAL_Fixed: ret.Type = VAL_Float; ret.Float = (*(fixed_t*)address) / 65536.; break; case VAL_Angle: ret.Type = VAL_Float; ret.Float = (*(angle_t*)address) * 90./ANGLE_90; // intentionally not using ANGLE_1 break; case VAL_Object: case VAL_Class: ret.Type = ExpValType(type.Type); // object and class pointers don't retain their specific class information as values ret.pointer = *(void**)address; break; default: ret.Type = VAL_Unknown; ret.pointer = NULL; break; } return ret; } //========================================================================== // // // //========================================================================== ExpVal FxExpression::EvalExpression (AActor *self) { ScriptPosition.Message(MSG_ERROR, "Unresolved expression found"); ExpVal val; val.Type = VAL_Int; val.Int = 0; return val; } //========================================================================== // // // //========================================================================== bool FxExpression::isConstant() const { return false; } //========================================================================== // // // //========================================================================== FxExpression *FxExpression::Resolve(FCompileContext &ctx) { isresolved = true; return this; } //========================================================================== // // // //========================================================================== FxExpression *FxExpression::ResolveAsBoolean(FCompileContext &ctx) { FxExpression *x = Resolve(ctx); if (x != NULL) { switch (x->ValueType.Type) { case VAL_Sound: case VAL_Color: case VAL_Name: x->ValueType = VAL_Int; break; default: break; } } return x; } //========================================================================== // // // //========================================================================== void FxExpression::RequestAddress() { ScriptPosition.Message(MSG_ERROR, "invalid dereference\n"); } //========================================================================== // // // //========================================================================== ExpVal FxConstant::EvalExpression (AActor *self) { return value; } //========================================================================== // // // //========================================================================== FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos) { FxExpression *x; if (sym->SymbolType == SYM_Const) { PSymbolConst *csym = static_cast(sym); switch(csym->ValueType) { case VAL_Int: x = new FxConstant(csym->Value, pos); break; case VAL_Float: x = new FxConstant(csym->Float, pos); break; default: pos.Message(MSG_ERROR, "Invalid constant '%s'\n", csym->SymbolName.GetChars()); return NULL; } } else { pos.Message(MSG_ERROR, "'%s' is not a constant\n", sym->SymbolName.GetChars()); x = NULL; } return x; } //========================================================================== // // // //========================================================================== 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->ValueType == VAL_Int) { FxExpression *x = basex; basex = NULL; delete this; return x; } else if (basex->ValueType == VAL_Float) { if (basex->isConstant()) { ExpVal constval = basex->EvalExpression(NULL); FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition); delete this; return x; } return this; } else { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return NULL; } } //========================================================================== // // // //========================================================================== ExpVal FxIntCast::EvalExpression (AActor *self) { ExpVal baseval = basex->EvalExpression(self); 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); if (Operand->ValueType.isNumeric()) { FxExpression *e = Operand; Operand = NULL; delete this; return e; } else { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return NULL; } } //========================================================================== // // // //========================================================================== 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->ValueType.isNumeric()) { if (Operand->isConstant()) { ExpVal val = Operand->EvalExpression(NULL); 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; } else { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return NULL; } } //========================================================================== // // // //========================================================================== ExpVal FxMinusSign::EvalExpression (AActor *self) { ExpVal ret; if (ValueType == VAL_Int) { ret.Int = -Operand->EvalExpression(self).GetInt(); ret.Type = VAL_Int; } else { ret.Float = -Operand->EvalExpression(self).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); if (Operand->ValueType == VAL_Float && ctx.lax) { // DECORATE allows floats here so cast them to int. Operand = new FxIntCast(Operand); Operand = Operand->Resolve(ctx); if (Operand == NULL) { delete this; return NULL; } } if (Operand->ValueType != VAL_Int) { ScriptPosition.Message(MSG_ERROR, "Integer type expected"); delete this; return NULL; } if (Operand->isConstant()) { int result = ~Operand->EvalExpression(NULL).GetInt(); FxExpression *e = new FxConstant(result, ScriptPosition); delete this; return e; } ValueType = VAL_Int; return this; } //========================================================================== // // // //========================================================================== ExpVal FxUnaryNotBitwise::EvalExpression (AActor *self) { ExpVal ret; ret.Int = ~Operand->EvalExpression(self).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->ValueType.isNumeric() || Operand->ValueType.isPointer()) { if (Operand->isConstant()) { bool result = !Operand->EvalExpression(NULL).GetBool(); FxExpression *e = new FxConstant(result, ScriptPosition); delete this; return e; } } else { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return NULL; } ValueType = VAL_Int; return this; } //========================================================================== // // // //========================================================================== ExpVal FxUnaryNotBoolean::EvalExpression (AActor *self) { ExpVal ret; ret.Int = !Operand->EvalExpression(self).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; } if (left->ValueType == VAL_Int && right->ValueType == VAL_Int) { ValueType = VAL_Int; } else if (left->ValueType.isNumeric() && right->ValueType.isNumeric()) { ValueType = VAL_Float; } else if (left->ValueType == VAL_Object && right->ValueType == VAL_Object) { ValueType = VAL_Object; } else if (left->ValueType == VAL_Class && right->ValueType == VAL_Class) { ValueType = VAL_Class; } else { ValueType = VAL_Unknown; } if (castnumeric) { // later! } 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 (!ValueType.isNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return NULL; } else if (left->isConstant() && right->isConstant()) { if (ValueType == VAL_Float) { double v; double v1 = left->EvalExpression(NULL).GetFloat(); double v2 = right->EvalExpression(NULL).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).GetInt(); int v2 = right->EvalExpression(NULL).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) { ExpVal ret; if (ValueType == VAL_Float) { double v1 = left->EvalExpression(self).GetFloat(); double v2 = right->EvalExpression(self).GetFloat(); ret.Type = VAL_Float; ret.Float = Operator == '+'? v1 + v2 : Operator == '-'? v1 - v2 : 0; } else { int v1 = left->EvalExpression(self).GetInt(); int v2 = right->EvalExpression(self).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 (!ValueType.isNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return NULL; } else if (left->isConstant() && right->isConstant()) { if (ValueType == VAL_Float) { double v; double v1 = left->EvalExpression(NULL).GetFloat(); double v2 = right->EvalExpression(NULL).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).GetInt(); int v2 = right->EvalExpression(NULL).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) { ExpVal ret; if (ValueType == VAL_Float) { double v1 = left->EvalExpression(self).GetFloat(); double v2 = right->EvalExpression(self).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).GetInt(); int v2 = right->EvalExpression(self).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 (!ValueType.isNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return NULL; } else if (left->isConstant() && right->isConstant()) { int v; if (ValueType == VAL_Float) { double v1 = left->EvalExpression(NULL).GetFloat(); double v2 = right->EvalExpression(NULL).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).GetInt(); int v2 = right->EvalExpression(NULL).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) { ExpVal ret; ret.Type = VAL_Int; if (left->ValueType == VAL_Float || right->ValueType == VAL_Float) { double v1 = left->EvalExpression(self).GetFloat(); double v2 = right->EvalExpression(self).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).GetInt(); int v2 = right->EvalExpression(self).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 (!ValueType.isNumeric() && !ValueType.isPointer()) { if (left->ValueType.Type == right->ValueType.Type) { // compare other types? if (left->ValueType == VAL_Sound || left->ValueType == VAL_Color || left->ValueType == VAL_Name) { left->ValueType = right->ValueType = VAL_Int; goto cont; } } ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return NULL; } cont: if (left->isConstant() && right->isConstant()) { int v; if (ValueType == VAL_Float) { double v1 = left->EvalExpression(NULL).GetFloat(); double v2 = right->EvalExpression(NULL).GetFloat(); v = Operator == TK_Eq? v1 == v2 : v1 != v2; } else { int v1 = left->EvalExpression(NULL).GetInt(); int v2 = right->EvalExpression(NULL).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) { ExpVal ret; ret.Type = VAL_Int; if (left->ValueType == VAL_Float || right->ValueType == VAL_Float) { double v1 = left->EvalExpression(self).GetFloat(); double v2 = right->EvalExpression(self).GetFloat(); ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; } else if (ValueType == VAL_Int) { int v1 = left->EvalExpression(self).GetInt(); int v2 = right->EvalExpression(self).GetInt(); ret.Int = Operator == TK_Eq? v1 == v2 : v1 != v2; } else { // Implement pointer comparison ret.Int = 0; } 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; if (ctx.lax && ValueType == VAL_Float) { // For DECORATE which allows floats here. if (left->ValueType != VAL_Int) { left = new FxIntCast(left); left = left->Resolve(ctx); } if (right->ValueType != VAL_Int) { right = new FxIntCast(right); right = left->Resolve(ctx); } if (left == NULL || right == NULL) { delete this; return NULL; } ValueType = VAL_Int; } if (ValueType != VAL_Int) { ScriptPosition.Message(MSG_ERROR, "Integer type expected"); delete this; return NULL; } else if (left->isConstant() && right->isConstant()) { int v1 = left->EvalExpression(NULL).GetInt(); int v2 = right->EvalExpression(NULL).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) { int v1 = left->EvalExpression(self).GetInt(); int v2 = right->EvalExpression(self).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).GetBool(); if (right->isConstant()) b_right = right->EvalExpression(NULL).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) { bool b_left = left->EvalExpression(self).GetBool(); ExpVal ret; ret.Type = VAL_Int; ret.Int = false; if (Operator == TK_AndAnd) { ret.Int = (b_left && right->EvalExpression(self).GetBool()); } else if (Operator == TK_OrOr) { ret.Int = (b_left || right->EvalExpression(self).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 if (truex->ValueType.isNumeric() && falsex->ValueType.isNumeric()) ValueType = VAL_Float; //else if (truex->ValueType != falsex->ValueType) if (condition->isConstant()) { ExpVal condval = condition->EvalExpression(NULL); 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) { ExpVal condval = condition->EvalExpression(self); bool result = condval.GetBool(); FxExpression *e = result? truex:falsex; return e->EvalExpression(self); } //========================================================================== // // // //========================================================================== FxAbs::FxAbs(FxExpression *v) : FxExpression(v->ScriptPosition) { val = v; ValueType = v->ValueType; } //========================================================================== // // // //========================================================================== FxAbs::~FxAbs() { SAFE_DELETE(val); } //========================================================================== // // // //========================================================================== FxExpression *FxAbs::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); SAFE_RESOLVE(val, ctx); if (!ValueType.isNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); delete this; return NULL; } else if (val->isConstant()) { ExpVal value = val->EvalExpression(NULL); 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) { ExpVal value = val->EvalExpression(self); 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) { if (mi != NULL && ma != NULL) { min = new FxIntCast(mi); max = new FxIntCast(ma); } else min = max = NULL; rng = r; 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) { ExpVal val; val.Type = VAL_Int; if (min != NULL && max != NULL) { int minval = min->EvalExpression (self).GetInt(); int maxval = max->EvalExpression (self).GetInt(); if (maxval < minval) { swapvalues (maxval, minval); } val.Int = (*rng)(maxval - minval + 1) + minval; } else { val.Int = (*rng)(); } return val; } //========================================================================== // // // //========================================================================== FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) : FxRandom(r, NULL, NULL, pos) { if (mi != NULL && ma != NULL) { min = mi; max = ma; } } //========================================================================== // // // //========================================================================== ExpVal FxFRandom::EvalExpression (AActor *self) { ExpVal val; val.Type = VAL_Float; int random = (*rng)(0x40000000); double frandom = random / double(0x40000000); if (min != NULL && max != NULL) { double minval = min->EvalExpression (self).GetFloat(); double maxval = max->EvalExpression (self).GetFloat(); if (maxval < minval) { swapvalues (maxval, minval); } val.Float = frandom * (maxval - minval) + minval; } else { val.Float = frandom; } 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) { ExpVal maskval = mask->EvalExpression(self); int imaskval = maskval.GetInt(); maskval.Type = VAL_Int; maskval.Int = rng->Random2(imaskval); return maskval; } //========================================================================== // // // //========================================================================== FxIdentifier::FxIdentifier(FName name, const FScriptPosition &pos) : FxExpression(pos) { Identifier = name; } //========================================================================== // // // //========================================================================== FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) { PSymbol * sym; FxExpression *newex = NULL; //FBaseCVar * cv = NULL; //FString s; int num; //const PClass *Class; CHECKRESOLVED(); // see if the current class (if valid) defines something with this name. if ((sym = ctx.FindInClass(Identifier)) != NULL) { if (sym->SymbolType == SYM_Const) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars()); newex = FxConstant::MakeConstant(sym, ScriptPosition); } else if (sym->SymbolType == SYM_Variable) { PSymbolVariable *vsym = static_cast(sym); ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as member variable, index %d\n", Identifier.GetChars(), vsym->offset); newex = new FxClassMember((new FxSelf(ScriptPosition))->Resolve(ctx), vsym, ScriptPosition); } else { ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars()); } } // now check the global identifiers. else if ((sym = ctx.FindGlobal(Identifier)) != NULL) { if (sym->SymbolType == SYM_Const) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global constant\n", Identifier.GetChars()); newex = FxConstant::MakeConstant(sym, ScriptPosition); } else if (sym->SymbolType == SYM_Variable) // global variables will always be native { PSymbolVariable *vsym = static_cast(sym); ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global variable, address %d\n", Identifier.GetChars(), vsym->offset); newex = new FxGlobalVariable(vsym, ScriptPosition); } else { ScriptPosition.Message(MSG_ERROR, "Invalid global identifier '%s'\n", Identifier.GetChars()); } } /* else if ((Class = PClass::FindClass(Identifier))) { pos.Message(MSG_DEBUGLOG, "Resolving name '%s' as class name\n", Identifier.GetChars()); newex = new FxClassType(Class, ScriptPosition); } } */ // also check for CVars /* else if ((cv = FindCVar(Identifier, NULL)) != NULL) { CLOG(CL_RESOLVE, LPrintf("Resolving name '%s' as cvar\n", Identifier.GetChars())); newex = new FxCVar(cv, ScriptPosition); } */ // amd line specials else if ((num = P_FindLineSpecial(Identifier, NULL, NULL))) { ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", Identifier.GetChars(), num); newex = new FxConstant(num, ScriptPosition); } else { ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars()); newex = new FxConstant(0, ScriptPosition); } delete this; return newex? newex->Resolve(ctx) : NULL; } //========================================================================== // // // //========================================================================== FxSelf::FxSelf(const FScriptPosition &pos) : FxExpression(pos) { } //========================================================================== // // // //========================================================================== FxExpression *FxSelf::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); if (!ctx.cls) { // can't really happen with DECORATE's expression evaluator. ScriptPosition.Message(MSG_ERROR, "self used outside of a member function"); delete this; return NULL; } ValueType = ctx.cls; ValueType.Type = VAL_Object; return this; } //========================================================================== // // // //========================================================================== ExpVal FxSelf::EvalExpression (AActor *self) { ExpVal ret; ret.Type = VAL_Object; ret.pointer = self; return ret; } //========================================================================== // // // //========================================================================== FxGlobalVariable::FxGlobalVariable(PSymbolVariable *mem, const FScriptPosition &pos) : FxExpression(pos) { var = mem; AddressRequested = false; } //========================================================================== // // // //========================================================================== void FxGlobalVariable::RequestAddress() { AddressRequested = true; } //========================================================================== // // // //========================================================================== FxExpression *FxGlobalVariable::Resolve(FCompileContext&) { CHECKRESOLVED(); switch (var->ValueType.Type) { case VAL_Int: case VAL_Bool: ValueType = VAL_Int; break; case VAL_Float: case VAL_Fixed: case VAL_Angle: ValueType = VAL_Float; case VAL_Object: case VAL_Class: ValueType = var->ValueType; break; default: ScriptPosition.Message(MSG_ERROR, "Invalid type for global variable"); delete this; return NULL; } return this; } //========================================================================== // // // //========================================================================== ExpVal FxGlobalVariable::EvalExpression (AActor *self) { ExpVal ret; if (!AddressRequested) { ret = GetVariableValue((void*)var->offset, var->ValueType); } else { ret.pointer = (void*)var->offset; ret.Type = VAL_Pointer; } return ret; } //========================================================================== // // // //========================================================================== FxClassMember::FxClassMember(FxExpression *x, PSymbolVariable* mem, const FScriptPosition &pos) : FxExpression(pos) { classx = x; membervar = mem; AddressRequested = false; //if (classx->IsDefaultObject()) Readonly=true; } //========================================================================== // // // //========================================================================== FxClassMember::~FxClassMember() { SAFE_DELETE(classx); } //========================================================================== // // // //========================================================================== void FxClassMember::RequestAddress() { AddressRequested = true; } //========================================================================== // // // //========================================================================== FxExpression *FxClassMember::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); SAFE_RESOLVE(classx, ctx); if (classx->ValueType != VAL_Object && classx->ValueType != VAL_Class) { ScriptPosition.Message(MSG_ERROR, "Member variable requires a class or object"); delete this; return NULL; } switch (membervar->ValueType.Type) { case VAL_Int: case VAL_Bool: ValueType = VAL_Int; break; case VAL_Float: case VAL_Fixed: case VAL_Angle: ValueType = VAL_Float; break; case VAL_Object: case VAL_Class: case VAL_Array: ValueType = membervar->ValueType; break; default: ScriptPosition.Message(MSG_ERROR, "Invalid type for member variable %s", membervar->SymbolName.GetChars()); delete this; return NULL; } return this; } //========================================================================== // // // //========================================================================== ExpVal FxClassMember::EvalExpression (AActor *self) { char *object = NULL; if (classx->ValueType == VAL_Class) { // not implemented yet } else { object = classx->EvalExpression(self).GetPointer(); } if (object == NULL) { I_Error("Accessing member variable without valid object"); } ExpVal ret; if (!AddressRequested) { ret = GetVariableValue(object + membervar->offset, membervar->ValueType); } else { ret.pointer = object + membervar->offset; ret.Type = VAL_Pointer; } return ret; } //========================================================================== // // // //========================================================================== FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index) :FxExpression(base->ScriptPosition) { Array=base; index = _index; //AddressRequested = false; } //========================================================================== // // // //========================================================================== FxArrayElement::~FxArrayElement() { SAFE_DELETE(Array); SAFE_DELETE(index); } //========================================================================== // // // //========================================================================== /* void FxArrayElement::RequestAddress() { AddressRequested = true; } */ //========================================================================== // // // //========================================================================== FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); SAFE_RESOLVE(Array,ctx); SAFE_RESOLVE(index,ctx); if (index->ValueType == VAL_Float && ctx.lax) { // DECORATE allows floats here so cast them to int. index = new FxIntCast(index); index = index->Resolve(ctx); if (index == NULL) { delete this; return NULL; } } if (index->ValueType != VAL_Int) { ScriptPosition.Message(MSG_ERROR, "Array index must be integer"); delete this; return NULL; } if (Array->ValueType != VAL_Array) { ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays."); delete this; return NULL; } ValueType = Array->ValueType.GetBaseType(); if (ValueType != VAL_Int) { // int arrays only for now ScriptPosition.Message(MSG_ERROR, "Only integer arrays are supported."); delete this; return NULL; } Array->RequestAddress(); return this; } //========================================================================== // // in its current state this won't be able to do more than handle the args array. // //========================================================================== ExpVal FxArrayElement::EvalExpression (AActor *self) { int * arraystart = Array->EvalExpression(self).GetPointer(); int indexval = index->EvalExpression(self).GetInt(); if (indexval < 0 || indexval >= Array->ValueType.size) { I_Error("Array index out of bounds"); } ExpVal ret; ret.Int = arraystart[indexval]; ret.Type = VAL_Int; return ret; } //========================================================================== // // // //========================================================================== FxFunctionCall::FxFunctionCall(FxExpression *self, FName methodname, FArgumentList *args, const FScriptPosition &pos) : FxExpression(pos) { Self = self; MethodName = methodname; ArgList = args; } //========================================================================== // // // //========================================================================== FxFunctionCall::~FxFunctionCall() { SAFE_DELETE(Self); SAFE_DELETE(ArgList); } //========================================================================== // // // //========================================================================== FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) { // There's currently only 2 global functions. // This will have to change later! if (MethodName == NAME_Sin || MethodName == NAME_Cos) { if (Self != NULL) { ScriptPosition.Message(MSG_ERROR, "Global variables cannot have a self pointer"); delete this; return NULL; } FxExpression *x = new FxGlobalFunctionCall(MethodName, ArgList, ScriptPosition); ArgList = NULL; delete this; return x->Resolve(ctx); } int min, max; int special = P_FindLineSpecial(MethodName.GetChars(), &min, &max); if (special > 0 && min >= 0) { int paramcount = ArgList? ArgList->Size() : 0; if (paramcount < min) { ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)", MethodName.GetChars(), min, paramcount); delete this; return NULL; } else if (paramcount > max) { ScriptPosition.Message(MSG_ERROR, "too many parameters for '%s' (expected %d, got %d)", MethodName.GetChars(), max, paramcount); delete this; return NULL; } FxExpression *x = new FxActionSpecialCall(Self, special, ArgList, ScriptPosition); ArgList = NULL; delete this; return x->Resolve(ctx); } ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars()); delete this; return NULL; } //========================================================================== // // // //========================================================================== FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos) : FxExpression(pos) { Self = self; Special = special; ArgList = args; } //========================================================================== // // // //========================================================================== FxActionSpecialCall::~FxActionSpecialCall() { SAFE_DELETE(Self); SAFE_DELETE(ArgList); } //========================================================================== // // // //========================================================================== FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); bool failed = false; if (ArgList != NULL) { for(unsigned i = 0; i < ArgList->Size(); i++) { (*ArgList)[i] = (*ArgList)[i]->Resolve(ctx); if ((*ArgList)[i] == NULL) failed = true; if ((*ArgList)[i]->ValueType != VAL_Int) { if (ctx.lax && ((*ArgList)[i]->ValueType == VAL_Float)) { (*ArgList)[i] = new FxIntCast((*ArgList)[i]); } else { ScriptPosition.Message(MSG_ERROR, "Integer expected for parameter %d", i); failed = true; } } } if (failed) { delete this; return NULL; } } ValueType = VAL_Int; return this; } //========================================================================== // // // //========================================================================== ExpVal FxActionSpecialCall::EvalExpression (AActor *self) { int v[5] = {0,0,0,0,0}; if (Self != NULL) { self = Self->EvalExpression(self).GetPointer(); } if (ArgList != NULL) { for(unsigned i = 0; i < ArgList->Size(); i++) { v[i] = (*ArgList)[i]->EvalExpression(self).GetInt(); } } ExpVal ret; ret.Type = VAL_Int; ret.Int = LineSpecials[Special](NULL, self, false, v[0], v[1], v[2], v[3], v[4]); return ret; } //========================================================================== // // // //========================================================================== FxGlobalFunctionCall::FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos) : FxExpression(pos) { Name = fname; ArgList = args; } //========================================================================== // // // //========================================================================== FxGlobalFunctionCall::~FxGlobalFunctionCall() { SAFE_DELETE(ArgList); } //========================================================================== // // // so far just a quick hack to handle sin and cos // //========================================================================== FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); if (ArgList == NULL || ArgList->Size() != 1) { ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", Name.GetChars()); delete this; return NULL; } (*ArgList)[0] = (*ArgList)[0]->Resolve(ctx); if ((*ArgList)[0] == NULL) { delete this; return NULL; } if (!(*ArgList)[0]->ValueType.isNumeric()) { ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter"); delete this; return NULL; } ValueType = VAL_Float; return this; } //========================================================================== // // // //========================================================================== ExpVal FxGlobalFunctionCall::EvalExpression (AActor *self) { double v = (*ArgList)[0]->EvalExpression(self).GetFloat(); ExpVal ret; ret.Type = VAL_Float; // shall we use the CRT's sin and cos functions? angle_t angle = angle_t(v * ANGLE_90/90.); if (Name == NAME_Sin) ret.Float = FIXED2FLOAT (finesine[angle>>ANGLETOFINESHIFT]); else ret.Float = FIXED2FLOAT (finecosine[angle>>ANGLETOFINESHIFT]); return ret; } //========================================================================== // // // //========================================================================== FxClassTypeCast::FxClassTypeCast(const PClass *dtype, FxExpression *x) : FxExpression(x->ScriptPosition) { desttype = dtype; basex=x; } //========================================================================== // // // //========================================================================== FxClassTypeCast::~FxClassTypeCast() { SAFE_DELETE(basex); } //========================================================================== // // // //========================================================================== FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); SAFE_RESOLVE(basex, ctx); if (basex->ValueType != VAL_Name) { ScriptPosition.Message(MSG_ERROR, "Cannot convert to class type"); delete this; return NULL; } if (basex->isConstant()) { FName clsname = basex->EvalExpression(NULL).GetName(); const PClass *cls = NULL; if (clsname != NAME_None || !ctx.isconst) { cls= PClass::FindClass(clsname); if (cls == NULL) { if (!ctx.lax) { ScriptPosition.Message(MSG_ERROR,"Unknown class name '%s'", clsname.GetChars()); delete this; return NULL; } // Since this happens in released WADs it must pass without a terminal error... :( ScriptPosition.Message(MSG_WARNING, "Unknown class name '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); } else { if (!cls->IsDescendantOf(desttype)) { ScriptPosition.Message(MSG_ERROR,"class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); delete this; return NULL; } } ScriptPosition.Message(MSG_DEBUG,"resolving '%s' as class name", clsname.GetChars()); } FxExpression *x = new FxConstant(cls, ScriptPosition); delete this; return x; } return this; } //========================================================================== // // // //========================================================================== ExpVal FxClassTypeCast::EvalExpression (AActor *self) { FName clsname = basex->EvalExpression(NULL).GetName(); const PClass *cls = PClass::FindClass(clsname); if (!cls->IsDescendantOf(desttype)) { Printf("class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars()); cls = NULL; } ExpVal ret; ret.Type = VAL_Class; ret.pointer = (void*)cls; return ret; } //========================================================================== // // // //========================================================================== FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); if (ctx.cls->ActorInfo == NULL || ctx.cls->ActorInfo->NumOwnedStates == 0) { // This can't really happen assert(false); } if (ctx.cls->ActorInfo->NumOwnedStates <= index) { ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d", ctx.cls->TypeName.GetChars(), index); delete this; return NULL; } FxExpression *x = new FxConstant(ctx.cls->ActorInfo->OwnedStates + index, ScriptPosition); delete this; return x; } //========================================================================== // // // //========================================================================== FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPosition &pos) :FxExpression(pos) { FName scopename; FString statestring = _statestring; int scopeindex = statestring.IndexOf("::"); if (scopeindex >= 0) { scopename = FName(statestring, scopeindex, false); statestring = statestring.Right(statestring.Len() - scopeindex - 2); } else { scopename = NULL; } names = MakeStateNameList(statestring); names.Insert(0, scopename); scope = NULL; } //========================================================================== // // // //========================================================================== FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); if (names[0] == NAME_None) { scope = NULL; } else if (names[0] == NAME_Super) { scope = ctx.cls->ParentClass; } else { scope = PClass::FindClass(names[0]); if (scope == NULL) { ScriptPosition.Message(MSG_ERROR, "Unknown class '%s' in state label", names[0].GetChars()); delete this; return NULL; } else if (!scope->IsDescendantOf(ctx.cls)) { ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.cls->TypeName.GetChars()); delete this; return NULL; } } if (scope != NULL) { FState *destination = NULL; // If the label is class specific we can resolve it right here if (names[1] != NAME_None) { if (scope->ActorInfo == NULL) { ScriptPosition.Message(MSG_ERROR, "'%s' has no actorinfo", names[0].GetChars()); delete this; return NULL; } destination = scope->ActorInfo->FindState(names.Size()-1, &names[1], false); if (destination == NULL) { ScriptPosition.Message(ctx.lax? MSG_WARNING:MSG_ERROR, "Unknown state jump destination"); if (!ctx.lax) { delete this; return NULL; } return this; } } FxExpression *x = new FxConstant(destination, ScriptPosition); delete this; return x; } names.Delete(0); names.ShrinkToFit(); ValueType = VAL_State; return this; } //========================================================================== // // // //========================================================================== ExpVal FxMultiNameState::EvalExpression (AActor *self) { ExpVal ret; ret.Type = VAL_State; ret.pointer = self->GetClass()->ActorInfo->FindState(names.Size(), &names[0]); if (ret.pointer == NULL) { const char *dot=""; Printf("Jump target '"); for (unsigned int i=0;iGetClass()->TypeName.GetChars()); } return ret; } //========================================================================== // // NOTE: I don't expect any of the following to survive Doomscript ;) // //========================================================================== FStateExpressions StateParams; //========================================================================== // // // //========================================================================== void FStateExpressions::Clear() { for(unsigned i=0; i= 0 && num < int(Size())) { assert(expressions[num].expr == NULL || expressions[num].cloned); expressions[num].expr = x; expressions[num].cloned = cloned; } } //========================================================================== // // // //========================================================================== void FStateExpressions::Copy(int dest, int src, int cnt) { for(int i=0; iResolve(ctx); if (expressions[i].expr == NULL) { errorcount++; } else if (expressions[i].constant && !expressions[i].expr->isConstant()) { expressions[i].expr->ScriptPosition.Message(MSG_ERROR, "Constant expression expected"); errorcount++; } } } for(unsigned i=0; iisresolved) { expressions[i].expr->ScriptPosition.Message(MSG_ERROR, "Expression at index %d not resolved\n", i); errorcount++; } } } return errorcount; } //========================================================================== // // // //========================================================================== FxExpression *FStateExpressions::Get(int num) { if (num >= 0 && num < int(Size())) return expressions[num].expr; return NULL; }