Skip to content

Commit

Permalink
Merge pull request Laupetin#68 from Laupetin/fix/empty-value-menu-mis…
Browse files Browse the repository at this point in the history
…match

Accept setLocalVar scripts without value as default value expression
  • Loading branch information
Laupetin authored Dec 25, 2023
2 parents 846a9d3 + 69cd172 commit f6b5dca
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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(';'),
}),
});
}

Expand Down Expand Up @@ -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
{
Expand All @@ -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));
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit f6b5dca

Please sign in to comment.