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
|
2010-12-23 00:01:24 +00:00
|
|
|
* Copyright (c) 2006-2010 Günther Brammer
|
2009-06-05 13:41:20 +00:00
|
|
|
* Copyright (c) 2007 Matthes Bender
|
2010-12-23 00:01:24 +00:00
|
|
|
* Copyright (c) 2009 Nicolas Hake
|
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>
|
2011-03-03 16:10:22 +00:00
|
|
|
|
2011-04-14 13:36:31 +00:00
|
|
|
#include <C4AulExec.h>
|
2011-03-03 16:10:22 +00:00
|
|
|
#include <C4DefList.h>
|
2009-05-08 13:28:41 +00:00
|
|
|
#include <C4StringTable.h>
|
2010-12-27 16:05:35 +00:00
|
|
|
#include <C4ValueArray.h>
|
2009-05-08 13:28:41 +00:00
|
|
|
#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>
|
|
|
|
|
2011-03-02 23:57:38 +00:00
|
|
|
const C4Value C4VNull;
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
const char* GetC4VName(const C4V_Type Type)
|
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
switch (Type)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
2011-05-09 12:37:28 +00:00
|
|
|
case C4V_Nil:
|
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";
|
2011-05-09 12:37:28 +00:00
|
|
|
case C4V_Any:
|
|
|
|
return "any";
|
2009-05-08 13:28:41 +00:00
|
|
|
default:
|
|
|
|
return "!Fehler!";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* C4Value::GetTypeInfo()
|
|
|
|
{
|
|
|
|
return GetC4VName(GetType());
|
|
|
|
}
|
|
|
|
|
2010-09-20 17:49:00 +00:00
|
|
|
bool C4Value::FnCnvObject() const
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-19 22:12:11 +00:00
|
|
|
// try casting
|
2011-03-02 13:12:06 +00:00
|
|
|
if (Data.PropList->GetObject()) return true;
|
2009-05-19 22:12:11 +00:00
|
|
|
return false;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2011-04-10 01:46:59 +00:00
|
|
|
|
|
|
|
bool C4Value::WarnAboutConversion(C4V_Type Type, C4V_Type vtToType)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2011-04-10 01:46:59 +00:00
|
|
|
switch (vtToType)
|
|
|
|
{
|
2011-05-09 12:37:28 +00:00
|
|
|
case C4V_Nil: return Type != C4V_Nil && Type != C4V_Any;
|
|
|
|
case C4V_Int: return Type != C4V_Int && Type != C4V_Nil && Type != C4V_Bool && Type != C4V_Any;
|
2011-04-10 01:46:59 +00:00
|
|
|
case C4V_Bool: return false;
|
2011-05-09 12:37:28 +00:00
|
|
|
case C4V_PropList: return Type != C4V_PropList && Type != C4V_C4Object && Type != C4V_Nil && Type != C4V_Any;
|
|
|
|
case C4V_C4Object: return Type != C4V_C4Object && Type != C4V_PropList && Type != C4V_Nil && Type != C4V_Any;
|
|
|
|
case C4V_String: return Type != C4V_String && Type != C4V_Nil && Type != C4V_Any;
|
|
|
|
case C4V_Array: return Type != C4V_Array && Type != C4V_Nil && Type != C4V_Any;
|
|
|
|
case C4V_Any: return false;
|
2011-04-10 01:46:59 +00:00
|
|
|
default: assert(!"C4Value::ConvertTo: impossible conversion target"); return false;
|
2010-04-08 00:47:45 +00:00
|
|
|
}
|
2011-04-10 01:46:59 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Humanreadable debug output
|
2011-05-05 20:27:22 +00:00
|
|
|
StdStrBuf C4Value::GetDataString(int depth) const
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
// ouput by type info
|
2010-03-28 18:58:01 +00:00
|
|
|
switch (GetType())
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
case C4V_Int:
|
2010-04-28 21:43:25 +00:00
|
|
|
return FormatString("%ld", static_cast<long>(Data.Int));
|
2009-05-08 13:28:41 +00:00
|
|
|
case C4V_Bool:
|
|
|
|
return StdStrBuf(Data ? "true" : "false");
|
|
|
|
case C4V_C4Object:
|
2009-04-18 00:46:19 +00:00
|
|
|
case C4V_PropList:
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2011-05-05 20:27:22 +00:00
|
|
|
StdStrBuf DataString;
|
|
|
|
DataString = "{";
|
|
|
|
if (Data.PropList->GetObject())
|
|
|
|
{
|
|
|
|
if (Data.Obj->Status == C4OS_NORMAL)
|
|
|
|
DataString.AppendFormat("#%d, ", Data.Obj->Number);
|
2009-05-08 13:28:41 +00:00
|
|
|
else
|
2011-05-05 20:27:22 +00:00
|
|
|
DataString.AppendFormat("(#%d), ", Data.Obj->Number);
|
|
|
|
}
|
|
|
|
else if (Data.PropList->GetDef())
|
|
|
|
DataString.AppendFormat("%s, ", Data.PropList->GetDef()->id.ToString());
|
|
|
|
Data.PropList->AppendDataString(&DataString, ", ", depth);
|
|
|
|
DataString.AppendChar('}');
|
|
|
|
return DataString;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
case C4V_String:
|
|
|
|
return (Data.Str && Data.Str->GetCStr()) ? FormatString("\"%s\"", Data.Str->GetCStr()) : StdStrBuf("(nullstring)");
|
|
|
|
case C4V_Array:
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2011-05-09 21:19:31 +00:00
|
|
|
if (depth <= 0 && Data.Array->GetSize())
|
2011-05-05 20:27:22 +00:00
|
|
|
{
|
|
|
|
return StdStrBuf("[...]");
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
StdStrBuf DataString;
|
|
|
|
DataString = "[";
|
|
|
|
for (int32_t i = 0; i < Data.Array->GetSize(); i++)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
2010-03-28 18:58:01 +00:00
|
|
|
if (i) DataString.Append(", ");
|
2011-05-09 21:19:31 +00:00
|
|
|
DataString.Append(std::move(Data.Array->GetItem(i).GetDataString(depth - 1)));
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
DataString.AppendChar(']');
|
|
|
|
return DataString;
|
|
|
|
}
|
2011-05-09 12:37:28 +00:00
|
|
|
case C4V_Nil:
|
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
|
2010-03-28 18:58:01 +00:00
|
|
|
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
|
2010-03-28 18:58:01 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2011-03-27 16:14:41 +00:00
|
|
|
const C4Value & C4ValueNumbers::GetValue(uint32_t n)
|
|
|
|
{
|
|
|
|
if (n < LoadedValues.size())
|
|
|
|
return LoadedValues[n];
|
|
|
|
LogF("ERROR: Value number %d is missing.", n);
|
|
|
|
return C4VNull;
|
|
|
|
}
|
|
|
|
|
2011-03-26 22:59:35 +00:00
|
|
|
void C4Value::Denumerate(class C4ValueNumbers * numbers)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
2011-03-27 16:14:41 +00:00
|
|
|
switch (Type)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
2011-03-27 16:14:41 +00:00
|
|
|
case C4V_Enum:
|
|
|
|
Set(numbers->GetValue(Data.Int)); break;
|
|
|
|
case C4V_Array:
|
|
|
|
Data.Array->Denumerate(numbers); break;
|
|
|
|
case C4V_PropList:
|
|
|
|
// objects and effects are denumerated via the main object list
|
|
|
|
if (!Data.PropList->IsNumbered() && !Data.PropList->IsDef())
|
|
|
|
Data.PropList->Denumerate(numbers);
|
|
|
|
break;
|
|
|
|
case C4V_C4ObjectEnum:
|
|
|
|
{
|
|
|
|
C4PropList *pObj = C4PropListNumbered::GetByNumber(Data.Int);
|
|
|
|
if (pObj)
|
|
|
|
// set
|
|
|
|
SetPropList(pObj);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// object: invalid value - set to zero
|
|
|
|
LogF("ERROR: Object number %d is missing.", int(Data.Int));
|
|
|
|
Set0();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default: break;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2011-03-27 16:14:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void C4ValueNumbers::Denumerate()
|
|
|
|
{
|
|
|
|
for (std::vector<C4Value>::iterator i = LoadedValues.begin(); i != LoadedValues.end(); ++i)
|
|
|
|
i->Denumerate(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t C4ValueNumbers::GetNumberForValue(C4Value * v)
|
|
|
|
{
|
|
|
|
// This is only used for C4Values containing pointers
|
|
|
|
// Assume that all pointers have the same size
|
|
|
|
if (ValueNumbers.find(v->_getObj()) == ValueNumbers.end())
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
2011-03-27 16:14:41 +00:00
|
|
|
ValuesToSave.push_back(v);
|
|
|
|
ValueNumbers[v->_getObj()] = ValuesToSave.size() - 1;
|
|
|
|
return ValuesToSave.size() - 1;
|
|
|
|
}
|
|
|
|
return ValueNumbers[v->_getObj()];
|
|
|
|
}
|
|
|
|
|
|
|
|
static char GetC4VID(const C4V_Type Type)
|
|
|
|
{
|
|
|
|
switch (Type)
|
|
|
|
{
|
2011-05-09 12:37:28 +00:00
|
|
|
case C4V_Nil:
|
2011-03-27 16:14:41 +00:00
|
|
|
return 'n';
|
|
|
|
case C4V_Int:
|
|
|
|
return 'i';
|
|
|
|
case C4V_Bool:
|
|
|
|
return 'b';
|
|
|
|
case C4V_PropList:
|
|
|
|
case C4V_Array:
|
|
|
|
case C4V_Enum:
|
|
|
|
return 'E';
|
|
|
|
case C4V_C4Object:
|
|
|
|
case C4V_C4ObjectEnum:
|
|
|
|
return 'O';
|
|
|
|
case C4V_String:
|
|
|
|
return 's';
|
|
|
|
case C4V_C4DefEnum:
|
|
|
|
return 'D';
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
return ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
static C4V_Type GetC4VFromID(const char C4VID)
|
|
|
|
{
|
|
|
|
switch (C4VID)
|
|
|
|
{
|
|
|
|
case 'n':
|
2011-05-21 21:13:49 +00:00
|
|
|
case 'A': // compat with OC 5.1
|
2011-05-09 12:37:28 +00:00
|
|
|
return C4V_Nil;
|
2011-03-27 16:14:41 +00:00
|
|
|
case 'i':
|
|
|
|
return C4V_Int;
|
|
|
|
case 'b':
|
|
|
|
return C4V_Bool;
|
|
|
|
case 's':
|
|
|
|
return C4V_String;
|
|
|
|
case 'O':
|
|
|
|
return C4V_C4ObjectEnum;
|
|
|
|
case 'D':
|
|
|
|
return C4V_C4DefEnum;
|
|
|
|
case 'E':
|
|
|
|
return C4V_Enum;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2011-03-27 16:14:41 +00:00
|
|
|
return C4V_Any;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
2011-03-26 22:59:35 +00:00
|
|
|
void C4Value::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Type
|
|
|
|
bool fCompiler = pComp->isCompiler();
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!fCompiler)
|
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Get type
|
2011-05-09 12:37:28 +00:00
|
|
|
assert(Type != C4V_Nil || !Data);
|
2009-05-08 13:28:41 +00:00
|
|
|
char cC4VID = GetC4VID(Type);
|
2011-03-27 16:14:41 +00:00
|
|
|
// special cases:
|
2010-09-08 18:09:27 +00:00
|
|
|
if (Type == C4V_PropList && getPropList()->IsDef())
|
2010-03-21 23:40:03 +00:00
|
|
|
cC4VID = GetC4VID(C4V_C4DefEnum);
|
2011-03-27 16:14:41 +00:00
|
|
|
else if (Type == C4V_PropList && getPropList()->IsNumbered())
|
2010-03-21 23:40:03 +00:00
|
|
|
cC4VID = GetC4VID(C4V_C4ObjectEnum);
|
2009-05-08 13:28:41 +00:00
|
|
|
// Write
|
|
|
|
pComp->Character(cC4VID);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
else
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Clear
|
2009-07-17 02:50:50 +00:00
|
|
|
Set0();
|
2009-05-08 13:28:41 +00:00
|
|
|
// Read type
|
|
|
|
char cC4VID;
|
|
|
|
try
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
pComp->Character(cC4VID);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
|
|
|
catch (StdCompiler::NotFoundException *pExc)
|
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
delete pExc;
|
2011-03-27 16:14:41 +00:00
|
|
|
cC4VID = 'n';
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
|
|
|
Type = GetC4VFromID(cC4VID);
|
2011-05-21 21:12:43 +00:00
|
|
|
if (Type == C4V_Any)
|
|
|
|
{
|
|
|
|
Type = C4V_Nil;
|
|
|
|
pComp->excCorrupt("unknown C4Value type tag '%c'", cC4VID);
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Data
|
|
|
|
int32_t iTmp;
|
2010-03-28 18:58:01 +00:00
|
|
|
switch (Type)
|
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
// simple data types: just save
|
2009-05-08 13:28:41 +00:00
|
|
|
case C4V_Int:
|
|
|
|
case C4V_Bool:
|
|
|
|
|
|
|
|
// these are 32-bit integers
|
|
|
|
iTmp = Data.Int;
|
|
|
|
pComp->Value(iTmp);
|
|
|
|
Data.Int = iTmp;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
// object: save object number instead
|
2009-05-19 22:12:11 +00:00
|
|
|
case C4V_C4Object: case C4V_PropList:
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-21 23:40:03 +00:00
|
|
|
assert(!fCompiler);
|
|
|
|
C4PropList * p = getPropList();
|
2011-03-27 16:14:41 +00:00
|
|
|
if (p->IsDef())
|
2010-03-21 23:40:03 +00:00
|
|
|
pComp->Value(p->GetDef()->id);
|
2011-03-27 16:14:41 +00:00
|
|
|
else if (p->IsNumbered())
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2011-02-06 00:59:49 +00:00
|
|
|
iTmp = getPropList()->GetPropListNumbered()->Number;
|
2010-03-21 23:40:03 +00:00
|
|
|
pComp->Value(iTmp);
|
|
|
|
}
|
2011-03-27 16:14:41 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
iTmp = numbers->GetNumberForValue(this);
|
|
|
|
pComp->Value(iTmp);
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-03-21 23:40:03 +00:00
|
|
|
|
2011-03-27 16:14:41 +00:00
|
|
|
case C4V_C4ObjectEnum: case C4V_Enum:
|
2010-03-21 23:40:03 +00:00
|
|
|
assert(fCompiler);
|
|
|
|
pComp->Value(iTmp); // must be denumerated later
|
|
|
|
Data.Int = iTmp;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case C4V_C4DefEnum:
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-21 23:40:03 +00:00
|
|
|
assert(fCompiler);
|
|
|
|
C4ID id;
|
2010-09-08 18:09:27 +00:00
|
|
|
pComp->Value(id);
|
2011-03-31 22:03:02 +00:00
|
|
|
C4PropList * p = Definitions.ID2Def(id);
|
|
|
|
if (!p)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2011-03-31 22:03:02 +00:00
|
|
|
Set0();
|
|
|
|
pComp->Warn("ERROR: Definition %s is missing.", id.ToString());
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2010-03-21 23:40:03 +00:00
|
|
|
else
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2011-03-31 22:03:02 +00:00
|
|
|
SetPropList(p);
|
2010-03-21 23:40:03 +00:00
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
case C4V_String:
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// search
|
|
|
|
StdStrBuf s;
|
|
|
|
if (!fCompiler) s = Data.Str->GetData();
|
|
|
|
pComp->Value(s);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (fCompiler)
|
|
|
|
{
|
2009-07-21 14:46:39 +00:00
|
|
|
C4String *pString = ::Strings.RegString(s);
|
2011-05-09 12:37:28 +00:00
|
|
|
Data.Str = pString;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (pString)
|
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
pString->IncRef();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
else
|
2011-05-09 12:37:28 +00:00
|
|
|
Type = C4V_Nil;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
case C4V_Array:
|
2011-03-27 16:14:41 +00:00
|
|
|
iTmp = numbers->GetNumberForValue(this);
|
|
|
|
pComp->Value(iTmp);
|
2009-05-08 13:28:41 +00:00
|
|
|
break;
|
|
|
|
|
2011-05-09 12:37:28 +00:00
|
|
|
case C4V_Nil:
|
2009-07-20 21:04:29 +00:00
|
|
|
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
|
|
|
|
|
|
|
default:
|
2011-05-09 12:37:28 +00:00
|
|
|
// shouldn't happen
|
2009-05-08 13:28:41 +00:00
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2011-03-27 16:14:41 +00:00
|
|
|
void C4ValueNumbers::CompileValue(StdCompiler * pComp, C4Value * v)
|
|
|
|
{
|
|
|
|
// Type
|
|
|
|
bool fCompiler = pComp->isCompiler();
|
|
|
|
char cC4VID;
|
|
|
|
switch(v->GetType())
|
|
|
|
{
|
|
|
|
case C4V_PropList: cC4VID = 'p'; break;
|
|
|
|
case C4V_Array: cC4VID = 'a'; break;
|
|
|
|
default: assert(fCompiler); break;
|
|
|
|
}
|
|
|
|
pComp->Character(cC4VID);
|
|
|
|
pComp->Separator(StdCompiler::SEP_START);
|
|
|
|
switch(cC4VID)
|
|
|
|
{
|
|
|
|
case 'p':
|
|
|
|
{
|
|
|
|
C4PropList * p = v->_getPropList();
|
|
|
|
pComp->Value(mkParAdapt(mkPtrAdaptNoNull(p), this));
|
|
|
|
if (fCompiler) v->SetPropList(p);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
{
|
|
|
|
C4ValueArray * a = v->_getArray();
|
|
|
|
pComp->Value(mkParAdapt(mkPtrAdaptNoNull(a), this));
|
|
|
|
if (fCompiler) v->SetArray(a);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pComp->excCorrupt("Unexpected character '%c'", cC4VID);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pComp->Separator(StdCompiler::SEP_END);
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4ValueNumbers::CompileFunc(StdCompiler * pComp)
|
|
|
|
{
|
|
|
|
bool fCompiler = pComp->isCompiler();
|
|
|
|
bool fNaming = pComp->hasNaming();
|
|
|
|
if (fCompiler)
|
|
|
|
{
|
|
|
|
uint32_t iSize;
|
|
|
|
if (!fNaming) pComp->Value(iSize);
|
|
|
|
// Read new
|
|
|
|
do
|
|
|
|
{
|
|
|
|
// No entries left to read?
|
|
|
|
if (!fNaming && !iSize--)
|
|
|
|
break;
|
|
|
|
// Read entries
|
|
|
|
try
|
|
|
|
{
|
|
|
|
LoadedValues.push_back(C4Value());
|
|
|
|
CompileValue(pComp, &LoadedValues.back());
|
|
|
|
}
|
|
|
|
catch (StdCompiler::NotFoundException *pEx)
|
|
|
|
{
|
|
|
|
// No value found: Stop reading loop
|
|
|
|
delete pEx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (pComp->Separator(StdCompiler::SEP_SEP));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Note: the list grows during this loop due to nested data structures.
|
|
|
|
// Data structures with loops are fine because the beginning of the loop
|
|
|
|
// will be found in the map and not saved again.
|
|
|
|
// This may still work with the binary compilers due to double-compiling
|
|
|
|
if (!fNaming)
|
|
|
|
{
|
|
|
|
int32_t iSize = ValuesToSave.size();
|
|
|
|
pComp->Value(iSize);
|
|
|
|
}
|
|
|
|
for(std::list<C4Value *>::iterator i = ValuesToSave.begin(); i != ValuesToSave.end(); ++i)
|
|
|
|
{
|
|
|
|
CompileValue(pComp, *i);
|
|
|
|
if (i != ValuesToSave.end()) pComp->Separator(StdCompiler::SEP_SEP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
bool C4Value::operator == (const C4Value& Value2) const
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
switch (Type)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
|
|
|
case C4V_Any:
|
|
|
|
assert(!Data);
|
|
|
|
return Value2.Type == Type;
|
|
|
|
case C4V_Int:
|
|
|
|
case C4V_Bool:
|
|
|
|
switch (Value2.Type)
|
|
|
|
{
|
|
|
|
case C4V_Int:
|
|
|
|
case C4V_Bool:
|
2009-05-08 13:28:41 +00:00
|
|
|
return Data == Value2.Data;
|
2010-03-28 18:58:01 +00:00
|
|
|
default:
|
|
|
|
return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
case C4V_C4Object: case C4V_PropList:
|
2011-01-15 22:03:01 +00:00
|
|
|
if (Value2.Type == C4V_C4Object || Value2.Type == C4V_PropList)
|
2010-09-10 21:01:30 +00:00
|
|
|
{
|
|
|
|
// Compare as equal if and only if the proplists are indistinguishable
|
|
|
|
// If one or both are mutable, they have to be the same
|
|
|
|
// otherwise, they have to have the same contents
|
|
|
|
if (Data.PropList == Value2.Data.PropList) return true;
|
|
|
|
if (!Data.PropList->IsFrozen() || !Value2.Data.PropList->IsFrozen()) return false;
|
|
|
|
return (*Data.PropList == *Value2.Data.PropList);
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
case C4V_String:
|
|
|
|
return Type == Value2.Type && Data.Str == Value2.Data.Str;
|
|
|
|
case C4V_Array:
|
|
|
|
return Type == Value2.Type && *(Data.Array) == *(Value2.Data.Array);
|
|
|
|
default:
|
|
|
|
return Data == Value2.Data;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
return GetData() == Value2.GetData();
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
bool C4Value::operator != (const C4Value& Value2) const
|
|
|
|
{
|
|
|
|
return !(*this == Value2);
|
|
|
|
}
|
2009-04-12 12:04:28 +00:00
|
|
|
|
2010-09-20 17:49:00 +00:00
|
|
|
C4ID C4Value::getC4ID() const
|
2009-04-12 12:04:28 +00:00
|
|
|
{
|
|
|
|
C4PropList * p = getPropList();
|
2010-03-28 18:58:01 +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;
|
|
|
|
}
|
2011-04-14 13:36:31 +00:00
|
|
|
|
|
|
|
void C4Value::LogDeletedObjectWarning(C4PropList * p)
|
|
|
|
{
|
2011-05-25 18:09:12 +00:00
|
|
|
if (p->GetPropListNumbered())
|
|
|
|
LogF("Warning: using deleted object (#%d) (%s)!", p->GetPropListNumbered()->Number, p->GetName());
|
|
|
|
else
|
|
|
|
LogF("Warning: using deleted proplist %p (%s)!", static_cast<void*>(p), p->GetName());
|
2011-04-14 13:36:31 +00:00
|
|
|
AulExec.LogCallStack();
|
|
|
|
}
|