2009-05-08 13:28:41 +00:00
|
|
|
/*
|
|
|
|
* OpenClonk, http://www.openclonk.org
|
|
|
|
*
|
2009-06-05 13:41:20 +00:00
|
|
|
* Copyright (c) 2001, 2004 Sven Eberhardt
|
|
|
|
* Copyright (c) 2001-2002, 2006 Peter Wortmann
|
|
|
|
* Copyright (c) 2006-2008 Günther Brammer
|
2009-05-08 13:28:41 +00:00
|
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
|
|
|
*
|
|
|
|
* Portions might be copyrighted by other authors who have contributed
|
|
|
|
* to OpenClonk.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
* See isc_license.txt for full license and disclaimer.
|
|
|
|
*
|
|
|
|
* "Clonk" is a registered trademark of Matthes Bender.
|
|
|
|
* See clonk_trademark_license.txt for full license.
|
|
|
|
*/
|
|
|
|
#ifndef INC_C4Value
|
|
|
|
#define INC_C4Value
|
|
|
|
|
|
|
|
#include "C4Id.h"
|
|
|
|
|
|
|
|
// class declarations
|
|
|
|
class C4Value;
|
|
|
|
class C4Object;
|
2009-09-21 04:01:55 +00:00
|
|
|
class C4PropList;
|
2009-05-08 13:28:41 +00:00
|
|
|
class C4String;
|
|
|
|
class C4ValueArray;
|
|
|
|
|
|
|
|
// C4Value type
|
|
|
|
enum C4V_Type
|
|
|
|
{
|
2009-07-20 21:04:29 +00:00
|
|
|
C4V_Any=0, // no type
|
2009-05-08 13:28:41 +00:00
|
|
|
C4V_Int=1, // Integer
|
|
|
|
C4V_Bool=2, // Boolean
|
2009-04-12 12:04:28 +00:00
|
|
|
C4V_PropList=3,
|
2009-05-08 13:28:41 +00:00
|
|
|
C4V_C4Object=4, // Pointer on Object
|
|
|
|
C4V_String=5, // String
|
|
|
|
C4V_Array=6, // pointer on array of values
|
|
|
|
C4V_pC4Value=7, // reference on a value (variable)
|
|
|
|
|
2010-01-25 04:00:59 +00:00
|
|
|
C4V_C4ObjectEnum=9 // enumerated object
|
2009-05-08 13:28:41 +00:00
|
|
|
};
|
|
|
|
|
2009-07-20 21:04:29 +00:00
|
|
|
#define C4V_Last (int) C4V_pC4Value
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
const char* GetC4VName(const C4V_Type Type);
|
|
|
|
char GetC4VID(const C4V_Type Type);
|
|
|
|
C4V_Type GetC4VFromID(char C4VID);
|
|
|
|
|
|
|
|
union C4V_Data {
|
|
|
|
long Int;
|
|
|
|
C4Object * Obj;
|
2009-05-19 22:12:11 +00:00
|
|
|
C4PropList * PropList;
|
2009-05-08 13:28:41 +00:00
|
|
|
C4String * Str;
|
|
|
|
C4Value * Ref;
|
|
|
|
C4ValueArray * Array;
|
|
|
|
// cheat a little - assume that all members have the same length
|
|
|
|
operator void * () { return Ref; }
|
|
|
|
operator const void * () const { return Ref; }
|
|
|
|
bool operator== (C4V_Data b) { return Ref == b.Ref; }
|
|
|
|
C4V_Data& operator= (C4Value * p) { Ref = p; return *this; }
|
|
|
|
};
|
|
|
|
// converter function, used in converter table
|
|
|
|
struct C4VCnvFn
|
|
|
|
{
|
2009-09-05 15:54:56 +00:00
|
|
|
bool (*Function) (C4Value*, C4V_Type); // function to be called; returns whether possible
|
2009-05-08 13:28:41 +00:00
|
|
|
bool Warn;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T> struct C4ValueConv;
|
|
|
|
|
|
|
|
class C4Value
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
2010-01-25 04:00:59 +00:00
|
|
|
C4Value() : NextRef(NULL), FirstRef(NULL), Type(C4V_Any), HasBaseArray(false) { Data.Ref = 0; }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-01-25 04:00:59 +00:00
|
|
|
C4Value(const C4Value &nValue) : Data(nValue.Data), NextRef(NULL), FirstRef(NULL), Type(nValue.Type), HasBaseArray(false)
|
2009-05-08 13:28:41 +00:00
|
|
|
{ AddDataRef(); }
|
|
|
|
|
2010-01-25 04:00:59 +00:00
|
|
|
explicit C4Value(bool data): NextRef(NULL), FirstRef(NULL), Type(C4V_Bool), HasBaseArray(false)
|
2009-07-20 21:04:29 +00:00
|
|
|
{ Data.Int = data; AddDataRef(); }
|
2010-01-25 04:00:59 +00:00
|
|
|
explicit C4Value(int32_t data): NextRef(NULL), FirstRef(NULL), Type(C4V_Int), HasBaseArray(false)
|
2009-07-20 20:42:38 +00:00
|
|
|
{ Data.Int = data; AddDataRef(); }
|
2010-01-25 04:00:59 +00:00
|
|
|
explicit C4Value(C4Object *pObj): NextRef(NULL), FirstRef(NULL), Type(pObj ? C4V_C4Object : C4V_Any), HasBaseArray(false)
|
2009-05-08 13:28:41 +00:00
|
|
|
{ Data.Obj = pObj; AddDataRef(); }
|
2010-01-25 04:00:59 +00:00
|
|
|
explicit C4Value(C4String *pStr): NextRef(NULL), FirstRef(NULL), Type(pStr ? C4V_String : C4V_Any), HasBaseArray(false)
|
2009-05-08 13:28:41 +00:00
|
|
|
{ Data.Str = pStr; AddDataRef(); }
|
2010-01-25 04:00:59 +00:00
|
|
|
explicit C4Value(C4ValueArray *pArray): NextRef(NULL), FirstRef(NULL), Type(pArray ? C4V_Array : C4V_Any), HasBaseArray(false)
|
2009-05-08 13:28:41 +00:00
|
|
|
{ Data.Array = pArray; AddDataRef(); }
|
2010-01-25 04:00:59 +00:00
|
|
|
explicit C4Value(C4PropList *p): NextRef(NULL), FirstRef(NULL), Type(p ? C4V_PropList : C4V_Any), HasBaseArray(false)
|
2009-05-19 22:12:11 +00:00
|
|
|
{ Data.PropList = p; AddDataRef(); }
|
2010-01-25 04:00:59 +00:00
|
|
|
explicit C4Value(C4Value *pVal): NextRef(NULL), FirstRef(NULL), Type(pVal ? C4V_pC4Value : C4V_Any), HasBaseArray(false)
|
2009-05-08 13:28:41 +00:00
|
|
|
{ Data.Ref = pVal; AddDataRef(); }
|
|
|
|
|
|
|
|
C4Value& operator = (const C4Value& nValue);
|
|
|
|
|
|
|
|
~C4Value();
|
|
|
|
|
|
|
|
// Checked getters
|
|
|
|
int32_t getInt() { return ConvertTo(C4V_Int) ? Data.Int : 0; }
|
2009-04-12 12:04:28 +00:00
|
|
|
int32_t getIntOrID() { Deref(); if (Type == C4V_Int || Type == C4V_Bool /* FIXME || Type == C4V_C4ID*/) return Data.Int; else return 0; }
|
2009-05-08 13:28:41 +00:00
|
|
|
bool getBool() { return ConvertTo(C4V_Bool) ? !! Data : 0; }
|
2009-04-12 12:04:28 +00:00
|
|
|
C4ID getC4ID();
|
2009-05-19 22:12:11 +00:00
|
|
|
C4Object * getObj() { return ConvertTo(C4V_C4Object) ? Data.Obj : NULL; }
|
|
|
|
C4PropList * getPropList() { return ConvertTo(C4V_PropList) ? Data.PropList : NULL; }
|
|
|
|
C4String * getStr() { return ConvertTo(C4V_String) ? Data.Str : NULL; }
|
|
|
|
C4ValueArray * getArray() { return ConvertTo(C4V_Array) ? Data.Array : NULL; }
|
|
|
|
C4Value * getRef() { return ConvertTo(C4V_pC4Value) ? Data.Ref : NULL; }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Unchecked getters
|
|
|
|
int32_t _getInt() const { return Data.Int; }
|
|
|
|
bool _getBool() const { return !! Data.Int; }
|
|
|
|
C4Object *_getObj() const { return Data.Obj; }
|
|
|
|
C4String *_getStr() const { return Data.Str; }
|
|
|
|
C4ValueArray *_getArray() const { return Data.Array; }
|
2009-05-19 22:12:11 +00:00
|
|
|
C4PropList *_getPropList() const { return Data.PropList; }
|
2009-05-08 13:28:41 +00:00
|
|
|
C4Value *_getRef() { return Data.Ref; }
|
|
|
|
long _getRaw() const { return Data.Int; }
|
|
|
|
|
|
|
|
// Template versions
|
|
|
|
template <typename T> inline T Get() { return C4ValueConv<T>::FromC4V(*this); }
|
|
|
|
template <typename T> inline T _Get() { return C4ValueConv<T>::_FromC4V(*this); }
|
|
|
|
|
|
|
|
bool operator ! () const { return !GetData(); }
|
2009-07-20 21:45:31 +00:00
|
|
|
inline operator const void* () const { return GetData()?this:0; } // To allow use of C4Value in conditions
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void Set(const C4Value &nValue) { if (this != &nValue) Set(nValue.Data, nValue.Type); }
|
|
|
|
|
|
|
|
void SetInt(int i) { C4V_Data d; d.Int = i; Set(d, C4V_Int); }
|
|
|
|
|
|
|
|
void SetBool(bool b) { C4V_Data d; d.Int = b; Set(d, C4V_Bool); }
|
|
|
|
|
|
|
|
void SetObject(C4Object * Obj) { C4V_Data d; d.Obj = Obj; Set(d, C4V_C4Object); }
|
|
|
|
|
|
|
|
void SetString(C4String * Str) { C4V_Data d; d.Str = Str; Set(d, C4V_String); }
|
|
|
|
|
|
|
|
void SetArray(C4ValueArray * Array) { C4V_Data d; d.Array = Array; Set(d, C4V_Array); }
|
|
|
|
|
2009-05-19 22:12:11 +00:00
|
|
|
void SetPropList(C4PropList * PropList) { C4V_Data d; d.PropList = PropList; Set(d, C4V_PropList); }
|
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
void SetRef(C4Value* nValue) { C4V_Data d; d.Ref = nValue; Set(d, C4V_pC4Value); }
|
|
|
|
|
|
|
|
void Set0();
|
|
|
|
|
|
|
|
bool operator == (const C4Value& Value2) const;
|
|
|
|
bool operator != (const C4Value& Value2) const;
|
|
|
|
|
|
|
|
// Change and set Type to int in case it was any before (avoids GuessType())
|
|
|
|
C4Value & operator += (int32_t by) { GetData().Int += by; GetRefVal().Type=C4V_Int; return *this; }
|
|
|
|
C4Value & operator ++ () { GetData().Int ++; GetRefVal().Type=C4V_Int; return *this; }
|
|
|
|
C4Value operator ++ (int) { C4Value alt = GetRefVal(); GetData().Int ++; GetRefVal().Type=C4V_Int; return alt; }
|
|
|
|
C4Value & operator -- () { GetData().Int --; GetRefVal().Type=C4V_Int; return *this; }
|
|
|
|
C4Value & operator -= (int32_t by) { GetData().Int -= by; GetRefVal().Type=C4V_Int; return *this; }
|
|
|
|
C4Value operator -- (int) { C4Value alt = GetRefVal(); GetData().Int --; GetRefVal().Type=C4V_Int; return alt; }
|
|
|
|
|
|
|
|
void Move(C4Value *nValue);
|
|
|
|
|
|
|
|
C4Value GetRef() { return C4Value(this); }
|
|
|
|
void Deref() { Set(GetRefVal()); }
|
|
|
|
bool IsRef() { return Type == C4V_pC4Value; }
|
|
|
|
|
|
|
|
// get data of referenced value
|
|
|
|
C4V_Data GetData() const { return GetRefVal().Data; }
|
|
|
|
C4V_Data & GetData() { return GetRefVal().Data; }
|
|
|
|
|
|
|
|
// get type of referenced value
|
|
|
|
C4V_Type GetType() const { return GetRefVal().Type; }
|
|
|
|
|
|
|
|
// return referenced value
|
|
|
|
const C4Value & GetRefVal() const;
|
|
|
|
C4Value & GetRefVal();
|
|
|
|
|
|
|
|
// Get the Value at the index. Throws C4AulExecError if not an array
|
|
|
|
void GetArrayElement(int32_t index, C4Value & to, struct C4AulContext *pctx = 0, bool noref = false);
|
|
|
|
// Set the length of the array. Throws C4AulExecError if not an array
|
|
|
|
void SetArrayLength(int32_t size, C4AulContext *cthr);
|
|
|
|
|
|
|
|
const char *GetTypeName() const { return GetC4VName(GetType()); }
|
|
|
|
const char *GetTypeInfo();
|
|
|
|
|
|
|
|
void DenumeratePointer();
|
|
|
|
|
|
|
|
StdStrBuf GetDataString();
|
|
|
|
|
2009-09-05 15:54:56 +00:00
|
|
|
inline bool ConvertTo(C4V_Type vtToType) // convert to dest type
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
C4VCnvFn Fn = C4ScriptCnvMap[Type][vtToType];
|
|
|
|
if (Fn.Function)
|
2009-09-05 15:54:56 +00:00
|
|
|
return (*Fn.Function)(this, vtToType);
|
2009-05-08 13:28:41 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compilation
|
|
|
|
void CompileFunc(StdCompiler *pComp);
|
|
|
|
|
2009-08-12 20:44:09 +00:00
|
|
|
static inline bool IsNullableType(C4V_Type Type)
|
|
|
|
{ return Type == C4V_Int || Type == C4V_Bool; }
|
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
protected:
|
|
|
|
// data
|
|
|
|
C4V_Data Data;
|
|
|
|
|
|
|
|
// reference-list
|
|
|
|
union {
|
|
|
|
C4Value * NextRef;
|
|
|
|
C4ValueArray * BaseArray;
|
|
|
|
};
|
|
|
|
C4Value * FirstRef;
|
|
|
|
|
|
|
|
// data type
|
|
|
|
C4V_Type Type:8;
|
|
|
|
bool HasBaseArray:8;
|
2009-08-15 12:15:10 +00:00
|
|
|
// All referenzes to a C4Value form a linked list, so that they can be updated if the C4Value
|
|
|
|
// has to move, (array is resized), or goes out of scope (func & f() { var r; return r; })
|
|
|
|
// If the reference is in an array, the last c4value in the list has HasBaseArray set, and
|
|
|
|
// BaseArray points to the array. This is used to count the references to elements that an
|
|
|
|
// array has, and maintain the invariant that an array can only have multiple references to
|
|
|
|
// the array OR its elements, but not both. For example, a[0] = a; has to copy the entire
|
|
|
|
// old array into its first element. But a[0]=42; GetLength(a); should not copy the array,
|
|
|
|
// so the element reference count has to be reset after a[0] is removed from the stack.
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4Value * GetNextRef() { if (HasBaseArray) return 0; else return NextRef; }
|
|
|
|
C4ValueArray * GetBaseArray() { if (HasBaseArray) return BaseArray; else return 0; }
|
|
|
|
|
2010-01-25 04:00:59 +00:00
|
|
|
C4Value(C4V_Data nData, C4V_Type nType): Data(nData), NextRef(NULL), FirstRef(NULL), HasBaseArray(false)
|
2009-07-20 21:04:29 +00:00
|
|
|
{ Type = nData || IsNullableType(nType) ? nType : C4V_Any; AddDataRef(); }
|
|
|
|
|
|
|
|
void Set(long nData, C4V_Type nType) { C4V_Data d; d.Int = nData; Set(d, nType); }
|
2009-05-08 13:28:41 +00:00
|
|
|
void Set(C4V_Data nData, C4V_Type nType);
|
|
|
|
|
|
|
|
void AddRef(C4Value *pRef);
|
|
|
|
void DelRef(const C4Value *pRef, C4Value * pNextRef, C4ValueArray * pBaseArray);
|
|
|
|
|
|
|
|
void AddDataRef();
|
|
|
|
void DelDataRef(C4V_Data Data, C4V_Type Type, C4Value * pNextRef, C4ValueArray * pBaseArray);
|
|
|
|
|
|
|
|
static C4VCnvFn C4ScriptCnvMap[C4V_Last+1][C4V_Last+1];
|
2009-09-05 15:54:56 +00:00
|
|
|
static bool FnCnvObject(C4Value *Val, C4V_Type toType);
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-05-19 22:12:11 +00:00
|
|
|
friend class C4PropList;
|
2009-05-08 13:28:41 +00:00
|
|
|
friend class C4AulDefFunc;
|
2009-07-21 14:46:39 +00:00
|
|
|
friend C4Value C4VInt(int32_t iVal);
|
|
|
|
friend C4Value C4VBool(bool fVal);
|
2009-05-08 13:28:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// converter
|
|
|
|
inline C4Value C4VInt(int32_t iVal) { C4V_Data d; d.Int = iVal; return C4Value(d, C4V_Int); }
|
|
|
|
inline C4Value C4VBool(bool fVal) { C4V_Data d; d.Int = fVal; return C4Value(d, C4V_Bool); }
|
2009-04-12 12:04:28 +00:00
|
|
|
C4Value C4VID(C4ID iVal);
|
2009-05-08 13:28:41 +00:00
|
|
|
inline C4Value C4VObj(C4Object *pObj) { return C4Value(pObj); }
|
2009-05-19 22:12:11 +00:00
|
|
|
inline C4Value C4VPropList(C4PropList * p) { return C4Value(p); }
|
2009-05-08 13:28:41 +00:00
|
|
|
inline C4Value C4VString(C4String *pStr) { return C4Value(pStr); }
|
|
|
|
inline C4Value C4VArray(C4ValueArray *pArray) { return C4Value(pArray); }
|
|
|
|
inline C4Value C4VRef(C4Value *pVal) { return pVal->GetRef(); }
|
|
|
|
|
|
|
|
C4Value C4VString(StdStrBuf strString);
|
|
|
|
C4Value C4VString(const char *strString);
|
|
|
|
|
|
|
|
// converter templates
|
|
|
|
template <> struct C4ValueConv<int32_t>
|
|
|
|
{
|
|
|
|
inline static C4V_Type Type() { return C4V_Int; }
|
|
|
|
inline static int32_t FromC4V(C4Value &v) { return v.getInt(); }
|
|
|
|
inline static int32_t _FromC4V(C4Value &v) { return v._getInt(); }
|
|
|
|
inline static C4Value ToC4V(int32_t v) { return C4VInt(v); }
|
|
|
|
};
|
|
|
|
template <> struct C4ValueConv<bool>
|
|
|
|
{
|
|
|
|
inline static C4V_Type Type() { return C4V_Bool; }
|
|
|
|
inline static bool FromC4V(C4Value &v) { return v.getBool(); }
|
|
|
|
inline static bool _FromC4V(C4Value &v) { return v._getBool(); }
|
|
|
|
inline static C4Value ToC4V(bool v) { return C4VBool(v); }
|
|
|
|
};
|
|
|
|
template <> struct C4ValueConv<C4ID>
|
|
|
|
{
|
2009-04-12 12:04:28 +00:00
|
|
|
inline static C4V_Type Type() { return C4V_PropList; }
|
2009-05-08 13:28:41 +00:00
|
|
|
inline static C4ID FromC4V(C4Value &v) { return v.getC4ID(); }
|
2009-04-12 12:04:28 +00:00
|
|
|
inline static C4ID _FromC4V(C4Value &v) { return FromC4V(v); }
|
2009-05-08 13:28:41 +00:00
|
|
|
inline static C4Value ToC4V(C4ID v) { return C4VID(v); }
|
|
|
|
};
|
|
|
|
template <> struct C4ValueConv<C4Object *>
|
|
|
|
{
|
|
|
|
inline static C4V_Type Type() { return C4V_C4Object; }
|
|
|
|
inline static C4Object *FromC4V(C4Value &v) { return v.getObj(); }
|
|
|
|
inline static C4Object *_FromC4V(C4Value &v) { return v._getObj(); }
|
|
|
|
inline static C4Value ToC4V(C4Object *v) { return C4VObj(v); }
|
|
|
|
};
|
|
|
|
template <> struct C4ValueConv<C4String *>
|
|
|
|
{
|
|
|
|
inline static C4V_Type Type() { return C4V_String; }
|
|
|
|
inline static C4String *FromC4V(C4Value &v) { return v.getStr(); }
|
|
|
|
inline static C4String *_FromC4V(C4Value &v) { return v._getStr(); }
|
|
|
|
inline static C4Value ToC4V(C4String *v) { return C4VString(v); }
|
|
|
|
};
|
|
|
|
template <> struct C4ValueConv<C4ValueArray *>
|
|
|
|
{
|
|
|
|
inline static C4V_Type Type() { return C4V_Array; }
|
|
|
|
inline static C4ValueArray *FromC4V(C4Value &v) { return v.getArray(); }
|
|
|
|
inline static C4ValueArray *_FromC4V(C4Value &v) { return v._getArray(); }
|
|
|
|
inline static C4Value ToC4V(C4ValueArray *v) { return C4VArray(v); }
|
|
|
|
};
|
2009-05-19 22:12:11 +00:00
|
|
|
template <> struct C4ValueConv<C4PropList *>
|
|
|
|
{
|
|
|
|
inline static C4V_Type Type() { return C4V_PropList; }
|
|
|
|
inline static C4PropList *FromC4V(C4Value &v) { return v.getPropList(); }
|
|
|
|
inline static C4PropList *_FromC4V(C4Value &v) { return v._getPropList(); }
|
|
|
|
inline static C4Value ToC4V(C4PropList *v) { return C4VPropList(v); }
|
|
|
|
};
|
2009-05-08 13:28:41 +00:00
|
|
|
template <> struct C4ValueConv<C4Value *>
|
|
|
|
{
|
|
|
|
inline static C4V_Type Type() { return C4V_pC4Value; }
|
|
|
|
inline static C4Value *FromC4V(C4Value &v) { return v.getRef(); }
|
|
|
|
inline static C4Value *_FromC4V(C4Value &v) { return v._getRef(); }
|
|
|
|
inline static C4Value ToC4V(C4Value *v) { return C4VRef(v); }
|
|
|
|
};
|
|
|
|
|
|
|
|
// aliases
|
|
|
|
template <> struct C4ValueConv<long> : public C4ValueConv<int32_t> { };
|
|
|
|
#if defined(_MSC_VER) && _MSC_VER <= 1100
|
|
|
|
template <> struct C4ValueConv<int> : public C4ValueConv<int32_t> { };
|
|
|
|
#endif
|
|
|
|
|
2009-08-12 20:44:09 +00:00
|
|
|
extern const C4Value C4VFalse, C4VTrue;
|
|
|
|
|
|
|
|
// type tag to allow other code to recognize C4VNull at compile time
|
|
|
|
class C4NullValue : public C4Value {};
|
|
|
|
extern const C4NullValue C4VNull;
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|