From 13589fd43cfca702897506ff13bf3c4c0857f78f Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 14 Nov 2021 12:46:02 +0100 Subject: [PATCH] Add menu eventhandlerset sequences for if, elseif and else --- .../Parsing/Menu/MenuFileParserState.cpp | 10 +- .../Parsing/Menu/MenuFileParserState.h | 2 + .../EventHandlerSetScopeSequences.cpp | 195 +++++++++++++++--- 3 files changed, 173 insertions(+), 34 deletions(-) diff --git a/src/ObjLoading/Parsing/Menu/MenuFileParserState.cpp b/src/ObjLoading/Parsing/Menu/MenuFileParserState.cpp index f16efedf..cc1ad48b 100644 --- a/src/ObjLoading/Parsing/Menu/MenuFileParserState.cpp +++ b/src/ObjLoading/Parsing/Menu/MenuFileParserState.cpp @@ -3,7 +3,13 @@ using namespace menu; MenuFileParserState::EventHandlerConditionState::EventHandlerConditionState(CommonEventHandlerCondition* condition) + : EventHandlerConditionState(condition, false) +{ +} + +MenuFileParserState::EventHandlerConditionState::EventHandlerConditionState(CommonEventHandlerCondition* condition, const bool autoSkip) : m_in_condition_elements(true), + m_auto_skip(autoSkip), m_condition(condition) { } @@ -22,12 +28,12 @@ MenuFileParserState::MenuFileParserState(const FeatureLevel featureLevel) MenuFileParserState::MenuFileParserState(const FeatureLevel featureLevel, const MenuAssetZoneState* zoneState) : MenuFileParserState(featureLevel) { - for(const auto& function : zoneState->m_functions) + for (const auto& function : zoneState->m_functions) { m_functions_by_name.emplace(std::make_pair(function->m_name, function.get())); } - for(const auto& menu : zoneState->m_menus) + for (const auto& menu : zoneState->m_menus) { m_menus_by_name.emplace(std::make_pair(menu->m_name, menu.get())); } diff --git a/src/ObjLoading/Parsing/Menu/MenuFileParserState.h b/src/ObjLoading/Parsing/Menu/MenuFileParserState.h index ca021132..3bba0eaa 100644 --- a/src/ObjLoading/Parsing/Menu/MenuFileParserState.h +++ b/src/ObjLoading/Parsing/Menu/MenuFileParserState.h @@ -22,9 +22,11 @@ namespace menu { public: bool m_in_condition_elements; + bool m_auto_skip; CommonEventHandlerCondition* m_condition; explicit EventHandlerConditionState(CommonEventHandlerCondition* condition); + EventHandlerConditionState(CommonEventHandlerCondition* condition, bool autoSkip); }; const FeatureLevel m_feature_level; diff --git a/src/ObjLoading/Parsing/Menu/Sequence/EventHandlerSetScopeSequences.cpp b/src/ObjLoading/Parsing/Menu/Sequence/EventHandlerSetScopeSequences.cpp index eaad6788..64aecfdf 100644 --- a/src/ObjLoading/Parsing/Menu/Sequence/EventHandlerSetScopeSequences.cpp +++ b/src/ObjLoading/Parsing/Menu/Sequence/EventHandlerSetScopeSequences.cpp @@ -130,26 +130,34 @@ namespace menu::event_handler_set_scope_sequences state->m_current_nested_event_handler_set->m_elements.emplace_back(std::make_unique(std::move(remainingScript))); state->m_current_script.clear(); - if (!state->m_condition_stack.empty()) - { - state->m_condition_stack.pop(); + bool conditionWasAutoSkip; + do + { + conditionWasAutoSkip = false; if (!state->m_condition_stack.empty()) { - const auto& newConditionState = state->m_condition_stack.top(); - if (newConditionState.m_in_condition_elements) - state->m_current_nested_event_handler_set = newConditionState.m_condition->m_condition_elements.get(); + conditionWasAutoSkip = state->m_condition_stack.top().m_auto_skip; + state->m_condition_stack.pop(); + + if (!state->m_condition_stack.empty()) + { + const auto& newConditionState = state->m_condition_stack.top(); + if (newConditionState.m_in_condition_elements) + state->m_current_nested_event_handler_set = newConditionState.m_condition->m_condition_elements.get(); + else + state->m_current_nested_event_handler_set = newConditionState.m_condition->m_else_elements.get(); + } else - state->m_current_nested_event_handler_set = newConditionState.m_condition->m_else_elements.get(); + state->m_current_nested_event_handler_set = state->m_current_event_handler_set; } else - state->m_current_nested_event_handler_set = state->m_current_event_handler_set; - } - else - { - state->m_current_event_handler_set = nullptr; - state->m_current_nested_event_handler_set = nullptr; + { + state->m_current_event_handler_set = nullptr; + state->m_current_nested_event_handler_set = nullptr; + } } + while (conditionWasAutoSkip); } }; @@ -258,6 +266,34 @@ namespace menu::event_handler_set_scope_sequences } }; + class SequenceLerp final : public SequenceGenericScriptStatement + { + public: + explicit SequenceLerp() + { + const ScriptMatcherFactory create(this); + + AddMatchers({ + create.And({ + create.ScriptKeyword("lerp"), + create.Or({ + create.ScriptKeyword("scale"), + create.ScriptKeyword("alpha"), + create.ScriptKeyword("x"), + create.ScriptKeyword("y"), + }), + create.ScriptKeyword("from"), + create.ScriptNumeric(), + create.ScriptKeyword("to"), + create.ScriptNumeric(), + create.ScriptKeyword("over"), + create.ScriptNumeric() + }).Capture(CAPTURE_SCRIPT_TOKEN), + create.Optional(create.Char(';')) + }); + } + }; + class SequenceSetLocalVar final : public MenuFileParser::sequence_t { static constexpr auto TAG_BOOL = static_cast(SetLocalVarType::BOOL); @@ -380,32 +416,124 @@ namespace menu::event_handler_set_scope_sequences } }; - class SequenceLerp final : public SequenceGenericScriptStatement + class SequenceIf final : public MenuFileParser::sequence_t { + static constexpr auto CAPTURE_KEYWORD = 1; + public: - explicit SequenceLerp() + SequenceIf() { const ScriptMatcherFactory create(this); + AddLabeledMatchers(MenuCommonMatchers::Expression(this), MenuCommonMatchers::LABEL_EXPRESSION); + AddMatchers({ - create.And({ - create.ScriptKeyword("lerp"), - create.Or({ - create.ScriptKeyword("scale"), - create.ScriptKeyword("alpha"), - create.ScriptKeyword("x"), - create.ScriptKeyword("y"), - }), - create.ScriptKeyword("from"), - create.ScriptNumeric(), - create.ScriptKeyword("to"), - create.ScriptNumeric(), - create.ScriptKeyword("over"), - create.ScriptNumeric() - }).Capture(CAPTURE_SCRIPT_TOKEN), - create.Optional(create.Char(';')) + create.Keyword("if").Capture(CAPTURE_KEYWORD), + create.Char('('), + create.Label(MenuCommonMatchers::LABEL_EXPRESSION), + create.Char(')'), + create.Char('{') }); } + + protected: + void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override + { + auto expression = MenuCommonMatchers::ProcessExpression(state, result); + + if (!expression) + throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Could not parse expression"); + + auto newCondition = std::make_unique(std::move(expression), std::make_unique(), nullptr); + auto* newConditionPtr = newCondition.get(); + state->m_current_nested_event_handler_set->m_elements.emplace_back(std::move(newCondition)); + + state->m_condition_stack.emplace(newConditionPtr); + state->m_current_nested_event_handler_set = newConditionPtr->m_condition_elements.get(); + } + }; + + class SequenceElseIf final : public MenuFileParser::sequence_t + { + static constexpr auto CAPTURE_KEYWORD = 1; + + public: + SequenceElseIf() + { + const ScriptMatcherFactory create(this); + + AddLabeledMatchers(MenuCommonMatchers::Expression(this), MenuCommonMatchers::LABEL_EXPRESSION); + + AddMatchers({ + create.Keyword("elseif").Capture(CAPTURE_KEYWORD), + create.Char('('), + create.Label(MenuCommonMatchers::LABEL_EXPRESSION), + create.Char(')'), + create.Char('{') + }); + } + + protected: + void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override + { + auto expression = MenuCommonMatchers::ProcessExpression(state, result); + + if (!expression) + throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Could not parse expression"); + + if (state->m_condition_stack.empty()) + throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Not in an if statement"); + + auto& currentCondition = state->m_condition_stack.top(); + + assert(currentCondition.m_in_condition_elements == (currentCondition.m_condition->m_else_elements == nullptr)); + if (!currentCondition.m_in_condition_elements) + throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Cannot specify elseif after else"); + currentCondition.m_in_condition_elements = false; + + auto newCondition = std::make_unique(std::move(expression), std::make_unique(), nullptr); + auto* newConditionPtr = newCondition.get(); + currentCondition.m_condition->m_else_elements = std::make_unique(); + currentCondition.m_condition->m_else_elements->m_elements.emplace_back(std::move(newCondition)); + + state->m_condition_stack.emplace(newConditionPtr, true); + state->m_current_nested_event_handler_set = newConditionPtr->m_condition_elements.get(); + } + }; + + class SequenceElse final : public MenuFileParser::sequence_t + { + static constexpr auto CAPTURE_KEYWORD = 1; + + public: + SequenceElse() + { + const ScriptMatcherFactory create(this); + + AddLabeledMatchers(MenuCommonMatchers::Expression(this), MenuCommonMatchers::LABEL_EXPRESSION); + + AddMatchers({ + create.Keyword("else").Capture(CAPTURE_KEYWORD), + create.Char('{') + }); + } + + protected: + void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override + { + if (state->m_condition_stack.empty()) + throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Not in an if statement"); + + auto& currentCondition = state->m_condition_stack.top(); + + assert(currentCondition.m_in_condition_elements == (currentCondition.m_condition->m_else_elements == nullptr)); + if (!currentCondition.m_in_condition_elements) + throw ParsingException(result.NextCapture(CAPTURE_KEYWORD).GetPos(), "Cannot specify second else block"); + + currentCondition.m_in_condition_elements = false; + currentCondition.m_condition->m_else_elements = std::make_unique(); + state->m_current_nested_event_handler_set = currentCondition.m_condition->m_else_elements.get(); + } }; } @@ -457,7 +585,7 @@ void EventHandlerSetScopeSequences::AddSequences(FeatureLevel featureLevel) AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("respondOnDvarStringValue"), create.ScriptText(), create.ScriptText(), create.ScriptText()})); AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("respondOnDvarIntValue"), create.ScriptText(), create.ScriptInt(), create.ScriptText()})); AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("respondOnDvarFloatValue"), create.ScriptText(), create.ScriptNumeric(), create.ScriptText()})); - AddSequence(std::make_unique()); + //AddSequence(std::make_unique()); AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("setPlayerDataSp")})); AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("updateMail")})); AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("openMail")})); @@ -481,4 +609,7 @@ void EventHandlerSetScopeSequences::AddSequences(FeatureLevel featureLevel) AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("togglePlayerMute")})); AddSequence(SequenceGenericScriptStatement::Create({create.ScriptKeyword("resolveError")})); AddSequence(std::make_unique()); + AddSequence(std::make_unique()); + AddSequence(std::make_unique()); + AddSequence(std::make_unique()); }