You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/components/compiler/extensions.cpp

218 lines
6.7 KiB
C++

#include "extensions.hpp"
#include <cassert>
#include <stdexcept>
#include "generator.hpp"
#include "literals.hpp"
namespace Compiler
{
Extensions::Extensions() : mNextKeywordIndex (-1) {}
int Extensions::searchKeyword (const std::string& keyword) const
{
std::map<std::string, int>::const_iterator iter = mKeywords.find (keyword);
if (iter==mKeywords.end())
return 0;
return iter->second;
}
bool Extensions::isFunction (int keyword, ScriptReturn& returnType, ScriptArgs& argumentType,
bool& explicitReference) const
{
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
if (iter==mFunctions.end())
return false;
if (explicitReference && iter->second.mCodeExplicit==-1)
explicitReference = false;
returnType = iter->second.mReturn;
argumentType = iter->second.mArguments;
return true;
}
bool Extensions::isInstruction (int keyword, ScriptArgs& argumentType,
bool& explicitReference) const
{
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
if (iter==mInstructions.end())
return false;
if (explicitReference && iter->second.mCodeExplicit==-1)
explicitReference = false;
argumentType = iter->second.mArguments;
return true;
}
void Extensions::registerFunction (const std::string& keyword, ScriptReturn returnType,
const ScriptArgs& argumentType, int code, int codeExplicit)
{
Function function;
if (argumentType.find ('/')==std::string::npos)
{
function.mSegment = 5;
assert (code>=33554432 && code<=67108863);
assert (codeExplicit==-1 || (codeExplicit>=33554432 && codeExplicit<=67108863));
}
else
{
function.mSegment = 3;
assert (code>=0x20000 && code<=0x2ffff);
assert (codeExplicit==-1 || (codeExplicit>=0x20000 && codeExplicit<=0x2ffff));
}
int keywordIndex = mNextKeywordIndex--;
mKeywords.insert (std::make_pair (keyword, keywordIndex));
function.mReturn = returnType;
function.mArguments = argumentType;
function.mCode = code;
function.mCodeExplicit = codeExplicit;
mFunctions.insert (std::make_pair (keywordIndex, function));
}
void Extensions::registerInstruction (const std::string& keyword,
const ScriptArgs& argumentType, int code, int codeExplicit)
{
Instruction instruction;
if (argumentType.find ('/')==std::string::npos)
{
instruction.mSegment = 5;
assert (code>=33554432 && code<=67108863);
assert (codeExplicit==-1 || (codeExplicit>=33554432 && codeExplicit<=67108863));
}
else
{
instruction.mSegment = 3;
assert (code>=0x20000 && code<=0x2ffff);
assert (codeExplicit==-1 || (codeExplicit>=0x20000 && codeExplicit<=0x2ffff));
}
int keywordIndex = mNextKeywordIndex--;
mKeywords.insert (std::make_pair (keyword, keywordIndex));
instruction.mArguments = argumentType;
instruction.mCode = code;
instruction.mCodeExplicit = codeExplicit;
mInstructions.insert (std::make_pair (keywordIndex, instruction));
}
void Extensions::generateFunctionCode (int keyword, std::vector<Interpreter::Type_Code>& code,
Literals& literals, const std::string& id, int optionalArguments) const
{
assert (optionalArguments>=0);
std::map<int, Function>::const_iterator iter = mFunctions.find (keyword);
if (iter==mFunctions.end())
throw std::logic_error ("unknown custom function keyword");
if (optionalArguments && iter->second.mSegment!=3)
throw std::logic_error ("functions with optional arguments must be placed into segment 3");
if (!id.empty())
{
if (iter->second.mCodeExplicit==-1)
throw std::logic_error ("explicit references not supported");
int index = literals.addString (id);
Generator::pushInt (code, literals, index);
}
switch (iter->second.mSegment)
{
case 3:
if (optionalArguments>=256)
throw std::logic_error ("number of optional arguments is too large for segment 3");
code.push_back (Generator::segment3 (
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit,
optionalArguments));
break;
case 5:
code.push_back (Generator::segment5 (
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
break;
default:
throw std::logic_error ("unsupported code segment");
}
}
void Extensions::generateInstructionCode (int keyword,
std::vector<Interpreter::Type_Code>& code, Literals& literals, const std::string& id,
int optionalArguments) const
{
assert (optionalArguments>=0);
std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword);
if (iter==mInstructions.end())
throw std::logic_error ("unknown custom instruction keyword");
if (optionalArguments && iter->second.mSegment!=3)
throw std::logic_error ("instructions with optional arguments must be placed into segment 3");
if (!id.empty())
{
if (iter->second.mCodeExplicit==-1)
throw std::logic_error ("explicit references not supported");
int index = literals.addString (id);
Generator::pushInt (code, literals, index);
}
switch (iter->second.mSegment)
{
case 3:
if (optionalArguments>=256)
throw std::logic_error ("number of optional arguments is too large for segment 3");
code.push_back (Generator::segment3 (
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit,
optionalArguments));
break;
case 5:
code.push_back (Generator::segment5 (
id.empty() ? iter->second.mCode : iter->second.mCodeExplicit));
break;
default:
throw std::logic_error ("unsupported code segment");
}
}
void Extensions::listKeywords (std::vector<std::string>& keywords) const
{
for (std::map<std::string, int>::const_iterator iter (mKeywords.begin());
iter!=mKeywords.end(); ++iter)
keywords.push_back (iter->first);
}
}