OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Aul.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // Miscellaneous script engine bits
17 
18 #include "C4Include.h"
19 #include "script/C4Aul.h"
20 
21 #include "c4group/C4Components.h"
23 #include "script/C4AulDebug.h"
24 #include "script/C4AulExec.h"
25 #include "script/C4Effect.h"
26 #include "script/C4ScriptHost.h"
27 
28 const char *C4AulWarningMessages[] = {
29 #define DIAG(id, text, enabled) text,
30 #include "C4AulWarnings.h"
31 #undef DIAG
32  nullptr
33 };
34 const char *C4AulWarningIDs[] = {
35 #define DIAG(id, text, enabled) #id,
36 #include "C4AulWarnings.h"
37 #undef DIAG
38  nullptr
39 };
40 
41 static_assert(std::extent<decltype(C4AulWarningMessages), 0>::value - 1 == static_cast<size_t>(C4AulWarningId::WarningCount), "Warning message count doesn't match warning count");
42 static_assert(std::extent<decltype(C4AulWarningIDs), 0>::value - 1 == static_cast<size_t>(C4AulWarningId::WarningCount), "Warning ID count doesn't match warning count");
43 
44 static class DefaultErrorHandler : public C4AulErrorHandler
45 {
46 public:
47  void OnError(const char *msg) override
48  {
49  DebugLogF("ERROR: %s", msg);
51  }
52  void OnWarning(const char *msg) override
53  {
54  DebugLogF("WARNING: %s", msg);
56  }
57 } DefaultErrorHandler;
58 
59 const char *C4AulError::what() const noexcept
60 {
61  return sMessage ? sMessage.getData() : "(unknown error)";
62 }
63 
64 /*--- C4AulScriptEngine ---*/
65 
67  C4PropListStaticMember(nullptr, nullptr, ::Strings.RegString("Global")),
68  ErrorHandler(&DefaultErrorHandler)
69 {
70  GlobalNamedNames.Reset();
71  GlobalNamed.Reset();
72  GlobalNamed.SetNameList(&GlobalNamedNames);
73  GlobalConstNames.Reset();
74  GlobalConsts.Reset();
75  GlobalConsts.SetNameList(&GlobalConstNames);
76  Child0 = ChildL = nullptr;
77  RegisterGlobalConstant("Global", C4VPropList(this));
78 }
79 
81 {
82  Clear();
83 }
84 
86 {
87 #ifndef NOAULDEBUG
88  // stop debugger
89  delete C4AulDebug::GetDebugger();
90 #endif
91  while (Child0)
92  if (Child0->Delete()) delete Child0;
93  else Child0->Unreg();
94  // clear own stuff
96  // reset values
97  warnCnt = errCnt = lineCnt = 0;
98  // resetting name lists will reset all data lists, too
99  // except not...
104  RegisterGlobalConstant("Global", C4VPropList(this));
105  GlobalNamed.Reset();
107  delete pGlobalEffects; pGlobalEffects=nullptr;
108  UserFiles.clear();
109  // Delete all global proplists made static (breaks
110  // cyclic references).
111  for (C4Value& value: OwnedPropLists)
112  {
113  C4PropList* plist = value.getPropList();
114  if (plist)
115  {
116  if (plist->Delete()) delete plist;
117  else plist->Clear();
118  }
119  }
120  OwnedPropLists.clear();
121 }
122 
123 void C4AulScriptEngine::RegisterGlobalConstant(const char *szName, const C4Value &rValue)
124 {
125  // Register name and set value.
126  // AddName returns the index of existing element if the name is assigned already.
127  // That is OK, since it will only change the value of the global ("overload" it).
128  // A warning would be nice here. However, this warning would show up whenever a script
129  // containing globals constants is recompiled.
130  GlobalConsts[GlobalConstNames.AddName(szName)] = rValue;
131 }
132 
133 bool C4AulScriptEngine::GetGlobalConstant(const char *szName, C4Value *pTargetValue)
134 {
135  // get index of global by name
136  int32_t iConstIndex = GlobalConstNames.GetItemNr(szName);
137  // not found?
138  if (iConstIndex<0) return false;
139  // if it's found, assign the value if desired
140  if (pTargetValue) *pTargetValue = GlobalConsts[iConstIndex];
141  // constant exists
142  return true;
143 }
144 
146 {
147  GlobalNamed.Denumerate(numbers);
148  // runtime data only: don't denumerate consts
149  GameScript.Denumerate(numbers);
152 }
153 
154 static void GlobalEffectsMergeCompileFunc(StdCompiler *pComp, C4Effect * & pEffects, const char * name, C4PropList * pForObj, C4ValueNumbers * numbers)
155 {
156  C4Effect *pOldEffect, *pNextOldEffect=pEffects;
157  pEffects = nullptr;
158  try
159  {
160  pComp->Value(mkParAdapt(mkNamingPtrAdapt(pEffects, name), pForObj, numbers));
161  }
162  catch (...)
163  {
164  delete pNextOldEffect;
165  throw;
166  }
167  while ((pOldEffect=pNextOldEffect))
168  {
169  pNextOldEffect = pOldEffect->pNext;
170  pOldEffect->Register(&pEffects, Abs(pOldEffect->iPriority));
171  }
172 }
173 
174 void C4AulScriptEngine::CompileFunc(StdCompiler *pComp, bool fScenarioSection, C4ValueNumbers * numbers)
175 {
176  if (!fScenarioSection)
177  {
178  assert(UserFiles.empty()); // user files must not be kept open
179  C4ValueMapData GlobalNamedDefault;
180  GlobalNamedDefault.SetNameList(&GlobalNamedNames);
181  pComp->Value(mkNamingAdapt(mkParAdapt(GlobalNamed, numbers), "StaticVariables", GlobalNamedDefault));
182  pComp->Value(mkNamingAdapt(mkParAdapt(*GameScript.ScenPropList._getPropList(), numbers), "Scenario"));
183  }
184  if (pComp->isDeserializer() && pGlobalEffects)
185  {
186  // loading scenario section or game re-init: Merge effects
187  // Must keep old effects here even if they're dead, because the LoadScenarioSection call typically came from execution of a global effect
188  // and otherwise dead pointers would remain on the stack
189  GlobalEffectsMergeCompileFunc(pComp, pGlobalEffects, "Effects", this, numbers);
190  GlobalEffectsMergeCompileFunc(pComp, GameScript.pScenarioEffects, "ScenarioEffects", GameScript.ScenPropList._getPropList(), numbers);
191  }
192  else
193  {
194  // Otherwise, just compile effects
195  pComp->Value(mkParAdapt(mkNamingPtrAdapt(pGlobalEffects, "Effects"), this, numbers));
197  }
198  pComp->Value(mkNamingAdapt(*numbers, "Values"));
199 }
200 
201 std::list<const char*> C4AulScriptEngine::GetFunctionNames(C4PropList * p)
202 {
203  std::list<const char*> functions;
204  std::list<const char*> global_functions;
205  auto sort_alpha = [](const char * const &a, const char * const &b) -> bool { return strcmp(a, b) < 0; };
206  if (!p) p = GetPropList();
207  const C4ValueArray * a = p->GetProperties();
208  for (int i = 0; i < a->GetSize(); ++i)
209  {
210  C4String * key = (*a)[i].getStr();
211  if (!key) continue;
212  C4AulFunc * f = p->GetFunc(key);
213  if (!f) continue;
214  if (!f->GetPublic()) continue;
215  if (!::ScriptEngine.GetPropList()->HasProperty(key))
216  functions.push_back(key->GetCStr());
217  else
218  global_functions.push_back(key->GetCStr());
219  }
220  delete a;
221  functions.sort(sort_alpha);
222  if (!functions.empty() && !global_functions.empty()) functions.push_back(nullptr); // separator
223  global_functions.sort(sort_alpha);
224  functions.splice(functions.end(), global_functions);
225  return functions;
226 }
227 
229 {
230  // create new file and return handle
231  // find empty handle
232  int32_t last_handle = 1;
233  for (std::list<C4AulUserFile>::const_iterator i = UserFiles.begin(); i != UserFiles.end(); ++i)
234  if ((*i).GetHandle() >= last_handle)
235  last_handle = (*i).GetHandle()+1;
236  // Create new user file
237  UserFiles.emplace_back(last_handle);
238  return last_handle;
239 }
240 
241 void C4AulScriptEngine::CloseUserFile(int32_t handle)
242 {
243  // close user file given by handle
244  for (std::list<C4AulUserFile>::iterator i = UserFiles.begin(); i != UserFiles.end(); ++i)
245  if ((*i).GetHandle() == handle)
246  {
247  UserFiles.erase(i);
248  break;
249  }
250 }
251 
253 {
254  // get user file given by handle
255  for (auto & UserFile : UserFiles)
256  if (UserFile.GetHandle() == handle)
257  {
258  return &UserFile;
259  }
260  // not found
261  return nullptr;
262 }
263 
265 {
266  assert(ErrorHandler == &DefaultErrorHandler);
267  ErrorHandler = handler;
268 }
269 
271 {
272  assert(ErrorHandler == handler);
273  ErrorHandler = &DefaultErrorHandler;
274 }
275 
276 /*--- C4AulFuncMap ---*/
277 
279 {
280  memset(Funcs, 0, sizeof(Funcs));
281 }
282 
284 {
285  assert(!FuncCnt);
286 }
287 
288 unsigned int C4AulFuncMap::Hash(const char * name)
289 {
290  // Fowler/Noll/Vo hash
291  unsigned int h = 2166136261u;
292  while (*name)
293  h = (h ^ *(name++)) * 16777619;
294  return h;
295 }
296 
297 C4AulFunc * C4AulFuncMap::GetFirstFunc(const char * Name)
298 {
299  if (!Name) return nullptr;
300  C4AulFunc * Func = Funcs[Hash(Name) % HashSize];
301  while (Func && !SEqual(Name, Func->GetName()))
302  Func = Func->MapNext;
303  return Func;
304 }
305 
307 {
308  C4AulFunc * Func = After->MapNext;
309  while (Func && After->GetName() != Func->GetName())
310  Func = Func->MapNext;
311  return Func;
312 }
313 
314 void C4AulFuncMap::Add(C4AulFunc * func)
315 {
316  ++FuncCnt;
317  // Get a pointer to the bucket
318  C4AulFunc ** pFunc = &(Funcs[Hash(func->GetName()) % HashSize]);
319  // move the current first to the second position
320  func->MapNext = *pFunc;
321  // Add the func
322  *pFunc = func;
323 }
324 
325 void C4AulFuncMap::Remove(C4AulFunc * func)
326 {
327  C4AulFunc ** pFunc = &Funcs[Hash(func->GetName()) % HashSize];
328  while (*pFunc != func)
329  {
330  pFunc = &((*pFunc)->MapNext);
331  assert(*pFunc); // crash on remove of a not contained func
332  }
333  *pFunc = (*pFunc)->MapNext;
334  --FuncCnt;
335 }
336 
338 {
340 }
C4Effect * pNext
Definition: C4Effect.h:75
const char * getData() const
Definition: StdBuf.h:442
void RegisterGlobalConstant(const char *szName, const C4Value &rValue)
C4ValueMapNames GlobalNamedNames
Definition: C4Aul.h:134
virtual bool GetPublic() const
Definition: C4AulFunc.h:68
void UnregisterErrorHandler(C4AulErrorHandler *handler)
C4PropListStatic * GetPropList()
Definition: C4Aul.h:151
std::list< C4AulUserFile > UserFiles
Definition: C4Aul.h:125
C4GameScriptHost GameScript
void Register(C4Effect **ppEffectList, int32_t iPrio)
Definition: C4Effect.cpp:71
C4AulScriptEngine ScriptEngine
Definition: C4Globals.cpp:43
#define b
const char * GetName() const
Definition: C4AulFunc.h:56
C4ValueMapData GlobalNamed
Definition: C4Aul.h:135
C4AulFunc * GetFunc(C4PropertyName k) const
Definition: C4PropList.h:105
void Denumerate(C4ValueNumbers *)
Definition: C4ValueMap.cpp:254
void Denumerate(C4ValueNumbers *) override
Definition: C4Effect.cpp:176
const char * GetCStr() const
Definition: C4StringTable.h:49
bool GetGlobalConstant(const char *szName, C4Value *pTargetValue)
C4AulFunc * GetFirstFunc(const char *Name)
void RegisterErrorHandler(C4AulErrorHandler *handler)
#define a
C4AulUserFile * GetUserFile(int32_t handle)
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
C4ValueMapNames GlobalConstNames
Definition: C4Aul.h:141
void Clear()
Definition: C4PropList.h:66
void CloseUserFile(int32_t handle)
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:92
int32_t AddName(const char *pnName)
Definition: C4ValueMap.cpp:429
virtual void Denumerate(C4ValueNumbers *)
Definition: C4PropList.cpp:350
void SetNameList(C4ValueMapNames *pnNames)
Definition: C4ValueMap.cpp:78
bool DebugLogF(const char *strMessage...)
Definition: C4Log.cpp:278
C4AulFunc * GetNextSNFunc(const C4AulFunc *After)
C4StringTable Strings
Definition: C4Globals.cpp:42
void Denumerate(C4ValueNumbers *) override
void CompileFunc(StdCompiler *pComp, bool fScenarioSection, C4ValueNumbers *numbers)
static C4AulDebug * GetDebugger()
Definition: C4AulDebug.h:31
C4Value C4VPropList(C4PropList *p)
Definition: C4Value.h:245
virtual C4ValueArray * GetProperties() const
Definition: C4PropList.cpp:914
C4Value ScenPropList
Definition: C4ScriptHost.h:163
void Add(C4AulFunc *func)
const char * what() const noexceptoverride
C4AulFunc * MapNext
Definition: C4AulFunc.h:61
C4ValueMapData GlobalConsts
Definition: C4Aul.h:142
void Denumerate(C4ValueNumbers *numbers)
const char * C4AulWarningMessages[]
Definition: C4Aul.cpp:28
void Value(const T &rStruct)
Definition: StdCompiler.h:161
int32_t GetSize() const
Definition: C4ValueArray.h:36
void Remove(C4AulFunc *func)
virtual void OnError(const char *msg)=0
virtual bool isDeserializer()
Definition: StdCompiler.h:53
int32_t GetItemNr(const char *strName) const
Definition: C4ValueMap.cpp:459
std::list< const char * > GetFunctionNames(C4PropList *)
bool HasProperty(C4String *k) const
Definition: C4PropList.h:118
virtual void OnWarning(const char *msg)=0
virtual ~C4AulErrorHandler()
int32_t iPriority
Definition: C4Effect.h:72
virtual bool Delete()
Definition: C4PropList.h:90
C4Effect * pScenarioEffects
Definition: C4ScriptHost.h:165
virtual bool Delete()
Definition: C4ScriptHost.h:43
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:458
std::vector< C4Value > OwnedPropLists
Definition: C4Aul.h:126
T Abs(T val)
Definition: Standard.h:42
StdPtrAdapt< T > mkNamingPtrAdapt(T *&rpObj, const char *szNaming)
Definition: StdAdaptors.h:604
C4AulErrorHandler * ErrorHandler
Definition: C4Aul.h:128
C4PropList * _getPropList() const
Definition: C4Value.h:129
const char * C4AulWarningIDs[]
Definition: C4Aul.cpp:34
int32_t CreateUserFile()
~C4AulScriptEngine() override
StdCopyStrBuf sMessage
Definition: C4Aul.h:44
C4ScriptHost * Child0
Definition: C4Aul.h:121
C4Effect * pGlobalEffects
Definition: C4Aul.h:144