Merge pull request #68 from Laupetin/fix/empty-value-menu-mismatch

Accept setLocalVar scripts without value as default value expression
This commit is contained in:
Jan 2023-12-25 10:01:29 +01:00 committed by GitHub
commit f6b5dcae39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 8 deletions

View File

@ -568,8 +568,15 @@ namespace menu::event_handler_set_scope_sequences
create.ScriptKeyword("setLocalVarString").Tag(TAG_STRING),
}),
create.ScriptText().Capture(CAPTURE_VAR_NAME),
create.Label(MenuExpressionMatchers::LABEL_EXPRESSION),
create.Optional(create.Char(';')),
create.Or({
create.And({
create.Label(MenuExpressionMatchers::LABEL_EXPRESSION),
create.Optional(create.Char(';')),
}),
// The game seems to accept setLocalVar expressions without value as setting the var to the default value
// This only applies to the menu parser though and not to the script parser so we need to separately parse this
create.Char(';'),
}),
});
}
@ -661,6 +668,26 @@ namespace menu::event_handler_set_scope_sequences
std::make_unique<CommonEventHandlerSetLocalVar>(type, varName, std::move(expression)));
}
static std::unique_ptr<ISimpleExpression> DefaultExpressionForType(const SetLocalVarType type)
{
switch (type)
{
case SetLocalVarType::INT:
case SetLocalVarType::BOOL:
return std::make_unique<SimpleExpressionValue>(0);
case SetLocalVarType::FLOAT:
return std::make_unique<SimpleExpressionValue>(0.0);
case SetLocalVarType::STRING:
return std::make_unique<SimpleExpressionValue>(std::string());
default:
assert(false);
return nullptr;
}
}
protected:
void ProcessMatch(MenuFileParserState* state, SequenceResult<SimpleParserValue>& result) const override
{
@ -671,13 +698,15 @@ namespace menu::event_handler_set_scope_sequences
const auto& varName = MenuMatcherFactory::TokenTextValue(varNameToken);
auto expression = expressionMatchers.ProcessExpression(result);
if (!expression)
throw ParsingException(varNameToken.GetPos(), "No expression");
if (expression && expression->IsStatic())
EmitStaticSetLocalVar(state, varNameToken.GetPos(), typeTag, varName, std::move(expression));
if (expression)
{
if (expression->IsStatic())
EmitStaticSetLocalVar(state, varNameToken.GetPos(), typeTag, varName, std::move(expression));
else
EmitDynamicSetLocalVar(state, typeTag, varName, std::move(expression));
}
else
EmitDynamicSetLocalVar(state, typeTag, varName, std::move(expression));
EmitStaticSetLocalVar(state, varNameToken.GetPos(), typeTag, varName, DefaultExpressionForType(typeTag));
}
};

View File

@ -1037,6 +1037,28 @@ namespace test::parsing::menu::sequence::event_handler_set
REQUIRE(setLocalVarElement->m_value->IsStatic() == false);
}
TEST_CASE("EventHandlerSetScopeSequences: Ensure setLocalVarString uses missing value as default value", "[parsing][sequence][menu]")
{
EventHandlerSetSequenceTestsHelper helper(FeatureLevel::IW4, true);
const TokenPos pos;
helper.Tokens({
SimpleParserValue::Identifier(TokenPos(), new std::string("setLocalVarString")),
SimpleParserValue::Identifier(TokenPos(), new std::string("ui_hint_text")),
SimpleParserValue::Character(TokenPos(), ';'),
SimpleParserValue::Character(TokenPos(), ';'),
SimpleParserValue::EndOfFile(pos),
});
const auto result = helper.PerformTest();
REQUIRE(result);
REQUIRE(helper.m_consumed_token_count == 3);
REQUIRE(helper.m_event_handler_set->m_elements.size() == 0);
const auto currentScript = helper.m_state->m_current_script.str();
REQUIRE(currentScript == R"("setLocalVarString" "ui_hint_text" "" ; )");
}
#pragma endregion
#pragma region Unit Tests for If/ElseIf/Else/CloseBracket