2009-05-08 13:28:41 +00:00
|
|
|
/*
|
|
|
|
* OpenClonk, http://www.openclonk.org
|
|
|
|
*
|
2009-06-05 13:41:20 +00:00
|
|
|
* Copyright (c) 2001, 2005-2006 Sven Eberhardt
|
|
|
|
* Copyright (c) 2001-2002, 2004-2006 Peter Wortmann
|
|
|
|
* Copyright (c) 2006-2009 Günther Brammer
|
|
|
|
* Copyright (c) 2007 Matthes Bender
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <C4Include.h>
|
|
|
|
#include <C4Value.h>
|
|
|
|
#include <C4StringTable.h>
|
|
|
|
#include <C4ValueList.h>
|
|
|
|
|
|
|
|
#include <C4Game.h>
|
2009-06-15 21:47:26 +00:00
|
|
|
#include <C4GameObjects.h>
|
2009-05-08 13:28:41 +00:00
|
|
|
#include <C4Object.h>
|
|
|
|
#include <C4Log.h>
|
|
|
|
|
2009-08-12 20:44:09 +00:00
|
|
|
const C4NullValue C4VNull = C4NullValue();
|
2009-05-08 13:28:41 +00:00
|
|
|
const C4Value C4VTrue = C4VBool(true);
|
|
|
|
const C4Value C4VFalse = C4VBool(false);
|
|
|
|
|
|
|
|
C4Value::~C4Value()
|
|
|
|
{
|
|
|
|
// resolve all C4Values referencing this Value
|
|
|
|
while(FirstRef)
|
|
|
|
FirstRef->Set(*this);
|
|
|
|
|
|
|
|
// delete contents
|
|
|
|
DelDataRef(Data, Type, GetNextRef(), GetBaseArray());
|
|
|
|
}
|
|
|
|
|
|
|
|
C4Value &C4Value::operator = (const C4Value &nValue)
|
|
|
|
{
|
|
|
|
// set referenced value
|
2010-03-22 18:32:10 +00:00
|
|
|
GetRefVal().Set(nValue.GetRefVal());
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::AddDataRef()
|
|
|
|
{
|
2009-07-20 21:04:29 +00:00
|
|
|
assert(Type != C4V_Any || !Data);
|
2009-05-08 13:28:41 +00:00
|
|
|
switch (Type)
|
|
|
|
{
|
2010-03-22 21:16:46 +00:00
|
|
|
case C4V_Ref: Data.Ref->AddRef(this); break;
|
2009-05-08 13:28:41 +00:00
|
|
|
case C4V_Array: Data.Array = Data.Array->IncRef(); break;
|
|
|
|
case C4V_String: Data.Str->IncRef(); break;
|
|
|
|
case C4V_C4Object:
|
2009-05-19 22:12:11 +00:00
|
|
|
case C4V_PropList:
|
|
|
|
Data.PropList->AddRef(this);
|
2009-05-08 13:28:41 +00:00
|
|
|
#ifdef _DEBUG
|
|
|
|
// check if the object actually exists
|
2010-03-21 23:40:03 +00:00
|
|
|
if(Data.PropList->GetPropListNumbered() && !::Objects.ObjectNumber(Data.PropList))
|
2010-01-25 04:00:59 +00:00
|
|
|
{ LogF("Warning: using wild object ptr %p!", static_cast<void*>(Data.PropList)); }
|
2009-05-19 22:12:11 +00:00
|
|
|
else if(!Data.PropList->Status)
|
2010-01-25 04:00:59 +00:00
|
|
|
{ LogF("Warning: using ptr on deleted object %p (%s)!", static_cast<void*>(Data.PropList), Data.PropList->GetName()); }
|
2009-05-08 13:28:41 +00:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::DelDataRef(C4V_Data Data, C4V_Type Type, C4Value * pNextRef, C4ValueArray * pBaseArray)
|
|
|
|
{
|
|
|
|
// clean up
|
|
|
|
switch (Type)
|
|
|
|
{
|
2010-03-22 21:16:46 +00:00
|
|
|
case C4V_Ref:
|
2009-05-08 13:28:41 +00:00
|
|
|
// Save because AddDataRef does not set this flag
|
|
|
|
HasBaseArray = false;
|
|
|
|
Data.Ref->DelRef(this, pNextRef, pBaseArray);
|
|
|
|
break;
|
2009-05-19 22:12:11 +00:00
|
|
|
case C4V_C4Object: case C4V_PropList: Data.PropList->DelRef(this, pNextRef); break;
|
2009-05-08 13:28:41 +00:00
|
|
|
case C4V_Array: Data.Array->DecRef(); break;
|
|
|
|
case C4V_String: Data.Str->DecRef(); break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::Set(C4V_Data nData, C4V_Type nType)
|
|
|
|
{
|
2009-07-20 21:04:29 +00:00
|
|
|
assert(nType != C4V_Any || !nData);
|
2009-05-08 13:28:41 +00:00
|
|
|
// Do not add this to the same linked list twice.
|
|
|
|
if (Data == nData && Type == nType) return;
|
|
|
|
|
|
|
|
C4V_Data oData = Data;
|
|
|
|
C4V_Type oType = Type;
|
|
|
|
C4Value * oNextRef = NextRef;
|
|
|
|
C4ValueArray * oBaseArray = BaseArray;
|
|
|
|
bool oHasBaseArray = HasBaseArray;
|
|
|
|
|
|
|
|
// change
|
|
|
|
Data = nData;
|
2009-07-20 21:04:29 +00:00
|
|
|
Type = nData || IsNullableType(nType) ? nType : C4V_Any;
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// hold
|
|
|
|
AddDataRef();
|
|
|
|
|
|
|
|
// clean up
|
|
|
|
DelDataRef(oData, oType, oHasBaseArray ? NULL : oNextRef, oHasBaseArray ? oBaseArray : NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::Set0()
|
|
|
|
{
|
|
|
|
C4V_Data oData = Data;
|
|
|
|
C4V_Type oType = Type;
|
|
|
|
|
|
|
|
// change
|
|
|
|
Data = 0;
|
2009-07-20 21:04:29 +00:00
|
|
|
Type = C4V_Any;
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// clean up (save even if Data was 0 before)
|
|
|
|
DelDataRef(oData, oType, HasBaseArray ? NULL : NextRef, HasBaseArray ? BaseArray : NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::Move(C4Value *nValue)
|
|
|
|
{
|
|
|
|
nValue->Set(*this);
|
|
|
|
|
|
|
|
// change references
|
|
|
|
for(C4Value *pVal = FirstRef; pVal; pVal = pVal->GetNextRef())
|
|
|
|
pVal->Data.Ref = nValue;
|
|
|
|
|
|
|
|
// copy ref list
|
|
|
|
assert(!nValue->FirstRef);
|
|
|
|
nValue->FirstRef = FirstRef;
|
|
|
|
|
|
|
|
// delete usself
|
|
|
|
FirstRef = NULL;
|
2009-07-20 21:04:29 +00:00
|
|
|
Set0();
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::GetArrayElement(int32_t Index, C4Value & target, C4AulContext *pctx, bool noref)
|
|
|
|
{
|
|
|
|
if (noref)
|
|
|
|
{
|
2010-03-22 18:32:10 +00:00
|
|
|
const C4Value & Ref = GetRefValConst();
|
|
|
|
// No array (and no nullpointer because Data==0 => Type==any)
|
|
|
|
if (Ref.Type != C4V_Array)
|
|
|
|
throw new C4AulExecError(pctx->Obj, "Array access: array expected");
|
2009-05-08 13:28:41 +00:00
|
|
|
// Get the item, but do not resize the array - it might be used more than once
|
|
|
|
if (Index < Ref.Data.Array->GetSize())
|
|
|
|
target.Set(Ref.Data.Array->GetItem(Index));
|
|
|
|
else
|
2009-07-20 16:22:27 +00:00
|
|
|
target.Set0();
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-22 18:32:10 +00:00
|
|
|
C4Value & Ref = GetRefVal();
|
|
|
|
// No array (and no nullpointer because Data==0 => Type==any)
|
|
|
|
if (Ref.Type != C4V_Array)
|
|
|
|
throw new C4AulExecError(pctx->Obj, "Array access: array expected");
|
2009-05-08 13:28:41 +00:00
|
|
|
// Is target the first ref?
|
|
|
|
if (Index >= Ref.Data.Array->GetSize() || !Ref.Data.Array->GetItem(Index).FirstRef)
|
|
|
|
{
|
|
|
|
Ref.Data.Array = Ref.Data.Array->IncElementRef();
|
|
|
|
target.SetRef(&Ref.Data.Array->GetItem(Index));
|
2010-03-22 21:16:46 +00:00
|
|
|
if (target.Type == C4V_Ref)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
assert(!target.NextRef);
|
|
|
|
target.BaseArray = Ref.Data.Array;
|
|
|
|
target.HasBaseArray = true;
|
|
|
|
}
|
|
|
|
// else target apparently owned the last reference to the array
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
target.SetRef(&Ref.Data.Array->GetItem(Index));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::SetArrayLength(int32_t size, C4AulContext *cthr)
|
|
|
|
{
|
|
|
|
C4Value & Ref = GetRefVal();
|
|
|
|
// No array
|
|
|
|
if (Ref.Type != C4V_Array)
|
|
|
|
throw new C4AulExecError(cthr->Obj, "SetLength: array expected");
|
|
|
|
Ref.Data.Array = Ref.Data.Array->SetLength(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
const C4Value & C4Value::GetRefVal() const
|
|
|
|
{
|
|
|
|
const C4Value* pVal = this;
|
2010-03-22 21:16:46 +00:00
|
|
|
while(pVal->Type == C4V_Ref)
|
2009-05-08 13:28:41 +00:00
|
|
|
pVal = pVal->Data.Ref;
|
|
|
|
return *pVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
C4Value &C4Value::GetRefVal()
|
|
|
|
{
|
|
|
|
C4Value* pVal = this;
|
2010-03-22 21:16:46 +00:00
|
|
|
while(pVal->Type == C4V_Ref)
|
2009-05-08 13:28:41 +00:00
|
|
|
pVal = pVal->Data.Ref;
|
|
|
|
return *pVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::AddRef(C4Value *pRef)
|
|
|
|
{
|
|
|
|
pRef->NextRef = FirstRef;
|
|
|
|
FirstRef = pRef;
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::DelRef(const C4Value *pRef, C4Value * pNextRef, C4ValueArray * pBaseArray)
|
|
|
|
{
|
|
|
|
if(pRef == FirstRef)
|
|
|
|
FirstRef = pNextRef;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
C4Value* pVal = FirstRef;
|
|
|
|
while(pVal->NextRef != pRef)
|
|
|
|
{
|
|
|
|
// assert that pRef really was in the list
|
|
|
|
assert(pVal->NextRef && !pVal->HasBaseArray);
|
|
|
|
pVal = pVal->NextRef;
|
|
|
|
}
|
|
|
|
pVal->NextRef = pNextRef;
|
|
|
|
if (pBaseArray)
|
|
|
|
{
|
|
|
|
pVal->HasBaseArray = true;
|
|
|
|
pVal->BaseArray = pBaseArray;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Was pRef the last ref to an array element?
|
|
|
|
if (pBaseArray && !FirstRef)
|
|
|
|
{
|
|
|
|
pBaseArray->DecElementRef();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* GetC4VName(const C4V_Type Type)
|
|
|
|
{
|
|
|
|
switch(Type)
|
|
|
|
{
|
|
|
|
case C4V_Any:
|
2009-07-26 15:42:22 +00:00
|
|
|
return "nil";
|
2009-05-08 13:28:41 +00:00
|
|
|
case C4V_Int:
|
|
|
|
return "int";
|
|
|
|
case C4V_Bool:
|
|
|
|
return "bool";
|
|
|
|
case C4V_C4Object:
|
|
|
|
return "object";
|
|
|
|
case C4V_String:
|
|
|
|
return "string";
|
|
|
|
case C4V_Array:
|
|
|
|
return "array";
|
2009-05-19 22:12:11 +00:00
|
|
|
case C4V_PropList:
|
|
|
|
return "proplist";
|
2010-03-22 21:16:46 +00:00
|
|
|
case C4V_Ref:
|
2009-05-08 13:28:41 +00:00
|
|
|
return "&";
|
|
|
|
default:
|
|
|
|
return "!Fehler!";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char GetC4VID(const C4V_Type Type)
|
|
|
|
{
|
|
|
|
switch(Type)
|
|
|
|
{
|
|
|
|
case C4V_Any:
|
|
|
|
return 'A';
|
|
|
|
case C4V_Int:
|
|
|
|
return 'i';
|
|
|
|
case C4V_Bool:
|
|
|
|
return 'b';
|
|
|
|
case C4V_C4Object:
|
|
|
|
return 'o';
|
|
|
|
case C4V_String:
|
|
|
|
return 's';
|
2010-03-22 21:16:46 +00:00
|
|
|
case C4V_Ref:
|
2009-05-08 13:28:41 +00:00
|
|
|
return 'V'; // should never happen
|
|
|
|
case C4V_C4ObjectEnum:
|
|
|
|
return 'O';
|
2010-03-21 23:40:03 +00:00
|
|
|
case C4V_C4DefEnum:
|
|
|
|
return 'D';
|
2009-05-08 13:28:41 +00:00
|
|
|
case C4V_Array:
|
|
|
|
return 'a';
|
2009-05-19 22:12:11 +00:00
|
|
|
case C4V_PropList:
|
|
|
|
return 'p';
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
return ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
C4V_Type GetC4VFromID(const char C4VID)
|
|
|
|
{
|
|
|
|
switch(C4VID)
|
|
|
|
{
|
|
|
|
case 'A':
|
|
|
|
return C4V_Any;
|
|
|
|
case 'i':
|
|
|
|
return C4V_Int;
|
|
|
|
case 'b':
|
|
|
|
return C4V_Bool;
|
|
|
|
case 'o':
|
|
|
|
return C4V_C4Object;
|
|
|
|
case 's':
|
|
|
|
return C4V_String;
|
|
|
|
case 'V':
|
2010-03-22 21:16:46 +00:00
|
|
|
return C4V_Ref;
|
2009-05-08 13:28:41 +00:00
|
|
|
case 'O':
|
|
|
|
return C4V_C4ObjectEnum;
|
2010-03-21 23:40:03 +00:00
|
|
|
case 'D':
|
|
|
|
return C4V_C4DefEnum;
|
2009-05-08 13:28:41 +00:00
|
|
|
case 'a':
|
|
|
|
return C4V_Array;
|
2009-05-19 22:12:11 +00:00
|
|
|
case 'p':
|
|
|
|
return C4V_PropList;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
return C4V_Any;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* C4Value::GetTypeInfo()
|
|
|
|
{
|
|
|
|
return GetC4VName(GetType());
|
|
|
|
}
|
|
|
|
|
|
|
|
// converter functions ----------------
|
|
|
|
|
2009-09-05 15:54:56 +00:00
|
|
|
static bool FnCnvError(C4Value *Val, C4V_Type toType)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
// deny convert
|
2009-08-15 18:50:32 +00:00
|
|
|
return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
2009-09-05 15:54:56 +00:00
|
|
|
static bool FnCnvDeref(C4Value *Val, C4V_Type toType)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
// resolve reference of Value
|
|
|
|
Val->Deref();
|
|
|
|
// retry to check convert
|
2009-09-05 15:54:56 +00:00
|
|
|
return Val->ConvertTo(toType);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool FnOk0(C4Value *Val, C4V_Type toType)
|
|
|
|
{
|
|
|
|
// 0 can be treated as nil, but every other integer can't
|
|
|
|
return !*Val;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
2009-09-05 15:54:56 +00:00
|
|
|
bool C4Value::FnCnvObject(C4Value *Val, C4V_Type toType)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
2009-05-19 22:12:11 +00:00
|
|
|
// try casting
|
|
|
|
if (dynamic_cast<C4Object *>(Val->Data.PropList)) return true;
|
|
|
|
return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Type conversion table
|
2009-09-05 15:54:56 +00:00
|
|
|
#define CnvOK 0, false // allow conversion by same value
|
|
|
|
#define CnvOK0 FnOk0, true
|
2009-05-08 13:28:41 +00:00
|
|
|
#define CnvError FnCnvError, true
|
|
|
|
#define CnvDeref FnCnvDeref, false
|
2009-05-19 22:12:11 +00:00
|
|
|
#define CnvObject FnCnvObject, false
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] = {
|
2009-07-20 21:04:29 +00:00
|
|
|
{ // C4V_Any - is always 0, convertible to everything
|
2009-09-05 15:54:56 +00:00
|
|
|
{ CnvOK }, // any same
|
|
|
|
{ CnvOK }, // int
|
|
|
|
{ CnvOK }, // Bool
|
|
|
|
{ CnvOK }, // PropList
|
|
|
|
{ CnvOK }, // C4Object
|
|
|
|
{ CnvOK }, // String
|
|
|
|
{ CnvOK }, // Array
|
|
|
|
{ CnvError }, // pC4Value
|
2009-05-08 13:28:41 +00:00
|
|
|
},
|
|
|
|
{ // C4V_Int
|
2009-09-05 15:54:56 +00:00
|
|
|
{ CnvOK }, // any
|
|
|
|
{ CnvOK }, // int same
|
|
|
|
{ CnvOK }, // Bool
|
|
|
|
{ CnvOK0 }, // PropList only if 0
|
|
|
|
{ CnvOK0 }, // C4Object only if 0
|
|
|
|
{ CnvOK0 }, // String only if 0
|
|
|
|
{ CnvOK0 }, // Array only if 0
|
|
|
|
{ CnvError }, // pC4Value
|
2009-05-08 13:28:41 +00:00
|
|
|
},
|
|
|
|
{ // C4V_Bool
|
2009-09-05 15:54:56 +00:00
|
|
|
{ CnvOK }, // any
|
|
|
|
{ CnvOK }, // int might be used
|
|
|
|
{ CnvOK }, // Bool same
|
|
|
|
{ CnvError }, // PropList NEVER!
|
|
|
|
{ CnvError }, // C4Object NEVER!
|
|
|
|
{ CnvError }, // String NEVER!
|
|
|
|
{ CnvError }, // Array NEVER!
|
|
|
|
{ CnvError }, // pC4Value
|
2009-05-08 13:28:41 +00:00
|
|
|
},
|
2009-04-12 12:04:28 +00:00
|
|
|
{ // C4V_PropList
|
2009-09-05 15:54:56 +00:00
|
|
|
{ CnvOK }, // any
|
|
|
|
{ CnvError }, // int NEVER!
|
|
|
|
{ CnvOK }, // Bool
|
|
|
|
{ CnvOK }, // PropList same
|
|
|
|
{ CnvObject }, // C4Object
|
|
|
|
{ CnvError }, // String NEVER!
|
|
|
|
{ CnvError }, // Array NEVER!
|
|
|
|
{ CnvError }, // pC4Value NEVER!
|
2009-05-08 13:28:41 +00:00
|
|
|
},
|
|
|
|
{ // C4V_Object
|
2009-09-05 15:54:56 +00:00
|
|
|
{ CnvOK }, // any
|
|
|
|
{ CnvError }, // int NEVER!
|
|
|
|
{ CnvOK }, // Bool
|
|
|
|
{ CnvOK }, // PropList
|
|
|
|
{ CnvOK }, // C4Object same
|
|
|
|
{ CnvError }, // String NEVER!
|
|
|
|
{ CnvError }, // Array NEVER!
|
|
|
|
{ CnvError }, // pC4Value NEVER!
|
2009-05-08 13:28:41 +00:00
|
|
|
},
|
|
|
|
{ // C4V_String
|
2009-09-05 15:54:56 +00:00
|
|
|
{ CnvOK }, // any
|
|
|
|
{ CnvError }, // int NEVER!
|
|
|
|
{ CnvOK }, // Bool
|
|
|
|
{ CnvError }, // PropList NEVER!
|
|
|
|
{ CnvError }, // C4Object NEVER!
|
|
|
|
{ CnvOK }, // String same
|
|
|
|
{ CnvError }, // Array NEVER!
|
|
|
|
{ CnvError }, // pC4Value NEVER!
|
2009-05-08 13:28:41 +00:00
|
|
|
},
|
|
|
|
{ // C4V_Array
|
2009-09-05 15:54:56 +00:00
|
|
|
{ CnvOK }, // any
|
|
|
|
{ CnvError }, // int NEVER!
|
|
|
|
{ CnvOK }, // Bool
|
|
|
|
{ CnvError }, // PropList NEVER!
|
|
|
|
{ CnvError }, // C4Object NEVER!
|
|
|
|
{ CnvError }, // String NEVER!
|
|
|
|
{ CnvOK }, // Array same
|
|
|
|
{ CnvError }, // pC4Value NEVER!
|
2009-05-08 13:28:41 +00:00
|
|
|
},
|
2010-03-22 21:16:46 +00:00
|
|
|
{ // C4V_Ref - resolve reference and retry type check
|
2009-09-05 15:54:56 +00:00
|
|
|
{ CnvDeref }, // any
|
|
|
|
{ CnvDeref }, // int
|
|
|
|
{ CnvDeref }, // Bool
|
|
|
|
{ CnvDeref }, // PropList
|
|
|
|
{ CnvDeref }, // C4Object
|
|
|
|
{ CnvDeref }, // String
|
|
|
|
{ CnvDeref }, // Array
|
|
|
|
{ CnvOK }, // pC4Value same
|
2009-05-08 13:28:41 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
#undef CnvOK
|
|
|
|
#undef CvnError
|
|
|
|
#undef CnvInt2Id
|
|
|
|
#undef CnvDirectOld
|
|
|
|
#undef CnvDeref
|
|
|
|
|
|
|
|
// Humanreadable debug output
|
|
|
|
StdStrBuf C4Value::GetDataString()
|
|
|
|
{
|
2010-03-22 21:16:46 +00:00
|
|
|
if (Type == C4V_Ref)
|
2009-05-08 13:28:41 +00:00
|
|
|
return GetRefVal().GetDataString() + "*";
|
|
|
|
|
|
|
|
// ouput by type info
|
|
|
|
switch(GetType())
|
|
|
|
{
|
|
|
|
case C4V_Int:
|
|
|
|
return FormatString("%ld", Data.Int);
|
|
|
|
case C4V_Bool:
|
|
|
|
return StdStrBuf(Data ? "true" : "false");
|
|
|
|
case C4V_C4Object:
|
2009-04-18 00:46:19 +00:00
|
|
|
case C4V_PropList:
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
// obj exists?
|
2009-07-21 14:46:39 +00:00
|
|
|
if(!::Objects.ObjectNumber(Data.PropList))
|
2009-05-08 13:28:41 +00:00
|
|
|
return FormatString("%ld", Data.Int);
|
|
|
|
else
|
2009-04-18 00:46:19 +00:00
|
|
|
if (Data.PropList)
|
2009-05-08 13:28:41 +00:00
|
|
|
if (Data.Obj->Status == C4OS_NORMAL)
|
2010-03-21 23:40:03 +00:00
|
|
|
return FormatString("%s #%d", Data.PropList->GetName(), Objects.ObjectNumber(Data.PropList));
|
2009-05-08 13:28:41 +00:00
|
|
|
else
|
2010-03-21 23:40:03 +00:00
|
|
|
return FormatString("{%s #%d}", Data.PropList->GetName(), Objects.ObjectNumber(Data.PropList));
|
2009-05-08 13:28:41 +00:00
|
|
|
else
|
|
|
|
return StdStrBuf("0"); // (impossible)
|
|
|
|
}
|
|
|
|
case C4V_String:
|
|
|
|
return (Data.Str && Data.Str->GetCStr()) ? FormatString("\"%s\"", Data.Str->GetCStr()) : StdStrBuf("(nullstring)");
|
|
|
|
case C4V_Array:
|
|
|
|
{
|
|
|
|
StdStrBuf DataString;
|
|
|
|
DataString = "[";
|
|
|
|
for(int32_t i = 0; i < Data.Array->GetSize(); i++)
|
|
|
|
{
|
|
|
|
if(i) DataString.Append(", ");
|
|
|
|
DataString.Append(static_cast<const StdStrBuf &>(Data.Array->GetItem(i).GetDataString()));
|
|
|
|
}
|
|
|
|
DataString.AppendChar(']');
|
|
|
|
return DataString;
|
|
|
|
}
|
2009-07-20 21:04:29 +00:00
|
|
|
case C4V_Any:
|
2009-07-17 02:50:50 +00:00
|
|
|
return StdStrBuf("nil");
|
2009-05-08 13:28:41 +00:00
|
|
|
default:
|
|
|
|
return StdStrBuf("-unknown type- ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
C4Value C4VString(const char *strString)
|
|
|
|
{
|
|
|
|
// safety
|
|
|
|
if(!strString) return C4Value();
|
2009-07-21 14:46:39 +00:00
|
|
|
return C4Value(::Strings.RegString(strString));
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
C4Value C4VString(StdStrBuf Str)
|
|
|
|
{
|
|
|
|
// safety
|
|
|
|
if(Str.isNull()) return C4Value();
|
2009-07-21 14:46:39 +00:00
|
|
|
return C4Value(::Strings.RegString(Str));
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::DenumeratePointer()
|
|
|
|
{
|
|
|
|
// array?
|
|
|
|
if (Type == C4V_Array)
|
|
|
|
{
|
|
|
|
Data.Array->DenumeratePointers();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// object types only
|
2010-03-21 23:40:03 +00:00
|
|
|
if(Type != C4V_C4ObjectEnum) return;
|
2009-05-08 13:28:41 +00:00
|
|
|
// get obj id, search object
|
2009-04-18 00:46:19 +00:00
|
|
|
int iObjID = Data.Int;
|
2010-03-21 23:40:03 +00:00
|
|
|
C4PropList *pObj = Objects.PropListPointer(iObjID);
|
2009-05-08 13:28:41 +00:00
|
|
|
if(pObj)
|
|
|
|
// set
|
2009-05-19 22:12:11 +00:00
|
|
|
SetPropList(pObj);
|
2009-05-08 13:28:41 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// object: invalid value - set to zero
|
2010-03-21 23:40:03 +00:00
|
|
|
LogF("ERROR: Object number %d is missing.", Data.Int);
|
2009-07-20 21:04:29 +00:00
|
|
|
Set0();
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4Value::CompileFunc(StdCompiler *pComp)
|
|
|
|
{
|
|
|
|
// Type
|
|
|
|
bool fCompiler = pComp->isCompiler();
|
|
|
|
if(!fCompiler)
|
|
|
|
{
|
|
|
|
// Get type
|
2009-07-20 21:04:29 +00:00
|
|
|
assert(Type != C4V_Any || !Data);
|
2009-05-08 13:28:41 +00:00
|
|
|
char cC4VID = GetC4VID(Type);
|
|
|
|
// Object reference is saved enumerated
|
|
|
|
if(Type == C4V_C4Object)
|
|
|
|
cC4VID = GetC4VID(C4V_C4ObjectEnum);
|
2010-03-21 23:40:03 +00:00
|
|
|
if(Type == C4V_PropList && getPropList()->GetDef())
|
|
|
|
cC4VID = GetC4VID(C4V_C4DefEnum);
|
|
|
|
else if(Type == C4V_PropList)
|
|
|
|
cC4VID = GetC4VID(C4V_C4ObjectEnum);
|
2009-05-08 13:28:41 +00:00
|
|
|
// Write
|
|
|
|
pComp->Character(cC4VID);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Clear
|
2009-07-17 02:50:50 +00:00
|
|
|
Set0();
|
2009-05-08 13:28:41 +00:00
|
|
|
// Read type
|
|
|
|
char cC4VID;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
pComp->Character(cC4VID);
|
|
|
|
}
|
|
|
|
catch(StdCompiler::NotFoundException *pExc)
|
|
|
|
{
|
|
|
|
delete pExc;
|
|
|
|
cC4VID = 'A';
|
|
|
|
}
|
|
|
|
// old style string
|
|
|
|
if (cC4VID == 'S')
|
|
|
|
{
|
|
|
|
int32_t iTmp;
|
|
|
|
pComp->Value(iTmp);
|
|
|
|
// search
|
2009-07-21 14:46:39 +00:00
|
|
|
C4String *pString = ::Strings.FindString(iTmp);
|
2009-05-08 13:28:41 +00:00
|
|
|
if(pString)
|
|
|
|
{
|
|
|
|
Data.Str = pString;
|
|
|
|
pString->IncRef();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Type = C4V_Any;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Type = GetC4VFromID(cC4VID);
|
|
|
|
}
|
|
|
|
// Data
|
|
|
|
int32_t iTmp;
|
|
|
|
switch(Type)
|
|
|
|
{
|
|
|
|
|
|
|
|
// simple data types: just save
|
|
|
|
case C4V_Int:
|
|
|
|
case C4V_Bool:
|
|
|
|
|
|
|
|
// these are 32-bit integers
|
|
|
|
iTmp = Data.Int;
|
|
|
|
pComp->Value(iTmp);
|
|
|
|
Data.Int = iTmp;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
// object: save object number instead
|
2009-05-19 22:12:11 +00:00
|
|
|
case C4V_C4Object: case C4V_PropList:
|
2010-03-21 23:40:03 +00:00
|
|
|
{
|
|
|
|
assert(!fCompiler);
|
|
|
|
C4PropList * p = getPropList();
|
|
|
|
if (Type == C4V_PropList && p->GetDef())
|
|
|
|
pComp->Value(p->GetDef()->id);
|
|
|
|
else
|
|
|
|
{
|
2009-07-21 14:46:39 +00:00
|
|
|
iTmp = ::Objects.ObjectNumber(getPropList());
|
2010-03-21 23:40:03 +00:00
|
|
|
pComp->Value(iTmp);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
case C4V_C4ObjectEnum:
|
2010-03-21 23:40:03 +00:00
|
|
|
assert(fCompiler);
|
|
|
|
pComp->Value(iTmp); // must be denumerated later
|
|
|
|
Data.Int = iTmp;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case C4V_C4DefEnum:
|
|
|
|
{
|
|
|
|
assert(fCompiler);
|
|
|
|
C4ID id;
|
|
|
|
pComp->Value(id); // must be denumerated later
|
|
|
|
Data.PropList = Definitions.ID2Def(id);
|
|
|
|
Type = C4V_PropList;
|
|
|
|
if(!Data.PropList)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
2010-03-21 23:40:03 +00:00
|
|
|
LogF("ERROR: Definition %s is missing.", id.ToString());
|
|
|
|
Type = C4V_Any;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Data.PropList->AddRef(this);
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-03-21 23:40:03 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// string: save string number
|
|
|
|
case C4V_String:
|
|
|
|
{
|
|
|
|
// search
|
|
|
|
StdStrBuf s;
|
|
|
|
if (!fCompiler) s = Data.Str->GetData();
|
|
|
|
pComp->Value(s);
|
|
|
|
if(fCompiler)
|
|
|
|
{
|
2009-07-21 14:46:39 +00:00
|
|
|
C4String *pString = ::Strings.RegString(s);
|
2009-05-08 13:28:41 +00:00
|
|
|
if(pString)
|
|
|
|
{
|
|
|
|
Data.Str = pString;
|
|
|
|
pString->IncRef();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Type = C4V_Any;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case C4V_Array:
|
|
|
|
pComp->Seperator(StdCompiler::SEP_START2);
|
|
|
|
pComp->Value(mkPtrAdapt(Data.Array, false));
|
|
|
|
if (fCompiler) Data.Array = Data.Array->IncRef();
|
|
|
|
pComp->Seperator(StdCompiler::SEP_END2);
|
|
|
|
break;
|
|
|
|
|
2009-07-20 21:04:29 +00:00
|
|
|
case C4V_Any:
|
|
|
|
assert(!Data);
|
2009-07-17 02:50:50 +00:00
|
|
|
// doesn't have a value, so nothing to store
|
|
|
|
break;
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// shouldn't happen
|
2010-03-22 21:16:46 +00:00
|
|
|
case C4V_Ref:
|
2009-05-08 13:28:41 +00:00
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool C4Value::operator == (const C4Value& Value2) const
|
|
|
|
{
|
|
|
|
switch (Type)
|
|
|
|
{
|
|
|
|
case C4V_Any:
|
|
|
|
assert(!Data);
|
2009-07-20 21:04:29 +00:00
|
|
|
return Value2.Type == Type;
|
2009-05-08 13:28:41 +00:00
|
|
|
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;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-19 22:12:11 +00:00
|
|
|
case C4V_C4Object: case C4V_PropList:
|
2009-05-08 13:28:41 +00:00
|
|
|
return Data == Value2.Data && Type == Value2.Type;
|
|
|
|
case C4V_String:
|
2009-04-01 21:36:58 +00:00
|
|
|
return Type == Value2.Type && Data.Str == Value2.Data.Str;
|
2009-05-08 13:28:41 +00:00
|
|
|
case C4V_Array:
|
|
|
|
return Type == Value2.Type && *(Data.Array) == *(Value2.Data.Array);
|
|
|
|
default:
|
|
|
|
// C4AulExec should have dereferenced both values, no need to implement comparison here
|
|
|
|
return Data == Value2.Data;
|
|
|
|
}
|
|
|
|
return GetData() == Value2.GetData();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool C4Value::operator != (const C4Value& Value2) const
|
|
|
|
{
|
|
|
|
return !(*this == Value2);
|
|
|
|
}
|
2009-04-12 12:04:28 +00:00
|
|
|
|
2009-07-21 14:46:39 +00:00
|
|
|
C4Value C4VID(C4ID iVal) { return C4Value(::Definitions.ID2Def(iVal)); }
|
2009-04-12 12:04:28 +00:00
|
|
|
C4ID C4Value::getC4ID()
|
|
|
|
{
|
|
|
|
C4PropList * p = getPropList();
|
2010-01-25 15:57:57 +00:00
|
|
|
if(!p) return C4ID::None;
|
2009-04-12 12:04:28 +00:00
|
|
|
C4Def * d = p->GetDef();
|
2010-01-25 15:57:57 +00:00
|
|
|
if (!d) return C4ID::None;
|
2009-04-12 12:04:28 +00:00
|
|
|
return d->id;
|
|
|
|
}
|