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