openclonk/src/script/C4AulLink.cpp

239 lines
6.0 KiB
C++
Raw Normal View History

2009-05-08 13:28:41 +00:00
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2009-2013, The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
2009-05-08 13:28:41 +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
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
2009-05-08 13:28:41 +00:00
*/
// links aul scripts; i.e. resolves includes & appends, etc
#include <C4Include.h>
#include <C4Aul.h>
#include <C4Def.h>
#include <C4DefList.h>
2009-06-05 18:46:03 +00:00
#include <C4Material.h>
2009-05-08 13:28:41 +00:00
#include <C4Game.h>
#include <C4GameObjects.h>
2009-05-08 13:28:41 +00:00
bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
{
2012-06-15 16:16:49 +00:00
return false;
}
bool C4AulScript::ResolveAppends(C4DefList *rDefs)
{
2012-06-15 16:16:49 +00:00
return false;
}
2009-05-08 13:28:41 +00:00
// ResolveAppends and ResolveIncludes must be called both
// for each script. ResolveAppends has to be called first!
bool C4ScriptHost::ResolveAppends(C4DefList *rDefs)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// resolve local appends
if (State != ASS_PREPARSED) return false;
for (std::list<StdCopyStrBuf>::iterator a = Appends.begin(); a != Appends.end(); ++a)
2010-03-28 18:58:01 +00:00
{
if (*a != "*")
2009-05-08 13:28:41 +00:00
{
C4Def *Def = rDefs->GetByName(*a);
2009-05-08 13:28:41 +00:00
if (Def)
{
if (std::find(Def->Script.SourceScripts.begin(), Def->Script.SourceScripts.end(), GetScriptHost()) == Def->Script.SourceScripts.end())
Def->Script.SourceScripts.push_back(GetScriptHost());
}
2009-05-08 13:28:41 +00:00
else
{
// save id in buffer because AulWarn will use the buffer of C4IdText
// to get the id of the object in which the error occurs...
// (stupid static buffers...)
Warn("#appendto %s not found", a->getData());
2009-05-08 13:28:41 +00:00
}
}
else
{
// append to all defs
2010-03-28 18:58:01 +00:00
for (int i = 0; i < rDefs->GetDefCount(); i++)
2009-05-08 13:28:41 +00:00
{
C4Def *pDef = rDefs->GetDef(i);
2010-03-28 18:58:01 +00:00
if (!pDef) break;
if (pDef == GetPropList()) continue;
2009-05-08 13:28:41 +00:00
// append
if (std::find(pDef->Script.SourceScripts.begin(), pDef->Script.SourceScripts.end(), GetScriptHost()) == pDef->Script.SourceScripts.end())
pDef->Script.SourceScripts.push_back(GetScriptHost());
2009-05-08 13:28:41 +00:00
}
}
}
2010-03-28 18:58:01 +00:00
return true;
}
2009-05-08 13:28:41 +00:00
bool C4ScriptHost::ResolveIncludes(C4DefList *rDefs)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Had been preparsed?
if (State != ASS_PREPARSED) return false;
2009-05-08 13:28:41 +00:00
// has already been resolved?
2010-03-28 18:58:01 +00:00
if (IncludesResolved) return true;
2009-05-08 13:28:41 +00:00
// catch circular includes
if (Resolving)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4AulParseError(this, "Circular include chain detected - ignoring all includes!").show();
IncludesResolved = true;
State = ASS_LINKED;
return false;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
Resolving=true;
// append all includes to local script
for (std::list<StdCopyStrBuf>::reverse_iterator i = Includes.rbegin(); i != Includes.rend(); ++i)
2010-03-28 18:58:01 +00:00
{
C4Def *Def = rDefs->GetByName(*i);
2009-05-08 13:28:41 +00:00
if (Def)
{
// resolve #includes in included script first (#include-chains :( )
if (!Def->Script.IncludesResolved)
2009-05-08 13:28:41 +00:00
if (!Def->Script.ResolveIncludes(rDefs))
continue; // skip this #include
for (std::list<C4ScriptHost *>::reverse_iterator s = Def->Script.SourceScripts.rbegin(); s != Def->Script.SourceScripts.rend(); ++s)
{
if (std::find(GetScriptHost()->SourceScripts.begin(), GetScriptHost()->SourceScripts.end(), *s) == GetScriptHost()->SourceScripts.end())
GetScriptHost()->SourceScripts.push_front(*s);
}
2009-05-08 13:28:41 +00:00
}
else
{
// save id in buffer because AulWarn will use the buffer of C4IdText
// to get the id of the object in which the error occurs...
// (stupid static buffers...)
Warn("#include %s not found", i->getData());
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
IncludesResolved = true;
// includes/appends are resolved now (for this script)
Resolving=false;
State = ASS_LINKED;
return true;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulScript::UnLink()
{
}
void C4ScriptHost::UnLink()
2010-03-28 18:58:01 +00:00
{
2011-10-14 23:38:59 +00:00
C4PropList * p = GetPropList();
if (p)
{
p->C4PropList::Clear();
p->SetProperty(P_Prototype, C4VPropList(Engine->GetPropList()));
}
2009-05-08 13:28:41 +00:00
// includes will have to be re-resolved now
IncludesResolved = false;
if (State > ASS_PREPARSED) State = ASS_PREPARSED;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulScriptEngine::UnLink()
2010-03-28 18:58:01 +00:00
{
warnCnt = errCnt = lineCnt = 0;
// unlink scripts
for (C4AulScript *s = Child0; s; s = s->Next)
s->UnLink();
GetPropList()->Thaw();
if (State > ASS_PREPARSED) State = ASS_PREPARSED;
// Do not clear global variables and constants, because they are registered by the
// preparser or other parts. Note that keeping those fields means that you cannot delete a global
// variable or constant at runtime by removing it from the script.
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4AulScript::ReloadScript(const char *szPath, const char *szLanguage)
2010-03-28 18:58:01 +00:00
{
return false;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulScriptEngine::Link(C4DefList *rDefs)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
try
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// resolve appends
for (C4AulScript *s = Child0; s; s = s->Next)
s->ResolveAppends(rDefs);
2009-05-08 13:28:41 +00:00
// resolve includes
for (C4AulScript *s = Child0; s; s = s->Next)
s->ResolveIncludes(rDefs);
2009-05-08 13:28:41 +00:00
// parse the scripts to byte code
for (C4AulScript *s = Child0; s; s = s->Next)
s->Parse();
2009-05-08 13:28:41 +00:00
// engine is always parsed (for global funcs)
State = ASS_PARSED;
// update material pointers
2009-06-05 18:46:03 +00:00
::MaterialMap.UpdateScriptPointers();
2009-05-08 13:28:41 +00:00
rDefs->CallEveryDefinition();
// Done modifying the proplists now
for (C4AulScript *s = Child0; s; s = s->Next)
s->GetPropList()->Freeze();
GetPropList()->Freeze();
2010-03-28 18:58:01 +00:00
}
catch (C4AulError &err)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// error??! show it!
err.show();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4AulScriptEngine::ReLink(C4DefList *rDefs)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// unlink scripts
UnLink();
// unlink defs
if (rDefs) rDefs->ResetIncludeDependencies();
// re-link
Link(rDefs);
// display state
LogF("C4AulScriptEngine linked - %d line%s, %d warning%s, %d error%s",
lineCnt, (lineCnt != 1 ? "s" : ""), warnCnt, (warnCnt != 1 ? "s" : ""), errCnt, (errCnt != 1 ? "s" : ""));
2009-05-08 13:28:41 +00:00
// update effect pointers
::Objects.UpdateScriptPointers();
2009-05-08 13:28:41 +00:00
// update material pointers
2009-06-05 18:46:03 +00:00
::MaterialMap.UpdateScriptPointers();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4AulScriptEngine::ReloadScript(const char *szScript, C4DefList *pDefs, const char *szLanguage)
2010-03-28 18:58:01 +00:00
{
C4AulScript * s;
for (s = Child0; s; s = s->Next)
if (s->ReloadScript(szScript, szLanguage))
break;
if (!s)
return false;
// relink
ReLink(pDefs);
// ok
return true;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00