2009-05-08 13:28:41 +00:00
|
|
|
/*
|
|
|
|
* OpenClonk, http://www.openclonk.org
|
|
|
|
*
|
2009-06-05 13:41:20 +00:00
|
|
|
* Copyright (c) 2001, 2006-2007 Sven Eberhardt
|
|
|
|
* Copyright (c) 2001-2002, 2004, 2007 Peter Wortmann
|
2010-12-23 00:01:24 +00:00
|
|
|
* Copyright (c) 2006-2009 Günther Brammer
|
2009-05-08 13:28:41 +00:00
|
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
|
|
|
*
|
|
|
|
* Portions might be copyrighted by other authors who have contributed
|
|
|
|
* to OpenClonk.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
* See isc_license.txt for full license and disclaimer.
|
|
|
|
*
|
|
|
|
* "Clonk" is a registered trademark of Matthes Bender.
|
|
|
|
* See clonk_trademark_license.txt for full license.
|
|
|
|
*/
|
|
|
|
// links aul scripts; i.e. resolves includes & appends, etc
|
|
|
|
|
|
|
|
#include <C4Include.h>
|
|
|
|
#include <C4Aul.h>
|
|
|
|
|
|
|
|
#include <C4Def.h>
|
2009-06-05 18:46:03 +00:00
|
|
|
#include <C4Material.h>
|
2009-05-08 13:28:41 +00:00
|
|
|
#include <C4Game.h>
|
2009-06-15 21:47:26 +00:00
|
|
|
#include <C4GameObjects.h>
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// ResolveAppends and ResolveIncludes must be called both
|
|
|
|
// for each script. ResolveAppends has to be called first!
|
2009-08-15 18:50:32 +00:00
|
|
|
bool C4AulScript::ResolveAppends(C4DefList *rDefs)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// resolve children appends
|
|
|
|
for (C4AulScript *s = Child0; s; s = s->Next) s->ResolveAppends(rDefs);
|
|
|
|
// resolve local appends
|
2009-08-15 18:50:32 +00:00
|
|
|
if (State != ASS_PREPARSED) return false;
|
2011-02-25 23:48:19 +00:00
|
|
|
for (std::list<C4ID>::iterator a = Appends.begin(); a != Appends.end(); ++a)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2011-02-25 23:48:19 +00:00
|
|
|
if (*a)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
2011-02-25 23:48:19 +00:00
|
|
|
C4Def *Def = rDefs->ID2Def(*a);
|
2009-05-08 13:28:41 +00:00
|
|
|
if (Def)
|
|
|
|
AppendTo(Def->Script, true);
|
|
|
|
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...)
|
2011-02-25 23:48:19 +00:00
|
|
|
Warn("script to #appendto not found: ", a->ToString());
|
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 == Def) continue;
|
2009-05-08 13:28:41 +00:00
|
|
|
// append
|
|
|
|
AppendTo(pDef->Script, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
return true;
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-08-15 18:50:32 +00:00
|
|
|
bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// resolve children includes
|
|
|
|
for (C4AulScript *s = Child0; s; s = s->Next) s->ResolveIncludes(rDefs);
|
|
|
|
// Had been preparsed?
|
2010-03-28 18:58:01 +00:00
|
|
|
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;
|
2009-08-15 18:50:32 +00:00
|
|
|
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
|
2011-02-25 23:48:19 +00:00
|
|
|
for (std::list<C4ID>::iterator i = Includes.begin(); i != Includes.end(); ++i)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2011-02-25 23:48:19 +00:00
|
|
|
C4Def *Def = rDefs->ID2Def(*i);
|
2009-05-08 13:28:41 +00:00
|
|
|
if (Def)
|
|
|
|
{
|
|
|
|
// resolve #includes in included script first (#include-chains :( )
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!((C4AulScript &)Def->Script).IncludesResolved)
|
2009-05-08 13:28:41 +00:00
|
|
|
if (!Def->Script.ResolveIncludes(rDefs))
|
|
|
|
continue; // skip this #include
|
|
|
|
|
|
|
|
Def->Script.AppendTo(*this, false);
|
|
|
|
}
|
|
|
|
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...)
|
2011-02-25 23:48:19 +00:00
|
|
|
Warn("script to #include not found: ", i->ToString());
|
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;
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4AulScript::AppendTo(C4AulScript &Scr, bool bHighPrio)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// definition appends
|
|
|
|
if (Def && Scr.Def) Scr.Def->IncludeDefinition(Def);
|
|
|
|
// append all funcs
|
|
|
|
// (in reverse order if inserted at begin of list)
|
|
|
|
C4AulScriptFunc *sf;
|
|
|
|
for (C4AulFunc *f = bHighPrio ? Func0 : FuncL; f; f = bHighPrio ? f->Next : f->Prev)
|
|
|
|
// script funcs only
|
2010-01-25 04:00:59 +00:00
|
|
|
if ((sf = f->SFunc()))
|
2009-05-08 13:28:41 +00:00
|
|
|
// no need to append global funcs
|
|
|
|
if (sf->Access != AA_GLOBAL)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// append: create copy
|
|
|
|
// (if high priority, insert at end, otherwise at the beginning)
|
|
|
|
C4AulScriptFunc *sfc = new C4AulScriptFunc(&Scr, sf->Name, bHighPrio);
|
|
|
|
sfc->CopyBody(*sf);
|
|
|
|
// link the copy to a local function
|
|
|
|
if (sf->LinkedTo)
|
|
|
|
{
|
|
|
|
sfc->LinkedTo = sf->LinkedTo;
|
|
|
|
sf->LinkedTo = sfc;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sfc->LinkedTo = sf;
|
|
|
|
sf->LinkedTo = sfc;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// mark as linked
|
|
|
|
// increase code size needed
|
|
|
|
// append all local vars (if any existing)
|
|
|
|
assert(!Def || this == &Def->Script);
|
|
|
|
assert(!Scr.Def || &Scr.Def->Script == &Scr);
|
2010-03-28 18:58:01 +00:00
|
|
|
if (LocalNamed.iSize == 0)
|
2009-05-08 13:28:41 +00:00
|
|
|
return;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!Scr.Def)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
Warn("could not append local variables to global script!", "");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// copy local var definitions
|
2010-03-28 18:58:01 +00:00
|
|
|
for (int ivar = 0; ivar < LocalNamed.iSize; ivar ++)
|
2009-05-08 13:28:41 +00:00
|
|
|
Scr.LocalNamed.AddName(LocalNamed.pNames[ivar]);
|
|
|
|
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4AulScript::UnLink()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// unlink children
|
|
|
|
for (C4AulScript *s = Child0; s; s = s->Next) s->UnLink();
|
|
|
|
|
|
|
|
// do not unlink temporary (e.g., DirectExec-script in ReloadDef)
|
|
|
|
if (Temporary) return;
|
|
|
|
|
|
|
|
// check if byte code needs to be freed
|
2010-03-18 21:10:32 +00:00
|
|
|
ClearCode();
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-09-22 01:33:57 +00:00
|
|
|
if (Def) Def->C4PropList::Clear();
|
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
// delete included/appended functions
|
|
|
|
C4AulFunc* pFunc = Func0;
|
2010-03-28 18:58:01 +00:00
|
|
|
while (pFunc)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
C4AulFunc* pNextFunc = pFunc->Next;
|
|
|
|
|
|
|
|
// clear stuff that's set in AfterLink
|
|
|
|
pFunc->UnLink();
|
|
|
|
|
|
|
|
if (pFunc->SFunc()) if (pFunc->Owner != pFunc->SFunc()->pOrgScript)
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!pFunc->LinkedTo || pFunc->LinkedTo->SFunc()) // do not kill global links; those will be deleted if corresponding sfunc in script is deleted
|
|
|
|
delete pFunc;
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
pFunc = pNextFunc;
|
|
|
|
}
|
|
|
|
// 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 C4AulScriptFunc::UnLink()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
OwnerOverloaded = NULL;
|
|
|
|
|
|
|
|
// clear desc information, ParseDesc will set these later on
|
2010-01-25 03:14:52 +00:00
|
|
|
idImage = C4ID::None;
|
2009-05-08 13:28:41 +00:00
|
|
|
iImagePhase = 0;
|
|
|
|
Condition = NULL;
|
|
|
|
ControlMethod = C4AUL_ControlMethod_All;
|
|
|
|
|
|
|
|
C4AulFunc::UnLink();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4AulScript::AfterLink()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// call for childs
|
|
|
|
for (C4AulScript *s = Child0; s; s = s->Next) s->AfterLink();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2011-02-06 20:37:19 +00:00
|
|
|
bool C4AulScript::ReloadScript(const char *szPath, const char *szLanguage)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
// call for childs
|
2009-05-08 13:28:41 +00:00
|
|
|
for (C4AulScript *s = Child0; s; s = s->Next)
|
2011-02-06 20:37:19 +00:00
|
|
|
if (s->ReloadScript(szPath, szLanguage))
|
2010-03-27 16:05:02 +00:00
|
|
|
return true;
|
|
|
|
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
|
|
|
|
ResolveAppends(rDefs);
|
|
|
|
|
|
|
|
// resolve includes
|
|
|
|
ResolveIncludes(rDefs);
|
|
|
|
|
|
|
|
// parse script funcs descs
|
|
|
|
ParseDescs();
|
|
|
|
|
|
|
|
// parse the scripts to byte code
|
|
|
|
Parse();
|
|
|
|
|
|
|
|
// engine is always parsed (for global funcs)
|
|
|
|
State = ASS_PARSED;
|
|
|
|
|
|
|
|
// get common funcs
|
|
|
|
AfterLink();
|
|
|
|
|
|
|
|
// non-strict scripts?
|
|
|
|
if (nonStrictCnt)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// warn!
|
|
|
|
// find first non-#strict script
|
|
|
|
C4AulScript *pNonStrictScr=FindFirstNonStrictScript();
|
|
|
|
if (pNonStrictScr)
|
|
|
|
pNonStrictScr->Warn("using non-#strict syntax!", NULL);
|
|
|
|
else
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
Warn("non-#strict script detected, but def is lost", NULL);
|
|
|
|
Warn("please contact piracy@treffpunktclonk.net for further instructions", NULL);
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
Warn(FormatString("%d script%s use non-#strict syntax!", nonStrictCnt, (nonStrictCnt != 1 ? "s" : "")).getData(), NULL);
|
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// update material pointers
|
2009-06-05 18:46:03 +00:00
|
|
|
::MaterialMap.UpdateScriptPointers();
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-05-19 22:30:49 +00:00
|
|
|
rDefs->CallEveryDefinition();
|
2009-05-08 13:28:41 +00:00
|
|
|
// display state
|
2009-05-11 13:09:53 +00:00
|
|
|
LogF("C4AulScriptEngine linked - %d line%s, %d warning%s, %d error%s",
|
2010-03-28 18:58:01 +00:00
|
|
|
lineCnt, (lineCnt != 1 ? "s" : ""), warnCnt, (warnCnt != 1 ? "s" : ""), errCnt, (errCnt != 1 ? "s" : ""));
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-03-27 16:05:02 +00:00
|
|
|
// reset counters
|
|
|
|
warnCnt = errCnt = nonStrictCnt = lineCnt = 0;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +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();
|
|
|
|
delete err;
|
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();
|
|
|
|
|
|
|
|
// clear string table
|
2011-01-08 16:04:20 +00:00
|
|
|
::GameScript.UnLink();
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// re-link
|
|
|
|
Link(rDefs);
|
|
|
|
|
|
|
|
// update effect pointers
|
2009-06-15 21:47:26 +00:00
|
|
|
::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
|
|
|
|
2011-02-06 20:37:19 +00:00
|
|
|
bool C4AulScriptEngine::ReloadScript(const char *szScript, C4DefList *pDefs, const char *szLanguage)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2010-03-27 16:05:02 +00:00
|
|
|
// reload
|
2011-02-06 20:37:19 +00:00
|
|
|
if (!C4AulScript::ReloadScript(szScript, szLanguage))
|
2010-03-27 16:05:02 +00:00
|
|
|
return false;
|
|
|
|
// relink
|
|
|
|
ReLink(pDefs);
|
|
|
|
// ok
|
|
|
|
return true;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|