Make use of custom functions when converting menus

This commit is contained in:
Jan
2021-12-28 23:52:42 +01:00
parent 338de302d9
commit 7188b0946d
27 changed files with 459 additions and 143 deletions
@@ -1,7 +1,12 @@
#include "MenuExpressionMatchers.h"
#include "MenuMatcherFactory.h"
#include "Parsing/Menu/Domain/Expression/CommonExpressionFunctionCall.h"
#include "Game/IW4/IW4.h"
#include "Game/IW5/IW5.h"
#include "Game/IW4/MenuConstantsIW4.h"
#include "Game/IW5/MenuConstantsIW5.h"
#include "Parsing/Menu/Domain/Expression/CommonExpressionBaseFunctionCall.h"
#include "Parsing/Menu/Domain/Expression/CommonExpressionCustomFunctionCall.h"
using namespace menu;
@@ -10,9 +15,14 @@ static constexpr int TAG_EXPRESSION_FUNCTION_CALL_END = SimpleExpressionMatchers
static constexpr int CAPTURE_FUNCTION_NAME = SimpleExpressionMatchers::CAPTURE_OFFSET_EXPRESSION_EXT + 1;
MenuExpressionMatchers::MenuExpressionMatchers(const MenuFileParserState* state)
: SimpleExpressionMatchers(true, true, true, true, true),
m_state(state)
{
}
MenuExpressionMatchers::MenuExpressionMatchers()
: SimpleExpressionMatchers(true, true, true, true, true)
: MenuExpressionMatchers(nullptr)
{
}
@@ -36,17 +46,73 @@ std::unique_ptr<SimpleExpressionMatchers::matcher_t> MenuExpressionMatchers::Par
});
}
const std::map<std::string, size_t>& MenuExpressionMatchers::GetBaseFunctionMapForFeatureLevel(const FeatureLevel featureLevel)
{
if(featureLevel == FeatureLevel::IW4)
{
static std::map<std::string, size_t> iw4FunctionMap;
static bool iw4FunctionMapInitialized = false;
if(!iw4FunctionMapInitialized)
{
for(size_t i = IW4::expressionFunction_e::EXP_FUNC_DYN_START; i < std::extent_v<decltype(IW4::g_expFunctionNames)>; i++)
iw4FunctionMap.emplace(std::make_pair(IW4::g_expFunctionNames[i], i));
}
return iw4FunctionMap;
}
if(featureLevel == FeatureLevel::IW5)
{
static std::map<std::string, size_t> iw5FunctionMap;
static bool iw5FunctionMapInitialized = false;
if(!iw5FunctionMapInitialized)
{
for(size_t i = IW5::expressionFunction_e::EXP_FUNC_DYN_START; i < std::extent_v<decltype(IW5::g_expFunctionNames)>; i++)
iw5FunctionMap.emplace(std::make_pair(IW5::g_expFunctionNames[i], i));
}
return iw5FunctionMap;
}
assert(false);
throw ParsingException(TokenPos(), "Feature level has no functions registered!!");
}
std::unique_ptr<ISimpleExpression> MenuExpressionMatchers::ProcessOperandExtension(SequenceResult<SimpleParserValue>& result) const
{
assert(m_state);
if(m_state == nullptr)
throw ParsingException(TokenPos(), "No state when processing menu operand extension!!");
if (result.PeekAndRemoveIfTag(TAG_EXPRESSION_FUNCTION_CALL) != TAG_EXPRESSION_FUNCTION_CALL)
throw ParsingException(TokenPos(), "Menu Operand Extension must be function call");
auto functionCall = std::make_unique<CommonExpressionFunctionCall>(result.NextCapture(CAPTURE_FUNCTION_NAME).IdentifierValue());
const auto& functionCallToken = result.NextCapture(CAPTURE_FUNCTION_NAME);
auto functionCallName = functionCallToken.IdentifierValue();
while (result.PeekAndRemoveIfTag(TAG_EXPRESSION_FUNCTION_CALL_END) != TAG_EXPRESSION_FUNCTION_CALL_END)
const auto& baseFunctionMap = GetBaseFunctionMapForFeatureLevel(m_state->m_feature_level);
const auto foundBaseFunction = baseFunctionMap.find(functionCallName);
if(foundBaseFunction != baseFunctionMap.end())
{
functionCall->m_args.emplace_back(ProcessExpression(result));
auto functionCall = std::make_unique<CommonExpressionBaseFunctionCall>(std::move(functionCallName), foundBaseFunction->second);
while (result.PeekAndRemoveIfTag(TAG_EXPRESSION_FUNCTION_CALL_END) != TAG_EXPRESSION_FUNCTION_CALL_END)
{
functionCall->m_args.emplace_back(ProcessExpression(result));
}
return std::move(functionCall);
}
return std::move(functionCall);
}
const auto foundCustomFunction = m_state->m_functions_by_name.find(functionCallName);
if(foundCustomFunction != m_state->m_functions_by_name.end())
{
auto functionCall = std::make_unique<CommonExpressionCustomFunctionCall>(std::move(functionCallName));
if(result.PeekAndRemoveIfTag(TAG_EXPRESSION_FUNCTION_CALL_END) != TAG_EXPRESSION_FUNCTION_CALL_END)
throw ParsingException(functionCallToken.GetPos(), "Custom functions cannot be called with arguments");
return std::move(functionCall);
}
throw ParsingException(functionCallToken.GetPos(), "Unknown function");
}
@@ -2,14 +2,20 @@
#include <memory>
#include "Parsing/Menu/MenuFileParserState.h"
#include "Parsing/Simple/Expression/SimpleExpressionMatchers.h"
namespace menu
{
class MenuExpressionMatchers final : public SimpleExpressionMatchers
{
const MenuFileParserState* m_state;
static const std::map<std::string, size_t>& GetBaseFunctionMapForFeatureLevel(FeatureLevel featureLevel);
public:
MenuExpressionMatchers();
explicit MenuExpressionMatchers(const MenuFileParserState* state);
protected:
std::unique_ptr<matcher_t> ParseOperandExtension(const supplier_t* labelSupplier) const override;
@@ -101,7 +101,7 @@ std::string& MenuMatcherFactory::TokenTextValue(const SimpleParserValue& value)
return value.StringValue();
}
int MenuMatcherFactory::TokenIntExpressionValue(SequenceResult<SimpleParserValue>& result)
int MenuMatcherFactory::TokenIntExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result)
{
const auto nextTag = result.PeekTag();
@@ -115,7 +115,7 @@ int MenuMatcherFactory::TokenIntExpressionValue(SequenceResult<SimpleParserValue
if (nextTag == TAG_EXPRESSION)
{
result.NextTag();
const auto expression = MenuExpressionMatchers().ProcessExpression(result);
const auto expression = MenuExpressionMatchers(state).ProcessExpression(result);
if (!expression || !expression->IsStatic())
throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Not a valid static expression");
@@ -131,7 +131,7 @@ int MenuMatcherFactory::TokenIntExpressionValue(SequenceResult<SimpleParserValue
throw ParsingException(TokenPos(), "TokenIntExpressionValue must be expression or int");
}
double MenuMatcherFactory::TokenNumericExpressionValue(SequenceResult<SimpleParserValue>& result)
double MenuMatcherFactory::TokenNumericExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result)
{
const auto nextTag = result.PeekTag();
@@ -145,7 +145,7 @@ double MenuMatcherFactory::TokenNumericExpressionValue(SequenceResult<SimplePars
if (nextTag == TAG_EXPRESSION)
{
result.NextTag();
const auto expression = MenuExpressionMatchers().ProcessExpression(result);
const auto expression = MenuExpressionMatchers(state).ProcessExpression(result);
if (!expression || !expression->IsStatic())
throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Not a valid static expression");
@@ -2,6 +2,7 @@
#include "Parsing/Sequence/SequenceResult.h"
#include "Parsing/Simple/Matcher/SimpleMatcherFactory.h"
#include "Parsing/Menu/MenuFileParserState.h"
namespace menu
{
@@ -30,7 +31,7 @@ namespace menu
_NODISCARD static double TokenNumericFloatingPointValue(const SimpleParserValue& value);
_NODISCARD static std::string& TokenTextValue(const SimpleParserValue& value);
_NODISCARD static int TokenIntExpressionValue(SequenceResult<SimpleParserValue>& result);
_NODISCARD static double TokenNumericExpressionValue(SequenceResult<SimpleParserValue>& result);
_NODISCARD static int TokenIntExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result);
_NODISCARD static double TokenNumericExpressionValue(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result);
};
}