Make menu and item rect accept expressions as static values

This commit is contained in:
Jan 2021-11-26 17:43:27 +01:00
parent 2a4768e5b0
commit fb70d9538a
5 changed files with 184 additions and 31 deletions

View File

@ -1,5 +1,7 @@
#include "MenuMatcherFactory.h" #include "MenuMatcherFactory.h"
#include "MenuExpressionMatchers.h"
using namespace menu; using namespace menu;
MenuMatcherFactory::MenuMatcherFactory(const IMatcherForLabelSupplier<SimpleParserValue>* labelSupplier) MenuMatcherFactory::MenuMatcherFactory(const IMatcherForLabelSupplier<SimpleParserValue>* labelSupplier)
@ -9,12 +11,36 @@ MenuMatcherFactory::MenuMatcherFactory(const IMatcherForLabelSupplier<SimplePars
MatcherFactoryWrapper<SimpleParserValue> MenuMatcherFactory::Text() const MatcherFactoryWrapper<SimpleParserValue> MenuMatcherFactory::Text() const
{ {
return MatcherFactoryWrapper<SimpleParserValue>(Or({String(), Identifier()})); return MatcherFactoryWrapper(Or({String(), Identifier()}));
} }
MatcherFactoryWrapper<SimpleParserValue> MenuMatcherFactory::Numeric() const MatcherFactoryWrapper<SimpleParserValue> MenuMatcherFactory::Numeric() const
{ {
return MatcherFactoryWrapper<SimpleParserValue>(Or({FloatingPoint(), Integer()})); return MatcherFactoryWrapper(Or({FloatingPoint(), Integer()}));
}
MatcherFactoryWrapper<SimpleParserValue> MenuMatcherFactory::IntExpression() const
{
return MatcherFactoryWrapper(Or({
Integer().Tag(TAG_INT).Capture(CAPTURE_INT),
And({
Char('(').Capture(CAPTURE_FIRST_TOKEN),
Label(MenuExpressionMatchers::LABEL_EXPRESSION),
Char(')'),
}).Tag(TAG_EXPRESSION)
}));
}
MatcherFactoryWrapper<SimpleParserValue> MenuMatcherFactory::NumericExpression() const
{
return MatcherFactoryWrapper(Or({
Numeric().Tag(TAG_NUMERIC).Capture(CAPTURE_NUMERIC),
And({
Char('(').Capture(CAPTURE_FIRST_TOKEN),
Label(MenuExpressionMatchers::LABEL_EXPRESSION),
Char(')'),
}).Tag(TAG_EXPRESSION)
}));
} }
int MenuMatcherFactory::TokenNumericIntValue(const SimpleParserValue& value) int MenuMatcherFactory::TokenNumericIntValue(const SimpleParserValue& value)
@ -31,7 +57,7 @@ double MenuMatcherFactory::TokenNumericFloatingPointValue(const SimpleParserValu
{ {
if (value.m_type == SimpleParserValueType::INTEGER) if (value.m_type == SimpleParserValueType::INTEGER)
{ {
return static_cast<double>(value.IntegerValue()); return value.IntegerValue();
} }
return value.FloatingPointValue(); return value.FloatingPointValue();
@ -46,3 +72,65 @@ std::string& MenuMatcherFactory::TokenTextValue(const SimpleParserValue& value)
return value.StringValue(); return value.StringValue();
} }
int MenuMatcherFactory::TokenIntExpressionValue(SequenceResult<SimpleParserValue>& result)
{
const auto nextTag = result.PeekTag();
assert(nextTag == TAG_INT || nextTag == TAG_EXPRESSION);
if (nextTag == TAG_INT)
{
result.NextTag();
return result.NextCapture(CAPTURE_INT).IntegerValue();
}
if (nextTag == TAG_EXPRESSION)
{
result.NextTag();
const auto expression = MenuExpressionMatchers().ProcessExpression(result);
if (!expression || !expression->IsStatic())
throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Not a valid static expression");
const auto value = expression->Evaluate();
if (value.m_type != SimpleExpressionValue::Type::INT)
throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Expression MUST be int type");
return value.m_int_value;
}
throw ParsingException(TokenPos(), "TokenIntExpressionValue must be expression or int");
}
double MenuMatcherFactory::TokenNumericExpressionValue(SequenceResult<SimpleParserValue>& result)
{
const auto nextTag = result.PeekTag();
assert(nextTag == TAG_NUMERIC || nextTag == TAG_EXPRESSION);
if (nextTag == TAG_NUMERIC)
{
result.NextTag();
return TokenNumericFloatingPointValue(result.NextCapture(CAPTURE_NUMERIC));
}
if (nextTag == TAG_EXPRESSION)
{
result.NextTag();
const auto expression = MenuExpressionMatchers().ProcessExpression(result);
if (!expression || !expression->IsStatic())
throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Not a valid static expression");
const auto value = expression->Evaluate();
if (value.m_type == SimpleExpressionValue::Type::INT)
return value.m_int_value;
if (value.m_type == SimpleExpressionValue::Type::DOUBLE)
return value.m_double_value;
throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Expression MUST be numeric type");
}
throw ParsingException(TokenPos(), "TokenNumericExpressionValue must be expression or numeric");
}

View File

@ -1,19 +1,34 @@
#pragma once #pragma once
#include "Parsing/Sequence/SequenceResult.h"
#include "Parsing/Simple/Matcher/SimpleMatcherFactory.h" #include "Parsing/Simple/Matcher/SimpleMatcherFactory.h"
namespace menu namespace menu
{ {
class MenuMatcherFactory : public SimpleMatcherFactory class MenuMatcherFactory : public SimpleMatcherFactory
{ {
static constexpr auto TAG_INT = 1420;
static constexpr auto TAG_NUMERIC = 1421;
static constexpr auto TAG_EXPRESSION = 1422;
static constexpr auto CAPTURE_FIRST_TOKEN = 1420;
static constexpr auto CAPTURE_INT = 1421;
static constexpr auto CAPTURE_NUMERIC = 1422;
public: public:
explicit MenuMatcherFactory(const IMatcherForLabelSupplier<SimpleParserValue>* labelSupplier); explicit MenuMatcherFactory(const IMatcherForLabelSupplier<SimpleParserValue>* labelSupplier);
_NODISCARD MatcherFactoryWrapper<SimpleParserValue> Text() const; _NODISCARD MatcherFactoryWrapper<SimpleParserValue> Text() const;
_NODISCARD MatcherFactoryWrapper<SimpleParserValue> Numeric() const; _NODISCARD MatcherFactoryWrapper<SimpleParserValue> Numeric() const;
_NODISCARD MatcherFactoryWrapper<SimpleParserValue> IntExpression() const;
_NODISCARD MatcherFactoryWrapper<SimpleParserValue> NumericExpression() const;
_NODISCARD static int TokenNumericIntValue(const SimpleParserValue& value); _NODISCARD static int TokenNumericIntValue(const SimpleParserValue& value);
_NODISCARD static double TokenNumericFloatingPointValue(const SimpleParserValue& value); _NODISCARD static double TokenNumericFloatingPointValue(const SimpleParserValue& value);
_NODISCARD static std::string& TokenTextValue(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);
}; };
} }

View File

@ -270,6 +270,29 @@ namespace menu::event_handler_set_scope_sequences
} }
}; };
class SequenceUiScriptStatement final : public SequenceGenericScriptStatement
{
public:
explicit SequenceUiScriptStatement(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<SimpleParserValue>>>> matchers)
: SequenceGenericScriptStatement()
{
const ScriptMatcherFactory create(this);
AddMatchers({
create.And({
create.ScriptKeyword("uiScript"),
create.And(matchers)
}).Capture(CAPTURE_SCRIPT_TOKEN),
create.Optional(create.Char(';'))
});
}
static std::unique_ptr<SequenceUiScriptStatement> Create(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<SimpleParserValue>>>> matchers)
{
return std::make_unique<SequenceUiScriptStatement>(matchers);
}
};
class SequenceSetPlayerData final : public SequenceGenericScriptStatement class SequenceSetPlayerData final : public SequenceGenericScriptStatement
{ {
public: public:
@ -653,6 +676,30 @@ void EventHandlerSetScopeSequences::AddSequences(FeatureLevel featureLevel)
AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("resolveError")})); AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("resolveError")}));
AddSequence(std::make_unique<SequenceLerp>()); AddSequence(std::make_unique<SequenceLerp>());
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("StartServer")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("loadArenas")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("loadGameInfo")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("clearError")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("Quit")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("Controls")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("Leave")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("closeingame")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("update"), create.ScriptText()}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("startSingleplayer")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("getLanguage")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("verifyLanguage")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("updateLanguage")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("mutePlayer")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("openMenuOnDvar"), create.ScriptText(), create.Or({create.ScriptStrictNumeric(), create.ScriptText()}), create.ScriptText()}));
AddSequence(
SequenceUiScriptStatement::Create({create.ScriptKeyword("openMenuOnDvarNot"), create.ScriptText(), create.Or({create.ScriptStrictNumeric(), create.ScriptText()}), create.ScriptText()}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("closeMenuOnDvar"), create.ScriptText(), create.Or({create.ScriptStrictNumeric(), create.ScriptText()}), create.ScriptText()}));
AddSequence(SequenceUiScriptStatement::Create(
{create.ScriptKeyword("closeMenuOnDvarNot"), create.ScriptText(), create.Or({create.ScriptStrictNumeric(), create.ScriptText()}), create.ScriptText()}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("setRecommended")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("clearLoadErrorsSummary")}));
AddSequence(SequenceUiScriptStatement::Create({create.ScriptKeyword("clearClientMatchData")}));
AddSequence(std::make_unique<SequenceIf>()); AddSequence(std::make_unique<SequenceIf>());
AddSequence(std::make_unique<SequenceElseIf>()); AddSequence(std::make_unique<SequenceElseIf>());
AddSequence(std::make_unique<SequenceElse>()); AddSequence(std::make_unique<SequenceElse>());

