OpenClonk
C4AulLink.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 // links aul scripts; i.e. resolves includes & appends, etc
17 
18 #include "C4Include.h"
19 #include "script/C4Aul.h"
20 
21 #include "game/C4Game.h"
22 #include "landscape/C4Material.h"
23 #include "object/C4Def.h"
24 #include "object/C4DefList.h"
25 #include "object/C4GameObjects.h"
26 #include "script/C4Effect.h"
27 
29 {
30  if (std::find(def->Script.SourceScripts.begin(), def->Script.SourceScripts.end(), this) == def->Script.SourceScripts.end())
31  {
32  def->Script.SourceScripts.push_back(this);
33  if (!Includes.empty())
34  {
35  Warn("#appendto contains #include");
36  // Try to fullfil #include, but it won't work properly: #appendtos
37  // are always appended, but #includes are prepended to the script.
38  def->Script.Includes.insert(def->Script.Includes.end(), Includes.begin(), Includes.end());
39  }
40 
41  }
42 }
43 
44 // ResolveAppends and ResolveIncludes must be called both
45 // for each script. ResolveAppends has to be called first!
47 {
48  // resolve local appends
49  if (State != ASS_PREPARSED) return false;
50  for (auto & Append : Appends)
51  {
52  if (Append != "*" || !rDefs)
53  {
54  C4Def *Def = rDefs ? rDefs->GetByName(Append) : nullptr;
55  if (Def)
56  {
57  DoAppend(Def);
58  }
59  else
60  {
61  // save id in buffer because AulWarn will use the buffer of C4IdText
62  // to get the id of the object in which the error occurs...
63  // (stupid static buffers...)
64  Warn("#appendto %s not found", Append.getData());
65  }
66  }
67  else
68  {
69  // append to all defs
70  for (int i = 0; i < rDefs->GetDefCount(); i++)
71  {
72  C4Def *pDef = rDefs->GetDef(i);
73  if (!pDef) break;
74  if (pDef == GetPropList()) continue;
75  // append
76  DoAppend(pDef);
77  }
78  }
79  }
80  return true;
81 }
82 
84 {
85  // Had been preparsed?
86  if (State != ASS_PREPARSED) return false;
87  // has already been resolved?
88  if (IncludesResolved) return true;
89  // catch circular includes
90  if (Resolving)
91  {
92  Engine->GetErrorHandler()->OnError(C4AulParseError(this, "Circular include chain detected - ignoring all includes!").what());
93  IncludesResolved = true;
94  State = ASS_LINKED;
95  return false;
96  }
97  Resolving=true;
98  // append all includes to local script
99  for (std::list<StdCopyStrBuf>::reverse_iterator i = Includes.rbegin(); i != Includes.rend(); ++i)
100  {
101  C4Def *Def = rDefs ? rDefs->GetByName(*i) : nullptr;
102  if (Def)
103  {
104  // resolve #includes in included script first (#include-chains :( )
105  if (!Def->Script.IncludesResolved)
106  if (!Def->Script.ResolveIncludes(rDefs))
107  continue; // skip this #include
108 
109  for (auto s = Def->Script.SourceScripts.rbegin(); s != Def->Script.SourceScripts.rend(); ++s)
110  {
111  if (std::find(SourceScripts.begin(), SourceScripts.end(), *s) == SourceScripts.end())
112  SourceScripts.push_front(*s);
113  }
114  }
115  else
116  {
117  // save id in buffer because AulWarn will use the buffer of C4IdText
118  // to get the id of the object in which the error occurs...
119  // (stupid static buffers...)
120  Warn("#include %s not found", i->getData());
121  }
122  }
123  IncludesResolved = true;
124  // includes/appends are resolved now (for this script)
125  Resolving=false;
126  State = ASS_LINKED;
127  return true;
128 }
129 
131 {
132  C4PropList * p = GetPropList();
133  if (p)
134  {
135  p->C4PropList::Clear();
137  }
138 
139  // Delete cyclic references of owned proplists
141 
142  // includes will have to be re-resolved now
143  IncludesResolved = false;
144 
146 }
147 
149 {
150  warnCnt = errCnt = lineCnt = 0;
151 
152  // Make everything writeable
154  for (C4ScriptHost *s = Child0; s; s = s->Next)
155  s->GetPropList()->ThawRecursively();
156 
157  // unlink scripts
158  for (C4ScriptHost *s = Child0; s; s = s->Next)
159  s->UnLink();
160  // Do not clear global variables and constants, because they are registered by the
161  // preparser or other parts. Note that keeping those fields means that you cannot delete a global
162  // variable or constant at runtime by removing it from the script.
163 }
164 
166 {
167  try
168  {
169  // resolve appends
170  for (C4ScriptHost *s = Child0; s; s = s->Next)
171  s->ResolveAppends(rDefs);
172 
173  // resolve includes
174  for (C4ScriptHost *s = Child0; s; s = s->Next)
175  s->ResolveIncludes(rDefs);
176 
177  // parse the scripts to byte code
178  for (C4ScriptHost *s = Child0; s; s = s->Next)
179  s->Parse();
180 
181  if (rDefs)
182  {
183  rDefs->SortByPriority();
184  rDefs->CallEveryDefinition();
185  }
186 
187  // Done modifying the proplists now
188  for (C4ScriptHost *s = Child0; s; s = s->Next)
189  s->GetPropList()->FreezeAndMakeStaticRecursively(&s->ownedPropLists);
190 
192  }
193  catch (C4AulError &err)
194  {
195  // error??! show it!
196  ErrorHandler->OnError(err.what());
197  }
198 
199  // Set name list for globals (FIXME: is this necessary?)
201 }
202 
203 
205 {
206  // unlink scripts
207  UnLink();
208 
209  // unlink defs
210  if (rDefs) rDefs->ResetIncludeDependencies();
211 
212  // re-link
213  Link(rDefs);
214 
215  // display state
216  LogF("C4AulScriptEngine linked - %d line%s, %d warning%s, %d error%s",
217  lineCnt, (lineCnt != 1 ? "s" : ""), warnCnt, (warnCnt != 1 ? "s" : ""), errCnt, (errCnt != 1 ? "s" : ""));
218 
219  // adjust global effects
222 }
223 
224 bool C4AulScriptEngine::ReloadScript(const char *szScript, const char *szLanguage)
225 {
226  C4ScriptHost * s;
227  for (s = Child0; s; s = s->Next)
228  if (s->ReloadScript(szScript, szLanguage))
229  break;
230  return !!s;
231 }
232 
#define s
C4AulScriptEngine ScriptEngine
Definition: C4Globals.cpp:43
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:262
C4GameScriptHost GameScript
@ ASS_PREPARSED
Definition: C4ScriptHost.h:34
@ ASS_LINKED
Definition: C4ScriptHost.h:35
@ P_Prototype
C4Value C4VPropList(C4PropList *p)
Definition: C4Value.h:242
virtual void OnError(const char *msg)=0
const char * what() const noexcept override
Definition: C4Aul.cpp:59
C4AulErrorHandler * GetErrorHandler() const
Definition: C4Aul.h:173
bool ReloadScript(const char *szScript, const char *szLanguage)
Definition: C4AulLink.cpp:224
C4PropListStatic * GetPropList()
Definition: C4Aul.h:151
C4ValueMapNames GlobalNamedNames
Definition: C4Aul.h:134
std::vector< C4Value > OwnedPropLists
Definition: C4Aul.h:126
C4ScriptHost * Child0
Definition: C4Aul.h:121
C4Effect * pGlobalEffects
Definition: C4Aul.h:144
C4AulErrorHandler * ErrorHandler
Definition: C4Aul.h:128
C4ValueMapData GlobalNamed
Definition: C4Aul.h:135
void Link(C4DefList *rDefs)
Definition: C4AulLink.cpp:165
void ReLink(C4DefList *rDefs)
Definition: C4AulLink.cpp:204
Definition: C4Def.h:99
C4DefScriptHost Script
Definition: C4Def.h:181
int32_t GetDefCount()
void SortByPriority()
Definition: stub-handle.cpp:76
C4Def * GetDef(int32_t Index)
void ResetIncludeDependencies()
Definition: stub-handle.cpp:78
void CallEveryDefinition()
Definition: stub-handle.cpp:77
C4Def * GetByName(const StdStrBuf &)
void ReAssignAllCallbackFunctions()
Definition: C4Effect.h:129
C4Effect * pScenarioEffects
Definition: C4ScriptHost.h:166
void ThawRecursively()
Definition: C4PropList.cpp:259
C4PropListStatic * FreezeAndMakeStaticRecursively(std::vector< C4Value > *prop_lists, const C4PropListStatic *parent=nullptr, C4String *key=nullptr)
Definition: C4PropList.cpp:279
void SetProperty(C4PropertyName k, const C4Value &to)
Definition: C4PropList.h:124
void DoAppend(C4Def *def)
Definition: C4AulLink.cpp:28
void DeleteOwnedPropLists()
bool ResolveIncludes(C4DefList *rDefs)
Definition: C4AulLink.cpp:83
C4AulScriptEngine * Engine
Definition: C4ScriptHost.h:77
C4AulScriptState State
Definition: C4ScriptHost.h:94
virtual void UnLink()
Definition: C4AulLink.cpp:130
bool IncludesResolved
Definition: C4ScriptHost.h:89
std::list< StdCopyStrBuf > Appends
Definition: C4ScriptHost.h:81
std::list< StdCopyStrBuf > Includes
Definition: C4ScriptHost.h:80
bool ResolveAppends(C4DefList *rDefs)
Definition: C4AulLink.cpp:46
virtual C4PropListStatic * GetPropList()
Definition: C4ScriptHost.h:51
std::deque< C4ScriptHost * > SourceScripts
Definition: C4ScriptHost.h:57
void Warn(const char *pMsg,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: C4AulParse.cpp:124
void SetNameList(C4ValueMapNames *pnNames)
Definition: C4ValueMap.cpp:78