From f814b926dd7e9920a4c934b8c4ac12c8cfba17e7 Mon Sep 17 00:00:00 2001 From: Palagiri Subbareddy Date: Thu, 25 Jun 2026 15:52:37 +0530 Subject: [PATCH 1/5] fix(core): enhance empty string expression validation error context (#8762) --- Core/GDCore/IDE/Events/ExpressionValidator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/GDCore/IDE/Events/ExpressionValidator.h b/Core/GDCore/IDE/Events/ExpressionValidator.h index c46f4724ef90..9daeb298111e 100644 --- a/Core/GDCore/IDE/Events/ExpressionValidator.h +++ b/Core/GDCore/IDE/Events/ExpressionValidator.h @@ -375,7 +375,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker { message = _("You must enter a number or a valid expression call."); } else if (parentType == Type::String) { message = _( - "You must enter a text (between quotes) or a valid expression call."); + "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); } else if (parentType == Type::Variable || parentType == Type::LegacyVariable) { message = _("You must enter a variable name."); } else if (parentType == Type::Object) { From 8eade806157e5bf281f68050ae8cbe3b2c0bab9d Mon Sep 17 00:00:00 2001 From: Palagiri Subbareddy Date: Thu, 25 Jun 2026 16:20:59 +0530 Subject: [PATCH 2/5] test: update assertions to match the new error context --- Core/tests/ExpressionParser2.cpp | 12 ++++++------ GDevelop.js/__tests__/Core.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/tests/ExpressionParser2.cpp b/Core/tests/ExpressionParser2.cpp index 1b469cdcd350..2dd7c8f7ec4b 100644 --- a/Core/tests/ExpressionParser2.cpp +++ b/Core/tests/ExpressionParser2.cpp @@ -87,7 +87,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { node->Visit(validator); REQUIRE(validator.GetFatalErrors().size() == 1); REQUIRE(validator.GetFatalErrors()[0]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call."); + "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); } SECTION("of type number") { auto node = parser.ParseExpression(""); @@ -306,7 +306,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { REQUIRE(validator.GetFatalErrors().size() == 1); REQUIRE( validator.GetFatalErrors()[0]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call."); + "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); } { auto node = parser.ParseExpression("abcd"); @@ -473,7 +473,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { "You must add the operator + between texts or expressions. For " "example: \"Your name: \" + VariableString(PlayerName)."); REQUIRE(validator.GetFatalErrors()[2]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call."); + "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); REQUIRE(validator.GetFatalErrors()[1]->GetMessage() == "The expression has extra character at the end that should be " @@ -492,7 +492,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { "You must add the operator + between texts or expressions. For " "example: \"Your name: \" + VariableString(PlayerName)."); REQUIRE(validator.GetFatalErrors()[2]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call."); + "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); REQUIRE(validator.GetFatalErrors()[1]->GetMessage() == "The expression has extra character at the end that should be " @@ -535,7 +535,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { REQUIRE(validator.GetFatalErrors().size() == 1); REQUIRE( validator.GetFatalErrors()[0]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call."); + "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); } } @@ -570,7 +570,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { "The expression has extra character at the end that should be " "removed (or completed if your expression is not finished)."); REQUIRE(validator.GetFatalErrors()[3]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call."); + "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); } } diff --git a/GDevelop.js/__tests__/Core.js b/GDevelop.js/__tests__/Core.js index 6f50642e8041..ba7146ac0eab 100644 --- a/GDevelop.js/__tests__/Core.js +++ b/GDevelop.js/__tests__/Core.js @@ -3984,7 +3984,7 @@ describe('libGD.js', function () { testExpression( 'string', '="Mynewscene"', - 'You must enter a text (between quotes) or a valid expression call.', + 'You must enter a text (between quotes) or a valid expression call. Please check your event parameters.', 0 ); }); From 8f0a5e36ab3ed989a6de40543099b9a30d870ebf Mon Sep 17 00:00:00 2001 From: Palagiri Subbareddy Date: Fri, 26 Jun 2026 15:25:11 +0530 Subject: [PATCH 3/5] Revert "fix(core): enhance empty string expression validation error context (#8762)" This reverts commit f814b926dd7e9920a4c934b8c4ac12c8cfba17e7. --- Core/GDCore/IDE/Events/ExpressionValidator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/GDCore/IDE/Events/ExpressionValidator.h b/Core/GDCore/IDE/Events/ExpressionValidator.h index 9daeb298111e..c46f4724ef90 100644 --- a/Core/GDCore/IDE/Events/ExpressionValidator.h +++ b/Core/GDCore/IDE/Events/ExpressionValidator.h @@ -375,7 +375,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker { message = _("You must enter a number or a valid expression call."); } else if (parentType == Type::String) { message = _( - "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); + "You must enter a text (between quotes) or a valid expression call."); } else if (parentType == Type::Variable || parentType == Type::LegacyVariable) { message = _("You must enter a variable name."); } else if (parentType == Type::Object) { From 80b04db76aaec4b5c95fd606403a56e82d1a309b Mon Sep 17 00:00:00 2001 From: Palagiri Subbareddy Date: Fri, 26 Jun 2026 15:25:11 +0530 Subject: [PATCH 4/5] Revert "test: update assertions to match the new error context" This reverts commit 8eade806157e5bf281f68050ae8cbe3b2c0bab9d. --- Core/tests/ExpressionParser2.cpp | 12 ++++++------ GDevelop.js/__tests__/Core.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/tests/ExpressionParser2.cpp b/Core/tests/ExpressionParser2.cpp index 2dd7c8f7ec4b..1b469cdcd350 100644 --- a/Core/tests/ExpressionParser2.cpp +++ b/Core/tests/ExpressionParser2.cpp @@ -87,7 +87,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { node->Visit(validator); REQUIRE(validator.GetFatalErrors().size() == 1); REQUIRE(validator.GetFatalErrors()[0]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); + "You must enter a text (between quotes) or a valid expression call."); } SECTION("of type number") { auto node = parser.ParseExpression(""); @@ -306,7 +306,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { REQUIRE(validator.GetFatalErrors().size() == 1); REQUIRE( validator.GetFatalErrors()[0]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); + "You must enter a text (between quotes) or a valid expression call."); } { auto node = parser.ParseExpression("abcd"); @@ -473,7 +473,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { "You must add the operator + between texts or expressions. For " "example: \"Your name: \" + VariableString(PlayerName)."); REQUIRE(validator.GetFatalErrors()[2]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); + "You must enter a text (between quotes) or a valid expression call."); REQUIRE(validator.GetFatalErrors()[1]->GetMessage() == "The expression has extra character at the end that should be " @@ -492,7 +492,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { "You must add the operator + between texts or expressions. For " "example: \"Your name: \" + VariableString(PlayerName)."); REQUIRE(validator.GetFatalErrors()[2]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); + "You must enter a text (between quotes) or a valid expression call."); REQUIRE(validator.GetFatalErrors()[1]->GetMessage() == "The expression has extra character at the end that should be " @@ -535,7 +535,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { REQUIRE(validator.GetFatalErrors().size() == 1); REQUIRE( validator.GetFatalErrors()[0]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); + "You must enter a text (between quotes) or a valid expression call."); } } @@ -570,7 +570,7 @@ TEST_CASE("ExpressionParser2", "[common][events]") { "The expression has extra character at the end that should be " "removed (or completed if your expression is not finished)."); REQUIRE(validator.GetFatalErrors()[3]->GetMessage() == - "You must enter a text (between quotes) or a valid expression call. Please check your event parameters."); + "You must enter a text (between quotes) or a valid expression call."); } } diff --git a/GDevelop.js/__tests__/Core.js b/GDevelop.js/__tests__/Core.js index ba7146ac0eab..6f50642e8041 100644 --- a/GDevelop.js/__tests__/Core.js +++ b/GDevelop.js/__tests__/Core.js @@ -3984,7 +3984,7 @@ describe('libGD.js', function () { testExpression( 'string', '="Mynewscene"', - 'You must enter a text (between quotes) or a valid expression call. Please check your event parameters.', + 'You must enter a text (between quotes) or a valid expression call.', 0 ); }); From 0a11545c0ccb1dbbc95474ac7d60c65da1e1ce73 Mon Sep 17 00:00:00 2001 From: Palagiri Subbareddy Date: Fri, 26 Jun 2026 16:08:59 +0530 Subject: [PATCH 5/5] fix(core): dynamically pass context to expression validation errors (#8762) This introduces a dynamic context parameter to ExpressionValidator, allowing callers (like InstructionValidator and event loops) to provide exact parameter descriptions (e.g., 'Parameter: X position', 'Parameter: Number of repeats'). This prevents the incorrect hardcoding of 'event parameters' across all expression usages. --- Core/GDCore/Events/Builtin/RepeatEvent.cpp | 4 ++-- Core/GDCore/IDE/Events/ExpressionValidator.cpp | 6 ++++++ Core/GDCore/IDE/Events/ExpressionValidator.h | 12 ++++++++++-- Core/GDCore/IDE/InstructionValidator.cpp | 3 ++- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Core/GDCore/Events/Builtin/RepeatEvent.cpp b/Core/GDCore/Events/Builtin/RepeatEvent.cpp index 48bf0900a6b1..b9c952a21926 100644 --- a/Core/GDCore/Events/Builtin/RepeatEvent.cpp +++ b/Core/GDCore/Events/Builtin/RepeatEvent.cpp @@ -49,7 +49,7 @@ vector > RepeatEvent::GetAllExpressionsWithMetadata() { vector > allExpressionsWithMetadata; - auto metadata = gd::ParameterMetadata().SetType("number"); + auto metadata = gd::ParameterMetadata().SetType("number").SetDescription(_("Number of repeats")); allExpressionsWithMetadata.push_back( std::make_pair(&repeatNumberExpression, metadata)); @@ -75,7 +75,7 @@ vector > RepeatEvent::GetAllExpressionsWithMetadata() const { vector > allExpressionsWithMetadata; - auto metadata = gd::ParameterMetadata().SetType("number"); + auto metadata = gd::ParameterMetadata().SetType("number").SetDescription(_("Number of repeats")); allExpressionsWithMetadata.push_back( std::make_pair(&repeatNumberExpression, metadata)); diff --git a/Core/GDCore/IDE/Events/ExpressionValidator.cpp b/Core/GDCore/IDE/Events/ExpressionValidator.cpp index cacb35887fa4..a46eff7ef705 100644 --- a/Core/GDCore/IDE/Events/ExpressionValidator.cpp +++ b/Core/GDCore/IDE/Events/ExpressionValidator.cpp @@ -408,7 +408,13 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction( parentType = StringToType(parameterMetadata.GetType()); auto parentParameterExtraInfo = currentParameterExtraInfo; currentParameterExtraInfo = ¶meterMetadata.GetExtraInfo(); + + auto parentParameterName = currentParameterName; + currentParameterName = parameterMetadata.GetDescription(); + parameter->Visit(*this); + + currentParameterName = parentParameterName; currentParameterExtraInfo = parentParameterExtraInfo; parentType = currentParentType; diff --git a/Core/GDCore/IDE/Events/ExpressionValidator.h b/Core/GDCore/IDE/Events/ExpressionValidator.h index c46f4724ef90..52ba9abc6624 100644 --- a/Core/GDCore/IDE/Events/ExpressionValidator.h +++ b/Core/GDCore/IDE/Events/ExpressionValidator.h @@ -40,7 +40,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker { ExpressionValidator(const gd::Platform &platform_, const gd::ProjectScopedContainers & projectScopedContainers_, const gd::String &rootType_, - const gd::String &extraInfo_ = emptyParameterExtraInfo) + const gd::String &extraInfo_ = emptyParameterExtraInfo, + const gd::String &contextDescription_ = "") : platform(platform_), projectScopedContainers(projectScopedContainers_), parentType(StringToType(gd::ValueTypeMetadata::GetExpressionPrimitiveValueType(rootType_))), @@ -48,7 +49,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker { forbidsUsageOfBracketsBecauseParentIsObject(false), currentParameterExtraInfo(&extraInfo_), variableObjectName(), - variableObjectNameLocation() {}; + variableObjectNameLocation(), + currentParameterName(contextDescription_) {}; virtual ~ExpressionValidator(){}; /** @@ -384,6 +386,11 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker { // It can't happen. message = _("You must enter a valid expression."); } + + if (!currentParameterName.empty()) { + message += " " + _("Parameter:") + " " + currentParameterName; + } + RaiseTypeError(message, node.location); childType = Type::Empty; } @@ -570,6 +577,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker { gd::String variableObjectName; gd::ExpressionParserLocation variableObjectNameLocation; const gd::String *currentParameterExtraInfo; + gd::String currentParameterName; const gd::Platform &platform; const gd::ProjectScopedContainers &projectScopedContainers; }; diff --git a/Core/GDCore/IDE/InstructionValidator.cpp b/Core/GDCore/IDE/InstructionValidator.cpp index 5608df5af254..2ed054325668 100644 --- a/Core/GDCore/IDE/InstructionValidator.cpp +++ b/Core/GDCore/IDE/InstructionValidator.cpp @@ -69,7 +69,8 @@ ParameterValidationResult InstructionValidator::ValidateParameter( *instruction.GetParameter(parameterIndex).GetRootNode(); ExpressionValidator expressionValidator(platform, projectScopedContainers, parameterType, - parameterMetadata.GetExtraInfo()); + parameterMetadata.GetExtraInfo(), + parameterMetadata.GetDescription()); expressionNode.Visit(expressionValidator); if (!expressionValidator.GetAllErrors().empty()) {