diff --git a/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp b/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp index 7073fa21d3..9ac74a0a47 100644 --- a/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp +++ b/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.cpp @@ -19,10 +19,35 @@ #include "GDCore/Extensions/Metadata/ObjectMetadata.h" #include "GDCore/Extensions/Platform.h" #include "GDCore/Extensions/PlatformExtension.h" +#include "GDCore/IDE/Events/ExpressionValidator.h" #include "GDCore/Project/Layout.h" #include "GDCore/Project/Project.h" namespace gd { +gd::String ExpressionCodeGenerator::GenerateExpressionCode( + EventsCodeGenerator& codeGenerator, + EventsCodeGenerationContext& context, + const gd::String& type, + const gd::String& expression) { + gd::ExpressionParser2 parser(codeGenerator.GetPlatform(), + codeGenerator.GetGlobalObjectsAndGroups(), + codeGenerator.GetObjectsAndGroups()); + auto node = parser.ParseExpression(type, expression); + gd::ExpressionValidator validator; + node->Visit(validator); + if (!validator.GetErrors().empty()) { + std::cout << "Error: " << validator.GetErrors()[0]->GetMessage() + << " in: " << expression << std::endl; + + return GenerateDefaultValue(type); + } + + ExpressionCodeGenerator generator(codeGenerator, context); + node->Visit(generator); + + return generator.GetOutput(); +} + void ExpressionCodeGenerator::OnVisitOperatorNode(OperatorNode& node) { node.leftHandSide->Visit(*this); output += " "; @@ -254,10 +279,13 @@ gd::String ExpressionCodeGenerator::GenerateParametersCodes( parameters[nonCodeOnlyParameterIndex]->Visit(generator); parametersCode += generator.GetOutput(); } else if (parameterMetadata.IsOptional()) { - // Optional parameters default value were not parsed at the time of the expression parsing. - // Parse them now. - ExpressionParser2 parser(codeGenerator.GetPlatform(), codeGenerator.GetGlobalObjectsAndGroups(), codeGenerator.GetObjectsAndGroups()); - auto node = parser.ParseExpression(parameterMetadata.GetType(), parameterMetadata.GetDefaultValue()); + // Optional parameters default value were not parsed at the time of the + // expression parsing. Parse them now. + ExpressionParser2 parser(codeGenerator.GetPlatform(), + codeGenerator.GetGlobalObjectsAndGroups(), + codeGenerator.GetObjectsAndGroups()); + auto node = parser.ParseExpression(parameterMetadata.GetType(), + parameterMetadata.GetDefaultValue()); node->Visit(generator); parametersCode += generator.GetOutput(); diff --git a/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h b/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h index 70c49a6a14..32a9cadba0 100644 --- a/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h +++ b/Core/GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h @@ -8,6 +8,7 @@ #include #include +#include "GDCore/Events/Parsers/ExpressionParser2.h" #include "GDCore/Events/Parsers/ExpressionParser2Node.h" #include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h" #include "GDCore/String.h" @@ -36,6 +37,16 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker { : codeGenerator(codeGenerator_), context(context_){}; virtual ~ExpressionCodeGenerator(){}; + /** + * Helper to generate the code for an expression. + * If expression is invalid, a default generated value is returned (0 for + * number expression, empty string for strings). + */ + static gd::String GenerateExpressionCode(EventsCodeGenerator& codeGenerator, + EventsCodeGenerationContext& context, + const gd::String& type, + const gd::String& expression); + const gd::String& GetOutput() { return output; }; protected: @@ -53,24 +64,24 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker { private: gd::String GenerateFreeFunctionCode( - const std::vector> & parameters, + const std::vector>& parameters, const ExpressionMetadata& expressionMetadata); gd::String GenerateObjectFunctionCode( const gd::String& type, const gd::String& objectName, - const std::vector> & parameters, + const std::vector>& parameters, const ExpressionMetadata& expressionMetadata); gd::String GenerateBehaviorFunctionCode( const gd::String& type, const gd::String& objectName, const gd::String& behaviorName, - const std::vector> & parameters, + const std::vector>& parameters, const ExpressionMetadata& expressionMetadata); gd::String GenerateParametersCodes( - const std::vector> & parameters, + const std::vector>& parameters, const ExpressionMetadata& expressionMetadata, size_t initialParameterIndex); - gd::String GenerateDefaultValue(const gd::String & type); + static gd::String GenerateDefaultValue(const gd::String& type); gd::String output; EventsCodeGenerator& codeGenerator; diff --git a/Core/GDCore/Events/Parsers/ExpressionParser2.h b/Core/GDCore/Events/Parsers/ExpressionParser2.h index 1785965350..42b474b256 100644 --- a/Core/GDCore/Events/Parsers/ExpressionParser2.h +++ b/Core/GDCore/Events/Parsers/ExpressionParser2.h @@ -71,7 +71,7 @@ class GD_CORE_API ExpressionParser2 { op->rightHandSide->diagnostic = RaiseSyntaxError( _("The expression has extra character at the end that should be " "removed (or completed if your expression is not finished).")); - return op; + return std::move(op); } return expression; diff --git a/Core/tests/ExpressionCodeGenerator.cpp b/Core/tests/ExpressionCodeGenerator.cpp index 70a9e45754..a6dc36e7b8 100644 --- a/Core/tests/ExpressionCodeGenerator.cpp +++ b/Core/tests/ExpressionCodeGenerator.cpp @@ -166,29 +166,33 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") { context); node->Visit(expressionCodeGenerator); - REQUIRE(expressionCodeGenerator.GetOutput() == "getMouseX(\"\", \"layer1\", 0)"); + REQUIRE(expressionCodeGenerator.GetOutput() == + "getMouseX(\"\", \"layer1\", 0)"); // (first argument is the currentScene) } { - auto node = - parser.ParseExpression("number", "MyExtension::MouseX(\"layer1\",2+2)"); + auto node = parser.ParseExpression("number", + "MyExtension::MouseX(\"layer1\",2+2)"); gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator, context); node->Visit(expressionCodeGenerator); - REQUIRE(expressionCodeGenerator.GetOutput() == "getMouseX(\"\", \"layer1\", 2 + 2)"); + REQUIRE(expressionCodeGenerator.GetOutput() == + "getMouseX(\"\", \"layer1\", 2 + 2)"); // (first argument is the currentScene) } } - SECTION("Valid function calls (deprecated way of specifying optional arguments)") { + SECTION( + "Valid function calls (deprecated way of specifying optional " + "arguments)") { { - auto node = - parser.ParseExpression("number", "MyExtension::MouseX(,)"); + auto node = parser.ParseExpression("number", "MyExtension::MouseX(,)"); gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator, context); node->Visit(expressionCodeGenerator); - REQUIRE(expressionCodeGenerator.GetOutput() == "getMouseX(\"\", \"\", 0)"); + REQUIRE(expressionCodeGenerator.GetOutput() == + "getMouseX(\"\", \"\", 0)"); // (first argument is the currentScene) } } @@ -297,4 +301,19 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") { } } } + SECTION("Helper for code generation") { + gd::String output = gd::ExpressionCodeGenerator::GenerateExpressionCode( + codeGenerator, + context, + "number", + "MyExtension::GetVariableAsNumber(myVariable[ \"hello\" + " + "MySpriteObject.GetObjectStringWith1Param(MyOtherSpriteObject." + "GetObjectVariableAsNumber(mySecondVariable)) ].child2)"); + REQUIRE(output == + "returnVariable(getLayoutVariable(myVariable).getChild(\"hello\" + " + "MySpriteObject.getObjectStringWith1Param(MyOtherSpriteObject." + "returnVariable" + "(getVariableForObject(MyOtherSpriteObject, mySecondVariable)) ?? " + "0) ?? \"\").getChild(\"child2\"))"); + } }