mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-11-04 07:26:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			201 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
 | 
						|
#include "scriptmanagerimp.hpp"
 | 
						|
 | 
						|
#include <cassert>
 | 
						|
#include <iostream>
 | 
						|
#include <sstream>
 | 
						|
#include <exception>
 | 
						|
#include <algorithm>
 | 
						|
 | 
						|
#include <components/esm/loadscpt.hpp>
 | 
						|
 | 
						|
#include <components/misc/stringops.hpp>
 | 
						|
 | 
						|
#include <components/compiler/scanner.hpp>
 | 
						|
#include <components/compiler/context.hpp>
 | 
						|
#include <components/compiler/exception.hpp>
 | 
						|
#include <components/compiler/quickfileparser.hpp>
 | 
						|
 | 
						|
#include "../mwworld/esmstore.hpp"
 | 
						|
 | 
						|
#include "extensions.hpp"
 | 
						|
 | 
						|
namespace MWScript
 | 
						|
{
 | 
						|
    ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose,
 | 
						|
        Compiler::Context& compilerContext, int warningsMode,
 | 
						|
        const std::vector<std::string>& scriptBlacklist)
 | 
						|
    : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose),
 | 
						|
      mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext),
 | 
						|
      mOpcodesInstalled (false), mGlobalScripts (store)
 | 
						|
    {
 | 
						|
        mErrorHandler.setWarningsMode (warningsMode);
 | 
						|
 | 
						|
        mScriptBlacklist.resize (scriptBlacklist.size());
 | 
						|
 | 
						|
        std::transform (scriptBlacklist.begin(), scriptBlacklist.end(),
 | 
						|
            mScriptBlacklist.begin(), Misc::StringUtils::lowerCase);
 | 
						|
        std::sort (mScriptBlacklist.begin(), mScriptBlacklist.end());
 | 
						|
    }
 | 
						|
 | 
						|
    bool ScriptManager::compile (const std::string& name)
 | 
						|
    {
 | 
						|
        mParser.reset();
 | 
						|
        mErrorHandler.reset();
 | 
						|
 | 
						|
        if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
 | 
						|
        {
 | 
						|
            if (mVerbose)
 | 
						|
                std::cout << "compiling script: " << name << std::endl;
 | 
						|
 | 
						|
            bool Success = true;
 | 
						|
            try
 | 
						|
            {
 | 
						|
                std::istringstream input (script->mScriptText);
 | 
						|
 | 
						|
                Compiler::Scanner scanner (mErrorHandler, input, mCompilerContext.getExtensions());
 | 
						|
 | 
						|
                scanner.scan (mParser);
 | 
						|
 | 
						|
                if (!mErrorHandler.isGood())
 | 
						|
                    Success = false;
 | 
						|
            }
 | 
						|
            catch (const Compiler::SourceException&)
 | 
						|
            {
 | 
						|
                // error has already been reported via error handler
 | 
						|
                Success = false;
 | 
						|
            }
 | 
						|
            catch (const std::exception& error)
 | 
						|
            {
 | 
						|
                std::cerr << "An exception has been thrown: " << error.what() << std::endl;
 | 
						|
                Success = false;
 | 
						|
            }
 | 
						|
 | 
						|
            if (!Success)
 | 
						|
            {
 | 
						|
                std::cerr
 | 
						|
                    << "compiling failed: " << name << std::endl;
 | 
						|
                if (mVerbose)
 | 
						|
                    std::cerr << script->mScriptText << std::endl << std::endl;
 | 
						|
            }
 | 
						|
 | 
						|
            if (Success)
 | 
						|
            {
 | 
						|
                std::vector<Interpreter::Type_Code> code;
 | 
						|
                mParser.getCode (code);
 | 
						|
                mScripts.insert (std::make_pair (name, std::make_pair (code, mParser.getLocals())));
 | 
						|
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext)
 | 
						|
    {
 | 
						|
        // compile script
 | 
						|
        ScriptCollection::iterator iter = mScripts.find (name);
 | 
						|
 | 
						|
        if (iter==mScripts.end())
 | 
						|
        {
 | 
						|
            if (!compile (name))
 | 
						|
            {
 | 
						|
                // failed -> ignore script from now on.
 | 
						|
                std::vector<Interpreter::Type_Code> empty;
 | 
						|
                mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals())));
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            iter = mScripts.find (name);
 | 
						|
            assert (iter!=mScripts.end());
 | 
						|
        }
 | 
						|
 | 
						|
        // execute script
 | 
						|
        if (!iter->second.first.empty())
 | 
						|
            try
 | 
						|
            {
 | 
						|
                if (!mOpcodesInstalled)
 | 
						|
                {
 | 
						|
                    installOpcodes (mInterpreter);
 | 
						|
                    mOpcodesInstalled = true;
 | 
						|
                }
 | 
						|
 | 
						|
                mInterpreter.run (&iter->second.first[0], iter->second.first.size(), interpreterContext);
 | 
						|
            }
 | 
						|
            catch (const std::exception& e)
 | 
						|
            {
 | 
						|
                std::cerr << "Execution of script " << name << " failed:" << std::endl;
 | 
						|
                std::cerr << e.what() << std::endl;
 | 
						|
 | 
						|
                iter->second.first.clear(); // don't execute again.
 | 
						|
            }
 | 
						|
    }
 | 
						|
 | 
						|
    std::pair<int, int> ScriptManager::compileAll()
 | 
						|
    {
 | 
						|
        int count = 0;
 | 
						|
        int success = 0;
 | 
						|
 | 
						|
        const MWWorld::Store<ESM::Script>& scripts = mStore.get<ESM::Script>();
 | 
						|
 | 
						|
        for (MWWorld::Store<ESM::Script>::iterator iter = scripts.begin();
 | 
						|
            iter != scripts.end(); ++iter)
 | 
						|
            if (!std::binary_search (mScriptBlacklist.begin(), mScriptBlacklist.end(),
 | 
						|
                Misc::StringUtils::lowerCase (iter->mId)))
 | 
						|
            {
 | 
						|
                ++count;
 | 
						|
 | 
						|
                if (compile (iter->mId))
 | 
						|
                    ++success;
 | 
						|
            }
 | 
						|
 | 
						|
        return std::make_pair (count, success);
 | 
						|
    }
 | 
						|
 | 
						|
    const Compiler::Locals& ScriptManager::getLocals (const std::string& name)
 | 
						|
    {
 | 
						|
        std::string name2 = Misc::StringUtils::lowerCase (name);
 | 
						|
 | 
						|
        {
 | 
						|
            ScriptCollection::iterator iter = mScripts.find (name2);
 | 
						|
 | 
						|
            if (iter!=mScripts.end())
 | 
						|
                return iter->second.second;
 | 
						|
        }
 | 
						|
 | 
						|
        {
 | 
						|
            std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name2);
 | 
						|
 | 
						|
            if (iter!=mOtherLocals.end())
 | 
						|
                return iter->second;
 | 
						|
        }
 | 
						|
 | 
						|
        if (const ESM::Script *script = mStore.get<ESM::Script>().find (name2))
 | 
						|
        {
 | 
						|
            if (mVerbose)
 | 
						|
                std::cout
 | 
						|
                    << "scanning script for local variable declarations: " << name2
 | 
						|
                    << std::endl;
 | 
						|
 | 
						|
            Compiler::Locals locals;
 | 
						|
 | 
						|
            std::istringstream stream (script->mScriptText);
 | 
						|
            Compiler::QuickFileParser parser (mErrorHandler, mCompilerContext, locals);
 | 
						|
            Compiler::Scanner scanner (mErrorHandler, stream, mCompilerContext.getExtensions());
 | 
						|
            scanner.scan (parser);
 | 
						|
 | 
						|
            std::map<std::string, Compiler::Locals>::iterator iter =
 | 
						|
                mOtherLocals.insert (std::make_pair (name2, locals)).first;
 | 
						|
 | 
						|
            return iter->second;
 | 
						|
        }
 | 
						|
 | 
						|
        throw std::logic_error ("script " + name + " does not exist");
 | 
						|
    }
 | 
						|
 | 
						|
    GlobalScripts& ScriptManager::getGlobalScripts()
 | 
						|
    {
 | 
						|
        return mGlobalScripts;
 | 
						|
    }
 | 
						|
}
 |