openclonk/src/script/C4Value.cpp

473 lines
10 KiB
C++
Raw Normal View History

2009-05-08 13:28:41 +00:00
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2001, 2005-2006 Sven Eberhardt
* Copyright (c) 2001-2002, 2004-2006 Peter Wortmann
* Copyright (c) 2006-2010 Günther Brammer
* Copyright (c) 2007 Matthes Bender
* 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>
#include <C4DefList.h>
2009-05-08 13:28:41 +00:00
#include <C4StringTable.h>
#include <C4ValueArray.h>
2009-05-08 13:28:41 +00:00
#include <C4Game.h>
#include <C4GameObjects.h>
2009-05-08 13:28:41 +00:00
#include <C4Object.h>
#include <C4Log.h>
const C4NullValue C4VNull = C4NullValue();
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
{
case C4V_Any:
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";
case C4V_PropList:
return "proplist";
2009-05-08 13:28:41 +00:00
default:
return "!Fehler!";
}
}
char GetC4VID(const C4V_Type Type)
{
2010-03-28 18:58:01 +00:00
switch (Type)
2009-05-08 13:28:41 +00:00
{
case C4V_Any:
return 'A';
case C4V_Int:
return 'i';
case C4V_Bool:
return 'b';
case C4V_PropList:
return 'p';
2009-05-08 13:28:41 +00:00
case C4V_C4Object:
case C4V_C4ObjectEnum:
return 'O';
case C4V_String:
return 's';
case C4V_C4DefEnum:
return 'D';
2009-05-08 13:28:41 +00:00
case C4V_Array:
return 'a';
default:
assert(false);
2009-05-08 13:28:41 +00:00
}
return ' ';
}
C4V_Type GetC4VFromID(const char C4VID)
{
2010-03-28 18:58:01 +00:00
switch (C4VID)
2009-05-08 13:28:41 +00:00
{
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 'O':
return C4V_C4ObjectEnum;
case 'D':
return C4V_C4DefEnum;
2009-05-08 13:28:41 +00:00
case 'a':
return C4V_Array;
case 'p':
return C4V_PropList;
2009-05-08 13:28:41 +00:00
}
return C4V_Any;
}
const char* C4Value::GetTypeInfo()
{
return GetC4VName(GetType());
}
bool C4Value::FnCnvObject() const
2010-03-28 18:58:01 +00:00
{
// try casting
if (Data.PropList->GetObject()) return true;
return false;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Type conversion table
#define CnvOK C4VCnvFn::CnvOK, false // allow conversion by same value
#define CnvOK0 C4VCnvFn::CnvOK0, true
#define CnvError C4VCnvFn::CnvError, true
#define CnvObject C4VCnvFn::CnvObject, false
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{
{ // C4V_Any - is always 0, convertible to everything
2010-03-28 18:58:01 +00:00
{ CnvOK }, // any same
{ CnvOK }, // int
{ CnvOK }, // Bool
{ CnvOK }, // PropList
{ CnvOK }, // C4Object
{ CnvOK }, // String
{ CnvOK }, // Array
2009-05-08 13:28:41 +00:00
},
{ // C4V_Int
2010-03-28 18:58:01 +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
2009-05-08 13:28:41 +00:00
},
{ // C4V_Bool
2010-03-28 18:58:01 +00:00
{ CnvOK }, // any
{ CnvOK }, // int might be used
{ CnvOK }, // Bool same
{ CnvError }, // PropList NEVER!
{ CnvError }, // C4Object NEVER!
{ CnvError }, // String NEVER!
{ CnvError }, // Array NEVER!
2009-05-08 13:28:41 +00:00
},
{ // C4V_PropList
2010-03-28 18:58:01 +00:00
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvOK }, // Bool
{ CnvOK }, // PropList same
{ CnvObject }, // C4Object
{ CnvError }, // String NEVER!
{ CnvError }, // Array NEVER!
2009-05-08 13:28:41 +00:00
},
{ // C4V_Object
2010-03-28 18:58:01 +00:00
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvOK }, // Bool
{ CnvOK }, // PropList
{ CnvOK }, // C4Object same
{ CnvError }, // String NEVER!
{ CnvError }, // Array NEVER!
2009-05-08 13:28:41 +00:00
},
{ // C4V_String
2010-03-28 18:58:01 +00:00
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvOK }, // Bool
{ CnvError }, // PropList NEVER!
{ CnvError }, // C4Object NEVER!
{ CnvOK }, // String same
{ CnvError }, // Array NEVER!
2009-05-08 13:28:41 +00:00
},
{ // C4V_Array
2010-03-28 18:58:01 +00:00
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvOK }, // Bool
{ CnvError }, // PropList NEVER!
{ CnvError }, // C4Object NEVER!
{ CnvError }, // String NEVER!
{ CnvOK }, // Array same
}
2009-05-08 13:28:41 +00:00
};
#undef CnvOK
#undef CnvOK0
#undef CnvError
#undef CnvObject
2009-05-08 13:28:41 +00:00
// Humanreadable debug output
StdStrBuf C4Value::GetDataString() 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:
case C4V_PropList:
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// obj exists?
2010-03-28 18:58:01 +00:00
if (!::Objects.ObjectNumber(Data.PropList))
2010-04-28 21:43:25 +00:00
return FormatString("%ld", static_cast<long>(Data.Int));
2010-03-28 18:58:01 +00:00
else if (Data.PropList)
if (Data.Obj->Status == C4OS_NORMAL)
return FormatString("%s #%d", Data.PropList->GetName(), Objects.ObjectNumber(Data.PropList));
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
return FormatString("{%s #%d}", Data.PropList->GetName(), Objects.ObjectNumber(Data.PropList));
else
return StdStrBuf("0"); // (impossible)
}
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
{
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(", ");
DataString.Append(static_cast<const StdStrBuf &>(Data.Array->GetItem(i).GetDataString()));
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
DataString.AppendChar(']');
return DataString;
}
case C4V_Any:
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
}
void C4Value::DenumeratePointer()
{
// array?
if (Type == C4V_Array)
{
Data.Array->DenumeratePointers();
return;
}
// object types only
2010-03-28 18:58:01 +00:00
if (Type != C4V_C4ObjectEnum) return;
2009-05-08 13:28:41 +00:00
// get obj id, search object
int iObjID = Data.Int;
C4PropList *pObj = Objects.PropListPointer(iObjID);
2010-03-28 18:58:01 +00:00
if (pObj)
2009-05-08 13:28:41 +00:00
// set
SetPropList(pObj);
2009-05-08 13:28:41 +00:00
else
{
// object: invalid value - set to zero
LogF("ERROR: Object number %d is missing.", iObjID);
Set0();
2009-05-08 13:28:41 +00:00
}
}
void C4Value::CompileFunc(StdCompiler *pComp)
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
assert(Type != C4V_Any || !Data);
2009-05-08 13:28:41 +00:00
char cC4VID = GetC4VID(Type);
// special case proplists
if (Type == C4V_PropList && getPropList()->IsDef())
cC4VID = GetC4VID(C4V_C4DefEnum);
else if (Type == C4V_PropList && !getPropList()->IsFrozen())
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
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;
cC4VID = 'A';
2010-03-28 18:58:01 +00:00
}
Type = GetC4VFromID(cC4VID);
}
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
case C4V_C4Object: case C4V_PropList:
2010-03-28 18:58:01 +00:00
{
if (fCompiler || (Type == C4V_PropList && getPropList()->IsFrozen() && !getPropList()->IsDef()))
{
assert(Type == C4V_PropList);
pComp->Separator(StdCompiler::SEP_START2);
pComp->Value(mkPtrAdapt(Data.PropList, false));
if (fCompiler) Data.PropList->AddRef(this);
pComp->Separator(StdCompiler::SEP_END2);
break;
}
assert(!fCompiler);
C4PropList * p = getPropList();
if (Type == C4V_PropList && p->IsDef())
pComp->Value(p->GetDef()->id);
else
2010-03-28 18:58:01 +00:00
{
2009-07-21 14:46:39 +00:00
iTmp = ::Objects.ObjectNumber(getPropList());
pComp->Value(iTmp);
}
2010-03-28 18:58:01 +00:00
break;
}
2009-05-08 13:28:41 +00:00
case C4V_C4ObjectEnum:
assert(fCompiler);
pComp->Value(iTmp); // must be denumerated later
Data.Int = iTmp;
break;
case C4V_C4DefEnum:
2010-03-28 18:58:01 +00:00
{
assert(fCompiler);
C4ID id;
pComp->Value(id);
Data.PropList = Definitions.ID2Def(id);
Type = C4V_PropList;
2010-03-28 18:58:01 +00:00
if (!Data.PropList)
{
LogF("ERROR: Definition %s is missing.", id.ToString());
Type = C4V_Any;
2010-03-28 18:58:01 +00:00
}
else
2010-03-28 18:58:01 +00:00
{
Data.PropList->AddRef(this);
}
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);
2010-03-28 18:58:01 +00:00
if (pString)
{
2009-05-08 13:28:41 +00:00
Data.Str = pString;
pString->IncRef();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
Type = C4V_Any;
}
2010-03-28 18:58:01 +00:00
break;
}
2009-05-08 13:28:41 +00:00
case C4V_Array:
2010-04-01 21:08:06 +00:00
pComp->Separator(StdCompiler::SEP_START2);
2009-05-08 13:28:41 +00:00
pComp->Value(mkPtrAdapt(Data.Array, false));
if (fCompiler) Data.Array->IncRef();
2010-04-01 21:08:06 +00:00
pComp->Separator(StdCompiler::SEP_END2);
2009-05-08 13:28:41 +00:00
break;
case C4V_Any:
assert(!Data);
// doesn't have a value, so nothing to store
break;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
// shouldn't happen
2009-05-08 13:28:41 +00:00
default:
assert(false);
break;
}
2010-03-28 18:58:01 +00:00
}
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:
if (Value2.Type == C4V_C4Object || Value2.Type == C4V_PropList)
{
// 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);
}
C4ID C4Value::getC4ID() const
{
C4PropList * p = getPropList();
2010-03-28 18:58:01 +00:00
if (!p) return C4ID::None;
C4Def * d = p->GetDef();
if (!d) return C4ID::None;
return d->id;
}