forked from Mirrors/openclonk
Add floating point support to C4Value/C4Aul
parent
ff2e4e05b0
commit
6938e64cba
|
@ -1535,7 +1535,7 @@ bool C4Command::InitEvaluation()
|
|||
case C4CMD_MoveTo:
|
||||
{
|
||||
// Target coordinates by Target
|
||||
if (Target) { Tx+=Target->GetX(); Ty+=Target->GetY(); Target=NULL; }
|
||||
if (Target) { Tx+=C4VInt(Target->GetX()); Ty+=Target->GetY(); Target=NULL; }
|
||||
// Adjust coordinates
|
||||
int32_t iTx = Tx._getInt();
|
||||
if (~Data.getInt() & C4CMD_MoveTo_NoPosAdjust) AdjustMoveToTarget(iTx,Ty,FreeMoveTo(cObj),cObj->Shape.Hgt);
|
||||
|
|
|
@ -55,6 +55,9 @@
|
|||
#define C4REAL_MODE C4REAL_MODE_SSE_FLOAT
|
||||
#endif
|
||||
|
||||
#include <boost/type_traits/is_class.hpp>
|
||||
#include <boost/type_traits/is_pod.hpp>
|
||||
|
||||
template<class C4RealImpl>
|
||||
class C4RealBase
|
||||
{
|
||||
|
@ -62,6 +65,7 @@ class C4RealBase
|
|||
|
||||
friend C4RealBase Sin(const C4RealBase &);
|
||||
friend C4RealBase Cos(const C4RealBase &);
|
||||
|
||||
public:
|
||||
inline C4RealBase(int32_t val = 0) : value(val) { }
|
||||
inline C4RealBase(float val) : value(val) {}
|
||||
|
@ -127,6 +131,23 @@ public:
|
|||
// versions via operator bool
|
||||
inline operator bool() const { return static_cast<bool>(value); }
|
||||
inline bool operator !() const { return !operator bool(); }
|
||||
|
||||
// C++03 doesn't support explicitly defaulted ctors, so C4RealBase can't
|
||||
// be a POD, so we can't directly store it into unions. Find a type that
|
||||
// allows this.
|
||||
template<class T, class IsPOD> struct StorageTypeSelector;
|
||||
template<class T>
|
||||
struct StorageTypeSelector<T, boost::false_type> { T v; };
|
||||
template<class T>
|
||||
struct StorageTypeSelector<T, boost::true_type> { typename T::StorageType v; };
|
||||
|
||||
typedef StorageTypeSelector<C4RealImpl, typename boost::is_class<C4RealImpl>::type> StorageType;
|
||||
static_assert(boost::is_pod<StorageType>::value, "C4RealBase: StorageType is not a POD type");
|
||||
|
||||
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
|
||||
|
||||
C4RealBase(StorageType rhs) : value(rhs.v) {}
|
||||
operator StorageType() const { StorageType nrv = {value}; return nrv; }
|
||||
};
|
||||
|
||||
typedef C4RealBase<class C4RealImpl_Fixed> C4Real_Fixed;
|
||||
|
|
|
@ -45,6 +45,9 @@ class C4RealImpl_Fixed
|
|||
static long SineTable[9001]; // external table of sine values
|
||||
|
||||
public:
|
||||
struct StorageType { int32_t v; };
|
||||
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
|
||||
|
||||
inline C4RealImpl_Fixed() : val(0) {}
|
||||
inline C4RealImpl_Fixed(const C4RealImpl_Fixed &rhs) : val(rhs.val) {}
|
||||
explicit inline C4RealImpl_Fixed(int32_t iVal) : val (iVal * FIXED_FPF) { }
|
||||
|
@ -57,6 +60,8 @@ public:
|
|||
explicit inline C4RealImpl_Fixed(float fVal)
|
||||
: val(static_cast<int32_t>(fVal * float(FIXED_FPF)))
|
||||
{ }
|
||||
inline C4RealImpl_Fixed(StorageType rhs) : val(rhs.v) {}
|
||||
operator StorageType() const { StorageType nrv = {val}; return nrv; }
|
||||
|
||||
int32_t to_int() const
|
||||
{
|
||||
|
|
|
@ -63,6 +63,21 @@ public:
|
|||
return f;
|
||||
}
|
||||
|
||||
// To store C4RealImpl_SSE into unions, we're using an anonymous struct
|
||||
// to distinguish types, and an int32_t inside that struct to avoid passing
|
||||
// parameters via the x87 stack.
|
||||
struct StorageType { int32_t v; };
|
||||
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
|
||||
inline C4RealImpl_SSE(StorageType rhs)
|
||||
: value(_mm_load_ss(reinterpret_cast<float*>(&rhs.v)))
|
||||
{}
|
||||
operator StorageType() const
|
||||
{
|
||||
StorageType nrv;
|
||||
_mm_store_ss(reinterpret_cast<float*>(&nrv.v), value);
|
||||
return nrv;
|
||||
}
|
||||
|
||||
// Arithmetics
|
||||
// We're using _ps intrinsics for everything except division because they
|
||||
// have the same latency as their _ss counterparts, but their representa-
|
||||
|
|
|
@ -192,6 +192,7 @@ enum C4AulBCCType
|
|||
AB_CALLFS, // failsafe direct call
|
||||
AB_STACK, // push nulls / pop
|
||||
AB_INT, // constant: int
|
||||
AB_FLOAT, // constant: float
|
||||
AB_BOOL, // constant: bool
|
||||
AB_STRING, // constant: string
|
||||
AB_C4ID, // constant: C4ID
|
||||
|
@ -238,6 +239,7 @@ struct C4AulBCC
|
|||
union
|
||||
{
|
||||
int32_t i;
|
||||
C4Real::StorageType fl;
|
||||
C4String * s;
|
||||
C4AulFunc * f;
|
||||
intptr_t X;
|
||||
|
|
|
@ -173,6 +173,10 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
PushValue(C4VInt(pCPos->Par.i));
|
||||
break;
|
||||
|
||||
case AB_FLOAT:
|
||||
PushValue(C4VFloat(pCPos->Par.fl));
|
||||
break;
|
||||
|
||||
case AB_BOOL:
|
||||
PushValue(C4VBool(!! pCPos->Par.i));
|
||||
break;
|
||||
|
@ -274,7 +278,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
if (!pPar2->_getInt())
|
||||
throw new C4AulExecError(pCurCtx->Obj, "Division by zero");
|
||||
pPar1->SetInt(pPar1->_getInt() / pPar2->_getInt());
|
||||
pPar1->Deref();
|
||||
*pPar1 /= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -282,7 +287,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
pPar1->SetInt(pPar1->_getInt() * pPar2->_getInt());
|
||||
pPar1->Deref();
|
||||
*pPar1 *= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -301,7 +307,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
pPar1->SetInt(pPar1->_getInt() - pPar2->_getInt());
|
||||
pPar1->Deref();
|
||||
*pPar1 -= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -309,7 +316,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
pPar1->SetInt(pPar1->_getInt() + pPar2->_getInt());
|
||||
pPar1->Deref();
|
||||
*pPar1 += *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -405,7 +413,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 *= pPar2 ->_getInt();
|
||||
*pPar1 *= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -415,7 +423,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
if (!pPar2->_getInt())
|
||||
throw new C4AulExecError(pCurCtx->Obj, "Division by zero");
|
||||
*pPar1 /= pPar2->_getInt();
|
||||
*pPar1 /= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -433,7 +441,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 += pPar2 ->_getInt();
|
||||
*pPar1 += *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -441,7 +449,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 -= pPar2 ->_getInt();
|
||||
*pPar1 -= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ enum C4AulTokenType
|
|||
ATT_DIR, // directive
|
||||
ATT_IDTF, // identifier
|
||||
ATT_INT, // integer constant
|
||||
ATT_FLOAT, // floating point constant
|
||||
ATT_BOOL, // boolean constant
|
||||
ATT_STRING, // string constant
|
||||
ATT_NIL, // "nil"
|
||||
|
@ -436,11 +437,11 @@ C4ScriptOpDef C4ScriptOpMap[] =
|
|||
|
||||
// postfix
|
||||
{ 14, "**", AB_Pow, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "/", AB_Div, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "*", AB_Mul, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "/", AB_Div, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 13, "*", AB_Mul, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 13, "%", AB_Mod, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 12, "-", AB_Sub, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 12, "+", AB_Sum, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 12, "-", AB_Sub, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 12, "+", AB_Sum, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 11, "<<", AB_LeftShift, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 11, ">>", AB_RightShift, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 10, "<", AB_LessThan, 1, 0, 0, C4V_Bool, C4V_Int, C4V_Int},
|
||||
|
@ -454,11 +455,11 @@ C4ScriptOpDef C4ScriptOpMap[] =
|
|||
{ 6, "|", AB_BitOr, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 5, "&&", AB_JUMPAND, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
|
||||
{ 4, "||", AB_JUMPOR, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
|
||||
{ 2, "*=", AB_MulIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "/=", AB_DivIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "*=", AB_MulIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
|
||||
{ 2, "/=", AB_DivIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
|
||||
{ 2, "%=", AB_ModIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "+=", AB_Inc, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "-=", AB_Dec, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "+=", AB_Inc, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
|
||||
{ 2, "-=", AB_Dec, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
|
||||
{ 2, "&=", AB_AndIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "|=", AB_OrIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "^=", AB_XOrIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
|
@ -545,6 +546,11 @@ static int32_t StrToI32(char *s, int base, char **scan_end)
|
|||
return result;
|
||||
}
|
||||
|
||||
static float StrToF32(const char *s, char **scan_end)
|
||||
{
|
||||
return strtod(s, scan_end);
|
||||
}
|
||||
|
||||
void C4AulParseState::ClearToken()
|
||||
{
|
||||
// if last token was a string, make sure its ref is deleted
|
||||
|
@ -571,6 +577,7 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
|
|||
TGS_Ident, // getting identifier
|
||||
TGS_Int, // getting integer
|
||||
TGS_IntHex, // getting hexadecimal integer
|
||||
TGS_Float, // getting floating point value
|
||||
TGS_String, // getting string
|
||||
TGS_Dir // getting directive
|
||||
};
|
||||
|
@ -709,6 +716,13 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
|
|||
break;
|
||||
|
||||
case TGS_Int: // integer: parse until non-number is found
|
||||
if (C == '.')
|
||||
{
|
||||
State = TGS_Float;
|
||||
break;
|
||||
}
|
||||
else
|
||||
// Fall through
|
||||
case TGS_IntHex:
|
||||
if ((C < '0') || (C > '9'))
|
||||
{
|
||||
|
@ -741,6 +755,17 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
|
|||
}
|
||||
break;
|
||||
|
||||
case TGS_Float: // float (after decimal point): parse until non-numeric
|
||||
if ((C < '0') || (C > '9'))
|
||||
{
|
||||
Len = Min(Len, C4AUL_MAX_Identifier);
|
||||
SCopy(SPos0, pToken, Len);
|
||||
float value = StrToF32(pToken, 0);
|
||||
*pInt = *reinterpret_cast<int*>(&value);
|
||||
return ATT_FLOAT;
|
||||
}
|
||||
break;
|
||||
|
||||
case TGS_String: // string: parse until '"'; check for eof!
|
||||
|
||||
// string end
|
||||
|
@ -1020,6 +1045,7 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
switch (eType)
|
||||
{
|
||||
case AB_INT:
|
||||
case AB_FLOAT:
|
||||
case AB_BOOL:
|
||||
case AB_STRING:
|
||||
case AB_C4ID:
|
||||
|
@ -2439,6 +2465,12 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
|
|||
switch (val.GetType())
|
||||
{
|
||||
case C4V_Int: AddBCC(AB_INT, val.GetData().Int); break;
|
||||
case C4V_Float:
|
||||
{
|
||||
C4Real::StorageType f = val.getFloat();
|
||||
AddBCC(AB_FLOAT, *reinterpret_cast<intptr_t*>(&f));
|
||||
break;
|
||||
}
|
||||
case C4V_Bool: AddBCC(AB_BOOL, val.GetData().Int); break;
|
||||
case C4V_String:
|
||||
AddBCC(AB_STRING, reinterpret_cast<intptr_t>(val._getStr()));
|
||||
|
@ -2474,6 +2506,12 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
|
|||
Shift();
|
||||
break;
|
||||
}
|
||||
case ATT_FLOAT: // constant in cInt
|
||||
{
|
||||
AddBCC(AB_FLOAT, cInt);
|
||||
Shift();
|
||||
break;
|
||||
}
|
||||
case ATT_BOOL: // constant in cInt
|
||||
{
|
||||
AddBCC(AB_BOOL, cInt);
|
||||
|
|
|
@ -284,6 +284,8 @@ const char* GetC4VName(const C4V_Type Type)
|
|||
return "nil";
|
||||
case C4V_Int:
|
||||
return "int";
|
||||
case C4V_Float:
|
||||
return "float";
|
||||
case C4V_Bool:
|
||||
return "bool";
|
||||
case C4V_C4Object:
|
||||
|
@ -309,6 +311,8 @@ char GetC4VID(const C4V_Type Type)
|
|||
return 'A';
|
||||
case C4V_Int:
|
||||
return 'i';
|
||||
case C4V_Float:
|
||||
return 'f';
|
||||
case C4V_Bool:
|
||||
return 'b';
|
||||
case C4V_C4Object:
|
||||
|
@ -338,6 +342,8 @@ C4V_Type GetC4VFromID(const char C4VID)
|
|||
return C4V_Any;
|
||||
case 'i':
|
||||
return C4V_Int;
|
||||
case 'f':
|
||||
return C4V_Float;
|
||||
case 'b':
|
||||
return C4V_Bool;
|
||||
case 'o':
|
||||
|
@ -400,9 +406,27 @@ bool C4Value::FnCnvObject(C4Value *Val, C4V_Type toType)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool FnI2F(C4Value *val, C4V_Type toType)
|
||||
{
|
||||
assert(val->GetType() == C4V_Int || val->GetType() == C4V_Bool);
|
||||
assert(toType == C4V_Float);
|
||||
val->SetFloat(val->_getInt());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool FnF2I(C4Value *val, C4V_Type toType)
|
||||
{
|
||||
assert(toType == C4V_Int || toType == C4V_Bool);
|
||||
assert(val->GetType() == C4V_Float);
|
||||
val->SetInt(val->_getFloat());
|
||||
return val->ConvertTo(toType);
|
||||
}
|
||||
|
||||
// Type conversion table
|
||||
#define CnvOK 0, false // allow conversion by same value
|
||||
#define CnvOK0 FnOk0, true
|
||||
#define CnvI2F FnI2F, false // convert int->C4Real
|
||||
#define CnvF2I FnF2I, false // convert C4Real->int
|
||||
#define CnvError FnCnvError, true
|
||||
#define CnvDeref FnCnvDeref, false
|
||||
#define CnvPLR FnCnvPLR, false
|
||||
|
@ -413,6 +437,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Any - is always 0, convertible to everything
|
||||
{ CnvOK }, // any same
|
||||
{ CnvOK }, // int
|
||||
{ CnvOK }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvOK }, // PropList
|
||||
{ CnvOK }, // C4Object
|
||||
|
@ -424,6 +449,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Int
|
||||
{ CnvOK }, // any
|
||||
{ CnvOK }, // int same
|
||||
{ CnvI2F }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvOK0 }, // PropList only if 0
|
||||
{ CnvOK0 }, // C4Object only if 0
|
||||
|
@ -432,9 +458,22 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ CnvError }, // Ref
|
||||
{ CnvError }, // PropListRef
|
||||
},
|
||||
{ // C4V_Float
|
||||
{ CnvOK }, // any
|
||||
{ CnvF2I }, // int
|
||||
{ CnvOK }, // float same
|
||||
{ CnvF2I }, // Bool
|
||||
{ CnvOK0 }, // PropList only if 0
|
||||
{ CnvOK0 }, // C4Object only if 0
|
||||
{ CnvOK0 }, // String only if 0
|
||||
{ CnvOK0 }, // Array only if 0
|
||||
{ CnvError }, // Ref
|
||||
{ CnvError }, // PropListRef
|
||||
},
|
||||
{ // C4V_Bool
|
||||
{ CnvOK }, // any
|
||||
{ CnvOK }, // int might be used
|
||||
{ CnvI2F }, // float
|
||||
{ CnvOK }, // Bool same
|
||||
{ CnvError }, // PropList NEVER!
|
||||
{ CnvError }, // C4Object NEVER!
|
||||
|
@ -446,6 +485,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_PropList
|
||||
{ CnvOK }, // any
|
||||
{ CnvError }, // int NEVER!
|
||||
{ CnvError }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvOK }, // PropList same
|
||||
{ CnvObject }, // C4Object
|
||||
|
@ -457,6 +497,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Object
|
||||
{ CnvOK }, // any
|
||||
{ CnvError }, // int NEVER!
|
||||
{ CnvError }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvOK }, // PropList
|
||||
{ CnvOK }, // C4Object same
|
||||
|
@ -468,6 +509,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_String
|
||||
{ CnvOK }, // any
|
||||
{ CnvError }, // int NEVER!
|
||||
{ CnvError }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvError }, // PropList NEVER!
|
||||
{ CnvError }, // C4Object NEVER!
|
||||
|
@ -479,6 +521,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Array
|
||||
{ CnvOK }, // any
|
||||
{ CnvError }, // int NEVER!
|
||||
{ CnvError }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvError }, // PropList NEVER!
|
||||
{ CnvError }, // C4Object NEVER!
|
||||
|
@ -490,6 +533,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Ref - resolve reference and retry type check
|
||||
{ CnvDeref }, // any
|
||||
{ CnvDeref }, // int
|
||||
{ CnvDeref }, // float
|
||||
{ CnvDeref }, // Bool
|
||||
{ CnvDeref }, // PropList
|
||||
{ CnvDeref }, // C4Object
|
||||
|
@ -501,6 +545,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Ref - resolve reference and retry type check
|
||||
{ CnvPLR }, // any
|
||||
{ CnvPLR }, // int
|
||||
{ CnvPLR }, // float
|
||||
{ CnvPLR }, // Bool
|
||||
{ CnvPLR }, // PropList
|
||||
{ CnvPLR }, // C4Object
|
||||
|
@ -513,6 +558,8 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
|
||||
#undef CnvOK
|
||||
#undef CnvOK0
|
||||
#undef CnvI2F
|
||||
#undef CnvF2I
|
||||
#undef CnvError
|
||||
#undef CnvDeref
|
||||
#undef CnvPLR
|
||||
|
@ -529,6 +576,8 @@ StdStrBuf C4Value::GetDataString()
|
|||
{
|
||||
case C4V_Int:
|
||||
return FormatString("%ld", static_cast<long>(Data.Int));
|
||||
case C4V_Float:
|
||||
return FormatString("%f", static_cast<float>(C4Real(Data.Float)));
|
||||
case C4V_Bool:
|
||||
return StdStrBuf(Data ? "true" : "false");
|
||||
case C4V_C4Object:
|
||||
|
@ -671,6 +720,12 @@ void C4Value::CompileFunc(StdCompiler *pComp)
|
|||
Data.Int = iTmp;
|
||||
|
||||
break;
|
||||
case C4V_Float:
|
||||
{
|
||||
C4Real val = Data.Float;
|
||||
pComp->Value(val);
|
||||
Data.Float = val;
|
||||
}
|
||||
|
||||
// object: save object number instead
|
||||
case C4V_C4Object: case C4V_PropList:
|
||||
|
@ -761,20 +816,25 @@ bool C4Value::operator == (const C4Value& Value2) const
|
|||
assert(!Data);
|
||||
return Value2.Type == Type;
|
||||
case C4V_Int:
|
||||
switch (Value2.Type)
|
||||
{
|
||||
case C4V_Int:
|
||||
case C4V_Bool:
|
||||
return Data == Value2.Data;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case C4V_Bool:
|
||||
switch (Value2.Type)
|
||||
{
|
||||
case C4V_Int:
|
||||
case C4V_Bool:
|
||||
return Data == Value2.Data;
|
||||
case C4V_Float:
|
||||
return C4Real(Value2.Data.Float) == static_cast<int>(Data.Int);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case C4V_Float:
|
||||
switch (Value2.Type)
|
||||
{
|
||||
case C4V_Int:
|
||||
case C4V_Bool:
|
||||
return C4Real(Data.Float) == static_cast<int>(Data.Int);
|
||||
case C4V_Float:
|
||||
return Data.Float == Value2.Data.Float;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define INC_C4Value
|
||||
|
||||
#include "C4Id.h"
|
||||
#include "C4Real.h"
|
||||
|
||||
// class declarations
|
||||
class C4Value;
|
||||
|
@ -32,18 +33,19 @@ class C4ValueArray;
|
|||
// C4Value type
|
||||
enum C4V_Type
|
||||
{
|
||||
C4V_Any=0, // nil
|
||||
C4V_Int=1,
|
||||
C4V_Bool=2,
|
||||
C4V_PropList=3,
|
||||
C4V_C4Object=4,
|
||||
C4V_String=5,
|
||||
C4V_Array=6,
|
||||
C4V_Ref=7, // reference to a value (variable)
|
||||
C4V_PropListRef=8, // reference to an entry in a proplist
|
||||
C4V_Any, // nil
|
||||
C4V_Int,
|
||||
C4V_Float,
|
||||
C4V_Bool,
|
||||
C4V_PropList,
|
||||
C4V_C4Object,
|
||||
C4V_String,
|
||||
C4V_Array,
|
||||
C4V_Ref, // reference to a value (variable)
|
||||
C4V_PropListRef, // reference to an entry in a proplist
|
||||
|
||||
C4V_C4ObjectEnum=9, // enumerated object
|
||||
C4V_C4DefEnum=10 // enumerated object
|
||||
C4V_C4ObjectEnum, // enumerated object
|
||||
C4V_C4DefEnum // enumerated object
|
||||
};
|
||||
|
||||
#define C4V_Last (int) C4V_PropListRef
|
||||
|
@ -54,6 +56,7 @@ C4V_Type GetC4VFromID(char C4VID);
|
|||
|
||||
union C4V_Data
|
||||
{
|
||||
C4Real::StorageType Float;
|
||||
intptr_t Int;
|
||||
C4Object * Obj;
|
||||
C4PropList * PropList;
|
||||
|
@ -88,6 +91,8 @@ public:
|
|||
{ Data.Int = data; AddDataRef(); }
|
||||
explicit C4Value(int32_t data): NextRef(NULL), FirstRef(NULL), Type(C4V_Int), HasBaseArray(false)
|
||||
{ Data.Int = data; AddDataRef(); }
|
||||
explicit C4Value(C4Real data): NextRef(NULL), FirstRef(NULL), Type(C4V_Float), HasBaseArray(false)
|
||||
{ Data.Float = data; AddDataRef(); }
|
||||
explicit C4Value(C4Object *pObj): NextRef(NULL), FirstRef(NULL), Type(pObj ? C4V_C4Object : C4V_Any), HasBaseArray(false)
|
||||
{ Data.Obj = pObj; AddDataRef(); }
|
||||
explicit C4Value(C4String *pStr): NextRef(NULL), FirstRef(NULL), Type(pStr ? C4V_String : C4V_Any), HasBaseArray(false)
|
||||
|
@ -105,6 +110,7 @@ public:
|
|||
|
||||
// Checked getters
|
||||
int32_t getInt() { return ConvertTo(C4V_Int) ? Data.Int : 0; }
|
||||
C4Real getFloat() { return ConvertTo(C4V_Float) ? Data.Float : C4Real(0); }
|
||||
bool getBool() { return ConvertTo(C4V_Bool) ? !! Data : 0; }
|
||||
C4ID getC4ID();
|
||||
C4Object * getObj() { return ConvertTo(C4V_C4Object) ? Data.Obj : NULL; }
|
||||
|
@ -115,6 +121,7 @@ public:
|
|||
|
||||
// Unchecked getters
|
||||
int32_t _getInt() const { return Data.Int; }
|
||||
C4Real _getFloat() const { return Data.Float; }
|
||||
bool _getBool() const { return !! Data.Int; }
|
||||
C4Object *_getObj() const { return Data.Obj; }
|
||||
C4String *_getStr() const { return Data.Str; }
|
||||
|
@ -133,6 +140,8 @@ public:
|
|||
|
||||
void SetInt(int i) { C4V_Data d; d.Int = i; Set(d, C4V_Int); }
|
||||
|
||||
void SetFloat(C4Real f) { C4V_Data d; d.Float = f; Set(d, C4V_Float); }
|
||||
|
||||
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); }
|
||||
|
@ -153,10 +162,29 @@ public:
|
|||
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 -= (int32_t by) { GetData().Int -= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
C4Value & operator *= (int32_t by) { GetData().Int *= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
C4Value & operator /= (int32_t by) { GetData().Int /= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
#define C4VALUE_ARITHMETIC_OPERATOR(op) \
|
||||
/* combined arithmetic and assignment op */ \
|
||||
C4Value &operator op##= (const C4Value &rhs) \
|
||||
{ \
|
||||
/* Promote numeric values to float if any operand is float */ \
|
||||
if (rhs.GetType() == C4V_Float || GetType() == C4V_Float) \
|
||||
{ \
|
||||
C4Real lhsf = getFloat(); \
|
||||
C4Real rhsf = C4Value(rhs).getFloat(); \
|
||||
SetFloat(lhsf op##= rhsf); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
GetData().Int op##= rhs.GetData().Int; \
|
||||
GetRefVal().Type=C4V_Int; \
|
||||
} \
|
||||
return *this; \
|
||||
}
|
||||
C4VALUE_ARITHMETIC_OPERATOR(+)
|
||||
C4VALUE_ARITHMETIC_OPERATOR(-)
|
||||
C4VALUE_ARITHMETIC_OPERATOR(*)
|
||||
C4VALUE_ARITHMETIC_OPERATOR(/)
|
||||
#undef C4VALUE_ARITHMETIC_OPERATOR
|
||||
C4Value & operator %= (int32_t by) { GetData().Int %= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
C4Value & operator &= (int32_t by) { GetData().Int &= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
C4Value & operator ^= (int32_t by) { GetData().Int ^= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
|
@ -215,7 +243,7 @@ public:
|
|||
void CompileFunc(StdCompiler *pComp);
|
||||
|
||||
static inline bool IsNullableType(C4V_Type Type)
|
||||
{ return Type == C4V_Int || Type == C4V_Bool; }
|
||||
{ return Type == C4V_Int || Type == C4V_Float || Type == C4V_Bool; }
|
||||
|
||||
protected:
|
||||
// data
|
||||
|
@ -269,6 +297,7 @@ protected:
|
|||
|
||||
// converter
|
||||
inline C4Value C4VInt(int32_t iVal) { C4V_Data d; d.Int = iVal; return C4Value(d, C4V_Int); }
|
||||
inline C4Value C4VFloat(C4Real f) { return C4Value(f); }
|
||||
inline C4Value C4VBool(bool fVal) { C4V_Data d; d.Int = fVal; return C4Value(d, C4V_Bool); }
|
||||
C4Value C4VID(C4ID iVal);
|
||||
inline C4Value C4VObj(C4Object *pObj) { return C4Value(pObj); }
|
||||
|
@ -288,6 +317,13 @@ template <> struct C4ValueConv<int32_t>
|
|||
inline static int32_t _FromC4V(C4Value &v) { return v._getInt(); }
|
||||
inline static C4Value ToC4V(int32_t v) { return C4VInt(v); }
|
||||
};
|
||||
template <> struct C4ValueConv<C4Real>
|
||||
{
|
||||
inline static C4V_Type Type() { return C4V_Float; }
|
||||
inline static C4Real FromC4V(C4Value &v) { return v.getFloat(); }
|
||||
inline static C4Real _FromC4V(C4Value &v) { return v._getFloat(); }
|
||||
inline static C4Value ToC4V(C4Real v) { return C4VFloat(v); }
|
||||
};
|
||||
template <> struct C4ValueConv<bool>
|
||||
{
|
||||
inline static C4V_Type Type() { return C4V_Bool; }
|
||||
|
|
Loading…
Reference in New Issue