/* * GDevelop Core * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights * reserved. This project is released under the MIT License. */ #include "EventsVariablesFinder.h" #include "GDCore/Events/Event.h" #include "GDCore/Events/Instruction.h" #include "GDCore/Events/Parsers/ExpressionParser2.h" #include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h" #include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h" #include "GDCore/Extensions/Metadata/ExpressionMetadata.h" #include "GDCore/Extensions/Metadata/InstructionMetadata.h" #include "GDCore/Extensions/Metadata/MetadataProvider.h" #include "GDCore/Extensions/Platform.h" #include "GDCore/Project/Layout.h" #include "GDCore/Project/Object.h" #include "GDCore/Project/Project.h" using namespace std; namespace gd { /** * \brief Go through the nodes and change the given object name to a new one. * * \see gd::ExpressionParser2 */ class GD_CORE_API ExpressionParameterSearcher : public ExpressionParser2NodeWorker { public: ExpressionParameterSearcher(std::set& results_, const gd::String& parameterType_, const gd::String& objectName_ = "") : results(results_), parameterType(parameterType_), objectName(objectName_){}; virtual ~ExpressionParameterSearcher(){}; protected: void OnVisitSubExpressionNode(SubExpressionNode& node) override { node.expression->Visit(*this); } void OnVisitOperatorNode(OperatorNode& node) override { node.leftHandSide->Visit(*this); node.rightHandSide->Visit(*this); } void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override { node.factor->Visit(*this); } void OnVisitNumberNode(NumberNode& node) override {} void OnVisitTextNode(TextNode& node) override {} void OnVisitVariableNode(VariableNode& node) override { if (node.child) node.child->Visit(*this); } void OnVisitVariableAccessorNode(VariableAccessorNode& node) override { if (node.child) node.child->Visit(*this); } void OnVisitVariableBracketAccessorNode( VariableBracketAccessorNode& node) override { node.expression->Visit(*this); if (node.child) node.child->Visit(*this); } void OnVisitIdentifierNode(IdentifierNode& node) override {} void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {} void OnVisitFunctionCallNode(FunctionCallNode& node) override { bool considerFunction = objectName.empty() || node.objectName == objectName; for (size_t i = 0; i < node.parameters.size() && i < node.expressionMetadata.parameters.size(); ++i) { auto& parameterMetadata = node.expressionMetadata.parameters[i]; if (considerFunction && parameterMetadata.GetType() == parameterType) { // Store the value of the parameter results.insert( gd::ExpressionParser2NodePrinter::PrintNode(*node.parameters[i])); } else { node.parameters[i]->Visit(*this); } } } void OnVisitEmptyNode(EmptyNode& node) override {} private: std::set& results; ///< Reference to the std::set where argument ///< values must be stored. gd::String parameterType; ///< The type of the parameters to be searched for. gd::String objectName; ///< If not empty, parameters will be taken into ///< account only if related to this object. }; std::set EventsVariablesFinder::FindAllGlobalVariables( const gd::Platform& platform, const gd::Project& project) { std::set results; for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) { std::set results2 = FindArgumentsInEvents(platform, project, project.GetLayout(i), project.GetLayout(i).GetEvents(), "globalvar"); results.insert(results2.begin(), results2.end()); } return results; } std::set EventsVariablesFinder::FindAllLayoutVariables( const gd::Platform& platform, const gd::Project& project, const gd::Layout& layout) { std::set results; std::set results2 = FindArgumentsInEvents( platform, project, layout, layout.GetEvents(), "scenevar"); results.insert(results2.begin(), results2.end()); return results; } std::set EventsVariablesFinder::FindAllObjectVariables( const gd::Platform& platform, const gd::Project& project, const gd::Layout& layout, const gd::Object& object) { std::set results; std::set results2 = FindArgumentsInEvents(platform, project, layout, layout.GetEvents(), "objectvar", object.GetName()); results.insert(results2.begin(), results2.end()); return results; } std::set EventsVariablesFinder::FindArgumentsInInstructions( const gd::Platform& platform, const gd::Project& project, const gd::Layout& layout, const gd::InstructionsList& instructions, bool instructionsAreConditions, const gd::String& parameterType, const gd::String& objectName) { std::set results; for (std::size_t aId = 0; aId < instructions.size(); ++aId) { gd::String lastObjectParameter = ""; gd::InstructionMetadata instrInfos = instructionsAreConditions ? MetadataProvider::GetConditionMetadata( platform, instructions[aId].GetType()) : MetadataProvider::GetActionMetadata( platform, instructions[aId].GetType()); for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) { // The parameter has the searched type... if (instrInfos.parameters[pNb].type == parameterType) { //...remember the value of the parameter. if (objectName.empty() || lastObjectParameter == objectName) results.insert(instructions[aId].GetParameter(pNb).GetPlainString()); } // Search in expressions else if (ParameterMetadata::IsExpression( "number", instrInfos.parameters[pNb].type)) { gd::ExpressionParser2 parser(platform, project, layout); auto node = parser.ParseExpression( "number", instructions[aId].GetParameter(pNb).GetPlainString()); ExpressionParameterSearcher searcher( results, parameterType, objectName); node->Visit(searcher); } // Search in gd::String expressions else if (ParameterMetadata::IsExpression( "string", instrInfos.parameters[pNb].type)) { gd::ExpressionParser2 parser(platform, project, layout); auto node = parser.ParseExpression( "number", instructions[aId].GetParameter(pNb).GetPlainString()); ExpressionParameterSearcher searcher( results, parameterType, objectName); node->Visit(searcher); } // Remember the value of the last "object" parameter. else if (gd::ParameterMetadata::IsObject( instrInfos.parameters[pNb].type)) { lastObjectParameter = instructions[aId].GetParameter(pNb).GetPlainString(); } } if (!instructions[aId].GetSubInstructions().empty()) FindArgumentsInInstructions(platform, project, layout, instructions[aId].GetSubInstructions(), instructionsAreConditions, parameterType); } return results; } std::set EventsVariablesFinder::FindArgumentsInEvents( const gd::Platform& platform, const gd::Project& project, const gd::Layout& layout, const gd::EventsList& events, const gd::String& parameterType, const gd::String& objectName) { std::set results; for (std::size_t i = 0; i < events.size(); ++i) { vector conditionsVectors = events[i].GetAllConditionsVectors(); for (std::size_t j = 0; j < conditionsVectors.size(); ++j) { std::set results2 = FindArgumentsInInstructions(platform, project, layout, *conditionsVectors[j], /*conditions=*/true, parameterType, objectName); results.insert(results2.begin(), results2.end()); } vector actionsVectors = events[i].GetAllActionsVectors(); for (std::size_t j = 0; j < actionsVectors.size(); ++j) { std::set results2 = FindArgumentsInInstructions(platform, project, layout, *actionsVectors[j], /*conditions=*/false, parameterType, objectName); results.insert(results2.begin(), results2.end()); } if (events[i].CanHaveSubEvents()) { std::set results2 = FindArgumentsInEvents(platform, project, layout, events[i].GetSubEvents(), parameterType, objectName); results.insert(results2.begin(), results2.end()); } } return results; } } // namespace gd