View File

@ -10,6 +10,7 @@
#include "Generic/GenericKeywordPropertySequence.h" #include "Generic/GenericKeywordPropertySequence.h"
#include "Generic/GenericMenuEventHandlerSetPropertySequence.h" #include "Generic/GenericMenuEventHandlerSetPropertySequence.h"
#include "Generic/GenericStringPropertySequence.h" #include "Generic/GenericStringPropertySequence.h"
#include "Parsing/Menu/Matcher/MenuExpressionMatchers.h"
#include "Parsing/Menu/Matcher/MenuMatcherFactory.h" #include "Parsing/Menu/Matcher/MenuMatcherFactory.h"
using namespace menu; using namespace menu;
@ -142,24 +143,21 @@ namespace menu::item_scope_sequences
class SequenceRect final : public MenuFileParser::sequence_t class SequenceRect final : public MenuFileParser::sequence_t
{ {
static constexpr auto CAPTURE_X = 1; static constexpr auto CAPTURE_ALIGN_HORIZONTAL = 1;
static constexpr auto CAPTURE_Y = 2; static constexpr auto CAPTURE_ALIGN_VERTICAL = 2;
static constexpr auto CAPTURE_W = 3;
static constexpr auto CAPTURE_H = 4;
static constexpr auto CAPTURE_ALIGN_HORIZONTAL = 5;
static constexpr auto CAPTURE_ALIGN_VERTICAL = 6;
public: public:
SequenceRect() SequenceRect()
{ {
const MenuMatcherFactory create(this); const MenuMatcherFactory create(this);
AddLabeledMatchers(MenuExpressionMatchers().Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION);
AddMatchers({ AddMatchers({
create.KeywordIgnoreCase("rect"), create.KeywordIgnoreCase("rect"),
create.Numeric().Capture(CAPTURE_X), create.NumericExpression(), // x
create.Numeric().Capture(CAPTURE_Y), create.NumericExpression(), // y
create.Numeric().Capture(CAPTURE_W), create.NumericExpression(), // w
create.Numeric().Capture(CAPTURE_H), create.NumericExpression(), // h
create.Optional(create.And({ create.Optional(create.And({
create.Integer().Capture(CAPTURE_ALIGN_HORIZONTAL), create.Integer().Capture(CAPTURE_ALIGN_HORIZONTAL),
create.Integer().Capture(CAPTURE_ALIGN_VERTICAL) create.Integer().Capture(CAPTURE_ALIGN_VERTICAL)
@ -172,12 +170,16 @@ namespace menu::item_scope_sequences
{ {
assert(state->m_current_item); assert(state->m_current_item);
const auto x = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto y = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto w = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto h = MenuMatcherFactory::TokenNumericExpressionValue(result);
CommonRect rect CommonRect rect
{ {
MenuMatcherFactory::TokenNumericFloatingPointValue(result.NextCapture(CAPTURE_X)), x,
MenuMatcherFactory::TokenNumericFloatingPointValue(result.NextCapture(CAPTURE_Y)), y,
MenuMatcherFactory::TokenNumericFloatingPointValue(result.NextCapture(CAPTURE_W)), w,
MenuMatcherFactory::TokenNumericFloatingPointValue(result.NextCapture(CAPTURE_H)), h,
0, 0 0, 0
}; };

View File

@ -79,10 +79,6 @@ namespace menu::menu_scope_sequences
class SequenceRect final : public MenuFileParser::sequence_t class SequenceRect final : public MenuFileParser::sequence_t
{ {
static constexpr auto CAPTURE_X = 1;
static constexpr auto CAPTURE_Y = 2;
static constexpr auto CAPTURE_W = 3;
static constexpr auto CAPTURE_H = 4;
static constexpr auto CAPTURE_ALIGN_HORIZONTAL = 5; static constexpr auto CAPTURE_ALIGN_HORIZONTAL = 5;
static constexpr auto CAPTURE_ALIGN_VERTICAL = 6; static constexpr auto CAPTURE_ALIGN_VERTICAL = 6;
@ -91,12 +87,13 @@ namespace menu::menu_scope_sequences
{ {
const MenuMatcherFactory create(this); const MenuMatcherFactory create(this);
AddLabeledMatchers(MenuExpressionMatchers().Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION);
AddMatchers({ AddMatchers({
create.KeywordIgnoreCase("rect"), create.KeywordIgnoreCase("rect"),
create.Numeric().Capture(CAPTURE_X), create.NumericExpression(), // x
create.Numeric().Capture(CAPTURE_Y), create.NumericExpression(), // y
create.Numeric().Capture(CAPTURE_W), create.NumericExpression(), // w
create.Numeric().Capture(CAPTURE_H), create.NumericExpression(), // h
create.Optional(create.And({ create.Optional(create.And({
create.Integer().Capture(CAPTURE_ALIGN_HORIZONTAL), create.Integer().Capture(CAPTURE_ALIGN_HORIZONTAL),
create.Integer().Capture(CAPTURE_ALIGN_VERTICAL) create.Integer().Capture(CAPTURE_ALIGN_VERTICAL)
@ -109,12 +106,16 @@ namespace menu::menu_scope_sequences
{ {
assert(state->m_current_menu); assert(state->m_current_menu);
const auto x = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto y = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto w = MenuMatcherFactory::TokenNumericExpressionValue(result);
const auto h = MenuMatcherFactory::TokenNumericExpressionValue(result);
CommonRect rect CommonRect rect
{ {
MenuMatcherFactory::TokenNumericFloatingPointValue(result.NextCapture(CAPTURE_X)), x,
MenuMatcherFactory::TokenNumericFloatingPointValue(result.NextCapture(CAPTURE_Y)), y,
MenuMatcherFactory::TokenNumericFloatingPointValue(result.NextCapture(CAPTURE_W)), w,
MenuMatcherFactory::TokenNumericFloatingPointValue(result.NextCapture(CAPTURE_H)), h,
0, 0 0, 0
}; };