Compare commits

..

1 Commits

572 changed files with 10454 additions and 20906 deletions

View File

@@ -65,7 +65,7 @@ jobs:
# To test signing the code in the CI, add "export CSC_FOR_PULL_REQUEST=true && " before the command.
- run:
name: Build GDevelop IDE
command: export CSC_FOR_PULL_REQUEST=true && export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && CI=false npm run build -- --mac --publish=never
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && CI=false npm run build -- --mac --publish=never
- run:
name: Clean dist folder to keep only installers/binaries.

View File

@@ -60,7 +60,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT WIN32 AND CMAKE_COMPILER_IS_
endif()
#Activate C++11
set(CMAKE_CXX_STANDARD 11) # Upgrading to C++17 would need to remove usage of bind2nd (should be easy).
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Mark some warnings as errors
@@ -77,8 +77,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
-Wno-unused-private-field
# Make as much warnings considered as errors as possible (only one for now).
-Werror=return-stack-address
-Werror=return-type)
-Werror=return-stack-address)
endif()
# Define common directories:

View File

@@ -45,39 +45,10 @@ ForEachChildVariableEvent::GetAllActionsVectors() const {
return allActions;
}
vector<pair<gd::Expression*, gd::ParameterMetadata> >
ForEachChildVariableEvent::GetAllExpressionsWithMetadata() {
vector<pair<gd::Expression*, gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("scenevar");
allExpressionsWithMetadata.push_back(
std::make_pair(&iterableVariableName, metadata));
allExpressionsWithMetadata.push_back(
std::make_pair(&valueIteratorVariableName, metadata));
allExpressionsWithMetadata.push_back(
std::make_pair(&keyIteratorVariableName, metadata));
return allExpressionsWithMetadata;
}
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
ForEachChildVariableEvent::GetAllExpressionsWithMetadata() const {
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("scenevar");
allExpressionsWithMetadata.push_back(
std::make_pair(&iterableVariableName, metadata));
allExpressionsWithMetadata.push_back(
std::make_pair(&valueIteratorVariableName, metadata));
allExpressionsWithMetadata.push_back(
std::make_pair(&keyIteratorVariableName, metadata));
return allExpressionsWithMetadata;
}
void ForEachChildVariableEvent::SerializeTo(SerializerElement& element) const {
element.AddChild("iterableVariableName").SetValue(iterableVariableName.GetPlainString());
element.AddChild("valueIteratorVariableName").SetValue(valueIteratorVariableName.GetPlainString());
element.AddChild("keyIteratorVariableName").SetValue(keyIteratorVariableName.GetPlainString());
element.AddChild("iterableVariableName").SetValue(iterableVariableName);
element.AddChild("valueIteratorVariableName").SetValue(valueIteratorVariableName);
element.AddChild("keyIteratorVariableName").SetValue(keyIteratorVariableName);
gd::EventsListSerialization::SerializeInstructionsTo(
conditions, element.AddChild("conditions"));
gd::EventsListSerialization::SerializeInstructionsTo(

View File

@@ -8,7 +8,6 @@
#define FOREACHCHILDVARIABLEEVENT_H
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Expression.h"
namespace gd {
class Instruction;
class Project;
@@ -45,7 +44,7 @@ class GD_CORE_API ForEachChildVariableEvent : public gd::BaseEvent {
*
* It is the structure variable that will be iterated on.
*/
const gd::String& GetIterableVariableName() const { return iterableVariableName.GetPlainString(); };
const gd::String& GetIterableVariableName() const { return iterableVariableName; };
/**
* \brief Set the iterable variable name attached to the event.
@@ -57,15 +56,15 @@ class GD_CORE_API ForEachChildVariableEvent : public gd::BaseEvent {
/**
* \brief Get the value iterator variable attached to the event.
*
* It is the variable that will contain the value of the
* It is the variable that will contain the value of the
* iterable's child being iterated on.
*/
const gd::String& GetValueIteratorVariableName() const { return valueIteratorVariableName.GetPlainString(); };
const gd::String& GetValueIteratorVariableName() const { return valueIteratorVariableName; };
/**
* \brief Set the value iterator variable attached to the event.
*
* It is the variable that will contain the value of the
* It is the variable that will contain the value of the
* iterable's child being iterated on.
*/
void SetValueIteratorVariableName(gd::String newName) { valueIteratorVariableName = newName; };
@@ -73,15 +72,15 @@ class GD_CORE_API ForEachChildVariableEvent : public gd::BaseEvent {
/**
* \brief Get the key iterator variable attached to the event.
*
* It is the variable that will contain the name of the
* It is the variable that will contain the name of the
* iterable's child being iterated on.
*/
const gd::String& GetKeyIteratorVariableName() const { return keyIteratorVariableName.GetPlainString(); };
const gd::String& GetKeyIteratorVariableName() const { return keyIteratorVariableName; };
/**
* \brief Set the key iterator variable attached to the event.
*
* It is the variable that will contain the name of the
* It is the variable that will contain the name of the
* iterable's child being iterated on.
*/
void SetKeyIteratorVariableName(gd::String newName) { keyIteratorVariableName = newName; };
@@ -93,19 +92,14 @@ class GD_CORE_API ForEachChildVariableEvent : public gd::BaseEvent {
virtual std::vector<gd::InstructionsList*> GetAllConditionsVectors();
virtual std::vector<gd::InstructionsList*> GetAllActionsVectors();
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() const;
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
GetAllExpressionsWithMetadata();
virtual void SerializeTo(SerializerElement& element) const;
virtual void UnserializeFrom(gd::Project& project,
const SerializerElement& element);
private:
gd::Expression valueIteratorVariableName;
gd::Expression keyIteratorVariableName;
gd::Expression iterableVariableName;
gd::String valueIteratorVariableName;
gd::String keyIteratorVariableName;
gd::String iterableVariableName;
gd::InstructionsList conditions;
gd::InstructionsList actions;
gd::EventsList events;

View File

@@ -64,6 +64,12 @@ class GD_CORE_API ForEachEvent : public gd::BaseEvent {
virtual void UnserializeFrom(gd::Project& project,
const SerializerElement& element);
std::vector<gd::Expression*> GetAllObjectExpressions() {
std::vector<gd::Expression*> allObjectExpressions;
allObjectExpressions.push_back(&objectsToPick);
return allObjectExpressions;
}
private:
gd::Expression objectsToPick;
gd::InstructionsList conditions;

View File

@@ -35,7 +35,7 @@ vector<pair<gd::Expression*, gd::ParameterMetadata> >
RepeatEvent::GetAllExpressionsWithMetadata() {
vector<pair<gd::Expression*, gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("number");
auto metadata = gd::ParameterMetadata().SetType("expression");
allExpressionsWithMetadata.push_back(
std::make_pair(&repeatNumberExpression, metadata));
@@ -61,7 +61,7 @@ vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
RepeatEvent::GetAllExpressionsWithMetadata() const {
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("number");
auto metadata = gd::ParameterMetadata().SetType("expression");
allExpressionsWithMetadata.push_back(
std::make_pair(&repeatNumberExpression, metadata));

View File

@@ -16,7 +16,6 @@
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/Project/Project.h"
using namespace std;
@@ -296,10 +295,16 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
gd::String objectInParameter =
condition.GetParameter(pNb).GetPlainString();
if (!GetObjectsContainersList().HasObjectOrGroupNamed(objectInParameter)) {
if (!GetObjectsAndGroups().HasObjectNamed(objectInParameter) &&
!GetGlobalObjectsAndGroups().HasObjectNamed(objectInParameter) &&
!GetObjectsAndGroups().GetObjectGroups().Has(objectInParameter) &&
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(
objectInParameter)) {
return "/* Unknown object - skipped. */";
} else if (!instrInfos.parameters[pNb].GetExtraInfo().empty() &&
GetObjectsContainersList().GetTypeOfObject(objectInParameter) !=
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(),
GetObjectsAndGroups(),
objectInParameter) !=
instrInfos.parameters[pNb].GetExtraInfo()) {
return "/* Mismatched object type - skipped. */";
}
@@ -310,10 +315,11 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
gd::String objectName = condition.GetParameter(0).GetPlainString();
if (!objectName.empty() && !instrInfos.parameters.empty()) {
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
ExpandObjectsName(objectName, context);
for (std::size_t i = 0; i < realObjects.size(); ++i) {
// Set up the context
gd::String objectType = GetObjectsContainersList().GetTypeOfObject(realObjects[i]);
gd::String objectType = gd::GetTypeOfObject(
GetGlobalObjectsAndGroups(), GetObjectsAndGroups(), realObjects[i]);
const ObjectMetadata& objInfo =
MetadataProvider::GetObjectMetadata(platform, objectType);
@@ -337,10 +343,13 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
}
} else if (instrInfos.IsBehaviorInstruction()) {
gd::String objectName = condition.GetParameter(0).GetPlainString();
gd::String behaviorType = GetObjectsContainersList().GetTypeOfBehavior(condition.GetParameter(1).GetPlainString());
gd::String behaviorType =
gd::GetTypeOfBehavior(GetGlobalObjectsAndGroups(),
GetObjectsAndGroups(),
condition.GetParameter(1).GetPlainString());
if (instrInfos.parameters.size() >= 2) {
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
ExpandObjectsName(objectName, context);
for (std::size_t i = 0; i < realObjects.size(); ++i) {
// Setup context
const BehaviorMetadata& autoInfo =
@@ -470,10 +479,16 @@ gd::String EventsCodeGenerator::GenerateActionCode(
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
gd::String objectInParameter = action.GetParameter(pNb).GetPlainString();
if (!GetObjectsContainersList().HasObjectOrGroupNamed(objectInParameter)) {
if (!GetObjectsAndGroups().HasObjectNamed(objectInParameter) &&
!GetGlobalObjectsAndGroups().HasObjectNamed(objectInParameter) &&
!GetObjectsAndGroups().GetObjectGroups().Has(objectInParameter) &&
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(
objectInParameter)) {
return "/* Unknown object - skipped. */";
} else if (!instrInfos.parameters[pNb].GetExtraInfo().empty() &&
GetObjectsContainersList().GetTypeOfObject(objectInParameter) !=
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(),
GetObjectsAndGroups(),
objectInParameter) !=
instrInfos.parameters[pNb].GetExtraInfo()) {
return "/* Mismatched object type - skipped. */";
}
@@ -486,10 +501,11 @@ gd::String EventsCodeGenerator::GenerateActionCode(
if (!instrInfos.parameters.empty()) {
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
ExpandObjectsName(objectName, context);
for (std::size_t i = 0; i < realObjects.size(); ++i) {
// Setup context
gd::String objectType = GetObjectsContainersList().GetTypeOfObject(realObjects[i]);
gd::String objectType = gd::GetTypeOfObject(
GetGlobalObjectsAndGroups(), GetObjectsAndGroups(), realObjects[i]);
const ObjectMetadata& objInfo =
MetadataProvider::GetObjectMetadata(platform, objectType);
@@ -513,11 +529,14 @@ gd::String EventsCodeGenerator::GenerateActionCode(
}
} else if (instrInfos.IsBehaviorInstruction()) {
gd::String objectName = action.GetParameter(0).GetPlainString();
gd::String behaviorType = GetObjectsContainersList().GetTypeOfBehavior(action.GetParameter(1).GetPlainString());
gd::String behaviorType =
gd::GetTypeOfBehavior(GetGlobalObjectsAndGroups(),
GetObjectsAndGroups(),
action.GetParameter(1).GetPlainString());
if (instrInfos.parameters.size() >= 2) {
std::vector<gd::String> realObjects =
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
ExpandObjectsName(objectName, context);
for (std::size_t i = 0; i < realObjects.size(); ++i) {
// Setup context
const BehaviorMetadata& autoInfo =
@@ -893,6 +912,41 @@ gd::String EventsCodeGenerator::ConvertToStringExplicit(
return "\"" + ConvertToString(plainString) + "\"";
}
std::vector<gd::String> EventsCodeGenerator::ExpandObjectsName(
const gd::String& objectName,
const EventsCodeGenerationContext& context) const {
// Note: this logic is duplicated in EventsContextAnalyzer::ExpandObjectsName
std::vector<gd::String> realObjects;
if (globalObjectsAndGroups.GetObjectGroups().Has(objectName))
realObjects = globalObjectsAndGroups.GetObjectGroups()
.Get(objectName)
.GetAllObjectsNames();
else if (objectsAndGroups.GetObjectGroups().Has(objectName))
realObjects =
objectsAndGroups.GetObjectGroups().Get(objectName).GetAllObjectsNames();
else
realObjects.push_back(objectName);
// If current object is present, use it and only it.
if (find(realObjects.begin(),
realObjects.end(),
context.GetCurrentObject()) != realObjects.end()) {
realObjects.clear();
realObjects.push_back(context.GetCurrentObject());
}
// Ensure that all returned objects actually exists.
for (std::size_t i = 0; i < realObjects.size();) {
if (!objectsAndGroups.HasObjectNamed(realObjects[i]) &&
!globalObjectsAndGroups.HasObjectNamed(realObjects[i]))
realObjects.erase(realObjects.begin() + i);
else
++i;
}
return realObjects;
}
void EventsCodeGenerator::DeleteUselessEvents(gd::EventsList& events) {
for (std::size_t eId = events.size() - 1; eId < events.size(); --eId) {
if (events[eId].CanHaveSubEvents()) // Process sub events, if any
@@ -1208,24 +1262,12 @@ gd::String EventsCodeGenerator::GenerateArgumentsList(
return argumentsStr;
}
gd::String EventsCodeGenerator::GeneratePropertyGetter(const gd::PropertiesContainer& propertiesContainer,
const gd::NamedPropertyDescriptor& property,
const gd::String& type,
gd::EventsCodeGenerationContext& context) {
return "getProperty" + property.GetName() + "()";
}
gd::String EventsCodeGenerator::GenerateParameterGetter(const gd::ParameterMetadata& parameter,
const gd::String& type,
gd::EventsCodeGenerationContext& context) {
return "getParameter" + parameter.GetName() + "()";
}
EventsCodeGenerator::EventsCodeGenerator(const gd::Project& project_,
const gd::Layout& layout,
const gd::Platform& platform_)
: platform(platform_),
projectScopedContainers(gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project_, layout)),
globalObjectsAndGroups(project_),
objectsAndGroups(layout),
hasProjectAndLayout(true),
project(&project_),
scene(&layout),
@@ -1237,9 +1279,11 @@ EventsCodeGenerator::EventsCodeGenerator(const gd::Project& project_,
EventsCodeGenerator::EventsCodeGenerator(
const gd::Platform& platform_,
const gd::ProjectScopedContainers& projectScopedContainers_)
const gd::ObjectsContainer& globalObjectsAndGroups_,
const gd::ObjectsContainer& objectsAndGroups_)
: platform(platform_),
projectScopedContainers(projectScopedContainers_),
globalObjectsAndGroups(globalObjectsAndGroups_),
objectsAndGroups(objectsAndGroups_),
hasProjectAndLayout(false),
project(nullptr),
scene(nullptr),

View File

@@ -13,14 +13,12 @@
#include "GDCore/Events/Event.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/String.h"
#include "GDCore/Project/ProjectScopedContainers.h"
namespace gd {
class EventsList;
class Expression;
class Project;
class Layout;
class ObjectsContainer;
class ObjectsContainersList;
class ExternalEvents;
class ParameterMetadata;
class ObjectMetadata;
@@ -59,7 +57,8 @@ class GD_CORE_API EventsCodeGenerator {
* objects/groups and platform
*/
EventsCodeGenerator(const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers_);
const gd::ObjectsContainer& globalObjectsAndGroups_,
const gd::ObjectsContainer& objectsAndGroups_);
virtual ~EventsCodeGenerator(){};
/**
@@ -327,12 +326,18 @@ class GD_CORE_API EventsCodeGenerator {
*/
bool ErrorOccurred() const { return errorOccurred; };
const gd::ObjectsContainersList& GetObjectsContainersList() const {
return projectScopedContainers.GetObjectsContainersList();
};
/**
* \brief Get the global objects/groups used for code generation.
*/
const gd::ObjectsContainer& GetGlobalObjectsAndGroups() const {
return globalObjectsAndGroups;
}
const gd::ProjectScopedContainers& GetProjectScopedContainers() const {
return projectScopedContainers;
/**
* \brief Get the objects/groups used for code generation.
*/
const gd::ObjectsContainer& GetObjectsAndGroups() const {
return objectsAndGroups;
}
/**
@@ -358,6 +363,22 @@ class GD_CORE_API EventsCodeGenerator {
*/
const gd::Platform& GetPlatform() const { return platform; }
/**
* \brief Convert a group name to the full list of objects contained in the
* group.
*
* Get a list containing the "real" objects name when the events refers to \a
* objectName :<br> If \a objectName is really an object, the list will only
* contains \a objectName unchanged.<br> If \a objectName is a group, the list
* will contains all the objects of the group.<br> If \a objectName is the
* "current" object in the context ( i.e: The object being used for launching
* an action... ), none of the two rules below apply, and the list will only
* contains the context "current" object name.
*/
std::vector<gd::String> ExpandObjectsName(
const gd::String& objectName,
const EventsCodeGenerationContext& context) const;
/**
* \brief Get the maximum depth of custom conditions reached during code
* generation.
@@ -545,10 +566,6 @@ class GD_CORE_API EventsCodeGenerator {
return ".getChild(" + ConvertToStringExplicit(childName) + ")";
};
virtual gd::String GenerateVariableValueAs(const gd::String& type) {
return type == "string" ? ".getAsString()" : ".getAsNumber()";
}
/**
* \brief Generate the code to get the child of a variable,
* using generated the expression.
@@ -577,15 +594,6 @@ class GD_CORE_API EventsCodeGenerator {
return "fakeObjectListOf_" + objectName;
}
virtual gd::String GeneratePropertyGetter(const gd::PropertiesContainer& propertiesContainer,
const gd::NamedPropertyDescriptor& property,
const gd::String& type,
gd::EventsCodeGenerationContext& context);
virtual gd::String GenerateParameterGetter(const gd::ParameterMetadata& parameter,
const gd::String& type,
gd::EventsCodeGenerationContext& context);
/**
* \brief Generate the code to reference an object which is
* in an empty/null state.
@@ -769,7 +777,8 @@ class GD_CORE_API EventsCodeGenerator {
const gd::Platform& platform; ///< The platform being used.
gd::ProjectScopedContainers projectScopedContainers;
const gd::ObjectsContainer& globalObjectsAndGroups;
const gd::ObjectsContainer& objectsAndGroups;
bool hasProjectAndLayout; ///< true only if project and layout are valid
///< references. If false, they should not be used.

View File

@@ -7,7 +7,6 @@
#include <memory>
#include <vector>
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
@@ -26,9 +25,6 @@
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/VariablesContainersList.h"
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
@@ -51,7 +47,8 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
}
gd::ExpressionValidator validator(codeGenerator.GetPlatform(),
codeGenerator.GetProjectScopedContainers(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType);
node->Visit(validator);
if (!validator.GetFatalErrors().empty()) {
@@ -103,94 +100,34 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
// This "translation" from the type to an enum could be avoided
// if all types were moved to an enum.
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType,
node);
if (gd::ParameterMetadata::IsExpression("variable", type)) {
// The node is a variable inside an expression waiting for a *variable* to be returned, not its value.
EventsCodeGenerator::VariableScope scope =
type == "globalvar"
? gd::EventsCodeGenerator::PROJECT_VARIABLE
: ((type == "scenevar")
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
rootObjectName,
node);
output += codeGenerator.GenerateGetVariable(
node.name, scope, context, objectName);
if (node.child) node.child->Visit(*this);
} else {
// The node represents a variable or an object variable in an expression waiting for its *value* to be returned.
codeGenerator.GetProjectScopedContainers().MatchIdentifierWithName<void>(node.name, [&](){
// Generate the code to access the object variables.
// Defer generation of the access to the object and variable to the child,
// once we know the name of the variable.
objectNameToUseForVariableAccessor = node.name;
if (node.child) node.child->Visit(*this);
objectNameToUseForVariableAccessor = "";
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
if (!codeGenerator.HasProjectAndLayout()) {
gd::LogWarning("Tried to generate access to a variable without a project/scene - the code generator only works for global and scene variables for now.");
output += GenerateDefaultValue(type);
return;
}
// This could be adapted in the future if more scopes are supported.
EventsCodeGenerator::VariableScope scope = gd::EventsCodeGenerator::PROJECT_VARIABLE;
if (codeGenerator.GetProjectScopedContainers().GetVariablesContainersList().GetBottomMostVariablesContainer()->Has(node.name)) {
scope = gd::EventsCodeGenerator::LAYOUT_VARIABLE;
}
output += codeGenerator.GenerateGetVariable(node.name, scope, context, "");
if (node.child) node.child->Visit(*this);
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
// Properties are not supported.
output += GenerateDefaultValue(type);
}, [&]() {
// Parameters are not supported.
output += GenerateDefaultValue(type);
}, [&]() {
// The identifier does not represents a variable (or a child variable), or not at least an existing
// one, nor an object variable. It's invalid.
output += GenerateDefaultValue(type);
});
}
EventsCodeGenerator::VariableScope scope =
type == "globalvar"
? gd::EventsCodeGenerator::PROJECT_VARIABLE
: ((type == "scenevar")
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootObjectName,
node);
output += codeGenerator.GenerateGetVariable(
node.name, scope, context, objectName);
if (node.child) node.child->Visit(*this);
}
void ExpressionCodeGenerator::OnVisitVariableAccessorNode(
VariableAccessorNode& node) {
if (!objectNameToUseForVariableAccessor.empty()) {
// Use the name of the object passed by the parent, as we need both to access an object variable.
output += codeGenerator.GenerateGetVariable(node.name,
gd::EventsCodeGenerator::OBJECT_VARIABLE, context, objectNameToUseForVariableAccessor);
// We have accessed an object variable, from now we can continue accessing the child variables
// (including using the bracket notation).
objectNameToUseForVariableAccessor = "";
} else {
output += codeGenerator.GenerateVariableAccessor(node.name);
}
output += codeGenerator.GenerateVariableAccessor(node.name);
if (node.child) node.child->Visit(*this);
}
void ExpressionCodeGenerator::OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) {
if (!objectNameToUseForVariableAccessor.empty()) {
// Bracket notation can't be used to directly access a variable of an object (`MyObject["MyVariable"]`).
// This would be rejected by the ExpressionValidator.
output += codeGenerator.GenerateBadVariable();
return;
}
ExpressionCodeGenerator generator("string", "", codeGenerator, context);
node.expression->Visit(generator);
output +=
@@ -200,10 +137,10 @@ void ExpressionCodeGenerator::OnVisitVariableBracketAccessorNode(
void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType,
node);
if (gd::ParameterMetadata::IsObject(type)) {
output +=
codeGenerator.GenerateObject(node.identifierName, type, context);
@@ -216,7 +153,8 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootObjectName,
node);
output += codeGenerator.GenerateGetVariable(
@@ -224,60 +162,30 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
if (!node.childIdentifierName.empty()) {
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
}
} else {
const auto& variablesContainersList = codeGenerator.GetProjectScopedContainers().GetVariablesContainersList();
const auto& propertiesContainersList = codeGenerator.GetProjectScopedContainers().GetPropertiesContainersList();
const auto& parametersVectorsList = codeGenerator.GetProjectScopedContainers().GetParametersVectorsList();
// The node represents a variable, property, parameter or an object.
codeGenerator.GetProjectScopedContainers().MatchIdentifierWithName<void>(node.identifierName, [&]() {
// Generate the code to access the object variable.
output += codeGenerator.GenerateGetVariable(
node.childIdentifierName, gd::EventsCodeGenerator::OBJECT_VARIABLE, context, node.identifierName);
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
if (!codeGenerator.HasProjectAndLayout()) {
gd::LogWarning("Tried to generate access to a variable without a project/scene - the code generator only works for global and scene variables for now.");
output += GenerateDefaultValue(type);
return;
}
// This could be adapted in the future if more scopes are supported at runtime.
EventsCodeGenerator::VariableScope scope = gd::EventsCodeGenerator::PROJECT_VARIABLE;
if (variablesContainersList.GetBottomMostVariablesContainer()->Has(node.identifierName)) {
scope = gd::EventsCodeGenerator::LAYOUT_VARIABLE;
}
output += codeGenerator.GenerateGetVariable(node.identifierName, scope, context, "");
if (!node.childIdentifierName.empty()) {
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
}
output += codeGenerator.GenerateVariableValueAs(type);
}, [&]() {
const auto& propertiesContainerAndProperty = propertiesContainersList.Get(node.identifierName);
output += codeGenerator.GeneratePropertyGetter(
propertiesContainerAndProperty.first, propertiesContainerAndProperty.second, type, context);
}, [&]() {
const auto& parameter = gd::ParameterMetadataTools::Get(parametersVectorsList, node.identifierName);
output += codeGenerator.GenerateParameterGetter(parameter, type, context);
}, [&]() {
// The identifier does not represents a variable (or a child variable), or not at least an existing
// one, nor an object variable. It's invalid.
output += GenerateDefaultValue(type);
});
} else if (node.childIdentifierName.empty()) {
output += "/* Error during generation, unrecognized identifier type: " +
codeGenerator.ConvertToString(type) + " with value " +
codeGenerator.ConvertToString(node.identifierName) + " */ " +
codeGenerator.ConvertToStringExplicit(node.identifierName);
}
else {
// This is for function names that are put in IdentifierNode
// because the type is needed to tell them apart from variables.
output += GenerateDefaultValue(type);
}
}
void ExpressionCodeGenerator::OnVisitFunctionCallNode(FunctionCallNode& node) {
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType,
node);
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
node);
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
@@ -328,6 +236,11 @@ gd::String ExpressionCodeGenerator::GenerateObjectFunctionCode(
const gd::String& objectName,
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata) {
const gd::ObjectsContainer& globalObjectsAndGroups =
codeGenerator.GetGlobalObjectsAndGroups();
const gd::ObjectsContainer& objectsAndGroups =
codeGenerator.GetObjectsAndGroups();
codeGenerator.AddIncludeFiles(
expressionMetadata.GetIncludeFiles());
@@ -348,11 +261,12 @@ gd::String ExpressionCodeGenerator::GenerateObjectFunctionCode(
// Get object(s) concerned by function call
std::vector<gd::String> realObjects =
codeGenerator.GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
codeGenerator.ExpandObjectsName(objectName, context);
for (std::size_t i = 0; i < realObjects.size(); ++i) {
context.ObjectsListNeeded(realObjects[i]);
gd::String objectType = codeGenerator.GetObjectsContainersList().GetTypeOfObject(realObjects[i]);
gd::String objectType = gd::GetTypeOfObject(
globalObjectsAndGroups, objectsAndGroups, realObjects[i]);
const ObjectMetadata& objInfo = MetadataProvider::GetObjectMetadata(
codeGenerator.GetPlatform(), objectType);
@@ -374,6 +288,11 @@ gd::String ExpressionCodeGenerator::GenerateBehaviorFunctionCode(
const gd::String& behaviorName,
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata) {
const gd::ObjectsContainer& globalObjectsAndGroups =
codeGenerator.GetGlobalObjectsAndGroups();
const gd::ObjectsContainer& objectsAndGroups =
codeGenerator.GetObjectsAndGroups();
codeGenerator.AddIncludeFiles(
expressionMetadata.GetIncludeFiles());
@@ -392,11 +311,12 @@ gd::String ExpressionCodeGenerator::GenerateBehaviorFunctionCode(
// Get object(s) concerned by function call
std::vector<gd::String> realObjects =
codeGenerator.GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
codeGenerator.ExpandObjectsName(objectName, context);
gd::String functionOutput = GenerateDefaultValue(type);
gd::String behaviorType = codeGenerator.GetObjectsContainersList().GetTypeOfBehavior(behaviorName);
gd::String behaviorType = gd::GetTypeOfBehavior(
globalObjectsAndGroups, objectsAndGroups, behaviorName);
const BehaviorMetadata& autoInfo = MetadataProvider::GetBehaviorMetadata(
codeGenerator.GetPlatform(), behaviorType);
@@ -432,7 +352,8 @@ gd::String ExpressionCodeGenerator::GenerateParametersCodes(
if (!parameterMetadata.IsCodeOnly()) {
if (nonCodeOnlyParameterIndex < parameters.size()) {
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootObjectName,
*parameters[nonCodeOnlyParameterIndex].get());
ExpressionCodeGenerator generator(parameterMetadata.GetType(), objectName, codeGenerator, context);
@@ -502,7 +423,8 @@ gd::String ExpressionCodeGenerator::GenerateDefaultValue(
void ExpressionCodeGenerator::OnVisitEmptyNode(EmptyNode& node) {
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType,
node);
output += GenerateDefaultValue(type);
@@ -511,7 +433,8 @@ void ExpressionCodeGenerator::OnVisitEmptyNode(EmptyNode& node) {
void ExpressionCodeGenerator::OnVisitObjectFunctionNameNode(
ObjectFunctionNameNode& node) {
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
codeGenerator.GetObjectsContainersList(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType,
node);
output += GenerateDefaultValue(type);

View File

@@ -102,7 +102,6 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
const std::vector<std::unique_ptr<ExpressionNode>>& parameters);
gd::String output;
gd::String objectNameToUseForVariableAccessor;
EventsCodeGenerator& codeGenerator;
EventsCodeGenerationContext& context;
const gd::String rootType;

View File

@@ -240,7 +240,7 @@ class GD_CORE_API BaseEvent {
*/
virtual void UnserializeFrom(gd::Project& project,
const SerializerElement& element){};
virtual bool AcceptVisitor(gd::EventVisitor& eventVisitor);
virtual void AcceptVisitor(gd::ReadOnlyEventVisitor& eventVisitor) const;
///@}
@@ -281,6 +281,15 @@ class GD_CORE_API BaseEvent {
* \brief True if the event should be folded in the events editor.
*/
bool IsFolded() const { return folded; }
/**
* \brief Return a list of all objects linked to the event.
*/
virtual std::vector<gd::Expression*> GetAllObjectExpressions() {
std::vector<gd::Expression*> allObjectExpressions;
return allObjectExpressions;
}
///@}
std::weak_ptr<gd::BaseEvent>

View File

@@ -47,9 +47,14 @@ class GD_CORE_API ExpressionParser2 {
virtual ~ExpressionParser2(){};
/**
* Parse the given expression into a tree of nodes.
* Parse the given expression with the specified type.
*
* \param expression The expression to parse.
* \param type Type of the expression: "string", "number",
* type supported by gd::ParameterMetadata::IsObject, types supported by
* gd::ParameterMetadata::IsExpression or "unknown".
* \param expression The expression to parse
* \param objectName Specify the object name, only for the
* case of "objectvar" type.
*
* \return The node representing the expression as a parsed tree.
*/
@@ -262,11 +267,12 @@ class GD_CORE_API ExpressionParser2 {
} else if (CheckIfChar(IsDot)) {
ExpressionParserLocation dotLocation = SkipChar();
SkipAllWhitespaces();
return ObjectFunctionOrBehaviorFunctionOrVariable(
return ObjectFunctionOrBehaviorFunction(
name, nameLocation, dotLocation);
} else if (CheckIfChar(IsOpeningSquareBracket)) {
return Variable(name, nameLocation);
} else {
}
else {
auto identifier = gd::make_unique<IdentifierNode>(name);
identifier->location = ExpressionParserLocation(
nameLocation.GetStartPosition(), GetCurrentPosition());
@@ -312,7 +318,7 @@ class GD_CORE_API ExpressionParser2 {
auto dotLocation = SkipChar();
SkipAllWhitespaces();
auto identifierAndLocation = ReadIdentifierName(/*allowDeprecatedSpacesInName=*/ false);
auto identifierAndLocation = ReadIdentifierName();
auto child =
gd::make_unique<VariableAccessorNode>(identifierAndLocation.name);
child->child = VariableAccessorOrVariableBracketAccessor();
@@ -352,11 +358,11 @@ class GD_CORE_API ExpressionParser2 {
}
std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
ObjectFunctionOrBehaviorFunctionOrVariable(
ObjectFunctionOrBehaviorFunction(
const gd::String &parentIdentifier,
const ExpressionParserLocation &parentIdentifierLocation,
const ExpressionParserLocation &parentIdentifierDotLocation) {
auto childIdentifierAndLocation = ReadIdentifierName(/*allowDeprecatedSpacesInName=*/ false);
auto childIdentifierAndLocation = ReadIdentifierName();
const gd::String &childIdentifierName = childIdentifierAndLocation.name;
const auto &childIdentifierNameLocation =
childIdentifierAndLocation.location;
@@ -414,6 +420,12 @@ class GD_CORE_API ExpressionParser2 {
auto node = gd::make_unique<IdentifierNode>(
parentIdentifier, childIdentifierName);
if (!CheckIfChar(IsParameterSeparator) && !CheckIfChar(IsClosingParenthesis) && !IsEndReached()) {
node->diagnostic = RaiseSyntaxError(
_("An opening parenthesis (for an object expression), a double colon "
"(:: for a behavior expression), a dot or an opening bracket (for "
"a child variable) where expected."));
}
node->location = ExpressionParserLocation(
parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
node->identifierNameLocation = parentIdentifierLocation;
@@ -613,13 +625,13 @@ class GD_CORE_API ExpressionParser2 {
ExpressionParserLocation location;
};
IdentifierAndLocation ReadIdentifierName(bool allowDeprecatedSpacesInName = true) {
IdentifierAndLocation ReadIdentifierName() {
gd::String name;
size_t startPosition = currentPosition;
while (currentPosition < expression.size() &&
(CheckIfChar(IsAllowedInIdentifier)
// Allow whitespace in identifier name for compatibility
|| (allowDeprecatedSpacesInName && expression[currentPosition] == ' '))) {
|| expression[currentPosition] == ' ')) {
name += expression[currentPosition];
currentPosition++;
}

View File

@@ -189,7 +189,7 @@ struct GD_CORE_API IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode
*
* The name of a function to call on an object or the behavior,
* for example: "MyObject.Function" or "MyObject.Physics".
*
*
* A variable, potentially with accessor to its child,
* for example: MyVariable or MyVariable.MyChild
*/
@@ -239,14 +239,13 @@ struct GD_CORE_API VariableAccessorOrVariableBracketAccessorNode : public Expres
};
/**
* \brief A variable, or object variable, with bracket accessor or at least 2 "dot" accessors.
*
* Example: `MyVariable["MyChildren"]` or `MyVariable.MyChildren.MyGrandChildren`.
* Example: `MyObject["MyVariable"]` or `MyObject.MyVariable.MyChildren`.
* \brief A variable with bracket accessor or at least 2 "dot" accessors.
*
* Example: MyVariable[MyChildren] or MyVariable.MyChildren.MyGranChildren.
*
* Other cases like "MyVariable" or "MyVariable.MyChildren" are IdentifierNode
* to allow handling ambiguities.
*
*
* \see gd::IdentifierNode
* \see gd::VariableAccessorNode
* \see gd::VariableBracketAccessorNode
@@ -268,7 +267,7 @@ struct GD_CORE_API VariableNode : public FunctionCallOrObjectFunctionNameOrEmpty
};
/**
* \brief A direct accessor to a child variable. Example: MyChild
* \brief A bracket accessor of a variable. Example: MyChild
* in MyVariable.MyChild
*/
struct GD_CORE_API VariableAccessorNode
@@ -286,7 +285,7 @@ struct GD_CORE_API VariableAccessorNode
};
/**
* \brief A bracket accessor to a child variable. Example: ["MyChild"]
* \brief A bracket accessor of a variable. Example: ["MyChild"]
* (in MyVariable["MyChild"]).
*/
struct GD_CORE_API VariableBracketAccessorNode
@@ -304,10 +303,10 @@ struct GD_CORE_API VariableBracketAccessorNode
/**
* \brief The name of a function to call on an object or the behavior
* For example: "MyObject.Physics::LinearVelocity".
*
*
* Other cases like "MyObject.Function" or "MyObject.Physics" are IdentifierNode
* to allow handling ambiguities.
*
*
* \see gd::IdentifierNode
*/
struct GD_CORE_API ObjectFunctionNameNode

View File

@@ -1277,9 +1277,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
// Deprecated
obj.AddAction("SetEffectDoubleParameter",
_("Effect property (number)"),
_("Change the value of a property of an effect.") + "\n" +
_("You can find the property names (and change the effect "
_("Effect parameter (number)"),
_("Change the value of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
@@ -1287,17 +1287,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("expression", _("New value"))
.MarkAsSimple()
.SetHidden();
// Deprecated
obj.AddAction("SetEffectStringParameter",
_("Effect property (string)"),
_("Change the value (string) of a property of an effect.") +
_("Effect parameter (string)"),
_("Change the value (string) of a parameter of an effect.") +
"\n" +
_("You can find the property names (and change the effect "
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
@@ -1305,16 +1305,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("string", _("New value"))
.MarkAsSimple()
.SetHidden();
// Deprecated
obj.AddAction("SetEffectBooleanParameter",
_("Effect property (enable or disable)"),
_("Enable or disable a property of an effect.") + "\n" +
_("You can find the property names (and change the effect "
_("Effect parameter (enable or disable)"),
_("Enable or disable a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Enable _PARAM2_ for effect _PARAM1_ of _PARAM0_: _PARAM3_"),
_("Effects"),
@@ -1322,8 +1322,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
.AddParameter("yesorno", _("Enable this property"))
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("yesorno", _("Enable?"))
.MarkAsSimple()
.SetHidden();

View File

@@ -444,9 +444,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
extension
.AddAction(
"SetLayerEffectParameter",
_("Effect property (number)"),
_("Change the value of a property of an effect.") + "\n" +
_("You can find the property names (and change the effect "
_("Effect parameter (number)"),
_("Change the value of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
_("Effects"),
@@ -456,16 +456,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("layerEffectName", _("Effect name"))
.AddParameter("layerEffectParameterName", _("Property name"))
.AddParameter("layerEffectParameterName", _("Parameter name"))
.AddParameter("expression", _("New value"))
.MarkAsAdvanced();
extension
.AddAction(
"SetLayerEffectStringParameter",
_("Effect property (string)"),
_("Change the value (string) of a property of an effect.") + "\n" +
_("You can find the property names (and change the effect "
_("Effect parameter (string)"),
_("Change the value (string) of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
_("Effects"),
@@ -475,16 +475,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("layerEffectName", _("Effect name"))
.AddParameter("layerEffectParameterName", _("Property name"))
.AddParameter("layerEffectParameterName", _("Parameter name"))
.AddParameter("string", _("New value"))
.MarkAsAdvanced();
extension
.AddAction(
"SetLayerEffectBooleanParameter",
_("Effect property (enable or disable)"),
_("Enable or disable a property of an effect.") + "\n" +
_("You can find the property names (and change the effect "
_("Effect parameter (enable or disable)"),
_("Enable or disable a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Enable _PARAM3_ for effect _PARAM2_ of layer _PARAM1_: _PARAM4_"),
_("Effects"),
@@ -494,8 +494,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("layerEffectName", _("Effect name"))
.AddParameter("layerEffectParameterName", _("Property name"))
.AddParameter("yesorno", _("Enable this property"))
.AddParameter("layerEffectParameterName", _("Parameter name"))
.AddParameter("yesorno", _("Enable this parameter"))
.MarkAsAdvanced();
extension

View File

@@ -52,9 +52,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
.MarkAsSimple();
aut.AddScopedAction("SetEffectDoubleParameter",
_("Effect property (number)"),
_("Change the value of a property of an effect.") + "\n" +
_("You can find the property names (and change the effect "
_("Effect parameter (number)"),
_("Change the value of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
_("Effects"),
@@ -63,15 +63,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("expression", _("New value"))
.MarkAsSimple();
aut.AddScopedAction("SetEffectStringParameter",
_("Effect property (string)"),
_("Change the value (string) of a property of an effect.") +
_("Effect parameter (string)"),
_("Change the value (string) of a parameter of an effect.") +
"\n" +
_("You can find the property names (and change the effect "
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of _PARAM0_"),
_("Effects"),
@@ -80,14 +80,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("string", _("New value"))
.MarkAsSimple();
aut.AddScopedAction("SetEffectBooleanParameter",
_("Effect property (enable or disable)"),
_("Enable or disable a property of an effect.") + "\n" +
_("You can find the property names (and change the effect "
_("Effect parameter (enable or disable)"),
_("Enable or disable a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Enable _PARAM3_ for effect _PARAM2_ of _PARAM0_: _PARAM4_"),
_("Effects"),
@@ -96,8 +96,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsEffectExtension(
.AddParameter("object", _("Object"))
.AddParameter("behavior", _("Behavior"), "EffectBehavior")
.AddParameter("objectEffectName", _("Effect name"))
.AddParameter("objectEffectParameterName", _("Property name"))
.AddParameter("yesorno", _("Enable this property"))
.AddParameter("objectEffectParameterName", _("Parameter name"))
.AddParameter("yesorno", _("Enable?"))
.MarkAsSimple();
aut.AddScopedCondition("IsEffectEnabled",

View File

@@ -14,7 +14,6 @@
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/String.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
@@ -392,19 +391,20 @@ MetadataProvider::GetBehaviorAnyExpressionMetadata(const gd::Platform& platform,
}
const gd::ExpressionMetadata& MetadataProvider::GetFunctionCallMetadata(
const gd::Platform& platform,
const gd::ObjectsContainersList &objectsContainersList,
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& node) {
if (!node.behaviorName.empty()) {
gd::String behaviorType =
objectsContainersList.GetTypeOfBehavior(node.behaviorName);
gd::String behaviorType =
GetTypeOfBehavior(globalObjectsContainer, objectsContainer, node.behaviorName);
return MetadataProvider::GetBehaviorAnyExpressionMetadata(
platform, behaviorType, node.functionName);
}
else if (!node.objectName.empty()) {
gd::String objectType =
objectsContainersList.GetTypeOfObject(node.objectName);
gd::String objectType =
GetTypeOfObject(globalObjectsContainer, objectsContainer, node.objectName);
return MetadataProvider::GetObjectAnyExpressionMetadata(
platform, objectType, node.functionName);
}
@@ -412,9 +412,10 @@ const gd::ExpressionMetadata& MetadataProvider::GetFunctionCallMetadata(
return MetadataProvider::GetAnyExpressionMetadata(platform, node.functionName);
}
const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
const gd::Platform& platform,
const gd::ObjectsContainersList &objectsContainersList,
const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& functionCall,
ExpressionNode& parameter) {
int parameterIndex = -1;
@@ -428,15 +429,17 @@ const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
return nullptr;
}
return MetadataProvider::GetFunctionCallParameterMetadata(
platform,
objectsContainersList,
platform,
globalObjectsContainer,
objectsContainer,
functionCall,
parameterIndex);
}
const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
const gd::Platform& platform,
const gd::ObjectsContainersList &objectsContainersList,
const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& functionCall,
int parameterIndex) {
// Search the parameter metadata index skipping invisible ones.
@@ -445,7 +448,7 @@ const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
ExpressionParser2::WrittenParametersFirstIndex(
functionCall.objectName, functionCall.behaviorName);
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
platform, objectsContainersList, functionCall);
platform, globalObjectsContainer, objectsContainer, functionCall);
if (IsBadExpressionMetadata(metadata)) {
return nullptr;

View File

@@ -15,7 +15,6 @@ class ExpressionMetadata;
class ExpressionMetadata;
class Platform;
class PlatformExtension;
class ObjectsContainersList;
struct FunctionCallNode;
struct ExpressionNode;
} // namespace gd
@@ -238,19 +237,22 @@ class GD_CORE_API MetadataProvider {
const gd::Platform& platform, gd::String objectType, gd::String exprType);
static const gd::ExpressionMetadata& GetFunctionCallMetadata(
const gd::Platform& platform,
const gd::ObjectsContainersList &objectsContainersList,
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& node);
static const gd::ParameterMetadata* GetFunctionCallParameterMetadata(
const gd::Platform& platform,
const gd::ObjectsContainersList &objectsContainersList,
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& functionCall,
ExpressionNode& parameter);
static const gd::ParameterMetadata* GetFunctionCallParameterMetadata(
const gd::Platform& platform,
const gd::ObjectsContainersList &objectsContainersList,
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& functionCall,
int parameterIndex);

View File

@@ -34,11 +34,6 @@ class GD_CORE_API ParameterMetadata {
*/
gd::ValueTypeMetadata &GetValueTypeMetadata() { return valueTypeMetadata; }
/**
* \brief Return the metadata of the parameter type.
*/
const gd::ValueTypeMetadata &GetValueTypeMetadata() const { return valueTypeMetadata; }
/**
* \brief Set the metadata of the parameter type.
*/

View File

@@ -8,7 +8,6 @@
#include "GDCore/Events/Expression.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
#include "InstructionMetadata.h"
@@ -16,8 +15,6 @@
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
namespace gd {
const ParameterMetadata ParameterMetadataTools::badParameterMetadata;
void ParameterMetadataTools::ParametersToObjectsContainer(
const gd::Project& project,
const std::vector<gd::ParameterMetadata>& parameters,
@@ -60,55 +57,6 @@ void ParameterMetadataTools::ParametersToObjectsContainer(
}
}
void ParameterMetadataTools::ForEachParameterWithPrefix(
const std::vector<const std::vector<gd::ParameterMetadata>*>&
parametersVectorsList,
const gd::String& prefix,
std::function<void(const gd::ParameterMetadata&)> cb) {
for (auto it = parametersVectorsList.rbegin();
it != parametersVectorsList.rend();
++it) {
const std::vector<gd::ParameterMetadata>* parametersVector = *it;
for (const auto& parameterMetadata: *parametersVector) {
if (parameterMetadata.GetName().find(prefix) == 0) cb(parameterMetadata);
}
}
}
bool ParameterMetadataTools::Has(
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const gd::String& parameterName) {
for (auto it = parametersVectorsList.rbegin();
it != parametersVectorsList.rend();
++it) {
const std::vector<gd::ParameterMetadata>* parametersVector = *it;
for (const auto& parameterMetadata: *parametersVector) {
if (parameterMetadata.GetName() == parameterName) return true;
}
}
return false;
}
const gd::ParameterMetadata& ParameterMetadataTools::Get(
const std::vector<const std::vector<gd::ParameterMetadata>*>&
parametersVectorsList,
const gd::String& parameterName) {
for (auto it = parametersVectorsList.rbegin();
it != parametersVectorsList.rend();
++it) {
const std::vector<gd::ParameterMetadata>* parametersVector = *it;
for (const auto& parameterMetadata: *parametersVector) {
if (parameterMetadata.GetName() == parameterName) return parameterMetadata;
}
}
return badParameterMetadata;
}
void ParameterMetadataTools::IterateOverParameters(
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
@@ -157,7 +105,8 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
void ParameterMetadataTools::IterateOverParametersWithIndex(
const gd::Platform &platform,
const gd::ObjectsContainersList &objectsContainersList, FunctionCallNode &node,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer, FunctionCallNode &node,
std::function<void(const gd::ParameterMetadata &parameterMetadata,
std::unique_ptr<gd::ExpressionNode> &parameterNode,
size_t parameterIndex, const gd::String &lastObjectName)>
@@ -168,7 +117,8 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
const gd::ExpressionMetadata &metadata =
isObjectFunction ? MetadataProvider::GetObjectAnyExpressionMetadata(
platform,
objectsContainersList.GetTypeOfObject(node.objectName),
GetTypeOfObject(globalObjectsContainer,
objectsContainer, node.objectName),
node.functionName)
: MetadataProvider::GetAnyExpressionMetadata(
platform, node.functionName);

View File

@@ -3,8 +3,9 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <functional>
#if defined(GD_IDE_ONLY)
#ifndef ParameterMetadataTools_H
#define ParameterMetadataTools_H
#include <vector>
#include <memory>
#include "GDCore/String.h"
@@ -12,7 +13,6 @@ namespace gd {
class Platform;
class Project;
class ObjectsContainer;
class ObjectsContainersList;
class ParameterMetadata;
class Expression;
struct FunctionCallNode;
@@ -27,19 +27,6 @@ class GD_CORE_API ParameterMetadataTools {
const std::vector<gd::ParameterMetadata>& parameters,
gd::ObjectsContainer& outputObjectsContainer);
static void ForEachParameterWithPrefix(
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const gd::String& prefix,
std::function<void(const gd::ParameterMetadata&)> cb);
static bool Has(
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const gd::String& parameterName);
static const gd::ParameterMetadata& Get(
const std::vector<const std::vector<gd::ParameterMetadata>*>& parametersVectorsList,
const gd::String& parameterName);
/**
* Iterate over a list of parameters and their values.
* Callback function is called with the parameter metadata, its value
@@ -72,7 +59,8 @@ class GD_CORE_API ParameterMetadataTools {
*/
static void IterateOverParametersWithIndex(
const gd::Platform &platform,
const gd::ObjectsContainersList &objectsContainersList, FunctionCallNode &node,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer, FunctionCallNode &node,
std::function<void(const gd::ParameterMetadata &parameterMetadata,
std::unique_ptr<gd::ExpressionNode> &parameterNode,
size_t parameterIndex,
@@ -86,8 +74,8 @@ class GD_CORE_API ParameterMetadataTools {
static size_t GetObjectParameterIndexFor(
const std::vector<gd::ParameterMetadata>& parametersMetadata,
size_t parameterIndex);
private:
static const gd::ParameterMetadata badParameterMetadata;
};
} // namespace gd
#endif // ParameterMetadataTools_H
#endif

View File

@@ -121,13 +121,6 @@ class GD_CORE_API ValueTypeMetadata {
return gd::ValueTypeMetadata::IsTypeExpression("string", name);
}
/**
* \brief Return true if the type is a boolean.
*/
bool IsBoolean() const {
return gd::ValueTypeMetadata::IsTypeExpression("boolean", name);
}
/**
* \brief Return true if the type of the parameter is a number.
* \note If you had a new type of parameter, also add it in the IDE (
@@ -138,24 +131,6 @@ class GD_CORE_API ValueTypeMetadata {
return gd::ValueTypeMetadata::IsTypeExpression("variable", name);
}
/**
* \brief Return true if the type is a variable but from a specific scope
* (scene, project or object). In new code, prefer to use the more generic "variable"
* parameter (which accepts any variable coming from an object or from containers in the scope).
*/
bool IsLegacyPreScopedVariable() const {
return gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(name);
}
/**
* \brief Return true if the type is a variable but from a specific scope
* (scene, project or object). In new code, prefer to use the more generic "variable"
* parameter (which accepts any variable coming from an object or from containers in the scope).
*/
static bool IsTypeLegacyPreScopedVariable(const gd::String &type) {
return type == "scenevar" || type == "globalvar" || type == "objectvar";
}
/**
* \brief Return true if the type is representing one object
* (or more, i.e: an object group).
@@ -200,13 +175,8 @@ class GD_CORE_API ValueTypeMetadata {
parameterType == "externalLayoutName" ||
parameterType == "leaderboardId" ||
parameterType == "identifier";
} else if (type == "boolean") {
return parameterType == "yesorno" || parameterType == "trueorfalse";
} else if (type == "variable") {
return
parameterType == "variable" || // Any variable.
// Old, "pre-scoped" variables:
parameterType == "objectvar" || parameterType == "globalvar" ||
return parameterType == "objectvar" || parameterType == "globalvar" ||
parameterType == "scenevar";
} else if (type == "resource") {
return parameterType == "fontResource" ||
@@ -226,7 +196,7 @@ class GD_CORE_API ValueTypeMetadata {
* \brief Return the expression type from the parameter type.
* Declinations of "number" and "string" types (like "forceMultiplier" or
* "sceneName") are replaced by "number" and "string".
*
*
* \note It only maps string and number types.
*/
static const gd::String &GetExpressionPrimitiveValueType(const gd::String &parameterType);
@@ -235,7 +205,7 @@ class GD_CORE_API ValueTypeMetadata {
* \brief Return the primitive type from the parameter type.
* Declinations of "number" and "string" types (like "forceMultiplier" or
* "sceneName") are replaced by "number" and "string".
*
*
* \note It also maps variable and boolean types.
*/
static const gd::String &GetPrimitiveValueType(const gd::String &parameterType);

View File

@@ -11,8 +11,6 @@
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Events/Expression.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/String.h"
using namespace std;
@@ -49,14 +47,7 @@ bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
for (std::size_t j = 0; j < actionsVectors.size(); ++j)
VisitInstructionList(*actionsVectors[j], false);
auto allExpressionsWithMetadata = event.GetAllExpressionsWithMetadata();
for (auto& expressionAndMetadata : allExpressionsWithMetadata) {
shouldDelete |= VisitEventExpression(
*expressionAndMetadata.first, expressionAndMetadata.second);
}
return shouldDelete;
return false;
}
bool ArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
@@ -84,11 +75,6 @@ bool ArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
return DoVisitInstruction(instruction, isCondition);
}
bool ArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
const gd::ParameterMetadata& metadata) {
return DoVisitEventExpression(expression, metadata);
}
ArbitraryEventsWorkerWithContext::~ArbitraryEventsWorkerWithContext() {}
@@ -155,12 +141,6 @@ void ReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& inst
DoVisitInstruction(instruction, isCondition);
}
void ReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
const gd::ParameterMetadata& metadata) {
DoVisitEventExpression(expression, metadata);
}
void ReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
shouldStopIteration = true;
}

View File

@@ -10,7 +10,6 @@
#include <vector>
#include "GDCore/Events/InstructionsList.h"
#include "GDCore/Events/EventVisitor.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/String.h"
namespace gd {
class Instruction;
@@ -18,8 +17,6 @@ class BaseEvent;
class LinkEvent;
class EventsList;
class ObjectsContainer;
class Expression;
class ParameterMetadata;
} // namespace gd
namespace gd {
@@ -50,7 +47,6 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
void VisitInstructionList(gd::InstructionsList& instructions,
bool areConditions);
bool VisitInstruction(gd::Instruction& instruction, bool isCondition);
bool VisitEventExpression(gd::Expression& expression, const gd::ParameterMetadata& metadata);
/**
* Called to do some work on an event list.
@@ -66,9 +62,9 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
/**
* Called to do some work on a link event.
*
*
* Note that DoVisitEvent is also called with this event.
*
*
* \return true if the event must be deleted from the events list, false
* otherwise (default).
*/
@@ -89,16 +85,6 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
bool isCondition) {
return false;
};
/**
* Called to do some work on an expression of an event.
* \return true if the event must be deleted from the list, false
* otherwise (default).
*/
virtual bool DoVisitEventExpression(gd::Expression& expression,
const gd::ParameterMetadata& metadata) {
return false;
}
};
/**
@@ -113,7 +99,8 @@ class GD_CORE_API ArbitraryEventsWorkerWithContext
: public ArbitraryEventsWorker {
public:
ArbitraryEventsWorkerWithContext()
: projectScopedContainers(nullptr){};
: currentGlobalObjectsContainer(nullptr),
currentObjectsContainer(nullptr){};
virtual ~ArbitraryEventsWorkerWithContext();
/**
@@ -121,27 +108,30 @@ class GD_CORE_API ArbitraryEventsWorkerWithContext
* giving the objects container on which the events are applying to.
*/
void Launch(gd::EventsList& events,
const gd::ProjectScopedContainers& projectScopedContainers_) {
projectScopedContainers = &projectScopedContainers_;
const gd::ObjectsContainer& globalObjectsContainer_,
const gd::ObjectsContainer& objectsContainer_) {
currentGlobalObjectsContainer = &globalObjectsContainer_;
currentObjectsContainer = &objectsContainer_;
ArbitraryEventsWorker::Launch(events);
};
void Launch(gd::EventsList& events) = delete;
protected:
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
const gd::ObjectsContainer& GetGlobalObjectsContainer() {
// Pointers are guaranteed to be not nullptr after
// Launch was called.
return *projectScopedContainers;
return *currentGlobalObjectsContainer;
};
const gd::ObjectsContainersList& GetObjectsContainersList() {
const gd::ObjectsContainer& GetObjectsContainer() {
// Pointers are guaranteed to be not nullptr after
// Launch was called.
return projectScopedContainers->GetObjectsContainersList();
return *currentObjectsContainer;
};
private:
const gd::ProjectScopedContainers* projectScopedContainers;
const gd::ObjectsContainer* currentGlobalObjectsContainer;
const gd::ObjectsContainer* currentObjectsContainer;
};
/**
@@ -172,7 +162,6 @@ protected:
void VisitInstructionList(const gd::InstructionsList& instructions,
bool areConditions);
void VisitInstruction(const gd::Instruction& instruction, bool isCondition);
void VisitEventExpression(const gd::Expression& expression, const gd::ParameterMetadata& metadata);
/**
* Called to do some work on an event list.
@@ -186,7 +175,7 @@ protected:
/**
* Called to do some work on a link event.
*
*
* Note that DoVisitEvent is also called with this event.
*/
virtual void DoVisitLinkEvent(const gd::LinkEvent& linkEvent) {};
@@ -203,13 +192,6 @@ protected:
virtual void DoVisitInstruction(const gd::Instruction& instruction,
bool isCondition) {};
/**
* Called to do some work on an expression of an event.
*/
virtual void DoVisitEventExpression(const gd::Expression& expression,
const gd::ParameterMetadata& metadata) {
}
bool shouldStopIteration;
};
@@ -225,7 +207,8 @@ class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
: public ReadOnlyArbitraryEventsWorker {
public:
ReadOnlyArbitraryEventsWorkerWithContext()
: projectScopedContainers(nullptr){};
: currentGlobalObjectsContainer(nullptr),
currentObjectsContainer(nullptr){};
virtual ~ReadOnlyArbitraryEventsWorkerWithContext();
/**
@@ -233,22 +216,30 @@ class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
* giving the objects container on which the events are applying to.
*/
void Launch(const gd::EventsList& events,
const gd::ProjectScopedContainers& projectScopedContainers_) {
projectScopedContainers = &projectScopedContainers_;
const gd::ObjectsContainer& globalObjectsContainer_,
const gd::ObjectsContainer& objectsContainer_) {
currentGlobalObjectsContainer = &globalObjectsContainer_;
currentObjectsContainer = &objectsContainer_;
ReadOnlyArbitraryEventsWorker::Launch(events);
};
void Launch(gd::EventsList& events) = delete;
protected:
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
const gd::ObjectsContainer& GetGlobalObjectsContainer() {
// Pointers are guaranteed to be not nullptr after
// Launch was called.
return *projectScopedContainers;
return *currentGlobalObjectsContainer;
};
const gd::ObjectsContainer& GetObjectsContainer() {
// Pointers are guaranteed to be not nullptr after
// Launch was called.
return *currentObjectsContainer;
};
private:
const gd::ProjectScopedContainers* projectScopedContainers;
const gd::ObjectsContainer* currentGlobalObjectsContainer;
const gd::ObjectsContainer* currentObjectsContainer;
};
} // namespace gd

View File

@@ -4,6 +4,7 @@
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"

View File

@@ -4,6 +4,7 @@
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"

View File

@@ -31,10 +31,14 @@ namespace gd {
class GD_CORE_API ExpressionBehaviorRenamer
: public ExpressionParser2NodeWorker {
public:
ExpressionBehaviorRenamer(const gd::String& objectName_,
ExpressionBehaviorRenamer(const gd::ObjectsContainer& globalObjectsContainer_,
const gd::ObjectsContainer& objectsContainer_,
const gd::String& objectName_,
const gd::String& oldBehaviorName_,
const gd::String& newBehaviorName_)
: hasDoneRenaming(false),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
objectName(objectName_),
oldBehaviorName(oldBehaviorName_),
newBehaviorName(newBehaviorName_){};
@@ -93,6 +97,8 @@ class GD_CORE_API ExpressionBehaviorRenamer
private:
bool hasDoneRenaming;
const gd::ObjectsContainer& globalObjectsContainer;
const gd::ObjectsContainer& objectsContainer;
const gd::String& objectName; // The object name for which the behavior
// must be replaced.
const gd::String& oldBehaviorName;
@@ -126,7 +132,9 @@ bool EventsBehaviorRenamer::DoVisitInstruction(gd::Instruction& instruction,
} else {
auto node = parameterValue.GetRootNode();
if (node) {
ExpressionBehaviorRenamer renamer(objectName,
ExpressionBehaviorRenamer renamer(GetGlobalObjectsContainer(),
GetObjectsContainer(),
objectName,
oldBehaviorName,
newBehaviorName);
node->Visit(renamer);

View File

@@ -19,8 +19,6 @@
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/String.h"
namespace gd {
@@ -35,11 +33,13 @@ class GD_CORE_API ExpressionObjectsAnalyzer
public:
ExpressionObjectsAnalyzer(
const gd::Platform &platform_,
const gd::ProjectScopedContainers &projectScopedContainers_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_,
EventsContext& context_) :
platform(platform_),
projectScopedContainers(projectScopedContainers_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootType(rootType_),
context(context_){};
virtual ~ExpressionObjectsAnalyzer(){};
@@ -58,25 +58,6 @@ class GD_CORE_API ExpressionObjectsAnalyzer
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, projectScopedContainers.GetObjectsContainersList(), rootType, node);
if (gd::ParameterMetadata::IsExpression("variable", type)) {
// Nothing to do (this can't reference an object)
} else {
projectScopedContainers.MatchIdentifierWithName<void>(node.name, [&]() {
// This is an object variable.
context.AddObjectName(projectScopedContainers, node.name);
}, [&]() {
// This is a variable.
}, [&]() {
// This is a property.
}, [&]() {
// This is a parameter.
}, [&]() {
// This is something else.
});
}
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
@@ -88,41 +69,26 @@ class GD_CORE_API ExpressionObjectsAnalyzer
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, projectScopedContainers.GetObjectsContainersList(), rootType, node);
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
if (gd::ParameterMetadata::IsObject(type)) {
context.AddObjectName(projectScopedContainers, node.identifierName);
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
// Nothing to do (identifier is a variable but not an object).
} else {
projectScopedContainers.MatchIdentifierWithName<void>(node.identifierName, [&]() {
// This is an object variable.
context.AddObjectName(projectScopedContainers, node.identifierName);
}, [&]() {
// This is a variable.
}, [&]() {
// This is a property.
}, [&]() {
// This is a parameter.
}, [&]() {
// This is something else.
});
context.AddObjectName(node.identifierName);
}
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (!node.objectName.empty()) {
context.AddObjectName(projectScopedContainers, node.objectName);
context.AddObjectName(node.objectName);
if (!node.behaviorFunctionName.empty()) {
context.AddBehaviorName(projectScopedContainers, node.objectName, node.objectFunctionOrBehaviorName);
context.AddBehaviorName(node.objectName, node.objectFunctionOrBehaviorName);
}
}
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
if (!node.objectName.empty()) {
context.AddObjectName(projectScopedContainers, node.objectName);
context.AddObjectName(node.objectName);
if (!node.behaviorName.empty()) {
context.AddBehaviorName(projectScopedContainers, node.objectName, node.behaviorName);
context.AddBehaviorName(node.objectName, node.behaviorName);
}
}
for (auto& parameter : node.parameters) {
@@ -133,7 +99,8 @@ class GD_CORE_API ExpressionObjectsAnalyzer
private:
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
EventsContext& context;
@@ -154,7 +121,8 @@ bool EventsContextAnalyzer::DoVisitInstruction(gd::Instruction& instruction,
const gd::Expression& parameterValue,
const gd::String& lastObjectName) {
AnalyzeParameter(platform,
GetProjectScopedContainers(),
project,
layout,
parameterMetadata,
parameterValue,
context,
@@ -166,7 +134,8 @@ bool EventsContextAnalyzer::DoVisitInstruction(gd::Instruction& instruction,
void EventsContextAnalyzer::AnalyzeParameter(
const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::ParameterMetadata& metadata,
const gd::Expression& parameter,
EventsContext& context,
@@ -174,39 +143,59 @@ void EventsContextAnalyzer::AnalyzeParameter(
const auto& value = parameter.GetPlainString();
const auto& type = metadata.GetType();
if (ParameterMetadata::IsObject(type)) {
context.AddObjectName(projectScopedContainers, value);
context.AddObjectName(value);
} else if (ParameterMetadata::IsExpression("number", type)) {
auto node = parameter.GetRootNode();
ExpressionObjectsAnalyzer analyzer(platform, projectScopedContainers, "number", context);
ExpressionObjectsAnalyzer analyzer(platform, project, layout, "number", context);
node->Visit(analyzer);
} else if (ParameterMetadata::IsExpression("string", type)) {
auto node = parameter.GetRootNode();
ExpressionObjectsAnalyzer analyzer(platform, projectScopedContainers, "string", context);
ExpressionObjectsAnalyzer analyzer(platform, project, layout, "string", context);
node->Visit(analyzer);
} else if (ParameterMetadata::IsBehavior(type)) {
context.AddBehaviorName(projectScopedContainers, lastObjectName, value);
context.AddBehaviorName(lastObjectName, value);
}
}
void EventsContext::AddObjectName(const gd::ProjectScopedContainers& projectScopedContainers,
const gd::String& objectOrGroupName) {
auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
for (auto& realObjectName : objectsContainersList.ExpandObjectName(objectOrGroupName)) {
void EventsContext::AddObjectName(const gd::String& objectOrGroupName) {
for (auto& realObjectName : ExpandObjectsName(objectOrGroupName)) {
objectNames.insert(realObjectName);
}
referencedObjectOrGroupNames.insert(objectOrGroupName);
}
void EventsContext::AddBehaviorName(const gd::ProjectScopedContainers& projectScopedContainers,
const gd::String& objectOrGroupName,
void EventsContext::AddBehaviorName(const gd::String& objectOrGroupName,
const gd::String& behaviorName) {
auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
for (auto& realObjectName : objectsContainersList.ExpandObjectName(objectOrGroupName)) {
for (auto& realObjectName : ExpandObjectsName(objectOrGroupName)) {
objectOrGroupBehaviorNames[realObjectName].insert(behaviorName);
}
objectOrGroupBehaviorNames[objectOrGroupName].insert(behaviorName);
}
std::vector<gd::String> EventsContext::ExpandObjectsName(
const gd::String& objectName) {
// Note: this logic is duplicated in EventsCodeGenerator::ExpandObjectsName
std::vector<gd::String> realObjects;
if (project.GetObjectGroups().Has(objectName))
realObjects =
project.GetObjectGroups().Get(objectName).GetAllObjectsNames();
else if (layout.GetObjectGroups().Has(objectName))
realObjects = layout.GetObjectGroups().Get(objectName).GetAllObjectsNames();
else
realObjects.push_back(objectName);
// Ensure that all returned objects actually exists.
for (std::size_t i = 0; i < realObjects.size();) {
if (!layout.HasObjectNamed(realObjects[i]) &&
!project.HasObjectNamed(realObjects[i]))
realObjects.erase(realObjects.begin() + i);
else
++i;
}
return realObjects;
}
} // namespace gd

View File

@@ -15,7 +15,6 @@ namespace gd {
class BaseEvent;
class Platform;
class ObjectsContainer;
class ObjectsContainersList;
class Project;
class Layout;
class EventsList;
@@ -30,13 +29,12 @@ namespace gd {
*/
class GD_CORE_API EventsContext {
public:
EventsContext(){};
EventsContext(gd::ObjectsContainer& project_, gd::ObjectsContainer& layout_)
: project(project_), layout(layout_){};
virtual ~EventsContext(){};
void AddObjectName(const gd::ProjectScopedContainers& projectScopedContainers,
const gd::String& objectOrGroupName);
void AddBehaviorName(const gd::ProjectScopedContainers& projectScopedContainers,
const gd::String& objectOrGroupName,
void AddObjectName(const gd::String& objectOrGroupName);
void AddBehaviorName(const gd::String& objectOrGroupName,
const gd::String& behaviorName);
/**
@@ -61,9 +59,13 @@ class GD_CORE_API EventsContext {
}
private:
std::vector<gd::String> ExpandObjectsName(const gd::String& objectOrGroupName);
std::set<gd::String> referencedObjectOrGroupNames;
std::set<gd::String> objectNames;
std::map<gd::String, std::set<gd::String>> objectOrGroupBehaviorNames;
gd::ObjectsContainer& project;
gd::ObjectsContainer& layout;
};
/**
@@ -71,10 +73,15 @@ class GD_CORE_API EventsContext {
*
* \ingroup IDE
*/
class GD_CORE_API EventsContextAnalyzer : public ArbitraryEventsWorkerWithContext {
class GD_CORE_API EventsContextAnalyzer : public ArbitraryEventsWorker {
public:
EventsContextAnalyzer(const gd::Platform& platform_)
: platform(platform_) {};
EventsContextAnalyzer(const gd::Platform& platform_,
gd::ObjectsContainer& project_,
gd::ObjectsContainer& layout_)
: platform(platform_),
project(project_),
layout(layout_),
context(project, layout){};
virtual ~EventsContextAnalyzer(){};
/**
@@ -83,7 +90,8 @@ class GD_CORE_API EventsContextAnalyzer : public ArbitraryEventsWorkerWithContex
const EventsContext& GetEventsContext() { return context; }
static void AnalyzeParameter(const gd::Platform& platform,
const gd::ProjectScopedContainers& projectScopedContainers,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::ParameterMetadata& metadata,
const gd::Expression& parameter,
EventsContext& context,
@@ -94,6 +102,8 @@ class GD_CORE_API EventsContextAnalyzer : public ArbitraryEventsWorkerWithContex
bool isCondition);
const gd::Platform& platform;
gd::ObjectsContainer& project;
gd::ObjectsContainer& layout;
EventsContext context;
};

View File

@@ -34,12 +34,14 @@ class GD_CORE_API IdentifierFinderExpressionNodeWorker
public:
IdentifierFinderExpressionNodeWorker(std::set<gd::String>& results_,
const gd::Platform &platform_,
const gd::ProjectScopedContainers &projectScopedContainers_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String& identifierType_,
const gd::String& objectName_ = "")
: results(results_),
platform(platform_),
projectScopedContainers(projectScopedContainers_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
identifierType(identifierType_),
objectName(objectName_){};
virtual ~IdentifierFinderExpressionNodeWorker(){};
@@ -77,14 +79,14 @@ class GD_CORE_API IdentifierFinderExpressionNodeWorker
const gd::ExpressionMetadata &metadata = isObjectFunction ?
MetadataProvider::GetObjectAnyExpressionMetadata(
platform,
projectScopedContainers.GetObjectsContainersList().GetTypeOfObject(objectName),
GetTypeOfObject(globalObjectsContainer, objectsContainer, objectName),
node.functionName):
MetadataProvider::GetAnyExpressionMetadata(platform, node.functionName);
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
return;
}
size_t parameterIndex = 0;
for (size_t metadataIndex = (isObjectFunction ? 1 : 0); metadataIndex < metadata.parameters.size()
&& parameterIndex < node.parameters.size(); ++metadataIndex) {
@@ -109,7 +111,8 @@ class GD_CORE_API IdentifierFinderExpressionNodeWorker
private:
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
std::set<gd::String>& results; ///< Reference to the std::set where argument
///< values must be stored.
@@ -163,7 +166,8 @@ class GD_CORE_API IdentifierFinderEventWorker
IdentifierFinderExpressionNodeWorker searcher(
results,
platform,
GetProjectScopedContainers(),
GetGlobalObjectsContainer(),
GetObjectsContainer(),
identifierType,
objectName);
node->Visit(searcher);
@@ -223,8 +227,7 @@ void EventsIdentifiersFinder::FindArgumentsInEventsAndDependencies(
platform,
identifierType,
objectName);
eventWorker.Launch(layout.GetEvents(),
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout));
eventWorker.Launch(layout.GetEvents(), project, layout);
DependenciesAnalyzer dependenciesAnalyzer = DependenciesAnalyzer(project, layout);
dependenciesAnalyzer.Analyze();
@@ -235,8 +238,7 @@ void EventsIdentifiersFinder::FindArgumentsInEventsAndDependencies(
platform,
identifierType,
objectName);
eventWorker.Launch(externalEvents.GetEvents(),
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout));
eventWorker.Launch(externalEvents.GetEvents(), project, layout);
}
for (const gd::String& sceneName : dependenciesAnalyzer.GetScenesDependencies()) {
const gd::Layout& dependencyLayout = project.GetLayout(sceneName);
@@ -245,8 +247,7 @@ void EventsIdentifiersFinder::FindArgumentsInEventsAndDependencies(
platform,
identifierType,
objectName);
eventWorker.Launch(dependencyLayout.GetEvents(),
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, dependencyLayout));
eventWorker.Launch(dependencyLayout.GetEvents(), project, dependencyLayout);
}
}

View File

@@ -1,277 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
#include <map>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/PropertiesContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
/**
* \brief Go through the nodes and rename properties,
* or signal if the instruction must be renamed if a removed property is used.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionPropertyReplacer
: public ExpressionParser2NodeWorker {
public:
ExpressionPropertyReplacer(
const gd::Platform& platform_,
const gd::ProjectScopedContainers& projectScopedContainers_,
const gd::PropertiesContainer& targetPropertiesContainer_,
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames_,
const std::unordered_set<gd::String>& removedPropertyNames_)
: hasDoneRenaming(false),
removedPropertyUsed(false),
platform(platform_),
projectScopedContainers(projectScopedContainers_),
targetPropertiesContainer(targetPropertiesContainer_),
oldToNewPropertyNames(oldToNewPropertyNames_),
removedPropertyNames(removedPropertyNames_){};
virtual ~ExpressionPropertyReplacer(){};
bool HasDoneRenaming() const { return hasDoneRenaming; }
bool IsRemovedPropertyUsed() const { return removedPropertyUsed; }
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 {
auto& propertiesContainersList =
projectScopedContainers.GetPropertiesContainersList();
// The node represents a variable or an object name on which a variable
// will be accessed, or a property with a child.
// Match the potential *new* name of the property, because refactorings are
// done after changes in the variables container.
projectScopedContainers.MatchIdentifierWithName<void>(
GetPotentialNewName(node.name),
[&]() {
// Do nothing, it's an object variable.
if (node.child) node.child->Visit(*this);
}, [&]() {
// Do nothing, it's a variable.
if (node.child) node.child->Visit(*this);
}, [&]() {
// This is a property, check if it's coming from the target container with
// properties to replace.
if (propertiesContainersList.HasPropertiesContainer(
targetPropertiesContainer)) {
// The node represents a property, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemovePropertyOfTargetPropertyContainer(node.name);
}
if (node.child) node.child->Visit(*this);
}, [&]() {
// Do nothing, it's a parameter.
if (node.child) node.child->Visit(*this);
}, [&]() {
// This is something else - potentially a deleted property.
// Check if it's coming from the target container with
// properties to replace.
if (propertiesContainersList.HasPropertiesContainer(
targetPropertiesContainer)) {
// The node represents a property, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemovePropertyOfTargetPropertyContainer(node.name);
}
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 {
auto& propertiesContainersList =
projectScopedContainers.GetPropertiesContainersList();
// Match the potential *new* name of the property, because refactorings are
// done after changes in the variables container.
projectScopedContainers.MatchIdentifierWithName<void>(
GetPotentialNewName(node.identifierName),
[&]() {
// Do nothing, it's an object variable.
}, [&]() {
// Do nothing, it's a variable.
}, [&]() {
// This is a property, check if it's coming from the target container with
// properties to replace.
if (propertiesContainersList.HasPropertiesContainer(
targetPropertiesContainer)) {
// The node represents a property, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemovePropertyOfTargetPropertyContainer(node.identifierName);
}
}, [&]() {
// Do nothing, it's a parameter.
}, [&]() {
// This is something else - potentially a deleted property.
// Check if it's coming from the target container with
// properties to replace.
if (propertiesContainersList.HasPropertiesContainer(
targetPropertiesContainer)) {
// The node represents a property, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemovePropertyOfTargetPropertyContainer(node.identifierName);
}
});
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
for (auto& parameter : node.parameters) {
parameter->Visit(*this);
}
}
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
bool hasDoneRenaming;
bool removedPropertyUsed;
const gd::String& GetPotentialNewName(const gd::String& oldName) {
return oldToNewPropertyNames.count(oldName) >= 1
? oldToNewPropertyNames.find(oldName)->second
: oldName;
}
bool RenameOrRemovePropertyOfTargetPropertyContainer(
gd::String& propertyName) {
if (oldToNewPropertyNames.count(propertyName) >= 1) {
propertyName = oldToNewPropertyNames.find(propertyName)->second;
hasDoneRenaming = true;
return true;
} else if (removedPropertyNames.count(propertyName) >= 1) {
removedPropertyUsed = true;
return true;
}
return false; // Nothing was changed or done.
}
// Scope:
const gd::Platform& platform;
const gd::ProjectScopedContainers& projectScopedContainers;
// Renaming or removing to do:
const gd::PropertiesContainer& targetPropertiesContainer;
const std::unordered_map<gd::String, gd::String>& oldToNewPropertyNames;
const std::unordered_set<gd::String>& removedPropertyNames;
gd::String objectNameToUseForVariableAccessor;
};
bool EventsPropertyReplacer::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const auto& metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
bool shouldDeleteInstruction = false;
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
instruction.GetParameters(),
metadata.GetParameters(),
[&](const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName) {
const gd::String& type = parameterMetadata.GetType();
if (!gd::ParameterMetadata::IsExpression("variable", type) &&
!gd::ParameterMetadata::IsExpression("number", type) &&
!gd::ParameterMetadata::IsExpression("string", type))
return; // Not an expression that can contain properties.
auto node = parameterValue.GetRootNode();
if (node) {
ExpressionPropertyReplacer renamer(platform,
GetProjectScopedContainers(),
targetPropertiesContainer,
oldToNewPropertyNames,
removedPropertyNames);
node->Visit(renamer);
if (renamer.IsRemovedPropertyUsed()) {
shouldDeleteInstruction = true;
} else if (renamer.HasDoneRenaming()) {
instruction.SetParameter(
parameterIndex, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
});
return shouldDeleteInstruction;
}
bool EventsPropertyReplacer::DoVisitEventExpression(
gd::Expression& expression, const gd::ParameterMetadata& metadata) {
const gd::String& type = metadata.GetType();
if (!gd::ParameterMetadata::IsExpression("variable", type) &&
!gd::ParameterMetadata::IsExpression("number", type) &&
!gd::ParameterMetadata::IsExpression("string", type))
return false; // Not an expression that can contain properties.
auto node = expression.GetRootNode();
if (node) {
ExpressionPropertyReplacer renamer(platform,
GetProjectScopedContainers(),
targetPropertiesContainer,
oldToNewPropertyNames,
removedPropertyNames);
node->Visit(renamer);
if (renamer.IsRemovedPropertyUsed()) {
return true;
} else if (renamer.HasDoneRenaming()) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
return false;
}
EventsPropertyReplacer::~EventsPropertyReplacer() {}
} // namespace gd

View File

@@ -1,56 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class PropertiesContainer;
class EventsList;
class Platform;
} // namespace gd
namespace gd {
/**
* \brief Replace in expressions and in parameters of actions or conditions,
* references to the name of a property by another.
*
* \ingroup IDE
*/
class GD_CORE_API EventsPropertyReplacer
: public ArbitraryEventsWorkerWithContext {
public:
EventsPropertyReplacer(
const gd::Platform &platform_,
const gd::PropertiesContainer &targetPropertiesContainer_,
const std::unordered_map<gd::String, gd::String> &oldToNewPropertyNames_,
const std::unordered_set<gd::String> &removedPropertyNames_)
: platform(platform_),
targetPropertiesContainer(targetPropertiesContainer_),
oldToNewPropertyNames(oldToNewPropertyNames_),
removedPropertyNames(removedPropertyNames_){};
virtual ~EventsPropertyReplacer();
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
bool DoVisitEventExpression(gd::Expression &expression,
const gd::ParameterMetadata &metadata) override;
const gd::Platform &platform;
const gd::PropertiesContainer &targetPropertiesContainer;
const std::unordered_map<gd::String, gd::String> &oldToNewPropertyNames;
const std::unordered_set<gd::String> &removedPropertyNames;
};
} // namespace gd

View File

@@ -20,7 +20,6 @@
#include "GDCore/IDE/Events/InstructionSentenceFormatter.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
using namespace std;
@@ -37,12 +36,14 @@ const gd::String EventsRefactorer::searchIgnoredCharacters = ";:,#()";
class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
public:
ExpressionObjectRenamer(const gd::Platform &platform_,
const gd::ProjectScopedContainers& projectScopedContainers_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_,
const gd::String& objectName_,
const gd::String& objectNewName_)
: platform(platform_),
projectScopedContainers(projectScopedContainers_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootType(rootType_),
hasDoneRenaming(false),
objectName(objectName_),
@@ -50,13 +51,14 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
virtual ~ExpressionObjectRenamer(){};
static bool Rename(const gd::Platform &platform,
const gd::ProjectScopedContainers &projectScopedContainers,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String &rootType,
gd::ExpressionNode& node,
const gd::String& objectName,
const gd::String& objectNewName) {
if (gd::ExpressionValidator::HasNoErrors(platform, projectScopedContainers, rootType, node)) {
ExpressionObjectRenamer renamer(platform, projectScopedContainers, rootType, objectName, objectNewName);
if (gd::ExpressionValidator::HasNoErrors(platform, globalObjectsContainer, objectsContainer, rootType, node)) {
ExpressionObjectRenamer renamer(platform, globalObjectsContainer, objectsContainer, rootType, objectName, objectNewName);
node.Visit(renamer);
return renamer.HasDoneRenaming();
@@ -81,29 +83,6 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
auto type = gd::ExpressionTypeFinder::GetType(platform, objectsContainersList, rootType, node);
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
// Nothing to do (this can't reference an object)
} else {
if (node.name == objectName) {
projectScopedContainers.MatchIdentifierWithName<void>(node.name, [&]() {
// This is an object variable.
hasDoneRenaming = true;
node.name = objectNewName;
}, [&]() {
// This is a variable.
}, [&]() {
// This is a property.
}, [&]() {
// This is a parameter.
}, [&]() {
// This is something else.
});
}
}
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
@@ -115,29 +94,11 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, projectScopedContainers.GetObjectsContainersList(), rootType, node);
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
if (gd::ParameterMetadata::IsObject(type) &&
node.identifierName == objectName) {
hasDoneRenaming = true;
node.identifierName = objectNewName;
} else if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
// Nothing to do (this can't reference an object)
} else {
if (node.identifierName == objectName) {
projectScopedContainers.MatchIdentifierWithName<void>(node.identifierName, [&]() {
// This is an object variable.
hasDoneRenaming = true;
node.identifierName = objectNewName;
}, [&]() {
// This is a variable.
}, [&]() {
// This is a property.
}, [&]() {
// This is a parameter.
}, [&]() {
// This is something else.
});
}
}
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
@@ -163,7 +124,8 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
const gd::String& objectNewName;
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
};
@@ -176,23 +138,26 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
public:
ExpressionObjectFinder(const gd::Platform &platform_,
const gd::ProjectScopedContainers &projectScopedContainers_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_,
const gd::String& searchedObjectName_)
const gd::String& objectName_)
: platform(platform_),
projectScopedContainers(projectScopedContainers_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootType(rootType_),
hasObject(false),
searchedObjectName(searchedObjectName_){};
objectName(objectName_){};
virtual ~ExpressionObjectFinder(){};
static bool CheckIfHasObject(const gd::Platform &platform,
const gd::ProjectScopedContainers &projectScopedContainers,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String &rootType,
gd::ExpressionNode& node,
const gd::String& objectName) {
if (gd::ExpressionValidator::HasNoErrors(platform, projectScopedContainers, rootType, node)) {
ExpressionObjectFinder finder(platform, projectScopedContainers, rootType, objectName);
if (gd::ExpressionValidator::HasNoErrors(platform, globalObjectsContainer, objectsContainer, rootType, node)) {
ExpressionObjectFinder finder(platform, globalObjectsContainer, objectsContainer, rootType, objectName);
node.Visit(finder);
return finder.HasFoundObject();
@@ -217,28 +182,6 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
auto type = gd::ExpressionTypeFinder::GetType(platform, objectsContainersList, rootType, node);
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
// Nothing to do (this can't reference an object)
} else {
if (node.name == searchedObjectName) {
projectScopedContainers.MatchIdentifierWithName<void>(node.name, [&]() {
// This is an object variable.
hasObject = true;
}, [&]() {
// This is a variable.
}, [&]() {
// This is a property.
}, [&]() {
// This is a parameter.
}, [&]() {
// This is something else.
});
}
}
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
@@ -250,36 +193,19 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, projectScopedContainers.GetObjectsContainersList(), rootType, node);
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
if (gd::ParameterMetadata::IsObject(type) &&
node.identifierName == searchedObjectName) {
node.identifierName == objectName) {
hasObject = true;
} else if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
// Nothing to do (this can't reference an object)
} else {
if (node.identifierName == searchedObjectName) {
projectScopedContainers.MatchIdentifierWithName<void>(node.identifierName, [&]() {
// This is an object variable.
hasObject = true;
}, [&]() {
// This is a variable.
}, [&]() {
// This is a property.
}, [&]() {
// This is a parameter.
}, [&]() {
// This is something else.
});
}
}
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (node.objectName == searchedObjectName) {
if (node.objectName == objectName) {
hasObject = true;
}
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
if (node.objectName == searchedObjectName) {
if (node.objectName == objectName) {
hasObject = true;
}
for (auto& parameter : node.parameters) {
@@ -290,15 +216,17 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
private:
bool hasObject;
const gd::String& searchedObjectName;
const gd::String& objectName;
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
};
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& actions,
gd::String oldName,
gd::String newName) {
@@ -317,7 +245,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
"number", instrInfos.parameters[pNb].GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
actions[aId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -327,7 +255,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
"string", instrInfos.parameters[pNb].GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
actions[aId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -337,7 +265,8 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
if (!actions[aId].GetSubInstructions().empty())
somethingModified =
RenameObjectInActions(platform,
projectScopedContainers,
project,
layout,
actions[aId].GetSubInstructions(),
oldName,
newName) ||
@@ -349,7 +278,8 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
bool EventsRefactorer::RenameObjectInConditions(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String oldName,
gd::String newName) {
@@ -369,7 +299,7 @@ bool EventsRefactorer::RenameObjectInConditions(
"number", instrInfos.parameters[pNb].GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
conditions[cId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -379,7 +309,7 @@ bool EventsRefactorer::RenameObjectInConditions(
"string", instrInfos.parameters[pNb].GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
conditions[cId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -389,7 +319,8 @@ bool EventsRefactorer::RenameObjectInConditions(
if (!conditions[cId].GetSubInstructions().empty())
somethingModified =
RenameObjectInConditions(platform,
projectScopedContainers,
project,
layout,
conditions[cId].GetSubInstructions(),
oldName,
newName) ||
@@ -401,7 +332,8 @@ bool EventsRefactorer::RenameObjectInConditions(
bool EventsRefactorer::RenameObjectInEventParameters(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
@@ -416,7 +348,7 @@ bool EventsRefactorer::RenameObjectInEventParameters(
parameterMetadata.GetType())) {
auto node = expression.GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "number", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
@@ -425,7 +357,7 @@ bool EventsRefactorer::RenameObjectInEventParameters(
parameterMetadata.GetType())) {
auto node = expression.GetRootNode();
if (ExpressionObjectRenamer::Rename(platform, projectScopedContainers, "string", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
@@ -434,7 +366,8 @@ bool EventsRefactorer::RenameObjectInEventParameters(
}
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String oldName,
gd::String newName) {
@@ -443,14 +376,14 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
events[i].GetAllConditionsVectors();
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
bool somethingModified = RenameObjectInConditions(
platform, projectScopedContainers, *conditionsVectors[j], oldName, newName);
platform, project, layout, *conditionsVectors[j], oldName, newName);
}
vector<gd::InstructionsList*> actionsVectors =
events[i].GetAllActionsVectors();
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
bool somethingModified = RenameObjectInActions(
platform, projectScopedContainers, *actionsVectors[j], oldName, newName);
platform, project, layout, *actionsVectors[j], oldName, newName);
}
vector<pair<gd::Expression*, gd::ParameterMetadata>>
@@ -460,7 +393,8 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
gd::ParameterMetadata parameterMetadata =
expressionsWithMetadata[j].second;
bool somethingModified = RenameObjectInEventParameters(platform,
projectScopedContainers,
project,
layout,
*expression,
parameterMetadata,
oldName,
@@ -469,7 +403,8 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
if (events[i].CanHaveSubEvents())
RenameObjectInEvents(platform,
projectScopedContainers,
project,
layout,
events[i].GetSubEvents(),
oldName,
newName);
@@ -477,7 +412,8 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
}
bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
gd::InstructionsList& actions,
gd::String name) {
bool somethingModified = false;
@@ -499,7 +435,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
"number", instrInfos.parameters[pNb].GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "number", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "number", *node, name)) {
deleteMe = true;
break;
}
@@ -509,7 +445,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
"string", instrInfos.parameters[pNb].GetType())) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "string", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "string", *node, name)) {
deleteMe = true;
break;
}
@@ -523,7 +459,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
} else if (!actions[aId].GetSubInstructions().empty())
somethingModified =
RemoveObjectInActions(platform,
projectScopedContainers,
globalObjectsContainer,
objectsContainer,
actions[aId].GetSubInstructions(),
name) ||
somethingModified;
@@ -534,7 +471,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
bool EventsRefactorer::RemoveObjectInConditions(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
gd::InstructionsList& conditions,
gd::String name) {
bool somethingModified = false;
@@ -557,7 +495,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
"number", instrInfos.parameters[pNb].GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "number", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "number", *node, name)) {
deleteMe = true;
break;
}
@@ -567,7 +505,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
"string", instrInfos.parameters[pNb].GetType())) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
if (ExpressionObjectFinder::CheckIfHasObject(platform, projectScopedContainers, "string", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "string", *node, name)) {
deleteMe = true;
break;
}
@@ -581,7 +519,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
} else if (!conditions[cId].GetSubInstructions().empty())
somethingModified =
RemoveObjectInConditions(platform,
projectScopedContainers,
globalObjectsContainer,
objectsContainer,
conditions[cId].GetSubInstructions(),
name) ||
somethingModified;
@@ -591,7 +530,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
}
void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
gd::EventsList& events,
gd::String name) {
for (std::size_t i = 0; i < events.size(); ++i) {
@@ -599,19 +539,19 @@ void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
events[i].GetAllConditionsVectors();
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
bool conditionsModified = RemoveObjectInConditions(
platform, projectScopedContainers, *conditionsVectors[j], name);
platform, globalObjectsContainer, objectsContainer, *conditionsVectors[j], name);
}
vector<gd::InstructionsList*> actionsVectors =
events[i].GetAllActionsVectors();
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
bool actionsModified = RemoveObjectInActions(
platform, projectScopedContainers, *actionsVectors[j], name);
platform, globalObjectsContainer, objectsContainer, *actionsVectors[j], name);
}
if (events[i].CanHaveSubEvents())
RemoveObjectInEvents(
platform, projectScopedContainers, events[i].GetSubEvents(), name);
platform, globalObjectsContainer, objectsContainer, events[i].GetSubEvents(), name);
}
}
@@ -647,20 +587,20 @@ std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
for (std::size_t i = 0; i < events.size(); ++i) {
bool eventModified = false;
auto allExpressionsWithMetadata = events[i].GetAllExpressionsWithMetadata();
for (auto& expressionAndMetadata : allExpressionsWithMetadata) {
gd::Expression* expression = expressionAndMetadata.first;
std::vector<gd::Expression*> allObjectExpressions =
events[i].GetAllObjectExpressions();
for (std::size_t j = 0; j < allObjectExpressions.size(); ++j) {
gd::String newExpressionPlainString =
matchCase ? expression->GetPlainString().FindAndReplace(
matchCase ? allObjectExpressions[j]->GetPlainString().FindAndReplace(
toReplace, newString, true)
: ReplaceAllOccurrencesCaseInsensitive(
expression->GetPlainString(),
allObjectExpressions[j]->GetPlainString(),
toReplace,
newString);
if (newExpressionPlainString != expression->GetPlainString()) {
*expression = gd::Expression(newExpressionPlainString);
if (newExpressionPlainString !=
allObjectExpressions[j]->GetPlainString()) {
*allObjectExpressions[j] = gd::Expression(newExpressionPlainString);
if (!eventModified) {
modifiedEvents.push_back(EventsSearchResult(
@@ -875,14 +815,14 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
for (std::size_t i = 0; i < events.size(); ++i) {
bool eventAddedInResults = false;
auto allExpressionsWithMetadata = events[i].GetAllExpressionsWithMetadata();
for (auto& expressionAndMetadata : allExpressionsWithMetadata) {
gd::Expression* expression = expressionAndMetadata.first;
std::vector<gd::Expression*> allObjectExpressions =
events[i].GetAllObjectExpressions();
for (std::size_t j = 0; j < allObjectExpressions.size(); ++j) {
size_t foundPosition =
matchCase
? expression->GetPlainString().find(search)
: expression->GetPlainString().FindCaseInsensitive(search);
? allObjectExpressions[j]->GetPlainString().find(search)
: allObjectExpressions[j]->GetPlainString().FindCaseInsensitive(
search);
if (foundPosition != gd::String::npos && !eventAddedInResults) {
results.push_back(EventsSearchResult(

View File

@@ -14,8 +14,6 @@
namespace gd {
class EventsList;
class ObjectsContainer;
class ObjectsContainersList;
class ProjectScopedContainers;
class Platform;
class ExternalEvents;
class BaseEvent;
@@ -81,7 +79,8 @@ class GD_CORE_API EventsRefactorer {
* events ).
*/
static void RenameObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String oldName,
gd::String newName);
@@ -90,7 +89,8 @@ class GD_CORE_API EventsRefactorer {
* Remove all actions or conditions using an object
*/
static void RemoveObjectInEvents(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String name);
@@ -136,7 +136,8 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RenameObjectInActions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
@@ -148,7 +149,8 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RenameObjectInConditions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
@@ -161,7 +163,8 @@ class GD_CORE_API EventsRefactorer {
*/
static bool RenameObjectInEventParameters(
const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
@@ -173,7 +176,8 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RemoveObjectInConditions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String name);
@@ -183,7 +187,8 @@ class GD_CORE_API EventsRefactorer {
* \return true if something was modified.
*/
static bool RemoveObjectInActions(const gd::Platform& platform,
gd::ProjectScopedContainers& projectScopedContainers,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String name);

View File

@@ -1,404 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/EventsVariableReplacer.h"
#include <map>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
/**
* \brief Go through the nodes and rename variables,
* or signal if the instruction must be renamed if a removed variable is used.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionVariableReplacer
: public ExpressionParser2NodeWorker {
public:
ExpressionVariableReplacer(
const gd::Platform& platform_,
const gd::ProjectScopedContainers& projectScopedContainers_,
const gd::VariablesContainer& targetVariablesContainer_,
const std::unordered_map<gd::String, gd::String>& oldToNewVariableNames_,
const std::unordered_set<gd::String>& removedVariableNames_)
: hasDoneRenaming(false),
removedVariableUsed(false),
platform(platform_),
projectScopedContainers(projectScopedContainers_),
forcedInitialVariablesContainer(nullptr),
targetVariablesContainer(targetVariablesContainer_),
oldToNewVariableNames(oldToNewVariableNames_),
removedVariableNames(removedVariableNames_){};
virtual ~ExpressionVariableReplacer(){};
void SetForcedInitialVariablesContainer(
const gd::VariablesContainer* forcedInitialVariablesContainer_) {
forcedInitialVariablesContainer = forcedInitialVariablesContainer_;
}
bool HasDoneRenaming() const { return hasDoneRenaming; }
bool IsRemovedVariableUsed() const { return removedVariableUsed; }
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 {
// The node represents a variable or an object name on which a variable
// will be accessed.
if (forcedInitialVariablesContainer) {
// A scope was forced. Honor it: it means this node represents a variable
// of the forced variables container.
if (forcedInitialVariablesContainer == &targetVariablesContainer) {
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
}
if (node.child) node.child->Visit(*this);
return;
}
// Match the potential *new* name of the variable, because refactorings are
// done after changes in the variables container.
projectScopedContainers.MatchIdentifierWithName<void>(
GetPotentialNewName(node.name),
[&]() {
// This represents an object.
// Remember the object name.
objectNameToUseForVariableAccessor = node.name;
if (node.child) node.child->Visit(*this);
objectNameToUseForVariableAccessor = "";
},
[&]() {
// This is a variable.
if (projectScopedContainers.GetVariablesContainersList()
.HasVariablesContainer(targetVariablesContainer)) {
// The node represents a variable, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
}
if (node.child) node.child->Visit(*this);
},
[&]() {
// This is a property.
if (node.child) node.child->Visit(*this);
},
[&]() {
// This is a parameter.
if (node.child) node.child->Visit(*this);
},
[&]() {
// This is something else - potentially a deleted variable.
if (projectScopedContainers.GetVariablesContainersList()
.HasVariablesContainer(targetVariablesContainer)) {
// The node represents a variable, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
}
if (node.child) node.child->Visit(*this);
});
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
auto& objectsContainersList =
projectScopedContainers.GetObjectsContainersList();
if (!objectNameToUseForVariableAccessor.empty()) {
if (objectsContainersList.HasVariablesContainer(
objectNameToUseForVariableAccessor, targetVariablesContainer)) {
// The node represents an object variable, and this object variables are
// the target. Do the replacement or removals:
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
}
}
objectNameToUseForVariableAccessor = "";
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
objectNameToUseForVariableAccessor = "";
node.expression->Visit(*this);
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
auto& objectsContainersList =
projectScopedContainers.GetObjectsContainersList();
// The node represents a variable or an object variable in an expression
// (and if it's a variable reference or a value does not have any importance
// here).
if (forcedInitialVariablesContainer) {
// A scope was forced. Honor it: it means this node represents a variable
// of the forced variables container.
if (forcedInitialVariablesContainer == &targetVariablesContainer) {
RenameOrRemoveVariableOfTargetVariableContainer(node.identifierName);
}
return;
}
// Match the potential *new* name of the variable, because refactorings are
// done after changes in the variables container.
projectScopedContainers.MatchIdentifierWithName<void>(
GetPotentialNewName(node.identifierName),
[&]() {
// This represents an object.
if (objectsContainersList.HasVariablesContainer(
node.identifierName, targetVariablesContainer)) {
// The node represents an object variable, and this object variables
// are the target. Do the replacement or removals:
RenameOrRemoveVariableOfTargetVariableContainer(
node.childIdentifierName);
}
},
[&]() {
// This is a variable.
if (projectScopedContainers.GetVariablesContainersList()
.HasVariablesContainer(targetVariablesContainer)) {
// The node represents a variable, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemoveVariableOfTargetVariableContainer(
node.identifierName);
}
},
[&]() {
// This is a property.
},
[&]() {
// This is a parameter.
},
[&]() {
// This is something else - potentially a deleted variable.
if (projectScopedContainers.GetVariablesContainersList()
.HasVariablesContainer(targetVariablesContainer)) {
// The node represents a variable, that can come from the target
// (because the target is in the scope), replace or remove it:
RenameOrRemoveVariableOfTargetVariableContainer(
node.identifierName);
}
});
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
const gd::ExpressionMetadata& metadata =
MetadataProvider::GetFunctionCallMetadata(
platform, projectScopedContainers.GetObjectsContainersList(), node);
for (size_t parameterIndex = 0; parameterIndex < node.parameters.size();
++parameterIndex) {
const gd::ParameterMetadata* parameterMetadata =
MetadataProvider::GetFunctionCallParameterMetadata(
platform,
projectScopedContainers.GetObjectsContainersList(),
node,
parameterIndex);
// Handle legacy pre-scoped variable parameters: in this case, we
// force the "scope" at which starts the evalution of variables.
if (parameterMetadata && parameterMetadata->GetValueTypeMetadata()
.IsLegacyPreScopedVariable()) {
const gd::VariablesContainer* oldForcedInitialVariablesContainer =
forcedInitialVariablesContainer;
forcedInitialVariablesContainer = nullptr;
if (parameterMetadata->GetType() == "globalvar") {
forcedInitialVariablesContainer =
projectScopedContainers.GetVariablesContainersList()
.GetTopMostVariablesContainer();
} else if (parameterMetadata->GetType() == "scenevar") {
forcedInitialVariablesContainer =
projectScopedContainers.GetVariablesContainersList()
.GetBottomMostVariablesContainer();
} else if (parameterMetadata->GetType() == "objectvar") {
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform,
projectScopedContainers.GetObjectsContainersList(),
node.objectName,
*node.parameters[parameterIndex].get());
forcedInitialVariablesContainer =
projectScopedContainers.GetObjectsContainersList()
.GetObjectOrGroupVariablesContainer(objectName);
}
node.parameters[parameterIndex]->Visit(*this);
forcedInitialVariablesContainer = oldForcedInitialVariablesContainer;
} else {
// For any other parameter, there is no special treatment being needed.
node.parameters[parameterIndex]->Visit(*this);
}
}
}
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
bool hasDoneRenaming;
bool removedVariableUsed;
const gd::String& GetPotentialNewName(const gd::String& oldName) {
return oldToNewVariableNames.count(oldName) >= 1
? oldToNewVariableNames.find(oldName)->second
: oldName;
}
bool RenameOrRemoveVariableOfTargetVariableContainer(
gd::String& variableName) {
if (oldToNewVariableNames.count(variableName) >= 1) {
variableName = oldToNewVariableNames.find(variableName)->second;
hasDoneRenaming = true;
return true;
} else if (removedVariableNames.count(variableName) >= 1) {
removedVariableUsed = true;
return true;
}
return false; // Nothing was changed or done.
}
// Scope:
const gd::Platform& platform;
const gd::ProjectScopedContainers& projectScopedContainers;
const gd::VariablesContainer* forcedInitialVariablesContainer;
// Renaming or removing to do:
const gd::VariablesContainer& targetVariablesContainer;
const std::unordered_map<gd::String, gd::String>& oldToNewVariableNames;
const std::unordered_set<gd::String>& removedVariableNames;
gd::String objectNameToUseForVariableAccessor;
};
const gd::VariablesContainer*
EventsVariableReplacer::FindForcedVariablesContainerIfAny(
const gd::String& type, const gd::String& lastObjectName) {
// Handle legacy pre-scoped variable parameters: in this case, we
// force the "scope" at which starts the evalution of variables.
if (type == "objectvar") {
return GetProjectScopedContainers()
.GetObjectsContainersList()
.GetObjectOrGroupVariablesContainer(lastObjectName);
} else if (type == "globalvar") {
return GetProjectScopedContainers()
.GetVariablesContainersList()
.GetTopMostVariablesContainer();
} else if (type == "scenevar") {
return GetProjectScopedContainers()
.GetVariablesContainersList()
.GetBottomMostVariablesContainer();
}
return nullptr;
}
bool EventsVariableReplacer::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const auto& metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
bool shouldDeleteInstruction = false;
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
instruction.GetParameters(),
metadata.GetParameters(),
[&](const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName) {
const gd::String& type = parameterMetadata.GetType();
if (!gd::ParameterMetadata::IsExpression("variable", type) &&
!gd::ParameterMetadata::IsExpression("number", type) &&
!gd::ParameterMetadata::IsExpression("string", type))
return; // Not an expression that can contain variables.
auto node = parameterValue.GetRootNode();
if (node) {
ExpressionVariableReplacer renamer(platform,
GetProjectScopedContainers(),
targetVariablesContainer,
oldToNewVariableNames,
removedVariableNames);
renamer.SetForcedInitialVariablesContainer(
FindForcedVariablesContainerIfAny(type, lastObjectName));
node->Visit(renamer);
if (renamer.IsRemovedVariableUsed()) {
shouldDeleteInstruction = true;
} else if (renamer.HasDoneRenaming()) {
instruction.SetParameter(
parameterIndex, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
});
return shouldDeleteInstruction;
}
bool EventsVariableReplacer::DoVisitEventExpression(
gd::Expression& expression, const gd::ParameterMetadata& metadata) {
const gd::String& type = metadata.GetType();
if (!gd::ParameterMetadata::IsExpression("variable", type) &&
!gd::ParameterMetadata::IsExpression("number", type) &&
!gd::ParameterMetadata::IsExpression("string", type))
return false; // Not an expression that can contain variables.
auto node = expression.GetRootNode();
if (node) {
ExpressionVariableReplacer renamer(platform,
GetProjectScopedContainers(),
targetVariablesContainer,
oldToNewVariableNames,
removedVariableNames);
renamer.SetForcedInitialVariablesContainer(
FindForcedVariablesContainerIfAny(type, ""));
node->Visit(renamer);
if (renamer.IsRemovedVariableUsed()) {
return true;
} else if (renamer.HasDoneRenaming()) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
return false;
}
EventsVariableReplacer::~EventsVariableReplacer() {}
} // namespace gd

View File

@@ -1,60 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#pragma once
#include <map>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class VariablesContainer;
class EventsList;
class Platform;
} // namespace gd
namespace gd {
/**
* \brief Replace in expressions and in parameters of actions or conditions,
* references to the name of a variable by another.
*
* \ingroup IDE
*/
class GD_CORE_API EventsVariableReplacer
: public ArbitraryEventsWorkerWithContext {
public:
EventsVariableReplacer(
const gd::Platform &platform_,
const gd::VariablesContainer &targetVariablesContainer_,
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames_,
const std::unordered_set<gd::String> &removedVariableNames_)
: platform(platform_),
targetVariablesContainer(targetVariablesContainer_),
oldToNewVariableNames(oldToNewVariableNames_),
removedVariableNames(removedVariableNames_){};
virtual ~EventsVariableReplacer();
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
bool DoVisitEventExpression(gd::Expression &expression,
const gd::ParameterMetadata &metadata) override;
const gd::VariablesContainer *FindForcedVariablesContainerIfAny(
const gd::String &type, const gd::String &lastObjectName);
const gd::Platform &platform;
const gd::VariablesContainer &targetVariablesContainer;
gd::String objectName;
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames;
const std::unordered_set<gd::String> &removedVariableNames;
};
} // namespace gd

View File

@@ -17,7 +17,6 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/IDE/DependenciesAnalyzer.h"
@@ -35,12 +34,14 @@ class GD_CORE_API VariableFinderExpressionNodeWorker
public:
VariableFinderExpressionNodeWorker(std::set<gd::String>& results_,
const gd::Platform &platform_,
const gd::ProjectScopedContainers &projectScopedContainers_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String& parameterType_,
const gd::String& objectName_ = "")
: results(results_),
platform(platform_),
projectScopedContainers(projectScopedContainers_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
parameterType(parameterType_),
objectName(objectName_){};
virtual ~VariableFinderExpressionNodeWorker(){};
@@ -59,9 +60,6 @@ class GD_CORE_API VariableFinderExpressionNodeWorker
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
// We don't check variables or object variables here, because object variables only work
// if the variable is already declared.
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
@@ -72,10 +70,7 @@ class GD_CORE_API VariableFinderExpressionNodeWorker
node.expression->Visit(*this);
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
// We don't check object variables here, because object variables only work
// if the variable is already declared.
}
void OnVisitIdentifierNode(IdentifierNode& node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
bool considerFunction = objectName.empty() || node.objectName == objectName;
@@ -84,7 +79,7 @@ class GD_CORE_API VariableFinderExpressionNodeWorker
const gd::ExpressionMetadata &metadata = isObjectFunction ?
MetadataProvider::GetObjectAnyExpressionMetadata(
platform,
projectScopedContainers.GetObjectsContainersList().GetTypeOfObject(objectName),
GetTypeOfObject(globalObjectsContainer, objectsContainer, objectName),
node.functionName):
MetadataProvider::GetAnyExpressionMetadata(platform, node.functionName);
@@ -115,7 +110,8 @@ class GD_CORE_API VariableFinderExpressionNodeWorker
private:
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
std::set<gd::String>& results; ///< Reference to the std::set where argument
///< values must be stored.
@@ -167,7 +163,8 @@ class GD_CORE_API VariableFinderEventWorker
VariableFinderExpressionNodeWorker searcher(
results,
platform,
GetProjectScopedContainers(),
GetGlobalObjectsContainer(),
GetObjectsContainer(),
parameterType,
objectName);
node->Visit(searcher);
@@ -255,8 +252,7 @@ void EventsVariablesFinder::FindArgumentsInEventsAndDependencies(
platform,
parameterType,
objectName);
eventWorker.Launch(layout.GetEvents(),
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout));
eventWorker.Launch(layout.GetEvents(), project, layout);
DependenciesAnalyzer dependenciesAnalyzer = DependenciesAnalyzer(project, layout);
dependenciesAnalyzer.Analyze();
@@ -267,8 +263,7 @@ void EventsVariablesFinder::FindArgumentsInEventsAndDependencies(
platform,
parameterType,
objectName);
eventWorker.Launch(externalEvents.GetEvents(),
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout));
eventWorker.Launch(externalEvents.GetEvents(), project, layout);
}
for (const gd::String& sceneName : dependenciesAnalyzer.GetScenesDependencies()) {
const gd::Layout& dependencyLayout = project.GetLayout(sceneName);
@@ -277,8 +272,7 @@ void EventsVariablesFinder::FindArgumentsInEventsAndDependencies(
platform,
parameterType,
objectName);
eventWorker.Launch(dependencyLayout.GetEvents(),
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, dependencyLayout));
eventWorker.Launch(dependencyLayout.GetEvents(), project, dependencyLayout);
}
}

View File

@@ -10,15 +10,21 @@ namespace gd {
const gd::ParameterMetadata
ExpressionCompletionDescription::badParameterMetadata;
const gd::ObjectConfiguration
ExpressionCompletionDescription::badObjectConfiguration;
/**
* \brief Turn an ExpressionCompletionDescription to a string.
*/
std::ostream& operator<<(std::ostream& os,
ExpressionCompletionDescription const& value) {
os << value.ToString();
os << "{ " << value.GetCompletionKind() << ", " << value.GetType() << ", "
<< value.GetPrefix() << ", " << value.GetObjectName() << ", "
<< value.GetBehaviorName() << ", "
<< (value.IsExact() ? "exact" : "non-exact") << ", "
<< (value.IsLastParameter() ? "last parameter" : "not last parameter")
<< ", "
<< (value.HasParameterMetadata()
? gd::String::From(&value.GetParameterMetadata())
: "no parameter metadata")
<< " }";
return os;
}

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,6 @@
namespace gd {
class Expression;
class ObjectsContainer;
class ObjectsContainersList;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
@@ -41,10 +40,11 @@ class GD_CORE_API ExpressionLeftSideTypeFinder : public ExpressionParser2NodeWor
* operations.
*/
static const gd::String GetType(const gd::Platform &platform,
const gd::ObjectsContainersList &objectsContainersList,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
gd::ExpressionNode& node) {
gd::ExpressionLeftSideTypeFinder typeFinder(
platform, objectsContainersList);
platform, globalObjectsContainer, objectsContainer);
node.Visit(typeFinder);
return typeFinder.GetType();
}
@@ -53,9 +53,11 @@ class GD_CORE_API ExpressionLeftSideTypeFinder : public ExpressionParser2NodeWor
protected:
ExpressionLeftSideTypeFinder(const gd::Platform &platform_,
const gd::ObjectsContainersList &objectsContainersList_)
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_)
: platform(platform_),
objectsContainersList(objectsContainersList_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
type("unknown") {};
const gd::String &GetType() {
@@ -83,7 +85,7 @@ class GD_CORE_API ExpressionLeftSideTypeFinder : public ExpressionParser2NodeWor
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
platform, objectsContainersList, node);
platform, globalObjectsContainer, objectsContainer, node);
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
type = "unknown";
}
@@ -111,7 +113,8 @@ class GD_CORE_API ExpressionLeftSideTypeFinder : public ExpressionParser2NodeWor
gd::String type;
const gd::Platform &platform;
const gd::ObjectsContainersList &objectsContainersList;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
};

View File

@@ -21,7 +21,6 @@
namespace gd {
class Expression;
class ObjectsContainer;
class ObjectsContainersList;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
@@ -32,7 +31,7 @@ namespace gd {
/**
* \brief Find the type of the expression or sub-expression that a given node
* represents.
*
*
* The type returned by this worker is a mix of:
* - an expected type looking up like a parameter declaration
* - an actual type looking down, but only looking at the most left branch
@@ -51,11 +50,12 @@ class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
* sub-expression that a given node represents.
*/
static const gd::String GetType(const gd::Platform &platform,
const gd::ObjectsContainersList &objectsContainersList,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String &rootType,
gd::ExpressionNode& node) {
gd::ExpressionTypeFinder typeFinder(
platform, objectsContainersList, rootType);
platform, globalObjectsContainer, objectsContainer, rootType);
node.Visit(typeFinder);
return typeFinder.GetType();
}
@@ -64,10 +64,12 @@ class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
protected:
ExpressionTypeFinder(const gd::Platform &platform_,
const gd::ObjectsContainersList &objectsContainersList_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_)
: platform(platform_),
objectsContainersList(objectsContainersList_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootType(rootType_),
type(ExpressionTypeFinder::unknownType),
child(nullptr) {};
@@ -112,8 +114,9 @@ class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
type = ExpressionTypeFinder::unknownType;
}
auto leftSideType = gd::ExpressionLeftSideTypeFinder::GetType(
platform,
objectsContainersList,
platform,
globalObjectsContainer,
objectsContainer,
node);
if (leftSideType == ExpressionTypeFinder::numberType
|| leftSideType == ExpressionTypeFinder::stringType) {
@@ -126,7 +129,7 @@ class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
if (child == nullptr) {
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
platform, objectsContainersList, node);
platform, globalObjectsContainer, objectsContainer, node);
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
VisitParent(node);
}
@@ -138,7 +141,8 @@ class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
const gd::ParameterMetadata* parameterMetadata =
gd::MetadataProvider::GetFunctionCallParameterMetadata(
platform,
objectsContainersList,
globalObjectsContainer,
objectsContainer,
node,
*child);
if (parameterMetadata == nullptr || parameterMetadata->GetType().empty()) {
@@ -158,8 +162,9 @@ class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
}
else if (rootType == ExpressionTypeFinder::numberOrStringType) {
auto leftSideType = gd::ExpressionLeftSideTypeFinder::GetType(
platform,
objectsContainersList,
platform,
globalObjectsContainer,
objectsContainer,
node);
if (leftSideType == ExpressionTypeFinder::numberType
|| leftSideType == ExpressionTypeFinder::stringType) {
@@ -183,7 +188,8 @@ class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
ExpressionNode *child;
const gd::Platform &platform;
const gd::ObjectsContainersList &objectsContainersList;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
};

View File

@@ -11,20 +11,16 @@
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Expression.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/Project/VariablesContainersList.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
using namespace std;
@@ -63,167 +59,61 @@ size_t GetMaximumParametersNumber(
} // namespace
bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
const gd::IdentifierNode& identifier) {
auto validateVariableTypeForExpression =
[this, &identifier](gd::Variable::Type type) {
// Collections type can't be used directly in expressions, a child
// must be accessed.
if (type == Variable::Structure) {
RaiseTypeError(_("You need to specify the name of the child variable "
"to access. For example: `MyVariable.child`."),
identifier.identifierNameLocation);
} else if (type == Variable::Array) {
RaiseTypeError(_("You need to specify the name of the child variable "
"to access. For example: `MyVariable[0]`."),
identifier.identifierNameLocation);
ExpressionValidator::Type ExpressionValidator::ValidateFunction(const gd::FunctionCallNode& function) {
} else {
// Number, string or boolean variables can be used in expressions.
return;
}
};
const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
const auto& propertiesContainersList = projectScopedContainers.GetPropertiesContainersList();
const auto& parametersVectorsList = projectScopedContainers.GetParametersVectorsList();
return projectScopedContainers.MatchIdentifierWithName<bool>(identifier.identifierName,
[&]() {
// This represents an object.
if (identifier.childIdentifierName.empty()) {
RaiseTypeError(_("An object variable or expression should be entered."),
identifier.identifierNameLocation);
return true; // We should have found a variable.
}
if (!objectsContainersList.HasObjectOrGroupWithVariableNamed(identifier.identifierName, identifier.childIdentifierName)) {
RaiseTypeError(_("This variable does not exist on this object or group."),
identifier.identifierNameLocation);
return true; // We should have found a variable.
}
return true; // We found a variable.
}, [&]() {
// This is a variable.
// Try to identify a declared variable with the name (and maybe the child
// variable).
const gd::Variable& variable =
variablesContainersList.Get(identifier.identifierName);
if (identifier.childIdentifierName.empty()) {
// Just the root variable is accessed, check it can be used in an
// expression.
validateVariableTypeForExpression(variable.GetType());
return true; // We found a variable.
} else {
// A child variable is accessed, check it can be used in an expression.
if (!variable.HasChild(identifier.childIdentifierName)) {
RaiseTypeError(_("No child variable with this name found."),
identifier.childIdentifierNameLocation);
return true; // We should have found a variable.
}
const gd::Variable& childVariable =
variable.GetChild(identifier.childIdentifierName);
return true; // We found a variable.
}
}, [&]() {
// This is a property.
if (!identifier.childIdentifierName.empty()) {
RaiseTypeError(_("Accessing a child variable of a property is not possible - just write the property name."),
identifier.childIdentifierNameLocation);
return true; // We found a property, even if the child is not allowed.
}
return true; // We found a property.
}, [&]() {
// This is a parameter.
if (!identifier.childIdentifierName.empty()) {
RaiseTypeError(_("Accessing a child variable of a parameter is not possible - just write the parameter name."),
identifier.childIdentifierNameLocation);
return true; // We found a parameter, even if the child is not allowed.
}
const auto& parameter = gd::ParameterMetadataTools::Get(parametersVectorsList, identifier.identifierName);
const auto& valueTypeMetadata = parameter.GetValueTypeMetadata();
if (!valueTypeMetadata.IsNumber() && !valueTypeMetadata.IsString() && !valueTypeMetadata.IsBoolean()) {
RaiseTypeError(_("This parameter is not a string, number or boolean - it can't be used in an expression."),
identifier.identifierNameLocation);
return true; // We found a parameter, even though the type is incompatible.
}
return true; // We found a parameter.
}, [&]() {
// This is something else.
return false;
});
}
ExpressionValidator::Type ExpressionValidator::ValidateFunction(
const gd::FunctionCallNode& function) {
ReportAnyError(function);
gd::String objectType = function.objectName.empty() ? "" :
GetTypeOfObject(globalObjectsContainer, objectsContainer, function.objectName);
gd::String behaviorType = function.behaviorName.empty() ? "" :
GetTypeOfBehavior(globalObjectsContainer, objectsContainer, function.behaviorName);
auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
gd::String objectType =
function.objectName.empty()
? ""
: objectsContainersList.GetTypeOfObject(function.objectName);
gd::String behaviorType = function.behaviorName.empty()
? ""
: objectsContainersList.GetTypeOfBehavior(function.behaviorName);
const gd::ExpressionMetadata& metadata =
function.behaviorName.empty()
? function.objectName.empty()
? MetadataProvider::GetAnyExpressionMetadata(
platform, function.functionName)
: MetadataProvider::GetObjectAnyExpressionMetadata(
platform, objectType, function.functionName)
: MetadataProvider::GetBehaviorAnyExpressionMetadata(
platform, behaviorType, function.functionName);
const gd::ExpressionMetadata &metadata = function.behaviorName.empty() ?
function.objectName.empty() ?
MetadataProvider::GetAnyExpressionMetadata(platform, function.functionName) :
MetadataProvider::GetObjectAnyExpressionMetadata(
platform, objectType, function.functionName) :
MetadataProvider::GetBehaviorAnyExpressionMetadata(
platform, behaviorType, function.functionName);
Type returnType = StringToType(metadata.GetReturnType());
if (!function.objectName.empty() &&
!objectsContainersList.HasObjectOrGroupNamed(function.objectName)) {
!globalObjectsContainer.HasObjectNamed(function.objectName) &&
!globalObjectsContainer.GetObjectGroups().Has(function.objectName) &&
!objectsContainer.HasObjectNamed(function.objectName) &&
!objectsContainer.GetObjectGroups().Has(function.objectName)) {
RaiseTypeError(_("This object doesn't exist."),
function.objectNameLocation,
/*isFatal=*/false);
function.objectNameLocation, /*isFatal=*/false);
return returnType;
}
if (!function.behaviorName.empty() &&
!objectsContainersList.HasBehaviorInObjectOrGroup(function.objectName,
function.behaviorName)) {
!gd::HasBehaviorInObjectOrGroup(globalObjectsContainer, objectsContainer,
function.objectName,
function.behaviorName)) {
RaiseTypeError(_("This behavior is not attached to this object."),
function.behaviorNameLocation,
/*isFatal=*/false);
function.behaviorNameLocation, /*isFatal=*/false);
return returnType;
}
if (!function.objectName.empty() &&
// If the function needs a capability on the object that may not be
// covered by all objects, check it now.
!metadata.GetRequiredBaseObjectCapability().empty()) {
const gd::ObjectMetadata& objectMetadata =
// If the function needs a capability on the object that may not be covered
// by all objects, check it now.
!metadata.GetRequiredBaseObjectCapability().empty()) {
const gd::ObjectMetadata &objectMetadata =
MetadataProvider::GetObjectMetadata(platform, objectType);
}
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
RaiseError("invalid_function_name",
_("Cannot find an expression with this name: ") +
function.functionName + "\n" +
_("Double check that you've not made any typo in the name."),
function.location);
return returnType;
RaiseError(
"invalid_function_name",
_("Cannot find an expression with this name: ") +
function.functionName + "\n" +
_("Double check that you've not made any typo in the name."),
function.location);
return returnType;
}
// Validate the type of the function
@@ -238,9 +128,9 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
} else if (parentType != Type::Number &&
parentType != Type::NumberOrString) {
RaiseTypeError(_("You tried to use an expression that returns a "
"number, but another type is expected:") +
" " + TypeToString(parentType),
function.location);
"number, but another type is expected:") +
" " + TypeToString(parentType),
function.location);
return returnType;
}
} else if (returnType == Type::String) {
@@ -254,16 +144,16 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
} else if (parentType != Type::String &&
parentType != Type::NumberOrString) {
RaiseTypeError(_("You tried to use an expression that returns a "
"string, but another type is expected:") +
" " + TypeToString(parentType),
function.location);
"string, but another type is expected:") +
" " + TypeToString(parentType),
function.location);
return returnType;
}
} else {
if (parentType != returnType) {
RaiseTypeError(
_("You tried to use an expression with the wrong return type:") +
" " + TypeToString(returnType),
_("You tried to use an expression with the wrong return type:") + " " +
TypeToString(returnType),
function.location);
return returnType;
}
@@ -272,12 +162,10 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
// Validate parameters count
size_t minParametersCount = GetMinimumParametersNumber(
metadata.parameters,
ExpressionParser2::WrittenParametersFirstIndex(function.objectName,
function.behaviorName));
ExpressionParser2::WrittenParametersFirstIndex(function.objectName, function.behaviorName));
size_t maxParametersCount = GetMaximumParametersNumber(
metadata.parameters,
ExpressionParser2::WrittenParametersFirstIndex(function.objectName,
function.behaviorName));
ExpressionParser2::WrittenParametersFirstIndex(function.objectName, function.behaviorName));
if (function.parameters.size() < minParametersCount ||
function.parameters.size() > maxParametersCount) {
gd::String expectedCountMessage =
@@ -291,29 +179,28 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
if (function.parameters.size() < minParametersCount) {
RaiseError(
"too_few_parameters",
_("You have not entered enough parameters for the expression.") +
" " + expectedCountMessage,
_("You have not entered enough parameters for the expression.") + " " +
expectedCountMessage,
function.location);
} else {
RaiseError(
"extra_parameter",
_("This parameter was not expected by this expression. Remove it "
"or verify that you've entered the proper expression name.") +
" " + expectedCountMessage,
ExpressionParserLocation(function.parameters[maxParametersCount]
->location.GetStartPosition(),
function.location.GetEndPosition() - 1));
"or verify that you've entered the proper expression name.") + " " +
expectedCountMessage,
ExpressionParserLocation(
function.parameters[maxParametersCount]->location.GetStartPosition(),
function.location.GetEndPosition() - 1));
}
return returnType;
}
// TODO: reverse the order of diagnostic?
size_t writtenParametersFirstIndex =
ExpressionParser2::WrittenParametersFirstIndex(function.objectName,
function.behaviorName);
ExpressionParser2::WrittenParametersFirstIndex(
function.objectName, function.behaviorName);
int metadataIndex = writtenParametersFirstIndex;
for (int parameterIndex = 0; parameterIndex < function.parameters.size();
parameterIndex++) {
for (int parameterIndex = 0; parameterIndex < function.parameters.size(); parameterIndex++) {
auto& parameter = function.parameters[parameterIndex];
while (metadata.GetParameters()[metadataIndex].IsCodeOnly()) {
// The sizes are already checked above.
@@ -321,45 +208,45 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
}
auto& parameterMetadata = metadata.GetParameters()[metadataIndex];
if (!parameterMetadata.IsOptional() ||
dynamic_cast<EmptyNode*>(parameter.get()) == nullptr) {
if (!parameterMetadata.IsOptional() || dynamic_cast<EmptyNode*>(parameter.get()) == nullptr) {
auto currentParentType = parentType;
parentType = StringToType(parameterMetadata.GetType());
parameter->Visit(*this);
parentType = currentParentType;
const gd::String& expectedParameterType = parameterMetadata.GetType();
const gd::String &expectedParameterType = parameterMetadata.GetType();
if (gd::ParameterMetadata::IsExpression(
ExpressionValidator::variableTypeString, expectedParameterType)) {
if (dynamic_cast<IdentifierNode*>(parameter.get()) == nullptr &&
dynamic_cast<VariableNode*>(parameter.get()) == nullptr) {
RaiseError("malformed_variable_parameter",
_("A variable name was expected but something else was "
"written. Enter just the name of the variable for this "
"parameter."),
parameter->location);
ExpressionValidator::variableTypeString, expectedParameterType)) {
if (dynamic_cast<IdentifierNode *>(parameter.get()) == nullptr
&& dynamic_cast<VariableNode *>(parameter.get()) == nullptr) {
RaiseError(
"malformed_variable_parameter",
_("A variable name was expected but something else was "
"written. Enter just the name of the variable for this "
"parameter."),
parameter->location);
}
} else if (gd::ParameterMetadata::IsObject(expectedParameterType)) {
if (dynamic_cast<IdentifierNode*>(parameter.get()) == nullptr) {
RaiseError("malformed_object_parameter",
_("An object name was expected but something else was "
"written. Enter just the name of the object for this "
"parameter."),
parameter->location);
if (dynamic_cast<IdentifierNode *>(parameter.get()) == nullptr) {
RaiseError(
"malformed_object_parameter",
_("An object name was expected but something else was "
"written. Enter just the name of the object for this "
"parameter."),
parameter->location);
}
}
// String and number are already checked in children.
else if (!gd::ParameterMetadata::IsExpression(
ExpressionValidator::numberTypeString,
expectedParameterType) &&
!gd::ParameterMetadata::IsExpression(
ExpressionValidator::stringTypeString,
expectedParameterType)) {
RaiseError("unknown_parameter_type",
_("This function is improperly set up. Reach out to the "
"extension developer or a GDevelop maintainer to fix "
"this issue"),
parameter->location);
ExpressionValidator::numberTypeString, expectedParameterType)
&& !gd::ParameterMetadata::IsExpression(
ExpressionValidator::stringTypeString, expectedParameterType)) {
RaiseError(
"unknown_parameter_type",
_("This function is improperly set up. Reach out to the "
"extension developer or a GDevelop maintainer to fix "
"this issue"),
parameter->location);
}
}
metadataIndex++;
@@ -367,60 +254,55 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
return returnType;
}
// TODO factorize in a file with an enum and helpers?
const gd::String ExpressionValidator::unknownTypeString = "unknown";
const gd::String ExpressionValidator::numberTypeString = "number";
const gd::String ExpressionValidator::stringTypeString = "string";
const gd::String ExpressionValidator::numberOrStringTypeString =
"number|string";
const gd::String ExpressionValidator::variableTypeString = "variable";
const gd::String ExpressionValidator::objectTypeString = "object";
const gd::String ExpressionValidator::emptyTypeString = "empty";
// TODO factorize in a file with an enum and helpers?
const gd::String ExpressionValidator::unknownTypeString = "unknown";
const gd::String ExpressionValidator::numberTypeString = "number";
const gd::String ExpressionValidator::stringTypeString = "string";
const gd::String ExpressionValidator::numberOrStringTypeString = "number|string";
const gd::String ExpressionValidator::variableTypeString = "variable";
const gd::String ExpressionValidator::objectTypeString = "object";
const gd::String ExpressionValidator::emptyTypeString = "empty";
const gd::String& ExpressionValidator::TypeToString(Type type) {
switch (type) {
case Type::Unknown:
const gd::String &ExpressionValidator::TypeToString(Type type) {
switch (type) {
case Type::Unknown:
return unknownTypeString;
case Type::Number:
case Type::Number:
return numberTypeString;
case Type::String:
case Type::String:
return stringTypeString;
case Type::NumberOrString:
case Type::NumberOrString:
return numberOrStringTypeString;
case Type::Variable:
case Type::Variable:
return variableTypeString;
case Type::Object:
case Type::Object:
return objectTypeString;
case Type::Empty:
case Type::Empty:
return emptyTypeString;
}
return unknownTypeString;
}
return unknownTypeString;
}
ExpressionValidator::Type ExpressionValidator::StringToType(
const gd::String& type) {
if (type == ExpressionValidator::numberTypeString ||
gd::ParameterMetadata::IsExpression(ExpressionValidator::numberTypeString,
type)) {
return Type::Number;
ExpressionValidator::Type ExpressionValidator::StringToType(const gd::String &type) {
if (type == ExpressionValidator::numberTypeString
|| gd::ParameterMetadata::IsExpression(ExpressionValidator::numberTypeString, type)) {
return Type::Number;
}
if (type == ExpressionValidator::stringTypeString
|| gd::ParameterMetadata::IsExpression(ExpressionValidator::stringTypeString, type)) {
return Type::String;
}
if (type == ExpressionValidator::numberOrStringTypeString) {
return Type::NumberOrString;
}
if (type == ExpressionValidator::variableTypeString
|| gd::ParameterMetadata::IsExpression(ExpressionValidator::variableTypeString, type)) {
return Type::Variable;
}
if (type == ExpressionValidator::objectTypeString
|| gd::ParameterMetadata::IsObject(type)) {
return Type::Object;
}
return Type::Unknown;
}
if (type == ExpressionValidator::stringTypeString ||
gd::ParameterMetadata::IsExpression(ExpressionValidator::stringTypeString,
type)) {
return Type::String;
}
if (type == ExpressionValidator::numberOrStringTypeString) {
return Type::NumberOrString;
}
if (type == ExpressionValidator::variableTypeString ||
gd::ParameterMetadata::IsExpression(
ExpressionValidator::variableTypeString, type)) {
return Type::Variable;
}
if (type == ExpressionValidator::objectTypeString ||
gd::ParameterMetadata::IsObject(type)) {
return Type::Object;
}
return Type::Unknown;
}
} // namespace gd

View File

@@ -13,18 +13,13 @@
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Project/VariablesContainersList.h"
namespace gd {
class Expression;
class ObjectsContainer;
class VariablesContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
class VariablesContainersList;
class ProjectScopedContainers;
} // namespace gd
namespace gd {
@@ -38,13 +33,14 @@ namespace gd {
class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
public:
ExpressionValidator(const gd::Platform &platform_,
const gd::ProjectScopedContainers & projectScopedContainers_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_)
: platform(platform_),
projectScopedContainers(projectScopedContainers_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
parentType(StringToType(gd::ParameterMetadata::GetExpressionValueType(rootType_))),
childType(Type::Unknown),
forbidsUsageOfBracketsBecauseParentIsObject(false) {};
childType(Type::Unknown) {};
virtual ~ExpressionValidator(){};
/**
@@ -52,10 +48,11 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
* any error including non-fatal ones.
*/
static bool HasNoErrors(const gd::Platform &platform,
const gd::ProjectScopedContainers & projectScopedContainers,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String &rootType,
gd::ExpressionNode& node) {
gd::ExpressionValidator validator(platform, projectScopedContainers, rootType);
gd::ExpressionValidator validator(platform, globalObjectsContainer, objectsContainer, rootType);
node.Visit(validator);
return validator.GetAllErrors().empty();
}
@@ -85,7 +82,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
void OnVisitOperatorNode(OperatorNode& node) override {
ReportAnyError(node);
node.leftHandSide->Visit(*this);
const Type leftType = childType;
@@ -188,69 +185,28 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
void OnVisitVariableNode(VariableNode& node) override {
ReportAnyError(node);
if (parentType == Type::Variable) {
childType = Type::Variable;
if (node.child) {
node.child->Visit(*this);
}
} else if (parentType == Type::String || parentType == Type::Number || parentType == Type::NumberOrString) {
// The node represents a variable or an object variable in an expression waiting for its *value* to be returned.
childType = parentType;
const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
const auto& propertiesContainerList = projectScopedContainers.GetPropertiesContainersList();
forbidsUsageOfBracketsBecauseParentIsObject = false;
projectScopedContainers.MatchIdentifierWithName<void>(node.name,
[&]() {
// This represents an object.
// While understood by the parser, it's forbidden to use the bracket notation just after
// an object name (`MyObject["MyVariable"]`).
forbidsUsageOfBracketsBecauseParentIsObject = true;
}, [&]() {
// This is a variable.
}, [&]() {
// This is a property.
// Being in this node implies that there is at least a child - which is not supported for properties.
RaiseTypeError(_("Accessing a child variable of a property is not possible - just write the property name."),
node.location);
}, [&]() {
// This is a parameter.
// Being in this node implies that there is at least a child - which is not supported for parameters.
RaiseTypeError(_("Accessing a child variable of a parameter is not possible - just write the parameter name."),
node.location);
}, [&]() {
// This is something else.
RaiseTypeError(_("No object, variable or property with this name found."),
node.location);
});
if (node.child) {
node.child->Visit(*this);
}
forbidsUsageOfBracketsBecauseParentIsObject = false;
} else {
if (node.child) {
node.child->Visit(*this);
}
childType = Type::Variable;
if (parentType == Type::String) {
RaiseTypeError(_("Variables must be surrounded by VariableString()."),
node.location);
} else if (parentType == Type::Number) {
RaiseTypeError(_("Variables must be surrounded by Variable()."),
node.location);
} else if (parentType == Type::NumberOrString) {
RaiseTypeError(
_("Variables must be surrounded by Variable() or VariableString()."),
node.location);
} else if (parentType != Type::Variable) {
RaiseTypeError(_("You entered a variable, but this type was expected:") +
" " + TypeToString(parentType),
node.location);
if (node.child) {
node.child->Visit(*this);
}
}
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
ReportAnyError(node);
// In the case we accessed an object variable (`MyObject.MyVariable`),
// brackets can now be used (`MyObject.MyVariable["MyChildVariable"]` is now valid).
forbidsUsageOfBracketsBecauseParentIsObject = false;
if (node.child) {
node.child->Visit(*this);
}
@@ -259,15 +215,6 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
VariableBracketAccessorNode& node) override {
ReportAnyError(node);
if (forbidsUsageOfBracketsBecauseParentIsObject) {
RaiseError("brackets_not_allowed_for_objects",
_("You can't use the brackets to access an object variable. "
"Use a dot followed by the variable name, like this: "
"`MyObject.MyVariable`."),
node.location);
}
forbidsUsageOfBracketsBecauseParentIsObject = false;
Type currentParentType = parentType;
parentType = Type::NumberOrString;
node.expression->Visit(*this);
@@ -280,29 +227,19 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
void OnVisitIdentifierNode(IdentifierNode& node) override {
ReportAnyError(node);
if (parentType == Type::String) {
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
// The identifier is not a variable, so either the variable is not properly declared
// or it's a text without quotes.
RaiseTypeError(_("You must wrap your text inside double quotes "
"(example: \"Hello world\")."),
node.location);
}
RaiseTypeError(_("You must wrap your text inside double quotes "
"(example: \"Hello world\")."),
node.location);
}
else if (parentType == Type::Number) {
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
// The identifier is not a variable, so the variable is not properly declared.
RaiseTypeError(
_("You must enter a number."), node.location);
}
RaiseTypeError(
_("You must enter a number."), node.location);
}
else if (parentType == Type::NumberOrString) {
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
// The identifier is not a variable, so either the variable is not properly declared
// or it's a text without quotes.
RaiseTypeError(
_("You must enter a number or a text, wrapped inside double quotes (example: \"Hello world\"), or a variable name."),
node.location);
}
RaiseTypeError(
_("You must enter a number or a text, wrapped inside double quotes "
"(example: \"Hello world\")."),
node.location);
}
else if (parentType != Type::Object && parentType != Type::Variable) {
// It can't happen.
@@ -341,7 +278,6 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
private:
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, Object, Empty};
Type ValidateFunction(const gd::FunctionCallNode& function);
bool ValidateObjectVariableOrVariableOrProperty(const gd::IdentifierNode& identifier);
void ReportAnyError(const ExpressionNode& node, bool isFatal = true) {
if (node.diagnostic && node.diagnostic->IsError()) {
@@ -355,7 +291,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
}
}
void RaiseError(const gd::String &type,
void RaiseError(const gd::String &type,
const gd::String &message, const ExpressionParserLocation &location, bool isFatal = true) {
auto diagnostic = gd::make_unique<ExpressionParserError>(
type, message, location);
@@ -393,11 +329,11 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
std::vector<ExpressionParserDiagnostic*> fatalErrors;
std::vector<ExpressionParserDiagnostic*> allErrors;
std::vector<std::unique_ptr<ExpressionParserDiagnostic>> supplementalErrors;
Type childType; ///< The type "discovered" down the tree and passed up.
Type parentType; ///< The type "required" by the top of the tree.
bool forbidsUsageOfBracketsBecauseParentIsObject;
Type childType;
Type parentType;
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
};
} // namespace gd

View File

@@ -15,7 +15,6 @@
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
#include "GDCore/Project/ObjectsContainersList.h"
#include "GDCore/Tools/Localization.h"
namespace gd {
@@ -32,10 +31,6 @@ namespace gd {
* \brief Find the object name that should be used as a context of the
* expression or sub-expression that a given node represents.
*
* This is needed because of the legacy convention where a "objectvar"
* parameter represents a variable of the object represented by the previous "object"
* parameter.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionVariableOwnerFinder : public ExpressionParser2NodeWorker {
@@ -46,11 +41,12 @@ class GD_CORE_API ExpressionVariableOwnerFinder : public ExpressionParser2NodeWo
* context of the expression or sub-expression that a given node represents.
*/
static const gd::String GetObjectName(const gd::Platform &platform,
const gd::ObjectsContainersList &objectsContainersList,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String& rootObjectName,
gd::ExpressionNode& node) {
gd::ExpressionVariableOwnerFinder typeFinder(
platform, objectsContainersList, rootObjectName);
platform, globalObjectsContainer, objectsContainer, rootObjectName);
node.Visit(typeFinder);
return typeFinder.GetObjectName();
}
@@ -59,10 +55,12 @@ class GD_CORE_API ExpressionVariableOwnerFinder : public ExpressionParser2NodeWo
protected:
ExpressionVariableOwnerFinder(const gd::Platform &platform_,
const gd::ObjectsContainersList &objectsContainersList_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String& rootObjectName_)
: platform(platform_),
objectsContainersList(objectsContainersList_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootObjectName(rootObjectName_),
objectName(""),
variableNode(nullptr) {};
@@ -128,8 +126,9 @@ class GD_CORE_API ExpressionVariableOwnerFinder : public ExpressionParser2NodeWo
}
const gd::ParameterMetadata* parameterMetadata =
MetadataProvider::GetFunctionCallParameterMetadata(
platform,
objectsContainersList,
platform,
globalObjectsContainer,
objectsContainer,
functionCall,
parameterIndex);
if (parameterMetadata == nullptr
@@ -143,8 +142,9 @@ class GD_CORE_API ExpressionVariableOwnerFinder : public ExpressionParser2NodeWo
for (int previousIndex = parameterIndex - 1; previousIndex >= 0; previousIndex--) {
const gd::ParameterMetadata* previousParameterMetadata =
MetadataProvider::GetFunctionCallParameterMetadata(
platform,
objectsContainersList,
platform,
globalObjectsContainer,
objectsContainer,
functionCall,
previousIndex);
if (previousParameterMetadata != nullptr
@@ -162,7 +162,8 @@ class GD_CORE_API ExpressionVariableOwnerFinder : public ExpressionParser2NodeWo
gd::ExpressionNode *variableNode;
const gd::Platform &platform;
const gd::ObjectsContainersList &objectsContainersList;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String &rootObjectName;
};

View File

@@ -31,14 +31,16 @@ namespace gd {
class GD_CORE_API ExpressionParameterMover
: public ExpressionParser2NodeWorker {
public:
ExpressionParameterMover(const gd::ProjectScopedContainers& projectScopedContainers_,
ExpressionParameterMover(const gd::ObjectsContainer& globalObjectsContainer_,
const gd::ObjectsContainer& objectsContainer_,
const gd::String& behaviorType_,
const gd::String& objectType_,
const gd::String& functionName_,
std::size_t oldIndex_,
std::size_t newIndex_)
: hasDoneMoving(false),
projectScopedContainers(projectScopedContainers_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
behaviorType(behaviorType_),
objectType(objectType_),
functionName(functionName_),
@@ -96,16 +98,16 @@ class GD_CORE_API ExpressionParameterMover
// This refactor only applies on events object functions
// and events object functions doesn't exist yet.
// This is a dead code.
const gd::String& thisObjectType = projectScopedContainers
.GetObjectsContainersList().GetTypeOfObject(node.objectName);
const gd::String& thisObjectType = gd::GetTypeOfObject(
globalObjectsContainer, objectsContainer, node.objectName);
if (thisObjectType == objectType) {
moveParameter(node.parameters, 1);
hasDoneMoving = true;
}
} else if (!behaviorType.empty() && !node.behaviorName.empty()) {
// Move parameter of a behavior function
const gd::String& thisBehaviorType = projectScopedContainers
.GetObjectsContainersList().GetTypeOfBehavior(node.behaviorName);
const gd::String& thisBehaviorType = gd::GetTypeOfBehavior(
globalObjectsContainer, objectsContainer, node.behaviorName);
if (thisBehaviorType == behaviorType) {
moveParameter(node.parameters, 2);
hasDoneMoving = true;
@@ -124,7 +126,8 @@ class GD_CORE_API ExpressionParameterMover
private:
bool hasDoneMoving;
const gd::ProjectScopedContainers& projectScopedContainers;
const gd::ObjectsContainer& globalObjectsContainer;
const gd::ObjectsContainer& objectsContainer;
const gd::String& behaviorType; // The behavior type of the function which
// must have a parameter moved (optional).
const gd::String& objectType; // The object type of the function which
@@ -152,7 +155,8 @@ bool ExpressionsParameterMover::DoVisitInstruction(gd::Instruction& instruction,
auto node = expression.GetRootNode();
if (node) {
ExpressionParameterMover mover(GetProjectScopedContainers(),
ExpressionParameterMover mover(GetGlobalObjectsContainer(),
GetObjectsContainer(),
behaviorType,
objectType,
functionName,

View File

@@ -23,20 +23,22 @@
namespace gd {
/**
* \brief Go through the nodes and change the given function name to a new name.
* \brief Go through the nodes and change the given object name to a new one.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionFunctionRenamer
: public ExpressionParser2NodeWorker {
public:
ExpressionFunctionRenamer(const gd::ProjectScopedContainers& projectScopedContainers_,
ExpressionFunctionRenamer(const gd::ObjectsContainer& globalObjectsContainer_,
const gd::ObjectsContainer& objectsContainer_,
const gd::String& behaviorType_,
const gd::String& objectType_,
const gd::String& oldFunctionName_,
const gd::String& newFunctionName_)
: hasDoneRenaming(false),
projectScopedContainers(projectScopedContainers_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
behaviorType(behaviorType_),
objectType(objectType_),
oldFunctionName(oldFunctionName_),
@@ -69,18 +71,16 @@ class GD_CORE_API ExpressionFunctionRenamer
node.expression->Visit(*this);
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
// Nothing to do as this is either a variable, an object variable a property or something else
// but not an expression.
}
void OnVisitIdentifierNode(IdentifierNode& node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (!node.behaviorFunctionName.empty()) {
// Behavior function name
if (!behaviorType.empty() &&
node.behaviorFunctionName == oldFunctionName) {
const gd::String& thisBehaviorType = projectScopedContainers
.GetObjectsContainersList().GetTypeOfBehavior(
node.objectFunctionOrBehaviorName);
const gd::String& thisBehaviorType =
gd::GetTypeOfBehavior(globalObjectsContainer,
objectsContainer,
node.objectFunctionOrBehaviorName);
if (thisBehaviorType == behaviorType) {
node.behaviorFunctionName = newFunctionName;
hasDoneRenaming = true;
@@ -90,8 +90,8 @@ class GD_CORE_API ExpressionFunctionRenamer
// Object function name
if (behaviorType.empty() && !objectType.empty() &&
node.objectFunctionOrBehaviorName == oldFunctionName) {
const gd::String& thisObjectType = projectScopedContainers
.GetObjectsContainersList().GetTypeOfObject(node.objectName);
const gd::String& thisObjectType = gd::GetTypeOfObject(
globalObjectsContainer, objectsContainer, node.objectName);
if (thisObjectType == objectType) {
node.objectFunctionOrBehaviorName = newFunctionName;
hasDoneRenaming = true;
@@ -104,16 +104,16 @@ class GD_CORE_API ExpressionFunctionRenamer
if (behaviorType.empty() && !objectType.empty() &&
!node.objectName.empty()) {
// Replace an object function
const gd::String& thisObjectType = projectScopedContainers
.GetObjectsContainersList().GetTypeOfObject(node.objectName);
const gd::String& thisObjectType = gd::GetTypeOfObject(
globalObjectsContainer, objectsContainer, node.objectName);
if (thisObjectType == objectType) {
node.functionName = newFunctionName;
hasDoneRenaming = true;
}
} else if (!behaviorType.empty() && !node.behaviorName.empty()) {
// Replace a behavior function
const gd::String& thisBehaviorType = projectScopedContainers
.GetObjectsContainersList().GetTypeOfBehavior(node.behaviorName);
const gd::String& thisBehaviorType = gd::GetTypeOfBehavior(
globalObjectsContainer, objectsContainer, node.behaviorName);
if (thisBehaviorType == behaviorType) {
node.functionName = newFunctionName;
hasDoneRenaming = true;
@@ -132,7 +132,8 @@ class GD_CORE_API ExpressionFunctionRenamer
private:
bool hasDoneRenaming;
const gd::ProjectScopedContainers& projectScopedContainers;
const gd::ObjectsContainer& globalObjectsContainer;
const gd::ObjectsContainer& objectsContainer;
const gd::String& behaviorType; // The behavior type for which the expression
// must be replaced (optional).
const gd::String& objectType; // The object type for which the expression
@@ -158,7 +159,8 @@ bool ExpressionsRenamer::DoVisitInstruction(gd::Instruction& instruction,
auto node = expression.GetRootNode();
if (node) {
ExpressionFunctionRenamer renamer(GetProjectScopedContainers(),
ExpressionFunctionRenamer renamer(GetGlobalObjectsContainer(),
GetObjectsContainer(),
behaviorType,
objectType,
oldFunctionName,

View File

@@ -34,12 +34,13 @@ class GD_CORE_API ExpressionIdentifierStringFinder
public:
ExpressionIdentifierStringFinder(
const gd::Platform &platform_,
const gd::ProjectScopedContainers& projectScopedContainers_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &expressionPlainString_,
const gd::String &parameterType_, const gd::String &objectName_,
const gd::String &layerName_, const gd::String &oldName_)
: platform(platform_),
projectScopedContainers(projectScopedContainers_),
: platform(platform_), globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
expressionPlainString(expressionPlainString_),
parameterType(parameterType_), objectName(objectName_),
layerName(layerName_), oldName(oldName_){};
@@ -81,7 +82,7 @@ protected:
void OnVisitFunctionCallNode(FunctionCallNode &node) override {
gd::String lastLayerName;
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
platform, projectScopedContainers.GetObjectsContainersList(), node,
platform, globalObjectsContainer, objectsContainer, node,
[&](const gd::ParameterMetadata &parameterMetadata,
std::unique_ptr<gd::ExpressionNode> &parameterNode,
size_t parameterIndex, const gd::String &lastObjectName) {
@@ -122,7 +123,8 @@ protected:
private:
const gd::Platform &platform;
const gd::ProjectScopedContainers &projectScopedContainers;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
/// It's used to extract parameter content.
const gd::String &expressionPlainString;
const gd::String &oldName;
@@ -174,7 +176,7 @@ bool ProjectElementRenamer::DoVisitInstruction(gd::Instruction &instruction,
auto node = parameterValue.GetRootNode();
if (node) {
ExpressionIdentifierStringFinder finder(
platform, GetProjectScopedContainers(),
platform, GetGlobalObjectsContainer(), GetObjectsContainer(),
parameterValue.GetPlainString(), parameterType, objectName,
layerName, oldName);
node->Visit(finder);

View File

@@ -108,33 +108,6 @@ void UsedExtensionsFinder::OnVisitUnaryOperatorNode(UnaryOperatorNode& node) {
// Add variable extension and visit sub-expressions on variable nodes
void UsedExtensionsFinder::OnVisitVariableNode(VariableNode& node) {
result.GetUsedExtensions().insert("BuiltinVariables");
auto type = gd::ExpressionTypeFinder::GetType(
project.GetCurrentPlatform(), GetObjectsContainersList(), rootType, node);
if (gd::ParameterMetadata::IsExpression("variable", type)) {
// Nothing to do (this can't reference an object)
} else {
GetProjectScopedContainers().MatchIdentifierWithName<void>(node.name,
[&]() {
// This represents an object.
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
project.GetCurrentPlatform(), node.name);
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());
for (auto &&includeFile : metadata.GetMetadata().includeFiles) {
result.GetUsedIncludeFiles().insert(includeFile);
}
}, [&]() {
// This is a variable.
}, [&]() {
// This is a property.
}, [&]() {
// This is a parameter.
}, [&]() {
// This is something else.
});
}
if (node.child) node.child->Visit(*this);
};
@@ -154,10 +127,9 @@ void UsedExtensionsFinder::OnVisitVariableBracketAccessorNode(
// Add extensions bound to Objects/Behaviors/Functions
void UsedExtensionsFinder::OnVisitIdentifierNode(IdentifierNode &node) {
auto type = gd::ExpressionTypeFinder::GetType(
project.GetCurrentPlatform(), GetObjectsContainersList(), rootType, node);
if (gd::ParameterMetadata::IsObject(type) ||
GetObjectsContainersList().HasObjectOrGroupNamed(node.identifierName)) {
// An object or object variable is used.
project.GetCurrentPlatform(), GetGlobalObjectsContainer(),
GetObjectsContainer(), rootType, node);
if (gd::ParameterMetadata::IsObject(type)) {
auto metadata = gd::MetadataProvider::GetExtensionAndObjectMetadata(
project.GetCurrentPlatform(), node.identifierName);
result.GetUsedExtensions().insert(metadata.GetExtension().GetName());

View File

@@ -16,9 +16,7 @@
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/PropertiesContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/String.h"
namespace gd {
@@ -88,17 +86,15 @@ void ProjectBrowserHelper::ExposeLayoutEvents(
void ProjectBrowserHelper::ExposeLayoutEvents(
gd::Project &project, gd::Layout &layout,
gd::ArbitraryEventsWorkerWithContext &worker) {
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
// Add layouts events
worker.Launch(layout.GetEvents(), projectScopedContainers);
worker.Launch(layout.GetEvents(), project, layout);
// Add external events events
for (std::size_t s = 0; s < project.GetExternalEventsCount(); s++) {
auto &externalEvents = project.GetExternalEvents(s);
if (externalEvents.GetAssociatedLayout() == layout.GetName()) {
worker.Launch(externalEvents.GetEvents(), projectScopedContainers);
worker.Launch(externalEvents.GetEvents(), project, layout);
}
}
}
@@ -112,19 +108,15 @@ void ProjectBrowserHelper::ExposeProjectEvents(
// Add layouts events
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
auto &layout = project.GetLayout(s);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
worker.Launch(layout.GetEvents(), projectScopedContainers);
worker.Launch(layout.GetEvents(), project, layout);
}
// Add external events events
for (std::size_t s = 0; s < project.GetExternalEventsCount(); s++) {
const auto &externalEvents = project.GetExternalEvents(s);
const gd::String &associatedLayout = externalEvents.GetAssociatedLayout();
if (project.HasLayoutNamed(associatedLayout)) {
auto &layout = project.GetLayout(associatedLayout);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
worker.Launch(project.GetExternalEvents(s).GetEvents(), projectScopedContainers);
worker.Launch(project.GetExternalEvents(s).GetEvents(), project,
project.GetLayout(associatedLayout));
}
}
// Add events based extensions
@@ -138,11 +130,9 @@ void ProjectBrowserHelper::ExposeProjectEvents(
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
project, eventsFunctionsExtension, *eventsFunction,
globalObjectsAndGroups, objectsAndGroups);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
projectScopedContainers.AddParameters(eventsFunction->GetParameters());
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
worker.Launch(eventsFunction->GetEvents(), globalObjectsAndGroups,
objectsAndGroups);
}
// Add (behavior) events functions
@@ -179,13 +169,9 @@ void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
gd::EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
project, eventsBasedBehavior, *eventsFunction, globalObjectsAndGroups,
objectsAndGroups);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
projectScopedContainers.AddPropertiesContainer(eventsBasedBehavior.GetSharedPropertyDescriptors());
projectScopedContainers.AddPropertiesContainer(eventsBasedBehavior.GetPropertyDescriptors());
projectScopedContainers.AddParameters(eventsFunction->GetParameters());
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
worker.Launch(eventsFunction->GetEvents(), globalObjectsAndGroups,
objectsAndGroups);
}
}
@@ -199,12 +185,9 @@ void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
project, eventsBasedObject, *eventsFunction, globalObjectsAndGroups,
objectsAndGroups);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
projectScopedContainers.AddPropertiesContainer(eventsBasedObject.GetPropertyDescriptors());
projectScopedContainers.AddParameters(eventsFunction->GetParameters());
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
worker.Launch(eventsFunction->GetEvents(), globalObjectsAndGroups,
objectsAndGroups);
}
}

View File

@@ -5,8 +5,6 @@
*/
#include "WholeProjectRefactorer.h"
#include <unordered_map>
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
@@ -17,8 +15,6 @@
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
#include "GDCore/IDE/Events/EventsVariableReplacer.h"
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
#include "GDCore/IDE/Events/InstructionsParameterMover.h"
@@ -50,8 +46,6 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/ObjectGroup.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
@@ -138,72 +132,6 @@ void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
}
}
VariablesChangeset WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
gd::Project &project,
const gd::SerializerElement &oldSerializedVariablesContainer,
const gd::VariablesContainer &newVariablesContainer) {
gd::VariablesChangeset changeset;
gd::VariablesContainer oldVariablesContainer;
oldVariablesContainer.UnserializeFrom(oldSerializedVariablesContainer);
if (oldVariablesContainer.GetPersistentUuid() !=
newVariablesContainer.GetPersistentUuid()) {
gd::LogWarning(
_("Called ComputeChangesetForVariablesContainer on variables containers "
"that are different - they can't be compared."));
return changeset;
}
std::unordered_map<gd::String, gd::String> removedUuidAndNames;
for (std::size_t i = 0; i < oldVariablesContainer.Count(); ++i) {
const auto &variable = oldVariablesContainer.Get(i);
const auto &variableName = oldVariablesContainer.GetNameAt(i);
// All variables are candidate to be removed.
removedUuidAndNames[variable.GetPersistentUuid()] = variableName;
}
for (std::size_t i = 0; i < newVariablesContainer.Count(); ++i) {
const auto &variable = newVariablesContainer.Get(i);
const auto &variableName = newVariablesContainer.GetNameAt(i);
auto existingOldVariableUuidAndName =
removedUuidAndNames.find(variable.GetPersistentUuid());
if (existingOldVariableUuidAndName == removedUuidAndNames.end()) {
// This is a new variable.
} else {
const gd::String &oldName = existingOldVariableUuidAndName->second;
if (oldName != variableName) {
// This is a renamed variable.
changeset.oldToNewVariableNames[oldName] = variableName;
}
// Renamed or not, this is not a removed variable.
removedUuidAndNames.erase(variable.GetPersistentUuid());
}
}
for (const auto &removedUuidAndName : removedUuidAndNames) {
changeset.removedVariableNames.insert(removedUuidAndName.second);
}
return changeset;
}
void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
gd::Project &project,
const gd::VariablesContainer &newVariablesContainer,
const gd::VariablesChangeset& changeset) {
gd::EventsVariableReplacer eventsVariableReplacer(
project.GetCurrentPlatform(),
newVariablesContainer,
changeset.oldToNewVariableNames,
changeset.removedVariableNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
eventsVariableReplacer);
}
void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior(
gd::Project &project,
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
@@ -743,15 +671,6 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
@@ -779,7 +698,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::String &oldPropertyName, const gd::String &newPropertyName) {
auto &properties = eventsBasedBehavior.GetSharedPropertyDescriptors();
auto &properties = eventsBasedBehavior.GetPropertyDescriptors();
if (!properties.Has(oldPropertyName))
return;
@@ -813,15 +732,6 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
@@ -870,15 +780,6 @@ void WholeProjectRefactorer::RenameEventsBasedObjectProperty(
EventsBasedObject::GetPropertyExpressionName(newPropertyName));
gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer);
std::unordered_map<gd::String, gd::String> oldToNewPropertyNames = {{oldPropertyName, newPropertyName}};
std::unordered_set<gd::String> removedPropertyNames;
gd::EventsPropertyReplacer eventsPropertyReplacer(
project.GetCurrentPlatform(),
properties,
oldToNewPropertyNames,
removedPropertyNames);
gd::ProjectBrowserHelper::ExposeProjectEvents(project, eventsPropertyReplacer);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
gd::PlatformExtension::GetObjectEventsFunctionFullType(
@@ -1398,12 +1299,10 @@ void WholeProjectRefactorer::DoRenameObject(
void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
gd::Project &project, gd::Layout &layout, const gd::String &objectName,
bool isObjectGroup, bool removeEventsAndGroups) {
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
// Remove object in the current layout
if (removeEventsAndGroups) {
gd::EventsRefactorer::RemoveObjectInEvents(project.GetCurrentPlatform(),
projectScopedContainers,
project, layout,
layout.GetEvents(), objectName);
}
if (!isObjectGroup) { // Object groups can't have instances or be in other
@@ -1422,9 +1321,8 @@ void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
for (auto &externalEventsName :
GetAssociatedExternalEvents(project, layout.GetName())) {
auto &externalEvents = project.GetExternalEvents(externalEventsName);
gd::EventsRefactorer::RemoveObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
project.GetCurrentPlatform(), project, layout,
externalEvents.GetEvents(), objectName);
}
}
@@ -1446,12 +1344,9 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
const gd::String &newName, bool isObjectGroup) {
if (oldName == newName || newName.empty() || oldName.empty())
return;
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
// Rename object in the current layout
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers, layout.GetEvents(),
project.GetCurrentPlatform(), project, layout, layout.GetEvents(),
oldName, newName);
if (!isObjectGroup) { // Object groups can't have instances or be in other
@@ -1467,7 +1362,7 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
GetAssociatedExternalEvents(project, layout.GetName())) {
auto &externalEvents = project.GetExternalEvents(externalEventsName);
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
project.GetCurrentPlatform(), project, layout,
externalEvents.GetEvents(), oldName, newName);
}
@@ -1617,13 +1512,10 @@ void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &objectName,
bool isObjectGroup, bool removeEventsAndGroups) {
// In theory we should pass a ProjectScopedContainers to this function so it does not have to construct one.
// In practice, this is ok because we only deal with objects.
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsContainer, objectsContainer);
// Remove object in the current layout
if (removeEventsAndGroups) {
gd::EventsRefactorer::RemoveObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
project.GetCurrentPlatform(), globalObjectsContainer, objectsContainer,
eventsFunction.GetEvents(), objectName);
}
if (!isObjectGroup) { // Object groups can't be in other groups
@@ -1655,12 +1547,9 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
gd::ObjectsContainer &globalObjectsContainer,
gd::ObjectsContainer &objectsContainer, const gd::String &oldName,
const gd::String &newName, bool isObjectGroup) {
// In theory we should pass a ProjectScopedContainers to this function so it does not have to construct one.
// In practice, this is ok because we only deal with objects.
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsContainer, objectsContainer);
// Rename object in the current layout
gd::EventsRefactorer::RenameObjectInEvents(
project.GetCurrentPlatform(), projectScopedContainers,
project.GetCurrentPlatform(), globalObjectsContainer, objectsContainer,
eventsFunction.GetEvents(), oldName, newName);
if (!isObjectGroup) { // Object groups can't be in other groups
@@ -1705,7 +1594,7 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRemoved(
if (layout.HasObjectNamed(objectName))
continue;
ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup,
ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup,
removeEventsAndGroups);
}
}

View File

@@ -7,9 +7,7 @@
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Platform;
class Project;
@@ -20,7 +18,6 @@ class String;
class EventsFunctionsExtension;
class EventsFunction;
class ObjectsContainer;
class VariablesContainer;
class EventsBasedBehavior;
class EventsBasedObject;
class ArbitraryEventsWorker;
@@ -33,20 +30,10 @@ class Behavior;
class BehaviorMetadata;
class UnfilledRequiredBehaviorPropertyProblem;
class ProjectBrowser;
class SerializerElement;
} // namespace gd
namespace gd {
struct VariablesChangeset {
std::unordered_set<gd::String> removedVariableNames;
std::unordered_map<gd::String, gd::String> oldToNewVariableNames;
bool HasRemovedVariables() { return !removedVariableNames.empty(); }
VariablesChangeset& ClearRemovedVariables() { removedVariableNames.clear(); return *this; }
};
/**
* \brief Tool functions to do refactoring on the whole project after
* changes like deletion or renaming of an object.
@@ -58,23 +45,6 @@ struct VariablesChangeset {
class GD_CORE_API WholeProjectRefactorer {
public:
/**
* \brief Compute the changes made on the variables of a variable container.
*/
static VariablesChangeset ComputeChangesetForVariablesContainer(
gd::Project &project,
const gd::SerializerElement &oldSerializedVariablesContainer,
const gd::VariablesContainer &newVariablesContainer);
/**
* \brief Refactor the project according to the changes (renaming or deletion)
* made to variables.
*/
static void ApplyRefactoringForVariablesContainer(
gd::Project &project,
const gd::VariablesContainer &newVariablesContainer,
const gd::VariablesChangeset& changeset);
/**
* \brief Refactor the project **before** an events function extension is
* renamed.

View File

@@ -4,7 +4,6 @@
* reserved. This project is released under the MIT License.
*/
#include "AbstractEventsBasedEntity.h"
#include "EventsFunctionsContainer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/MakeUnique.h"
@@ -14,10 +13,7 @@ namespace gd {
AbstractEventsBasedEntity::AbstractEventsBasedEntity(
const gd::String& _name,
gd::EventsFunctionsContainer::FunctionOwner functionContainerSource)
: name(_name),
fullName(""),
eventsFunctionsContainer(functionContainerSource),
propertyDescriptors(functionContainerSource) {}
: name(_name), fullName(""), eventsFunctionsContainer(functionContainerSource) {}
void AbstractEventsBasedEntity::SerializeTo(SerializerElement& element) const {
element.SetAttribute("description", description);
@@ -31,8 +27,8 @@ void AbstractEventsBasedEntity::SerializeTo(SerializerElement& element) const {
"propertyDescriptor", element.AddChild("propertyDescriptors"));
}
void AbstractEventsBasedEntity::UnserializeFrom(
gd::Project& project, const SerializerElement& element) {
void AbstractEventsBasedEntity::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
description = element.GetStringAttribute("description");
name = element.GetStringAttribute("name");
fullName = element.GetStringAttribute("fullName");

View File

@@ -8,7 +8,7 @@
#include <vector>
#include "GDCore/Project/NamedPropertyDescriptor.h"
#include "GDCore/Project/PropertiesContainer.h"
#include "GDCore/Tools/SerializableWithNameList.h"
#include "GDCore/Project/EventsFunctionsContainer.h"
#include "GDCore/String.h"
namespace gd {
@@ -98,14 +98,15 @@ class GD_CORE_API AbstractEventsBasedEntity {
/**
* \brief Return a reference to the list of the properties.
*/
gd::PropertiesContainer& GetPropertyDescriptors() {
SerializableWithNameList<NamedPropertyDescriptor>& GetPropertyDescriptors() {
return propertyDescriptors;
}
/**
* \brief Return a const reference to the list of the properties.
*/
const gd::PropertiesContainer& GetPropertyDescriptors() const {
const SerializableWithNameList<NamedPropertyDescriptor>& GetPropertyDescriptors()
const {
return propertyDescriptors;
}
@@ -149,7 +150,7 @@ class GD_CORE_API AbstractEventsBasedEntity {
gd::String fullName;
gd::String description;
gd::EventsFunctionsContainer eventsFunctionsContainer;
gd::PropertiesContainer propertyDescriptors;
SerializableWithNameList<NamedPropertyDescriptor> propertyDescriptors;
gd::String extensionName;
};

View File

@@ -8,7 +8,6 @@
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertiesContainer.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Serialization/SerializerElement.h"
@@ -18,7 +17,7 @@
using namespace gd;
void CustomConfigurationHelper::InitializeContent(
const gd::PropertiesContainer &properties,
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
gd::SerializerElement &configurationContent) {
for (auto &&property : properties.GetInternalVector()) {
auto &element = configurationContent.AddChild(property->GetName());
@@ -36,7 +35,7 @@ void CustomConfigurationHelper::InitializeContent(
}
std::map<gd::String, gd::PropertyDescriptor> CustomConfigurationHelper::GetProperties(
const gd::PropertiesContainer &properties,
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
const gd::SerializerElement &configurationContent) {
auto behaviorProperties = std::map<gd::String, gd::PropertyDescriptor>();
@@ -72,7 +71,7 @@ std::map<gd::String, gd::PropertyDescriptor> CustomConfigurationHelper::GetPrope
}
bool CustomConfigurationHelper::UpdateProperty(
const gd::PropertiesContainer &properties,
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
gd::SerializerElement &configurationContent,
const gd::String &propertyName,
const gd::String &newValue) {

View File

@@ -9,7 +9,6 @@
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertiesContainer.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Serialization/SerializerElement.h"
@@ -26,15 +25,15 @@ public:
CustomConfigurationHelper() {}
static void InitializeContent(
const gd::PropertiesContainer &properties,
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
gd::SerializerElement &behaviorContent);
static std::map<gd::String, gd::PropertyDescriptor> GetProperties(
const gd::PropertiesContainer &properties,
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
const gd::SerializerElement &behaviorContent);
static bool UpdateProperty(
const gd::PropertiesContainer &properties,
const gd::SerializableWithNameList<gd::NamedPropertyDescriptor> &properties,
gd::SerializerElement &behaviorContent,
const gd::String &name,
const gd::String &value);

View File

@@ -13,8 +13,7 @@ namespace gd {
EventsBasedBehavior::EventsBasedBehavior()
: AbstractEventsBasedEntity(
"MyBehavior",
gd::EventsFunctionsContainer::FunctionOwner::Behavior),
sharedPropertyDescriptors(gd::EventsFunctionsContainer::FunctionOwner::Behavior) {}
gd::EventsFunctionsContainer::FunctionOwner::Behavior) {}
void EventsBasedBehavior::SerializeTo(SerializerElement& element) const {
AbstractEventsBasedEntity::SerializeTo(element);

View File

@@ -9,7 +9,7 @@
#include <vector>
#include "GDCore/Project/AbstractEventsBasedEntity.h"
#include "GDCore/Project/NamedPropertyDescriptor.h"
#include "GDCore/Project/PropertiesContainer.h"
#include "GDCore/Tools/SerializableWithNameList.h"
#include "GDCore/Project/EventsFunctionsContainer.h"
#include "GDCore/String.h"
namespace gd {
@@ -91,14 +91,14 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
/**
* \brief Return a reference to the list of shared properties.
*/
gd::PropertiesContainer& GetSharedPropertyDescriptors() {
SerializableWithNameList<NamedPropertyDescriptor>& GetSharedPropertyDescriptors() {
return sharedPropertyDescriptors;
}
/**
* \brief Return a const reference to the list of shared properties.
*/
const gd::PropertiesContainer& GetSharedPropertyDescriptors()
const SerializableWithNameList<NamedPropertyDescriptor>& GetSharedPropertyDescriptors()
const {
return sharedPropertyDescriptors;
}
@@ -140,7 +140,7 @@ class GD_CORE_API EventsBasedBehavior: public AbstractEventsBasedEntity {
private:
gd::String objectType;
bool isPrivate = false;
gd::PropertiesContainer sharedPropertyDescriptors;
SerializableWithNameList<NamedPropertyDescriptor> sharedPropertyDescriptors;
};
} // namespace gd

View File

@@ -13,75 +13,19 @@
namespace gd {
class Effect;
}
namespace gd {
class Camera;
}
namespace gd {
class SerializerElement;
}
namespace gd {
class EffectsContainer;
}
namespace gd {
/**
* \brief A camera is used to render a specific area of a layout.
*
* \see gd::Layout
* \ingroup PlatformDefinition
*/
class GD_CORE_API Camera {
public:
Camera();
~Camera(){};
/**
* \brief Change the viewport, i.e the area of the window where the camera
* will be displayed. \note The coordinates must be between 0 and 1.
*/
void SetViewport(float x1_, float y1_, float x2_, float y2_) {
x1 = x1_;
x2 = x2_;
y1 = y1_;
y2 = y2_;
};
void SetViewportX1(float x1_) { x1 = x1_; };
void SetViewportY1(float y1_) { y1 = y1_; };
void SetViewportX2(float x2_) { x2 = x2_; };
void SetViewportY2(float y2_) { y2 = y2_; };
float GetViewportX1() const { return x1; };
float GetViewportY1() const { return y1; };
float GetViewportX2() const { return x2; };
float GetViewportY2() const { return y2; };
/**
* \brief Change the size of the rendered area of the scene, in pixels.
*/
void SetSize(float width_, float height_) {
width = width_;
height = height_;
};
float GetWidth() const { return width; };
float GetHeight() const { return height; };
void SetUseDefaultSize(bool useDefaultSize = true) {
defaultSize = useDefaultSize;
};
bool UseDefaultSize() const { return defaultSize; }
void SetUseDefaultViewport(bool useDefaultViewport = true) {
defaultViewport = useDefaultViewport;
};
bool UseDefaultViewport() const { return defaultViewport; }
private:
bool defaultSize; ///< True if the camera use the default window size
bool defaultViewport; ///< True if the camera use the default viewport size
float x1;
float y1;
float x2;
float y2;
float width; ///< The width of the rendered area
float height; ///< The height of the rendered area
};
/**
* \brief Represents a layer of a layout.
*
@@ -297,6 +241,68 @@ struct LayerHasName : public std::binary_function<gd::Layer, gd::String, bool> {
}
};
/**
* \brief A camera is used to render a specific area of a layout.
*
* \see gd::Layout
* \ingroup PlatformDefinition
*/
class GD_CORE_API Camera {
public:
Camera();
~Camera(){};
/**
* \brief Change the viewport, i.e the area of the window where the camera
* will be displayed. \note The coordinates must be between 0 and 1.
*/
void SetViewport(float x1_, float y1_, float x2_, float y2_) {
x1 = x1_;
x2 = x2_;
y1 = y1_;
y2 = y2_;
};
void SetViewportX1(float x1_) { x1 = x1_; };
void SetViewportY1(float y1_) { y1 = y1_; };
void SetViewportX2(float x2_) { x2 = x2_; };
void SetViewportY2(float y2_) { y2 = y2_; };
float GetViewportX1() const { return x1; };
float GetViewportY1() const { return y1; };
float GetViewportX2() const { return x2; };
float GetViewportY2() const { return y2; };
/**
* \brief Change the size of the rendered area of the scene, in pixels.
*/
void SetSize(float width_, float height_) {
width = width_;
height = height_;
};
float GetWidth() const { return width; };
float GetHeight() const { return height; };
void SetUseDefaultSize(bool useDefaultSize = true) {
defaultSize = useDefaultSize;
};
bool UseDefaultSize() const { return defaultSize; }
void SetUseDefaultViewport(bool useDefaultViewport = true) {
defaultViewport = useDefaultViewport;
};
bool UseDefaultViewport() const { return defaultViewport; }
private:
bool defaultSize; ///< True if the camera use the default window size
bool defaultViewport; ///< True if the camera use the default viewport size
float x1;
float y1;
float x2;
float y2;
float width; ///< The width of the rendered area
float height; ///< The height of the rendered area
};
} // namespace gd
#endif // GDCORE_LAYER_H

View File

@@ -742,7 +742,7 @@ gd::String GD_CORE_API GetTypeOfBehavior(const gd::ObjectsContainer& project,
vector<gd::String> GD_CORE_API
GetBehaviorsOfObject(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
const gd::String& name,
gd::String name,
bool searchInGroups) {
bool behaviorsAlreadyInserted = false;
vector<gd::String> behaviors;

View File

@@ -435,7 +435,6 @@ std::vector<gd::String> GetHiddenLayers(const Layout& layout);
* \note If a group contains only objects of a same type, then the group has
* this type. Otherwise, it is considered as an object without any specific
* type.
* \deprecated Use gd::ObjectsContainersList::GetTypeOfObject instead.
*
* @return Type of the object/group.
*/
@@ -445,7 +444,6 @@ gd::String GD_CORE_API GetTypeOfObject(const ObjectsContainer& game,
bool searchInGroups = true);
/**
* \brief Check if an object or all objects of a group has a behavior.
* \deprecated Use gd::ObjectsContainersList::HasBehaviorInObjectOrGroup instead.
*/
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
@@ -481,7 +479,6 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain
/**
* \brief Get a type from a behavior name
* @return Type of the behavior.
* @deprecated - Use GetTypeOfBehaviorInObjectOrGroup instead.
*/
gd::String GD_CORE_API GetTypeOfBehavior(const ObjectsContainer& game,
const ObjectsContainer& layout,
@@ -498,7 +495,7 @@ gd::String GD_CORE_API GetTypeOfBehavior(const ObjectsContainer& game,
std::vector<gd::String> GD_CORE_API
GetBehaviorsOfObject(const ObjectsContainer& game,
const ObjectsContainer& layout,
const gd::String& objectName,
gd::String objectName,
bool searchInGroups = true);
} // namespace gd

View File

@@ -5,6 +5,7 @@
*/
#include "LoadingScreen.h"
#include "GDCore/Serialization/SerializerElement.h"
namespace gd {

View File

@@ -15,7 +15,6 @@
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/Tools/Log.h"
#include "GDCore/Tools/UUID/UUID.h"
namespace gd {
@@ -36,7 +35,6 @@ Object::Object(const gd::String& name_,
}
void Object::Init(const gd::Object& object) {
persistentUuid = object.persistentUuid;
name = object.name;
assetStoreId = object.assetStoreId;
objectVariables = object.objectVariables;
@@ -129,8 +127,6 @@ gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
void Object::UnserializeFrom(gd::Project& project,
const SerializerElement& element) {
persistentUuid = element.GetStringAttribute("persistentUuid");
SetType(element.GetStringAttribute("type"));
assetStoreId = element.GetStringAttribute("assetStoreId");
name = element.GetStringAttribute("name", name, "nom");
@@ -201,9 +197,6 @@ void Object::UnserializeFrom(gd::Project& project,
}
void Object::SerializeTo(SerializerElement& element) const {
if (!persistentUuid.empty())
element.SetStringAttribute("persistentUuid", persistentUuid);
element.SetAttribute("name", GetName());
element.SetAttribute("assetStoreId", GetAssetStoreId());
element.SetAttribute("type", GetType());
@@ -234,18 +227,4 @@ void Object::SerializeTo(SerializerElement& element) const {
configuration->SerializeTo(element);
}
Object& Object::ResetPersistentUuid() {
persistentUuid = UUID::MakeUuid4();
objectVariables.ResetPersistentUuid();
return *this;
}
Object& Object::ClearPersistentUuid() {
persistentUuid = "";
objectVariables.ClearPersistentUuid();
return *this;
}
} // namespace gd

View File

@@ -243,18 +243,6 @@ class GD_CORE_API Object {
* \see DoUnserializeFrom
*/
void UnserializeFrom(gd::Project& project, const SerializerElement& element);
/**
* \brief Reset the persistent UUID, used to recognize
* the same object between serialization.
*/
Object& ResetPersistentUuid();
/**
* \brief Remove the persistent UUID - when the object no
* longer need to be recognized between serializations.
*/
Object& ClearPersistentUuid();
///@}
protected:
@@ -271,8 +259,6 @@ class GD_CORE_API Object {
gd::String tags; ///< Comma-separated list of tags
gd::EffectsContainer
effectsContainer; ///< The effects container for the object.
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID,
///< useful for computing changesets.
/**
* Initialize object using another object. Used by copy-ctor and assign-op.

View File

@@ -162,11 +162,4 @@ void ObjectGroupsContainer::Move(std::size_t oldIndex, std::size_t newIndex) {
objectGroups.insert(objectGroups.begin() + newIndex, std::move(objectGroup));
}
void ObjectGroupsContainer::ForEachNameWithPrefix(const gd::String& prefix,
std::function<void(const gd::String& name)> fn) const {
for (const auto& objectGroup: objectGroups) {
if (objectGroup->GetName().find(prefix) == 0) fn(objectGroup->GetName());
}
}
} // namespace gd

View File

@@ -116,11 +116,6 @@ class GD_CORE_API ObjectGroupsContainer {
* \brief Clear all groups of the container.
*/
inline void Clear() { objectGroups.clear(); }
/**
* \brief Call the callback for each group name starting with the prefix passed in parameter.
*/
void ForEachNameWithPrefix(const gd::String& prefix, std::function<void(const gd::String& name)> fn) const;
///@}
/** \name Saving and loading

View File

@@ -1,250 +0,0 @@
#include "ObjectsContainersList.h"
#include <vector>
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
ObjectsContainersList
ObjectsContainersList::MakeNewObjectsContainersListForProjectAndLayout(
const gd::Project& project, const gd::Layout& layout) {
ObjectsContainersList objectsContainersList;
objectsContainersList.Add(project);
objectsContainersList.Add(layout);
return objectsContainersList;
}
ObjectsContainersList
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
const gd::ObjectsContainer& globalObjectsContainer,
const gd::ObjectsContainer& objectsContainer) {
ObjectsContainersList objectsContainersList;
objectsContainersList.Add(globalObjectsContainer);
objectsContainersList.Add(objectsContainer);
return objectsContainersList;
}
bool ObjectsContainersList::HasObjectOrGroupNamed(
const gd::String& name) const {
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
if ((*it)->HasObjectNamed(name) || (*it)->GetObjectGroups().Has(name))
return true;
}
return false;
}
bool ObjectsContainersList::HasObjectNamed(const gd::String& name) const {
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
if ((*it)->HasObjectNamed(name)) return true;
}
return false;
}
bool ObjectsContainersList::HasObjectOrGroupWithVariableNamed(
const gd::String& objectOrGroupName, const gd::String& variableName) const {
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
if ((*it)->HasObjectNamed(objectOrGroupName)) {
const auto& variables =
(*it)->GetObject(objectOrGroupName).GetVariables();
return variables.Has(variableName);
}
if ((*it)->GetObjectGroups().Has(objectOrGroupName)) {
// Could be adapted if objects groups have variables in the future.
}
}
return false;
}
bool ObjectsContainersList::HasVariablesContainer(
const gd::String& objectOrGroupName,
const gd::VariablesContainer& variablesContainer) const {
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
if ((*it)->HasObjectNamed(objectOrGroupName)) {
return &variablesContainer ==
&(*it)->GetObject(objectOrGroupName).GetVariables();
}
if ((*it)->GetObjectGroups().Has(objectOrGroupName)) {
// Could be adapted if objects groups have variables in the future.
}
}
return false;
}
const gd::VariablesContainer*
ObjectsContainersList::GetObjectOrGroupVariablesContainer(
const gd::String& objectOrGroupName) const {
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
if ((*it)->HasObjectNamed(objectOrGroupName)) {
return &(*it)->GetObject(objectOrGroupName).GetVariables();
}
if ((*it)->GetObjectGroups().Has(objectOrGroupName)) {
// Could be adapted if objects groups have variables in the future.
}
}
return nullptr;
}
void ObjectsContainersList::ForEachNameWithPrefix(
const gd::String& prefix,
std::function<void(const gd::String& name,
const gd::ObjectConfiguration* objectConfiguration)> fn)
const {
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
for (const auto& object : (*it)->GetObjects()) {
if (object->GetName().find(prefix) == 0)
fn(object->GetName(), &object->GetConfiguration());
}
(*it)->GetObjectGroups().ForEachNameWithPrefix(
prefix, [&](const gd::String& name) { fn(name, nullptr); });
}
}
std::vector<gd::String> ObjectsContainersList::ExpandObjectName(
const gd::String& objectOrGroupName,
const gd::String& onlyObjectToSelectIfPresent) const {
std::vector<gd::String> realObjects;
// Check progressively each object container to find the object or the group
// with the specified name.
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
if ((*it)->HasObjectNamed(objectOrGroupName)) {
// We found the object, it's a single object with this name.
realObjects.push_back(objectOrGroupName);
break;
}
if ((*it)->GetObjectGroups().Has(objectOrGroupName)) {
// We found a group with this name, expand the object names inside of it.
realObjects =
(*it)->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
break;
}
}
// If the "current object" is present, use it and only it.
if (!onlyObjectToSelectIfPresent.empty() &&
find(realObjects.begin(),
realObjects.end(),
onlyObjectToSelectIfPresent) != realObjects.end()) {
realObjects.clear();
realObjects.push_back(onlyObjectToSelectIfPresent);
}
// Ensure that all returned objects actually exists (i.e: if some groups have
// names refering to non existing objects, don't return them).
for (std::size_t i = 0; i < realObjects.size();) {
if (!HasObjectNamed(realObjects[i]))
realObjects.erase(realObjects.begin() + i);
else
++i;
}
return realObjects;
}
void ObjectsContainersList::ForEachObject(
std::function<void(const gd::Object& object)> fn) const {
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
++it) {
const auto& objectsContainer = **it;
for (const auto& object : objectsContainer.GetObjects()) {
fn(*object);
}
}
}
gd::String ObjectsContainersList::GetTypeOfObject(
const gd::String& objectName) const {
if (objectsContainers.size() != 2) {
std::cout << this << std::endl;
std::cout << objectsContainers.size() << std::endl;
// TODO: rework forwarded methods so they can work with any number of
// containers.
gd::LogFatalError(
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
"not being exactly 2. This is a logical error and will crash.");
}
return gd::GetTypeOfObject(
*objectsContainers[0], *objectsContainers[1], objectName, true);
}
bool ObjectsContainersList::HasBehaviorInObjectOrGroup(
const gd::String& objectOrGroupName, const gd::String& behaviorName) const {
if (objectsContainers.size() != 2) {
// TODO: rework forwarded methods so they can work with any number of
// containers.
gd::LogFatalError(
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
"not being exactly 2. This is a logical error and will crash.");
}
return gd::HasBehaviorInObjectOrGroup(*objectsContainers[0],
*objectsContainers[1],
objectOrGroupName,
behaviorName,
true);
}
gd::String ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup(
const gd::String& objectOrGroupName,
const gd::String& behaviorName,
bool searchInGroups) const {
if (objectsContainers.size() != 2) {
// TODO: rework forwarded methods so they can work with any number of
// containers.
gd::LogFatalError(
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
"not being exactly 2. This is a logical error and will crash.");
}
return gd::GetTypeOfBehaviorInObjectOrGroup(*objectsContainers[0],
*objectsContainers[1],
objectOrGroupName,
behaviorName,
searchInGroups);
}
gd::String ObjectsContainersList::GetTypeOfBehavior(
const gd::String& behaviorName, bool searchInGroups) const {
if (objectsContainers.size() != 2) {
// TODO: rework forwarded methods so they can work with any number of
// containers.
gd::LogFatalError(
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
"not being exactly 2. This is a logical error and will crash.");
}
return gd::GetTypeOfBehavior(
*objectsContainers[0], *objectsContainers[1], behaviorName, searchInGroups);
}
std::vector<gd::String> ObjectsContainersList::GetBehaviorsOfObject(
const gd::String& objectName, bool searchInGroups) const {
if (objectsContainers.size() != 2) {
// TODO: rework forwarded methods so they can work with any number of
// containers.
gd::LogFatalError(
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
"not being exactly 2. This is a logical error and will crash.");
}
return gd::GetBehaviorsOfObject(
*objectsContainers[0], *objectsContainers[1], objectName, searchInGroups);
}
} // namespace gd

View File

@@ -1,142 +0,0 @@
#pragma once
#include <vector>
#include "Variable.h"
namespace gd {
class String;
class Project;
class Layout;
class ObjectsContainer;
class VariablesContainer;
class Object;
class ObjectConfiguration;
} // namespace gd
namespace gd {
/**
* \brief A list of objects containers, useful for accessing objects in a
* scoped way, along with methods to access them.
*
* \see gd::Object
* \see gd::ObjectsContainer
* \see gd::Project
* \see gd::Layout
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API ObjectsContainersList {
public:
virtual ~ObjectsContainersList(){};
static ObjectsContainersList MakeNewObjectsContainersListForProjectAndLayout(
const gd::Project& project, const gd::Layout& layout);
static ObjectsContainersList MakeNewObjectsContainersListForContainers(
const gd::ObjectsContainer& globalObjectsContainer,
const gd::ObjectsContainer& objectsContainer);
/**
* \brief Check if the specified object or group exists.
*/
bool HasObjectOrGroupNamed(const gd::String& name) const;
/**
* \brief Check if the specified object or group has the specified variable in
* its declared variables.
*/
bool HasObjectOrGroupWithVariableNamed(const gd::String& objectOrGroupName,
const gd::String& variableName) const;
/**
* \brief Check if the specified object or group has the specified variables
* container.
*/
bool HasVariablesContainer(
const gd::String& objectOrGroupName,
const gd::VariablesContainer& variablesContainer) const;
/**
* \brief Return the container of the variables for the specified object or
* group of objects.
*/
const gd::VariablesContainer* GetObjectOrGroupVariablesContainer(
const gd::String& objectOrGroupName) const;
/**
* \brief Get a type from an object/group name.
* \note If a group contains only objects of a same type, then the group has
* this type. Otherwise, it is considered as an object without any specific
* type.
*
* @return Type of the object/group.
*/
gd::String GetTypeOfObject(const gd::String& objectName) const;
/**
* \brief Check if an object or all object of a group has a behavior.
*/
bool HasBehaviorInObjectOrGroup(const gd::String& objectOrGroupName,
const gd::String& behaviorName) const;
/**
* \brief Get the type of a behavior if an object or all objects of a group has it.
*/
gd::String GetTypeOfBehaviorInObjectOrGroup(const gd::String &objectOrGroupName,
const gd::String &behaviorName,
bool searchInGroups = true) const;
/**
* \brief Get a type from a behavior name
* @return Type of the behavior.
* @deprecated - Use GetTypeOfBehaviorInObjectOrGroup instead.
*/
gd::String GetTypeOfBehavior(const gd::String& behaviorName, bool searchInGroups = true) const;
/**
* \brief Get behaviors of an object/group
* \note The behaviors of a group are the behaviors which are found in common
* when looking all the objects of the group.
*
* @return Vector containing names of behaviors
*/
std::vector<gd::String>
GetBehaviorsOfObject(const gd::String& objectName,
bool searchInGroups = true) const;
/**
* \brief Return a list containing all objects refered to by the group.
* If an object name is passed, then only this object name is returned.
*
* If \a onlyObjectToSelectIfPresent is set and present in the group(s),
* only this object will be returned. This is useful for considering this
* object as the "currently selected" object, when generating a condition or
* an action.
*/
std::vector<gd::String> ExpandObjectName(
const gd::String& objectOrGroupName,
const gd::String& onlyObjectToSelectIfPresent = "") const;
void ForEachObject(std::function<void(const gd::Object& object)> fn) const;
/**
* \brief Call the callback for each object or group name starting with the prefix passed in parameter.
*/
void ForEachNameWithPrefix(const gd::String& prefix, std::function<void(const gd::String& name, const gd::ObjectConfiguration* objectConfiguration)> fn) const;
/** Do not use - should be private but accessible to let Emscripten create a
* temporary. */
ObjectsContainersList(){};
private:
bool HasObjectNamed(const gd::String& name) const;
void Add(const gd::ObjectsContainer& objectsContainer) {
objectsContainers.push_back(&objectsContainer);
};
std::vector<const gd::ObjectsContainer*> objectsContainers;
};
} // namespace gd

View File

@@ -1,174 +0,0 @@
#pragma once
#include <set>
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "ObjectsContainersList.h"
#include "PropertiesContainersList.h"
#include "VariablesContainersList.h"
namespace gd {
class Project;
class ObjectsContainer;
class ObjectsContainersList;
class VariablesContainersList;
class PropertiesContainersList;
class NamedPropertyDescriptor;
} // namespace gd
namespace gd {
/**
* \brief Holds references to variables, objects, properties and other
* containers.
*
* This is useful to access elements of a project from a specific location,
* honoring the scope of each element.
*
* For example, in an expression, when an identifier is written, this class is
* used to know what this identifier refers too.
*/
class ProjectScopedContainers {
public:
ProjectScopedContainers(
const gd::ObjectsContainersList &objectsContainersList_,
const gd::VariablesContainersList &variablesContainersList_,
const gd::PropertiesContainersList &propertiesContainersList_)
: objectsContainersList(objectsContainersList_),
variablesContainersList(variablesContainersList_),
propertiesContainersList(propertiesContainersList_){};
virtual ~ProjectScopedContainers(){};
static ProjectScopedContainers
MakeNewProjectScopedContainersForProjectAndLayout(const gd::Project &project,
const gd::Layout &layout) {
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForProjectAndLayout(
project, layout),
VariablesContainersList::
MakeNewVariablesContainersListForProjectAndLayout(project, layout),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
return projectScopedContainers;
}
static ProjectScopedContainers MakeNewProjectScopedContainersFor(
const gd::ObjectsContainer &globalObjectsContainers,
const gd::ObjectsContainer &objectsContainers) {
ProjectScopedContainers projectScopedContainers(
ObjectsContainersList::MakeNewObjectsContainersListForContainers(
globalObjectsContainers, objectsContainers),
VariablesContainersList::MakeNewEmptyVariablesContainersList(),
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
return projectScopedContainers;
}
ProjectScopedContainers &AddPropertiesContainer(
const gd::PropertiesContainer &container) {
propertiesContainersList.Add(container);
return *this;
}
ProjectScopedContainers &AddParameters(
const std::vector<gd::ParameterMetadata> &parameters) {
parametersVectorsList.push_back(&parameters);
return *this;
}
template <class ReturnType>
ReturnType MatchIdentifierWithName(
const gd::String &name,
std::function<ReturnType()> objectCallback,
std::function<ReturnType()> variableCallback,
std::function<ReturnType()> propertyCallback,
std::function<ReturnType()> parameterCallback,
std::function<ReturnType()> notFoundCallback) const {
if (objectsContainersList.HasObjectOrGroupNamed(name))
return objectCallback();
else if (variablesContainersList.Has(name))
return variableCallback();
else if (ParameterMetadataTools::Has(parametersVectorsList, name))
return parameterCallback();
else if (propertiesContainersList.Has(name))
return propertyCallback();
return notFoundCallback();
};
void ForEachIdentifierWithPrefix(
const gd::String &prefix,
std::function<void(const gd::String &name,
const ObjectConfiguration *objectConfiguration)>
objectCallback,
std::function<void(const gd::String &name, const gd::Variable &variable)>
variableCallback,
std::function<void(const gd::NamedPropertyDescriptor &property)>
propertyCallback,
std::function<void(const gd::ParameterMetadata &parameter)>
parameterCallback) const {
std::set<gd::String> namesAlreadySeen;
objectsContainersList.ForEachNameWithPrefix(
prefix,
[&](const gd::String &name,
const ObjectConfiguration *objectConfiguration) {
if (namesAlreadySeen.count(name) == 0) {
namesAlreadySeen.insert(name);
objectCallback(name, objectConfiguration);
}
});
variablesContainersList.ForEachVariableWithPrefix(
prefix, [&](const gd::String &name, const gd::Variable &variable) {
if (namesAlreadySeen.count(name) == 0) {
namesAlreadySeen.insert(name);
variableCallback(name, variable);
}
});
gd::ParameterMetadataTools::ForEachParameterWithPrefix(
parametersVectorsList,
prefix,
[&](const gd::ParameterMetadata &parameter) {
if (namesAlreadySeen.count(parameter.GetName()) == 0) {
namesAlreadySeen.insert(parameter.GetName());
parameterCallback(parameter);
}
});
propertiesContainersList.ForEachPropertyWithPrefix(
prefix, [&](const gd::NamedPropertyDescriptor &property) {
if (namesAlreadySeen.count(property.GetName()) == 0) {
namesAlreadySeen.insert(property.GetName());
propertyCallback(property);
}
});
};
const gd::ObjectsContainersList &GetObjectsContainersList() const {
return objectsContainersList;
};
const gd::VariablesContainersList &GetVariablesContainersList() const {
return variablesContainersList;
};
const gd::PropertiesContainersList &GetPropertiesContainersList() const {
return propertiesContainersList;
};
const std::vector<const std::vector<gd::ParameterMetadata> *> &GetParametersVectorsList() const {
return parametersVectorsList;
};
/** Do not use - should be private but accessible to let Emscripten create a
* temporary. */
ProjectScopedContainers(){};
private:
gd::ObjectsContainersList objectsContainersList;
gd::VariablesContainersList variablesContainersList;
gd::PropertiesContainersList propertiesContainersList;
std::vector<const std::vector<gd::ParameterMetadata> *> parametersVectorsList;
};
} // namespace gd

View File

@@ -1,46 +0,0 @@
#pragma once
#include "EventsFunctionsContainer.h"
#include "GDCore/Tools/SerializableWithNameList.h"
#include "NamedPropertyDescriptor.h"
namespace gd {
/**
* \brief A container of properties, used for custom behaviors, custom objects,
* extensions...
*
* \see gd::NamedPropertyDescriptor
*
* \ingroup PlatformDefinition
*/
class PropertiesContainer
: public SerializableWithNameList<NamedPropertyDescriptor> {
public:
PropertiesContainer(EventsFunctionsContainer::FunctionOwner owner)
: SerializableWithNameList<NamedPropertyDescriptor>(), owner(owner) {}
PropertiesContainer(const PropertiesContainer& other)
: SerializableWithNameList<NamedPropertyDescriptor>(other),
owner(other.owner) {}
PropertiesContainer& operator=(const PropertiesContainer& other) {
if (this != &other) {
SerializableWithNameList<NamedPropertyDescriptor>::operator=(other);
owner = other.owner;
}
return *this;
}
void ForEachPropertyWithPrefix(const gd::String& prefix, std::function<void(const gd::NamedPropertyDescriptor& property)> fn) const {
for (const auto& property: elements) {
if (property->GetName().find(prefix) == 0) fn(*property);
}
}
EventsFunctionsContainer::FunctionOwner GetOwner() const { return owner; }
private:
EventsFunctionsContainer::FunctionOwner owner;
};
} // namespace gd

View File

@@ -1,67 +0,0 @@
#include "PropertiesContainersList.h"
#include <functional>
#include <vector>
#include "PropertiesContainer.h"
namespace gd {
NamedPropertyDescriptor PropertiesContainersList::badNamedPropertyDescriptor;
PropertiesContainer PropertiesContainersList::badPropertiesContainer(gd::EventsFunctionsContainer::FunctionOwner::Extension);
PropertiesContainersList
PropertiesContainersList::MakeNewPropertiesContainersListFor(
const gd::PropertiesContainer& propertiesContainer) {
PropertiesContainersList propertiesContainersList;
propertiesContainersList.Add(propertiesContainer);
return propertiesContainersList;
}
PropertiesContainersList
PropertiesContainersList::MakeNewEmptyPropertiesContainersList() {
PropertiesContainersList propertiesContainersList;
return propertiesContainersList;
}
bool PropertiesContainersList::Has(const gd::String& name) const {
for (auto it = propertiesContainers.rbegin();
it != propertiesContainers.rend();
++it) {
if ((*it)->Has(name)) return true;
}
return false;
}
std::pair<std::reference_wrapper<const gd::PropertiesContainer>,
std::reference_wrapper<const NamedPropertyDescriptor>>
PropertiesContainersList::Get(const gd::String& name) const {
for (auto it = propertiesContainers.rbegin();
it != propertiesContainers.rend();
++it) {
if ((*it)->Has(name)) return {**it, (*it)->Get(name)};
}
return {badPropertiesContainer, badNamedPropertyDescriptor};
}
bool PropertiesContainersList::HasPropertiesContainer(const gd::PropertiesContainer& propertiesContainer) const {
for (auto it = propertiesContainers.rbegin(); it != propertiesContainers.rend();
++it) {
if (*it == &propertiesContainer) return true;
}
return false;
}
void PropertiesContainersList::ForEachPropertyWithPrefix(
const gd::String& prefix,
std::function<void(const gd::NamedPropertyDescriptor& property)> fn) const {
for (auto it = propertiesContainers.rbegin(); it != propertiesContainers.rend();
++it) {
(*it)->ForEachPropertyWithPrefix(prefix, fn);
}
}
} // namespace gd

View File

@@ -1,84 +0,0 @@
#pragma once
#include <functional>
#include <vector>
#include "PropertiesContainer.h"
namespace gd {
class String;
class Project;
class Layout;
class NamedPropertyDescriptor;
} // namespace gd
namespace gd {
/**
* \brief A list of property containers, useful for accessing properties in a
* scoped way.
*
* \see gd::NamedPropertyDescriptor
* \see gd::Project
* \see gd::Layout
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API PropertiesContainersList {
public:
virtual ~PropertiesContainersList(){};
static PropertiesContainersList MakeNewPropertiesContainersListFor(
const gd::PropertiesContainer& propertiesContainer);
static PropertiesContainersList MakeNewEmptyPropertiesContainersList();
/**
* \brief Add a new container of properties in the list.
* Add containers in order from the most global one to the most local one.
*/
void Add(const gd::PropertiesContainer& propertiesContainer) {
propertiesContainers.push_back(&propertiesContainer);
};
/**
* \brief Return true if the specified property is in one of the containers.
*/
bool Has(const gd::String& name) const;
/**
* \brief Return a reference to the property called \a name, and the
* properties container holding it.
*/
std::pair<std::reference_wrapper<const gd::PropertiesContainer>,
std::reference_wrapper<const NamedPropertyDescriptor>>
Get(const gd::String& name) const;
/**
* \brief Return true if the specified properties container is present.
*/
bool HasPropertiesContainer(const gd::PropertiesContainer& propertiesContainer) const;
/**
* Get the properties container at the bottom of the scope (so the most
* "local" one).
*/
const PropertiesContainer* GetBottomMostPropertiesContainer() const {
if (propertiesContainers.empty()) return nullptr;
return propertiesContainers.back();
}
/**
* \brief Call the callback for each property having a name starting with the specified prefix.
*/
void ForEachPropertyWithPrefix(const gd::String& prefix, std::function<void(const gd::NamedPropertyDescriptor& property)> fn) const;
/** Do not use - should be private but accessible to let Emscripten create a
* temporary. */
PropertiesContainersList(){};
private:
std::vector<const gd::PropertiesContainer*> propertiesContainers;
static NamedPropertyDescriptor badNamedPropertyDescriptor;
static PropertiesContainer badPropertiesContainer;
};
} // namespace gd

View File

@@ -10,7 +10,6 @@
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
#include "GDCore/Tools/UUID/UUID.h"
using namespace std;
@@ -229,9 +228,6 @@ void Variable::SerializeTo(SerializerElement& element) const {
element.SetStringAttribute("type", TypeAsString(GetType()));
if (IsFolded()) element.SetBoolAttribute("folded", true);
if (!persistentUuid.empty())
element.SetStringAttribute("persistentUuid", persistentUuid);
if (type == Type::String) {
element.SetStringAttribute("value", GetString());
} else if (type == Type::Number) {
@@ -258,8 +254,6 @@ void Variable::SerializeTo(SerializerElement& element) const {
void Variable::UnserializeFrom(const SerializerElement& element) {
type = StringAsType(element.GetStringAttribute("type", "string"));
persistentUuid = element.GetStringAttribute("persistentUuid");
// Compatibility with GD <= 5.0.0-beta102
// Before, everything was stored as strings.
// We can unserialize primitives as string as they can be converted from/to
@@ -296,12 +290,7 @@ void Variable::UnserializeFrom(const SerializerElement& element) {
PushNew().UnserializeFrom(childElement);
}
}
}
Variable& Variable::ResetPersistentUuid() {
persistentUuid = UUID::MakeUuid4();
return *this;
}
} // namespace gd
std::vector<gd::String> Variable::GetAllChildrenNames() const {
std::vector<gd::String> names;
@@ -349,8 +338,7 @@ Variable::Variable(const Variable& other)
str(other.str),
folded(other.folded),
boolVal(other.boolVal),
type(other.type),
persistentUuid(other.persistentUuid) {
type(other.type) {
CopyChildren(other);
}
@@ -361,7 +349,6 @@ Variable& Variable::operator=(const Variable& other) {
folded = other.folded;
boolVal = other.boolVal;
type = other.type;
persistentUuid = other.persistentUuid;
CopyChildren(other);
}

View File

@@ -338,24 +338,6 @@ class GD_CORE_API Variable {
* \brief Unserialize the variable.
*/
void UnserializeFrom(const SerializerElement& element);
/**
* \brief Reset the persistent UUID used to recognize
* the same variable between serialization.
*/
Variable& ResetPersistentUuid();
/**
* \brief Remove the persistent UUID - when the variable no
* longer needs to be recognized between serializations.
*/
Variable& ClearPersistentUuid() { persistentUuid = ""; return *this; };
/**
* \brief Get the persistent UUID used to recognize
* the same variable between serialization.
*/
const gd::String& GetPersistentUuid() const { return persistentUuid; };
///@}
private:
@@ -379,8 +361,6 @@ class GD_CORE_API Variable {
mutable std::vector<std::shared_ptr<Variable>>
childrenArray; ///< Children, when the variable is considered as an
///< array.
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID,
///< useful for computing changesets.
/**
* Initialize children by copying them from another variable. Used by

View File

@@ -12,7 +12,6 @@
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
#include "GDCore/TinyXml/tinyxml.h"
#include "GDCore/Tools/UUID/UUID.h"
namespace gd {
@@ -162,18 +161,7 @@ void VariablesContainer::Move(std::size_t oldIndex, std::size_t newIndex) {
variables.insert(variables.begin() + newIndex, nameAndVariable);
}
void VariablesContainer::ForEachVariableWithPrefix(
const gd::String& prefix,
std::function<void(const gd::String& name, const gd::Variable& variable)> fn) const {
for (const auto& nameAndVariable: variables) {
if (nameAndVariable.first.find(prefix) == 0) fn(nameAndVariable.first, *nameAndVariable.second);
}
}
void VariablesContainer::SerializeTo(SerializerElement& element) const {
if (!persistentUuid.empty())
element.SetStringAttribute("persistentUuid", persistentUuid);
element.ConsiderAsArrayOf("variable");
for (std::size_t j = 0; j < variables.size(); j++) {
SerializerElement& variableElement = element.AddChild("variable");
@@ -183,8 +171,6 @@ void VariablesContainer::SerializeTo(SerializerElement& element) const {
}
void VariablesContainer::UnserializeFrom(const SerializerElement& element) {
persistentUuid = element.GetStringAttribute("persistentUuid");
Clear();
element.ConsiderAsArrayOf("variable", "Variable");
for (std::size_t j = 0; j < element.GetChildrenCount(); j++) {
@@ -197,24 +183,6 @@ void VariablesContainer::UnserializeFrom(const SerializerElement& element) {
}
}
VariablesContainer& VariablesContainer::ResetPersistentUuid() {
persistentUuid = UUID::MakeUuid4();
for(auto& variable: variables) {
variable.second->ResetPersistentUuid();
}
return *this;
}
VariablesContainer& VariablesContainer::ClearPersistentUuid() {
persistentUuid = "";
for(auto& variable: variables) {
variable.second->ClearPersistentUuid();
}
return *this;
}
VariablesContainer::VariablesContainer(const VariablesContainer& other) {
Init(other);
}
@@ -227,7 +195,6 @@ VariablesContainer& VariablesContainer::operator=(
}
void VariablesContainer::Init(const gd::VariablesContainer& other) {
persistentUuid = other.persistentUuid;
variables.clear();
for (auto& it : other.variables) {
variables.push_back(

View File

@@ -137,11 +137,6 @@ class GD_CORE_API VariablesContainer {
* \brief Clear all variables of the container.
*/
inline void Clear() { variables.clear(); }
/**
* \brief Call the callback for each variable with a name starting with the specified prefix.
*/
void ForEachVariableWithPrefix(const gd::String& prefix, std::function<void(const gd::String& name, const gd::Variable& variable)> fn) const;
///@}
/** \name Saving and loading
@@ -157,30 +152,10 @@ class GD_CORE_API VariablesContainer {
* \brief Unserialize the variable container.
*/
void UnserializeFrom(const SerializerElement& element);
/**
* \brief Reset the persistent UUID, used to recognize
* the same variables between serialization.
*/
VariablesContainer& ResetPersistentUuid();
/**
* \brief Remove the persistent UUID - when the variables no
* longer need to be recognized between serializations.
*/
VariablesContainer& ClearPersistentUuid();
/**
* \brief Get the persistent UUID used to recognize
* the same variables between serialization.
*/
const gd::String& GetPersistentUuid() const { return persistentUuid; };
///@}
private:
std::vector<std::pair<gd::String, std::shared_ptr<gd::Variable>>> variables;
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID,
///< useful for computing changesets.
static gd::Variable badVariable;
static gd::String badName;

View File

@@ -1,64 +0,0 @@
#include "VariablesContainersList.h"
#include <vector>
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Variable.h"
namespace gd {
Variable VariablesContainersList::badVariable;
VariablesContainersList
VariablesContainersList::MakeNewVariablesContainersListForProjectAndLayout(
const gd::Project& project, const gd::Layout& layout) {
VariablesContainersList variablesContainersList;
variablesContainersList.Add(project.GetVariables());
variablesContainersList.Add(layout.GetVariables());
return variablesContainersList;
}
VariablesContainersList
VariablesContainersList::MakeNewEmptyVariablesContainersList() {
VariablesContainersList variablesContainersList;
return variablesContainersList;
}
bool VariablesContainersList::Has(const gd::String& name) const {
for (auto it = variablesContainers.rbegin(); it != variablesContainers.rend();
++it) {
if ((*it)->Has(name)) return true;
}
return false;
}
const Variable& VariablesContainersList::Get(const gd::String& name) const {
for (auto it = variablesContainers.rbegin(); it != variablesContainers.rend();
++it) {
if ((*it)->Has(name)) return (*it)->Get(name);
}
return badVariable;
}
bool VariablesContainersList::HasVariablesContainer(const gd::VariablesContainer& variablesContainer) const {
for (auto it = variablesContainers.rbegin(); it != variablesContainers.rend();
++it) {
if (*it == &variablesContainer) return true;
}
return false;
}
void VariablesContainersList::ForEachVariableWithPrefix(
const gd::String& prefix,
std::function<void(const gd::String& name, const gd::Variable& variable)> fn) const {
for (auto it = variablesContainers.rbegin(); it != variablesContainers.rend();
++it) {
(*it)->ForEachVariableWithPrefix(prefix, fn);
}
}
} // namespace gd

View File

@@ -1,85 +0,0 @@
#pragma once
#include <vector>
#include <functional>
namespace gd {
class String;
class Project;
class Layout;
class VariablesContainer;
class Variable;
} // namespace gd
namespace gd {
/**
* \brief A list of variables containers, useful for accessing variables in a
* scoped way.
*
* \see gd::Variable
* \see gd::Project
* \see gd::Layout
*
* \ingroup PlatformDefinition
*/
class GD_CORE_API VariablesContainersList {
public:
virtual ~VariablesContainersList(){};
static VariablesContainersList
MakeNewVariablesContainersListForProjectAndLayout(const gd::Project& project,
const gd::Layout& layout);
static VariablesContainersList MakeNewEmptyVariablesContainersList();
/**
* \brief Return true if the specified variable is in one of the containers.
*/
bool Has(const gd::String& name) const;
/**
* \brief Return a reference to the variable called \a name.
*/
const Variable& Get(const gd::String& name) const;
/**
* \brief Return true if the specified variable container is present.
*/
bool HasVariablesContainer(const gd::VariablesContainer& variablesContainer) const;
/**
* Get the variables container at the top of the scope (so the most "global" one).
* \brief Avoid using apart when a scope must be forced.
*/
const VariablesContainer* GetTopMostVariablesContainer() const {
if (variablesContainers.empty()) return nullptr;
return variablesContainers.front();
};
/**
* Get the variables container at the bottom of the scope (so the most "local" one).
* \brief Avoid using apart when a scope must be forced.
*/
const VariablesContainer* GetBottomMostVariablesContainer() const {
if (variablesContainers.empty()) return nullptr;
return variablesContainers.back();
}
/**
* \brief Call the callback for each variable having a name starting with the specified prefix.
*/
void ForEachVariableWithPrefix(const gd::String& prefix, std::function<void(const gd::String& name, const gd::Variable& variable)> fn) const;
/** Do not use - should be private but accessible to let Emscripten create a temporary. */
VariablesContainersList() {};
private:
void Add(const gd::VariablesContainer& variablesContainer) {
variablesContainers.push_back(&variablesContainer);
};
std::vector<const gd::VariablesContainer*> variablesContainers;
static Variable badVariable;
};
} // namespace gd

View File

@@ -13,8 +13,6 @@
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Events/Builtin/StandardEvent.h"
#include "GDCore/Events/Builtin/ForEachChildVariableEvent.h"
#include "GDCore/Events/Builtin/RepeatEvent.h"
#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h"
#include "GDCore/Extensions/Metadata/ParameterOptions.h"
#include "catch.hpp"
@@ -105,8 +103,6 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
commonInstructionsExtension->SetExtensionInformation(
"BuiltinCommonInstructions", "instruction extension", "", "", "");
commonInstructionsExtension->AddEvent("Standard", "Standard event", "", "", "", std::make_shared<gd::StandardEvent>());
commonInstructionsExtension->AddEvent("ForEachChildVariable", "For each child variable event", "", "", "", std::make_shared<gd::ForEachChildVariableEvent>());
commonInstructionsExtension->AddEvent("Repeat", "Repeat event", "", "", "", std::make_shared<gd::RepeatEvent>());
std::shared_ptr<gd::PlatformExtension> baseObjectExtension =
std::shared_ptr<gd::PlatformExtension>(new gd::PlatformExtension);
@@ -247,20 +243,6 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
.AddParameter("soundfile", "Parameter 3 (an audio resource)")
.SetFunctionName("doSomethingWithResources");
extension
->AddAction("DoSomethingWithLegacyPreScopedVariables",
"Do something with variables",
"This does something with variables",
"Do something with variables please",
"",
"",
"")
.AddParameter("scenevar", "Scene variable")
.AddParameter("globalvar", "Global variable")
.AddParameter("object", "Some object")
.AddParameter("objectvar", "Some variable of the object")
.SetFunctionName("doSomethingWithVariables");
extension->AddExpression("GetNumber", "Get me a number", "", "", "")
.SetFunctionName("getNumber");
extension
@@ -363,7 +345,7 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("expression", _("Number parameter"))
.AddParameter("string", _("String parameter"))
.AddParameter("expression", _("Identifier parameter"))
.AddParameter("", _("Identifier parameter"))
.SetFunctionName("getObjectStringWith3Param");
object
.AddStrExpression("GetObjectStringWith2ObjectParam",
@@ -578,15 +560,15 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
extension
->AddExpression(
"LayerEffectParameter",
_("Effect property (number)"),
_("Return the value of a property of an effect."),
_("Effect parameter (number)"),
_("Return the value of a parameter of an effect."),
_("Effects"),
"")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("layerEffectName", _("Effect name"))
.AddParameter("layerEffectParameterName", _("Property name"));
.AddParameter("layerEffectParameterName", _("Parameter name"));
}
{

View File

@@ -15,7 +15,6 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "catch.hpp"
namespace {
@@ -36,8 +35,6 @@ TEST_CASE("EventsBehaviorRenamer (expressions)", "[common]") {
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
auto &object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
@@ -60,7 +57,7 @@ TEST_CASE("EventsBehaviorRenamer (expressions)", "[common]") {
// Rename the first behavior.
gd::EventsBehaviorRenamer behaviorRenamer(
platform, "Object1", "MyBehavior", "MyRenamedBehavior");
behaviorRenamer.Launch(layout1.GetEvents(), projectScopedContainers);
behaviorRenamer.Launch(layout1.GetEvents(), project, layout1);
// Verify the expression were updated.
REQUIRE(EnsureStandardEvent(layout1.GetEvents().GetEvent(0))
@@ -77,8 +74,6 @@ TEST_CASE("EventsBehaviorRenamer (instructions)", "[common]") {
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
auto projectScopedContainers =
gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
auto &object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
@@ -114,7 +109,7 @@ TEST_CASE("EventsBehaviorRenamer (instructions)", "[common]") {
// Rename MyBehavior.
gd::EventsBehaviorRenamer behaviorRenamer(
platform, "Object1", "MyBehavior", "MyRenamedBehavior");
behaviorRenamer.Launch(layout1.GetEvents(), projectScopedContainers);
behaviorRenamer.Launch(layout1.GetEvents(), project, layout1);
// Ensure the action using MyBehavior has its parameter renamed.
REQUIRE(EnsureStandardEvent(layout1.GetEvents().GetEvent(0))

View File

@@ -20,13 +20,6 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
// Add some variables and objects:
layout1.GetVariables().InsertNew("MySceneVariable", 0);
layout1.GetVariables().InsertNew("MySceneVariable2", 1);
layout1.GetVariables().InsertNew("MySceneStructureVariable", 2).GetChild("MyChild");
layout1.GetVariables().InsertNew("MySceneStructureVariable2", 2).GetChild("MyChild");
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
layout1.InsertNewObject(
project, "MyExtension::Sprite", "MyOtherSpriteObject", 1);
@@ -34,15 +27,6 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
"MyExtension::FakeObjectWithDefaultBehavior",
"FakeObjectWithDefaultBehavior",
2);
// Also insert a variable having the same name as an object:
layout1.InsertNewObject(project, "MyExtension::Sprite", "ObjectWithNameReused", 3);
layout1.GetVariables().InsertNew("ObjectWithNameReused", 3).GetChild("MyChild");
// Also insert a global variable having the same name as a scene variable:
layout1.GetVariables().InsertNew("SceneVariableWithNameReused", 4);
project.GetVariables().InsertNew("SceneVariableWithNameReused", 0);
auto &group = layout1.GetObjectGroups().InsertNew("AllObjects");
group.AddObject("MySpriteObject");
group.AddObject("MyOtherSpriteObject");
@@ -285,7 +269,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
parser.ParseExpression("MySpriteObject.GetObjectStringWith3Param("
"MySpriteObject.GetObjectNumber() / 2.3, "
"MySpriteObject.GetObjectStringWith1Param("
"MyExtension::GetNumber()), UnknownObject.Unknown)");
"MyExtension::GetNumber()), test)");
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
"",
codeGenerator,
@@ -297,7 +281,8 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
"MySpriteObject.getObjectStringWith3Param(MySpriteObject."
"getObjectNumber() ?? 0 / 2.3, "
"MySpriteObject.getObjectStringWith1Param(getNumber()) ?? \"\", "
"0) ?? \"\"");
"/* Error during generation, unrecognized identifier type: "
"unknown with value test */ \"test\") ?? \"\"");
}
SECTION("missing parameter") {
{
@@ -407,178 +392,9 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
"123) ?? \"\"");
}
}
SECTION("Properties (1 level)") {
gd::PropertiesContainer propertiesContainer(gd::EventsFunctionsContainer::Extension);
auto projectScopedContainersWithProperties = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithProperties.AddPropertiesContainer(propertiesContainer);
propertiesContainer.InsertNew("MyProperty");
propertiesContainer.InsertNew("MyProperty2");
gd::EventsCodeGenerator codeGeneratorWithProperties(platform, projectScopedContainersWithProperties);
{
auto node =
parser.ParseExpression("MyProperty + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGeneratorWithProperties,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getPropertyMyProperty() + 1");
}
{
auto node =
parser.ParseExpression("MyProperty + MyProperty2");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGeneratorWithProperties,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getPropertyMyProperty() + getPropertyMyProperty2()");
}
}
SECTION("Parameters (1 level)") {
std::vector<gd::ParameterMetadata> parameters;
gd::ParameterMetadata param1;
param1.SetName("MyParameter1");
param1.SetType("number");
gd::ParameterMetadata param2;
param2.SetName("MyParameter2");
param2.SetType("string");
parameters.push_back(param1);
parameters.push_back(param2);
auto projectScopedContainersWithParameters = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
projectScopedContainersWithParameters.AddParameters(parameters);
gd::EventsCodeGenerator codeGeneratorWithProperties(platform, projectScopedContainersWithParameters);
{
auto node =
parser.ParseExpression("MyParameter1 + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGeneratorWithProperties,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getParameterMyParameter1() + 1");
}
{
auto node =
parser.ParseExpression("MyParameter1 + MyParameter2");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGeneratorWithProperties,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getParameterMyParameter1() + getParameterMyParameter2()");
}
}
SECTION("Scene variables (1 level)") {
{
auto node =
parser.ParseExpression("MySceneVariable + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneVariable).getAsNumber() + 1");
}
{
auto node =
parser.ParseExpression("MySceneVariable + MySceneVariable2");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneVariable).getAsNumber() + getLayoutVariable(MySceneVariable2).getAsNumber()");
}
}
SECTION("Scene variables (conflict with a global variable)") {
{
auto node =
parser.ParseExpression("SceneVariableWithNameReused + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(SceneVariableWithNameReused).getAsNumber() + 1");
}
}
SECTION("Scene variables (2 levels)") {
{
auto node =
parser.ParseExpression("MySceneStructureVariable.MyChild + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + 1");
}
{
auto node =
parser.ParseExpression("MySceneStructureVariable.MyChild + MySceneStructureVariable2.MyChild");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + getLayoutVariable(MySceneStructureVariable2).getChild(\"MyChild\").getAsNumber()");
}
}
SECTION("Scene variables (2 levels with bracket accessor)") {
{
auto node =
parser.ParseExpression("MySceneStructureVariable[\"MyChild\"] + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + 1");
}
{
auto node =
parser.ParseExpression("MySceneStructureVariable[\"MyChild\"] + MySceneStructureVariable2[\"MyChild\"]");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getLayoutVariable(MySceneStructureVariable).getChild(\"MyChild\").getAsNumber() + getLayoutVariable(MySceneStructureVariable2).getChild(\"MyChild\").getAsNumber()");
}
}
SECTION("Object variable with non existing object (invalid)") {
SECTION("Function name") {
auto node =
parser.ParseExpression("MyNonExistingSpriteObject.MyVariable");
parser.ParseExpression("MySpriteObject.GetObjectNumber");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
@@ -588,124 +404,6 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "0");
}
SECTION("Object variables (1 level)") {
{
auto node =
parser.ParseExpression("MySpriteObject.MyVariable + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getVariableForObject(MySpriteObject, MyVariable).getAsNumber() + 1");
}
{
auto node =
parser.ParseExpression("MySpriteObject.MyVariable + MySpriteObject.MyVariable2");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getVariableForObject(MySpriteObject, MyVariable).getAsNumber() + getVariableForObject(MySpriteObject, MyVariable2).getAsNumber()");
}
}
SECTION("Object variables (conflict with a scene variable)") {
{
auto node =
parser.ParseExpression("ObjectWithNameReused.MyVariable + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getVariableForObject(ObjectWithNameReused, MyVariable).getAsNumber() + 1");
}
}
SECTION("Object variables (1 level with bracket accessor) (invalid)") {
{
auto node =
parser.ParseExpression("MySpriteObject[\"BracketNotationCantBeUsedHere\"] + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "fakeBadVariable.getAsNumber() + 1");
}
{
auto node =
parser.ParseExpression("MySpriteObject.MyVariable + MySpriteObject.MyVariable2");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getVariableForObject(MySpriteObject, MyVariable).getAsNumber() + getVariableForObject(MySpriteObject, MyVariable2).getAsNumber()");
}
}
SECTION("Object variables (2 levels)") {
{
auto node =
parser.ParseExpression("MySpriteObject.MyVariable.MyChildVariable + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getVariableForObject(MySpriteObject, MyVariable).getChild(\"MyChildVariable\").getAsNumber() + 1");
}
{
auto node =
parser.ParseExpression("MySpriteObject.MyVariable.MyChildVariable + MySpriteObject.MyVariable2.MyChildVariable");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getVariableForObject(MySpriteObject, MyVariable).getChild(\"MyChildVariable\").getAsNumber() + getVariableForObject(MySpriteObject, MyVariable2).getChild(\"MyChildVariable\").getAsNumber()");
}
}
SECTION("Object variables (2 levels with bracket accessor)") {
{
auto node =
parser.ParseExpression("MySpriteObject.MyVariable[\"MyChildVariable\"] + 1");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getVariableForObject(MySpriteObject, MyVariable).getChild(\"MyChildVariable\").getAsNumber() + 1");
}
{
auto node =
parser.ParseExpression("MySpriteObject.MyVariable[\"MyChildVariable\"] + MySpriteObject.MyVariable2[\"MyChildVariable\"]");
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
"",
codeGenerator,
context);
REQUIRE(node);
node->Visit(expressionCodeGenerator);
REQUIRE(expressionCodeGenerator.GetOutput() == "getVariableForObject(MySpriteObject, MyVariable).getChild(\"MyChildVariable\").getAsNumber() + getVariableForObject(MySpriteObject, MyVariable2).getChild(\"MyChildVariable\").getAsNumber()");
}
}
SECTION("Invalid variables") {
SECTION("empty variable") {
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
@@ -761,7 +459,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
"\"world\" ]", "")
== "getLayoutVariable(myVariable).getChild(\"hello\" + \"world\")");
}
SECTION("object variable (legacy)") {
SECTION("object variable") {
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
codeGenerator, context, "objectvar", "myVariable", "MySpriteObject")
== "getVariableForObject(MySpriteObject, myVariable)");

View File

@@ -5,8 +5,6 @@
*/
#include "GDCore/IDE/Events/ExpressionCompletionFinder.h"
#include <vector>
#include "DummyPlatform.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
@@ -14,7 +12,6 @@
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "catch.hpp"
TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
@@ -22,14 +19,7 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto& layout1 = project.InsertNewLayout("Layout1", 0);
layout1.GetVariables().InsertNew("myVariable");
auto& object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
object1.GetVariables().InsertNew("myObjectVariable");
gd::ProjectScopedContainers projectScopedContainers =
gd::ProjectScopedContainers::
MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
layout1.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
gd::ExpressionParser2 parser;
@@ -38,49 +28,38 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
size_t location) {
auto node = parser.ParseExpression(expression);
REQUIRE(node != nullptr);
auto completions =
gd::ExpressionCompletionFinder::GetCompletionDescriptionsFor(
platform, projectScopedContainers, type, *node, location);
std::vector<gd::String> completionsAsString;
for (const auto& completion : completions) {
completionsAsString.push_back(completion.ToString());
}
return completionsAsString;
return gd::ExpressionCompletionFinder::GetCompletionDescriptionsFor(
platform, project, layout1, type, *node, location);
};
const std::vector<gd::String> expectedEmptyCompletions;
const std::vector<gd::ExpressionCompletionDescription>
expectedEmptyCompletions;
SECTION("Identifier") {
SECTION("Object or expression completions when type is string") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "My", 0, 2).ToString()
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForObject("string", "My", 0, 2),
gd::ExpressionCompletionDescription::ForExpression(
"string", "My", 0, 2)};
REQUIRE(getCompletionsFor("string", "My", 0) == expectedCompletions);
REQUIRE(getCompletionsFor("string", "My", 1) == expectedCompletions);
REQUIRE(getCompletionsFor("string", "My", 2) == expectedEmptyCompletions);
}
SECTION("Object or expression completions when type is number") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, number, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("number", "My", 0, 2).ToString()
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForObject("number", "My", 0, 2),
gd::ExpressionCompletionDescription::ForExpression(
"number", "My", 0, 2)};
REQUIRE(getCompletionsFor("number", "My", 0) == expectedCompletions);
REQUIRE(getCompletionsFor("number", "My", 1) == expectedCompletions);
REQUIRE(getCompletionsFor("number", "My", 2) == expectedEmptyCompletions);
}
SECTION("Object or expression completions when type is number|string") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, number|string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("number|string", "My", 0, 2).ToString()
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForObject(
"number|string", "My", 0, 2),
gd::ExpressionCompletionDescription::ForExpression(
"number|string", "My", 0, 2)};
REQUIRE(getCompletionsFor("number|string", "My", 0) ==
expectedCompletions);
REQUIRE(getCompletionsFor("number|string", "My", 1) ==
@@ -89,51 +68,26 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
expectedEmptyCompletions);
}
SECTION("Object or expression completions in a variable name") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "My", 0, 2).ToString()
};
// clang-format on
REQUIRE(getCompletionsFor(
"number",
"MyExtension::GetVariableAsNumber(MyVariable[\"abc\" + My",
52) == expectedCompletions);
REQUIRE(getCompletionsFor(
"number",
"MyExtension::GetVariableAsNumber(MyVariable[\"abc\" + My",
53) == expectedCompletions);
REQUIRE(getCompletionsFor(
"number",
"MyExtension::GetVariableAsNumber(MyVariable[\"abc\" + My",
54) == expectedEmptyCompletions);
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForObject("string", "My", 0, 2),
gd::ExpressionCompletionDescription::ForExpression(
"string", "My", 0, 2)};
REQUIRE(getCompletionsFor("number", "MyExtension::GetVariableAsNumber(MyVariable[\"abc\" + My", 52) == expectedCompletions);
REQUIRE(getCompletionsFor("number", "MyExtension::GetVariableAsNumber(MyVariable[\"abc\" + My", 53) == expectedCompletions);
REQUIRE(getCompletionsFor("number", "MyExtension::GetVariableAsNumber(MyVariable[\"abc\" + My", 54) == expectedEmptyCompletions);
}
SECTION("Object or expression completions in a variable index") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, number, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("number", "My", 0, 2).ToString()
};
// clang-format on
REQUIRE(getCompletionsFor(
"number",
"MyExtension::GetVariableAsNumber(MyVariable[12345 + My",
52) == expectedCompletions);
REQUIRE(getCompletionsFor(
"number",
"MyExtension::GetVariableAsNumber(MyVariable[12345 + My",
53) == expectedCompletions);
REQUIRE(getCompletionsFor(
"number",
"MyExtension::GetVariableAsNumber(MyVariable[12345 + My",
54) == expectedEmptyCompletions);
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForObject("number", "My", 0, 2),
gd::ExpressionCompletionDescription::ForExpression(
"number", "My", 0, 2)};
REQUIRE(getCompletionsFor("number", "MyExtension::GetVariableAsNumber(MyVariable[12345 + My", 52) == expectedCompletions);
REQUIRE(getCompletionsFor("number", "MyExtension::GetVariableAsNumber(MyVariable[12345 + My", 53) == expectedCompletions);
REQUIRE(getCompletionsFor("number", "MyExtension::GetVariableAsNumber(MyVariable[12345 + My", 54) == expectedEmptyCompletions);
}
SECTION("Object when type is an object") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, object, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForObject("object", "My", 0, 2)};
REQUIRE(getCompletionsFor("object", "My", 0) == expectedCompletions);
REQUIRE(getCompletionsFor("object", "My", 1) == expectedCompletions);
REQUIRE(getCompletionsFor("object", "My", 2) == expectedEmptyCompletions);
@@ -142,11 +96,9 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Object when type is an object (alternate type)") {
// Also test alternate types also considered as objects (but that can
// result in different code generation):
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, objectPtr, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForObject(
"objectPtr", "My", 0, 2)};
REQUIRE(getCompletionsFor("objectPtr", "My", 0) == expectedCompletions);
REQUIRE(getCompletionsFor("objectPtr", "My", 1) == expectedCompletions);
REQUIRE(getCompletionsFor("objectPtr", "My", 2) ==
@@ -169,15 +121,13 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Free function") {
SECTION("Test 1") {
std::vector<gd::String> expectedCompletions{
gd::ExpressionCompletionDescription::ForExpressionWithPrefix(
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForExpression(
"string", "Function", 0, 8)};
std::vector<gd::ExpressionCompletionDescription> expectedExactCompletions{
gd::ExpressionCompletionDescription::ForExpression(
"string", "Function", 0, 8)
.ToString()};
std::vector<gd::String> expectedExactCompletions{
gd::ExpressionCompletionDescription::ForExpressionWithPrefix(
"string", "Function", 0, 8)
.SetIsExact(true)
.ToString()};
.SetIsExact(true)};
REQUIRE(getCompletionsFor("string", "Function(", 0) ==
expectedCompletions);
REQUIRE(getCompletionsFor("string", "Function(", 1) ==
@@ -197,48 +147,43 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
REQUIRE(getCompletionsFor("string", "Function(\"", 9) ==
expectedEmptyCompletions);
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 0, unknown, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }",
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("unknown", "My", 9, 10).ToString()
};
// clang-format on
REQUIRE(getCompletionsFor("string", "Function(My", 10) ==
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForObject("unknown", "a", 9, 10),
gd::ExpressionCompletionDescription::ForExpression(
"unknown", "a", 9, 10)};
REQUIRE(getCompletionsFor("string", "Function(a", 9) ==
expectedCompletions);
}
SECTION("Function with a Variable as argument") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 3, no type, 1, no prefix, myVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForVariable(
"scenevar", "myVar", 33, 38)};
REQUIRE(getCompletionsFor("number",
"MyExtension::GetVariableAsNumber(myVar",
33) == expectedCompletions);
}
SECTION("Object function with a Variable as argument") {
// clang-format off
std::vector<gd::String> expectedCompletions{
"{ 3, no type, 1, no prefix, myObjectVariable, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, no object configuration }",
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForVariable(
"objectvar", "myVar", 35, 40, "MyObject")};
getCompletionsFor("number",
"MyObject.GetObjectVariableAsNumber(myVar",
35);
REQUIRE(getCompletionsFor("number",
"MyObject.GetObjectVariableAsNumber(myObj",
"MyObject.GetObjectVariableAsNumber(myVar",
35) == expectedCompletions);
}
SECTION("Function with a Layer as argument") {
// clang-format off
std::vector<gd::String> expectedCompletions{
gd::ExpressionCompletionDescription::ForTextWithPrefix(
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
gd::ExpressionCompletionDescription::ForText(
"layer",
gd::MetadataProvider::GetExpressionMetadata(platform, "MyExtension::MouseX").GetParameter(0),
gd::MetadataProvider::GetExpressionMetadata(platform,
"MyExtension::MouseX")
.GetParameter(0),
"",
20,
21,
false)
.ToString()
};
// clang-format on
false)};
REQUIRE(getCompletionsFor("number", "MyExtension::MouseX(\"", 20) ==
expectedCompletions);
}
@@ -246,15 +191,16 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Partial object or behavior function") {
SECTION("Test with string type") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorOrFunctionCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("Func", 9, 13, "MyObject").ToString(),
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "Func", 9, 13, "MyObject").ToString()
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription>
expectedObjectCompletions{
gd::ExpressionCompletionDescription::ForObject(
"string", "MyObject", 0, 8)};
std::vector<gd::ExpressionCompletionDescription>
expectedBehaviorOrFunctionCompletions{
gd::ExpressionCompletionDescription::ForBehavior(
"Func", 9, 13, "MyObject"),
gd::ExpressionCompletionDescription::ForExpression(
"string", "Func", 9, 13, "MyObject")};
REQUIRE(getCompletionsFor("string", "MyObject.Func", 0) ==
expectedObjectCompletions);
REQUIRE(getCompletionsFor("string", "MyObject.Func", 7) ==
@@ -269,15 +215,16 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
expectedEmptyCompletions);
}
SECTION("Test with 'number|string' type") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, number|string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorOrFunctionCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("Func", 9, 13, "MyObject").ToString(),
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("number|string", "Func", 9, 13, "MyObject").ToString()
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription>
expectedObjectCompletions{
gd::ExpressionCompletionDescription::ForObject(
"number|string", "MyObject", 0, 8)};
std::vector<gd::ExpressionCompletionDescription>
expectedBehaviorOrFunctionCompletions{
gd::ExpressionCompletionDescription::ForBehavior(
"Func", 9, 13, "MyObject"),
gd::ExpressionCompletionDescription::ForExpression(
"number|string", "Func", 9, 13, "MyObject")};
REQUIRE(getCompletionsFor("number|string", "MyObject.Func", 0) ==
expectedObjectCompletions);
REQUIRE(getCompletionsFor("number|string", "MyObject.Func", 7) ==
@@ -295,18 +242,21 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Object function") {
SECTION("Test 1") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorOrFunctionCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("Func", 9, 13, "MyObject").ToString(),
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "Func", 9, 13, "MyObject").ToString()
};
std::vector<gd::String> expectedExactFunctionCompletions{
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "Func", 9, 13, "MyObject").SetIsExact(true).ToString()
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription>
expectedObjectCompletions{
gd::ExpressionCompletionDescription::ForObject(
"string", "MyObject", 0, 8)};
std::vector<gd::ExpressionCompletionDescription>
expectedBehaviorOrFunctionCompletions{
gd::ExpressionCompletionDescription::ForBehavior(
"Func", 9, 13, "MyObject"),
gd::ExpressionCompletionDescription::ForExpression(
"string", "Func", 9, 13, "MyObject")};
std::vector<gd::ExpressionCompletionDescription>
expectedExactFunctionCompletions{
gd::ExpressionCompletionDescription::ForExpression(
"string", "Func", 9, 13, "MyObject")
.SetIsExact(true)};
REQUIRE(getCompletionsFor("string", "MyObject.Func(", 0) ==
expectedObjectCompletions);
REQUIRE(getCompletionsFor("string", "MyObject.Func(", 7) ==
@@ -328,16 +278,18 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Partial behavior function") {
SECTION("Test 1") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("MyBehavior", 9, 19, "MyObject").ToString()};
std::vector<gd::String> expectedFunctionCompletions{
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "Func", 21, 25, "MyObject", "MyBehavior").ToString()
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription>
expectedObjectCompletions{
gd::ExpressionCompletionDescription::ForObject(
"string", "MyObject", 0, 8)};
std::vector<gd::ExpressionCompletionDescription>
expectedBehaviorCompletions{
gd::ExpressionCompletionDescription::ForBehavior(
"MyBehavior", 9, 19, "MyObject")};
std::vector<gd::ExpressionCompletionDescription>
expectedFunctionCompletions{
gd::ExpressionCompletionDescription::ForExpression(
"string", "Func", 21, 25, "MyObject", "MyBehavior")};
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::Func", 0) ==
expectedObjectCompletions);
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::Func", 7) ==
@@ -358,17 +310,18 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
expectedFunctionCompletions);
}
SECTION("Test 2") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("MyBehavior", 9, 19, "MyObject").ToString()
};
std::vector<gd::String> expectedFunctionCompletions{
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "", 21, 21, "MyObject", "MyBehavior").ToString()
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription>
expectedObjectCompletions{
gd::ExpressionCompletionDescription::ForObject(
"string", "MyObject", 0, 8)};
std::vector<gd::ExpressionCompletionDescription>
expectedBehaviorCompletions{
gd::ExpressionCompletionDescription::ForBehavior(
"MyBehavior", 9, 19, "MyObject")};
std::vector<gd::ExpressionCompletionDescription>
expectedFunctionCompletions{
gd::ExpressionCompletionDescription::ForExpression(
"string", "", 21, 21, "MyObject", "MyBehavior")};
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::", 0) ==
expectedObjectCompletions);
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::", 7) ==
@@ -388,20 +341,23 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
SECTION("Behavior function") {
SECTION("Test 1") {
// clang-format off
std::vector<gd::String> expectedObjectCompletions{
"{ 0, string, 1, no prefix, MyObject, no object name, no behavior name, non-exact, not last parameter, no parameter metadata, with object configuration }"
};
std::vector<gd::String> expectedBehaviorCompletions{
gd::ExpressionCompletionDescription::ForBehaviorWithPrefix("MyBehavior", 9, 19, "MyObject").ToString()
};
std::vector<gd::String> expectedFunctionCompletions{
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "Func", 21, 25, "MyObject", "MyBehavior").ToString()
};
std::vector<gd::String> expectedExactFunctionCompletions{
gd::ExpressionCompletionDescription::ForExpressionWithPrefix("string", "Func", 21, 25, "MyObject", "MyBehavior").SetIsExact(true).ToString()
};
// clang-format on
std::vector<gd::ExpressionCompletionDescription>
expectedObjectCompletions{
gd::ExpressionCompletionDescription::ForObject(
"string", "MyObject", 0, 8)};
std::vector<gd::ExpressionCompletionDescription>
expectedBehaviorCompletions{
gd::ExpressionCompletionDescription::ForBehavior(
"MyBehavior", 9, 19, "MyObject")};
std::vector<gd::ExpressionCompletionDescription>
expectedFunctionCompletions{
gd::ExpressionCompletionDescription::ForExpression(
"string", "Func", 21, 25, "MyObject", "MyBehavior")};
std::vector<gd::ExpressionCompletionDescription>
expectedExactFunctionCompletions{
gd::ExpressionCompletionDescription::ForExpression(
"string", "Func", 21, 25, "MyObject", "MyBehavior")
.SetIsExact(true)};
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::Func(", 0) ==
expectedObjectCompletions);
REQUIRE(getCompletionsFor("string", "MyObject.MyBehavior::Func(", 7) ==

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,6 @@
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ProjectScopedContainers.h"
#include "catch.hpp"
TEST_CASE("ExpressionParser2 - Benchmarks", "[common][events]") {
@@ -22,16 +21,14 @@ TEST_CASE("ExpressionParser2 - Benchmarks", "[common][events]") {
auto &layout1 = project.InsertNewLayout("Layout1", 0);
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
auto projectScopedContainers = gd::ProjectScopedContainers::MakeNewProjectScopedContainersForProjectAndLayout(project, layout1);
gd::ExpressionParser2 parser;
auto parseExpression = [&parser, &platform, &projectScopedContainers](const gd::String &expression) {
auto parseExpressionWithType = [&parser, &platform, &projectScopedContainers,
auto parseExpression = [&parser, &project, &platform, &layout1](const gd::String &expression) {
auto parseExpressionWithType = [&parser, &project, &platform, &layout1,
&expression](const gd::String &type) {
auto node = parser.ParseExpression(expression);
REQUIRE(node != nullptr);
gd::ExpressionValidator validator(platform, projectScopedContainers, type);
gd::ExpressionValidator validator(platform, project, layout1, type);
node->Visit(validator);
};

View File

@@ -17,6 +17,13 @@
using namespace gd;
namespace {
void SetupProject(gd::Project &project, gd::Platform &platform){
};
} // namespace
TEST_CASE("Layout", "[common]") {
SECTION("Find the type of a behavior in a object") {

View File

@@ -1,569 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering project refactoring
*/
#include <algorithm>
#include <stdexcept>
#include "DummyPlatform.h"
#include "GDCore/Events/Builtin/ForEachChildVariableEvent.h"
#include "GDCore/Events/Builtin/LinkEvent.h"
#include "GDCore/Events/Builtin/RepeatEvent.h"
#include "GDCore/Events/Builtin/StandardEvent.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/ExternalLayout.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/Serialization/Serializer.h"
#include "catch.hpp"
TEST_CASE("WholeProjectRefactorer::ApplyRefactoringForVariablesContainer",
"[common]") {
SECTION("Variable renamed (project, layout, object)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
gd::StandardEvent &event =
dynamic_cast<gd::StandardEvent &>(layout1.GetEvents().InsertNewEvent(
project, "BuiltinCommonInstructions::Standard"));
gd::ForEachChildVariableEvent &forEachChildVariableEvent =
dynamic_cast<gd::ForEachChildVariableEvent &>(
layout1.GetEvents().InsertNewEvent(
project, "BuiltinCommonInstructions::ForEachChildVariable"));
gd::RepeatEvent &repeatEvent =
dynamic_cast<gd::RepeatEvent &>(layout1.GetEvents().InsertNewEvent(
project, "BuiltinCommonInstructions::Repeat"));
// Declare global variables.
project.GetVariables().InsertNew("MyGlobalVariable", 0).SetValue(123);
project.GetVariables().InsertNew("MyGlobalVariable2", 0).SetValue(123);
project.GetVariables().InsertNew("SharedVariableName", 0).SetValue(123);
project.GetVariables()
.InsertNew("MyGlobalStructureVariable", 0)
.GetChild("MyChild")
.SetValue(123);
project.GetVariables()
.InsertNew("MyGlobalStructureVariable2", 0)
.GetChild("MyChild")
.SetValue(123);
// Declare variables in the scene.
layout1.GetVariables().InsertNew("MySceneVariable", 0).SetValue(123);
layout1.GetVariables().InsertNew("MySceneVariable2", 0).SetValue(123);
layout1.GetVariables().InsertNew("SharedVariableName", 0).SetValue(123);
layout1.GetVariables()
.InsertNew("MySceneStructureVariable", 0)
.GetChild("MyChild")
.SetValue(123);
layout1.GetVariables()
.InsertNew("MySceneStructureVariable2", 0)
.GetChild("MyChild")
.SetValue(123);
// Declare variables in objects.
auto &object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
object1.GetVariables().InsertNew("MyObjectVariable");
object1.GetVariables()
.InsertNew("MyObjectStructureVariable")
.GetChild("MyChild")
.SetValue(123);
auto &object2 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
object2.GetVariables().InsertNew("MyObjectVariable");
object2.GetVariables()
.InsertNew("MyObjectStructureVariable")
.GetChild("MyChild")
.SetValue(123);
// Create an event using the variables.
// clang-format off
{
gd::Instruction action;
action.SetType("MyExtension::DoSomething");
action.SetParametersCount(1);
action.SetParameter(
0,
gd::Expression(
"1 + "
"MySceneVariable + "
"MySceneVariable2 + "
"Object1.MyObjectVariable + "
"Object2.MyObjectVariable + "
"Object1.MyObjectStructureVariable.MyChild + "
"Object2.MyObjectStructureVariable.MyChild + "
"MySceneStructureVariable.MyChild + "
"MySceneStructureVariable2.MyChild + "
"MyGlobalVariable + "
"MyGlobalVariable2 + "
"MyGlobalStructureVariable.MyChild + "
"MyGlobalStructureVariable2.MyChild"));
event.GetActions().Insert(action);
}
// Expressions with "old" "scenevar", "globalvar", "objectvar":
{
gd::Instruction action;
action.SetType("MyExtension::DoSomething");
action.SetParametersCount(1);
action.SetParameter(
0,
gd::Expression(
// "objectvar" (in a free expression):
"1 + "
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object1, MyObjectVariable, Object2, MyObjectVariable) + "
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object1, MyObjectStructureVariable.MyChild, Object2, MyObjectStructureVariable.MyChild) + "
// "objectvar" (using the name of the object being called):
"Object1.GetObjectVariableAsNumber(MyObjectVariable) + "
"Object2.GetObjectVariableAsNumber(MyObjectVariable) + "
"Object1.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild) + "
"Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild) + "
"Object1.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild) + "
"Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild) + "
// "globalvar" and "scenevar":
"MyExtension::GetGlobalVariableAsNumber(MyGlobalVariable) + "
"MyExtension::GetGlobalVariableAsNumber(MyGlobalVariable2) + "
"MyExtension::GetGlobalVariableAsNumber(SharedVariableName) + "
"MyExtension::GetVariableAsNumber(MySceneVariable) + "
"MyExtension::GetVariableAsNumber(MySceneVariable2) + "
"MyExtension::GetVariableAsNumber(SharedVariableName) + "
"MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable.MyChild) + "
"MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild) + "
"MyExtension::GetVariableAsNumber(MySceneStructureVariable.MyChild) + "
"MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild) + "
"MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable.MyChild.GrandChild) + "
"MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild.GrandChild) + "
"MyExtension::GetVariableAsNumber(MySceneStructureVariable.MyChild.GrandChild) + "
"MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild.GrandChild)"));
event.GetActions().Insert(action);
}
{
gd::Instruction action;
action.SetType("MyExtension::DoSomethingWithLegacyPreScopedVariables");
action.SetParametersCount(4);
action.SetParameter(0, gd::Expression("MySceneVariable"));
action.SetParameter(1, gd::Expression("MyGlobalVariable"));
action.SetParameter(2, gd::Expression("Object1"));
action.SetParameter(3, gd::Expression("MyObjectVariable"));
event.GetActions().Insert(action);
}
{
gd::Instruction action;
action.SetType("MyExtension::DoSomethingWithLegacyPreScopedVariables");
action.SetParametersCount(4);
action.SetParameter(0, gd::Expression("SharedVariableName"));
action.SetParameter(1, gd::Expression("SharedVariableName"));
action.SetParameter(2, gd::Expression("Object2"));
action.SetParameter(3, gd::Expression("MyObjectVariable"));
event.GetActions().Insert(action);
}
forEachChildVariableEvent.SetIterableVariableName("MySceneStructureVariable");
repeatEvent.SetRepeatExpression("1 + MySceneVariable + Object1.MyObjectVariable + Object2.MyObjectVariable");
// clang-format on
// Do a copy of layout1 to ensure other scene is unchanged after the
// refactoring.
gd::Layout layout2 = layout1;
layout2.SetName("Layout2");
project.InsertLayout(layout2, 1);
gd::SerializerElement originalSerializedLayout2;
layout2.SerializeTo(originalSerializedLayout2);
// Do the changes and launch the refactoring.
project.GetVariables().ResetPersistentUuid();
layout1.GetVariables().ResetPersistentUuid();
object1.ResetPersistentUuid();
gd::SerializerElement originalSerializedProjectVariables;
project.GetVariables().SerializeTo(originalSerializedProjectVariables);
gd::SerializerElement originalSerializedLayoutVariables;
layout1.GetVariables().SerializeTo(originalSerializedLayoutVariables);
gd::SerializerElement originalSerializedObject1Variables;
object1.GetVariables().SerializeTo(originalSerializedObject1Variables);
project.GetVariables().Rename("MyGlobalVariable",
"MyRenamedGlobalVariable");
project.GetVariables().Rename("MyGlobalStructureVariable",
"MyRenamedGlobalStructureVariable");
project.GetVariables().Rename("SharedVariableName",
"RenamedGlobalVariableFromASharedName");
auto changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
project,
originalSerializedProjectVariables,
project.GetVariables());
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project,
project.GetVariables(),
changeset);
layout1.GetVariables().Rename("MySceneVariable", "MyRenamedSceneVariable");
layout1.GetVariables().Rename("MySceneStructureVariable",
"MyRenamedSceneStructureVariable");
changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
project,
originalSerializedLayoutVariables,
layout1.GetVariables());
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project,
layout1.GetVariables(),
changeset);
object1.GetVariables().Rename("MyObjectVariable",
"MyRenamedObjectVariable");
object1.GetVariables().Rename("MyObjectStructureVariable",
"MyRenamedObjectStructureVariable");
changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
project,
originalSerializedObject1Variables,
object1.GetVariables());
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project,
object1.GetVariables(),
changeset);
// Check the first layout is updated.
// clang-format off
{
// Updated direct access to variables:
REQUIRE(event.GetActions()[0].GetParameter(0).GetPlainString() ==
"1 + "
"MyRenamedSceneVariable + "
"MySceneVariable2 + "
"Object1.MyRenamedObjectVariable + "
"Object2.MyObjectVariable + "
"Object1.MyRenamedObjectStructureVariable.MyChild + "
"Object2.MyObjectStructureVariable.MyChild + "
"MyRenamedSceneStructureVariable.MyChild + "
"MySceneStructureVariable2.MyChild + "
"MyRenamedGlobalVariable + "
"MyGlobalVariable2 + "
"MyRenamedGlobalStructureVariable.MyChild + "
"MyGlobalStructureVariable2.MyChild"
);
// Updated access to variables using the legacy "pre-scoped" "scenevar",
// "globalvar" and "objectvar" parameters in expressions:
REQUIRE(event.GetActions()[1].GetParameter(0).GetPlainString() ==
"1 + "
// Multiple "objectvar" parameters in a free function:
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object1, MyRenamedObjectVariable, Object2, MyObjectVariable) + "
// Multiple "objectvar" parameters in a free function, with child
// variable:
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object1, MyRenamedObjectStructureVariable.MyChild, Object2, MyObjectStructureVariable.MyChild) + "
// Single "objectvar" from the object being accessed:
"Object1.GetObjectVariableAsNumber(MyRenamedObjectVariable) + "
"Object2.GetObjectVariableAsNumber(MyObjectVariable) + "
// Single "objectvar" from the object being accessed, with child
// variales:
"Object1.GetObjectVariableAsNumber(MyRenamedObjectStructureVariable.MyChild) + "
"Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild) + "
"Object1.GetObjectVariableAsNumber(MyRenamedObjectStructureVariable.MyChild.GrandChild) + "
"Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild) + "
// "globalvar" and "scenevar" in a free function:
"MyExtension::GetGlobalVariableAsNumber(MyRenamedGlobalVariable) + "
"MyExtension::GetGlobalVariableAsNumber(MyGlobalVariable2) + "
"MyExtension::GetGlobalVariableAsNumber(RenamedGlobalVariableFromASharedName) + "
"MyExtension::GetVariableAsNumber(MyRenamedSceneVariable) + "
"MyExtension::GetVariableAsNumber(MySceneVariable2) + "
"MyExtension::GetVariableAsNumber(SharedVariableName) + "
// "globalvar" and "scenevar" in a free function, with child
// variables:
"MyExtension::GetGlobalVariableAsNumber(MyRenamedGlobalStructureVariable.MyChild) + "
"MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild) + "
"MyExtension::GetVariableAsNumber(MyRenamedSceneStructureVariable.MyChild) + "
"MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild) + "
// "globalvar" and "scenevar" in a free function, with grand child
// variables:
"MyExtension::GetGlobalVariableAsNumber(MyRenamedGlobalStructureVariable.MyChild.GrandChild) + "
"MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild.GrandChild) + "
"MyExtension::GetVariableAsNumber(MyRenamedSceneStructureVariable.MyChild.GrandChild) + "
"MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild.GrandChild)");
// Updated "scenevar", "globalvar" and "object" parameters of an
// instruction:
REQUIRE(event.GetActions()[2].GetParameter(0).GetPlainString() ==
"MyRenamedSceneVariable");
REQUIRE(event.GetActions()[2].GetParameter(1).GetPlainString() ==
"MyRenamedGlobalVariable");
REQUIRE(event.GetActions()[2].GetParameter(2).GetPlainString() ==
"Object1");
REQUIRE(event.GetActions()[2].GetParameter(3).GetPlainString() ==
"MyRenamedObjectVariable");
// Updated "scenevar" and "globalvar" parameters of an instruction:
REQUIRE(event.GetActions()[3].GetParameter(0).GetPlainString() ==
"SharedVariableName");
REQUIRE(event.GetActions()[3].GetParameter(1).GetPlainString() ==
"RenamedGlobalVariableFromASharedName");
// Unchanged "object" and "objectvar" parameters:
REQUIRE(event.GetActions()[3].GetParameter(2).GetPlainString() ==
"Object2");
REQUIRE(event.GetActions()[3].GetParameter(3).GetPlainString() ==
"MyObjectVariable");
}
REQUIRE(forEachChildVariableEvent.GetIterableVariableName() == "MyRenamedSceneStructureVariable");
REQUIRE(repeatEvent.GetRepeatExpression() == "1 + MyRenamedSceneVariable + Object1.MyRenamedObjectVariable + Object2.MyObjectVariable");
// clang-format on
// Check the other layout is untouched.
{
gd::SerializerElement serializedLayout2;
layout2.SerializeTo(serializedLayout2);
REQUIRE(gd::Serializer::ToJSON(serializedLayout2) ==
gd::Serializer::ToJSON(originalSerializedLayout2));
}
}
SECTION("Variable removed (project, layout, object)") {
gd::Project project;
gd::Platform platform;
SetupProjectWithDummyPlatform(project, platform);
auto &layout1 = project.InsertNewLayout("Layout1", 0);
gd::StandardEvent &event =
dynamic_cast<gd::StandardEvent &>(layout1.GetEvents().InsertNewEvent(
project, "BuiltinCommonInstructions::Standard"));
// Declare global variables.
project.GetVariables().InsertNew("MyGlobalVariable", 0).SetValue(123);
project.GetVariables().InsertNew("MyGlobalVariable2", 0).SetValue(123);
project.GetVariables().InsertNew("SharedVariableName", 0).SetValue(123);
project.GetVariables()
.InsertNew("MyGlobalStructureVariable", 0)
.GetChild("MyChild")
.SetValue(123);
project.GetVariables()
.InsertNew("MyGlobalStructureVariable2", 0)
.GetChild("MyChild")
.SetValue(123);
// Declare variables in the scene.
layout1.GetVariables().InsertNew("MySceneVariable", 0).SetValue(123);
layout1.GetVariables().InsertNew("MySceneVariable2", 0).SetValue(123);
layout1.GetVariables().InsertNew("SharedVariableName", 0).SetValue(123);
layout1.GetVariables()
.InsertNew("MySceneStructureVariable", 0)
.GetChild("MyChild")
.SetValue(123);
layout1.GetVariables()
.InsertNew("MySceneStructureVariable2", 0)
.GetChild("MyChild")
.SetValue(123);
// Declare variables in objects.
auto &object1 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object1", 0);
object1.GetVariables().InsertNew("MyObjectVariable");
object1.GetVariables()
.InsertNew("MyObjectStructureVariable")
.GetChild("MyChild")
.SetValue(123);
auto &object2 =
layout1.InsertNewObject(project, "MyExtension::Sprite", "Object2", 0);
object2.GetVariables().InsertNew("MyObjectVariable");
object2.GetVariables()
.InsertNew("MyObjectStructureVariable")
.GetChild("MyChild")
.SetValue(123);
auto makeTestAction = [](const gd::String &expression) {
gd::Instruction action;
action.SetType("MyExtension::DoSomething");
action.SetParametersCount(1);
action.SetParameter(0, expression);
return action;
};
// Create an event using the variables.
// clang-format off
event.GetActions().Insert(makeTestAction("1 + MySceneVariable"));
event.GetActions().Insert(makeTestAction("1 + MySceneVariable2"));
event.GetActions().Insert(makeTestAction("1 + Object1.MyObjectVariable"));
event.GetActions().Insert(makeTestAction("1 + Object2.MyObjectVariable"));
event.GetActions().Insert(makeTestAction("1 + Object1.MyObjectStructureVariable.MyChild"));
event.GetActions().Insert(makeTestAction("1 + Object2.MyObjectStructureVariable.MyChild"));
event.GetActions().Insert(makeTestAction("1 + MySceneStructureVariable.MyChild"));
event.GetActions().Insert(makeTestAction("1 + MySceneStructureVariable2.MyChild"));
event.GetActions().Insert(makeTestAction("1 + MyGlobalVariable"));
event.GetActions().Insert(makeTestAction("1 + MyGlobalVariable2"));
event.GetActions().Insert(makeTestAction("1 + MyGlobalStructureVariable.MyChild"));
event.GetActions().Insert(makeTestAction("1 + MyGlobalStructureVariable2.MyChild"));
// Expressions with "old" "scenevar", "globalvar", "objectvar":
// "objectvar" (in a free expression):
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object1, MyObjectVariable, Object2, MyObjectVariable)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object2, MyObjectVariable, Object2, MyObjectVariable)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object1, MyObjectStructureVariable.MyChild, Object2, MyObjectStructureVariable.MyChild)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object2, MyObjectStructureVariable.MyChild, Object2, MyObjectStructureVariable.MyChild)"));
// "objectvar" (using the name of the object being called):
event.GetActions().Insert(makeTestAction("1 + Object1.GetObjectVariableAsNumber(MyObjectVariable)"));
event.GetActions().Insert(makeTestAction("1 + Object2.GetObjectVariableAsNumber(MyObjectVariable)"));
event.GetActions().Insert(makeTestAction("1 + Object1.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild)"));
event.GetActions().Insert(makeTestAction("1 + Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild)"));
event.GetActions().Insert(makeTestAction("1 + Object1.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild)"));
event.GetActions().Insert(makeTestAction("1 + Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalVariable)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalVariable2)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetGlobalVariableAsNumber(SharedVariableName)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetVariableAsNumber(MySceneVariable)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetVariableAsNumber(MySceneVariable2)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetVariableAsNumber(SharedVariableName)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable.MyChild)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetVariableAsNumber(MySceneStructureVariable.MyChild)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable.MyChild.GrandChild)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild.GrandChild)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetVariableAsNumber(MySceneStructureVariable.MyChild.GrandChild)"));
event.GetActions().Insert(makeTestAction("1 + MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild.GrandChild)"));
{
gd::Instruction action;
action.SetType("MyExtension::DoSomethingWithLegacyPreScopedVariables");
action.SetParametersCount(4);
action.SetParameter(0, gd::Expression("MySceneVariable")); // To remove
action.SetParameter(1, gd::Expression("MyGlobalVariable2"));
action.SetParameter(2, gd::Expression("Object2"));
action.SetParameter(3, gd::Expression("MyObjectVariable"));
event.GetActions().Insert(action);
}
{
gd::Instruction action;
action.SetType("MyExtension::DoSomethingWithLegacyPreScopedVariables");
action.SetParametersCount(4);
action.SetParameter(0, gd::Expression("MySceneVariable2"));
action.SetParameter(1, gd::Expression("MyGlobalVariable")); // To remove
action.SetParameter(2, gd::Expression("Object2"));
action.SetParameter(3, gd::Expression("MyObjectVariable"));
event.GetActions().Insert(action);
}
{
gd::Instruction action;
action.SetType("MyExtension::DoSomethingWithLegacyPreScopedVariables");
action.SetParametersCount(4);
action.SetParameter(0, gd::Expression("MySceneVariable2"));
action.SetParameter(1, gd::Expression("MyGlobalVariable2"));
action.SetParameter(2, gd::Expression("Object1"));
action.SetParameter(3, gd::Expression("MyObjectVariable")); // To remove
event.GetActions().Insert(action);
}
{
gd::Instruction action;
action.SetType("MyExtension::DoSomethingWithLegacyPreScopedVariables");
action.SetParametersCount(4);
action.SetParameter(0, gd::Expression("MySceneVariable2"));
action.SetParameter(1, gd::Expression("MyGlobalVariable2"));
action.SetParameter(2, gd::Expression("Object2"));
action.SetParameter(3, gd::Expression("MyObjectVariable"));
event.GetActions().Insert(action);
}
// clang-format on
// Do a copy of layout1 to ensure other scene is unchanged after the
// refactoring.
gd::Layout layout2 = layout1;
layout2.SetName("Layout2");
project.InsertLayout(layout2, 1);
gd::SerializerElement originalSerializedLayout2;
layout2.SerializeTo(originalSerializedLayout2);
// Do the changes and launch the refactoring.
project.GetVariables().ResetPersistentUuid();
layout1.GetVariables().ResetPersistentUuid();
object1.ResetPersistentUuid();
gd::SerializerElement originalSerializedProjectVariables;
project.GetVariables().SerializeTo(originalSerializedProjectVariables);
gd::SerializerElement originalSerializedLayoutVariables;
layout1.GetVariables().SerializeTo(originalSerializedLayoutVariables);
gd::SerializerElement originalSerializedObject1Variables;
object1.GetVariables().SerializeTo(originalSerializedObject1Variables);
project.GetVariables().Remove("MyGlobalVariable");
project.GetVariables().Remove("MyGlobalStructureVariable");
project.GetVariables().Remove("SharedVariableName");
auto changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
project,
originalSerializedProjectVariables,
project.GetVariables());
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project,
project.GetVariables(),
changeset);
layout1.GetVariables().Remove("MySceneVariable");
layout1.GetVariables().Remove("MySceneStructureVariable");
changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
project,
originalSerializedLayoutVariables,
layout1.GetVariables());
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project,
layout1.GetVariables(),
changeset);
object1.GetVariables().Remove("MyObjectVariable");
object1.GetVariables().Remove("MyObjectStructureVariable");
changeset = gd::WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
project,
originalSerializedObject1Variables,
object1.GetVariables());
gd::WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
project,
object1.GetVariables(),
changeset);
// Check the first layout is updated.
{
REQUIRE(event.GetActions().GetCount() == 19);
// clang-format off
// All the actions using the removed variables are gone.
REQUIRE(event.GetActions()[0].GetParameter(0).GetPlainString() == "1 + MySceneVariable2");
REQUIRE(event.GetActions()[1].GetParameter(0).GetPlainString() == "1 + Object2.MyObjectVariable");
REQUIRE(event.GetActions()[2].GetParameter(0).GetPlainString() == "1 + Object2.MyObjectStructureVariable.MyChild");
REQUIRE(event.GetActions()[3].GetParameter(0).GetPlainString() == "1 + MySceneStructureVariable2.MyChild");
REQUIRE(event.GetActions()[4].GetParameter(0).GetPlainString() == "1 + MyGlobalVariable2");
REQUIRE(event.GetActions()[5].GetParameter(0).GetPlainString() == "1 + MyGlobalStructureVariable2.MyChild");
REQUIRE(event.GetActions()[6].GetParameter(0).GetPlainString() == "1 + MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object2, MyObjectVariable, Object2, MyObjectVariable)");
REQUIRE(event.GetActions()[7].GetParameter(0).GetPlainString() == "1 + MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam(Object2, MyObjectStructureVariable.MyChild, Object2, MyObjectStructureVariable.MyChild)");
REQUIRE(event.GetActions()[8].GetParameter(0).GetPlainString() == "1 + Object2.GetObjectVariableAsNumber(MyObjectVariable)");
REQUIRE(event.GetActions()[9].GetParameter(0).GetPlainString() == "1 + Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild)");
REQUIRE(event.GetActions()[10].GetParameter(0).GetPlainString() == "1 + Object2.GetObjectVariableAsNumber(MyObjectStructureVariable.MyChild.GrandChild)");
REQUIRE(event.GetActions()[11].GetParameter(0).GetPlainString() == "1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalVariable2)");
REQUIRE(event.GetActions()[12].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(MySceneVariable2)");
REQUIRE(event.GetActions()[13].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(SharedVariableName)");
REQUIRE(event.GetActions()[14].GetParameter(0).GetPlainString() == "1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild)");
REQUIRE(event.GetActions()[15].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild)");
REQUIRE(event.GetActions()[16].GetParameter(0).GetPlainString() == "1 + MyExtension::GetGlobalVariableAsNumber(MyGlobalStructureVariable2.MyChild.GrandChild)");
REQUIRE(event.GetActions()[17].GetParameter(0).GetPlainString() == "1 + MyExtension::GetVariableAsNumber(MySceneStructureVariable2.MyChild.GrandChild)");
REQUIRE(event.GetActions()[18].GetParameter(0).GetPlainString() == "MySceneVariable2");
REQUIRE(event.GetActions()[18].GetParameter(1).GetPlainString() == "MyGlobalVariable2");
REQUIRE(event.GetActions()[18].GetParameter(2).GetPlainString() == "Object2");
REQUIRE(event.GetActions()[18].GetParameter(3).GetPlainString() == "MyObjectVariable");
// clang-format on
}
// Check the other layout is untouched.
{
gd::SerializerElement serializedLayout2;
layout2.SerializeTo(serializedLayout2);
REQUIRE(gd::Serializer::ToJSON(serializedLayout2) ==
gd::Serializer::ToJSON(originalSerializedLayout2));
}
}
}

View File

@@ -306,7 +306,7 @@ const void SetupEvents(gd::EventsList &eventList) {
action.SetParameter(
0,
gd::Expression(
"ObjectWithMyBehavior.GetObjectNumber() + ObjectWithMyBehavior.MyVariable + ObjectWithMyBehavior.MyStructureVariable.Child"));
"ObjectWithMyBehavior.GetObjectNumber()"));
event.GetActions().Insert(action);
eventList.InsertEvent(event);
}
@@ -415,13 +415,13 @@ const void SetupEvents(gd::EventsList &eventList) {
if (eventList.GetEventsCount() != BehaviorSharedPropertyAction) {
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
}
// Create an event in the layout using "MySharedProperty" action
// Create an event in the layout using "MyProperty" action
{
gd::StandardEvent event;
gd::Instruction instruction;
instruction.SetType(
"MyEventsExtension::MyEventsBasedBehavior::" +
gd::EventsBasedBehavior::GetSharedPropertyActionName("MySharedProperty"));
gd::EventsBasedBehavior::GetSharedPropertyActionName("MyProperty"));
event.GetActions().Insert(instruction);
eventList.InsertEvent(event);
}
@@ -429,13 +429,13 @@ const void SetupEvents(gd::EventsList &eventList) {
if (eventList.GetEventsCount() != BehaviorSharedPropertyCondition) {
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
}
// Create an event in the layout using "MySharedProperty" condition
// Create an event in the layout using "MyProperty" condition
{
gd::StandardEvent event;
gd::Instruction instruction;
instruction.SetType(
"MyEventsExtension::MyEventsBasedBehavior::" +
gd::EventsBasedBehavior::GetSharedPropertyConditionName("MySharedProperty"));
gd::EventsBasedBehavior::GetSharedPropertyConditionName("MyProperty"));
event.GetConditions().Insert(instruction);
eventList.InsertEvent(event);
}
@@ -443,7 +443,7 @@ const void SetupEvents(gd::EventsList &eventList) {
if (eventList.GetEventsCount() != BehaviorSharedPropertyExpression) {
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
}
// Create an event in the layout using "MySharedProperty" expression
// Create an event in the layout using "MyProperty" expression
{
gd::StandardEvent event;
gd::Instruction instruction;
@@ -452,7 +452,7 @@ const void SetupEvents(gd::EventsList &eventList) {
instruction.SetParameter(
0, gd::Expression("ObjectWithMyBehavior.MyBehavior::" +
gd::EventsBasedBehavior::GetSharedPropertyExpressionName(
"MySharedProperty") +
"MyProperty") +
"()"));
event.GetActions().Insert(instruction);
eventList.InsertEvent(event);
@@ -929,15 +929,11 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
.SetFunctionType(gd::EventsFunction::ActionWithOperator)
.SetGetterName("MyBehaviorEventsFunctionExpressionAndCondition");
// Add a property:
// Add property
eventsBasedBehavior.GetPropertyDescriptors()
.InsertNew("MyProperty", 0)
.SetType("Number");
// Add a shared property:
eventsBasedBehavior.GetSharedPropertyDescriptors()
.InsertNew("MySharedProperty", 0)
.SetType("Number");
// The same name is used for another shared property to ensure there is no name
// The same name is used for the shared property to ensure there is no name
// collision.
eventsBasedBehavior.GetSharedPropertyDescriptors()
.InsertNew("MyProperty", 0)
@@ -1072,8 +1068,6 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
auto &childObject = eventsBasedObject.InsertNewObject(
project, "MyExtension::Sprite", "ObjectWithMyBehavior", 0);
childObject.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
childObject.GetVariables().InsertNew("MyVariable");
childObject.GetVariables().InsertNew("MyStructureVariable").CastTo(gd::Variable::Structure);
auto &group = eventsBasedObject.GetObjectGroups().InsertNew("GroupWithMyBehavior");
group.AddObject(childObject.GetName());
@@ -1160,8 +1154,6 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
auto &object = layout.InsertNewObject(project, "MyExtension::Sprite",
"ObjectWithMyBehavior", 0);
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
object.GetVariables().InsertNew("MyVariable");
object.GetVariables().InsertNew("MyStructureVariable").CastTo(gd::Variable::Structure);
auto &group = layout.GetObjectGroups().InsertNew("GroupWithMyBehavior", 0);
group.AddObject("ObjectWithMyBehavior");
@@ -1463,10 +1455,10 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
REQUIRE(GetEventFirstActionFirstParameterString(eventsList->GetEvent(
FreeFunctionWithObjects)) == "RenamedObjectWithMyBehavior");
// Check object name has been renamed in expressions and in object variables.
// Check object name has been renamed in expressions.
REQUIRE(GetEventFirstActionFirstParameterString(
eventsList->GetEvent(FreeFunctionWithObjectExpression)) ==
"RenamedObjectWithMyBehavior.GetObjectNumber() + RenamedObjectWithMyBehavior.MyVariable + RenamedObjectWithMyBehavior.MyStructureVariable.Child");
"RenamedObjectWithMyBehavior.GetObjectNumber()");
}
}
}
@@ -1575,12 +1567,6 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
gd::ParameterMetadataTools::ParametersToObjectsContainer(
project, eventsFunction.GetParameters(), objectsContainer);
// Simulate a variable in ObjectWithMyBehavior, even if this is not
// supported by the editor.
auto& objectWithMyBehavior = objectsContainer.GetObject("ObjectWithMyBehavior");
objectWithMyBehavior.GetVariables().InsertNew("MyVariable");
objectWithMyBehavior.GetVariables().InsertNew("MyStructureVariable").CastTo(gd::Variable::Structure);
// Trigger the refactoring after the renaming of an object
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
project, eventsFunction, globalObjectsContainer, objectsContainer,
@@ -1593,11 +1579,11 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
eventsFunction.GetEvents().GetEvent(FreeFunctionWithObjects)) ==
"RenamedObjectWithMyBehavior");
// Check object name has been renamed in expressions and object variables.
// Check object name has been renamed in expressions.
REQUIRE(GetEventFirstActionFirstParameterString(
eventsFunction.GetEvents().GetEvent(
FreeFunctionWithObjectExpression)) ==
"RenamedObjectWithMyBehavior.GetObjectNumber() + RenamedObjectWithMyBehavior.MyVariable + RenamedObjectWithMyBehavior.MyStructureVariable.Child");
"RenamedObjectWithMyBehavior.GetObjectNumber()");
}
}
@@ -1632,10 +1618,10 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
objectFunctionEvents.GetEvent(FreeFunctionWithObjects)) ==
"RenamedObjectWithMyBehavior");
// Check object name has been renamed in expressions and object variables.
// Check object name has been renamed in expressions.
REQUIRE(GetEventFirstActionFirstParameterString(
objectFunctionEvents.GetEvent(FreeFunctionWithObjectExpression)) ==
"RenamedObjectWithMyBehavior.GetObjectNumber() + RenamedObjectWithMyBehavior.MyVariable + RenamedObjectWithMyBehavior.MyStructureVariable.Child");
"RenamedObjectWithMyBehavior.GetObjectNumber()");
}
SECTION("Object deleted (in events function)") {
@@ -1756,7 +1742,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
eventsList->GetEvent(BehaviorActionWithOperator)) ==
"MyRenamedExtension::MyEventsBasedBehavior::"
"MyBehaviorEventsFunctionActionWithOperator");
// Check if events-based behaviors properties have been renamed in
// instructions
REQUIRE(GetEventFirstActionType(
@@ -1766,7 +1752,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
REQUIRE(GetEventFirstActionType(
eventsList->GetEvent(BehaviorSharedPropertyAction)) ==
"MyRenamedExtension::MyEventsBasedBehavior::"
"SetSharedPropertyMySharedProperty");
"SetSharedPropertyMyProperty");
// Check events-based behavior methods have *not* been renamed in
// expressions
@@ -2128,7 +2114,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
REQUIRE(GetEventFirstActionType(
eventsList->GetEvent(BehaviorSharedPropertyAction)) ==
"MyEventsExtension::MyRenamedEventsBasedBehavior::"
"SetSharedPropertyMySharedProperty");
"SetSharedPropertyMyProperty");
// Check events-based behavior methods have *not* been renamed in
// expressions
@@ -2743,16 +2729,16 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
REQUIRE(GetEventFirstActionType(
eventsList->GetEvent(BehaviorSharedPropertyAction)) ==
"MyEventsExtension::MyEventsBasedBehavior::"
"SetSharedPropertyMySharedProperty");
"SetSharedPropertyMyProperty");
REQUIRE(GetEventFirstConditionType(
eventsList->GetEvent(BehaviorSharedPropertyCondition)) ==
"MyEventsExtension::MyEventsBasedBehavior::"
"SharedPropertyMySharedProperty");
"SharedPropertyMyProperty");
REQUIRE(GetEventFirstActionFirstParameterString(
eventsList->GetEvent(BehaviorSharedPropertyExpression)) ==
"ObjectWithMyBehavior.MyBehavior::SharedPropertyMySharedProperty()");
"ObjectWithMyBehavior.MyBehavior::SharedPropertyMyProperty()");
}
}
@@ -2764,11 +2750,6 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
auto &eventsBasedBehavior =
eventsExtension.GetEventsBasedBehaviors().Get("MyEventsBasedBehavior");
gd::WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
project, eventsExtension, eventsBasedBehavior, "MySharedProperty",
"MyRenamedSharedProperty");
// Also wrongly try to rename a property that is not a shared property.
gd::WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
project, eventsExtension, eventsBasedBehavior, "MyProperty",
"MyRenamedProperty");
@@ -2779,16 +2760,16 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
REQUIRE(GetEventFirstActionType(
eventsList->GetEvent(BehaviorSharedPropertyAction)) ==
"MyEventsExtension::MyEventsBasedBehavior::"
"SetSharedPropertyMyRenamedSharedProperty");
"SetSharedPropertyMyRenamedProperty");
REQUIRE(GetEventFirstConditionType(
eventsList->GetEvent(BehaviorSharedPropertyCondition)) ==
"MyEventsExtension::MyEventsBasedBehavior::"
"SharedPropertyMyRenamedSharedProperty");
"SharedPropertyMyRenamedProperty");
REQUIRE(GetEventFirstActionFirstParameterString(
eventsList->GetEvent(BehaviorSharedPropertyExpression)) ==
"ObjectWithMyBehavior.MyBehavior::SharedPropertyMyRenamedSharedProperty()");
"ObjectWithMyBehavior.MyBehavior::SharedPropertyMyRenamedProperty()");
// Ensure that the property was NOT renamed.
REQUIRE(GetEventFirstActionType(
@@ -2970,7 +2951,7 @@ TEST_CASE("WholeProjectRefactorer (FixInvalidRequiredBehaviorProperties)",
// - add the behavior "A" to an object
// Check that no behavior is added on the object for it and that there is no
// crash.
SECTION("Fix nothing if there are no missing required behavior") {
gd::Project project;
gd::Platform platform;
@@ -3751,7 +3732,7 @@ TEST_CASE("RemoveLayer", "[common]") {
layout.InsertNewLayer("My layer", 0);
otherLayout.InsertNewLayer("My layer", 0);
auto &externalLayout =
project.InsertNewExternalLayout("My external layout", 0);
auto &otherExternalLayout =
@@ -3765,7 +3746,7 @@ TEST_CASE("RemoveLayer", "[common]") {
initialInstances.InsertNewInitialInstance().SetLayer("My layer");
initialInstances.InsertNewInitialInstance().SetLayer("");
initialInstances.InsertNewInitialInstance().SetLayer("");
auto &externalInitialInstances = externalLayout.GetInitialInstances();
externalInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
externalInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
@@ -3808,7 +3789,7 @@ TEST_CASE("MergeLayers", "[common]") {
layout.InsertNewLayer("My layer", 0);
otherLayout.InsertNewLayer("My layer", 0);
auto &externalLayout =
project.InsertNewExternalLayout("My external layout", 0);
auto &otherExternalLayout =
@@ -3823,7 +3804,7 @@ TEST_CASE("MergeLayers", "[common]") {
initialInstances.InsertNewInitialInstance().SetLayer("");
initialInstances.InsertNewInitialInstance().SetLayer("");
initialInstances.InsertNewInitialInstance().SetLayer("My other layer");
auto &externalInitialInstances = externalLayout.GetInitialInstances();
externalInitialInstances.InsertNewInitialInstance().SetLayer("My layer");
externalInitialInstances.InsertNewInitialInstance().SetLayer("My layer");

View File

@@ -144,40 +144,6 @@ namespace gdjs {
return this._z;
}
/**
* Get the Z position of the rendered object.
*
* For most objects, this will returns the same value as getZ(). But if the
* object has an origin that is not the same as the point (0,0,0) of the
* object displayed, getDrawableZ will differ.
*
* @return The Z position of the rendered object.
*/
getDrawableZ(): float {
return this.getZ();
}
/**
* Return the Z position of the object center, **relative to the object Z
* position** (`getDrawableX`).
*
* Use `getCenterZInScene` to get the position of the center in the scene.
*
* @return the Z position of the object center, relative to
* `getDrawableZ()`.
*/
getCenterZ(): float {
return this.getDepth() / 2;
}
getCenterZInScene(): float {
return this.getDrawableZ() + this.getCenterZ();
}
setCenterZInScene(z: float): void {
this.setZ(z + this._z - (this.getDrawableZ() + this.getCenterZ()));
}
setAngle(angle: float): void {
super.setAngle(angle);
this.getRenderer().updateRotation();

View File

@@ -15,17 +15,6 @@ namespace gdjs {
*/
getZ(): float;
/**
* Return the Z position of the object center, **relative to the scene origin**.
*/
getCenterZInScene(): float;
/**
* Change the object center Z position in the scene.
* @param z The new Z position of the center in the scene.
*/
setCenterZInScene(z: float): void;
/**
* Set the object rotation on the X axis.
*
@@ -143,14 +132,6 @@ namespace gdjs {
return this.object.getZ();
}
getCenterZInScene(): number {
return this.object.getCenterZInScene();
}
setCenterZInScene(z: number): void {
this.object.setCenterZInScene(z);
}
setRotationX(angle: float): void {
this.object.setRotationX(angle);
}

View File

@@ -67,22 +67,6 @@ module.exports = {
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setZ')
.setGetter('getZ');
base3D
.addExpressionAndConditionAndAction(
'number',
'CenterZ',
_('Center Z position'),
_('the Z position of the center of rotation'),
_('the Z position of the center'),
_('Position/Center'),
'res/conditions/3d_box.svg'
)
.addParameter('object', _('3D object'))
.addParameter('behavior', _('Behavior'), 'Base3DBehavior')
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
.setFunctionName('setCenterZInScene')
.setGetter('getCenterZInScene');
base3D
.addExpressionAndConditionAndAction(

View File

@@ -298,11 +298,6 @@ namespace gdjs {
return this.getHeight() * centerPoint[1];
}
getCenterZ(): float {
const centerPoint = this._renderer.getCenterPoint();
return this.getDepth() * centerPoint[2];
}
getDrawableX(): float {
const originPoint = this._renderer.getOriginPoint();
return this.getX() - this.getWidth() * originPoint[0];
@@ -312,11 +307,6 @@ namespace gdjs {
const originPoint = this._renderer.getOriginPoint();
return this.getY() - this.getHeight() * originPoint[1];
}
getDrawableZ(): float {
const originPoint = this._renderer.getOriginPoint();
return this.getZ() - this.getDepth() * originPoint[2];
}
}
export namespace Model3DRuntimeObject {

View File

@@ -176,7 +176,7 @@ module.exports = {
)
.setCategoryFullName(_('Text'))
.addDefaultBehavior('EffectCapability::EffectBehavior')
.addDefaultBehavior('OpacityCapability::OpacityBehavior');
.addDefaultBehavior("OpacityCapability::OpacityBehavior");
/**
* Utility function to add both a setter and a getter to a property from a list.
@@ -398,7 +398,7 @@ module.exports = {
conditionDescription: _('Check the current text alignment.'),
conditionSentence: _('The text alignment of _PARAM0_ is _PARAM1_'),
actionDescription: _('Change the alignment of the text.'),
actionSentence: _('text alignment'),
actionSentence: _('Set text alignment of _PARAM0_ to _PARAM1_'),
expressionLabel: _('Get the text alignment'),
expressionDescription: _('Get the text alignment'),
},

View File

@@ -1,10 +1,12 @@
declare var MultiStyleText: any;
namespace gdjs {
/**
* The PIXI.js renderer for the BBCode Text runtime object.
*/
export class BBTextRuntimeObjectPixiRenderer {
_object: gdjs.BBTextRuntimeObject;
_pixiObject: MultiStyleText;
_pixiObject: any;
/**
* @param runtimeObject The object to render
@@ -16,24 +18,32 @@ namespace gdjs {
) {
this._object = runtimeObject;
this._pixiObject = new MultiStyleText(runtimeObject._text, {
default: {
fontFamily: instanceContainer
.getGame()
.getFontManager()
.getFontFamily(runtimeObject._fontFamily),
fontSize: runtimeObject._fontSize + 'px',
fill: gdjs.rgbToHexNumber(
runtimeObject._color[0],
runtimeObject._color[1],
runtimeObject._color[2]
),
tagStyle: 'bbcode',
wordWrap: runtimeObject._wordWrap,
wordWrapWidth: runtimeObject._wrappingWidth,
align: runtimeObject._align as PIXI.TextStyleAlign | undefined,
},
});
// Load (or reset) the text
if (this._pixiObject === undefined) {
this._pixiObject = new MultiStyleText(runtimeObject._text, {
default: {
fontFamily: instanceContainer
.getGame()
.getFontManager()
.getFontFamily(runtimeObject._fontFamily),
fontSize: runtimeObject._fontSize + 'px',
fill: gdjs.rgbToHexNumber(
runtimeObject._color[0],
runtimeObject._color[1],
runtimeObject._color[2]
),
tagStyle: 'bbcode',
wordWrap: runtimeObject._wordWrap,
wordWrapWidth: runtimeObject._wrappingWidth,
align: runtimeObject._align,
},
});
} else {
this.updateColor();
this.updateAlignment();
this.updateFontFamily();
this.updateFontSize();
}
instanceContainer
.getLayer('')
.getRenderer()
@@ -54,14 +64,12 @@ namespace gdjs {
}
updateWordWrap(): void {
//@ts-ignore Private member usage.
this._pixiObject._style.wordWrap = this._object._wordWrap;
this._pixiObject.dirty = true;
this.updatePosition();
}
updateWrappingWidth(): void {
//@ts-ignore Private member usage.
this._pixiObject._style.wordWrapWidth = this._object._wrappingWidth;
this._pixiObject.dirty = true;
this.updatePosition();
@@ -73,7 +81,6 @@ namespace gdjs {
}
updateColor(): void {
//@ts-ignore Private member usage.
this._pixiObject.textStyles.default.fill = gdjs.rgbToHexNumber(
this._object._color[0],
this._object._color[1],
@@ -83,13 +90,11 @@ namespace gdjs {
}
updateAlignment(): void {
//@ts-ignore Private member usage.
this._pixiObject._style.align = this._object._align;
this._pixiObject.dirty = true;
}
updateFontFamily(): void {
//@ts-ignore Private member usage.
this._pixiObject.textStyles.default.fontFamily = this._object
.getInstanceContainer()
.getGame()
@@ -99,7 +104,6 @@ namespace gdjs {
}
updateFontSize(): void {
//@ts-ignore Private member usage.
this._pixiObject.textStyles.default.fontSize =
this._object._fontSize + 'px';
this._pixiObject.dirty = true;

View File

@@ -35,9 +35,6 @@ let text = new MultiStyleText("Let's make some <ml>multiline</ml>\nand <ms>multi
## Build instructions
The library is no longer maintain and need this fix to work with Pixi 7:
- [Fix empty color attribute errors with Pixi 7](https://github.com/D8H/pixi-multistyle-text/pull/1)
```bash
yarn install
yarn build

View File

@@ -1,45 +0,0 @@
declare interface TextStyleExtended extends Partial<PIXI.ITextStyle> {
valign?: 'top' | 'middle' | 'bottom' | 'baseline' | number;
debug?: boolean;
tagStyle?: 'xml' | 'bbcode';
}
declare interface TextStyleSet {
[key: string]: TextStyleExtended;
}
declare interface MstDebugOptions {
spans: {
enabled?: boolean;
baseline?: string;
top?: string;
bottom?: string;
bounding?: string;
text?: boolean;
};
objects: {
enabled?: boolean;
bounding?: string;
text?: boolean;
};
}
declare class MultiStyleText extends PIXI.Text {
private static DEFAULT_TAG_STYLE;
static debugOptions: MstDebugOptions;
private textStyles;
private hitboxes;
constructor(text: string, styles: TextStyleSet);
private handleInteraction;
set styles(styles: TextStyleSet);
setTagStyle(tag: string, style: TextStyleExtended): void;
deleteTagStyle(tag: string): void;
private getTagRegex;
private getPropertyRegex;
private getBBcodePropertyRegex;
private _getTextDataPerLine;
private getFontString;
private createTextData;
private getDropShadowPadding;
private withPrivateMembers;
updateText(): void;
protected wordWrap(text: string): string;
private assign;
}

File diff suppressed because one or more lines are too long

View File

@@ -737,9 +737,8 @@ module.exports = {
RenderedBitmapTextInstance.prototype.onRemovedFromScene = function () {
RenderedInstance.prototype.onRemovedFromScene.call(this);
const fontName = this._pixiObject.fontName;
releaseBitmapFont(this._pixiObject.fontName);
this._pixiObject.destroy();
releaseBitmapFont(fontName);
};
/**

View File

@@ -1,4 +1,6 @@
namespace gdjs {
import PIXI = GlobalPIXIModule.PIXI;
/**
* The PIXI.js renderer for the Bitmap Text runtime object.
*/

View File

@@ -1,15 +1,17 @@
namespace gdjs {
import PIXI = GlobalPIXIModule.PIXI;
gdjs.PixiFiltersTools.registerFilterCreator(
'BlackAndWhite',
new (class extends gdjs.PixiFiltersTools.PixiFilterCreator {
makePIXIFilter(target, effectData) {
const colorMatrix = new PIXI.ColorMatrixFilter();
const colorMatrix = new PIXI.filters.ColorMatrixFilter();
colorMatrix.blackAndWhite(false);
return colorMatrix;
}
updatePreRender(filter, target) {}
updateDoubleParameter(filter, parameterName, value) {
const colorMatrix = (filter as unknown) as PIXI.ColorMatrixFilter;
// @ts-ignore - unsure why PIXI.filters is not recognised.
const colorMatrix = (filter as unknown) as PIXI.filters.ColorMatrixFilter;
if (parameterName !== 'opacity') {
return;
}

View File

@@ -1,14 +1,16 @@
namespace gdjs {
import PIXI = GlobalPIXIModule.PIXI;
gdjs.PixiFiltersTools.registerFilterCreator(
'BlendingMode',
new (class extends gdjs.PixiFiltersTools.PixiFilterCreator {
makePIXIFilter(target, effectData) {
const blendingModeFilter = new PIXI.AlphaFilter();
const blendingModeFilter = new PIXI.filters.AlphaFilter();
return blendingModeFilter;
}
updatePreRender(filter, target) {}
updateDoubleParameter(filter, parameterName, value) {
const blendingModeFilter = (filter as unknown) as PIXI.AlphaFilter;
// @ts-ignore - unsure why PIXI.filters is not recognised.
const blendingModeFilter = (filter as unknown) as PIXI.filters.AlphaFilter;
if (parameterName === 'alpha') {
blendingModeFilter.alpha = value;
} else if (parameterName === 'blendmode') {

View File

@@ -1,9 +1,10 @@
namespace gdjs {
import PIXI = GlobalPIXIModule.PIXI;
gdjs.PixiFiltersTools.registerFilterCreator(
'Blur',
new (class extends gdjs.PixiFiltersTools.PixiFilterCreator {
makePIXIFilter(target, effectData) {
const blur = new PIXI.BlurFilter();
const blur = new PIXI.filters.BlurFilter();
return blur;
}
updatePreRender(filter, target) {}

Some files were not shown because too many files have changed in this diff Show More