openclonk/src/script/C4AulLink.cpp

319 lines
7.8 KiB
C++
Raw Normal View History

2009-05-08 13:28:41 +00:00
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2001, 2006-2007 Sven Eberhardt
* Copyright (c) 2001-2002, 2004, 2007 Peter Wortmann
* 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>
#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!
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
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
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;
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;
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
ClearCode();
2009-05-08 13:28:41 +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
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
bool C4AulScript::ReloadScript(const char *szPath, const char *szLanguage)
2010-03-28 18:58:01 +00:00
{
// call for childs
2009-05-08 13:28:41 +00:00
for (C4AulScript *s = Child0; s; s = s->Next)
if (s->ReloadScript(szPath, szLanguage))
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
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
// 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
::GameScript.UnLink();
2009-05-08 13:28:41 +00:00
// re-link
Link(rDefs);
// 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
{
// reload
if (!C4AulScript::ReloadScript(szScript, szLanguage))
return false;
// relink
ReLink(pDefs);
// ok
return true;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00