2009-05-08 13:28:41 +00:00
|
|
|
/*
|
|
|
|
* OpenClonk, http://www.openclonk.org
|
|
|
|
*
|
2013-12-17 20:01:09 +00:00
|
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
|
2016-04-03 18:18:29 +00:00
|
|
|
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
|
2009-05-08 13:28:41 +00:00
|
|
|
*
|
2013-12-17 20:01:09 +00:00
|
|
|
* Distributed under the terms of the ISC license; see accompanying file
|
|
|
|
* "COPYING" for details.
|
2009-05-08 13:28:41 +00:00
|
|
|
*
|
2013-12-17 20:01:09 +00:00
|
|
|
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
|
|
|
|
* See accompanying file "TRADEMARK" for details.
|
2009-05-08 13:28:41 +00:00
|
|
|
*
|
2013-12-17 20:01:09 +00:00
|
|
|
* To redistribute this file separately, substitute the full license texts
|
|
|
|
* for the above references.
|
2009-05-08 13:28:41 +00:00
|
|
|
*/
|
2012-05-14 20:07:33 +00:00
|
|
|
// Miscellaneous script engine bits
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2016-04-03 18:07:56 +00:00
|
|
|
#include "C4Include.h"
|
|
|
|
#include "script/C4Aul.h"
|
|
|
|
#include "script/C4AulExec.h"
|
|
|
|
#include "script/C4AulDebug.h"
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2016-04-03 18:07:56 +00:00
|
|
|
#include "config/C4Config.h"
|
|
|
|
#include "object/C4Def.h"
|
|
|
|
#include "lib/C4Log.h"
|
|
|
|
#include "c4group/C4Components.h"
|
|
|
|
#include "c4group/C4LangStringTable.h"
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-12-22 03:26:37 +00:00
|
|
|
C4AulError::C4AulError(): shown(false) {}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4AulError::show()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-12-22 03:26:37 +00:00
|
|
|
shown = true;
|
2009-05-08 13:28:41 +00:00
|
|
|
// simply log error message
|
2010-03-28 18:58:01 +00:00
|
|
|
if (sMessage)
|
2009-05-08 13:28:41 +00:00
|
|
|
DebugLog(sMessage.getData());
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2016-01-22 23:57:30 +00:00
|
|
|
const char *C4AulError::what() const noexcept
|
|
|
|
{
|
|
|
|
return sMessage ? sMessage.getData() : "(unknown error)";
|
|
|
|
}
|
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
/*--- C4AulScriptEngine ---*/
|
|
|
|
|
|
|
|
C4AulScriptEngine::C4AulScriptEngine():
|
2016-01-03 19:44:05 +00:00
|
|
|
C4PropListStaticMember(NULL, NULL, ::Strings.RegString("Global")),
|
2012-07-25 23:27:52 +00:00
|
|
|
warnCnt(0), errCnt(0), lineCnt(0)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
GlobalNamedNames.Reset();
|
|
|
|
GlobalNamed.Reset();
|
|
|
|
GlobalNamed.SetNameList(&GlobalNamedNames);
|
|
|
|
GlobalConstNames.Reset();
|
|
|
|
GlobalConsts.Reset();
|
|
|
|
GlobalConsts.SetNameList(&GlobalConstNames);
|
2012-01-25 03:15:39 +00:00
|
|
|
Child0 = ChildL = NULL;
|
2016-01-03 19:44:05 +00:00
|
|
|
RegisterGlobalConstant("Global", C4VPropList(this));
|
2011-10-04 20:12:45 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2012-07-25 23:27:52 +00:00
|
|
|
C4AulScriptEngine::~C4AulScriptEngine()
|
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4AulScriptEngine::Clear()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-02-23 18:29:26 +00:00
|
|
|
#ifndef NOAULDEBUG
|
2009-04-21 21:44:56 +00:00
|
|
|
// stop debugger
|
2011-03-02 23:58:43 +00:00
|
|
|
delete C4AulDebug::GetDebugger();
|
2010-02-23 18:29:26 +00:00
|
|
|
#endif
|
2012-01-25 03:15:39 +00:00
|
|
|
while (Child0)
|
|
|
|
if (Child0->Delete()) delete Child0;
|
|
|
|
else Child0->Unreg();
|
2009-05-08 13:28:41 +00:00
|
|
|
// clear own stuff
|
2016-01-03 19:44:05 +00:00
|
|
|
C4PropListStaticMember::Clear();
|
2009-05-08 13:28:41 +00:00
|
|
|
// reset values
|
2012-01-25 03:15:53 +00:00
|
|
|
warnCnt = errCnt = lineCnt = 0;
|
2009-05-08 13:28:41 +00:00
|
|
|
// resetting name lists will reset all data lists, too
|
|
|
|
// except not...
|
|
|
|
GlobalNamedNames.Reset();
|
|
|
|
GlobalConstNames.Reset();
|
|
|
|
GlobalConsts.Reset();
|
|
|
|
GlobalConsts.SetNameList(&GlobalConstNames);
|
2016-01-03 19:44:05 +00:00
|
|
|
RegisterGlobalConstant("Global", C4VPropList(this));
|
2009-05-08 13:28:41 +00:00
|
|
|
GlobalNamed.Reset();
|
|
|
|
GlobalNamed.SetNameList(&GlobalNamedNames);
|
2013-12-22 22:47:40 +00:00
|
|
|
UserFiles.clear();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4AulScriptEngine::RegisterGlobalConstant(const char *szName, const C4Value &rValue)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Register name and set value.
|
|
|
|
// AddName returns the index of existing element if the name is assigned already.
|
|
|
|
// That is OK, since it will only change the value of the global ("overload" it).
|
|
|
|
// A warning would be nice here. However, this warning would show up whenever a script
|
|
|
|
// containing globals constants is recompiled.
|
|
|
|
GlobalConsts[GlobalConstNames.AddName(szName)] = rValue;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
bool C4AulScriptEngine::GetGlobalConstant(const char *szName, C4Value *pTargetValue)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// get index of global by name
|
|
|
|
int32_t iConstIndex = GlobalConstNames.GetItemNr(szName);
|
|
|
|
// not found?
|
|
|
|
if (iConstIndex<0) return false;
|
|
|
|
// if it's found, assign the value if desired
|
|
|
|
if (pTargetValue) *pTargetValue = GlobalConsts[iConstIndex];
|
|
|
|
// constant exists
|
|
|
|
return true;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2016-01-03 19:44:05 +00:00
|
|
|
void C4AulScriptEngine::Denumerate(C4ValueNumbers * numbers)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2011-03-26 22:59:35 +00:00
|
|
|
GlobalNamed.Denumerate(numbers);
|
2009-05-08 13:28:41 +00:00
|
|
|
// runtime data only: don't denumerate consts
|
2012-06-01 15:27:59 +00:00
|
|
|
GameScript.ScenPropList.Denumerate(numbers);
|
2016-01-03 19:44:05 +00:00
|
|
|
C4PropListStaticMember::Denumerate(numbers);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-04-21 21:44:56 +00:00
|
|
|
|
2011-03-26 22:59:35 +00:00
|
|
|
void C4AulScriptEngine::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2013-12-22 22:47:40 +00:00
|
|
|
assert(UserFiles.empty()); // user files must not be kept open
|
2009-05-08 13:28:41 +00:00
|
|
|
C4ValueMapData GlobalNamedDefault;
|
|
|
|
GlobalNamedDefault.SetNameList(&GlobalNamedNames);
|
2011-09-19 19:48:14 +00:00
|
|
|
pComp->Value(mkNamingAdapt(mkParAdapt(GlobalNamed, numbers), "StaticVariables", GlobalNamedDefault));
|
2012-06-01 15:27:59 +00:00
|
|
|
pComp->Value(mkNamingAdapt(mkParAdapt(*GameScript.ScenPropList._getPropList(), numbers), "Scenario"));
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-04-21 21:44:56 +00:00
|
|
|
|
2012-05-18 15:49:38 +00:00
|
|
|
std::list<const char*> C4AulScriptEngine::GetFunctionNames(C4PropList * p)
|
2011-01-13 00:09:06 +00:00
|
|
|
{
|
2011-10-13 22:40:55 +00:00
|
|
|
std::list<const char*> functions;
|
2012-05-18 15:49:38 +00:00
|
|
|
std::list<const char*> global_functions;
|
2015-09-27 00:10:55 +00:00
|
|
|
auto sort_alpha = [](const char * const &a, const char * const &b) -> bool { return strcmp(a, b) < 0; };
|
2012-05-18 15:49:38 +00:00
|
|
|
if (!p) p = GetPropList();
|
|
|
|
const C4ValueArray * a = p->GetProperties();
|
|
|
|
for (int i = 0; i < a->GetSize(); ++i)
|
2011-01-13 00:09:06 +00:00
|
|
|
{
|
2012-05-18 15:49:38 +00:00
|
|
|
C4String * key = (*a)[i].getStr();
|
|
|
|
if (!key) continue;
|
|
|
|
C4AulFunc * f = p->GetFunc(key);
|
|
|
|
if (!f) continue;
|
|
|
|
if (!f->GetPublic()) continue;
|
2015-09-27 00:10:55 +00:00
|
|
|
if (!::ScriptEngine.GetPropList()->HasProperty(key))
|
2012-05-18 15:49:38 +00:00
|
|
|
functions.push_back(key->GetCStr());
|
|
|
|
else
|
|
|
|
global_functions.push_back(key->GetCStr());
|
2011-01-13 00:09:06 +00:00
|
|
|
}
|
2012-05-18 15:49:38 +00:00
|
|
|
delete a;
|
2015-09-27 00:10:55 +00:00
|
|
|
functions.sort(sort_alpha);
|
|
|
|
if (!functions.empty() && !global_functions.empty()) functions.push_back(0); // separator
|
|
|
|
global_functions.sort(sort_alpha);
|
2012-05-18 15:49:38 +00:00
|
|
|
functions.splice(functions.end(), global_functions);
|
2011-01-13 00:09:06 +00:00
|
|
|
return functions;
|
|
|
|
}
|
|
|
|
|
2013-12-22 22:47:40 +00:00
|
|
|
int32_t C4AulScriptEngine::CreateUserFile()
|
|
|
|
{
|
|
|
|
// create new file and return handle
|
|
|
|
// find empty handle
|
|
|
|
int32_t last_handle = 1;
|
|
|
|
for (std::list<C4AulUserFile>::const_iterator i = UserFiles.begin(); i != UserFiles.end(); ++i)
|
|
|
|
if ((*i).GetHandle() >= last_handle)
|
|
|
|
last_handle = (*i).GetHandle()+1;
|
|
|
|
// Create new user file
|
|
|
|
UserFiles.push_back(C4AulUserFile(last_handle));
|
|
|
|
return last_handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void C4AulScriptEngine::CloseUserFile(int32_t handle)
|
|
|
|
{
|
|
|
|
// close user file given by handle
|
|
|
|
for (std::list<C4AulUserFile>::iterator i = UserFiles.begin(); i != UserFiles.end(); ++i)
|
|
|
|
if ((*i).GetHandle() == handle)
|
|
|
|
{
|
|
|
|
UserFiles.erase(i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
C4AulUserFile *C4AulScriptEngine::GetUserFile(int32_t handle)
|
|
|
|
{
|
|
|
|
// get user file given by handle
|
|
|
|
for (std::list<C4AulUserFile>::iterator i = UserFiles.begin(); i != UserFiles.end(); ++i)
|
|
|
|
if ((*i).GetHandle() == handle)
|
|
|
|
{
|
|
|
|
return &*i;
|
|
|
|
}
|
|
|
|
// not found
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
/*--- C4AulFuncMap ---*/
|
|
|
|
|
2012-05-27 22:53:41 +00:00
|
|
|
C4AulFuncMap::C4AulFuncMap(): FuncCnt(0)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2012-05-27 22:53:41 +00:00
|
|
|
memset(Funcs, 0, sizeof (C4AulFunc *) * HashSize);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4AulFuncMap::~C4AulFuncMap()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2012-05-27 22:53:41 +00:00
|
|
|
assert(!FuncCnt);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
unsigned int C4AulFuncMap::Hash(const char * name)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Fowler/Noll/Vo hash
|
|
|
|
unsigned int h = 2166136261u;
|
|
|
|
while (*name)
|
|
|
|
h = (h ^ *(name++)) * 16777619;
|
|
|
|
return h;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2016-02-01 01:14:54 +00:00
|
|
|
C4AulFunc * C4AulFuncMap::GetFirstFunc(const char * Name)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
if (!Name) return NULL;
|
2016-02-01 01:14:54 +00:00
|
|
|
C4AulFunc * Func = Funcs[Hash(Name) % HashSize];
|
|
|
|
while (Func && !SEqual(Name, Func->GetName()))
|
2009-05-08 13:28:41 +00:00
|
|
|
Func = Func->MapNext;
|
|
|
|
return Func;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4AulFunc * C4AulFuncMap::GetNextSNFunc(const C4AulFunc * After)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
C4AulFunc * Func = After->MapNext;
|
2012-05-27 22:53:41 +00:00
|
|
|
while (Func && After->GetName() != Func->GetName())
|
2009-05-08 13:28:41 +00:00
|
|
|
Func = Func->MapNext;
|
|
|
|
return Func;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2012-05-27 22:53:41 +00:00
|
|
|
void C4AulFuncMap::Add(C4AulFunc * func)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2012-05-27 22:53:41 +00:00
|
|
|
++FuncCnt;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Get a pointer to the bucket
|
2012-05-27 22:53:41 +00:00
|
|
|
C4AulFunc ** pFunc = &(Funcs[Hash(func->GetName()) % HashSize]);
|
|
|
|
// move the current first to the second position
|
|
|
|
func->MapNext = *pFunc;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Add the func
|
|
|
|
*pFunc = func;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4AulFuncMap::Remove(C4AulFunc * func)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2012-05-27 22:53:41 +00:00
|
|
|
C4AulFunc ** pFunc = &Funcs[Hash(func->GetName()) % HashSize];
|
2009-05-08 13:28:41 +00:00
|
|
|
while (*pFunc != func)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
pFunc = &((*pFunc)->MapNext);
|
|
|
|
assert(*pFunc); // crash on remove of a not contained func
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
*pFunc = (*pFunc)->MapNext;
|
|
|
|
--FuncCnt;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|