qzdoom/src/thingdef/thingdef_exp.h
Christoph Oelckers d753d41752 - Added NULL checks to all places where class names are passed as DECORATE
parameters.
- All DECORATE parameters are passed as expressions now. This change allows
  for compile time checks of all class names being used in DECORATE so many
  incorrect definitions may output warnings now.
- Changed DECORATE sound and color parameters to use expressions.
- Changed: S_StopChannel now resets the actor's sound flags. The previous bug
  made me think that delaying this until FMod calls the end of sound callback 
  may simply be too late.


SVN r1276 (trunk)
2008-10-25 17:38:00 +00:00

767 lines
18 KiB
C++

#ifndef THINGDEF_EXP_H
#define THINGDEF_EXP_H
/*
** thingdef_exp.h
**
** 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 "m_random.h"
#define CHECKRESOLVED() if (isresolved) return this; isresolved=true;
#define SAFE_DELETE(p) if (p!=NULL) { delete p; p=NULL; }
#define RESOLVE(p,c) if (p!=NULL) p = p->Resolve(c)
#define ABORT(p) if (!(p)) { delete this; return NULL; }
#define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p)
extern PSymbolTable GlobalSymbols;
//==========================================================================
//
//
//
//==========================================================================
struct FCompileContext
{
const PClass *cls;
bool lax;
bool isconst;
PSymbol *FindInClass(FName identifier)
{
return cls? cls->Symbols.FindSymbol(identifier, true) : NULL;
}
PSymbol *FindGlobal(FName identifier)
{
return GlobalSymbols.FindSymbol(identifier, true);
}
};
//==========================================================================
//
//
//
//==========================================================================
struct ExpVal
{
ExpValType Type;
union
{
int Int;
double Float;
void *pointer;
};
int GetInt() const
{
return Type == VAL_Int? Int : Type == VAL_Float? int(Float) : 0;
}
double GetFloat() const
{
return Type == VAL_Int? double(Int) : Type == VAL_Float? Float : 0;
}
bool GetBool() const
{
return (Type == VAL_Int || Type == VAL_Sound) ? !!Int : Type == VAL_Float? Float!=0. : false;
}
template<class T> T *GetPointer() const
{
return Type == VAL_Object || Type == VAL_Pointer? (T*)pointer : NULL;
}
FSoundID GetSoundID() const
{
return Type == VAL_Sound? Int : 0;
}
int GetColor() const
{
return Type == VAL_Color? Int : 0;
}
FName GetName() const
{
return Type == VAL_Name? ENamedName(Int) : NAME_None;
}
FState *GetState() const
{
return Type == VAL_State? (FState*)pointer : NULL;
}
const PClass *GetClass() const
{
return Type == VAL_Class? (const PClass *)pointer : NULL;
}
};
//==========================================================================
//
//
//
//==========================================================================
class FxExpression
{
protected:
FxExpression(const FScriptPosition &pos)
{
isresolved = false;
ScriptPosition = pos;
}
public:
virtual ~FxExpression() {}
virtual FxExpression *Resolve(FCompileContext &ctx);
FxExpression *ResolveAsBoolean(FCompileContext &ctx);
virtual ExpVal EvalExpression (AActor *self);
virtual bool isConstant() const;
virtual void RequestAddress();
FScriptPosition ScriptPosition;
FExpressionType ValueType;
bool isresolved;
};
//==========================================================================
//
// FxIdentifier
//
//==========================================================================
class FxIdentifier : public FxExpression
{
FName Identifier;
public:
FxIdentifier(FName i, const FScriptPosition &p);
FxExpression *Resolve(FCompileContext&);
};
//==========================================================================
//
// FxDotIdentifier
//
//==========================================================================
class FxDotIdentifier : public FxExpression
{
FxExpression *container;
FName Identifier;
public:
FxDotIdentifier(FxExpression*, FName, const FScriptPosition &);
~FxDotIdentifier();
FxExpression *Resolve(FCompileContext&);
};
//==========================================================================
//
// FxClassDefaults
//
//==========================================================================
class FxClassDefaults : public FxExpression
{
FxExpression *obj;
public:
FxClassDefaults(FxExpression*, const FScriptPosition &);
~FxClassDefaults();
FxExpression *Resolve(FCompileContext&);
bool IsDefaultObject() const;
};
//==========================================================================
//
// FxConstant
//
//==========================================================================
class FxConstant : public FxExpression
{
ExpVal value;
public:
FxConstant(int val, const FScriptPosition &pos) : FxExpression(pos)
{
ValueType = value.Type = VAL_Int;
value.Int = val;
isresolved = true;
}
FxConstant(double val, const FScriptPosition &pos) : FxExpression(pos)
{
ValueType = value.Type = VAL_Float;
value.Float = val;
isresolved = true;
}
FxConstant(FSoundID val, const FScriptPosition &pos) : FxExpression(pos)
{
ValueType = value.Type = VAL_Sound;
value.Int = val;
isresolved = true;
}
FxConstant(FName val, const FScriptPosition &pos) : FxExpression(pos)
{
ValueType = value.Type = VAL_Name;
value.Int = val;
isresolved = true;
}
FxConstant(ExpVal cv, const FScriptPosition &pos) : FxExpression(pos)
{
value = cv;
ValueType = cv.Type;
isresolved = true;
}
FxConstant(const PClass *val, const FScriptPosition &pos) : FxExpression(pos)
{
value.pointer = (void*)val;
ValueType = val;
value.Type = VAL_Class;
isresolved = true;
}
FxConstant(FState *state, const FScriptPosition &pos) : FxExpression(pos)
{
value.pointer = state;
ValueType = value.Type = VAL_State;
isresolved = true;
}
static FxExpression *MakeConstant(PSymbol *sym, const FScriptPosition &pos);
bool isConstant() const
{
return true;
}
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
//
//
//==========================================================================
class FxIntCast : public FxExpression
{
FxExpression *basex;
public:
FxIntCast(FxExpression *x);
~FxIntCast();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxSign
//
//==========================================================================
class FxPlusSign : public FxExpression
{
FxExpression *Operand;
public:
FxPlusSign(FxExpression*);
~FxPlusSign();
FxExpression *Resolve(FCompileContext&);
};
//==========================================================================
//
// FxSign
//
//==========================================================================
class FxMinusSign : public FxExpression
{
FxExpression *Operand;
public:
FxMinusSign(FxExpression*);
~FxMinusSign();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxUnaryNot
//
//==========================================================================
class FxUnaryNotBitwise : public FxExpression
{
FxExpression *Operand;
public:
FxUnaryNotBitwise(FxExpression*);
~FxUnaryNotBitwise();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxUnaryNot
//
//==========================================================================
class FxUnaryNotBoolean : public FxExpression
{
FxExpression *Operand;
public:
FxUnaryNotBoolean(FxExpression*);
~FxUnaryNotBoolean();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxBinary
//
//==========================================================================
class FxBinary : public FxExpression
{
public:
int Operator;
FxExpression *left;
FxExpression *right;
FxBinary(int, FxExpression*, FxExpression*);
~FxBinary();
bool ResolveLR(FCompileContext& ctx, bool castnumeric);
};
//==========================================================================
//
// FxBinary
//
//==========================================================================
class FxAddSub : public FxBinary
{
public:
FxAddSub(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxBinary
//
//==========================================================================
class FxMulDiv : public FxBinary
{
public:
FxMulDiv(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxBinary
//
//==========================================================================
class FxCompareRel : public FxBinary
{
public:
FxCompareRel(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxBinary
//
//==========================================================================
class FxCompareEq : public FxBinary
{
public:
FxCompareEq(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxBinary
//
//==========================================================================
class FxBinaryInt : public FxBinary
{
public:
FxBinaryInt(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxBinaryLogical
//
//==========================================================================
class FxBinaryLogical : public FxExpression
{
public:
int Operator;
FxExpression *left;
FxExpression *right;
FxBinaryLogical(int, FxExpression*, FxExpression*);
~FxBinaryLogical();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxConditional
//
//==========================================================================
class FxConditional : public FxExpression
{
public:
FxExpression *condition;
FxExpression *truex;
FxExpression *falsex;
FxConditional(FxExpression*, FxExpression*, FxExpression*);
~FxConditional();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
//
//
//==========================================================================
class FxAbs : public FxExpression
{
FxExpression *val;
public:
FxAbs(FxExpression *v);
~FxAbs();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
//
//
//==========================================================================
class FxRandom : public FxExpression
{
FRandom * rng;
FxExpression *min, *max;
public:
FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos);
~FxRandom();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
//
//
//==========================================================================
class FxRandom2 : public FxExpression
{
FRandom * rng;
FxExpression *mask;
public:
FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos);
~FxRandom2();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxGlobalVariable
//
//==========================================================================
class FxGlobalVariable : public FxExpression
{
public:
PSymbolVariable *var;
bool AddressRequested;
FxGlobalVariable(PSymbolVariable*, const FScriptPosition&);
FxExpression *Resolve(FCompileContext&);
void RequestAddress();
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxClassMember
//
//==========================================================================
class FxClassMember : public FxExpression
{
public:
FxExpression *classx;
PSymbolVariable *membervar;
bool AddressRequested;
FxClassMember(FxExpression*, PSymbolVariable*, const FScriptPosition&);
~FxClassMember();
FxExpression *Resolve(FCompileContext&);
void RequestAddress();
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxSelf
//
//==========================================================================
class FxSelf : public FxExpression
{
public:
FxSelf(const FScriptPosition&);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxArrayElement
//
//==========================================================================
class FxArrayElement : public FxExpression
{
public:
FxExpression *Array;
FxExpression *index;
//bool AddressRequested;
FxArrayElement(FxExpression*, FxExpression*);
~FxArrayElement();
FxExpression *Resolve(FCompileContext&);
//void RequestAddress();
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxFunctionCall
//
//==========================================================================
typedef TDeletingArray<FxExpression*> FArgumentList;
class FxFunctionCall : public FxExpression
{
FxExpression *Self;
FName MethodName;
FArgumentList *ArgList;
public:
FxFunctionCall(FxExpression *self, FName methodname, FArgumentList *args, const FScriptPosition &pos);
~FxFunctionCall();
FxExpression *Resolve(FCompileContext&);
};
//==========================================================================
//
// FxActionSpecialCall
//
//==========================================================================
class FxActionSpecialCall : public FxExpression
{
FxExpression *Self;
int Special;
FArgumentList *ArgList;
public:
FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos);
~FxActionSpecialCall();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// FxGlobalFunctionCall
//
//==========================================================================
class FxGlobalFunctionCall : public FxExpression
{
FName Name;
FArgumentList *ArgList;
public:
FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos);
~FxGlobalFunctionCall();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
//
//
//==========================================================================
class FxClassTypeCast : public FxExpression
{
const PClass *desttype;
FxExpression *basex;
public:
FxClassTypeCast(const PClass *dtype, FxExpression *x);
~FxClassTypeCast();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
//==========================================================================
//
// Only used to resolve the old jump by index feature of DECORATE
//
//==========================================================================
class FxStateByIndex : public FxExpression
{
int index;
public:
FxStateByIndex(int i, const FScriptPosition &pos) : FxExpression(pos)
{
index = i;
}
FxExpression *Resolve(FCompileContext&);
};
//==========================================================================
//
//
//
//==========================================================================
class FxMultiNameState : public FxExpression
{
const PClass *scope;
TArray<FName> names;
public:
FxMultiNameState(const char *statestring, const FScriptPosition &pos);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
};
FxExpression *ParseExpression (FScanner &sc, PClass *cls);
#endif