2010-07-02 14:18:25 +00:00
|
|
|
|
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>
|
2010-07-02 14:18:25 +00:00
|
|
|
#include <iostream>
|
2010-07-02 15:21:27 +00:00
|
|
|
#include <sstream>
|
|
|
|
#include <exception>
|
|
|
|
|
|
|
|
#include <components/esm/loadscpt.hpp>
|
|
|
|
#include <components/esm_store/store.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>
|
2010-07-02 16:08:00 +00:00
|
|
|
|
2010-07-18 17:54:56 +00:00
|
|
|
#include "extensions.hpp"
|
2010-07-03 18:35:59 +00:00
|
|
|
|
2010-07-02 14:18:25 +00:00
|
|
|
namespace MWScript
|
|
|
|
{
|
2010-07-02 15:21:27 +00:00
|
|
|
ScriptManager::ScriptManager (const ESMS::ESMStore& store, bool verbose,
|
|
|
|
Compiler::Context& compilerContext)
|
|
|
|
: mErrorHandler (std::cerr), mStore (store), mVerbose (verbose),
|
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)
|
2010-07-02 14:18:25 +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();
|
|
|
|
|
|
|
|
bool Success = true;
|
|
|
|
|
|
|
|
if (const ESM::Script *script = mStore.scripts.find (name))
|
2010-08-29 21:40:59 +00:00
|
|
|
{
|
2010-07-02 15:21:27 +00:00
|
|
|
if (mVerbose)
|
|
|
|
std::cout << "compiling script: " << name << std::endl;
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
try
|
2010-08-29 21:40:59 +00:00
|
|
|
{
|
2010-07-02 15:21:27 +00:00
|
|
|
std::istringstream input (script->scriptText);
|
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)
|
|
|
|
{
|
|
|
|
std::cerr << "An exception has been thrown: " << error.what() << std::endl;
|
2010-07-02 15:21:27 +00:00
|
|
|
Success = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Success && mVerbose)
|
|
|
|
{
|
|
|
|
std::cerr
|
|
|
|
<< "compiling failed: " << name << std::endl
|
|
|
|
<< script->scriptText
|
|
|
|
<< std::endl << std::endl;
|
|
|
|
}
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
if (Success)
|
|
|
|
{
|
|
|
|
std::vector<Interpreter::Type_Code> code;
|
|
|
|
mParser.getCode (code);
|
2012-03-05 15:56:14 +00:00
|
|
|
mScripts.insert (std::make_pair (name, std::make_pair (code, mParser.getLocals())));
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-02 15:21:27 +00:00
|
|
|
// TODO sanity check on generated locals
|
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
|
|
|
}
|
|
|
|
|
2010-07-02 16:08:00 +00:00
|
|
|
void 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;
|
2012-03-05 15:56:14 +00:00
|
|
|
mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals())));
|
2010-07-02 15:21:27 +00:00
|
|
|
return;
|
|
|
|
}
|
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
|
2012-03-05 15:56:14 +00:00
|
|
|
if (!iter->second.first.empty())
|
2010-07-02 16:08:00 +00:00
|
|
|
try
|
|
|
|
{
|
2011-05-18 14:01:19 +00:00
|
|
|
if (!mOpcodesInstalled)
|
|
|
|
{
|
|
|
|
installOpcodes (mInterpreter);
|
|
|
|
mOpcodesInstalled = true;
|
|
|
|
}
|
|
|
|
|
2012-03-05 15:56:14 +00:00
|
|
|
mInterpreter.run (&iter->second.first[0], iter->second.first.size(), interpreterContext);
|
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
|
|
|
{
|
|
|
|
std::cerr << "exeution of script " << name << " failed." << std::endl;
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2010-07-03 18:35:59 +00:00
|
|
|
if (mVerbose)
|
|
|
|
std::cerr << "(" << e.what() << ")" << std::endl;
|
2010-08-29 21:40:59 +00:00
|
|
|
|
2012-03-05 15:56:14 +00:00
|
|
|
iter->second.first.clear(); // don't execute again.
|
2010-07-02 16:08:00 +00:00
|
|
|
}
|
2010-07-02 14:18:25 +00:00
|
|
|
}
|
2011-10-09 10:05:13 +00:00
|
|
|
|
|
|
|
std::pair<int, int> ScriptManager::compileAll()
|
|
|
|
{
|
|
|
|
typedef ESMS::ScriptListT<ESM::Script>::MapType Container;
|
|
|
|
|
|
|
|
const Container& scripts = mStore.scripts.list;
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
int success = 0;
|
|
|
|
|
|
|
|
for (Container::const_iterator iter (scripts.begin()); iter!=scripts.end(); ++iter, ++count)
|
|
|
|
if (compile (iter->first))
|
|
|
|
++success;
|
|
|
|
|
|
|
|
return std::make_pair (count, success);
|
|
|
|
}
|
2012-03-05 15:56:14 +00:00
|
|
|
|
|
|
|
Compiler::Locals& ScriptManager::getLocals (const std::string& name)
|
|
|
|
{
|
|
|
|
ScriptCollection::iterator iter = mScripts.find (name);
|
|
|
|
|
|
|
|
if (iter==mScripts.end())
|
|
|
|
{
|
|
|
|
if (!compile (name))
|
|
|
|
{
|
2012-06-16 11:06:23 +00:00
|
|
|
/// \todo Handle case of cyclic member variable access. Currently this could look up
|
|
|
|
/// the whole application in an endless recursion.
|
|
|
|
|
2012-03-05 15:56:14 +00:00
|
|
|
// failed -> ignore script from now on.
|
|
|
|
std::vector<Interpreter::Type_Code> empty;
|
|
|
|
mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals())));
|
|
|
|
throw std::runtime_error ("failed to compile script " + name);
|
|
|
|
}
|
|
|
|
|
|
|
|
iter = mScripts.find (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return iter->second.second;
|
|
|
|
}
|
2012-04-23 09:15:47 +00:00
|
|
|
|
|
|
|
GlobalScripts& ScriptManager::getGlobalScripts()
|
|
|
|
{
|
|
|
|
return mGlobalScripts;
|
|
|
|
}
|
2012-06-07 09:59:45 +00:00
|
|
|
|
|
|
|
int ScriptManager::getLocalIndex (const std::string& scriptId, const std::string& variable,
|
|
|
|
char type)
|
|
|
|
{
|
|
|
|
const ESM::Script *script = mStore.scripts.find (scriptId);
|
|
|
|
|
|
|
|
int offset = 0;
|
|
|
|
int size = 0;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case 's':
|
|
|
|
|
|
|
|
offset = 0;
|
|
|
|
size = script->data.numShorts;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'l':
|
|
|
|
|
|
|
|
offset = script->data.numShorts;
|
|
|
|
size = script->data.numLongs;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
|
|
|
|
offset = script->data.numShorts+script->data.numLongs;
|
|
|
|
size = script->data.numFloats;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
throw std::runtime_error ("invalid variable type");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i=0; i<size; ++i)
|
|
|
|
if (script->varNames.at (i+offset)==variable)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId);
|
|
|
|
}
|
2010-07-02 14:18:25 +00:00
|
|
|
}
|