2012-08-08 13:18:55 +00:00
|
|
|
#include "scriptmanagerimp.hpp"
|
2010-07-02 14:18:25 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
#include <cassert>
|
|
|
|
#include <sstream>
|
|
|
|
#include <exception>
|
2014-07-21 07:34:10 +00:00
|
|
|
#include <algorithm>
|
2010-07-02 15:21:27 +00:00
|
|
|
|
2018-08-14 19:05:43 +00:00
|
|
|
#include <components/debug/debuglog.hpp>
|
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
#include <components/esm/loadscpt.hpp>
|
2014-02-11 12:56:56 +00:00
|
|
|
|
|
|
|
#include <components/misc/stringops.hpp>
|
2010-07-02 14:18:25 +00:00
|
|
|
|
2010-07-02 16:08:00 +00:00
|
|
|
#include <components/compiler/scanner.hpp>
|
2010-07-03 10:12:13 +00:00
|
|
|
#include <components/compiler/context.hpp>
|
2012-06-16 09:52:35 +00:00
|
|
|
#include <components/compiler/exception.hpp>
|
2014-02-14 10:15:16 +00:00
|
|
|
#include <components/compiler/quickfileparser.hpp>
|
2010-07-02 16:08:00 +00:00
|
|
|
|
2014-02-11 12:56:56 +00:00
|
|
|
#include "../mwworld/esmstore.hpp"
|
|
|
|
|
2010-07-18 17:54:56 +00:00
|
|
|
#include "extensions.hpp"
|
2020-05-10 12:57:06 +00:00
|
|
|
#include "interpretercontext.hpp"
|
2010-07-03 18:35:59 +00:00
|
|
|
|
2010-07-02 14:18:25 +00:00
|
|
|
namespace MWScript
|
|
|
|
{
|
2017-02-20 20:09:15 +00:00
|
|
|
ScriptManager::ScriptManager (const MWWorld::ESMStore& store,
|
2014-07-21 07:34:10 +00:00
|
|
|
Compiler::Context& compilerContext, int warningsMode,
|
|
|
|
const std::vector<std::string>& scriptBlacklist)
|
2019-04-21 10:12:32 +00:00
|
|
|
: mErrorHandler(), mStore (store),
|
2011-05-18 14:01:19 +00:00
|
|
|
mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext),
|
2012-08-08 13:18:55 +00:00
|
|
|
mOpcodesInstalled (false), mGlobalScripts (store)
|
2014-02-02 13:09:59 +00:00
|
|
|
{
|
|
|
|
mErrorHandler.setWarningsMode (warningsMode);
|
2014-07-21 07:34:10 +00:00
|
|
|
|
|
|
|
mScriptBlacklist.resize (scriptBlacklist.size());
|
|
|
|
|
|
|
|
std::transform (scriptBlacklist.begin(), scriptBlacklist.end(),
|
|
|
|
mScriptBlacklist.begin(), Misc::StringUtils::lowerCase);
|
|
|
|
std::sort (mScriptBlacklist.begin(), mScriptBlacklist.end());
|
2014-02-02 13:09:59 +00:00
|
|
|
}
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
bool ScriptManager::compile (const std::string& name)
|
|
|
|
{
|
|
|
|
mParser.reset();
|
|
|
|
mErrorHandler.reset();
|
|
|
|
|
2012-11-06 08:36:21 +00:00
|
|
|
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
|
2010-08-29 21:40:59 +00:00
|
|
|
{
|
2017-02-20 20:09:15 +00:00
|
|
|
mErrorHandler.setContext(name);
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2014-09-26 15:12:48 +00:00
|
|
|
bool Success = true;
|
2010-07-02 15:21:27 +00:00
|
|
|
try
|
2010-08-29 21:40:59 +00:00
|
|
|
{
|
2012-09-17 07:37:50 +00:00
|
|
|
std::istringstream input (script->mScriptText);
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-03 10:12:13 +00:00
|
|
|
Compiler::Scanner scanner (mErrorHandler, input, mCompilerContext.getExtensions());
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
scanner.scan (mParser);
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
if (!mErrorHandler.isGood())
|
|
|
|
Success = false;
|
|
|
|
}
|
2012-06-16 09:52:35 +00:00
|
|
|
catch (const Compiler::SourceException&)
|
2010-07-02 15:21:27 +00:00
|
|
|
{
|
2012-06-16 09:52:35 +00:00
|
|
|
// error has already been reported via error handler
|
2012-06-16 11:06:23 +00:00
|
|
|
Success = false;
|
2012-06-16 09:52:35 +00:00
|
|
|
}
|
|
|
|
catch (const std::exception& error)
|
|
|
|
{
|
2018-08-14 19:05:43 +00:00
|
|
|
Log(Debug::Error) << "Error: An exception has been thrown: " << error.what();
|
2010-07-02 15:21:27 +00:00
|
|
|
Success = false;
|
|
|
|
}
|
|
|
|
|
2014-06-20 21:56:21 +00:00
|
|
|
if (!Success)
|
2010-07-02 15:21:27 +00:00
|
|
|
{
|
2019-04-21 10:12:32 +00:00
|
|
|
Log(Debug::Error) << "Error: script compiling failed: " << name;
|
2010-07-02 15:21:27 +00:00
|
|
|
}
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
if (Success)
|
|
|
|
{
|
|
|
|
std::vector<Interpreter::Type_Code> code;
|
2020-07-14 06:53:01 +00:00
|
|
|
mParser.getCode(code);
|
|
|
|
mScripts.emplace(name, CompiledScript(code, mParser.getLocals()));
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2010-08-29 21:40:59 +00:00
|
|
|
|
|
|
|
return false;
|
2010-07-02 15:21:27 +00:00
|
|
|
}
|
|
|
|
|
2020-05-10 12:57:06 +00:00
|
|
|
bool ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext)
|
2010-07-02 14:18:25 +00:00
|
|
|
{
|
2010-07-02 15:21:27 +00:00
|
|
|
// compile script
|
2012-03-05 15:56:14 +00:00
|
|
|
ScriptCollection::iterator iter = mScripts.find (name);
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
if (iter==mScripts.end())
|
|
|
|
{
|
|
|
|
if (!compile (name))
|
|
|
|
{
|
|
|
|
// failed -> ignore script from now on.
|
|
|
|
std::vector<Interpreter::Type_Code> empty;
|
2020-07-14 06:53:01 +00:00
|
|
|
mScripts.emplace(name, CompiledScript(empty, Compiler::Locals()));
|
2020-05-10 12:57:06 +00:00
|
|
|
return false;
|
2010-07-02 15:21:27 +00:00
|
|
|
}
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
iter = mScripts.find (name);
|
|
|
|
assert (iter!=mScripts.end());
|
|
|
|
}
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
// execute script
|
2020-07-14 06:53:01 +00:00
|
|
|
if (!iter->second.mByteCode.empty() && iter->second.mActive)
|
2010-07-02 16:08:00 +00:00
|
|
|
try
|
|
|
|
{
|
2011-05-18 14:01:19 +00:00
|
|
|
if (!mOpcodesInstalled)
|
|
|
|
{
|
|
|
|
installOpcodes (mInterpreter);
|
|
|
|
mOpcodesInstalled = true;
|
|
|
|
}
|
|
|
|
|
2020-07-14 06:53:01 +00:00
|
|
|
mInterpreter.run (&iter->second.mByteCode[0], iter->second.mByteCode.size(), interpreterContext);
|
2020-05-10 12:57:06 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
catch (const MissingImplicitRefError& e)
|
|
|
|
{
|
|
|
|
Log(Debug::Error) << "Execution of script " << name << " failed: " << e.what();
|
2010-07-02 16:08:00 +00:00
|
|
|
}
|
2010-07-03 18:35:59 +00:00
|
|
|
catch (const std::exception& e)
|
2010-07-02 16:08:00 +00:00
|
|
|
{
|
2020-05-10 12:57:06 +00:00
|
|
|
Log(Debug::Error) << "Execution of script " << name << " failed: " << e.what();
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2020-07-14 06:53:01 +00:00
|
|
|
iter->second.mActive = false; // don't execute again.
|
2010-07-02 16:08:00 +00:00
|
|
|
}
|
2020-05-10 12:57:06 +00:00
|
|
|
return false;
|
2010-07-02 14:18:25 +00:00
|
|
|
}
|
2011-10-09 10:05:13 +00:00
|
|
|
|
2020-07-14 06:53:01 +00:00
|
|
|
void ScriptManager::clear()
|
|
|
|
{
|
|
|
|
for (auto& script : mScripts)
|
|
|
|
{
|
|
|
|
script.second.mActive = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
mGlobalScripts.clear();
|
|
|
|
}
|
|
|
|
|
2011-10-09 10:05:13 +00:00
|
|
|
std::pair<int, int> ScriptManager::compileAll()
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
int success = 0;
|
|
|
|
|
2020-07-30 16:57:25 +00:00
|
|
|
for (auto& script : mStore.get<ESM::Script>())
|
|
|
|
{
|
2014-07-21 07:34:10 +00:00
|
|
|
if (!std::binary_search (mScriptBlacklist.begin(), mScriptBlacklist.end(),
|
2020-07-30 16:57:25 +00:00
|
|
|
Misc::StringUtils::lowerCase(script.mId)))
|
2014-07-21 07:34:10 +00:00
|
|
|
{
|
|
|
|
++count;
|
|
|
|
|
2020-07-30 16:57:25 +00:00
|
|
|
if (compile(script.mId))
|
2014-07-21 07:34:10 +00:00
|
|
|
++success;
|
|
|
|
}
|
2020-07-30 16:57:25 +00:00
|
|
|
}
|
2011-10-09 10:05:13 +00:00
|
|
|
|
|
|
|
return std::make_pair (count, success);
|
|
|
|
}
|
2012-03-05 15:56:14 +00:00
|
|
|
|
2014-07-25 06:12:53 +00:00
|
|
|
const Compiler::Locals& ScriptManager::getLocals (const std::string& name)
|
2012-03-05 15:56:14 +00:00
|
|
|
{
|
2014-02-11 12:56:56 +00:00
|
|
|
std::string name2 = Misc::StringUtils::lowerCase (name);
|
|
|
|
|
2013-02-23 13:40:56 +00:00
|
|
|
{
|
2014-02-11 12:56:56 +00:00
|
|
|
ScriptCollection::iterator iter = mScripts.find (name2);
|
2013-02-23 13:40:56 +00:00
|
|
|
|
|
|
|
if (iter!=mScripts.end())
|
2020-07-14 06:53:01 +00:00
|
|
|
return iter->second.mLocals;
|
2013-02-23 13:40:56 +00:00
|
|
|
}
|
2012-03-05 15:56:14 +00:00
|
|
|
|
|
|
|
{
|
2014-02-11 12:56:56 +00:00
|
|
|
std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name2);
|
2012-06-16 11:06:23 +00:00
|
|
|
|
2013-02-23 13:40:56 +00:00
|
|
|
if (iter!=mOtherLocals.end())
|
|
|
|
return iter->second;
|
|
|
|
}
|
2012-03-05 15:56:14 +00:00
|
|
|
|
2015-09-15 11:58:07 +00:00
|
|
|
if (const ESM::Script *script = mStore.get<ESM::Script>().search (name2))
|
2013-02-23 13:40:56 +00:00
|
|
|
{
|
2014-02-14 10:15:16 +00:00
|
|
|
Compiler::Locals locals;
|
2013-02-23 13:40:56 +00:00
|
|
|
|
2020-04-04 12:09:00 +00:00
|
|
|
const Compiler::ContextOverride override(mErrorHandler, name2 + "[local variables]");
|
2017-02-20 20:09:15 +00:00
|
|
|
|
2014-02-14 10:15:16 +00:00
|
|
|
std::istringstream stream (script->mScriptText);
|
|
|
|
Compiler::QuickFileParser parser (mErrorHandler, mCompilerContext, locals);
|
|
|
|
Compiler::Scanner scanner (mErrorHandler, stream, mCompilerContext.getExtensions());
|
|
|
|
scanner.scan (parser);
|
2013-02-23 19:20:40 +00:00
|
|
|
|
|
|
|
std::map<std::string, Compiler::Locals>::iterator iter =
|
2020-07-30 16:57:25 +00:00
|
|
|
mOtherLocals.emplace(name2, locals).first;
|
2013-02-23 19:20:40 +00:00
|
|
|
|
|
|
|
return iter->second;
|
2012-03-05 15:56:14 +00:00
|
|
|
}
|
|
|
|
|
2013-02-23 13:40:56 +00:00
|
|
|
throw std::logic_error ("script " + name + " does not exist");
|
2012-03-05 15:56:14 +00:00
|
|
|
}
|
2012-04-23 09:15:47 +00:00
|
|
|
|
|
|
|
GlobalScripts& ScriptManager::getGlobalScripts()
|
|
|
|
{
|
|
|
|
return mGlobalScripts;
|
|
|
|
}
|
2010-07-02 14:18:25 +00:00
|
|
|
}
|