mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
2 Commits
v5.0.139
...
refactor/p
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ac97470140 | ||
![]() |
bde4e9254d |
8
.github/ISSUE_TEMPLATE/--feature-request.md
vendored
8
.github/ISSUE_TEMPLATE/--feature-request.md
vendored
@@ -10,11 +10,11 @@ assignees: ''
|
||||
|
||||
BEFORE opening a new feature request, please make sure that you:
|
||||
|
||||
- Understand the implications of your feature with the help of [the Forum](https://forum.gdevelop.io/c/gdevelop-general/feature-requests/35), OR
|
||||
- Peer-reviewed it with other users on Discord,
|
||||
- Consider commenting on the [Feature Request Forum](https://forum.gdevelop.io/c/gdevelop-general/feature-requests/35) if something is important for you
|
||||
- Discussed it on the discord or the forum,
|
||||
- There is not already a suggestion about it in the issues or in the roadmap: https://trello.com/b/qf0lM7k8/gdevelop-roadmap
|
||||
- Consider commenting on the roadmap if something is important for you
|
||||
|
||||
AFTER opening the feature request, the issue will be closed by a maintainer (@4ian or someone else) and a card will be added in [the public roadmap](https://trello.com/b/qf0lM7k8/gdevelop-ideas-box) if it's relevant and does not exist yet :)
|
||||
AFTER opening the feature request, the issue will be closed by a maintainer (@4ian or someone else) and a card will be added in the roadmap if it's relevant and does not exist yet :)
|
||||
|
||||
## Description
|
||||
|
||||
|
6
.github/ISSUE_TEMPLATE/config.yml
vendored
6
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -4,14 +4,14 @@ contact_links:
|
||||
url: https://discord.gg/rjdYHvj
|
||||
about: Discuss on the forum or on the Discord to get help creating a game or identifying a bug.
|
||||
- name: GDevelop Forums
|
||||
url: https://forum.gdevelop.io
|
||||
url: https://forum.gdevelop-app.com
|
||||
about: You can also discuss game creation, new feature requests and bugs on the forum.
|
||||
- name: GDevelop Roadmap
|
||||
url: https://trello.com/b/qf0lM7k8/gdevelop-roadmap
|
||||
about: Look at the roadmap and vote on features that you want to see in GDevelop.
|
||||
- name: Submit a new game example that you created
|
||||
url: https://github.com/GDevelopApp/GDevelop-examples/issues/new/choose
|
||||
about: You can submit a game that you made to be added to examples in the "GDevelop-examples" repository
|
||||
about: You can submit a game that you made to be added to examples in the "GDevelop-examples" repository
|
||||
- name: Submit a new game extension that you created
|
||||
url: https://github.com/4ian/GDevelop-extensions/issues/new/choose
|
||||
about: You can submit an extension that you made in the "GDevelop-extensions" repository
|
||||
about: You can submit an extension that you made in the "GDevelop-extensions" repository
|
||||
|
2
.github/workflows/issues.yml
vendored
2
.github/workflows/issues.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
type: "body"
|
||||
regex: ".*Scroll down to '\\.\\.\\.\\.'.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any steps to reproduce the bug.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop.io/), the Discord chat or [read the documentation](https://wiki.gdevelop.io/gdevelop5/start) to learn more about GDevelop. Thanks!"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any steps to reproduce the bug.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop-app.com/), the Discord chat or [read the documentation](https://wiki.gdevelop.io/gdevelop5/start) to learn more about GDevelop. Thanks!"
|
||||
- name: Autoclose known beta 105 web-app update bug
|
||||
uses: arkon/issue-closer-action@v1.1
|
||||
with:
|
||||
|
@@ -23,9 +23,8 @@ vector<gd::String> CommentEvent::GetAllSearchableStrings() const {
|
||||
|
||||
bool CommentEvent::ReplaceAllSearchableStrings(
|
||||
std::vector<gd::String> newSearchableString) {
|
||||
if (newSearchableString[0] == com1) return false;
|
||||
SetComment(newSearchableString[0]);
|
||||
return true;
|
||||
return newSearchableString[0] == com1;
|
||||
}
|
||||
|
||||
void CommentEvent::SerializeTo(SerializerElement &element) const {
|
||||
|
@@ -53,10 +53,8 @@ void ForEachChildVariableEvent::SerializeTo(SerializerElement& element) const {
|
||||
conditions, element.AddChild("conditions"));
|
||||
gd::EventsListSerialization::SerializeInstructionsTo(
|
||||
actions, element.AddChild("actions"));
|
||||
|
||||
if (!events.IsEmpty())
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
}
|
||||
|
||||
void ForEachChildVariableEvent::UnserializeFrom(gd::Project& project,
|
||||
@@ -68,12 +66,8 @@ void ForEachChildVariableEvent::UnserializeFrom(gd::Project& project,
|
||||
project, conditions, element.GetChild("conditions", 0, "Conditions"));
|
||||
gd::EventsListSerialization::UnserializeInstructionsFrom(
|
||||
project, actions, element.GetChild("actions", 0, "Actions"));
|
||||
|
||||
events.Clear();
|
||||
if (element.HasChild("events", "Events")) {
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -74,10 +74,8 @@ void ForEachEvent::SerializeTo(SerializerElement& element) const {
|
||||
conditions, element.AddChild("conditions"));
|
||||
gd::EventsListSerialization::SerializeInstructionsTo(
|
||||
actions, element.AddChild("actions"));
|
||||
|
||||
if (!events.IsEmpty())
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
}
|
||||
|
||||
void ForEachEvent::UnserializeFrom(gd::Project& project,
|
||||
@@ -88,12 +86,8 @@ void ForEachEvent::UnserializeFrom(gd::Project& project,
|
||||
project, conditions, element.GetChild("conditions", 0, "Conditions"));
|
||||
gd::EventsListSerialization::UnserializeInstructionsFrom(
|
||||
project, actions, element.GetChild("actions", 0, "Actions"));
|
||||
|
||||
events.Clear();
|
||||
if (element.HasChild("events", "Events")) {
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -29,9 +29,8 @@ vector<gd::String> GroupEvent::GetAllSearchableStrings() const {
|
||||
|
||||
bool GroupEvent::ReplaceAllSearchableStrings(
|
||||
std::vector<gd::String> newSearchableString) {
|
||||
if (newSearchableString[0] == name) return false;
|
||||
SetName(newSearchableString[0]);
|
||||
return true;
|
||||
return newSearchableString[0] == name;
|
||||
}
|
||||
|
||||
void GroupEvent::SerializeTo(SerializerElement& element) const {
|
||||
|
@@ -75,10 +75,8 @@ void RepeatEvent::SerializeTo(SerializerElement& element) const {
|
||||
conditions, element.AddChild("conditions"));
|
||||
gd::EventsListSerialization::SerializeInstructionsTo(
|
||||
actions, element.AddChild("actions"));
|
||||
|
||||
if (!events.IsEmpty())
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
}
|
||||
|
||||
void RepeatEvent::UnserializeFrom(gd::Project& project,
|
||||
@@ -91,12 +89,8 @@ void RepeatEvent::UnserializeFrom(gd::Project& project,
|
||||
project, conditions, element.GetChild("conditions", 0, "Conditions"));
|
||||
gd::EventsListSerialization::UnserializeInstructionsFrom(
|
||||
project, actions, element.GetChild("actions", 0, "Actions"));
|
||||
|
||||
events.Clear();
|
||||
if (element.HasChild("events", "Events")) {
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -53,10 +53,8 @@ void StandardEvent::SerializeTo(SerializerElement& element) const {
|
||||
conditions, element.AddChild("conditions"));
|
||||
gd::EventsListSerialization::SerializeInstructionsTo(
|
||||
actions, element.AddChild("actions"));
|
||||
|
||||
if (!events.IsEmpty())
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
}
|
||||
|
||||
void StandardEvent::UnserializeFrom(gd::Project& project,
|
||||
|
@@ -52,10 +52,8 @@ void WhileEvent::SerializeTo(SerializerElement& element) const {
|
||||
conditions, element.AddChild("conditions"));
|
||||
gd::EventsListSerialization::SerializeInstructionsTo(
|
||||
actions, element.AddChild("actions"));
|
||||
|
||||
if (!events.IsEmpty())
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
}
|
||||
|
||||
void WhileEvent::UnserializeFrom(gd::Project& project,
|
||||
@@ -70,12 +68,8 @@ void WhileEvent::UnserializeFrom(gd::Project& project,
|
||||
project, conditions, element.GetChild("conditions", 0, "Conditions"));
|
||||
gd::EventsListSerialization::UnserializeInstructionsFrom(
|
||||
project, actions, element.GetChild("actions", 0, "Actions"));
|
||||
|
||||
events.Clear();
|
||||
if (element.HasChild("events", "Events")) {
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -468,14 +468,6 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
action, *this, context);
|
||||
}
|
||||
|
||||
// Get the correct function name depending on whether it should be async or
|
||||
// not.
|
||||
const gd::String& functionCallName =
|
||||
instrInfos.IsAsync() &&
|
||||
(!instrInfos.IsOptionallyAsync() || action.IsAwaited())
|
||||
? instrInfos.codeExtraInformation.asyncFunctionCallName
|
||||
: instrInfos.codeExtraInformation.functionCallName;
|
||||
|
||||
// Be sure there is no lack of parameter.
|
||||
while (action.GetParameters().size() < instrInfos.parameters.size()) {
|
||||
vector<gd::Expression> parameters = action.GetParameters();
|
||||
@@ -530,7 +522,6 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
action.GetParameters(), instrInfos.parameters, context);
|
||||
actionCode += GenerateObjectAction(realObjects[i],
|
||||
objInfo,
|
||||
functionCallName,
|
||||
arguments,
|
||||
instrInfos,
|
||||
context,
|
||||
@@ -565,7 +556,6 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
GenerateBehaviorAction(realObjects[i],
|
||||
action.GetParameter(1).GetPlainString(),
|
||||
autoInfo,
|
||||
functionCallName,
|
||||
arguments,
|
||||
instrInfos,
|
||||
context,
|
||||
@@ -577,11 +567,8 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
} else {
|
||||
vector<gd::String> arguments = GenerateParametersCodes(
|
||||
action.GetParameters(), instrInfos.parameters, context);
|
||||
actionCode += GenerateFreeAction(functionCallName,
|
||||
arguments,
|
||||
instrInfos,
|
||||
context,
|
||||
optionalAsyncCallbackName);
|
||||
actionCode +=
|
||||
GenerateFreeAction(arguments, instrInfos, context, optionalAsyncCallbackName);
|
||||
}
|
||||
|
||||
return actionCode;
|
||||
@@ -671,7 +658,7 @@ gd::String EventsCodeGenerator::GenerateActionsListCode(
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
const gd::Expression& parameter,
|
||||
const gd::String& parameter,
|
||||
const gd::ParameterMetadata& metadata,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& lastObjectName,
|
||||
@@ -681,21 +668,19 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
|
||||
if (ParameterMetadata::IsExpression("number", metadata.type)) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, "number", parameter, lastObjectName);
|
||||
*this, context, "number", parameter);
|
||||
} else if (ParameterMetadata::IsExpression("string", metadata.type)) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, "string", parameter, lastObjectName);
|
||||
*this, context, "string", parameter);
|
||||
} else if (ParameterMetadata::IsExpression("variable", metadata.type)) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, metadata.type, parameter, lastObjectName);
|
||||
} else if (ParameterMetadata::IsObject(metadata.type)) {
|
||||
// It would be possible to run a gd::ExpressionCodeGenerator if later
|
||||
// objects can have nested objects, or function returning objects.
|
||||
argOutput =
|
||||
GenerateObject(parameter.GetPlainString(), metadata.type, context);
|
||||
argOutput = GenerateObject(parameter, metadata.type, context);
|
||||
} else if (metadata.type == "relationalOperator") {
|
||||
auto parameterString = parameter.GetPlainString();
|
||||
argOutput += parameterString == "=" ? "==" : parameterString;
|
||||
argOutput += parameter == "=" ? "==" : parameter;
|
||||
if (argOutput != "==" && argOutput != "<" && argOutput != ">" &&
|
||||
argOutput != "<=" && argOutput != ">=" && argOutput != "!=") {
|
||||
cout << "Warning: Bad relational operator: Set to == by default." << endl;
|
||||
@@ -704,7 +689,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
|
||||
argOutput = "\"" + argOutput + "\"";
|
||||
} else if (metadata.type == "operator") {
|
||||
argOutput += parameter.GetPlainString();
|
||||
argOutput += parameter;
|
||||
if (argOutput != "=" && argOutput != "+" && argOutput != "-" &&
|
||||
argOutput != "/" && argOutput != "*") {
|
||||
cout << "Warning: Bad operator: Set to = by default." << endl;
|
||||
@@ -713,9 +698,9 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
|
||||
argOutput = "\"" + argOutput + "\"";
|
||||
} else if (ParameterMetadata::IsBehavior(metadata.type)) {
|
||||
argOutput = GenerateGetBehaviorNameCode(parameter.GetPlainString());
|
||||
argOutput = GenerateGetBehaviorNameCode(parameter);
|
||||
} else if (metadata.type == "key") {
|
||||
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
|
||||
argOutput = "\"" + ConvertToString(parameter) + "\"";
|
||||
} else if (metadata.type == "audioResource" ||
|
||||
metadata.type == "bitmapFontResource" ||
|
||||
metadata.type == "fontResource" ||
|
||||
@@ -725,20 +710,16 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
// Deprecated, old parameter names:
|
||||
metadata.type == "password" || metadata.type == "musicfile" ||
|
||||
metadata.type == "soundfile" || metadata.type == "police") {
|
||||
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
|
||||
argOutput = "\"" + ConvertToString(parameter) + "\"";
|
||||
} else if (metadata.type == "mouse") {
|
||||
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
|
||||
argOutput = "\"" + ConvertToString(parameter) + "\"";
|
||||
} else if (metadata.type == "yesorno") {
|
||||
auto parameterString = parameter.GetPlainString();
|
||||
argOutput += (parameterString == "yes" || parameterString == "oui")
|
||||
? GenerateTrue()
|
||||
: GenerateFalse();
|
||||
argOutput += (parameter == "yes" || parameter == "oui") ? GenerateTrue()
|
||||
: GenerateFalse();
|
||||
} else if (metadata.type == "trueorfalse") {
|
||||
auto parameterString = parameter.GetPlainString();
|
||||
// This is duplicated in AdvancedExtension.cpp for GDJS
|
||||
argOutput += (parameterString == "True" || parameterString == "Vrai")
|
||||
? GenerateTrue()
|
||||
: GenerateFalse();
|
||||
argOutput += (parameter == "True" || parameter == "Vrai") ? GenerateTrue()
|
||||
: GenerateFalse();
|
||||
}
|
||||
// Code only parameter type
|
||||
else if (metadata.type == "inlineCode") {
|
||||
@@ -757,7 +738,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
if (!metadata.type.empty())
|
||||
cout << "Warning: Unknown type of parameter \"" << metadata.type
|
||||
<< "\"." << std::endl;
|
||||
argOutput += "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
|
||||
argOutput += "\"" + ConvertToString(parameter) + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,7 +758,7 @@ vector<gd::String> EventsCodeGenerator::GenerateParametersCodes(
|
||||
parametersInfo,
|
||||
[this, &context, &supplementaryParametersTypes, &arguments](
|
||||
const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
const gd::String& parameterValue,
|
||||
const gd::String& lastObjectName) {
|
||||
gd::String argOutput =
|
||||
GenerateParameterCodes(parameterValue,
|
||||
@@ -1098,7 +1079,6 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateFreeAction(
|
||||
const gd::String& functionCallName,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
@@ -1112,21 +1092,21 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
|
||||
call = GenerateOperatorCall(
|
||||
instrInfos,
|
||||
arguments,
|
||||
functionCallName,
|
||||
instrInfos.codeExtraInformation.functionCallName,
|
||||
instrInfos.codeExtraInformation.optionalAssociatedInstruction);
|
||||
else if (instrInfos.codeExtraInformation.accessType ==
|
||||
gd::InstructionMetadata::ExtraInformation::Mutators)
|
||||
call =
|
||||
GenerateMutatorCall(instrInfos,
|
||||
arguments,
|
||||
functionCallName);
|
||||
instrInfos.codeExtraInformation.functionCallName);
|
||||
else
|
||||
call = GenerateCompoundOperatorCall(
|
||||
instrInfos,
|
||||
arguments,
|
||||
functionCallName);
|
||||
instrInfos.codeExtraInformation.functionCallName);
|
||||
} else {
|
||||
call = functionCallName + "(" +
|
||||
call = instrInfos.codeExtraInformation.functionCallName + "(" +
|
||||
GenerateArgumentsList(arguments) + ")";
|
||||
}
|
||||
|
||||
@@ -1140,7 +1120,6 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
|
||||
gd::String EventsCodeGenerator::GenerateObjectAction(
|
||||
const gd::String& objectName,
|
||||
const gd::ObjectMetadata& objInfo,
|
||||
const gd::String& functionCallName,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
@@ -1154,25 +1133,27 @@ gd::String EventsCodeGenerator::GenerateObjectAction(
|
||||
call = GenerateOperatorCall(
|
||||
instrInfos,
|
||||
arguments,
|
||||
functionCallName,
|
||||
instrInfos.codeExtraInformation.functionCallName,
|
||||
instrInfos.codeExtraInformation.optionalAssociatedInstruction,
|
||||
2);
|
||||
else
|
||||
call = GenerateCompoundOperatorCall(
|
||||
instrInfos, arguments, functionCallName, 2);
|
||||
instrInfos,
|
||||
arguments,
|
||||
instrInfos.codeExtraInformation.functionCallName,
|
||||
2);
|
||||
|
||||
return "For each picked object \"" + objectName + "\", call " + call +
|
||||
".\n";
|
||||
} else {
|
||||
gd::String argumentsStr = GenerateArgumentsList(arguments, 1);
|
||||
|
||||
call = functionCallName + "(" + argumentsStr + ")";
|
||||
call = instrInfos.codeExtraInformation.functionCallName + "(" +
|
||||
argumentsStr + ")";
|
||||
|
||||
return "For each picked object \"" + objectName + "\", call " + call + "(" +
|
||||
argumentsStr + ")" +
|
||||
(optionalAsyncCallbackName.empty()
|
||||
? ""
|
||||
: (", then call" + optionalAsyncCallbackName)) +
|
||||
(optionalAsyncCallbackName.empty() ? "" : (", then call" + optionalAsyncCallbackName)) +
|
||||
".\n";
|
||||
}
|
||||
}
|
||||
@@ -1181,7 +1162,6 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
|
||||
const gd::String& objectName,
|
||||
const gd::String& behaviorName,
|
||||
const gd::BehaviorMetadata& autoInfo,
|
||||
const gd::String& functionCallName,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
@@ -1195,28 +1175,26 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
|
||||
call = GenerateOperatorCall(
|
||||
instrInfos,
|
||||
arguments,
|
||||
functionCallName,
|
||||
instrInfos.codeExtraInformation.functionCallName,
|
||||
instrInfos.codeExtraInformation.optionalAssociatedInstruction,
|
||||
2);
|
||||
else
|
||||
call = GenerateCompoundOperatorCall(
|
||||
instrInfos,
|
||||
arguments,
|
||||
functionCallName,
|
||||
instrInfos.codeExtraInformation.functionCallName,
|
||||
2);
|
||||
return "For each picked object \"" + objectName + "\", call " + call +
|
||||
" for behavior \"" + behaviorName + "\".\n";
|
||||
} else {
|
||||
gd::String argumentsStr = GenerateArgumentsList(arguments, 2);
|
||||
|
||||
call = functionCallName + "(" +
|
||||
call = instrInfos.codeExtraInformation.functionCallName + "(" +
|
||||
argumentsStr + ")";
|
||||
|
||||
return "For each picked object \"" + objectName + "\", call " + call + "(" +
|
||||
argumentsStr + ")" + " for behavior \"" + behaviorName + "\"" +
|
||||
(optionalAsyncCallbackName.empty()
|
||||
? ""
|
||||
: (", then call" + optionalAsyncCallbackName)) +
|
||||
(optionalAsyncCallbackName.empty() ? "" : (", then call" + optionalAsyncCallbackName)) +
|
||||
".\n";
|
||||
}
|
||||
}
|
||||
@@ -1265,7 +1243,7 @@ gd::String EventsCodeGenerator::GenerateArgumentsList(
|
||||
return argumentsStr;
|
||||
}
|
||||
|
||||
EventsCodeGenerator::EventsCodeGenerator(const gd::Project& project_,
|
||||
EventsCodeGenerator::EventsCodeGenerator(gd::Project& project_,
|
||||
const gd::Layout& layout,
|
||||
const gd::Platform& platform_)
|
||||
: platform(platform_),
|
||||
@@ -1282,7 +1260,7 @@ EventsCodeGenerator::EventsCodeGenerator(const gd::Project& project_,
|
||||
|
||||
EventsCodeGenerator::EventsCodeGenerator(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ObjectsContainer& globalObjectsAndGroups_,
|
||||
gd::ObjectsContainer& globalObjectsAndGroups_,
|
||||
const gd::ObjectsContainer& objectsAndGroups_)
|
||||
: platform(platform_),
|
||||
globalObjectsAndGroups(globalObjectsAndGroups_),
|
||||
|
@@ -48,7 +48,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
* \brief Construct a code generator for the specified
|
||||
* platform/project/layout.
|
||||
*/
|
||||
EventsCodeGenerator(const gd::Project& project_,
|
||||
EventsCodeGenerator(gd::Project& project_,
|
||||
const gd::Layout& layout,
|
||||
const gd::Platform& platform_);
|
||||
|
||||
@@ -57,7 +57,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
* objects/groups and platform
|
||||
*/
|
||||
EventsCodeGenerator(const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& globalObjectsAndGroups_,
|
||||
gd::ObjectsContainer& globalObjectsAndGroups_,
|
||||
const gd::ObjectsContainer& objectsAndGroups_);
|
||||
virtual ~EventsCodeGenerator(){};
|
||||
|
||||
@@ -154,10 +154,9 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
* \param context Context used for generation
|
||||
* \return Code
|
||||
*/
|
||||
gd::String GenerateActionCode(
|
||||
gd::Instruction& action,
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName = "");
|
||||
gd::String GenerateActionCode(gd::Instruction& action,
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& optionalAsyncCallbackName = "");
|
||||
|
||||
struct CallbackDescriptor {
|
||||
CallbackDescriptor(const gd::String functionName_,
|
||||
@@ -175,8 +174,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
*/
|
||||
const gd::String argumentsList;
|
||||
/**
|
||||
* A set of all objects that need to be backed up to be passed to the
|
||||
* callback code.
|
||||
* A set of all objects that need to be backed up to be passed to the callback code.
|
||||
*/
|
||||
const std::set<gd::String> requiredObjects;
|
||||
};
|
||||
@@ -329,7 +327,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
/**
|
||||
* \brief Get the global objects/groups used for code generation.
|
||||
*/
|
||||
const gd::ObjectsContainer& GetGlobalObjectsAndGroups() const {
|
||||
gd::ObjectsContainer& GetGlobalObjectsAndGroups() const {
|
||||
return globalObjectsAndGroups;
|
||||
}
|
||||
|
||||
@@ -350,7 +348,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
* \brief Get the project the code is being generated for.
|
||||
* \warning This is only valid if HasProjectAndLayout() is true.
|
||||
*/
|
||||
const gd::Project& GetProject() const { return *project; }
|
||||
gd::Project& GetProject() const { return *project; }
|
||||
|
||||
/**
|
||||
* \brief Get the layout the code is being generated for.
|
||||
@@ -509,17 +507,17 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
* - currentScene: Reference to the current runtime scene.
|
||||
* - objectList : a map containing lists of objects which are specified by the
|
||||
object name in another parameter.
|
||||
* - objectListOrEmptyIfJustDeclared : Same as `objectList` but do not pick
|
||||
object if they are not already picked.
|
||||
* - objectPtr: Return a reference to the object specified by the object name
|
||||
in another parameter. Example:
|
||||
* - objectListOrEmptyIfJustDeclared : Same as `objectList` but do not pick object if
|
||||
they are not already picked.
|
||||
* - objectPtr: Return a reference to the object specified by the object name in
|
||||
another parameter. Example:
|
||||
* \code
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectPtr", _("Target object"))
|
||||
* \endcode
|
||||
*/
|
||||
virtual gd::String GenerateParameterCodes(
|
||||
const gd::Expression& parameter,
|
||||
const gd::String& parameter,
|
||||
const gd::ParameterMetadata& metadata,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& lastObjectName,
|
||||
@@ -702,7 +700,6 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
gd::EventsCodeGenerationContext& context);
|
||||
|
||||
virtual gd::String GenerateFreeAction(
|
||||
const gd::String& functionCallName,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
@@ -711,7 +708,6 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
virtual gd::String GenerateObjectAction(
|
||||
const gd::String& objectName,
|
||||
const gd::ObjectMetadata& objInfo,
|
||||
const gd::String& functionCallName,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
@@ -721,7 +717,6 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
const gd::String& objectName,
|
||||
const gd::String& behaviorName,
|
||||
const gd::BehaviorMetadata& autoInfo,
|
||||
const gd::String& functionCallName,
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
@@ -775,13 +770,13 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
|
||||
const gd::Platform& platform; ///< The platform being used.
|
||||
|
||||
const gd::ObjectsContainer& globalObjectsAndGroups;
|
||||
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.
|
||||
const gd::Project* project; ///< The project being used.
|
||||
const gd::Layout* scene; ///< The scene being generated.
|
||||
gd::Project* project; ///< The project being used.
|
||||
const gd::Layout* scene; ///< The scene being generated.
|
||||
|
||||
bool errorOccurred; ///< Must be set to true if an error occured.
|
||||
bool compilationForRuntime; ///< Is set to true if the code generation is
|
||||
|
@@ -25,38 +25,36 @@
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
gd::String ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
EventsCodeGenerator& codeGenerator,
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& rootType,
|
||||
const gd::Expression& expression,
|
||||
const gd::String& rootObjectName) {
|
||||
ExpressionCodeGenerator generator(rootType, rootObjectName, codeGenerator, context);
|
||||
const gd::String& type,
|
||||
const gd::String& expression,
|
||||
const gd::String& objectName) {
|
||||
gd::ExpressionParser2 parser(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups());
|
||||
ExpressionCodeGenerator generator(codeGenerator, context);
|
||||
|
||||
auto node = expression.GetRootNode();
|
||||
auto node = parser.ParseExpression(type, expression, objectName);
|
||||
if (!node) {
|
||||
std::cout << "Error: error while parsing: \"" << expression.GetPlainString()
|
||||
<< "\" (" << rootType << ")" << std::endl;
|
||||
std::cout << "Error: error while parsing: \"" << expression << "\" ("
|
||||
<< type << ")" << std::endl;
|
||||
|
||||
return generator.GenerateDefaultValue(rootType);
|
||||
return generator.GenerateDefaultValue(type);
|
||||
}
|
||||
|
||||
gd::ExpressionValidator validator(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
rootType);
|
||||
gd::ExpressionValidator validator;
|
||||
node->Visit(validator);
|
||||
if (!validator.GetErrors().empty()) {
|
||||
std::cout << "Error: \"" << validator.GetErrors()[0]->GetMessage()
|
||||
<< "\" in: \"" << expression.GetPlainString() << "\" ("
|
||||
<< rootType << ")" << std::endl;
|
||||
<< "\" in: \"" << expression << "\" (" << type << ")"
|
||||
<< std::endl;
|
||||
|
||||
return generator.GenerateDefaultValue(rootType);
|
||||
return generator.GenerateDefaultValue(type);
|
||||
}
|
||||
|
||||
node->Visit(generator);
|
||||
@@ -99,24 +97,15 @@ void ExpressionCodeGenerator::OnVisitTextNode(TextNode& node) {
|
||||
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.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
rootType,
|
||||
node);
|
||||
EventsCodeGenerator::VariableScope scope =
|
||||
type == "globalvar"
|
||||
node.type == "globalvar"
|
||||
? gd::EventsCodeGenerator::PROJECT_VARIABLE
|
||||
: ((type == "scenevar")
|
||||
: ((node.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);
|
||||
node.name, scope, context, node.objectName);
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
|
||||
@@ -128,7 +117,7 @@ void ExpressionCodeGenerator::OnVisitVariableAccessorNode(
|
||||
|
||||
void ExpressionCodeGenerator::OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) {
|
||||
ExpressionCodeGenerator generator("string", "", codeGenerator, context);
|
||||
ExpressionCodeGenerator generator(codeGenerator, context);
|
||||
node.expression->Visit(generator);
|
||||
output +=
|
||||
codeGenerator.GenerateVariableBracketAccessor(generator.GetOutput());
|
||||
@@ -136,79 +125,39 @@ void ExpressionCodeGenerator::OnVisitVariableBracketAccessorNode(
|
||||
}
|
||||
|
||||
void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
rootType,
|
||||
node);
|
||||
if (gd::ParameterMetadata::IsObject(type)) {
|
||||
if (gd::ParameterMetadata::IsObject(node.type)) {
|
||||
output +=
|
||||
codeGenerator.GenerateObject(node.identifierName, type, context);
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", 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.identifierName, scope, context, objectName);
|
||||
if (!node.childIdentifierName.empty()) {
|
||||
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
|
||||
}
|
||||
} else if (node.childIdentifierName.empty()) {
|
||||
codeGenerator.GenerateObject(node.identifierName, node.type, context);
|
||||
} else {
|
||||
output += "/* Error during generation, unrecognized identifier type: " +
|
||||
codeGenerator.ConvertToString(type) + " with value " +
|
||||
codeGenerator.ConvertToString(node.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 appart from variables.
|
||||
output += GenerateDefaultValue(type);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionCodeGenerator::OnVisitFunctionCallNode(FunctionCallNode& node) {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
rootType,
|
||||
node);
|
||||
|
||||
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
|
||||
codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
node);
|
||||
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(node.expressionMetadata)) {
|
||||
output += "/* Error during generation, function not found: " +
|
||||
codeGenerator.ConvertToString(node.functionName) + " */ " +
|
||||
GenerateDefaultValue(type);
|
||||
GenerateDefaultValue(node.type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!node.objectName.empty()) {
|
||||
if (!node.behaviorName.empty()) {
|
||||
output += GenerateBehaviorFunctionCode(type,
|
||||
output += GenerateBehaviorFunctionCode(node.type,
|
||||
node.objectName,
|
||||
node.behaviorName,
|
||||
node.parameters,
|
||||
metadata);
|
||||
node.expressionMetadata);
|
||||
} else {
|
||||
output += GenerateObjectFunctionCode(
|
||||
type, node.objectName, node.parameters, metadata);
|
||||
node.type, node.objectName, node.parameters, node.expressionMetadata);
|
||||
}
|
||||
} else {
|
||||
output +=
|
||||
GenerateFreeFunctionCode(node.parameters, metadata);
|
||||
GenerateFreeFunctionCode(node.parameters, node.expressionMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,21 +305,18 @@ gd::String ExpressionCodeGenerator::GenerateParametersCodes(
|
||||
|
||||
auto& parameterMetadata = expressionMetadata.parameters[i];
|
||||
if (!parameterMetadata.IsCodeOnly()) {
|
||||
ExpressionCodeGenerator generator(codeGenerator, context);
|
||||
if (nonCodeOnlyParameterIndex < parameters.size()) {
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
rootObjectName,
|
||||
*parameters[nonCodeOnlyParameterIndex].get());
|
||||
ExpressionCodeGenerator generator(parameterMetadata.GetType(), objectName, codeGenerator, context);
|
||||
parameters[nonCodeOnlyParameterIndex]->Visit(generator);
|
||||
parametersCode += generator.GetOutput();
|
||||
} else if (parameterMetadata.IsOptional()) {
|
||||
ExpressionCodeGenerator generator(parameterMetadata.GetType(), "", codeGenerator, context);
|
||||
// Optional parameters default value were not parsed at the time of the
|
||||
// expression parsing. Parse them now.
|
||||
ExpressionParser2 parser;
|
||||
auto node = parser.ParseExpression(parameterMetadata.GetDefaultValue());
|
||||
ExpressionParser2 parser(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups());
|
||||
auto node = parser.ParseExpression(parameterMetadata.GetType(),
|
||||
parameterMetadata.GetDefaultValue());
|
||||
|
||||
node->Visit(generator);
|
||||
parametersCode += generator.GetOutput();
|
||||
@@ -428,22 +374,12 @@ gd::String ExpressionCodeGenerator::GenerateDefaultValue(
|
||||
}
|
||||
|
||||
void ExpressionCodeGenerator::OnVisitEmptyNode(EmptyNode& node) {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
rootType,
|
||||
node);
|
||||
output += GenerateDefaultValue(type);
|
||||
output += GenerateDefaultValue(node.type);
|
||||
}
|
||||
|
||||
void ExpressionCodeGenerator::OnVisitObjectFunctionNameNode(
|
||||
ObjectFunctionNameNode& node) {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
rootType,
|
||||
node);
|
||||
output += GenerateDefaultValue(type);
|
||||
output += GenerateDefaultValue(node.type);
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -34,11 +35,9 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionCodeGenerator(const gd::String &rootType_,
|
||||
const gd::String &rootObjectName_,
|
||||
EventsCodeGenerator& codeGenerator_,
|
||||
ExpressionCodeGenerator(EventsCodeGenerator& codeGenerator_,
|
||||
EventsCodeGenerationContext& context_)
|
||||
: rootType(rootType_), rootObjectName(rootObjectName_), codeGenerator(codeGenerator_), context(context_){};
|
||||
: codeGenerator(codeGenerator_), context(context_){};
|
||||
virtual ~ExpressionCodeGenerator(){};
|
||||
|
||||
/**
|
||||
@@ -58,7 +57,7 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
|
||||
static gd::String GenerateExpressionCode(EventsCodeGenerator& codeGenerator,
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& type,
|
||||
const gd::Expression& expression,
|
||||
const gd::String& expression,
|
||||
const gd::String& objectName = "");
|
||||
|
||||
const gd::String& GetOutput() { return output; };
|
||||
@@ -104,8 +103,6 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
|
||||
gd::String output;
|
||||
EventsCodeGenerator& codeGenerator;
|
||||
EventsCodeGenerationContext& context;
|
||||
const gd::String rootType;
|
||||
const gd::String rootObjectName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -75,8 +75,7 @@ void BaseEvent::PreprocessAsyncActions(const gd::Platform& platform) {
|
||||
const auto& action = actionsList->at(aId);
|
||||
const gd::InstructionMetadata& actionMetadata =
|
||||
gd::MetadataProvider::GetActionMetadata(platform, action.GetType());
|
||||
if (actionMetadata.IsAsync() &&
|
||||
(!actionMetadata.IsOptionallyAsync() || action.IsAwaited())) {
|
||||
if (actionMetadata.IsAsync()) {
|
||||
gd::InstructionsList remainingActions;
|
||||
remainingActions.InsertInstructions(
|
||||
*actionsList, aId + 1, actionsList->size() - 1);
|
||||
|
@@ -1,41 +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/Events/Expression.h"
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
Expression::Expression() : node(nullptr) {};
|
||||
|
||||
Expression::Expression(gd::String plainString_)
|
||||
: node(nullptr), plainString(plainString_) {};
|
||||
|
||||
Expression::Expression(const char* plainString_)
|
||||
: node(nullptr), plainString(plainString_) {};
|
||||
|
||||
Expression::Expression(const Expression& copy)
|
||||
: node(nullptr), plainString{copy.plainString} {};
|
||||
|
||||
Expression& Expression::operator=(const Expression& expression) {
|
||||
plainString = expression.plainString;
|
||||
node = nullptr;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Expression::~Expression(){};
|
||||
|
||||
ExpressionNode* Expression::GetRootNode() const {
|
||||
if (!node) {
|
||||
gd::ExpressionParser2 parser = ExpressionParser2();
|
||||
node = std::move(parser.ParseExpression(plainString));
|
||||
}
|
||||
return node.get();
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -6,15 +6,7 @@
|
||||
|
||||
#ifndef GDCORE_EXPRESSION_H
|
||||
#define GDCORE_EXPRESSION_H
|
||||
|
||||
#include "GDCore/String.h"
|
||||
#include <memory>
|
||||
|
||||
namespace gd {
|
||||
class ExpressionParser2;
|
||||
class ObjectsContainer;
|
||||
struct ExpressionNode;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -32,49 +24,32 @@ class GD_CORE_API Expression {
|
||||
/**
|
||||
* \brief Construct an empty expression
|
||||
*/
|
||||
Expression();
|
||||
Expression(){};
|
||||
|
||||
/**
|
||||
* \brief Construct an expression from a string
|
||||
*/
|
||||
Expression(gd::String plainString_);
|
||||
Expression(gd::String plainString_) : plainString(plainString_){};
|
||||
|
||||
/**
|
||||
* \brief Construct an expression from a const char *
|
||||
*/
|
||||
Expression(const char* plainString_);
|
||||
|
||||
/**
|
||||
* \brief Copy construct an expression.
|
||||
*/
|
||||
Expression(const Expression& copy);
|
||||
|
||||
/**
|
||||
* \brief Expression affectation overriding.
|
||||
*/
|
||||
Expression& operator=(const Expression& expression);
|
||||
Expression(const char* plainString_) : plainString(plainString_){};
|
||||
|
||||
/**
|
||||
* \brief Get the plain string representing the expression
|
||||
*/
|
||||
inline const gd::String& GetPlainString() const { return plainString; };
|
||||
|
||||
/**
|
||||
* @brief Get the expression node.
|
||||
* @return std::unique_ptr<gd::ExpressionNode>
|
||||
*/
|
||||
gd::ExpressionNode* GetRootNode() const;
|
||||
|
||||
/**
|
||||
* \brief Mimics std::string::c_str
|
||||
*/
|
||||
inline const char* c_str() const { return plainString.c_str(); };
|
||||
|
||||
virtual ~Expression();
|
||||
virtual ~Expression(){};
|
||||
|
||||
private:
|
||||
gd::String plainString; ///< The expression string
|
||||
mutable std::unique_ptr<gd::ExpressionNode> node;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -72,22 +72,6 @@ class GD_CORE_API Instruction {
|
||||
*/
|
||||
void SetInverted(bool inverted_) { inverted = inverted_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the async instruction should be awaited.
|
||||
* This is not relevant if the instruction is not optionally asynchronous.
|
||||
*
|
||||
* \return true if the instruction is to be awaited
|
||||
*/
|
||||
bool IsAwaited() const { return awaitAsync; }
|
||||
|
||||
/**
|
||||
* \brief Set if the async instruction is to be awaited or not.
|
||||
* This is not relevant if the instruction is not optionally asynchronous.
|
||||
*
|
||||
* \param inverted true if the instruction must be awaited
|
||||
*/
|
||||
void SetAwaited(bool awaited) { awaitAsync = awaited; }
|
||||
|
||||
/**
|
||||
* \brief Return the number of parameters of the instruction.
|
||||
*/
|
||||
@@ -155,9 +139,7 @@ class GD_CORE_API Instruction {
|
||||
* Useful to get reference to the original instruction in memory during code
|
||||
* generation, to ensure stable unique identifiers.
|
||||
*/
|
||||
std::weak_ptr<Instruction> GetOriginalInstruction() {
|
||||
return originalInstruction;
|
||||
};
|
||||
std::weak_ptr<Instruction> GetOriginalInstruction() { return originalInstruction; };
|
||||
|
||||
friend std::shared_ptr<Instruction> CloneRememberingOriginalElement(
|
||||
std::shared_ptr<Instruction> instruction);
|
||||
@@ -166,9 +148,6 @@ class GD_CORE_API Instruction {
|
||||
gd::String type; ///< Instruction type
|
||||
bool inverted; ///< True if the instruction if inverted. Only applicable for
|
||||
///< instruction used as conditions by events
|
||||
bool awaitAsync =
|
||||
false; ///< Tells the code generator whether the optionally asynchronous
|
||||
///< instruction should be generated as asynchronous (awaited) or not.
|
||||
mutable std::vector<gd::Expression>
|
||||
parameters; ///< Vector containing the parameters
|
||||
gd::InstructionsList subInstructions; ///< Sub instructions, if applicable.
|
||||
|
@@ -26,16 +26,132 @@ namespace gd {
|
||||
|
||||
gd::String ExpressionParser2::NAMESPACE_SEPARATOR = "::";
|
||||
|
||||
ExpressionParser2::ExpressionParser2()
|
||||
ExpressionParser2::ExpressionParser2(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ObjectsContainer& globalObjectsContainer_,
|
||||
const gd::ObjectsContainer& objectsContainer_)
|
||||
: expression(""),
|
||||
currentPosition(0) {}
|
||||
currentPosition(0),
|
||||
platform(platform_),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_) {}
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Return the minimum number of parameters, starting from a given parameter
|
||||
* (by convention, 1 for object functions and 2 for behavior functions).
|
||||
*/
|
||||
size_t GetMinimumParametersNumber(
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
size_t initialParameterIndex) {
|
||||
size_t nb = 0;
|
||||
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
|
||||
if (!parameters[i].optional && !parameters[i].codeOnly) nb++;
|
||||
}
|
||||
|
||||
return nb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of parameters, starting from a given parameter
|
||||
* (by convention, 1 for object functions and 2 for behavior functions).
|
||||
*/
|
||||
size_t GetMaximumParametersNumber(
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
size_t initialParameterIndex) {
|
||||
size_t nb = 0;
|
||||
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
|
||||
if (!parameters[i].codeOnly) nb++;
|
||||
}
|
||||
|
||||
return nb;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<ExpressionParserDiagnostic> ExpressionParser2::ValidateFunction(
|
||||
const gd::String& type,
|
||||
const gd::FunctionCallNode& function,
|
||||
size_t functionStartPosition) {
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(
|
||||
function.expressionMetadata)) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"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."),
|
||||
functionStartPosition,
|
||||
GetCurrentPosition());
|
||||
}
|
||||
|
||||
// Validate the type of the function
|
||||
const gd::String& returnType = function.expressionMetadata.GetReturnType();
|
||||
if (returnType == "number") {
|
||||
if (type == "string")
|
||||
return RaiseTypeError(
|
||||
_("You tried to use an expression that returns a number, but a "
|
||||
"string is expected. Use `ToString` if you need to convert a "
|
||||
"number to a string."),
|
||||
functionStartPosition);
|
||||
else if (type != "number" && type != "number|string")
|
||||
return RaiseTypeError(_("You tried to use an expression that returns a "
|
||||
"number, but another type is expected:") +
|
||||
" " + type,
|
||||
functionStartPosition);
|
||||
} else if (returnType == "string") {
|
||||
if (type == "number")
|
||||
return RaiseTypeError(
|
||||
_("You tried to use an expression that returns a string, but a "
|
||||
"number is expected. Use `ToNumber` if you need to convert a "
|
||||
"string to a number."),
|
||||
functionStartPosition);
|
||||
else if (type != "string" && type != "number|string")
|
||||
return RaiseTypeError(_("You tried to use an expression that returns a "
|
||||
"string, but another type is expected:") +
|
||||
" " + type,
|
||||
functionStartPosition);
|
||||
} else {
|
||||
if (type != returnType)
|
||||
return RaiseTypeError(
|
||||
_("You tried to use an expression with the wrong return type:") + " " +
|
||||
returnType,
|
||||
functionStartPosition);
|
||||
}
|
||||
|
||||
// Validate parameters count
|
||||
size_t minParametersCount = GetMinimumParametersNumber(
|
||||
function.expressionMetadata.parameters,
|
||||
WrittenParametersFirstIndex(function.objectName, function.behaviorName));
|
||||
size_t maxParametersCount = GetMaximumParametersNumber(
|
||||
function.expressionMetadata.parameters,
|
||||
WrittenParametersFirstIndex(function.objectName, function.behaviorName));
|
||||
if (function.parameters.size() < minParametersCount ||
|
||||
function.parameters.size() > maxParametersCount) {
|
||||
gd::String expectedCountMessage =
|
||||
minParametersCount == maxParametersCount
|
||||
? _("The number of parameters must be exactly ") +
|
||||
gd::String::From(minParametersCount)
|
||||
: _("The number of parameters must be: ") +
|
||||
gd::String::From(minParametersCount) + "-" +
|
||||
gd::String::From(maxParametersCount);
|
||||
|
||||
if (function.parameters.size() < minParametersCount) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"too_few_parameters",
|
||||
"You have not entered enough parameters for the expression. " +
|
||||
expectedCountMessage,
|
||||
functionStartPosition,
|
||||
GetCurrentPosition());
|
||||
}
|
||||
}
|
||||
|
||||
return gd::make_unique<ExpressionParserDiagnostic>();
|
||||
}
|
||||
|
||||
std::unique_ptr<TextNode> ExpressionParser2::ReadText() {
|
||||
size_t textStartPosition = GetCurrentPosition();
|
||||
SkipAllWhitespaces();
|
||||
if (!CheckIfChar(IsQuote)) {
|
||||
auto text = gd::make_unique<TextNode>("");
|
||||
// It can't happen.
|
||||
text->diagnostic =
|
||||
RaiseSyntaxError(_("A text must start with a double quote (\")."));
|
||||
text->location =
|
||||
|
@@ -40,7 +40,9 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API ExpressionParser2 {
|
||||
public:
|
||||
ExpressionParser2();
|
||||
ExpressionParser2(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_);
|
||||
virtual ~ExpressionParser2(){};
|
||||
|
||||
/**
|
||||
@@ -56,11 +58,13 @@ class GD_CORE_API ExpressionParser2 {
|
||||
* \return The node representing the expression as a parsed tree.
|
||||
*/
|
||||
std::unique_ptr<ExpressionNode> ParseExpression(
|
||||
const gd::String &expression_) {
|
||||
const gd::String &type,
|
||||
const gd::String &expression_,
|
||||
const gd::String &objectName = "") {
|
||||
expression = expression_;
|
||||
|
||||
currentPosition = 0;
|
||||
return Start();
|
||||
return Start(type, objectName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,16 +88,18 @@ class GD_CORE_API ExpressionParser2 {
|
||||
* Each method is a part of the grammar.
|
||||
*/
|
||||
///@{
|
||||
std::unique_ptr<ExpressionNode> Start() {
|
||||
std::unique_ptr<ExpressionNode> Start(const gd::String &type,
|
||||
const gd::String &objectName = "") {
|
||||
size_t expressionStartPosition = GetCurrentPosition();
|
||||
auto expression = Expression();
|
||||
auto expression = Expression(type, objectName);
|
||||
|
||||
const gd::String &inferredType = expression->type;
|
||||
|
||||
// Check for extra characters at the end of the expression
|
||||
if (!IsEndReached()) {
|
||||
auto op = gd::make_unique<OperatorNode>(' ');
|
||||
auto op = gd::make_unique<OperatorNode>(inferredType, ' ');
|
||||
op->leftHandSide = std::move(expression);
|
||||
op->rightHandSide = ReadUntilEnd();
|
||||
op->rightHandSide->parent = op.get();
|
||||
op->rightHandSide = ReadUntilEnd("unknown");
|
||||
|
||||
op->rightHandSide->diagnostic = RaiseSyntaxError(
|
||||
_("The expression has extra character at the end that should be "
|
||||
@@ -107,49 +113,61 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return expression;
|
||||
}
|
||||
|
||||
std::unique_ptr<ExpressionNode> Expression() {
|
||||
std::unique_ptr<ExpressionNode> Expression(
|
||||
const gd::String &type, const gd::String &objectName = "") {
|
||||
SkipAllWhitespaces();
|
||||
|
||||
size_t expressionStartPosition = GetCurrentPosition();
|
||||
std::unique_ptr<ExpressionNode> leftHandSide = Term();
|
||||
std::unique_ptr<ExpressionNode> leftHandSide = Term(type, objectName);
|
||||
|
||||
const gd::String &inferredType = leftHandSide->type;
|
||||
|
||||
SkipAllWhitespaces();
|
||||
|
||||
if (IsEndReached()) return leftHandSide;
|
||||
if (CheckIfChar(IsExpressionEndingChar)) return leftHandSide;
|
||||
if (CheckIfChar(IsExpressionOperator)) {
|
||||
auto op = gd::make_unique<OperatorNode>(GetCurrentChar());
|
||||
auto op = gd::make_unique<OperatorNode>(inferredType, GetCurrentChar());
|
||||
op->leftHandSide = std::move(leftHandSide);
|
||||
op->leftHandSide->parent = op.get();
|
||||
op->diagnostic = ValidateOperator(GetCurrentChar());
|
||||
op->diagnostic = ValidateOperator(inferredType, GetCurrentChar());
|
||||
SkipChar();
|
||||
op->rightHandSide = Expression();
|
||||
op->rightHandSide->parent = op.get();
|
||||
op->rightHandSide = Expression(inferredType, objectName);
|
||||
|
||||
op->location = ExpressionParserLocation(expressionStartPosition,
|
||||
GetCurrentPosition());
|
||||
return std::move(op);
|
||||
}
|
||||
|
||||
leftHandSide->diagnostic = RaiseSyntaxError(
|
||||
"More than one term was found. Verify that your expression is "
|
||||
"properly written.");
|
||||
if (inferredType == "string") {
|
||||
leftHandSide->diagnostic = RaiseSyntaxError(
|
||||
"You must add the operator + between texts or expressions. For "
|
||||
"example: \"Your name: \" + VariableString(PlayerName).");
|
||||
} else if (inferredType == "number") {
|
||||
leftHandSide->diagnostic = RaiseSyntaxError(
|
||||
"No operator found. Did you forget to enter an operator (like +, -, "
|
||||
"* or /) between numbers or expressions?");
|
||||
} else {
|
||||
leftHandSide->diagnostic = RaiseSyntaxError(
|
||||
"More than one term was found. Verify that your expression is "
|
||||
"properly written.");
|
||||
}
|
||||
|
||||
auto op = gd::make_unique<OperatorNode>(' ');
|
||||
auto op = gd::make_unique<OperatorNode>(inferredType, ' ');
|
||||
op->leftHandSide = std::move(leftHandSide);
|
||||
op->leftHandSide->parent = op.get();
|
||||
op->rightHandSide = Expression();
|
||||
op->rightHandSide->parent = op.get();
|
||||
op->rightHandSide = Expression(inferredType, objectName);
|
||||
op->location =
|
||||
ExpressionParserLocation(expressionStartPosition, GetCurrentPosition());
|
||||
return std::move(op);
|
||||
}
|
||||
|
||||
std::unique_ptr<ExpressionNode> Term() {
|
||||
std::unique_ptr<ExpressionNode> Term(const gd::String &type,
|
||||
const gd::String &objectName) {
|
||||
SkipAllWhitespaces();
|
||||
|
||||
size_t expressionStartPosition = GetCurrentPosition();
|
||||
std::unique_ptr<ExpressionNode> factor = Factor();
|
||||
std::unique_ptr<ExpressionNode> factor = Factor(type, objectName);
|
||||
|
||||
const gd::String &inferredType = factor->type;
|
||||
|
||||
SkipAllWhitespaces();
|
||||
|
||||
@@ -157,13 +175,11 @@ class GD_CORE_API ExpressionParser2 {
|
||||
// to guarantee the proper operator precedence. (Expression could also
|
||||
// be reworked to use a while loop).
|
||||
while (CheckIfChar(IsTermOperator)) {
|
||||
auto op = gd::make_unique<OperatorNode>(GetCurrentChar());
|
||||
auto op = gd::make_unique<OperatorNode>(inferredType, GetCurrentChar());
|
||||
op->leftHandSide = std::move(factor);
|
||||
op->leftHandSide->parent = op.get();
|
||||
op->diagnostic = ValidateOperator(GetCurrentChar());
|
||||
op->diagnostic = ValidateOperator(inferredType, GetCurrentChar());
|
||||
SkipChar();
|
||||
op->rightHandSide = Factor();
|
||||
op->rightHandSide->parent = op.get();
|
||||
op->rightHandSide = Factor(inferredType, objectName);
|
||||
op->location = ExpressionParserLocation(expressionStartPosition,
|
||||
GetCurrentPosition());
|
||||
SkipAllWhitespaces();
|
||||
@@ -174,35 +190,54 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return factor;
|
||||
};
|
||||
|
||||
std::unique_ptr<ExpressionNode> Factor() {
|
||||
std::unique_ptr<ExpressionNode> Factor(const gd::String &type,
|
||||
const gd::String &objectName) {
|
||||
SkipAllWhitespaces();
|
||||
size_t expressionStartPosition = GetCurrentPosition();
|
||||
|
||||
if (CheckIfChar(IsQuote)) {
|
||||
std::unique_ptr<ExpressionNode> factor = ReadText();
|
||||
if (type == "number")
|
||||
factor->diagnostic =
|
||||
RaiseTypeError(_("You entered a text, but a number was expected."),
|
||||
expressionStartPosition);
|
||||
else if (type != "string" && type != "number|string")
|
||||
factor->diagnostic = RaiseTypeError(
|
||||
_("You entered a text, but this type was expected:") + type,
|
||||
expressionStartPosition);
|
||||
|
||||
return factor;
|
||||
} else if (CheckIfChar(IsUnaryOperator)) {
|
||||
auto unaryOperatorCharacter = GetCurrentChar();
|
||||
SkipChar();
|
||||
|
||||
auto operatorOperand = Factor();
|
||||
auto operatorOperand = Factor(type, objectName);
|
||||
const gd::String &inferredType = operatorOperand->type;
|
||||
|
||||
auto unaryOperator = gd::make_unique<UnaryOperatorNode>(
|
||||
unaryOperatorCharacter);
|
||||
inferredType, unaryOperatorCharacter);
|
||||
unaryOperator->diagnostic = ValidateUnaryOperator(
|
||||
unaryOperatorCharacter, expressionStartPosition);
|
||||
inferredType, unaryOperatorCharacter, expressionStartPosition);
|
||||
unaryOperator->factor = std::move(operatorOperand);
|
||||
unaryOperator->factor->parent = unaryOperator.get();
|
||||
unaryOperator->location = ExpressionParserLocation(
|
||||
expressionStartPosition, GetCurrentPosition());
|
||||
|
||||
return std::move(unaryOperator);
|
||||
} else if (CheckIfChar(IsNumberFirstChar)) {
|
||||
std::unique_ptr<ExpressionNode> factor = ReadNumber();
|
||||
if (type == "string")
|
||||
factor->diagnostic = RaiseTypeError(
|
||||
_("You entered a number, but a text was expected (in quotes)."),
|
||||
expressionStartPosition);
|
||||
else if (type != "number" && type != "number|string")
|
||||
factor->diagnostic = RaiseTypeError(
|
||||
_("You entered a number, but this type was expected:") + type,
|
||||
expressionStartPosition);
|
||||
|
||||
return factor;
|
||||
} else if (CheckIfChar(IsOpeningParenthesis)) {
|
||||
SkipChar();
|
||||
std::unique_ptr<ExpressionNode> factor = SubExpression();
|
||||
std::unique_ptr<ExpressionNode> factor = SubExpression(type, objectName);
|
||||
|
||||
if (!CheckIfChar(IsClosingParenthesis)) {
|
||||
factor->diagnostic =
|
||||
@@ -212,20 +247,29 @@ class GD_CORE_API ExpressionParser2 {
|
||||
SkipIfChar(IsClosingParenthesis);
|
||||
return factor;
|
||||
} else if (IsIdentifierAllowedChar()) {
|
||||
return Identifier();
|
||||
// This is a place where the grammar differs according to the
|
||||
// type being expected.
|
||||
if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
return Variable(type, objectName);
|
||||
} else {
|
||||
return Identifier(type);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<ExpressionNode> factor = ReadUntilWhitespace();
|
||||
std::unique_ptr<ExpressionNode> factor = ReadUntilWhitespace(type);
|
||||
factor->diagnostic = RaiseEmptyError(type, expressionStartPosition);
|
||||
return factor;
|
||||
}
|
||||
|
||||
std::unique_ptr<SubExpressionNode> SubExpression() {
|
||||
std::unique_ptr<SubExpressionNode> SubExpression(
|
||||
const gd::String &type, const gd::String &objectName) {
|
||||
size_t expressionStartPosition = GetCurrentPosition();
|
||||
|
||||
auto expression = Expression();
|
||||
auto expression = Expression(type, objectName);
|
||||
const gd::String &inferredType = expression->type;
|
||||
|
||||
auto subExpression =
|
||||
gd::make_unique<SubExpressionNode>(std::move(expression));
|
||||
gd::make_unique<SubExpressionNode>(inferredType, std::move(expression));
|
||||
subExpression->location =
|
||||
ExpressionParserLocation(expressionStartPosition, GetCurrentPosition());
|
||||
|
||||
@@ -233,7 +277,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
};
|
||||
|
||||
std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
|
||||
Identifier() {
|
||||
Identifier(const gd::String &type) {
|
||||
auto identifierAndLocation = ReadIdentifierName();
|
||||
gd::String name = identifierAndLocation.name;
|
||||
auto nameLocation = identifierAndLocation.location;
|
||||
@@ -260,28 +304,47 @@ class GD_CORE_API ExpressionParser2 {
|
||||
|
||||
if (CheckIfChar(IsOpeningParenthesis)) {
|
||||
ExpressionParserLocation openingParenthesisLocation = SkipChar();
|
||||
return FreeFunction(name, nameLocation, openingParenthesisLocation);
|
||||
return FreeFunction(type, name, nameLocation, openingParenthesisLocation);
|
||||
} else if (CheckIfChar(IsDot)) {
|
||||
ExpressionParserLocation dotLocation = SkipChar();
|
||||
SkipAllWhitespaces();
|
||||
return ObjectFunctionOrBehaviorFunction(
|
||||
name, nameLocation, dotLocation);
|
||||
} else if (CheckIfChar(IsOpeningSquareBracket)) {
|
||||
return Variable(name, nameLocation);
|
||||
}
|
||||
else {
|
||||
auto identifier = gd::make_unique<IdentifierNode>(name);
|
||||
type, name, nameLocation, dotLocation);
|
||||
} else {
|
||||
auto identifier = gd::make_unique<IdentifierNode>(name, type);
|
||||
if (type == "string") {
|
||||
identifier->diagnostic =
|
||||
RaiseTypeError(_("You must wrap your text inside double quotes "
|
||||
"(example: \"Hello world\")."),
|
||||
nameLocation.GetStartPosition());
|
||||
} else if (type == "number") {
|
||||
identifier->diagnostic = RaiseTypeError(
|
||||
_("You must enter a number."), nameLocation.GetStartPosition());
|
||||
} else if (type == "number|string") {
|
||||
identifier->diagnostic = RaiseTypeError(
|
||||
_("You must enter a number or a text, wrapped inside double quotes "
|
||||
"(example: \"Hello world\")."),
|
||||
nameLocation.GetStartPosition());
|
||||
} else if (!gd::ParameterMetadata::IsObject(type)) {
|
||||
identifier->diagnostic = RaiseTypeError(
|
||||
_("You've entered a name, but this type was expected:") + type,
|
||||
nameLocation.GetStartPosition());
|
||||
}
|
||||
|
||||
identifier->location = ExpressionParserLocation(
|
||||
nameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
identifier->identifierNameLocation = identifier->location;
|
||||
return std::move(identifier);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<VariableNode> Variable(const gd::String &name, gd::ExpressionParserLocation nameLocation) {
|
||||
auto variable = gd::make_unique<VariableNode>(name);
|
||||
std::unique_ptr<VariableNode> Variable(const gd::String &type,
|
||||
const gd::String &objectName) {
|
||||
auto identifierAndLocation = ReadIdentifierName();
|
||||
const gd::String &name = identifierAndLocation.name;
|
||||
const auto &nameLocation = identifierAndLocation.location;
|
||||
|
||||
auto variable = gd::make_unique<VariableNode>(type, name, objectName);
|
||||
variable->child = VariableAccessorOrVariableBracketAccessor();
|
||||
variable->child->parent = variable.get();
|
||||
|
||||
variable->location = ExpressionParserLocation(
|
||||
nameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
@@ -296,8 +359,8 @@ class GD_CORE_API ExpressionParser2 {
|
||||
SkipAllWhitespaces();
|
||||
if (CheckIfChar(IsOpeningSquareBracket)) {
|
||||
SkipChar();
|
||||
auto child = gd::make_unique<VariableBracketAccessorNode>(Expression());
|
||||
child->expression->parent = child.get();
|
||||
auto child = gd::make_unique<VariableBracketAccessorNode>(
|
||||
Expression("number|string"));
|
||||
|
||||
if (!CheckIfChar(IsClosingSquareBracket)) {
|
||||
child->diagnostic =
|
||||
@@ -306,7 +369,6 @@ class GD_CORE_API ExpressionParser2 {
|
||||
}
|
||||
SkipIfChar(IsClosingSquareBracket);
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
child->location =
|
||||
ExpressionParserLocation(childStartPosition, GetCurrentPosition());
|
||||
|
||||
@@ -319,7 +381,6 @@ class GD_CORE_API ExpressionParser2 {
|
||||
auto child =
|
||||
gd::make_unique<VariableAccessorNode>(identifierAndLocation.name);
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
child->nameLocation = identifierAndLocation.location;
|
||||
child->dotLocation = dotLocation;
|
||||
child->location =
|
||||
@@ -328,21 +389,40 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return std::move(child);
|
||||
}
|
||||
|
||||
return std::move(gd::make_unique<VariableAccessorOrVariableBracketAccessorNode>());
|
||||
return std::move(
|
||||
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>());
|
||||
}
|
||||
|
||||
std::unique_ptr<FunctionCallNode> FreeFunction(
|
||||
const gd::String &type,
|
||||
const gd::String &functionFullName,
|
||||
const ExpressionParserLocation &identifierLocation,
|
||||
const ExpressionParserLocation &openingParenthesisLocation) {
|
||||
// TODO: error if trying to use function for type != "number" && != "string"
|
||||
// + Test for it
|
||||
|
||||
const gd::ExpressionMetadata &metadata =
|
||||
MetadataProvider::GetAnyExpressionMetadata(platform, functionFullName);
|
||||
|
||||
// In case we can't find a valid expression, ensure the node has the type
|
||||
// that is requested by the parent, so we avoid putting "unknown" (which
|
||||
// would be also correct, but less precise and would prevent completions to
|
||||
// be shown to the user)
|
||||
const gd::String returnType =
|
||||
gd::MetadataProvider::IsBadExpressionMetadata(metadata) == true
|
||||
? type
|
||||
: metadata.GetReturnType();
|
||||
|
||||
auto parametersNode = Parameters(metadata.parameters);
|
||||
auto function =
|
||||
gd::make_unique<FunctionCallNode>(functionFullName);
|
||||
auto parametersNode = Parameters(function.get());
|
||||
function->parameters = std::move(parametersNode.parameters);
|
||||
gd::make_unique<FunctionCallNode>(returnType,
|
||||
std::move(parametersNode.parameters),
|
||||
metadata,
|
||||
functionFullName);
|
||||
function->diagnostic = std::move(parametersNode.diagnostic);
|
||||
if (!function->diagnostic) // TODO: reverse the order of diagnostic?
|
||||
function->diagnostic = ValidateFunction(
|
||||
type, *function, identifierLocation.GetStartPosition());
|
||||
|
||||
function->location = ExpressionParserLocation(
|
||||
identifierLocation.GetStartPosition(), GetCurrentPosition());
|
||||
@@ -354,15 +434,16 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return std::move(function);
|
||||
}
|
||||
|
||||
std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
|
||||
std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode>
|
||||
ObjectFunctionOrBehaviorFunction(
|
||||
const gd::String &parentIdentifier,
|
||||
const ExpressionParserLocation &parentIdentifierLocation,
|
||||
const ExpressionParserLocation &parentIdentifierDotLocation) {
|
||||
auto childIdentifierAndLocation = ReadIdentifierName();
|
||||
const gd::String &childIdentifierName = childIdentifierAndLocation.name;
|
||||
const auto &childIdentifierNameLocation =
|
||||
childIdentifierAndLocation.location;
|
||||
const gd::String &type,
|
||||
const gd::String &objectName,
|
||||
const ExpressionParserLocation &objectNameLocation,
|
||||
const ExpressionParserLocation &objectNameDotLocation) {
|
||||
auto identifierAndLocation = ReadIdentifierName();
|
||||
const gd::String &objectFunctionOrBehaviorName = identifierAndLocation.name;
|
||||
const auto &objectFunctionOrBehaviorNameLocation =
|
||||
identifierAndLocation.location;
|
||||
|
||||
SkipAllWhitespaces();
|
||||
|
||||
@@ -370,68 +451,87 @@ class GD_CORE_API ExpressionParser2 {
|
||||
ExpressionParserLocation namespaceSeparatorLocation =
|
||||
SkipNamespaceSeparator();
|
||||
SkipAllWhitespaces();
|
||||
return BehaviorFunction(parentIdentifier,
|
||||
childIdentifierName,
|
||||
parentIdentifierLocation,
|
||||
parentIdentifierDotLocation,
|
||||
childIdentifierNameLocation,
|
||||
return BehaviorFunction(type,
|
||||
objectName,
|
||||
objectFunctionOrBehaviorName,
|
||||
objectNameLocation,
|
||||
objectNameDotLocation,
|
||||
objectFunctionOrBehaviorNameLocation,
|
||||
namespaceSeparatorLocation);
|
||||
} else if (CheckIfChar(IsOpeningParenthesis)) {
|
||||
ExpressionParserLocation openingParenthesisLocation = SkipChar();
|
||||
|
||||
gd::String objectType =
|
||||
GetTypeOfObject(globalObjectsContainer, objectsContainer, objectName);
|
||||
|
||||
const gd::ExpressionMetadata &metadata =
|
||||
MetadataProvider::GetObjectAnyExpressionMetadata(
|
||||
platform, objectType, objectFunctionOrBehaviorName);
|
||||
|
||||
// In case we can't find a valid expression, ensure the node has the type
|
||||
// that is requested by the parent, so we avoid putting "unknown" (which
|
||||
// would be also correct, but less precise and would prevent completions
|
||||
// to be shown to the user)
|
||||
const gd::String returnType =
|
||||
gd::MetadataProvider::IsBadExpressionMetadata(metadata) == true
|
||||
? type
|
||||
: metadata.GetReturnType();
|
||||
|
||||
auto parametersNode = Parameters(metadata.parameters, objectName);
|
||||
auto function = gd::make_unique<FunctionCallNode>(
|
||||
parentIdentifier,
|
||||
childIdentifierName);
|
||||
auto parametersNode = Parameters(function.get(), parentIdentifier);
|
||||
function->parameters = std::move(parametersNode.parameters),
|
||||
returnType,
|
||||
objectName,
|
||||
std::move(parametersNode.parameters),
|
||||
metadata,
|
||||
objectFunctionOrBehaviorName);
|
||||
function->diagnostic = std::move(parametersNode.diagnostic);
|
||||
|
||||
if (!function->diagnostic) // TODO: reverse the order of diagnostic?
|
||||
function->diagnostic = ValidateFunction(
|
||||
type, *function, objectNameLocation.GetStartPosition());
|
||||
|
||||
// If the function needs a capability on the object that may not be covered
|
||||
// by all objects, check it now.
|
||||
if (!metadata.GetRequiredBaseObjectCapability().empty()) {
|
||||
const gd::ObjectMetadata &objectMetadata =
|
||||
MetadataProvider::GetObjectMetadata(platform, objectType);
|
||||
|
||||
if (objectMetadata.IsUnsupportedBaseObjectCapability(
|
||||
metadata.GetRequiredBaseObjectCapability())) {
|
||||
function->diagnostic = RaiseTypeError(
|
||||
_("This expression exists, but it can't be used on this object."),
|
||||
objectNameLocation.GetStartPosition());
|
||||
}
|
||||
}
|
||||
|
||||
function->location = ExpressionParserLocation(
|
||||
parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
|
||||
function->objectNameLocation = parentIdentifierLocation;
|
||||
function->objectNameDotLocation = parentIdentifierDotLocation;
|
||||
function->functionNameLocation = childIdentifierNameLocation;
|
||||
objectNameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
function->objectNameLocation = objectNameLocation;
|
||||
function->objectNameDotLocation = objectNameDotLocation;
|
||||
function->functionNameLocation = objectFunctionOrBehaviorNameLocation;
|
||||
function->openingParenthesisLocation = openingParenthesisLocation;
|
||||
function->closingParenthesisLocation =
|
||||
parametersNode.closingParenthesisLocation;
|
||||
return std::move(function);
|
||||
} else if (CheckIfChar(IsDot) || CheckIfChar(IsOpeningSquareBracket)) {
|
||||
auto variable = gd::make_unique<VariableNode>(parentIdentifier);
|
||||
auto child =
|
||||
gd::make_unique<VariableAccessorNode>(childIdentifierName);
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->child->parent = child.get();
|
||||
child->nameLocation = childIdentifierNameLocation;
|
||||
child->dotLocation = parentIdentifierDotLocation;
|
||||
child->location = ExpressionParserLocation(
|
||||
parentIdentifierDotLocation.GetStartPosition(), GetCurrentPosition());
|
||||
variable->child = std::move(child);
|
||||
variable->child->parent = variable.get();
|
||||
|
||||
variable->location = ExpressionParserLocation(
|
||||
parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
|
||||
variable->nameLocation = parentIdentifierLocation;
|
||||
|
||||
return std::move(variable);
|
||||
}
|
||||
|
||||
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."));
|
||||
}
|
||||
auto node = gd::make_unique<ObjectFunctionNameNode>(
|
||||
type, objectName, objectFunctionOrBehaviorName);
|
||||
node->diagnostic = RaiseSyntaxError(
|
||||
_("An opening parenthesis (for an object expression), or double colon "
|
||||
"(::) was expected (for a behavior expression)."));
|
||||
|
||||
node->location = ExpressionParserLocation(
|
||||
parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
|
||||
node->identifierNameLocation = parentIdentifierLocation;
|
||||
node->identifierNameDotLocation = parentIdentifierDotLocation;
|
||||
node->childIdentifierNameLocation = childIdentifierNameLocation;
|
||||
objectNameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
node->objectNameLocation = objectNameLocation;
|
||||
node->objectNameDotLocation = objectNameDotLocation;
|
||||
node->objectFunctionOrBehaviorNameLocation =
|
||||
objectFunctionOrBehaviorNameLocation;
|
||||
return std::move(node);
|
||||
}
|
||||
|
||||
std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode> BehaviorFunction(
|
||||
const gd::String &type,
|
||||
const gd::String &objectName,
|
||||
const gd::String &behaviorName,
|
||||
const ExpressionParserLocation &objectNameLocation,
|
||||
@@ -447,14 +547,35 @@ class GD_CORE_API ExpressionParser2 {
|
||||
if (CheckIfChar(IsOpeningParenthesis)) {
|
||||
ExpressionParserLocation openingParenthesisLocation = SkipChar();
|
||||
|
||||
gd::String behaviorType = GetTypeOfBehavior(
|
||||
globalObjectsContainer, objectsContainer, behaviorName);
|
||||
|
||||
const gd::ExpressionMetadata &metadata =
|
||||
MetadataProvider::GetBehaviorAnyExpressionMetadata(
|
||||
platform, behaviorType, functionName);
|
||||
|
||||
// In case we can't find a valid expression, ensure the node has the type
|
||||
// that is requested by the parent, so we avoid putting "unknown" (which
|
||||
// would be also correct, but less precise and would prevent completions
|
||||
// to be shown to the user)
|
||||
const gd::String returnType =
|
||||
gd::MetadataProvider::IsBadExpressionMetadata(metadata) == true
|
||||
? type
|
||||
: metadata.GetReturnType();
|
||||
|
||||
auto parametersNode =
|
||||
Parameters(metadata.parameters, objectName, behaviorName);
|
||||
auto function = gd::make_unique<FunctionCallNode>(
|
||||
returnType,
|
||||
objectName,
|
||||
behaviorName,
|
||||
std::move(parametersNode.parameters),
|
||||
metadata,
|
||||
functionName);
|
||||
auto parametersNode =
|
||||
Parameters(function.get(), objectName, behaviorName);
|
||||
function->parameters = std::move(parametersNode.parameters);
|
||||
function->diagnostic = std::move(parametersNode.diagnostic);
|
||||
if (!function->diagnostic) // TODO: reverse the order of diagnostic?
|
||||
function->diagnostic = ValidateFunction(
|
||||
type, *function, objectNameLocation.GetStartPosition());
|
||||
|
||||
function->location = ExpressionParserLocation(
|
||||
objectNameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
@@ -470,7 +591,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return std::move(function);
|
||||
} else {
|
||||
auto node = gd::make_unique<ObjectFunctionNameNode>(
|
||||
objectName, behaviorName, functionName);
|
||||
type, objectName, behaviorName, functionName);
|
||||
node->diagnostic = RaiseSyntaxError(
|
||||
_("An opening parenthesis was expected here to call a function."));
|
||||
|
||||
@@ -494,7 +615,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
};
|
||||
|
||||
ParametersNode Parameters(
|
||||
FunctionCallNode *functionCallNode,
|
||||
std::vector<gd::ParameterMetadata> parameterMetadata,
|
||||
const gd::String &objectName = "",
|
||||
const gd::String &behaviorName = "") {
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters;
|
||||
@@ -505,25 +626,77 @@ class GD_CORE_API ExpressionParser2 {
|
||||
size_t parameterIndex =
|
||||
WrittenParametersFirstIndex(objectName, behaviorName);
|
||||
|
||||
bool previousCharacterIsParameterSeparator = false;
|
||||
while (!IsEndReached()) {
|
||||
SkipAllWhitespaces();
|
||||
|
||||
if (CheckIfChar(IsClosingParenthesis) && !previousCharacterIsParameterSeparator) {
|
||||
if (CheckIfChar(IsClosingParenthesis)) {
|
||||
auto closingParenthesisLocation = SkipChar();
|
||||
return ParametersNode{
|
||||
std::move(parameters), nullptr, closingParenthesisLocation};
|
||||
}
|
||||
bool isEmptyParameter = CheckIfChar(IsParameterSeparator)
|
||||
|| (CheckIfChar(IsClosingParenthesis) && previousCharacterIsParameterSeparator);
|
||||
auto parameter = isEmptyParameter ? gd::make_unique<EmptyNode>() : Expression();
|
||||
parameter->parent = functionCallNode;
|
||||
parameters.push_back(std::move(parameter));
|
||||
} else {
|
||||
if (parameterIndex < parameterMetadata.size()) {
|
||||
const gd::String &type = parameterMetadata[parameterIndex].GetType();
|
||||
if (parameterMetadata[parameterIndex].IsCodeOnly()) {
|
||||
// Do nothing, code only parameters are not written in expressions.
|
||||
} else if (gd::ParameterMetadata::IsExpression("number", type)) {
|
||||
parameters.push_back(Expression("number"));
|
||||
} else if (gd::ParameterMetadata::IsExpression("string", type)) {
|
||||
parameters.push_back(Expression("string"));
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
parameters.push_back(Expression(
|
||||
type, lastObjectName.empty() ? objectName : lastObjectName));
|
||||
} else if (gd::ParameterMetadata::IsObject(type)) {
|
||||
size_t parameterStartPosition = GetCurrentPosition();
|
||||
std::unique_ptr<ExpressionNode> objectExpression = Expression(type);
|
||||
|
||||
SkipAllWhitespaces();
|
||||
previousCharacterIsParameterSeparator = CheckIfChar(IsParameterSeparator);
|
||||
SkipIfChar(IsParameterSeparator);
|
||||
parameterIndex++;
|
||||
// Memorize the last object name. By convention, parameters that
|
||||
// require an object (mainly, "objectvar" and "behavior") should be
|
||||
// placed after the object in the list of parameters (if possible,
|
||||
// just after). Search "lastObjectName" in the codebase for other
|
||||
// place where this convention is enforced.
|
||||
if (auto identifierNode =
|
||||
dynamic_cast<IdentifierNode *>(objectExpression.get())) {
|
||||
lastObjectName = identifierNode->identifierName;
|
||||
} else {
|
||||
objectExpression->diagnostic =
|
||||
gd::make_unique<ExpressionParserError>(
|
||||
"malformed_object_parameter",
|
||||
_("An object name was expected but something else was "
|
||||
"written. Enter just the name of the object for this "
|
||||
"parameter."),
|
||||
parameterStartPosition,
|
||||
GetCurrentPosition());
|
||||
}
|
||||
|
||||
parameters.push_back(std::move(objectExpression));
|
||||
} else {
|
||||
size_t parameterStartPosition = GetCurrentPosition();
|
||||
parameters.push_back(Expression("unknown"));
|
||||
parameters.back()->diagnostic =
|
||||
gd::make_unique<ExpressionParserError>(
|
||||
"unknown_parameter_type",
|
||||
_("This function is improperly set up. Reach out to the "
|
||||
"extension developer or a GDevelop maintainer to fix "
|
||||
"this issue"),
|
||||
parameterStartPosition,
|
||||
GetCurrentPosition());
|
||||
}
|
||||
} else {
|
||||
size_t parameterStartPosition = GetCurrentPosition();
|
||||
parameters.push_back(Expression("unknown"));
|
||||
parameters.back()
|
||||
->diagnostic = gd::make_unique<ExpressionParserError>(
|
||||
"extra_parameter",
|
||||
_("This parameter was not expected by this expression. Remove it "
|
||||
"or verify that you've entered the proper expression name."),
|
||||
parameterStartPosition,
|
||||
GetCurrentPosition());
|
||||
}
|
||||
|
||||
SkipAllWhitespaces();
|
||||
SkipIfChar(IsParameterSeparator);
|
||||
parameterIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionParserLocation invalidClosingParenthesisLocation;
|
||||
@@ -535,32 +708,92 @@ class GD_CORE_API ExpressionParser2 {
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Validators
|
||||
* Return a diagnostic if any error is found
|
||||
*/
|
||||
///@{
|
||||
std::unique_ptr<ExpressionParserDiagnostic> ValidateFunction(
|
||||
const gd::String &type,
|
||||
const gd::FunctionCallNode &function,
|
||||
size_t functionStartPosition);
|
||||
|
||||
std::unique_ptr<ExpressionParserDiagnostic> ValidateOperator(
|
||||
gd::String::value_type operatorChar) {
|
||||
if (operatorChar == '+' || operatorChar == '-' || operatorChar == '/' ||
|
||||
operatorChar == '*') {
|
||||
return gd::make_unique<ExpressionParserDiagnostic>();
|
||||
const gd::String &type, gd::String::value_type operatorChar) {
|
||||
if (type == "number") {
|
||||
if (operatorChar == '+' || operatorChar == '-' || operatorChar == '/' ||
|
||||
operatorChar == '*') {
|
||||
return gd::make_unique<ExpressionParserDiagnostic>();
|
||||
}
|
||||
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("You've used an operator that is not supported. Operator should be "
|
||||
"either +, -, / or *."),
|
||||
GetCurrentPosition());
|
||||
} else if (type == "string") {
|
||||
if (operatorChar == '+') {
|
||||
return gd::make_unique<ExpressionParserDiagnostic>();
|
||||
}
|
||||
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("You've used an operator that is not supported. Only + can be used "
|
||||
"to concatenate texts."),
|
||||
GetCurrentPosition());
|
||||
} else if (gd::ParameterMetadata::IsObject(type)) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("Operators (+, -, /, *) can't be used with an object name. Remove "
|
||||
"the operator."),
|
||||
GetCurrentPosition());
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("Operators (+, -, /, *) can't be used in variable names. Remove "
|
||||
"the operator from the variable name."),
|
||||
GetCurrentPosition());
|
||||
}
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("You've used an operator that is not supported. Operator should be "
|
||||
"either +, -, / or *."),
|
||||
GetCurrentPosition());
|
||||
|
||||
return gd::make_unique<ExpressionParserDiagnostic>();
|
||||
}
|
||||
|
||||
std::unique_ptr<ExpressionParserDiagnostic> ValidateUnaryOperator(
|
||||
const gd::String &type,
|
||||
gd::String::value_type operatorChar,
|
||||
size_t position) {
|
||||
if (operatorChar == '+' || operatorChar == '-') {
|
||||
return gd::make_unique<ExpressionParserDiagnostic>();
|
||||
if (type == "number") {
|
||||
if (operatorChar == '+' || operatorChar == '-') {
|
||||
return gd::make_unique<ExpressionParserDiagnostic>();
|
||||
}
|
||||
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("You've used an \"unary\" operator that is not supported. Operator "
|
||||
"should be "
|
||||
"either + or -."),
|
||||
position);
|
||||
} else if (type == "string") {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("You've used an operator that is not supported. Only + can be used "
|
||||
"to concatenate texts, and must be placed between two texts (or "
|
||||
"expressions)."),
|
||||
position);
|
||||
} else if (gd::ParameterMetadata::IsObject(type)) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("Operators (+, -) can't be used with an object name. Remove the "
|
||||
"operator."),
|
||||
position);
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("Operators (+, -) can't be used in variable names. Remove "
|
||||
"the operator from the variable name."),
|
||||
position);
|
||||
}
|
||||
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("You've used an \"unary\" operator that is not supported. Operator "
|
||||
"should be "
|
||||
"either + or -."),
|
||||
position);
|
||||
return gd::make_unique<ExpressionParserDiagnostic>();
|
||||
}
|
||||
///@}
|
||||
|
||||
@@ -748,7 +981,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
|
||||
std::unique_ptr<NumberNode> ReadNumber();
|
||||
|
||||
std::unique_ptr<EmptyNode> ReadUntilWhitespace() {
|
||||
std::unique_ptr<EmptyNode> ReadUntilWhitespace(gd::String type) {
|
||||
size_t startPosition = GetCurrentPosition();
|
||||
gd::String text;
|
||||
while (currentPosition < expression.size() &&
|
||||
@@ -757,13 +990,13 @@ class GD_CORE_API ExpressionParser2 {
|
||||
currentPosition++;
|
||||
}
|
||||
|
||||
auto node = gd::make_unique<EmptyNode>(text);
|
||||
auto node = gd::make_unique<EmptyNode>(type, text);
|
||||
node->location =
|
||||
ExpressionParserLocation(startPosition, GetCurrentPosition());
|
||||
return node;
|
||||
}
|
||||
|
||||
std::unique_ptr<EmptyNode> ReadUntilEnd() {
|
||||
std::unique_ptr<EmptyNode> ReadUntilEnd(gd::String type) {
|
||||
size_t startPosition = GetCurrentPosition();
|
||||
gd::String text;
|
||||
while (currentPosition < expression.size()) {
|
||||
@@ -771,7 +1004,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
currentPosition++;
|
||||
}
|
||||
|
||||
auto node = gd::make_unique<EmptyNode>(text);
|
||||
auto node = gd::make_unique<EmptyNode>(type, text);
|
||||
node->location =
|
||||
ExpressionParserLocation(startPosition, GetCurrentPosition());
|
||||
return node;
|
||||
@@ -804,11 +1037,34 @@ class GD_CORE_API ExpressionParser2 {
|
||||
return std::move(gd::make_unique<ExpressionParserError>(
|
||||
"type_error", message, beginningPosition, GetCurrentPosition()));
|
||||
}
|
||||
|
||||
std::unique_ptr<ExpressionParserError> RaiseEmptyError(
|
||||
const gd::String &type, size_t beginningPosition) {
|
||||
gd::String message;
|
||||
if (type == "number") {
|
||||
message = _("You must enter a number or a valid expression call.");
|
||||
} else if (type == "string") {
|
||||
message = _(
|
||||
"You must enter a text (between quotes) or a valid expression call.");
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
message = _("You must enter a variable name.");
|
||||
} else if (gd::ParameterMetadata::IsObject(type)) {
|
||||
message = _("You must enter a valid object name.");
|
||||
} else {
|
||||
message = _("You must enter a valid expression.");
|
||||
}
|
||||
|
||||
return std::move(RaiseTypeError(message, beginningPosition));
|
||||
}
|
||||
///@}
|
||||
|
||||
gd::String expression;
|
||||
std::size_t currentPosition;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
|
||||
static gd::String NAMESPACE_SEPARATOR;
|
||||
};
|
||||
|
||||
|
@@ -17,7 +17,6 @@ class ObjectsContainer;
|
||||
class Platform;
|
||||
class ParameterMetadata;
|
||||
class ExpressionMetadata;
|
||||
struct FunctionCallNode;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -58,10 +57,6 @@ struct GD_CORE_API ExpressionParserDiagnostic {
|
||||
* \brief An error that can be attached to a gd::ExpressionNode.
|
||||
*/
|
||||
struct GD_CORE_API ExpressionParserError : public ExpressionParserDiagnostic {
|
||||
ExpressionParserError(const gd::String &type_,
|
||||
const gd::String &message_,
|
||||
const ExpressionParserLocation &location_)
|
||||
: type(type_), message(message_), location(location_){};
|
||||
ExpressionParserError(const gd::String &type_,
|
||||
const gd::String &message_,
|
||||
size_t position_)
|
||||
@@ -91,7 +86,7 @@ struct GD_CORE_API ExpressionParserError : public ExpressionParserDiagnostic {
|
||||
* an expression inherits from.
|
||||
*/
|
||||
struct GD_CORE_API ExpressionNode {
|
||||
ExpressionNode() : parent(nullptr) {};
|
||||
ExpressionNode(const gd::String &type_) : type(type_){};
|
||||
virtual ~ExpressionNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker){};
|
||||
|
||||
@@ -102,12 +97,17 @@ struct GD_CORE_API ExpressionNode {
|
||||
/// function can store the position of the
|
||||
/// object name, the dot, the function
|
||||
/// name, etc...
|
||||
ExpressionNode *parent;
|
||||
|
||||
gd::String type; // Actual type of the node.
|
||||
// "string", "number", type supported by
|
||||
// gd::ParameterMetadata::IsObject, types supported by
|
||||
// gd::ParameterMetadata::IsExpression or "unknown".
|
||||
};
|
||||
|
||||
struct GD_CORE_API SubExpressionNode : public ExpressionNode {
|
||||
SubExpressionNode(std::unique_ptr<ExpressionNode> expression_)
|
||||
: ExpressionNode(), expression(std::move(expression_)){};
|
||||
SubExpressionNode(const gd::String &type_,
|
||||
std::unique_ptr<ExpressionNode> expression_)
|
||||
: ExpressionNode(type_), expression(std::move(expression_)){};
|
||||
virtual ~SubExpressionNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitSubExpressionNode(*this);
|
||||
@@ -120,8 +120,8 @@ struct GD_CORE_API SubExpressionNode : public ExpressionNode {
|
||||
* \brief An operator node. For example: "lhs + rhs".
|
||||
*/
|
||||
struct GD_CORE_API OperatorNode : public ExpressionNode {
|
||||
OperatorNode(gd::String::value_type op_)
|
||||
: ExpressionNode(), op(op_){};
|
||||
OperatorNode(const gd::String &type_, gd::String::value_type op_)
|
||||
: ExpressionNode(type_), op(op_){};
|
||||
virtual ~OperatorNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitOperatorNode(*this);
|
||||
@@ -136,8 +136,8 @@ struct GD_CORE_API OperatorNode : public ExpressionNode {
|
||||
* \brief A unary operator node. For example: "-2".
|
||||
*/
|
||||
struct GD_CORE_API UnaryOperatorNode : public ExpressionNode {
|
||||
UnaryOperatorNode(gd::String::value_type op_)
|
||||
: ExpressionNode(), op(op_){};
|
||||
UnaryOperatorNode(const gd::String &type_, gd::String::value_type op_)
|
||||
: ExpressionNode(type_), op(op_){};
|
||||
virtual ~UnaryOperatorNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitUnaryOperatorNode(*this);
|
||||
@@ -153,7 +153,7 @@ struct GD_CORE_API UnaryOperatorNode : public ExpressionNode {
|
||||
*/
|
||||
struct GD_CORE_API NumberNode : public ExpressionNode {
|
||||
NumberNode(const gd::String &number_)
|
||||
: ExpressionNode(), number(number_){};
|
||||
: ExpressionNode("number"), number(number_){};
|
||||
virtual ~NumberNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitNumberNode(*this);
|
||||
@@ -168,7 +168,7 @@ struct GD_CORE_API NumberNode : public ExpressionNode {
|
||||
* Its `type` is always "string".
|
||||
*/
|
||||
struct GD_CORE_API TextNode : public ExpressionNode {
|
||||
TextNode(const gd::String &text_) : ExpressionNode(), text(text_){};
|
||||
TextNode(const gd::String &text_) : ExpressionNode("string"), text(text_){};
|
||||
virtual ~TextNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitTextNode(*this);
|
||||
@@ -177,88 +177,32 @@ struct GD_CORE_API TextNode : public ExpressionNode {
|
||||
gd::String text;
|
||||
};
|
||||
|
||||
struct GD_CORE_API IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode
|
||||
: public ExpressionNode {
|
||||
IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode()
|
||||
: ExpressionNode(){};
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An identifier node, usually representing an object or a variable
|
||||
* with an optional function name or child variable name respectively.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
struct GD_CORE_API IdentifierNode
|
||||
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
IdentifierNode(
|
||||
const gd::String &identifierName_)
|
||||
: IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(),
|
||||
identifierName(identifierName_),
|
||||
childIdentifierName(""){};
|
||||
IdentifierNode(
|
||||
const gd::String &identifierName_,
|
||||
const gd::String &childIdentifierName_)
|
||||
: IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(),
|
||||
identifierName(identifierName_),
|
||||
childIdentifierName(childIdentifierName_){};
|
||||
virtual ~IdentifierNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitIdentifierNode(*this);
|
||||
};
|
||||
|
||||
gd::String identifierName; ///< The object or variable name.
|
||||
gd::String childIdentifierName; ///< The object function or variable child name.
|
||||
|
||||
|
||||
ExpressionParserLocation
|
||||
identifierNameLocation; ///< Location of the object or variable name.
|
||||
ExpressionParserLocation
|
||||
identifierNameDotLocation; ///< Location of the "." after the object or variable name.
|
||||
ExpressionParserLocation childIdentifierNameLocation; ///< Location of object
|
||||
/// function, behavior or
|
||||
/// child variable name.
|
||||
};
|
||||
|
||||
struct GD_CORE_API FunctionCallOrObjectFunctionNameOrEmptyNode
|
||||
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
FunctionCallOrObjectFunctionNameOrEmptyNode()
|
||||
: IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(){};
|
||||
virtual ~FunctionCallOrObjectFunctionNameOrEmptyNode(){};
|
||||
void Visit(ExpressionParser2NodeWorker &worker) override{};
|
||||
};
|
||||
|
||||
struct GD_CORE_API VariableAccessorOrVariableBracketAccessorNode : public ExpressionNode {
|
||||
VariableAccessorOrVariableBracketAccessorNode() : ExpressionNode(){};
|
||||
VariableAccessorOrVariableBracketAccessorNode() : ExpressionNode(""){};
|
||||
|
||||
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode> child;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A variable with bracket accessor or at least 2 "dot" accessors.
|
||||
* \brief A variable, potentially with accessor to its children.
|
||||
*
|
||||
* Example: MyVariable or MyVariable.MyChildren
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
struct GD_CORE_API VariableNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
VariableNode(const gd::String &name_)
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(), name(name_){};
|
||||
struct GD_CORE_API VariableNode : public ExpressionNode {
|
||||
VariableNode(const gd::String &type_,
|
||||
const gd::String &name_,
|
||||
const gd::String &objectName_)
|
||||
: ExpressionNode(type_), name(name_), objectName(objectName_){};
|
||||
virtual ~VariableNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitVariableNode(*this);
|
||||
};
|
||||
|
||||
gd::String name;
|
||||
gd::String objectName;
|
||||
|
||||
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
|
||||
child; // Can be nullptr if no accessor
|
||||
@@ -272,8 +216,7 @@ struct GD_CORE_API VariableNode : public FunctionCallOrObjectFunctionNameOrEmpty
|
||||
*/
|
||||
struct GD_CORE_API VariableAccessorNode
|
||||
: public VariableAccessorOrVariableBracketAccessorNode {
|
||||
VariableAccessorNode(const gd::String &name_)
|
||||
: VariableAccessorOrVariableBracketAccessorNode(), name(name_){};
|
||||
VariableAccessorNode(const gd::String &name_) : name(name_){};
|
||||
virtual ~VariableAccessorNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitVariableAccessorNode(*this);
|
||||
@@ -291,7 +234,7 @@ struct GD_CORE_API VariableAccessorNode
|
||||
struct GD_CORE_API VariableBracketAccessorNode
|
||||
: public VariableAccessorOrVariableBracketAccessorNode {
|
||||
VariableBracketAccessorNode(std::unique_ptr<ExpressionNode> expression_)
|
||||
: VariableAccessorOrVariableBracketAccessorNode(), expression(std::move(expression_)){};
|
||||
: expression(std::move(expression_)){};
|
||||
virtual ~VariableBracketAccessorNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitVariableBracketAccessorNode(*this);
|
||||
@@ -300,26 +243,55 @@ struct GD_CORE_API VariableBracketAccessorNode
|
||||
std::unique_ptr<ExpressionNode> expression;
|
||||
};
|
||||
|
||||
struct GD_CORE_API IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode
|
||||
: public ExpressionNode {
|
||||
IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(
|
||||
const gd::String &type)
|
||||
: ExpressionNode(type){};
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An identifier node, usually representing an object or a function name.
|
||||
*/
|
||||
struct GD_CORE_API IdentifierNode
|
||||
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
IdentifierNode(const gd::String &identifierName_, const gd::String &type_)
|
||||
: IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(type_),
|
||||
identifierName(identifierName_){};
|
||||
virtual ~IdentifierNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitIdentifierNode(*this);
|
||||
};
|
||||
|
||||
gd::String identifierName;
|
||||
};
|
||||
|
||||
struct GD_CORE_API FunctionCallOrObjectFunctionNameOrEmptyNode
|
||||
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
FunctionCallOrObjectFunctionNameOrEmptyNode(const gd::String &type)
|
||||
: IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(type){};
|
||||
virtual ~FunctionCallOrObjectFunctionNameOrEmptyNode(){};
|
||||
void Visit(ExpressionParser2NodeWorker &worker) override{};
|
||||
};
|
||||
|
||||
/**
|
||||
* \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
|
||||
* For example: "MyObject.Function" or "MyObject.Physics" or
|
||||
* "MyObject.Physics::LinearVelocity".
|
||||
*/
|
||||
struct GD_CORE_API ObjectFunctionNameNode
|
||||
: public FunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
ObjectFunctionNameNode(const gd::String &objectName_,
|
||||
ObjectFunctionNameNode(const gd::String &type_,
|
||||
const gd::String &objectName_,
|
||||
const gd::String &objectFunctionOrBehaviorName_)
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(),
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_),
|
||||
objectName(objectName_),
|
||||
objectFunctionOrBehaviorName(objectFunctionOrBehaviorName_) {}
|
||||
ObjectFunctionNameNode(const gd::String &objectName_,
|
||||
ObjectFunctionNameNode(const gd::String &type_,
|
||||
const gd::String &objectName_,
|
||||
const gd::String &behaviorName_,
|
||||
const gd::String &behaviorFunctionName_)
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(),
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_),
|
||||
objectName(objectName_),
|
||||
objectFunctionOrBehaviorName(behaviorName_),
|
||||
behaviorFunctionName(behaviorFunctionName_) {}
|
||||
@@ -362,24 +334,39 @@ struct GD_CORE_API ObjectFunctionNameNode
|
||||
*/
|
||||
struct GD_CORE_API FunctionCallNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
/** \brief Construct a free function call node. */
|
||||
FunctionCallNode(const gd::String &functionName_)
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(),
|
||||
FunctionCallNode(const gd::String &type_,
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
|
||||
const ExpressionMetadata &expressionMetadata_,
|
||||
const gd::String &functionName_)
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_),
|
||||
parameters(std::move(parameters_)),
|
||||
expressionMetadata(expressionMetadata_),
|
||||
functionName(functionName_){};
|
||||
|
||||
/** \brief Construct an object function call node. */
|
||||
FunctionCallNode(const gd::String &objectName_,
|
||||
FunctionCallNode(const gd::String &type_,
|
||||
const gd::String &objectName_,
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
|
||||
const ExpressionMetadata &expressionMetadata_,
|
||||
const gd::String &functionName_)
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(),
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_),
|
||||
objectName(objectName_),
|
||||
parameters(std::move(parameters_)),
|
||||
expressionMetadata(expressionMetadata_),
|
||||
functionName(functionName_){};
|
||||
|
||||
/** \brief Construct a behavior function call node. */
|
||||
FunctionCallNode(const gd::String &objectName_,
|
||||
FunctionCallNode(const gd::String &type_,
|
||||
const gd::String &objectName_,
|
||||
const gd::String &behaviorName_,
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
|
||||
const ExpressionMetadata &expressionMetadata_,
|
||||
const gd::String &functionName_)
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(),
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_),
|
||||
objectName(objectName_),
|
||||
behaviorName(behaviorName_),
|
||||
parameters(std::move(parameters_)),
|
||||
expressionMetadata(expressionMetadata_),
|
||||
functionName(functionName_){};
|
||||
virtual ~FunctionCallNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
@@ -389,6 +376,7 @@ struct GD_CORE_API FunctionCallNode : public FunctionCallOrObjectFunctionNameOrE
|
||||
gd::String objectName;
|
||||
gd::String behaviorName;
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters;
|
||||
const ExpressionMetadata &expressionMetadata;
|
||||
gd::String functionName;
|
||||
|
||||
ExpressionParserLocation
|
||||
@@ -413,8 +401,8 @@ struct GD_CORE_API FunctionCallNode : public FunctionCallOrObjectFunctionNameOrE
|
||||
* encountered and any other node could not make sense.
|
||||
*/
|
||||
struct GD_CORE_API EmptyNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
EmptyNode(const gd::String &text_ = "")
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(), text(text_){};
|
||||
EmptyNode(const gd::String &type_, const gd::String &text_ = "")
|
||||
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_), text(text_){};
|
||||
virtual ~EmptyNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitEmptyNode(*this);
|
||||
|
@@ -91,9 +91,6 @@ class GD_CORE_API ExpressionParser2NodePrinter
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
output += node.identifierName;
|
||||
if (!node.childIdentifierName.empty()) {
|
||||
output += "." + node.childIdentifierName;
|
||||
}
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
if (!node.behaviorFunctionName.empty()) {
|
||||
|
@@ -4,7 +4,6 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
@@ -233,8 +232,7 @@ void EventsListSerialization::SerializeEventsTo(const EventsList& list,
|
||||
const gd::BaseEvent& event = list.GetEvent(j);
|
||||
SerializerElement& eventElem = events.AddChild("event");
|
||||
|
||||
if (event.IsDisabled())
|
||||
eventElem.SetAttribute("disabled", event.IsDisabled());
|
||||
if (event.IsDisabled()) eventElem.SetAttribute("disabled", event.IsDisabled());
|
||||
if (event.IsFolded()) eventElem.SetAttribute("folded", event.IsFolded());
|
||||
eventElem.AddChild("type").SetValue(event.GetType());
|
||||
|
||||
@@ -269,9 +267,6 @@ void gd::EventsListSerialization::UnserializeInstructionsFrom(
|
||||
instrElement.GetChild("type", 0, "Type")
|
||||
.GetBoolAttribute("inverted", false, "Contraire"));
|
||||
|
||||
instruction.SetAwaited(
|
||||
instrElement.GetChild("type", 0, "Type").GetBoolAttribute("await"));
|
||||
|
||||
// Read parameters
|
||||
vector<gd::Expression> parameters;
|
||||
|
||||
@@ -345,12 +340,9 @@ void gd::EventsListSerialization::SerializeInstructionsTo(
|
||||
instructions.ConsiderAsArrayOf("instruction");
|
||||
for (std::size_t k = 0; k < list.size(); k++) {
|
||||
SerializerElement& instruction = instructions.AddChild("instruction");
|
||||
instruction.AddChild("type").SetAttribute("value", list[k].GetType());
|
||||
|
||||
if (list[k].IsInverted())
|
||||
instruction.GetChild("type").SetAttribute("inverted", true);
|
||||
if (list[k].IsAwaited())
|
||||
instruction.GetChild("type").SetAttribute("await", true);
|
||||
instruction.AddChild("type")
|
||||
.SetAttribute("value", list[k].GetType())
|
||||
.SetAttribute("inverted", list[k].IsInverted());
|
||||
|
||||
// Parameters
|
||||
SerializerElement& parameters = instruction.AddChild("parameters");
|
||||
@@ -360,10 +352,9 @@ void gd::EventsListSerialization::SerializeInstructionsTo(
|
||||
.SetValue(list[k].GetParameter(l).GetPlainString());
|
||||
|
||||
// Sub instructions
|
||||
if (!list[k].GetSubInstructions().empty()) {
|
||||
SerializeInstructionsTo(list[k].GetSubInstructions(),
|
||||
instruction.AddChild("subInstructions"));
|
||||
}
|
||||
SerializerElement& subInstructions =
|
||||
instruction.AddChild("subInstructions");
|
||||
SerializeInstructionsTo(list[k].GetSubInstructions(), subInstructions);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,14 +14,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
|
||||
extension
|
||||
.SetExtensionInformation(
|
||||
"BuiltinAudio",
|
||||
_("Sounds and music"),
|
||||
_("Sounds and musics"),
|
||||
_("GDevelop provides several conditions and actions to play audio "
|
||||
"files. They can be either long music or short sound effects."),
|
||||
"files. They can be either long musics or short sound effects."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/audio")
|
||||
.SetCategory("Audio");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Sounds and music"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Sounds and musics"))
|
||||
.SetIcon("res/actions/music24.png");
|
||||
|
||||
extension
|
||||
|
@@ -219,7 +219,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
obj.AddAction("SetAngle",
|
||||
_("Angle"),
|
||||
_("Change the angle of rotation of an object (in degrees)."),
|
||||
_("Change the angle of rotation of an object."),
|
||||
_("the angle"),
|
||||
_("Angle"),
|
||||
"res/actions/direction24.png",
|
||||
@@ -289,8 +289,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Speed on X axis (in pixels per second)"))
|
||||
.AddParameter("expression", _("Speed on Y axis (in pixels per second)"))
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
|
||||
.SetDefaultValue("0");
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"));
|
||||
|
||||
obj.AddAction("AddForceAL",
|
||||
_("Add a force (angle)"),
|
||||
@@ -306,8 +305,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("expression", _("Angle"))
|
||||
.AddParameter("expression", _("Speed (in pixels per second)"))
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction(
|
||||
@@ -325,8 +323,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("expression", _("X position"))
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.AddParameter("expression", _("Speed (in pixels per second)"))
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction(
|
||||
@@ -759,8 +756,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectPtr", _("Target Object"))
|
||||
.AddParameter("expression", _("Speed (in pixels per second)"))
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction(
|
||||
@@ -780,8 +776,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("objectPtr", _("Rotate around this object"))
|
||||
.AddParameter("expression", _("Speed (in degrees per second)"))
|
||||
.AddParameter("expression", _("Distance (in pixels)"))
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.AddParameter("forceMultiplier", _("Force multiplier"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("MettreAutour",
|
||||
@@ -998,7 +993,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
obj.AddExpression("ForceAngle",
|
||||
_("Angle of the sum of forces"),
|
||||
_("Angle of the sum of forces (in degrees)"),
|
||||
_("Angle of the sum of forces"),
|
||||
_("Movement using forces"),
|
||||
"res/actions/force.png")
|
||||
.AddParameter("object", _("Object"));
|
||||
@@ -1131,9 +1126,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
obj.AddExpression("AngleToObject",
|
||||
_("Angle between two objects"),
|
||||
_("Compute the angle between two objects (in degrees). "
|
||||
"If you need the angle to an arbitrary position, "
|
||||
"use AngleToPosition."),
|
||||
_("Compute the angle between two objects. If you need the "
|
||||
"angle to an arbitrary position, use AngleToPosition."),
|
||||
_("Angle"),
|
||||
"res/actions/position.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
@@ -1166,8 +1160,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddExpression("AngleToPosition",
|
||||
_("Angle between an object and a position"),
|
||||
_("Compute the angle between the object center and a "
|
||||
"\"target\" position (in degrees). If you need the angle "
|
||||
"between two objects, use AngleToObject."),
|
||||
"\"target\" position. If you need the angle between two "
|
||||
"objects, use AngleToObject."),
|
||||
_("Angle"),
|
||||
"res/actions/position.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
|
@@ -29,7 +29,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
extension
|
||||
.AddExpressionAndConditionAndAction(
|
||||
"number",
|
||||
"CameraCenterX",
|
||||
"CameraX",
|
||||
_("Camera center X position"),
|
||||
_("the X position of the center of a camera"),
|
||||
_("the X position of camera _PARAM4_ (layer: _PARAM3_)"),
|
||||
@@ -43,25 +43,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.SetDefaultValue("0")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
// Compatibility with GD <= 5.0.135
|
||||
extension.AddDuplicatedCondition("CameraX", "CameraCenterX")
|
||||
.SetHidden(); // Deprecated
|
||||
extension.AddDuplicatedExpression("CameraX", "CameraCenterX")
|
||||
.SetHidden(); // Deprecated
|
||||
extension.AddDuplicatedAction("SetCameraX", "SetCameraCenterX")
|
||||
.SetHidden(); // Deprecated
|
||||
|
||||
extension.AddDuplicatedAction("CameraX", "SetCameraX")
|
||||
.SetHidden(); // Deprecated
|
||||
|
||||
extension.AddDuplicatedExpression("VueX", "CameraX")
|
||||
.SetHidden(); // Deprecated
|
||||
// end of compatibility code
|
||||
|
||||
extension
|
||||
.AddExpressionAndConditionAndAction(
|
||||
"number",
|
||||
"CameraCenterY",
|
||||
"CameraY",
|
||||
_("Camera center Y position"),
|
||||
_("the Y position of the center of a camera"),
|
||||
_("the Y position of camera _PARAM4_ (layer: _PARAM3_)"),
|
||||
@@ -75,20 +65,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.SetDefaultValue("0")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
// Compatibility with GD <= 5.0.135
|
||||
extension.AddDuplicatedCondition("CameraY", "CameraCenterY")
|
||||
.SetHidden(); // Deprecated
|
||||
extension.AddDuplicatedExpression("CameraY", "CameraCenterY")
|
||||
.SetHidden(); // Deprecated
|
||||
extension.AddDuplicatedAction("SetCameraY", "SetCameraCenterY")
|
||||
.SetHidden(); // Deprecated
|
||||
|
||||
extension.AddDuplicatedAction("CameraY", "SetCameraY")
|
||||
.SetHidden(); // Deprecated
|
||||
|
||||
extension.AddDuplicatedExpression("VueY", "CameraY")
|
||||
.SetHidden(); // Deprecated
|
||||
// end of compatibility code
|
||||
|
||||
extension
|
||||
.AddExpressionAndCondition(
|
||||
@@ -100,9 +80,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"))
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.AddParameter("expression", _("Camera number"))
|
||||
.UseStandardParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -116,77 +96,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"))
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.UseStandardParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddExpressionAndCondition(
|
||||
"number",
|
||||
"CameraBorderLeft",
|
||||
_("Camera left border position"),
|
||||
_("the position of the left border of a camera"),
|
||||
_("the position of the left border of camera _PARAM2_ of layer "
|
||||
"_PARAM1_"),
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.UseStandardParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddExpressionAndCondition(
|
||||
"number",
|
||||
"CameraBorderRight",
|
||||
_("Camera right border position"),
|
||||
_("the position of the right border of a camera"),
|
||||
_("the position of the right border of camera _PARAM2_ of layer "
|
||||
"_PARAM1_"),
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.UseStandardParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddExpressionAndCondition(
|
||||
"number",
|
||||
"CameraBorderTop",
|
||||
_("Camera top border position"),
|
||||
_("the position of the top border of a camera"),
|
||||
_("the position of the top border of camera _PARAM2_ of layer "
|
||||
"_PARAM1_"),
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.UseStandardParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddExpressionAndCondition(
|
||||
"number",
|
||||
"CameraBorderBottom",
|
||||
_("Camera bottom border position"),
|
||||
_("the position of the bottom border of a camera"),
|
||||
_("the position of the bottom border of camera _PARAM2_ of layer "
|
||||
"_PARAM1_"),
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.AddParameter("expression", _("Camera number"))
|
||||
.UseStandardParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -195,7 +107,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"number",
|
||||
"CameraAngle",
|
||||
_("Angle of a camera of a layer"),
|
||||
_("the angle of rotation of a camera (in degrees)"),
|
||||
_("the angle of rotation of a camera"),
|
||||
_("the angle of camera (layer: _PARAM3_, camera: _PARAM4_)"),
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
|
@@ -96,13 +96,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
_("Difference between two angles"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("First angle, in degrees"))
|
||||
.AddParameter("expression", _("Second angle, in degrees"));
|
||||
.AddParameter("expression", _("First angle"))
|
||||
.AddParameter("expression", _("Second angle"));
|
||||
|
||||
extension
|
||||
.AddExpression("AngleBetweenPositions",
|
||||
_("Angle between two positions"),
|
||||
_("Compute the angle between two positions (in degrees)."),
|
||||
_("Compute the angle between two positions."),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("First point X position"))
|
||||
@@ -159,8 +159,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
extension
|
||||
.AddExpression("acos",
|
||||
_("Arccosine"),
|
||||
_("Arccosine, return an angle (in radian). "
|
||||
"`ToDeg` allows to convert it to degrees."),
|
||||
_("Arccosine"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
@@ -176,8 +175,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
extension
|
||||
.AddExpression("asin",
|
||||
_("Arcsine"),
|
||||
_("Arcsine, return an angle (in radian). "
|
||||
"`ToDeg` allows to convert it to degrees."),
|
||||
_("Arcsine"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
@@ -193,8 +191,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
extension
|
||||
.AddExpression("atan",
|
||||
_("Arctangent"),
|
||||
_("Arctangent, return an angle (in radian). "
|
||||
"`ToDeg` allows to convert it to degrees."),
|
||||
_("Arctangent"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
@@ -261,8 +258,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
extension
|
||||
.AddExpression("cos",
|
||||
_("Cosine"),
|
||||
_("Cosine of an angle (in radian). "
|
||||
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
|
||||
_("Cosine of a number"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
@@ -404,8 +400,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
extension
|
||||
.AddExpression("sin",
|
||||
_("Sine"),
|
||||
_("Sine of an angle (in radian). "
|
||||
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
|
||||
_("Sine of a number"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
@@ -429,8 +424,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
|
||||
extension
|
||||
.AddExpression("tan",
|
||||
_("Tangent"),
|
||||
_("Tangent of an angle (in radian). "
|
||||
"If you want to use degrees, use`ToRad`: `tan(ToRad(45))`."),
|
||||
_("Tangent of a number"),
|
||||
"",
|
||||
"res/mathfunction.png")
|
||||
.AddParameter("expression", _("Expression"));
|
||||
|
@@ -4,10 +4,8 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
@@ -31,15 +29,6 @@ const Sprite& Direction::GetSprite(std::size_t nb) const { return sprites[nb]; }
|
||||
|
||||
Sprite& Direction::GetSprite(std::size_t nb) { return sprites[nb]; }
|
||||
|
||||
const std::vector<gd::String>& Direction::GetSpriteNames() const {
|
||||
static std::vector<gd::String> spriteNames;
|
||||
spriteNames.clear();
|
||||
for (std::size_t i = 0; i < sprites.size(); ++i) {
|
||||
spriteNames.push_back(sprites[i].GetImageName());
|
||||
}
|
||||
return spriteNames;
|
||||
}
|
||||
|
||||
void Direction::RemoveSprite(std::size_t index) {
|
||||
if (index < sprites.size()) sprites.erase(sprites.begin() + index);
|
||||
}
|
||||
|
@@ -72,13 +72,6 @@ class GD_CORE_API Direction {
|
||||
*/
|
||||
Sprite& GetSprite(std::size_t nb);
|
||||
|
||||
/**
|
||||
* \brief Return a vector of references to sprite names.
|
||||
*
|
||||
* \return A vector of all sprite names references.
|
||||
*/
|
||||
const std::vector<gd::String>& GetSpriteNames() const;
|
||||
|
||||
/**
|
||||
* \brief Check if the direction contains sprites.
|
||||
*
|
||||
|
@@ -21,7 +21,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/all-features/timers-and-time");
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Timers and time"))
|
||||
extension.AddInstructionOrExpressionGroupMetadata(
|
||||
_("Timers and time")
|
||||
)
|
||||
.SetIcon("res/conditions/timer24.png");
|
||||
|
||||
// Deprecated and replaced by CompareTimer
|
||||
@@ -156,7 +158,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
"res/timer.svg",
|
||||
"res/timer.svg")
|
||||
.AddParameter("expression", "Time to wait in seconds")
|
||||
.SetHelpPath("/all-features/timers-and-time/wait-action");
|
||||
.SetHelpPath("/all-features/timers-and-time/wait-action")
|
||||
.SetAsync();
|
||||
|
||||
extension
|
||||
.AddExpression("TimeDelta",
|
||||
|
@@ -22,6 +22,7 @@ InstructionMetadata::InstructionMetadata()
|
||||
canHaveSubInstructions(false),
|
||||
hidden(true),
|
||||
usageComplexity(5),
|
||||
isAsync(false),
|
||||
isPrivate(false),
|
||||
isObjectInstruction(false),
|
||||
isBehaviorInstruction(false) {}
|
||||
@@ -45,6 +46,7 @@ InstructionMetadata::InstructionMetadata(const gd::String& extensionNamespace_,
|
||||
extensionNamespace(extensionNamespace_),
|
||||
hidden(false),
|
||||
usageComplexity(5),
|
||||
isAsync(false),
|
||||
isPrivate(false),
|
||||
isObjectInstruction(false),
|
||||
isBehaviorInstruction(false) {}
|
||||
|
@@ -6,10 +6,10 @@
|
||||
|
||||
#ifndef INSTRUCTIONMETADATA_H
|
||||
#define INSTRUCTIONMETADATA_H
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -104,16 +104,16 @@ class GD_CORE_API InstructionMetadata {
|
||||
* background, executing the instructions following it before the frame after
|
||||
* it resolved.
|
||||
*/
|
||||
bool IsAsync() const {
|
||||
return !codeExtraInformation.asyncFunctionCallName.empty();
|
||||
}
|
||||
bool IsAsync() const { return isAsync; }
|
||||
|
||||
/**
|
||||
* Check if the instruction asynchronicity is optional. If it is, it can either
|
||||
* be used synchronously or asynchronously, with one function for each.
|
||||
* Set that the instruction is asynchronous - it will be running in the
|
||||
* background, executing the instructions following it before the frame after
|
||||
* it resolved.
|
||||
*/
|
||||
bool IsOptionallyAsync() const {
|
||||
return IsAsync() && !codeExtraInformation.functionCallName.empty();
|
||||
InstructionMetadata &SetAsync() {
|
||||
isAsync = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,26 +319,14 @@ class GD_CORE_API InstructionMetadata {
|
||||
virtual ~ExtraInformation(){};
|
||||
|
||||
/**
|
||||
* Set the name of the function which will be called in the generated code.
|
||||
* \param functionName the name of the function to call.
|
||||
* Set the function name which will be used when generating the code.
|
||||
* \param functionName the name of the function to call
|
||||
*/
|
||||
ExtraInformation &SetFunctionName(const gd::String &functionName_) {
|
||||
functionCallName = functionName_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the function, doing asynchronous work, which will be called in
|
||||
* the generated code. This function should return an asynchronous task
|
||||
* (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
|
||||
*
|
||||
* \param functionName the name of the function doing asynchronous work to call.
|
||||
*/
|
||||
ExtraInformation &SetAsyncFunctionName(const gd::String &functionName_) {
|
||||
asyncFunctionCallName = functionName_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare if the instruction being declared is somewhat manipulating in a
|
||||
* standard way.
|
||||
@@ -366,7 +354,7 @@ class GD_CORE_API InstructionMetadata {
|
||||
* .AddParameter("object", _("Object"), "Text", false)
|
||||
* .AddParameter("operator", _("Modification operator"), "string")
|
||||
* .AddParameter("string", _("String"))
|
||||
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString");
|
||||
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString").SetIncludeFile("MyExtension/TextObject.h");
|
||||
*
|
||||
* DECLARE_END_OBJECT_ACTION()
|
||||
* \endcode
|
||||
@@ -434,7 +422,6 @@ class GD_CORE_API InstructionMetadata {
|
||||
bool HasCustomCodeGenerator() const { return hasCustomCodeGenerator; }
|
||||
|
||||
gd::String functionCallName;
|
||||
gd::String asyncFunctionCallName;
|
||||
gd::String type;
|
||||
AccessType accessType;
|
||||
gd::String optionalAssociatedInstruction;
|
||||
@@ -467,26 +454,15 @@ class GD_CORE_API InstructionMetadata {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the function which will be called in the generated code.
|
||||
* \param functionName the name of the function to call.
|
||||
* \brief Set the function that should be called when generating the source
|
||||
* code from events.
|
||||
* \param functionName the name of the function to call
|
||||
* \note Shortcut for `codeExtraInformation.SetFunctionName`.
|
||||
*/
|
||||
ExtraInformation &SetFunctionName(const gd::String &functionName) {
|
||||
return codeExtraInformation.SetFunctionName(functionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the function, doing asynchronous work, which will be called in
|
||||
* the generated code. This function should return an asynchronous task
|
||||
* (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
|
||||
*
|
||||
* \param functionName the name of the function doing asynchronous work to call.
|
||||
* \note Shortcut for `codeExtraInformation.SetAsyncFunctionName`.
|
||||
*/
|
||||
ExtraInformation &SetAsyncFunctionName(const gd::String &functionName) {
|
||||
return codeExtraInformation.SetAsyncFunctionName(functionName);
|
||||
}
|
||||
|
||||
std::vector<ParameterMetadata> parameters;
|
||||
|
||||
private:
|
||||
@@ -503,6 +479,7 @@ class GD_CORE_API InstructionMetadata {
|
||||
int usageComplexity; ///< Evaluate the instruction from 0 (simple&easy to
|
||||
///< use) to 10 (complex to understand)
|
||||
bool isPrivate;
|
||||
bool isAsync;
|
||||
bool isObjectInstruction;
|
||||
bool isBehaviorInstruction;
|
||||
gd::String requiredBaseObjectCapability;
|
||||
|
@@ -13,9 +13,7 @@
|
||||
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -32,9 +30,12 @@ ExtensionAndMetadata<BehaviorMetadata>
|
||||
MetadataProvider::GetExtensionAndBehaviorMetadata(const gd::Platform& platform,
|
||||
gd::String behaviorType) {
|
||||
for (auto& extension : platform.GetAllPlatformExtensions()) {
|
||||
if (extension->HasBehavior(behaviorType))
|
||||
return ExtensionAndMetadata<BehaviorMetadata>(
|
||||
*extension, extension->GetBehaviorMetadata(behaviorType));
|
||||
auto behaviorTypes = extension->GetBehaviorsTypes();
|
||||
for (std::size_t j = 0; j < behaviorTypes.size(); ++j) {
|
||||
if (behaviorTypes[j] == behaviorType)
|
||||
return ExtensionAndMetadata<BehaviorMetadata>(
|
||||
*extension, extension->GetBehaviorMetadata(behaviorType));
|
||||
}
|
||||
}
|
||||
|
||||
return ExtensionAndMetadata<BehaviorMetadata>(badExtension, badBehaviorMetadata);
|
||||
@@ -201,7 +202,8 @@ MetadataProvider::GetExtensionAndBehaviorExpressionMetadata(
|
||||
const gd::Platform& platform, gd::String autoType, gd::String exprType) {
|
||||
auto& extensions = platform.GetAllPlatformExtensions();
|
||||
for (auto& extension : extensions) {
|
||||
if (extension->HasBehavior(autoType)) {
|
||||
const auto& autos = extension->GetBehaviorsTypes();
|
||||
if (find(autos.begin(), autos.end(), autoType) != autos.end()) {
|
||||
const auto& allAutoExpressions =
|
||||
extension->GetAllExpressionsForBehavior(autoType);
|
||||
if (allAutoExpressions.find(exprType) != allAutoExpressions.end())
|
||||
@@ -290,7 +292,8 @@ MetadataProvider::GetExtensionAndBehaviorStrExpressionMetadata(
|
||||
const gd::Platform& platform, gd::String autoType, gd::String exprType) {
|
||||
auto& extensions = platform.GetAllPlatformExtensions();
|
||||
for (auto& extension : extensions) {
|
||||
if (extension->HasBehavior(autoType)) {
|
||||
const auto& autos = extension->GetBehaviorsTypes();
|
||||
if (find(autos.begin(), autos.end(), autoType) != autos.end()) {
|
||||
const auto& allBehaviorStrExpressions =
|
||||
extension->GetAllStrExpressionsForBehavior(autoType);
|
||||
if (allBehaviorStrExpressions.find(exprType) !=
|
||||
@@ -347,30 +350,28 @@ const gd::ExpressionMetadata& MetadataProvider::GetAnyExpressionMetadata(
|
||||
const gd::Platform& platform, gd::String exprType) {
|
||||
const auto& numberExpressionMetadata =
|
||||
GetExpressionMetadata(platform, exprType);
|
||||
if (&numberExpressionMetadata != &badExpressionMetadata) {
|
||||
return numberExpressionMetadata;
|
||||
}
|
||||
const auto& stringExpressionMetadata =
|
||||
GetStrExpressionMetadata(platform, exprType);
|
||||
if (&stringExpressionMetadata != &badExpressionMetadata) {
|
||||
return stringExpressionMetadata;
|
||||
}
|
||||
return badExpressionMetadata;
|
||||
|
||||
return &numberExpressionMetadata != &badExpressionMetadata
|
||||
? numberExpressionMetadata
|
||||
: &stringExpressionMetadata != &badExpressionMetadata
|
||||
? stringExpressionMetadata
|
||||
: badExpressionMetadata;
|
||||
}
|
||||
|
||||
const gd::ExpressionMetadata& MetadataProvider::GetObjectAnyExpressionMetadata(
|
||||
const gd::Platform& platform, gd::String objectType, gd::String exprType) {
|
||||
const auto& numberExpressionMetadata =
|
||||
GetObjectExpressionMetadata(platform, objectType, exprType);
|
||||
if (&numberExpressionMetadata != &badExpressionMetadata) {
|
||||
return numberExpressionMetadata;
|
||||
}
|
||||
const auto& stringExpressionMetadata =
|
||||
GetObjectStrExpressionMetadata(platform, objectType, exprType);
|
||||
if (&stringExpressionMetadata != &badExpressionMetadata) {
|
||||
return stringExpressionMetadata;
|
||||
}
|
||||
return badExpressionMetadata;
|
||||
|
||||
return &numberExpressionMetadata != &badExpressionMetadata
|
||||
? numberExpressionMetadata
|
||||
: &stringExpressionMetadata != &badExpressionMetadata
|
||||
? stringExpressionMetadata
|
||||
: badExpressionMetadata;
|
||||
}
|
||||
|
||||
const gd::ExpressionMetadata&
|
||||
@@ -379,98 +380,14 @@ MetadataProvider::GetBehaviorAnyExpressionMetadata(const gd::Platform& platform,
|
||||
gd::String exprType) {
|
||||
const auto& numberExpressionMetadata =
|
||||
GetBehaviorExpressionMetadata(platform, autoType, exprType);
|
||||
if (&numberExpressionMetadata != &badExpressionMetadata) {
|
||||
return numberExpressionMetadata;
|
||||
}
|
||||
const auto& stringExpressionMetadata =
|
||||
GetBehaviorStrExpressionMetadata(platform, autoType, exprType);
|
||||
if (&stringExpressionMetadata != &badExpressionMetadata) {
|
||||
return stringExpressionMetadata;
|
||||
}
|
||||
return badExpressionMetadata;
|
||||
}
|
||||
|
||||
const gd::ExpressionMetadata& MetadataProvider::GetFunctionCallMetadata(
|
||||
const gd::Platform& platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
FunctionCallNode& node) {
|
||||
|
||||
if (!node.behaviorName.empty()) {
|
||||
gd::String behaviorType =
|
||||
GetTypeOfBehavior(globalObjectsContainer, objectsContainer, node.behaviorName);
|
||||
return MetadataProvider::GetBehaviorAnyExpressionMetadata(
|
||||
platform, behaviorType, node.functionName);
|
||||
}
|
||||
else if (!node.objectName.empty()) {
|
||||
gd::String objectType =
|
||||
GetTypeOfObject(globalObjectsContainer, objectsContainer, node.objectName);
|
||||
return MetadataProvider::GetObjectAnyExpressionMetadata(
|
||||
platform, objectType, node.functionName);
|
||||
}
|
||||
|
||||
return MetadataProvider::GetAnyExpressionMetadata(platform, node.functionName);
|
||||
}
|
||||
|
||||
const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
const gd::Platform& platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
FunctionCallNode& functionCall,
|
||||
ExpressionNode& parameter) {
|
||||
int parameterIndex = -1;
|
||||
for (int i = 0; i < functionCall.parameters.size(); i++) {
|
||||
if (functionCall.parameters.at(i).get() == ¶meter) {
|
||||
parameterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterIndex < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform,
|
||||
globalObjectsContainer,
|
||||
objectsContainer,
|
||||
functionCall,
|
||||
parameterIndex);
|
||||
}
|
||||
|
||||
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.
|
||||
size_t visibleParameterIndex = 0;
|
||||
size_t metadataParameterIndex =
|
||||
ExpressionParser2::WrittenParametersFirstIndex(
|
||||
functionCall.objectName, functionCall.behaviorName);
|
||||
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
|
||||
platform, globalObjectsContainer, objectsContainer, functionCall);
|
||||
|
||||
if (IsBadExpressionMetadata(metadata)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO use a badMetadata instead of a nullptr?
|
||||
const gd::ParameterMetadata* parameterMetadata = nullptr;
|
||||
while (metadataParameterIndex <
|
||||
metadata.parameters.size()) {
|
||||
if (!metadata.parameters[metadataParameterIndex]
|
||||
.IsCodeOnly()) {
|
||||
if (visibleParameterIndex == parameterIndex) {
|
||||
parameterMetadata = &metadata.parameters[metadataParameterIndex];
|
||||
}
|
||||
visibleParameterIndex++;
|
||||
}
|
||||
metadataParameterIndex++;
|
||||
}
|
||||
const int visibleParameterCount = visibleParameterIndex;
|
||||
// It can be null if there are too many parameters in the expression, this text node is
|
||||
// not actually linked to a parameter expected by the function call.
|
||||
return parameterMetadata;
|
||||
return &numberExpressionMetadata != &badExpressionMetadata
|
||||
? numberExpressionMetadata
|
||||
: &stringExpressionMetadata != &badExpressionMetadata
|
||||
? stringExpressionMetadata
|
||||
: badExpressionMetadata;
|
||||
}
|
||||
|
||||
MetadataProvider::~MetadataProvider() {}
|
||||
|
@@ -15,8 +15,6 @@ class ExpressionMetadata;
|
||||
class ExpressionMetadata;
|
||||
class Platform;
|
||||
class PlatformExtension;
|
||||
struct FunctionCallNode;
|
||||
struct ExpressionNode;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -236,26 +234,6 @@ class GD_CORE_API MetadataProvider {
|
||||
static const gd::ExpressionMetadata& GetObjectAnyExpressionMetadata(
|
||||
const gd::Platform& platform, gd::String objectType, gd::String exprType);
|
||||
|
||||
static const gd::ExpressionMetadata& GetFunctionCallMetadata(
|
||||
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::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
FunctionCallNode& functionCall,
|
||||
ExpressionNode& parameter);
|
||||
|
||||
static const gd::ParameterMetadata* GetFunctionCallParameterMetadata(
|
||||
const gd::Platform& platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
FunctionCallNode& functionCall,
|
||||
int parameterIndex);
|
||||
|
||||
/**
|
||||
* Get information about an expression from its type.
|
||||
* Works for behavior expressions.
|
||||
|
@@ -35,18 +35,4 @@ void ParameterMetadata::UnserializeFrom(const SerializerElement& element) {
|
||||
name = element.GetStringAttribute("name");
|
||||
}
|
||||
|
||||
// TODO factorize in a file with an enum and helpers?
|
||||
const gd::String ParameterMetadata::numberType = "number";
|
||||
const gd::String ParameterMetadata::stringType = "string";
|
||||
|
||||
const gd::String &ParameterMetadata::GetExpressionValueType(const gd::String ¶meterType) {
|
||||
if (parameterType == "number" || gd::ParameterMetadata::IsExpression("number", parameterType)) {
|
||||
return ParameterMetadata::numberType;
|
||||
}
|
||||
if (parameterType == "string" || gd::ParameterMetadata::IsExpression("string", parameterType)) {
|
||||
return ParameterMetadata::stringType;
|
||||
}
|
||||
return parameterType;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -207,15 +207,6 @@ class GD_CORE_API ParameterMetadata {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \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".
|
||||
*/
|
||||
static const gd::String &GetExpressionValueType(const gd::String ¶meterType);
|
||||
static const gd::String numberType;
|
||||
static const gd::String stringType;
|
||||
|
||||
/** \name Serialization
|
||||
*/
|
||||
///@{
|
||||
|
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace gd {
|
||||
void ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
gd::Project& project,
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
@@ -59,13 +59,13 @@ void ParameterMetadataTools::IterateOverParameters(
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const std::vector<gd::ParameterMetadata>& parametersMetadata,
|
||||
std::function<void(const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
const gd::String& parameterValue,
|
||||
const gd::String& lastObjectName)> fn) {
|
||||
IterateOverParametersWithIndex(
|
||||
parameters,
|
||||
parametersMetadata,
|
||||
[&fn](const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
const gd::String& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
fn(parameterMetadata, parameterValue, lastObjectName);
|
||||
@@ -76,17 +76,17 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const std::vector<gd::ParameterMetadata>& parametersMetadata,
|
||||
std::function<void(const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
const gd::String& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName)> fn) {
|
||||
gd::String lastObjectName = "";
|
||||
for (std::size_t pNb = 0; pNb < parametersMetadata.size(); ++pNb) {
|
||||
const gd::ParameterMetadata& parameterMetadata = parametersMetadata[pNb];
|
||||
const gd::Expression& parameterValue =
|
||||
const gd::String& parameterValue =
|
||||
pNb < parameters.size() ? parameters[pNb].GetPlainString() : "";
|
||||
const gd::Expression& parameterValueOrDefault =
|
||||
parameterValue.GetPlainString().empty() && parameterMetadata.optional
|
||||
? Expression(parameterMetadata.GetDefaultValue())
|
||||
const gd::String& parameterValueOrDefault =
|
||||
parameterValue.empty() && parameterMetadata.optional
|
||||
? parameterMetadata.GetDefaultValue()
|
||||
: parameterValue;
|
||||
|
||||
fn(parameterMetadata, parameterValueOrDefault, pNb, lastObjectName);
|
||||
@@ -97,7 +97,7 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
// Search "lastObjectName" in the codebase for other place where this
|
||||
// convention is enforced.
|
||||
if (gd::ParameterMetadata::IsObject(parameterMetadata.GetType()))
|
||||
lastObjectName = parameterValueOrDefault.GetPlainString();
|
||||
lastObjectName = parameterValueOrDefault;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,7 @@ namespace gd {
|
||||
class GD_CORE_API ParameterMetadataTools {
|
||||
public:
|
||||
static void ParametersToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
gd::Project& project,
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
||||
@@ -32,7 +32,7 @@ class GD_CORE_API ParameterMetadataTools {
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const std::vector<gd::ParameterMetadata>& parametersMetadata,
|
||||
std::function<void(const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
const gd::String& parameterValue,
|
||||
const gd::String& lastObjectName)> fn);
|
||||
|
||||
/**
|
||||
@@ -44,7 +44,7 @@ class GD_CORE_API ParameterMetadataTools {
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const std::vector<gd::ParameterMetadata>& parametersMetadata,
|
||||
std::function<void(const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
const gd::String& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName)> fn);
|
||||
|
||||
|
@@ -346,11 +346,6 @@ gd::BehaviorMetadata& PlatformExtension::GetBehaviorMetadata(
|
||||
return badBehaviorMetadata;
|
||||
}
|
||||
|
||||
bool PlatformExtension::HasBehavior(
|
||||
const gd::String& behaviorType) const {
|
||||
return behaviorsInfo.find(behaviorType) != behaviorsInfo.end();
|
||||
}
|
||||
|
||||
gd::EffectMetadata& PlatformExtension::GetEffectMetadata(
|
||||
const gd::String& effectName) {
|
||||
if (effectsMetadata.find(effectName) != effectsMetadata.end())
|
||||
@@ -380,7 +375,7 @@ gd::InstructionMetadata& PlatformExtension::AddDuplicatedAction(
|
||||
|
||||
auto copiedAction = actionsInfos.find(copiedNameWithNamespace);
|
||||
if (copiedAction == actionsInfos.end()) {
|
||||
gd::LogError("Could not find an action with name " +
|
||||
gd::LogWarning("Could not find an action with name " +
|
||||
copiedNameWithNamespace + " to copy.");
|
||||
} else {
|
||||
actionsInfos[newNameWithNamespace] = copiedAction->second;
|
||||
@@ -400,7 +395,7 @@ gd::InstructionMetadata& PlatformExtension::AddDuplicatedCondition(
|
||||
|
||||
auto copiedCondition = conditionsInfos.find(copiedNameWithNamespace);
|
||||
if (copiedCondition == conditionsInfos.end()) {
|
||||
gd::LogError("Could not find a condition with name " +
|
||||
gd::LogWarning("Could not find a condition with name " +
|
||||
copiedNameWithNamespace + " to copy.");
|
||||
} else {
|
||||
conditionsInfos[newNameWithNamespace] = copiedCondition->second;
|
||||
@@ -417,7 +412,7 @@ gd::ExpressionMetadata& PlatformExtension::AddDuplicatedExpression(
|
||||
|
||||
auto copiedExpression = expressionsInfos.find(copiedNameWithNamespace);
|
||||
if (copiedExpression == expressionsInfos.end()) {
|
||||
gd::LogError("Could not find an expression with name " +
|
||||
gd::LogWarning("Could not find an expression with name " +
|
||||
copiedNameWithNamespace + " to copy.");
|
||||
} else {
|
||||
expressionsInfos[newNameWithNamespace] = copiedExpression->second;
|
||||
@@ -434,7 +429,7 @@ gd::ExpressionMetadata& PlatformExtension::AddDuplicatedStrExpression(
|
||||
|
||||
auto copiedExpression = strExpressionsInfos.find(copiedNameWithNamespace);
|
||||
if (copiedExpression == strExpressionsInfos.end()) {
|
||||
gd::LogError("Could not find a string expression with name " +
|
||||
gd::LogWarning("Could not find a string expression with name " +
|
||||
copiedNameWithNamespace + " to copy.");
|
||||
} else {
|
||||
strExpressionsInfos[newNameWithNamespace] = copiedExpression->second;
|
||||
|
@@ -467,12 +467,6 @@ class GD_CORE_API PlatformExtension {
|
||||
*/
|
||||
BehaviorMetadata& GetBehaviorMetadata(const gd::String& behaviorType);
|
||||
|
||||
/**
|
||||
* \brief Return true if the extension contains a behavior associated to \a
|
||||
* behaviorType
|
||||
*/
|
||||
bool HasBehavior(const gd::String& behaviorType) const;
|
||||
|
||||
/**
|
||||
* \brief Return the metadata for the effect with the given name.
|
||||
*/
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
@@ -117,20 +118,27 @@ bool EventsBehaviorRenamer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
instruction.GetParameters(),
|
||||
metadata.GetParameters(),
|
||||
[&](const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
const gd::String& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
const gd::String& type = parameterMetadata.type;
|
||||
|
||||
if (gd::ParameterMetadata::IsBehavior(type)) {
|
||||
if (lastObjectName == objectName) {
|
||||
if (parameterValue.GetPlainString() == oldBehaviorName) {
|
||||
if (parameterValue == oldBehaviorName) {
|
||||
instruction.SetParameter(parameterIndex,
|
||||
gd::Expression(newBehaviorName));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto node = parameterValue.GetRootNode();
|
||||
gd::ExpressionParser2 parser(
|
||||
platform, GetGlobalObjectsContainer(), GetObjectsContainer());
|
||||
auto node =
|
||||
gd::ParameterMetadata::IsExpression("number", type)
|
||||
? parser.ParseExpression("number", parameterValue)
|
||||
: (gd::ParameterMetadata::IsExpression("string", type)
|
||||
? parser.ParseExpression("string", parameterValue)
|
||||
: std::unique_ptr<gd::ExpressionNode>());
|
||||
if (node) {
|
||||
ExpressionBehaviorRenamer renamer(GetGlobalObjectsContainer(),
|
||||
GetObjectsContainer(),
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
@@ -16,7 +17,6 @@
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -31,17 +31,7 @@ namespace gd {
|
||||
class GD_CORE_API ExpressionObjectsAnalyzer
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionObjectsAnalyzer(
|
||||
const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_,
|
||||
const gd::String &rootType_,
|
||||
EventsContext& context_) :
|
||||
platform(platform_),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
rootType(rootType_),
|
||||
context(context_){};
|
||||
ExpressionObjectsAnalyzer(EventsContext& context_) : context(context_){};
|
||||
virtual ~ExpressionObjectsAnalyzer(){};
|
||||
|
||||
protected:
|
||||
@@ -69,8 +59,7 @@ class GD_CORE_API ExpressionObjectsAnalyzer
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
|
||||
if (gd::ParameterMetadata::IsObject(type)) {
|
||||
if (gd::ParameterMetadata::IsObject(node.type)) {
|
||||
context.AddObjectName(node.identifierName);
|
||||
}
|
||||
}
|
||||
@@ -98,11 +87,6 @@ class GD_CORE_API ExpressionObjectsAnalyzer
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
|
||||
private:
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
const gd::String rootType;
|
||||
|
||||
EventsContext& context;
|
||||
};
|
||||
|
||||
@@ -118,7 +102,7 @@ bool EventsContextAnalyzer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
instruction.GetParameters(),
|
||||
instrInfo.parameters,
|
||||
[this](const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
const gd::String& parameterValue,
|
||||
const gd::String& lastObjectName) {
|
||||
AnalyzeParameter(platform,
|
||||
project,
|
||||
@@ -145,14 +129,16 @@ void EventsContextAnalyzer::AnalyzeParameter(
|
||||
if (ParameterMetadata::IsObject(type)) {
|
||||
context.AddObjectName(value);
|
||||
} else if (ParameterMetadata::IsExpression("number", type)) {
|
||||
auto node = parameter.GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", value);
|
||||
|
||||
ExpressionObjectsAnalyzer analyzer(platform, project, layout, "number", context);
|
||||
ExpressionObjectsAnalyzer analyzer(context);
|
||||
node->Visit(analyzer);
|
||||
} else if (ParameterMetadata::IsExpression("string", type)) {
|
||||
auto node = parameter.GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", value);
|
||||
|
||||
ExpressionObjectsAnalyzer analyzer(platform, project, layout, "string", context);
|
||||
ExpressionObjectsAnalyzer analyzer(context);
|
||||
node->Visit(analyzer);
|
||||
} else if (ParameterMetadata::IsBehavior(type)) {
|
||||
context.AddBehaviorName(lastObjectName, value);
|
||||
|
@@ -1,41 +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/EventsLeaderboardsLister.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool EventsLeaderboardsLister::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
const gd::InstructionMetadata& instrInfo =
|
||||
isCondition ? MetadataProvider::GetConditionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType())
|
||||
: MetadataProvider::GetActionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType());
|
||||
|
||||
for (int i = 0; i < instruction.GetParametersCount() &&
|
||||
i < instrInfo.GetParametersCount();
|
||||
++i)
|
||||
if (instrInfo.GetParameter(i).type == "leaderboardId") {
|
||||
leaderboardIds.insert(instruction.GetParameter(i).GetPlainString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EventsLeaderboardsLister::~EventsLeaderboardsLister() {}
|
||||
|
||||
} // namespace gd
|
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EventsLeaderboardsLister_H
|
||||
#define EventsLeaderboardsLister_H
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class Project;
|
||||
class EventsList;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief List the leaderboard ids in the instructions.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsLeaderboardsLister : public ArbitraryEventsWorker {
|
||||
public:
|
||||
EventsLeaderboardsLister(gd::Project& project_) : project(project_){};
|
||||
virtual ~EventsLeaderboardsLister();
|
||||
|
||||
/**
|
||||
* Return the values of all leaderboardIds found in the events.
|
||||
*/
|
||||
const std::set<gd::String>& GetLeaderboardIds() { return leaderboardIds; }
|
||||
|
||||
private:
|
||||
virtual bool DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition);
|
||||
|
||||
std::set<gd::String> leaderboardIds;
|
||||
gd::Project& project;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // EventsLeaderboardsLister_H
|
@@ -1,49 +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/EventsLeaderboardsRenamer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool EventsLeaderboardsRenamer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
const gd::InstructionMetadata& instrInfo =
|
||||
isCondition ? MetadataProvider::GetConditionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType())
|
||||
: MetadataProvider::GetActionMetadata(
|
||||
project.GetCurrentPlatform(), instruction.GetType());
|
||||
|
||||
for (int i = 0; i < instruction.GetParametersCount() &&
|
||||
i < instrInfo.GetParametersCount();
|
||||
++i) {
|
||||
const gd::ParameterMetadata parameter = instrInfo.GetParameter(i);
|
||||
|
||||
if (parameter.type == "leaderboardId") {
|
||||
const gd::String leaderboardId =
|
||||
instruction.GetParameter(i).GetPlainString();
|
||||
|
||||
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
|
||||
instruction.SetParameter(i, leaderboardIdMap[leaderboardId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EventsLeaderboardsRenamer::~EventsLeaderboardsRenamer() {}
|
||||
|
||||
} // namespace gd
|
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EventsLeaderboardsRenamer_H
|
||||
#define EventsLeaderboardsRenamer_H
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class Project;
|
||||
class EventsList;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Replace the leaderboard ids in the instructions.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsLeaderboardsRenamer : public ArbitraryEventsWorker {
|
||||
public:
|
||||
EventsLeaderboardsRenamer(
|
||||
gd::Project& project_,
|
||||
const std::map<gd::String, gd::String>& leaderboardIdMap_)
|
||||
: project(project_), leaderboardIdMap(leaderboardIdMap_){};
|
||||
virtual ~EventsLeaderboardsRenamer();
|
||||
|
||||
private:
|
||||
virtual bool DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition);
|
||||
|
||||
std::map<gd::String, gd::String> leaderboardIdMap;
|
||||
gd::Project& project;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // EventsLeaderboardsRenamer_H
|
@@ -11,15 +11,15 @@
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/IDE/Events/InstructionSentenceFormatter.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/InstructionSentenceFormatter.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -34,30 +34,18 @@ const gd::String EventsRefactorer::searchIgnoredCharacters = ";:,#()";
|
||||
*/
|
||||
class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionObjectRenamer(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_,
|
||||
const gd::String &rootType_,
|
||||
const gd::String& objectName_,
|
||||
ExpressionObjectRenamer(const gd::String& objectName_,
|
||||
const gd::String& objectNewName_)
|
||||
: platform(platform_),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
rootType(rootType_),
|
||||
hasDoneRenaming(false),
|
||||
: hasDoneRenaming(false),
|
||||
objectName(objectName_),
|
||||
objectNewName(objectNewName_){};
|
||||
virtual ~ExpressionObjectRenamer(){};
|
||||
|
||||
static bool Rename(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
const gd::String &rootType,
|
||||
gd::ExpressionNode& node,
|
||||
static bool Rename(gd::ExpressionNode& node,
|
||||
const gd::String& objectName,
|
||||
const gd::String& objectNewName) {
|
||||
if (gd::ExpressionValidator::HasNoErrors(platform, globalObjectsContainer, objectsContainer, rootType, node)) {
|
||||
ExpressionObjectRenamer renamer(platform, globalObjectsContainer, objectsContainer, rootType, objectName, objectNewName);
|
||||
if (ExpressionValidator::HasNoErrors(node)) {
|
||||
ExpressionObjectRenamer renamer(objectName, objectNewName);
|
||||
node.Visit(renamer);
|
||||
|
||||
return renamer.HasDoneRenaming();
|
||||
@@ -93,8 +81,7 @@ 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, globalObjectsContainer, objectsContainer, rootType, node);
|
||||
if (gd::ParameterMetadata::IsObject(type) &&
|
||||
if (gd::ParameterMetadata::IsObject(node.type) &&
|
||||
node.identifierName == objectName) {
|
||||
hasDoneRenaming = true;
|
||||
node.identifierName = objectNewName;
|
||||
@@ -121,11 +108,6 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
bool hasDoneRenaming;
|
||||
const gd::String& objectName;
|
||||
const gd::String& objectNewName;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
const gd::String rootType;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -136,27 +118,14 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
*/
|
||||
class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionObjectFinder(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_,
|
||||
const gd::String &rootType_,
|
||||
const gd::String& objectName_)
|
||||
: platform(platform_),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
rootType(rootType_),
|
||||
hasObject(false),
|
||||
objectName(objectName_){};
|
||||
ExpressionObjectFinder(const gd::String& objectName_)
|
||||
: hasObject(false), objectName(objectName_){};
|
||||
virtual ~ExpressionObjectFinder(){};
|
||||
|
||||
static bool CheckIfHasObject(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
const gd::String &rootType,
|
||||
gd::ExpressionNode& node,
|
||||
static bool CheckIfHasObject(gd::ExpressionNode& node,
|
||||
const gd::String& objectName) {
|
||||
if (gd::ExpressionValidator::HasNoErrors(platform, globalObjectsContainer, objectsContainer, rootType, node)) {
|
||||
ExpressionObjectFinder finder(platform, globalObjectsContainer, objectsContainer, rootType, objectName);
|
||||
if (ExpressionValidator::HasNoErrors(node)) {
|
||||
ExpressionObjectFinder finder(objectName);
|
||||
node.Visit(finder);
|
||||
|
||||
return finder.HasFoundObject();
|
||||
@@ -192,8 +161,7 @@ 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, globalObjectsContainer, objectsContainer, rootType, node);
|
||||
if (gd::ParameterMetadata::IsObject(type) &&
|
||||
if (gd::ParameterMetadata::IsObject(node.type) &&
|
||||
node.identifierName == objectName) {
|
||||
hasObject = true;
|
||||
}
|
||||
@@ -216,11 +184,6 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
|
||||
private:
|
||||
bool hasObject;
|
||||
const gd::String& objectName;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
const gd::String rootType;
|
||||
};
|
||||
|
||||
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
@@ -242,9 +205,11 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression(
|
||||
"number", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
actions[aId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
@@ -252,9 +217,11 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression(
|
||||
"string", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
actions[aId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
@@ -296,9 +263,11 @@ bool EventsRefactorer::RenameObjectInConditions(
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression(
|
||||
"number", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
conditions[cId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
@@ -306,9 +275,11 @@ bool EventsRefactorer::RenameObjectInConditions(
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression(
|
||||
"string", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
conditions[cId].SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
@@ -345,18 +316,20 @@ bool EventsRefactorer::RenameObjectInEventParameters(
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression("number",
|
||||
parameterMetadata.GetType())) {
|
||||
auto node = expression.GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", expression.GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression("string",
|
||||
parameterMetadata.GetType())) {
|
||||
auto node = expression.GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", expression.GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
}
|
||||
}
|
||||
@@ -432,9 +405,11 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
// Find object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression(
|
||||
"number", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(platform, project, layout, "number", *node, name)) {
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
break;
|
||||
}
|
||||
@@ -442,9 +417,11 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
// Find object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression(
|
||||
"string", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(platform, project, layout, "string", *node, name)) {
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
break;
|
||||
}
|
||||
@@ -492,9 +469,11 @@ bool EventsRefactorer::RemoveObjectInConditions(
|
||||
// Find object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression(
|
||||
"number", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(platform, project, layout, "number", *node, name)) {
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
break;
|
||||
}
|
||||
@@ -502,9 +481,11 @@ bool EventsRefactorer::RemoveObjectInConditions(
|
||||
// Find object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression(
|
||||
"string", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(platform, project, layout, "string", *node, name)) {
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
break;
|
||||
}
|
||||
@@ -554,19 +535,16 @@ void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
|
||||
gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::EventsList& events,
|
||||
gd::String toReplace,
|
||||
gd::String newString,
|
||||
bool matchCase,
|
||||
bool inConditions,
|
||||
bool inActions,
|
||||
bool inEventStrings) {
|
||||
vector<EventsSearchResult> modifiedEvents;
|
||||
void EventsRefactorer::ReplaceStringInEvents(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::EventsList& events,
|
||||
gd::String toReplace,
|
||||
gd::String newString,
|
||||
bool matchCase,
|
||||
bool inConditions,
|
||||
bool inActions,
|
||||
bool inEventStrings) {
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
bool eventModified = false;
|
||||
if (inConditions) {
|
||||
vector<gd::InstructionsList*> conditionsVectors =
|
||||
events[i].GetAllConditionsVectors();
|
||||
@@ -578,13 +556,6 @@ std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
|
||||
toReplace,
|
||||
newString,
|
||||
matchCase);
|
||||
if (conditionsModified && !eventModified) {
|
||||
modifiedEvents.push_back(EventsSearchResult(
|
||||
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
|
||||
&events,
|
||||
i));
|
||||
eventModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,45 +569,25 @@ std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
|
||||
toReplace,
|
||||
newString,
|
||||
matchCase);
|
||||
if (actionsModified && !eventModified) {
|
||||
modifiedEvents.push_back(EventsSearchResult(
|
||||
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
|
||||
&events,
|
||||
i));
|
||||
eventModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inEventStrings) {
|
||||
bool eventStringModified = ReplaceStringInEventSearchableStrings(
|
||||
project, layout, events[i], toReplace, newString, matchCase);
|
||||
if (eventStringModified && !eventModified) {
|
||||
modifiedEvents.push_back(EventsSearchResult(
|
||||
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
|
||||
&events,
|
||||
i));
|
||||
eventModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (events[i].CanHaveSubEvents()) {
|
||||
std::vector<EventsSearchResult> modifiedSubEvent =
|
||||
ReplaceStringInEvents(project,
|
||||
layout,
|
||||
events[i].GetSubEvents(),
|
||||
toReplace,
|
||||
newString,
|
||||
matchCase,
|
||||
inConditions,
|
||||
inActions,
|
||||
inEventStrings);
|
||||
std::copy(modifiedSubEvent.begin(),
|
||||
modifiedSubEvent.end(),
|
||||
std::back_inserter(modifiedEvents));
|
||||
}
|
||||
if (events[i].CanHaveSubEvents())
|
||||
ReplaceStringInEvents(project,
|
||||
layout,
|
||||
events[i].GetSubEvents(),
|
||||
toReplace,
|
||||
newString,
|
||||
matchCase,
|
||||
inConditions,
|
||||
inActions,
|
||||
inEventStrings);
|
||||
}
|
||||
return modifiedEvents;
|
||||
}
|
||||
|
||||
gd::String ReplaceAllOccurencesCaseUnsensitive(gd::String context,
|
||||
@@ -767,16 +718,14 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
bool inEventSentences) {
|
||||
vector<EventsSearchResult> results;
|
||||
|
||||
const gd::String& ignored_characters =
|
||||
EventsRefactorer::searchIgnoredCharacters;
|
||||
const gd::String& ignored_characters = EventsRefactorer::searchIgnoredCharacters;
|
||||
|
||||
search.replace_if(
|
||||
search.begin(),
|
||||
search.end(),
|
||||
[ignored_characters](const char& c) {
|
||||
return ignored_characters.find(c) != gd::String::npos;
|
||||
},
|
||||
"");
|
||||
search.replace_if(search.begin(),
|
||||
search.end(),
|
||||
[ignored_characters](const char &c) {
|
||||
return ignored_characters.find(c) != gd::String::npos;
|
||||
},
|
||||
"");
|
||||
search = search.LeftTrim().RightTrim();
|
||||
search.RemoveConsecutiveOccurrences(search.begin(), search.end(), ' ');
|
||||
|
||||
@@ -788,11 +737,8 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
events[i].GetAllConditionsVectors();
|
||||
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
|
||||
if (!eventAddedInResults &&
|
||||
SearchStringInConditions(platform,
|
||||
*conditionsVectors[j],
|
||||
search,
|
||||
matchCase,
|
||||
inEventSentences)) {
|
||||
SearchStringInConditions(
|
||||
platform, *conditionsVectors[j], search, matchCase, inEventSentences)) {
|
||||
results.push_back(EventsSearchResult(
|
||||
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
|
||||
&events,
|
||||
@@ -805,11 +751,9 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
vector<gd::InstructionsList*> actionsVectors =
|
||||
events[i].GetAllActionsVectors();
|
||||
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
|
||||
if (!eventAddedInResults && SearchStringInActions(platform,
|
||||
*actionsVectors[j],
|
||||
search,
|
||||
matchCase,
|
||||
inEventSentences)) {
|
||||
if (!eventAddedInResults &&
|
||||
SearchStringInActions(
|
||||
platform, *actionsVectors[j], search, matchCase, inEventSentences)) {
|
||||
results.push_back(EventsSearchResult(
|
||||
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
|
||||
&events,
|
||||
@@ -846,11 +790,12 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
return results;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::SearchStringInActions(const gd::Platform& platform,
|
||||
gd::InstructionsList& actions,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool inSentences) {
|
||||
bool EventsRefactorer::SearchStringInActions(
|
||||
const gd::Platform& platform,
|
||||
gd::InstructionsList& actions,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool inSentences) {
|
||||
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
|
||||
for (std::size_t pNb = 0; pNb < actions[aId].GetParameters().size();
|
||||
++pNb) {
|
||||
@@ -881,30 +826,27 @@ bool EventsRefactorer::SearchStringInActions(const gd::Platform& platform,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::SearchStringInFormattedText(const gd::Platform& platform,
|
||||
gd::Instruction& instruction,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool isCondition) {
|
||||
bool EventsRefactorer::SearchStringInFormattedText(
|
||||
const gd::Platform& platform,
|
||||
gd::Instruction& instruction,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool isCondition) {
|
||||
const auto& metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
gd::String completeSentence =
|
||||
gd::InstructionSentenceFormatter::Get()->GetFullText(instruction,
|
||||
metadata);
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
gd::String completeSentence = gd::InstructionSentenceFormatter::Get()->GetFullText(instruction, metadata);
|
||||
|
||||
const gd::String& ignored_characters =
|
||||
EventsRefactorer::searchIgnoredCharacters;
|
||||
const gd::String& ignored_characters = EventsRefactorer::searchIgnoredCharacters;
|
||||
|
||||
completeSentence.replace_if(
|
||||
completeSentence.begin(),
|
||||
completeSentence.end(),
|
||||
[ignored_characters](const char& c) {
|
||||
return ignored_characters.find(c) != gd::String::npos;
|
||||
},
|
||||
"");
|
||||
completeSentence.replace_if(completeSentence.begin(),
|
||||
completeSentence.end(),
|
||||
[ignored_characters](const char &c) {
|
||||
return ignored_characters.find(c) != gd::String::npos;
|
||||
},
|
||||
"");
|
||||
|
||||
completeSentence.RemoveConsecutiveOccurrences(
|
||||
completeSentence.begin(), completeSentence.end(), ' ');
|
||||
|
@@ -7,7 +7,6 @@
|
||||
#define GDCORE_EVENTSREFACTORER_H
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -19,7 +18,7 @@ class ExternalEvents;
|
||||
class BaseEvent;
|
||||
class Instruction;
|
||||
typedef std::shared_ptr<gd::BaseEvent> BaseEventSPtr;
|
||||
} // namespace gd
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -44,11 +43,10 @@ class GD_CORE_API EventsSearchResult {
|
||||
bool IsEventsListValid() const { return eventsList != nullptr; }
|
||||
|
||||
/**
|
||||
* \brief Get the events list containing the event pointed by the
|
||||
* EventsSearchResult. \warning Only call this when IsEventsListValid returns
|
||||
* true.
|
||||
* \brief Get the events list containing the event pointed by the EventsSearchResult.
|
||||
* \warning Only call this when IsEventsListValid returns true.
|
||||
*/
|
||||
const gd::EventsList& GetEventsList() const { return *eventsList; }
|
||||
const gd::EventsList & GetEventsList() const { return *eventsList; }
|
||||
|
||||
std::size_t GetPositionInList() const { return positionInList; }
|
||||
|
||||
@@ -58,7 +56,7 @@ class GD_CORE_API EventsSearchResult {
|
||||
* \brief Get the event pointed by the EventsSearchResult.
|
||||
* \warning Only call this when IsEventValid returns true.
|
||||
*/
|
||||
const gd::BaseEvent& GetEvent() const { return *event.lock(); }
|
||||
const gd::BaseEvent & GetEvent() const { return *event.lock(); }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -100,31 +98,27 @@ class GD_CORE_API EventsRefactorer {
|
||||
* \return A vector containing EventsSearchResult objects filled with events
|
||||
* containing the string
|
||||
*/
|
||||
static std::vector<EventsSearchResult> SearchInEvents(
|
||||
const gd::Platform& platform,
|
||||
gd::EventsList& events,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool inConditions,
|
||||
bool inActions,
|
||||
bool inEventStrings,
|
||||
bool inEventSentences);
|
||||
static std::vector<EventsSearchResult> SearchInEvents(const gd::Platform& platform,
|
||||
gd::EventsList& events,
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool inConditions,
|
||||
bool inActions,
|
||||
bool inEventStrings,
|
||||
bool inEventSentences);
|
||||
|
||||
/**
|
||||
* Replace all occurrences of a gd::String in events
|
||||
*
|
||||
* \return A vector of all modified events.
|
||||
*/
|
||||
static std::vector<EventsSearchResult> ReplaceStringInEvents(
|
||||
gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::EventsList& events,
|
||||
gd::String toReplace,
|
||||
gd::String newString,
|
||||
bool matchCase,
|
||||
bool inConditions,
|
||||
bool inActions,
|
||||
bool inEventString);
|
||||
static void ReplaceStringInEvents(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::EventsList& events,
|
||||
gd::String toReplace,
|
||||
gd::String newString,
|
||||
bool matchCase,
|
||||
bool inConditions,
|
||||
bool inActions,
|
||||
bool inEventString);
|
||||
|
||||
virtual ~EventsRefactorer(){};
|
||||
|
||||
@@ -154,21 +148,20 @@ class GD_CORE_API EventsRefactorer {
|
||||
gd::InstructionsList& instructions,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
/**
|
||||
/**
|
||||
* Replace all occurrences of an object name by another name in an expression
|
||||
* with the specified metadata
|
||||
* ( include : objects or objects in math/text expressions ).
|
||||
*
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RenameObjectInEventParameters(
|
||||
const gd::Platform& platform,
|
||||
gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::Expression& expression,
|
||||
gd::ParameterMetadata parameterMetadata,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
static bool RenameObjectInEventParameters(const gd::Platform& platform,
|
||||
gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::Expression& expression,
|
||||
gd::ParameterMetadata parameterMetadata,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
|
||||
/**
|
||||
* Remove all conditions of the list using an object
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include "EventsVariablesFinder.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
@@ -31,16 +32,10 @@ namespace gd {
|
||||
class GD_CORE_API ExpressionParameterSearcher
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionParameterSearcher(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_,
|
||||
std::set<gd::String>& results_,
|
||||
ExpressionParameterSearcher(std::set<gd::String>& results_,
|
||||
const gd::String& parameterType_,
|
||||
const gd::String& objectName_ = "")
|
||||
: platform(platform_),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
results(results_),
|
||||
: results(results_),
|
||||
parameterType(parameterType_),
|
||||
objectName(objectName_){};
|
||||
virtual ~ExpressionParameterSearcher(){};
|
||||
@@ -73,22 +68,10 @@ class GD_CORE_API ExpressionParameterSearcher
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
bool considerFunction = objectName.empty() || node.objectName == objectName;
|
||||
|
||||
const gd::ExpressionMetadata &metadata = node.objectName.empty() ?
|
||||
MetadataProvider::GetAnyExpressionMetadata(platform, node.functionName) :
|
||||
MetadataProvider::GetObjectAnyExpressionMetadata(
|
||||
platform,
|
||||
GetTypeOfObject(globalObjectsContainer, objectsContainer, objectName),
|
||||
node.functionName);
|
||||
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node.parameters.size() &&
|
||||
i < metadata.parameters.size();
|
||||
i < node.expressionMetadata.parameters.size();
|
||||
++i) {
|
||||
auto& parameterMetadata = metadata.parameters[i];
|
||||
auto& parameterMetadata = node.expressionMetadata.parameters[i];
|
||||
if (considerFunction && parameterMetadata.GetType() == parameterType) {
|
||||
// Store the value of the parameter
|
||||
results.insert(
|
||||
@@ -101,10 +84,6 @@ class GD_CORE_API ExpressionParameterSearcher
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
|
||||
private:
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
|
||||
std::set<gd::String>& results; ///< Reference to the std::set where argument
|
||||
///< values must be stored.
|
||||
gd::String parameterType; ///< The type of the parameters to be searched for.
|
||||
@@ -186,18 +165,24 @@ std::set<gd::String> EventsVariablesFinder::FindArgumentsInInstructions(
|
||||
}
|
||||
// Search in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type) ||
|
||||
ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
auto node = instructions[aId].GetParameter(pNb).GetRootNode();
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression(
|
||||
"number", instructions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
ExpressionParameterSearcher searcher(
|
||||
platform,
|
||||
project,
|
||||
layout,
|
||||
results,
|
||||
parameterType,
|
||||
objectName);
|
||||
results, parameterType, objectName);
|
||||
node->Visit(searcher);
|
||||
}
|
||||
// Search in gd::String expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression(
|
||||
"number", instructions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
ExpressionParameterSearcher searcher(
|
||||
results, parameterType, objectName);
|
||||
node->Visit(searcher);
|
||||
}
|
||||
// Remember the value of the last "object" parameter.
|
||||
|
@@ -15,8 +15,6 @@
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
@@ -292,11 +290,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
* and returns completions for it.
|
||||
*/
|
||||
static std::vector<ExpressionCompletionDescription>
|
||||
GetCompletionDescriptionsFor(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
const gd::String &rootType,
|
||||
gd::ExpressionNode& node,
|
||||
GetCompletionDescriptionsFor(gd::ExpressionNode& node,
|
||||
size_t searchedPosition) {
|
||||
gd::ExpressionNodeLocationFinder finder(searchedPosition);
|
||||
node.Visit(finder);
|
||||
@@ -309,7 +303,6 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
|
||||
gd::ExpressionNode* maybeParentNodeAtLocation = finder.GetParentNode();
|
||||
gd::ExpressionCompletionFinder autocompletionProvider(
|
||||
platform, globalObjectsContainer, objectsContainer, rootType,
|
||||
searchedPosition, maybeParentNodeAtLocation);
|
||||
nodeAtLocation->Visit(autocompletionProvider);
|
||||
return autocompletionProvider.GetCompletionDescriptions();
|
||||
@@ -327,21 +320,19 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
// No completions.
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
node.type, "", searchedPosition + 1, searchedPosition + 1));
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {
|
||||
// No completions
|
||||
@@ -353,7 +344,6 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
FunctionCallNode* functionCall =
|
||||
dynamic_cast<FunctionCallNode*>(maybeParentNodeAtLocation);
|
||||
if (functionCall != nullptr) {
|
||||
|
||||
int parameterIndex = -1;
|
||||
for (int i = 0; i < functionCall->parameters.size(); i++) {
|
||||
if (functionCall->parameters.at(i).get() == &node) {
|
||||
@@ -369,16 +359,15 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
size_t metadataParameterIndex =
|
||||
ExpressionParser2::WrittenParametersFirstIndex(
|
||||
functionCall->objectName, functionCall->behaviorName);
|
||||
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
|
||||
platform, globalObjectsContainer, objectsContainer, *functionCall);
|
||||
|
||||
const gd::ParameterMetadata* parameterMetadata = nullptr;
|
||||
while (metadataParameterIndex <
|
||||
metadata.parameters.size()) {
|
||||
if (!metadata.parameters[metadataParameterIndex]
|
||||
functionCall->expressionMetadata.parameters.size()) {
|
||||
if (!functionCall->expressionMetadata.parameters[metadataParameterIndex]
|
||||
.IsCodeOnly()) {
|
||||
if (visibleParameterIndex == parameterIndex) {
|
||||
parameterMetadata = &metadata.parameters[metadataParameterIndex];
|
||||
parameterMetadata = &functionCall->expressionMetadata
|
||||
.parameters[metadataParameterIndex];
|
||||
}
|
||||
visibleParameterIndex++;
|
||||
}
|
||||
@@ -409,21 +398,12 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform,
|
||||
globalObjectsContainer,
|
||||
objectsContainer,
|
||||
// Variable fields doesn't use expression completion,
|
||||
// so the object will be found inside the expression itself.
|
||||
"",
|
||||
node);
|
||||
completions.push_back(ExpressionCompletionDescription::ForVariable(
|
||||
type,
|
||||
node.type,
|
||||
node.name,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition(),
|
||||
objectName));
|
||||
node.objectName));
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
// No completions
|
||||
@@ -433,69 +413,35 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
// No completions
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
|
||||
if (gd::ParameterMetadata::IsObject(type)) {
|
||||
if (gd::ParameterMetadata::IsObject(node.type)) {
|
||||
// Only show completions of objects if an object is required
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
type,
|
||||
node.type,
|
||||
node.identifierName,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition()));
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
|
||||
platform,
|
||||
globalObjectsContainer,
|
||||
objectsContainer,
|
||||
// Variable fields doesn't use expression completion,
|
||||
// so the object will be found inside the expression itself.
|
||||
"",
|
||||
node);
|
||||
completions.push_back(ExpressionCompletionDescription::ForVariable(
|
||||
type,
|
||||
} else {
|
||||
// Show completions for expressions and objects otherwise.
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type,
|
||||
node.identifierName,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition(),
|
||||
objectName));
|
||||
} else {
|
||||
// Object function or behavior name
|
||||
if (IsCaretOn(node.identifierNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
type,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation.GetStartPosition(),
|
||||
node.identifierNameLocation.GetEndPosition()));
|
||||
if (!node.identifierNameDotLocation.IsValid()) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
type,
|
||||
node.identifierName,
|
||||
node.identifierNameLocation.GetStartPosition(),
|
||||
node.identifierNameLocation.GetEndPosition()));
|
||||
}
|
||||
} else if (IsCaretOn(node.identifierNameDotLocation) ||
|
||||
IsCaretOn(node.childIdentifierNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForBehavior(
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation.GetStartPosition(),
|
||||
node.childIdentifierNameLocation.GetEndPosition(),
|
||||
node.identifierName));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
type,
|
||||
node.childIdentifierName,
|
||||
node.childIdentifierNameLocation.GetStartPosition(),
|
||||
node.childIdentifierNameLocation.GetEndPosition(),
|
||||
node.identifierName));
|
||||
}
|
||||
node.location.GetEndPosition()));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type,
|
||||
node.identifierName,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition()));
|
||||
}
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
|
||||
if (!node.behaviorFunctionName.empty() ||
|
||||
node.behaviorNameNamespaceSeparatorLocation.IsValid()) {
|
||||
// Behavior function (or behavior function being written, with the
|
||||
// function name missing)
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
type,
|
||||
node.type,
|
||||
node.objectName,
|
||||
node.objectNameLocation.GetStartPosition(),
|
||||
node.objectNameLocation.GetEndPosition()));
|
||||
@@ -509,7 +455,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
} else if (IsCaretOn(node.behaviorNameNamespaceSeparatorLocation) ||
|
||||
IsCaretOn(node.behaviorFunctionNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
type,
|
||||
node.type,
|
||||
node.behaviorFunctionName,
|
||||
node.behaviorFunctionNameLocation.GetStartPosition(),
|
||||
node.behaviorFunctionNameLocation.GetEndPosition(),
|
||||
@@ -520,7 +466,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
// Object function or behavior name
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
type,
|
||||
node.type,
|
||||
node.objectName,
|
||||
node.objectNameLocation.GetStartPosition(),
|
||||
node.objectNameLocation.GetEndPosition()));
|
||||
@@ -532,7 +478,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
|
||||
node.objectName));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
type,
|
||||
node.type,
|
||||
node.objectFunctionOrBehaviorName,
|
||||
node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
|
||||
node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
|
||||
@@ -541,7 +487,6 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
|
||||
bool isCaretOnParenthesis = IsCaretOn(node.openingParenthesisLocation) ||
|
||||
IsCaretOn(node.closingParenthesisLocation);
|
||||
|
||||
@@ -549,7 +494,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
// Behavior function
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
type,
|
||||
node.type,
|
||||
node.objectName,
|
||||
node.objectNameLocation.GetStartPosition(),
|
||||
node.objectNameLocation.GetEndPosition()));
|
||||
@@ -562,7 +507,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
node.objectName));
|
||||
} else {
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
type,
|
||||
node.type,
|
||||
node.functionName,
|
||||
node.functionNameLocation.GetStartPosition(),
|
||||
node.functionNameLocation.GetEndPosition(),
|
||||
@@ -574,7 +519,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
// Object function
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
type,
|
||||
node.type,
|
||||
node.objectName,
|
||||
node.objectNameLocation.GetStartPosition(),
|
||||
node.objectNameLocation.GetEndPosition()));
|
||||
@@ -593,7 +538,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
type,
|
||||
node.type,
|
||||
node.functionName,
|
||||
node.functionNameLocation.GetStartPosition(),
|
||||
node.functionNameLocation.GetEndPosition(),
|
||||
@@ -603,7 +548,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
} else {
|
||||
// Free function
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
type,
|
||||
node.type,
|
||||
node.functionName,
|
||||
node.functionNameLocation.GetStartPosition(),
|
||||
node.functionNameLocation.GetEndPosition())
|
||||
@@ -611,14 +556,13 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
type,
|
||||
node.type,
|
||||
node.text,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition()));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
type,
|
||||
node.type,
|
||||
node.text,
|
||||
node.location.GetStartPosition(),
|
||||
node.location.GetEndPosition()));
|
||||
@@ -634,27 +578,14 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
(inclusive && searchedPosition <= location.GetEndPosition())));
|
||||
}
|
||||
|
||||
ExpressionCompletionFinder(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_,
|
||||
const gd::String &rootType_,
|
||||
size_t searchedPosition_,
|
||||
ExpressionCompletionFinder(size_t searchedPosition_,
|
||||
gd::ExpressionNode* maybeParentNodeAtLocation_)
|
||||
: platform(platform_),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
rootType(rootType_),
|
||||
searchedPosition(searchedPosition_),
|
||||
: searchedPosition(searchedPosition_),
|
||||
maybeParentNodeAtLocation(maybeParentNodeAtLocation_){};
|
||||
|
||||
std::vector<ExpressionCompletionDescription> completions;
|
||||
size_t searchedPosition;
|
||||
gd::ExpressionNode* maybeParentNodeAtLocation;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
const gd::String rootType;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONLEFTSIDETYPEFINDER_H
|
||||
#define GDCORE_EXPRESSIONLEFTSIDETYPEFINDER_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
class Platform;
|
||||
class ParameterMetadata;
|
||||
class ExpressionMetadata;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Find the type of the node at the left side of operations.
|
||||
*
|
||||
* \see gd::ExpressionTypeFinder
|
||||
*/
|
||||
class GD_CORE_API ExpressionLeftSideTypeFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Helper function to find the type of the node at the left side of
|
||||
* operations.
|
||||
*/
|
||||
static const gd::String GetType(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
gd::ExpressionNode& node) {
|
||||
gd::ExpressionLeftSideTypeFinder typeFinder(
|
||||
platform, globalObjectsContainer, objectsContainer);
|
||||
node.Visit(typeFinder);
|
||||
return typeFinder.GetType();
|
||||
}
|
||||
|
||||
virtual ~ExpressionLeftSideTypeFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionLeftSideTypeFinder(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_)
|
||||
: platform(platform_),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
type("unknown") {};
|
||||
|
||||
const gd::String &GetType() {
|
||||
return type;
|
||||
};
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
node.expression->Visit(*this);
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
node.leftHandSide->Visit(*this);
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
node.factor->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
node.expression->Visit(*this);
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {
|
||||
type = "number";
|
||||
}
|
||||
void OnVisitTextNode(TextNode& node) override {
|
||||
type = "string";
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
|
||||
platform, globalObjectsContainer, objectsContainer, node);
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
|
||||
type = "unknown";
|
||||
}
|
||||
else {
|
||||
type = metadata.GetReturnType();
|
||||
}
|
||||
}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
type = "unknown";
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
type = "unknown";
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
type = "unknown";
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {
|
||||
type = "unknown";
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
type = "unknown";
|
||||
}
|
||||
|
||||
private:
|
||||
gd::String type;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
const gd::String rootType;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONLEFTSIDETYPEFINDER_H
|
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Expression.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/Project.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
// TODO factorize in a file with an enum and helpers?
|
||||
const gd::String ExpressionTypeFinder::unknownType = "unknown";
|
||||
const gd::String ExpressionTypeFinder::numberType = "number";
|
||||
const gd::String ExpressionTypeFinder::stringType = "string";
|
||||
const gd::String ExpressionTypeFinder::numberOrStringType = "number|string";
|
||||
|
||||
} // namespace gd
|
@@ -1,198 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONTYPEFINDER_H
|
||||
#define GDCORE_EXPRESSIONTYPEFINDER_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/IDE/Events/ExpressionLeftSideTypeFinder.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
class Platform;
|
||||
class ParameterMetadata;
|
||||
class ExpressionMetadata;
|
||||
} // namespace gd
|
||||
|
||||
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
|
||||
* (using ExpressionLeftSideTypeFinder)
|
||||
*
|
||||
* This logic was built with the constraint of following a parser that can't
|
||||
* know the right side. Now that it is extracted, it could be enhanced if needed.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Helper function to find the type of the expression or
|
||||
* sub-expression that a given node represents.
|
||||
*/
|
||||
static const gd::String GetType(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
const gd::String &rootType,
|
||||
gd::ExpressionNode& node) {
|
||||
gd::ExpressionTypeFinder typeFinder(
|
||||
platform, globalObjectsContainer, objectsContainer, rootType);
|
||||
node.Visit(typeFinder);
|
||||
return typeFinder.GetType();
|
||||
}
|
||||
|
||||
virtual ~ExpressionTypeFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionTypeFinder(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_,
|
||||
const gd::String &rootType_)
|
||||
: platform(platform_),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
rootType(rootType_),
|
||||
type(ExpressionTypeFinder::unknownType),
|
||||
child(nullptr) {};
|
||||
|
||||
const gd::String &GetType() {
|
||||
return gd::ParameterMetadata::GetExpressionValueType(type);
|
||||
};
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
VisitParent(node);
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
VisitParent(node);
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
VisitParent(node);
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {
|
||||
type = ExpressionTypeFinder::numberType;
|
||||
}
|
||||
void OnVisitTextNode(TextNode& node) override {
|
||||
type = ExpressionTypeFinder::stringType;
|
||||
}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
VisitParent(node);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
VisitParent(node);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
VisitParent(node);
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {
|
||||
VisitParent(node);
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
VisitParent(node);
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
if (child == nullptr) {
|
||||
type = ExpressionTypeFinder::unknownType;
|
||||
}
|
||||
auto leftSideType = gd::ExpressionLeftSideTypeFinder::GetType(
|
||||
platform,
|
||||
globalObjectsContainer,
|
||||
objectsContainer,
|
||||
node);
|
||||
if (leftSideType == ExpressionTypeFinder::numberType
|
||||
|| leftSideType == ExpressionTypeFinder::stringType) {
|
||||
type = leftSideType;
|
||||
}
|
||||
else {
|
||||
type = ExpressionTypeFinder::numberOrStringType;
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
if (child == nullptr) {
|
||||
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
|
||||
platform, globalObjectsContainer, objectsContainer, node);
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
|
||||
VisitParent(node);
|
||||
}
|
||||
else {
|
||||
type = metadata.GetReturnType();
|
||||
}
|
||||
}
|
||||
else {
|
||||
const gd::ParameterMetadata* parameterMetadata =
|
||||
gd::MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform,
|
||||
globalObjectsContainer,
|
||||
objectsContainer,
|
||||
node,
|
||||
*child);
|
||||
if (parameterMetadata == nullptr || parameterMetadata->GetType().empty()) {
|
||||
type = ExpressionTypeFinder::unknownType;
|
||||
}
|
||||
else {
|
||||
type = parameterMetadata->GetType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
inline void VisitParent(ExpressionNode& node) {
|
||||
child = &node;
|
||||
if (node.parent != nullptr) {
|
||||
node.parent->Visit(*this);
|
||||
}
|
||||
else if (rootType == ExpressionTypeFinder::numberOrStringType) {
|
||||
auto leftSideType = gd::ExpressionLeftSideTypeFinder::GetType(
|
||||
platform,
|
||||
globalObjectsContainer,
|
||||
objectsContainer,
|
||||
node);
|
||||
if (leftSideType == ExpressionTypeFinder::numberType
|
||||
|| leftSideType == ExpressionTypeFinder::stringType) {
|
||||
type = leftSideType;
|
||||
}
|
||||
else {
|
||||
type = rootType;
|
||||
}
|
||||
}
|
||||
else {
|
||||
type = rootType;
|
||||
}
|
||||
}
|
||||
|
||||
static const gd::String unknownType;
|
||||
static const gd::String numberType;
|
||||
static const gd::String stringType;
|
||||
static const gd::String numberOrStringType;
|
||||
|
||||
gd::String type;
|
||||
ExpressionNode *child;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
const gd::String rootType;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONTYPEFINDER_H
|
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Expression.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/Project.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Return the minimum number of parameters, starting from a given parameter
|
||||
* (by convention, 1 for object functions and 2 for behavior functions).
|
||||
*/
|
||||
size_t GetMinimumParametersNumber(
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
size_t initialParameterIndex) {
|
||||
size_t nb = 0;
|
||||
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
|
||||
if (!parameters[i].optional && !parameters[i].codeOnly) nb++;
|
||||
}
|
||||
|
||||
return nb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of parameters, starting from a given parameter
|
||||
* (by convention, 1 for object functions and 2 for behavior functions).
|
||||
*/
|
||||
size_t GetMaximumParametersNumber(
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
size_t initialParameterIndex) {
|
||||
size_t nb = 0;
|
||||
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
|
||||
if (!parameters[i].codeOnly) nb++;
|
||||
}
|
||||
|
||||
return nb;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (!function.objectName.empty()) {
|
||||
// If the function needs a capability on the object that may not be covered
|
||||
// by all objects, check it now.
|
||||
if (!metadata.GetRequiredBaseObjectCapability().empty()) {
|
||||
const gd::ObjectMetadata &objectMetadata =
|
||||
MetadataProvider::GetObjectMetadata(platform, objectType);
|
||||
|
||||
if (objectMetadata.IsUnsupportedBaseObjectCapability(
|
||||
metadata.GetRequiredBaseObjectCapability())) {
|
||||
RaiseTypeError(
|
||||
_("This expression exists, but it can't be used on this object."),
|
||||
function.objectNameLocation);
|
||||
return StringToType(metadata.GetReturnType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Type returnType = StringToType(metadata.GetReturnType());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Validate the type of the function
|
||||
if (returnType == Type::Number) {
|
||||
if (parentType == Type::String) {
|
||||
RaiseTypeError(
|
||||
_("You tried to use an expression that returns a number, but a "
|
||||
"string is expected. Use `ToString` if you need to convert a "
|
||||
"number to a string."),
|
||||
function.location);
|
||||
return returnType;
|
||||
}
|
||||
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);
|
||||
return returnType;
|
||||
}
|
||||
} else if (returnType == Type::String) {
|
||||
if (parentType == Type::Number) {
|
||||
RaiseTypeError(
|
||||
_("You tried to use an expression that returns a string, but a "
|
||||
"number is expected. Use `ToNumber` if you need to convert a "
|
||||
"string to a number."),
|
||||
function.location);
|
||||
return returnType;
|
||||
}
|
||||
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);
|
||||
return returnType;
|
||||
}
|
||||
} else {
|
||||
if (parentType != returnType) {
|
||||
RaiseTypeError(
|
||||
_("You tried to use an expression with the wrong return type:") + " " +
|
||||
TypeToString(returnType),
|
||||
function.location);
|
||||
return returnType;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate parameters count
|
||||
size_t minParametersCount = GetMinimumParametersNumber(
|
||||
metadata.parameters,
|
||||
ExpressionParser2::WrittenParametersFirstIndex(function.objectName, function.behaviorName));
|
||||
size_t maxParametersCount = GetMaximumParametersNumber(
|
||||
metadata.parameters,
|
||||
ExpressionParser2::WrittenParametersFirstIndex(function.objectName, function.behaviorName));
|
||||
if (function.parameters.size() < minParametersCount ||
|
||||
function.parameters.size() > maxParametersCount) {
|
||||
gd::String expectedCountMessage =
|
||||
minParametersCount == maxParametersCount
|
||||
? _("The number of parameters must be exactly ") +
|
||||
gd::String::From(minParametersCount)
|
||||
: _("The number of parameters must be: ") +
|
||||
gd::String::From(minParametersCount) + "-" +
|
||||
gd::String::From(maxParametersCount);
|
||||
|
||||
if (function.parameters.size() < minParametersCount) {
|
||||
RaiseError(
|
||||
"too_few_parameters",
|
||||
_("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));
|
||||
}
|
||||
return returnType;
|
||||
}
|
||||
|
||||
// TODO: reverse the order of diagnostic?
|
||||
size_t writtenParametersFirstIndex =
|
||||
ExpressionParser2::WrittenParametersFirstIndex(
|
||||
function.objectName, function.behaviorName);
|
||||
int metadataIndex = writtenParametersFirstIndex;
|
||||
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.
|
||||
metadataIndex++;
|
||||
}
|
||||
auto& parameterMetadata = metadata.GetParameters()[metadataIndex];
|
||||
|
||||
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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
metadataIndex++;
|
||||
}
|
||||
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";
|
||||
|
||||
const gd::String &ExpressionValidator::TypeToString(Type type) {
|
||||
switch (type) {
|
||||
case Type::Unknown:
|
||||
return unknownTypeString;
|
||||
case Type::Number:
|
||||
return numberTypeString;
|
||||
case Type::String:
|
||||
return stringTypeString;
|
||||
case Type::NumberOrString:
|
||||
return numberOrStringTypeString;
|
||||
case Type::Variable:
|
||||
return variableTypeString;
|
||||
case Type::Object:
|
||||
return objectTypeString;
|
||||
case Type::Empty:
|
||||
return emptyTypeString;
|
||||
}
|
||||
return unknownTypeString;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
} // namespace gd
|
@@ -10,10 +10,6 @@
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
@@ -32,27 +28,15 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionValidator(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_,
|
||||
const gd::String &rootType_)
|
||||
: platform(platform_),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
parentType(StringToType(gd::ParameterMetadata::GetExpressionValueType(rootType_))),
|
||||
childType(Type::Unknown) {};
|
||||
ExpressionValidator(){};
|
||||
virtual ~ExpressionValidator(){};
|
||||
|
||||
/**
|
||||
* \brief Helper function to check if a given node does not contain
|
||||
* any error.
|
||||
*/
|
||||
static bool HasNoErrors(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
const gd::String &rootType,
|
||||
gd::ExpressionNode& node) {
|
||||
gd::ExpressionValidator validator(platform, globalObjectsContainer, objectsContainer, rootType);
|
||||
static bool HasNoErrors(gd::ExpressionNode& node) {
|
||||
gd::ExpressionValidator validator;
|
||||
node.Visit(validator);
|
||||
return validator.GetErrors().empty();
|
||||
}
|
||||
@@ -72,247 +56,52 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
node.expression->Visit(*this);
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
|
||||
node.leftHandSide->Visit(*this);
|
||||
const Type leftType = childType;
|
||||
|
||||
if (leftType == Type::Number) {
|
||||
if (node.op == ' ') {
|
||||
RaiseError("syntax_error",
|
||||
"No operator found. Did you forget to enter an operator (like +, -, "
|
||||
"* or /) between numbers or expressions?", node.rightHandSide->location);
|
||||
}
|
||||
}
|
||||
else if (leftType == Type::String) {
|
||||
if (node.op == ' ') {
|
||||
RaiseError("syntax_error",
|
||||
"You must add the operator + between texts or expressions. For "
|
||||
"example: \"Your name: \" + VariableString(PlayerName).", node.rightHandSide->location);
|
||||
}
|
||||
else if (node.op != '+') {
|
||||
RaiseOperatorError(
|
||||
_("You've used an operator that is not supported. Only + can be used "
|
||||
"to concatenate texts."),
|
||||
ExpressionParserLocation(node.leftHandSide->location.GetEndPosition() + 1, node.location.GetEndPosition()));
|
||||
}
|
||||
} else if (leftType == Type::Object) {
|
||||
RaiseOperatorError(
|
||||
_("Operators (+, -, /, *) can't be used with an object name. Remove "
|
||||
"the operator."),
|
||||
node.rightHandSide->location);
|
||||
} else if (leftType == Type::Variable) {
|
||||
RaiseOperatorError(
|
||||
_("Operators (+, -, /, *) can't be used in variable names. Remove "
|
||||
"the operator from the variable name."),
|
||||
node.rightHandSide->location);
|
||||
}
|
||||
|
||||
parentType = leftType;
|
||||
ReportAnyError(node);
|
||||
node.rightHandSide->Visit(*this);
|
||||
const Type rightType = childType;
|
||||
|
||||
childType = leftType;
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
node.factor->Visit(*this);
|
||||
const Type rightType = childType;
|
||||
|
||||
if (rightType == Type::Number) {
|
||||
if (node.op != '+' && node.op != '-') {
|
||||
// This is actually a dead code because the parser takes them as
|
||||
// binary operations with an empty left side which makes as much sense.
|
||||
RaiseTypeError(
|
||||
_("You've used an \"unary\" operator that is not supported. Operator "
|
||||
"should be "
|
||||
"either + or -."),
|
||||
node.location);
|
||||
}
|
||||
} else if (rightType == Type::String) {
|
||||
RaiseTypeError(
|
||||
_("You've used an operator that is not supported. Only + can be used "
|
||||
"to concatenate texts, and must be placed between two texts (or "
|
||||
"expressions)."),
|
||||
node.location);
|
||||
} else if (rightType == Type::Object) {
|
||||
RaiseTypeError(
|
||||
_("Operators (+, -) can't be used with an object name. Remove the "
|
||||
"operator."),
|
||||
node.location);
|
||||
} else if (rightType == Type::Variable) {
|
||||
RaiseTypeError(
|
||||
_("Operators (+, -) can't be used in variable names. Remove "
|
||||
"the operator from the variable name."),
|
||||
node.location);
|
||||
}
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {
|
||||
ReportAnyError(node);
|
||||
childType = Type::Number;
|
||||
CheckType(parentType, childType, node.location);
|
||||
}
|
||||
void OnVisitTextNode(TextNode& node) override {
|
||||
ReportAnyError(node);
|
||||
childType = Type::String;
|
||||
CheckType(parentType, childType, node.location);
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override { ReportAnyError(node); }
|
||||
void OnVisitTextNode(TextNode& node) override { ReportAnyError(node); }
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
ReportAnyError(node);
|
||||
if (node.child) {
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
childType = Type::Variable;
|
||||
CheckType(parentType, childType, node.location);
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
if (node.child) {
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
|
||||
Type currentParentType = parentType;
|
||||
parentType = Type::NumberOrString;
|
||||
node.expression->Visit(*this);
|
||||
parentType = currentParentType;
|
||||
|
||||
if (node.child) {
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
ReportAnyError(node);
|
||||
if (parentType == Type::String) {
|
||||
RaiseTypeError(_("You must wrap your text inside double quotes "
|
||||
"(example: \"Hello world\")."),
|
||||
node.location);
|
||||
}
|
||||
else if (parentType == Type::Number) {
|
||||
RaiseTypeError(
|
||||
_("You must enter a number."), node.location);
|
||||
}
|
||||
else if (parentType == Type::NumberOrString) {
|
||||
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.
|
||||
RaiseTypeError(
|
||||
_("You've entered a name, but this type was expected:") + " " + TypeToString(parentType),
|
||||
node.location);
|
||||
}
|
||||
childType = parentType;
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
ReportAnyError(node);
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
childType = ValidateFunction(node);
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {
|
||||
ReportAnyError(node);
|
||||
gd::String message;
|
||||
if (parentType == Type::Number) {
|
||||
message = _("You must enter a number or a valid expression call.");
|
||||
} else if (parentType == Type::String) {
|
||||
message = _(
|
||||
"You must enter a text (between quotes) or a valid expression call.");
|
||||
} else if (parentType == Type::Variable) {
|
||||
message = _("You must enter a variable name.");
|
||||
} else if (parentType == Type::Object) {
|
||||
message = _("You must enter a valid object name.");
|
||||
} else {
|
||||
// It can't happen.
|
||||
message = _("You must enter a valid expression.");
|
||||
for (auto& parameter : node.parameters) {
|
||||
parameter->Visit(*this);
|
||||
}
|
||||
RaiseTypeError(message, node.location);
|
||||
childType = Type::Empty;
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override { ReportAnyError(node); }
|
||||
|
||||
private:
|
||||
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, Object, Empty};
|
||||
Type ValidateFunction(const gd::FunctionCallNode& function);
|
||||
|
||||
void ReportAnyError(const ExpressionNode& node) {
|
||||
void ReportAnyError(ExpressionNode& node) {
|
||||
if (node.diagnostic && node.diagnostic->IsError()) {
|
||||
// Syntax errors are holden by the AST nodes.
|
||||
// It's fine to give pointers on them as the AST live longer than errors
|
||||
// handling.
|
||||
errors.push_back(node.diagnostic.get());
|
||||
}
|
||||
}
|
||||
|
||||
void RaiseError(const gd::String &type,
|
||||
const gd::String &message, const ExpressionParserLocation &location) {
|
||||
auto diagnostic = gd::make_unique<ExpressionParserError>(
|
||||
type, message, location);
|
||||
errors.push_back(diagnostic.get());
|
||||
// Errors found by the validator are not holden by the AST nodes.
|
||||
// They must be owned by the validator to keep living while errors are
|
||||
// handled by the caller.
|
||||
supplementalErrors.push_back(std::move(diagnostic));
|
||||
}
|
||||
|
||||
void RaiseTypeError(
|
||||
const gd::String &message, const ExpressionParserLocation &location) {
|
||||
RaiseError("type_error", message, location);
|
||||
}
|
||||
|
||||
void RaiseOperatorError(
|
||||
const gd::String &message, const ExpressionParserLocation &location) {
|
||||
RaiseError("invalid_operator", message, location);
|
||||
}
|
||||
|
||||
void CheckType(Type expect, Type actual, const ExpressionParserLocation &location) {
|
||||
if (actual == Type::String) {
|
||||
if (expect == Type::Number) {
|
||||
RaiseTypeError(_("You entered a text, but a number was expected."),
|
||||
location);
|
||||
}
|
||||
else if (expect != Type::String && expect != Type::NumberOrString) {
|
||||
RaiseTypeError(
|
||||
_("You entered a text, but this type was expected:") + " " + TypeToString(expect),
|
||||
location);
|
||||
}
|
||||
}
|
||||
else if (actual == Type::Number) {
|
||||
if (expect == Type::String) {
|
||||
RaiseTypeError(
|
||||
_("You entered a number, but a text was expected (in quotes)."),
|
||||
location);
|
||||
}
|
||||
else if (expect != Type::Number && expect != Type::NumberOrString) {
|
||||
RaiseTypeError(
|
||||
_("You entered a number, but this type was expected:") + " " + TypeToString(expect),
|
||||
location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Type StringToType(const gd::String &type);
|
||||
static const gd::String &TypeToString(Type type);
|
||||
static const gd::String unknownTypeString;
|
||||
static const gd::String numberTypeString;
|
||||
static const gd::String stringTypeString;
|
||||
static const gd::String numberOrStringTypeString;
|
||||
static const gd::String variableTypeString;
|
||||
static const gd::String objectTypeString;
|
||||
static const gd::String identifierTypeString;
|
||||
static const gd::String emptyTypeString;
|
||||
|
||||
std::vector<ExpressionParserDiagnostic*> errors;
|
||||
std::vector<std::unique_ptr<ExpressionParserDiagnostic>> supplementalErrors;
|
||||
Type childType;
|
||||
Type parentType;
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONVARIABLEOWNERFINDER_H
|
||||
#define GDCORE_EXPRESSIONVARIABLEOWNERFINDER_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
class Platform;
|
||||
class ParameterMetadata;
|
||||
class ExpressionMetadata;
|
||||
} // namespace gd
|
||||
|
||||
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.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariableOwnerFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Helper function to find the object name that should be used as a
|
||||
* context of the expression or sub-expression that a given node represents.
|
||||
*/
|
||||
static const gd::String GetObjectName(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer,
|
||||
const gd::String& rootObjectName,
|
||||
gd::ExpressionNode& node) {
|
||||
gd::ExpressionVariableOwnerFinder typeFinder(
|
||||
platform, globalObjectsContainer, objectsContainer, rootObjectName);
|
||||
node.Visit(typeFinder);
|
||||
return typeFinder.GetObjectName();
|
||||
}
|
||||
|
||||
virtual ~ExpressionVariableOwnerFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionVariableOwnerFinder(const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_,
|
||||
const gd::String& rootObjectName_)
|
||||
: platform(platform_),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
rootObjectName(rootObjectName_),
|
||||
objectName(""),
|
||||
variableNode(nullptr) {};
|
||||
|
||||
/**
|
||||
* \brief Get all the errors
|
||||
*
|
||||
* No errors means that the expression is valid.
|
||||
*/
|
||||
const gd::String &GetObjectName() {
|
||||
return objectName;
|
||||
};
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (variableNode != nullptr) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
if (node.parent == nullptr) {
|
||||
objectName = rootObjectName;
|
||||
return;
|
||||
}
|
||||
variableNode = &node;
|
||||
node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (variableNode != nullptr) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
if (node.parent == nullptr) {
|
||||
objectName = rootObjectName;
|
||||
return;
|
||||
}
|
||||
// This node is not necessarily a variable node.
|
||||
// It will be checked when visiting the FunctionCallNode.
|
||||
variableNode = &node;
|
||||
node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {
|
||||
if (variableNode == nullptr) {
|
||||
return;
|
||||
}
|
||||
int parameterIndex = -1;
|
||||
for (int i = 0; i < functionCall.parameters.size(); i++) {
|
||||
if (functionCall.parameters.at(i).get() == variableNode) {
|
||||
parameterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterIndex < 0) {
|
||||
return;
|
||||
}
|
||||
const gd::ParameterMetadata* parameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform,
|
||||
globalObjectsContainer,
|
||||
objectsContainer,
|
||||
functionCall,
|
||||
parameterIndex);
|
||||
if (parameterMetadata == nullptr
|
||||
|| parameterMetadata->GetType() != "objectvar") {
|
||||
return;
|
||||
}
|
||||
|
||||
// The object on which the function is called is returned if no previous
|
||||
// parameters are objects.
|
||||
objectName = functionCall.objectName;
|
||||
for (int previousIndex = parameterIndex - 1; previousIndex >= 0; previousIndex--) {
|
||||
const gd::ParameterMetadata* previousParameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform,
|
||||
globalObjectsContainer,
|
||||
objectsContainer,
|
||||
functionCall,
|
||||
previousIndex);
|
||||
if (previousParameterMetadata != nullptr
|
||||
&& gd::ParameterMetadata::IsObject(previousParameterMetadata->GetType())) {
|
||||
auto previousParameterNode = functionCall.parameters[previousIndex].get();
|
||||
IdentifierNode* objectNode = dynamic_cast<IdentifierNode*>(previousParameterNode);
|
||||
objectName = objectNode->identifierName;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
gd::String objectName;
|
||||
gd::ExpressionNode *variableNode;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
const gd::String &rootObjectName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONVARIABLEOWNERFINDER_H
|
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
@@ -145,9 +146,17 @@ bool ExpressionsParameterMover::DoVisitInstruction(gd::Instruction& instruction,
|
||||
pNb < instruction.GetParametersCount();
|
||||
++pNb) {
|
||||
const gd::String& type = metadata.parameters[pNb].type;
|
||||
const gd::Expression& expression = instruction.GetParameter(pNb);
|
||||
const gd::String& expression =
|
||||
instruction.GetParameter(pNb).GetPlainString();
|
||||
|
||||
auto node = expression.GetRootNode();
|
||||
gd::ExpressionParser2 parser(
|
||||
platform, GetGlobalObjectsContainer(), GetObjectsContainer());
|
||||
|
||||
auto node = gd::ParameterMetadata::IsExpression("number", type)
|
||||
? parser.ParseExpression("number", expression)
|
||||
: (gd::ParameterMetadata::IsExpression("string", type)
|
||||
? parser.ParseExpression("string", expression)
|
||||
: std::unique_ptr<gd::ExpressionNode>());
|
||||
if (node) {
|
||||
ExpressionParameterMover mover(GetGlobalObjectsContainer(),
|
||||
GetObjectsContainer(),
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
@@ -155,9 +156,18 @@ bool ExpressionsRenamer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
|
||||
pNb < instruction.GetParametersCount();
|
||||
++pNb) {
|
||||
const gd::Expression& expression = instruction.GetParameter(pNb);
|
||||
const gd::String& type = metadata.parameters[pNb].type;
|
||||
const gd::String& expression =
|
||||
instruction.GetParameter(pNb).GetPlainString();
|
||||
|
||||
auto node = expression.GetRootNode();
|
||||
gd::ExpressionParser2 parser(
|
||||
platform, GetGlobalObjectsContainer(), GetObjectsContainer());
|
||||
|
||||
auto node = gd::ParameterMetadata::IsExpression("number", type)
|
||||
? parser.ParseExpression("number", expression)
|
||||
: (gd::ParameterMetadata::IsExpression("string", type)
|
||||
? parser.ParseExpression("string", expression)
|
||||
: std::unique_ptr<gd::ExpressionNode>());
|
||||
if (node) {
|
||||
ExpressionFunctionRenamer renamer(GetGlobalObjectsContainer(),
|
||||
GetObjectsContainer(),
|
||||
|
@@ -1,10 +1,10 @@
|
||||
#include "UsedExtensionsFinder.h"
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#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/BehaviorContent.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
@@ -54,12 +54,13 @@ bool UsedExtensionsFinder::DoVisitInstruction(gd::Instruction& instruction,
|
||||
metadata.GetMetadata().GetParameter(i).GetType();
|
||||
i++;
|
||||
|
||||
if (gd::ParameterMetadata::IsExpression("string", parameterType)) {
|
||||
rootType = "string";
|
||||
expression.GetRootNode()->Visit(*this);
|
||||
} else if (gd::ParameterMetadata::IsExpression("number", parameterType)) {
|
||||
rootType = "number";
|
||||
expression.GetRootNode()->Visit(*this);
|
||||
if (gd::ParameterMetadata::IsExpression("string", parameterType) ||
|
||||
gd::ParameterMetadata::IsExpression("number", parameterType)) {
|
||||
gd::ExpressionParser2 parser(project.GetCurrentPlatform(),
|
||||
GetGlobalObjectsContainer(),
|
||||
GetObjectsContainer());
|
||||
parser.ParseExpression(parameterType, expression.GetPlainString())
|
||||
->Visit(*this);
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", parameterType))
|
||||
usedExtensions.insert("BuiltinVariables");
|
||||
}
|
||||
@@ -112,8 +113,7 @@ void UsedExtensionsFinder::OnVisitVariableBracketAccessorNode(
|
||||
|
||||
// Add extensions bound to Objects/Behaviors/Functions
|
||||
void UsedExtensionsFinder::OnVisitIdentifierNode(IdentifierNode& node) {
|
||||
auto type = gd::ExpressionTypeFinder::GetType(project.GetCurrentPlatform(), GetGlobalObjectsContainer(), GetObjectsContainer(), rootType, node);
|
||||
if (gd::ParameterMetadata::IsObject(type)) {
|
||||
if (gd::ParameterMetadata::IsObject(node.type)) {
|
||||
usedExtensions.insert(gd::MetadataProvider::GetExtensionAndObjectMetadata(
|
||||
project.GetCurrentPlatform(), node.identifierName)
|
||||
.GetExtension()
|
||||
|
@@ -31,7 +31,6 @@ class GD_CORE_API UsedExtensionsFinder
|
||||
private:
|
||||
UsedExtensionsFinder(gd::Project& project_) : project(project_){};
|
||||
gd::Project& project;
|
||||
gd::String rootType;
|
||||
std::set<gd::String> usedExtensions;
|
||||
|
||||
// Object Visitor
|
||||
|
@@ -18,7 +18,7 @@
|
||||
namespace gd {
|
||||
|
||||
void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
gd::Project& project,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
@@ -36,7 +36,7 @@ void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
}
|
||||
|
||||
void EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
|
@@ -32,7 +32,7 @@ class GD_CORE_API EventsFunctionTools {
|
||||
* generation for example.
|
||||
*/
|
||||
static void FreeEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
gd::Project& project,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
@@ -46,7 +46,7 @@ class GD_CORE_API EventsFunctionTools {
|
||||
* generation for example.
|
||||
*/
|
||||
static void BehaviorEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
|
@@ -126,10 +126,9 @@ class ResourceWorkerInEventsWorker : public ArbitraryEventsWorker {
|
||||
instruction.GetParameters(),
|
||||
metadata.GetParameters(),
|
||||
[this, &instruction](const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterExpression,
|
||||
const gd::String& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
const String& parameterValue = parameterExpression.GetPlainString();
|
||||
if (parameterMetadata.GetType() ==
|
||||
"police") { // Should be renamed fontResource
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
|
@@ -54,8 +54,11 @@ Layout::Layout()
|
||||
oglFOV(90.0f),
|
||||
oglZNear(1.0f),
|
||||
oglZFar(500.0f),
|
||||
disableInputWhenNotFocused(true),
|
||||
disableInputWhenNotFocused(true)
|
||||
#if defined(GD_IDE_ONLY)
|
||||
,
|
||||
profiler(NULL)
|
||||
#endif
|
||||
{
|
||||
gd::Layer layer;
|
||||
layer.SetCameraCount(1);
|
||||
@@ -329,6 +332,7 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
disableInputWhenNotFocused =
|
||||
element.GetBoolAttribute("disableInputWhenNotFocused");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
editorSettings.UnserializeFrom(
|
||||
element.GetChild("uiSettings", 0, "UISettings"));
|
||||
|
||||
@@ -336,6 +340,7 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
element.GetChild("objectsGroups", 0, "GroupesObjets"));
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, GetEvents(), element.GetChild("events", 0, "Events"));
|
||||
#endif
|
||||
|
||||
UnserializeObjectsFrom(project, element.GetChild("objects", 0, "Objets"));
|
||||
initialInstances.UnserializeFrom(
|
||||
@@ -405,11 +410,13 @@ void Layout::Init(const Layout& other) {
|
||||
std::unique_ptr<gd::BehaviorContent>(it.second->Clone());
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
events = other.events;
|
||||
editorSettings = other.editorSettings;
|
||||
objectGroups = other.objectGroups;
|
||||
|
||||
profiler = other.profiler;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<gd::String> GetHiddenLayers(const Layout& layout) {
|
||||
@@ -423,6 +430,7 @@ std::vector<gd::String> GetHiddenLayers(const Layout& layout) {
|
||||
return hiddenLayers;
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::String name,
|
||||
@@ -436,7 +444,7 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
|
||||
type = project.GetObject(name).GetType();
|
||||
|
||||
// Search in groups
|
||||
else if (searchInGroups) {
|
||||
if (searchInGroups) {
|
||||
for (std::size_t i = 0; i < layout.GetObjectGroups().size(); ++i) {
|
||||
if (layout.GetObjectGroups()[i].GetName() == name) {
|
||||
// A group has the name searched
|
||||
@@ -497,16 +505,18 @@ gd::String GD_CORE_API GetTypeOfBehavior(const gd::ObjectsContainer& project,
|
||||
gd::String name,
|
||||
bool searchInGroups) {
|
||||
for (std::size_t i = 0; i < layout.GetObjectsCount(); ++i) {
|
||||
const auto &object = layout.GetObject(i);
|
||||
if (object.HasBehaviorNamed(name)) {
|
||||
return object.GetBehavior(name).GetTypeName();
|
||||
vector<gd::String> behaviors = layout.GetObject(i).GetAllBehaviorNames();
|
||||
for (std::size_t j = 0; j < behaviors.size(); ++j) {
|
||||
if (layout.GetObject(i).GetBehavior(behaviors[j]).GetName() == name)
|
||||
return layout.GetObject(i).GetBehavior(behaviors[j]).GetTypeName();
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < project.GetObjectsCount(); ++i) {
|
||||
const auto &object = project.GetObject(i);
|
||||
if (object.HasBehaviorNamed(name)) {
|
||||
return object.GetBehavior(name).GetTypeName();
|
||||
vector<gd::String> behaviors = project.GetObject(i).GetAllBehaviorNames();
|
||||
for (std::size_t j = 0; j < behaviors.size(); ++j) {
|
||||
if (project.GetObject(i).GetBehavior(behaviors[j]).GetName() == name)
|
||||
return project.GetObject(i).GetBehavior(behaviors[j]).GetTypeName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,5 +612,6 @@ GetBehaviorsOfObject(const gd::ObjectsContainer& project,
|
||||
|
||||
return behaviors;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -12,7 +12,9 @@
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#endif
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -22,7 +24,6 @@ Object::Object(const gd::String& name_) : name(name_) {}
|
||||
|
||||
void Object::Init(const gd::Object& object) {
|
||||
name = object.name;
|
||||
assetStoreId = object.assetStoreId;
|
||||
type = object.type;
|
||||
objectVariables = object.objectVariables;
|
||||
tags = object.tags;
|
||||
@@ -79,12 +80,13 @@ gd::BehaviorContent& Object::AddBehavior(
|
||||
return *behaviors[behaviorName];
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::map<gd::String, gd::PropertyDescriptor> Object::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
gd::BehaviorContent* Object::AddNewBehavior(const gd::Project& project,
|
||||
gd::BehaviorContent* Object::AddNewBehavior(gd::Project& project,
|
||||
const gd::String& type,
|
||||
const gd::String& name) {
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
@@ -107,11 +109,11 @@ Object::GetInitialInstanceProperties(const gd::InitialInstance& instance,
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Object::UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element) {
|
||||
type = element.GetStringAttribute("type");
|
||||
assetStoreId = element.GetStringAttribute("assetStoreId");
|
||||
name = element.GetStringAttribute("name", name, "nom");
|
||||
tags = element.GetStringAttribute("tags");
|
||||
|
||||
@@ -182,9 +184,9 @@ void Object::UnserializeFrom(gd::Project& project,
|
||||
DoUnserializeFrom(project, element);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void Object::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
element.SetAttribute("assetStoreId", GetAssetStoreId());
|
||||
element.SetAttribute("type", GetType());
|
||||
element.SetAttribute("tags", GetTags());
|
||||
objectVariables.SerializeTo(element.AddChild("variables"));
|
||||
@@ -207,5 +209,6 @@ void Object::SerializeTo(SerializerElement& element) const {
|
||||
|
||||
DoSerializeTo(element);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -83,14 +83,6 @@ class GD_CORE_API Object {
|
||||
*/
|
||||
const gd::String& GetName() const { return name; };
|
||||
|
||||
/** \brief Change the asset store id of the object.
|
||||
*/
|
||||
void SetAssetStoreId(const gd::String& assetStoreId_) { assetStoreId = assetStoreId_; };
|
||||
|
||||
/** \brief Return the asset store id of the object.
|
||||
*/
|
||||
const gd::String& GetAssetStoreId() const { return assetStoreId; };
|
||||
|
||||
/** \brief Change the type of the object.
|
||||
*/
|
||||
void SetType(const gd::String& type_) { type = type_; }
|
||||
@@ -108,6 +100,7 @@ class GD_CORE_API Object {
|
||||
const gd::String& GetTags() const { return tags; }
|
||||
///@}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/** \name Resources management
|
||||
* Members functions related to managing resources used by the object
|
||||
*/
|
||||
@@ -193,6 +186,7 @@ class GD_CORE_API Object {
|
||||
return false;
|
||||
};
|
||||
///@}
|
||||
#endif
|
||||
|
||||
/** \name Behaviors management
|
||||
* Members functions related to behaviors management.
|
||||
@@ -238,6 +232,7 @@ class GD_CORE_API Object {
|
||||
*/
|
||||
gd::BehaviorContent& AddBehavior(const gd::BehaviorContent& behavior);
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Add the behavior of the specified \a type with the specified \a
|
||||
* name.
|
||||
@@ -247,9 +242,10 @@ class GD_CORE_API Object {
|
||||
* \return A pointer to the newly added behavior content. NULL if the creation
|
||||
* failed.
|
||||
*/
|
||||
gd::BehaviorContent* AddNewBehavior(const gd::Project& project,
|
||||
gd::BehaviorContent* AddNewBehavior(gd::Project& project,
|
||||
const gd::String& type,
|
||||
const gd::String& name);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Get a read-only access to the map containing the behaviors with
|
||||
@@ -300,11 +296,13 @@ class GD_CORE_API Object {
|
||||
* Members functions related to serialization of the object
|
||||
*/
|
||||
///@{
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Serialize the object.
|
||||
* \see DoSerializeTo
|
||||
*/
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Unserialize the object.
|
||||
@@ -315,7 +313,6 @@ class GD_CORE_API Object {
|
||||
|
||||
protected:
|
||||
gd::String name; ///< The full name of the object
|
||||
gd::String assetStoreId; ///< The ID of the asset if the object comes from the store.
|
||||
gd::String type; ///< Which type is the object. ( To test if we can do
|
||||
///< something reserved to some objects with it )
|
||||
std::map<gd::String, std::unique_ptr<gd::BehaviorContent>>
|
||||
@@ -334,10 +331,12 @@ class GD_CORE_API Object {
|
||||
virtual void DoUnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element){};
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Derived objects can redefine this method to save custom attributes.
|
||||
*/
|
||||
virtual void DoSerializeTo(SerializerElement& element) const {};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize object using another object. Used by copy-ctor and assign-op.
|
||||
|
@@ -76,7 +76,7 @@ std::size_t ObjectsContainer::GetObjectsCount() const {
|
||||
return initialObjects.size();
|
||||
}
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::Object& ObjectsContainer::InsertNewObject(const gd::Project& project,
|
||||
gd::Object& ObjectsContainer::InsertNewObject(gd::Project& project,
|
||||
const gd::String& objectType,
|
||||
const gd::String& name,
|
||||
std::size_t position) {
|
||||
|
@@ -94,7 +94,7 @@ class GD_CORE_API ObjectsContainer {
|
||||
* \note The object is created using the project's current platform.
|
||||
* \return A reference to the object in the list.
|
||||
*/
|
||||
gd::Object& InsertNewObject(const gd::Project& project,
|
||||
gd::Object& InsertNewObject(gd::Project& project,
|
||||
const gd::String& objectType,
|
||||
const gd::String& name,
|
||||
std::size_t position);
|
||||
|
@@ -51,7 +51,6 @@ Project::Project()
|
||||
: name(_("Project")),
|
||||
version("1.0.0"),
|
||||
packageName("com.example.gamename"),
|
||||
templateSlug(""),
|
||||
orientation("landscape"),
|
||||
folderProject(false),
|
||||
windowWidth(800),
|
||||
@@ -517,7 +516,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
SetProjectUuid(propElement.GetStringAttribute("projectUuid", ""));
|
||||
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
|
||||
SetPackageName(propElement.GetStringAttribute("packageName"));
|
||||
SetTemplateSlug(propElement.GetStringAttribute("templateSlug"));
|
||||
SetOrientation(propElement.GetStringAttribute("orientation", "default"));
|
||||
SetFolderProject(propElement.GetBoolAttribute("folderProject"));
|
||||
SetLastCompilationDirectory(propElement
|
||||
@@ -749,7 +747,6 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
propElement.SetAttribute("projectUuid", projectUuid);
|
||||
propElement.SetAttribute("folderProject", folderProject);
|
||||
propElement.SetAttribute("packageName", packageName);
|
||||
propElement.SetAttribute("templateSlug", templateSlug);
|
||||
propElement.SetAttribute("orientation", orientation);
|
||||
platformSpecificAssets.SerializeTo(
|
||||
propElement.AddChild("platformSpecificAssets"));
|
||||
@@ -977,7 +974,6 @@ void Project::Init(const gd::Project& game) {
|
||||
isPlayableWithGamepad = game.isPlayableWithGamepad;
|
||||
isPlayableWithMobile = game.isPlayableWithMobile;
|
||||
packageName = game.packageName;
|
||||
templateSlug = game.templateSlug;
|
||||
orientation = game.orientation;
|
||||
folderProject = game.folderProject;
|
||||
latestCompilationDirectory = game.latestCompilationDirectory;
|
||||
|
@@ -162,18 +162,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
const gd::String& GetPackageName() const { return packageName; }
|
||||
|
||||
/**
|
||||
* \brief Change the slug of the template from which the project is created.
|
||||
*/
|
||||
void SetTemplateSlug(const gd::String& templateSlug_) {
|
||||
templateSlug = templateSlug_;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the slug of the template from which the project is created.
|
||||
*/
|
||||
const gd::String& GetTemplateSlug() const { return templateSlug; }
|
||||
|
||||
/**
|
||||
* \brief Change the project orientation (in particular when exported with
|
||||
* Cordova). This has no effect on desktop and web browsers. \param
|
||||
@@ -995,8 +983,6 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
bool isPlayableWithGamepad; ///< The project is playable with a gamepad.
|
||||
bool isPlayableWithMobile; ///< The project is playable on a mobile.
|
||||
gd::String packageName; ///< Game package name
|
||||
gd::String templateSlug; ///< The slug of the template from which the game is
|
||||
///< created.
|
||||
gd::String orientation; ///< Lock game orientation (on mobile devices).
|
||||
///< "default", "landscape" or "portrait".
|
||||
bool
|
||||
|
@@ -184,17 +184,11 @@ std::map<gd::String, gd::PropertyDescriptor> AudioResource::GetProperties()
|
||||
const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties[_("Preload as sound")]
|
||||
.SetDescription(_("Loads the fully decoded file into cache, so it can be played right away as Sound with no further delays."))
|
||||
.SetValue(preloadAsSound ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
properties[_("Preload as music")]
|
||||
.SetDescription(_("Prepares the file for immediate streaming as Music (does not wait for complete download)."))
|
||||
.SetValue(preloadAsMusic ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
properties[_("Preload in cache")]
|
||||
.SetDescription(_("Loads the complete file into cache, but does not decode it into memory until requested."))
|
||||
.SetValue(preloadInCache ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
|
||||
return properties;
|
||||
}
|
||||
@@ -205,8 +199,6 @@ bool AudioResource::UpdateProperty(const gd::String& name,
|
||||
preloadAsSound = value == "1";
|
||||
else if (name == _("Preload as music"))
|
||||
preloadAsMusic = value == "1";
|
||||
else if (name == _("Preload in cache"))
|
||||
preloadInCache = value == "1";
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -577,7 +569,6 @@ void AudioResource::UnserializeFrom(const SerializerElement& element) {
|
||||
SetFile(element.GetStringAttribute("file"));
|
||||
SetPreloadAsMusic(element.GetBoolAttribute("preloadAsMusic"));
|
||||
SetPreloadAsSound(element.GetBoolAttribute("preloadAsSound"));
|
||||
SetPreloadInCache(element.GetBoolAttribute("preloadInCache"));
|
||||
}
|
||||
|
||||
void AudioResource::SerializeTo(SerializerElement& element) const {
|
||||
@@ -585,7 +576,6 @@ void AudioResource::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("file", GetFile());
|
||||
element.SetAttribute("preloadAsMusic", PreloadAsMusic());
|
||||
element.SetAttribute("preloadAsSound", PreloadAsSound());
|
||||
element.SetAttribute("preloadInCache", PreloadInCache());
|
||||
}
|
||||
|
||||
void FontResource::SetFile(const gd::String& newFile) {
|
||||
|
@@ -60,7 +60,7 @@ class GD_CORE_API Resource {
|
||||
* \see gd::Resource::GetFile
|
||||
* \see gd::Resource::SetFile
|
||||
*/
|
||||
virtual bool UseFile() const { return false; }
|
||||
virtual bool UseFile() { return false; }
|
||||
|
||||
/**
|
||||
* \brief Return, if applicable, the String containing the file used by the
|
||||
@@ -184,7 +184,7 @@ class GD_CORE_API ImageResource : public Resource {
|
||||
*/
|
||||
virtual void SetFile(const gd::String& newFile) override;
|
||||
|
||||
virtual bool UseFile() const override { return true; }
|
||||
virtual bool UseFile() override { return true; }
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
|
||||
@@ -223,7 +223,7 @@ class GD_CORE_API ImageResource : public Resource {
|
||||
*/
|
||||
class GD_CORE_API AudioResource : public Resource {
|
||||
public:
|
||||
AudioResource() : Resource(), preloadAsMusic(false), preloadAsSound(false), preloadInCache(false) {
|
||||
AudioResource() : Resource(), preloadAsMusic(false), preloadAsSound(false) {
|
||||
SetKind("audio");
|
||||
};
|
||||
virtual ~AudioResource(){};
|
||||
@@ -234,7 +234,7 @@ class GD_CORE_API AudioResource : public Resource {
|
||||
virtual const gd::String& GetFile() const override { return file; };
|
||||
virtual void SetFile(const gd::String& newFile) override;
|
||||
|
||||
virtual bool UseFile() const override { return true; }
|
||||
virtual bool UseFile() override { return true; }
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
|
||||
@@ -263,21 +263,10 @@ class GD_CORE_API AudioResource : public Resource {
|
||||
*/
|
||||
void SetPreloadAsSound(bool enable = true) { preloadAsSound = enable; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the audio resource should be preloaded in cache (without decoding into memory).
|
||||
*/
|
||||
bool PreloadInCache() const { return preloadInCache; }
|
||||
|
||||
/**
|
||||
* \brief Set if the audio resource should be preloaded in cache (without decoding into memory).
|
||||
*/
|
||||
void SetPreloadInCache(bool enable = true) { preloadInCache = enable; }
|
||||
|
||||
private:
|
||||
gd::String file;
|
||||
bool preloadAsSound;
|
||||
bool preloadAsMusic;
|
||||
bool preloadInCache;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -297,7 +286,7 @@ class GD_CORE_API FontResource : public Resource {
|
||||
virtual const gd::String& GetFile() const override { return file; };
|
||||
virtual void SetFile(const gd::String& newFile) override;
|
||||
|
||||
virtual bool UseFile() const override { return true; }
|
||||
virtual bool UseFile() override { return true; }
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
|
||||
void UnserializeFrom(const SerializerElement& element) override;
|
||||
@@ -323,7 +312,7 @@ class GD_CORE_API VideoResource : public Resource {
|
||||
virtual const gd::String& GetFile() const override { return file; };
|
||||
virtual void SetFile(const gd::String& newFile) override;
|
||||
|
||||
virtual bool UseFile() const override { return true; }
|
||||
virtual bool UseFile() override { return true; }
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
|
||||
void UnserializeFrom(const SerializerElement& element) override;
|
||||
@@ -349,7 +338,7 @@ class GD_CORE_API JsonResource : public Resource {
|
||||
virtual const gd::String& GetFile() const override { return file; };
|
||||
virtual void SetFile(const gd::String& newFile) override;
|
||||
|
||||
virtual bool UseFile() const override { return true; }
|
||||
virtual bool UseFile() override { return true; }
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
|
||||
@@ -390,7 +379,7 @@ class GD_CORE_API BitmapFontResource : public Resource {
|
||||
virtual const gd::String& GetFile() const override { return file; };
|
||||
virtual void SetFile(const gd::String& newFile) override;
|
||||
|
||||
virtual bool UseFile() const override { return true; }
|
||||
virtual bool UseFile() override { return true; }
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
|
||||
void UnserializeFrom(const SerializerElement& element) override;
|
||||
|
2
Core/GDCore/TinyXml/tinyxmlparser.cpp
vendored
2
Core/GDCore/TinyXml/tinyxmlparser.cpp
vendored
@@ -354,7 +354,7 @@ const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )
|
||||
}
|
||||
else
|
||||
{
|
||||
while ( (*p && IsWhiteSpace( *p )) || *p == '\n' || *p =='\r' )
|
||||
while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' )
|
||||
++p;
|
||||
}
|
||||
|
||||
|
@@ -31,8 +31,8 @@ Extensions do have the same distinction between the "**IDE**" part and the "**Ru
|
||||
|
||||
In GDevelop, developers can associate and manipulate variables in their games. To represent them, we have two things:
|
||||
|
||||
- The **editor** `gd::Variable` that is part of the structure of the game, so living in [GDCore in Variable.h](https://docs.gdevelop.io/GDCore%20Documentation/classgd_1_1_variable.html). This is what is shown in the editor, saved on disk in the project file.
|
||||
- The **game engine** variable, called `gdjs.Variable` in GDJS. [Documentation is in the GDJS **game engine**](https://docs.gdevelop.io/GDJS%20Runtime%20Documentation/classes/gdjs.Variable.html). This JavaScript class is what is used during a game.
|
||||
- The **editor** `gd::Variable` that is part of the structure of the game, so living in [GDCore in Variable.h](https://docs.gdevelop-app.com/GDCore%20Documentation/classgd_1_1_variable.html). This is what is shown in the editor, saved on disk in the project file.
|
||||
- The **game engine** variable, called `gdjs.Variable` in GDJS. [Documentation is in the GDJS **game engine**](https://docs.gdevelop-app.com/GDJS%20Runtime%20Documentation/Variable.html). This JavaScript class is what is used during a game.
|
||||
|
||||
The editor `gd::Variable` **knows nothing** about the game engine class `gdjs.Variable`. And the `gdjs.Variable` class in the game engine knows almost nothing from `gd::Variable` (apart from how it's written in JSON, to be able to load a game default variables).
|
||||
|
||||
@@ -56,10 +56,10 @@ The game engine is in GDJS/Runtime and is all written in TypeScript.
|
||||
|
||||
## What about events?
|
||||
|
||||
An "**event**" is by default something that [is mostly empty](https://docs.gdevelop.io/GDCore%20Documentation/classgd_1_1_base_event.html). In a more traditional programming language, an event can be seen as a scope or block (example: `{ some code here }` in a C style language like JavaScript, Java or C++).
|
||||
An "**event**" is by default something that [is mostly empty](https://docs.gdevelop-app.com/GDCore%20Documentation/classgd_1_1_base_event.html). In a more traditional programming language, an event can be seen as a scope or block (example: `{ some code here }` in a C style language like JavaScript, Java or C++).
|
||||
|
||||
[Default events are defined](https://github.com/4ian/GDevelop/tree/master/Core/GDCore/Events/Builtin) in GDevelop Core.
|
||||
In particular, there is StandardEvent, which has conditions and actions. Conditions and actions are both a list of [`gd::Instruction`](https://docs.gdevelop.io/GDCore%20Documentation/classgd_1_1_instruction.html). A `gd::Instruction` is either a condition or an action (it depends only on the context where they are used).
|
||||
In particular, there is StandardEvent, which has conditions and actions. Conditions and actions are both a list of [`gd::Instruction`](https://docs.gdevelop-app.com/GDCore%20Documentation/classgd_1_1_instruction.html). A `gd::Instruction` is either a condition or an action (it depends only on the context where they are used).
|
||||
|
||||
A `gd::Instruction` is "just" a type (the name of the action or condition), and some parameters. You can think of it as a function in a programming language (`add(2, 3)` is calling a function called "add" with parameters "2" and "3"). Conditions have the special thing that they are functions returning true or false (and potentially being used to do a filter on the objects being picked for next conditions and actions).
|
||||
|
||||
|
@@ -6,7 +6,7 @@ GDevelop Core is a portable C++ library, compiled to be used in JavaScript in th
|
||||
|
||||
## 1) Getting started 🤓
|
||||
|
||||
First, take a look at the _Readme.md_ at the root of the repository and the [developer documentation](https://docs.gdevelop.io/).
|
||||
First, take a look at the _Readme.md_ at the root of the repository and the [developer documentation](https://docs.gdevelop-app.com/).
|
||||
|
||||
## 2) How to contribute 😎
|
||||
|
||||
|
@@ -197,17 +197,6 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
.AddParameter("object", _("Object 2 parameter"))
|
||||
.AddParameter("objectvar", _("Variable for object 2"))
|
||||
.SetFunctionName("getStringWith2ObjectParamAnd2ObjectVarParam");
|
||||
extension
|
||||
->AddStrExpression(
|
||||
"GetStringWith1ObjectParamAnd2ObjectVarParam",
|
||||
"Get string with 2 objectvar param one from the same object param",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", _("Object 1 parameter"))
|
||||
.AddParameter("objectvar", _("Variable for object 1"))
|
||||
.AddParameter("objectvar", _("Variable for object 2"))
|
||||
.SetFunctionName("getStringWith1ObjectParamAnd2ObjectVarParam");
|
||||
|
||||
auto& object = extension->AddObject<gd::Object>(
|
||||
"Sprite", "Dummy Sprite", "Dummy sprite object", "");
|
||||
|
@@ -32,7 +32,7 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
group.AddObject("MyOtherSpriteObject");
|
||||
group.AddObject("MyFakeObjectWithUnsupportedCapability");
|
||||
|
||||
gd::ExpressionParser2 parser;
|
||||
gd::ExpressionParser2 parser(platform, project, layout1);
|
||||
|
||||
unsigned int maxDepth = 0;
|
||||
gd::EventsCodeGenerationContext context(&maxDepth);
|
||||
@@ -40,10 +40,8 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
SECTION("Valid text generation") {
|
||||
{
|
||||
auto node = parser.ParseExpression("\"hello world\"");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
auto node = parser.ParseExpression("string", "\"hello world\"");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -51,10 +49,8 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"hello world\"");
|
||||
}
|
||||
{
|
||||
auto node = parser.ParseExpression("\"hello\" + \"world\" ");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
auto node = parser.ParseExpression("string", "\"hello\" + \"world\" ");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -63,10 +59,8 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
}
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"\"{\\\"hello\\\": \\\"world \\\\\\\" \\\"}\"");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
"string", "\"{\\\"hello\\\": \\\"world \\\\\\\" \\\"}\"");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -78,10 +72,8 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
SECTION("Valid number generation") {
|
||||
{
|
||||
auto node = parser.ParseExpression("12.45");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
auto node = parser.ParseExpression("number", "12.45");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -93,10 +85,8 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
SECTION("Invalid operators generation") {
|
||||
// TODO: Should any error return directly 0 or ""?
|
||||
{
|
||||
auto node = parser.ParseExpression("12.45 +");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
auto node = parser.ParseExpression("number", "12.45 +");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -104,10 +94,8 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "12.45 + 0");
|
||||
}
|
||||
{
|
||||
auto node = parser.ParseExpression("12.45 * *");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
auto node = parser.ParseExpression("number", "12.45 * *");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -118,20 +106,16 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
|
||||
SECTION("Valid unary operator generation") {
|
||||
{
|
||||
auto node = parser.ParseExpression("-12.45");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
auto node = parser.ParseExpression("number", "-12.45");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "-(12.45)");
|
||||
}
|
||||
{
|
||||
auto node = parser.ParseExpression("12.5 + -2. / (.3)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
auto node = parser.ParseExpression("number", "12.5 + -2. / (.3)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
@@ -140,24 +124,20 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
}
|
||||
|
||||
SECTION("Valid function calls") {
|
||||
SECTION("without parameter") {
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression(" 1 / MyExtension::GetNumber()");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
parser.ParseExpression("number", " 1 / MyExtension::GetNumber()");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "1 / getNumber()");
|
||||
}
|
||||
SECTION("number and string parameters") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
"number", "MyExtension::GetNumberWith2Params(12, \"hello world\")");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -165,13 +145,12 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"getNumberWith2Params(12, \"hello world\")");
|
||||
}
|
||||
SECTION("nested function call") {
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression("MyExtension::GetNumberWith2Params("
|
||||
parser.ParseExpression("number",
|
||||
"MyExtension::GetNumberWith2Params("
|
||||
"MyExtension::GetNumber(), \"hello world\")");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -179,12 +158,10 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"getNumberWith2Params(getNumber(), \"hello world\")");
|
||||
}
|
||||
SECTION("object function") {
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression("MySpriteObject.GetObjectNumber()");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
parser.ParseExpression("number", "MySpriteObject.GetObjectNumber()");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -192,12 +169,11 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"MySpriteObject.getObjectNumber() ?? 0");
|
||||
}
|
||||
SECTION("object function with nested free function") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"string",
|
||||
"MySpriteObject.GetObjectStringWith1Param(MyExtension::GetNumber())");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -207,11 +183,22 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
}
|
||||
}
|
||||
SECTION("Valid function calls with optional arguments") {
|
||||
SECTION("with optional parameter set") {
|
||||
auto node = parser.ParseExpression("MyExtension::MouseX(\"layer1\",2+2)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression("number", "MyExtension::MouseX(\"layer1\",)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"getMouseX(\"\", \"layer1\", 0)");
|
||||
// (first argument is the currentScene)
|
||||
}
|
||||
{
|
||||
auto node = parser.ParseExpression("number",
|
||||
"MyExtension::MouseX(\"layer1\",2+2)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -220,39 +207,13 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
"getMouseX(\"\", \"layer1\", 2 + 2)");
|
||||
// (first argument is the currentScene)
|
||||
}
|
||||
SECTION("with last optional parameter omit") {
|
||||
auto node =
|
||||
parser.ParseExpression("MyExtension::MouseX(\"layer1\")");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"getMouseX(\"\", \"layer1\", 0)");
|
||||
// (first argument is the currentScene)
|
||||
}
|
||||
SECTION("with last optional parameter omit (deprecated way)") {
|
||||
auto node =
|
||||
parser.ParseExpression("MyExtension::MouseX(\"layer1\",)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"getMouseX(\"\", \"layer1\", 0)");
|
||||
// (first argument is the currentScene)
|
||||
}
|
||||
SECTION("with explicit comma (deprecated way)") {
|
||||
auto node = parser.ParseExpression("MyExtension::MouseX(,)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
}
|
||||
SECTION(
|
||||
"Valid function calls (deprecated way of specifying optional "
|
||||
"arguments)") {
|
||||
{
|
||||
auto node = parser.ParseExpression("number", "MyExtension::MouseX(,)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -262,17 +223,15 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
// (first argument is the currentScene)
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Invalid function calls") {
|
||||
SECTION("unknown identifier in parameters") {
|
||||
{
|
||||
auto node =
|
||||
parser.ParseExpression("MySpriteObject.GetObjectStringWith3Param("
|
||||
parser.ParseExpression("string",
|
||||
"MySpriteObject.GetObjectStringWith3Param("
|
||||
"MySpriteObject.GetObjectNumber() / 2.3, "
|
||||
"MySpriteObject.GetObjectStringWith1Param("
|
||||
"MyExtension::GetNumber()), test)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -284,38 +243,33 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
"/* Error during generation, unrecognized identifier type: "
|
||||
"unknown with value test */ \"test\") ?? \"\"");
|
||||
}
|
||||
SECTION("missing parameter") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"MyExtension::GetNumberWith2Params(MyExtension::GetNumber())");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
context);
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(MyExtension::GetNumber())");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"getNumberWith2Params(getNumber(), /* Error during generation, "
|
||||
"parameter not existing in the nodes */ \"\")");
|
||||
}
|
||||
{
|
||||
// Using GenerateExpressionCode, the default value of 0 should be returned
|
||||
// as expression is invalid.
|
||||
REQUIRE(
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(MyExtension::GetNumber())") ==
|
||||
"0");
|
||||
}
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"getNumberWith2Params(getNumber(), /* Error during generation, "
|
||||
"parameter not existing in the nodes */ \"\")");
|
||||
}
|
||||
SECTION("unknown function") {
|
||||
auto node = parser.ParseExpression("MyExtension::Idontexist()");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
{
|
||||
// Using GenerateExpressionCode, the default value of 0 should be returned
|
||||
// as expression is invalid.
|
||||
REQUIRE(
|
||||
gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator,
|
||||
context,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(MyExtension::GetNumber())") ==
|
||||
"0");
|
||||
}
|
||||
{
|
||||
auto node = parser.ParseExpression("number", "MyExtension::Idontexist()");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -324,12 +278,11 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
"/* Error during generation, function not found: "
|
||||
"MyExtension::Idontexist */ 0");
|
||||
}
|
||||
SECTION("too much parameters") {
|
||||
auto node = parser.ParseExpression("MyExtension::GetNumberWith2Params(1, "
|
||||
{
|
||||
auto node = parser.ParseExpression("number",
|
||||
"MyExtension::GetNumberWith2Params(1, "
|
||||
"\"2\", MyExtension::GetNumber())");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -338,14 +291,13 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
"getNumberWith2Params(1, \"2\")");
|
||||
}
|
||||
}
|
||||
SECTION("function calls (capabilities)") {
|
||||
SECTION("supported capability") {
|
||||
SECTION("Invalid function calls (capabilities)") {
|
||||
{
|
||||
// Capability is supported, so the expression is valid.
|
||||
auto node = parser.ParseExpression(
|
||||
"string",
|
||||
"MySpriteObject.GetSomethingRequiringEffectCapability(123)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -354,29 +306,26 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
expressionCodeGenerator.GetOutput() ==
|
||||
"MySpriteObject.getSomethingRequiringEffectCapability(123) ?? \"\"");
|
||||
}
|
||||
SECTION("unsupported capability") {
|
||||
{
|
||||
// Capability is not supported, so the expression is not even valid.
|
||||
auto node =
|
||||
parser.ParseExpression("MyFakeObjectWithUnsupportedCapability."
|
||||
parser.ParseExpression("string",
|
||||
"MyFakeObjectWithUnsupportedCapability."
|
||||
"GetSomethingRequiringEffectCapability(123)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "\"\"");
|
||||
}
|
||||
SECTION("group with partial support") {
|
||||
{
|
||||
// We use a group, capability is supported only by one object of the
|
||||
// group. The expression itself is valid, but code generation should skip
|
||||
// the objects with unsupported capability.
|
||||
auto node = parser.ParseExpression(
|
||||
"AllObjects.GetSomethingRequiringEffectCapability(123)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
"string", "AllObjects.GetSomethingRequiringEffectCapability(123)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -387,87 +336,51 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
"MySpriteObject.getSomethingRequiringEffectCapability(123) ?? \"\"");
|
||||
}
|
||||
}
|
||||
SECTION("Function name") {
|
||||
auto node =
|
||||
parser.ParseExpression("MySpriteObject.GetObjectNumber");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() == "0");
|
||||
}
|
||||
SECTION("Invalid variables") {
|
||||
SECTION("empty variable") {
|
||||
{
|
||||
// Test an empty expression
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "") == "fakeBadVariable");
|
||||
}
|
||||
SECTION("only an unary operator") {
|
||||
{
|
||||
// Test a unary operator
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "objectvar", "-") ==
|
||||
"fakeBadVariable");
|
||||
}
|
||||
SECTION("only a binary operator") {
|
||||
{
|
||||
// Test an operator
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "globalvar", "/") ==
|
||||
"fakeBadVariable");
|
||||
}
|
||||
}
|
||||
SECTION("Invalid variables, using operators") {
|
||||
SECTION("unary operation") {
|
||||
{
|
||||
// Test a unary operator
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "objectvar", "-(var1)") ==
|
||||
"fakeBadVariable");
|
||||
}
|
||||
SECTION("binary operation") {
|
||||
{
|
||||
// Test an operator
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "globalvar", "var1+var2") ==
|
||||
"fakeBadVariable");
|
||||
}
|
||||
SECTION("multiple operation") {
|
||||
{
|
||||
// Test multiple operators
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "globalvar", "var1/var2/var3/var4") ==
|
||||
"fakeBadVariable");
|
||||
}
|
||||
}
|
||||
SECTION("Valid variables") {
|
||||
SECTION("simple variable") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable", "")
|
||||
== "getLayoutVariable(myVariable)");
|
||||
}
|
||||
SECTION("child dot accessor") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable.myChild", "")
|
||||
== "getLayoutVariable(myVariable).getChild(\"myChild\")");
|
||||
}
|
||||
SECTION("2 children") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable.child1.child2", "")
|
||||
== "getLayoutVariable(myVariable).getChild(\"child1\").getChild(\"child2\")");
|
||||
}
|
||||
SECTION("bracket access") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "scenevar", "myVariable[ \"hello\" + "
|
||||
"\"world\" ]", "")
|
||||
== "getLayoutVariable(myVariable).getChild(\"hello\" + \"world\")");
|
||||
}
|
||||
SECTION("object variable") {
|
||||
REQUIRE(gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "objectvar", "myVariable", "MySpriteObject")
|
||||
== "getVariableForObject(MySpriteObject, myVariable)");
|
||||
}
|
||||
}
|
||||
SECTION("Valid function calls with variables") {
|
||||
SECTION("Simple access") {
|
||||
SECTION("Scene variable") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"MyExtension::GetVariableAsNumber(myVariable)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
"number", "MyExtension::GetVariableAsNumber(myVariable)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -475,12 +388,11 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"returnVariable(getLayoutVariable(myVariable))");
|
||||
}
|
||||
SECTION("Global variable") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"number",
|
||||
"MyExtension::GetGlobalVariableAsNumber(myGlobalVariable)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -488,76 +400,13 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"returnVariable(getProjectVariable(myGlobalVariable))");
|
||||
}
|
||||
SECTION("Variables on different objects") {
|
||||
auto node = parser.ParseExpression(
|
||||
"MyExtension::GetStringWith2ObjectParamAnd2ObjectVarParam("
|
||||
"MySpriteObject, myVariable, MyOtherSpriteObject, myOtherVariable)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"getStringWith2ObjectParamAnd2ObjectVarParam(fakeObjectListOf_MySpriteObject, "
|
||||
"getVariableForObject(MySpriteObject, myVariable), "
|
||||
"fakeObjectListOf_MyOtherSpriteObject, "
|
||||
"getVariableForObject(MyOtherSpriteObject, myOtherVariable))");
|
||||
}
|
||||
SECTION("Variables on the same object") {
|
||||
auto node = parser.ParseExpression(
|
||||
"MyExtension::GetStringWith1ObjectParamAnd2ObjectVarParam("
|
||||
"MySpriteObject, myVariable, myOtherVariable)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("string",
|
||||
"",
|
||||
codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"getStringWith1ObjectParamAnd2ObjectVarParam(fakeObjectListOf_MySpriteObject, "
|
||||
"getVariableForObject(MySpriteObject, myVariable), "
|
||||
"getVariableForObject(MySpriteObject, myOtherVariable))");
|
||||
}
|
||||
SECTION("Object variable with object function call") {
|
||||
auto node = parser.ParseExpression(
|
||||
"MySpriteObject.GetObjectVariableAsNumber(myVariable)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(
|
||||
expressionCodeGenerator.GetOutput() ==
|
||||
"MySpriteObject.returnVariable(getVariableForObject("
|
||||
"MySpriteObject, myVariable)) ?? 0");
|
||||
}
|
||||
}
|
||||
SECTION("Child access") {
|
||||
SECTION("1 child") {
|
||||
auto node = parser.ParseExpression(
|
||||
"MyExtension::GetVariableAsNumber(myVariable.child1)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
node->Visit(expressionCodeGenerator);
|
||||
REQUIRE(expressionCodeGenerator.GetOutput() ==
|
||||
"returnVariable(getLayoutVariable(myVariable).getChild("
|
||||
"\"child1\"))");
|
||||
}
|
||||
SECTION("2 children") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"number",
|
||||
"MyExtension::GetVariableAsNumber(myVariable.child1.child2)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -566,13 +415,12 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
"returnVariable(getLayoutVariable(myVariable).getChild("
|
||||
"\"child1\").getChild(\"child2\"))");
|
||||
}
|
||||
SECTION("bracket access") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"number",
|
||||
"MyExtension::GetVariableAsNumber(myVariable[ \"hello\" + "
|
||||
"\"world\" ].child2)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -581,14 +429,13 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
"returnVariable(getLayoutVariable(myVariable).getChild("
|
||||
"\"hello\" + \"world\").getChild(\"child2\"))");
|
||||
}
|
||||
SECTION("bracket access with nested variable") {
|
||||
{
|
||||
auto node = parser.ParseExpression(
|
||||
"number",
|
||||
"MyExtension::GetVariableAsNumber(myVariable[ \"hello\" + "
|
||||
"MySpriteObject.GetObjectStringWith1Param(MyOtherSpriteObject."
|
||||
"GetObjectVariableAsNumber(mySecondVariable)) ].child2)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
@@ -615,10 +462,8 @@ TEST_CASE("ExpressionCodeGenerator", "[common][events]") {
|
||||
}
|
||||
SECTION("Mixed test (1)") {
|
||||
{
|
||||
auto node = parser.ParseExpression("-+-MyExtension::MouseX(,)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator("number",
|
||||
"",
|
||||
codeGenerator,
|
||||
auto node = parser.ParseExpression("number", "-+-MyExtension::MouseX(,)");
|
||||
gd::ExpressionCodeGenerator expressionCodeGenerator(codeGenerator,
|
||||
context);
|
||||
|
||||
REQUIRE(node);
|
||||
|
@@ -19,17 +19,16 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto& layout1 = project.InsertNewLayout("Layout1", 0);
|
||||
layout1.InsertNewObject(project, "MyExtension::Sprite", "MyObject", 0);
|
||||
|
||||
gd::ExpressionParser2 parser;
|
||||
gd::ExpressionParser2 parser(platform, project, layout1);
|
||||
|
||||
auto getCompletionsFor = [&](const gd::String& type,
|
||||
const gd::String& expression,
|
||||
size_t location) {
|
||||
auto node = parser.ParseExpression(expression);
|
||||
auto node = parser.ParseExpression(type, expression);
|
||||
REQUIRE(node != nullptr);
|
||||
return gd::ExpressionCompletionFinder::GetCompletionDescriptionsFor(
|
||||
platform, project, layout1, type, *node, location);
|
||||
*node, location);
|
||||
};
|
||||
|
||||
const std::vector<gd::ExpressionCompletionDescription>
|
||||
@@ -67,24 +66,6 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
REQUIRE(getCompletionsFor("number|string", "My", 2) ==
|
||||
expectedEmptyCompletions);
|
||||
}
|
||||
SECTION("Object or expression completions in a variable name") {
|
||||
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") {
|
||||
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") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForObject("object", "My", 0, 2)};
|
||||
@@ -162,17 +143,6 @@ TEST_CASE("ExpressionCompletionFinder", "[common][events]") {
|
||||
"MyExtension::GetVariableAsNumber(myVar",
|
||||
33) == expectedCompletions);
|
||||
}
|
||||
SECTION("Object function with a Variable as argument") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForVariable(
|
||||
"objectvar", "myVar", 35, 40, "MyObject")};
|
||||
getCompletionsFor("number",
|
||||
"MyObject.GetObjectVariableAsNumber(myVar",
|
||||
35);
|
||||
REQUIRE(getCompletionsFor("number",
|
||||
"MyObject.GetObjectVariableAsNumber(myVar",
|
||||
35) == expectedCompletions);
|
||||
}
|
||||
SECTION("Function with a Layer as argument") {
|
||||
std::vector<gd::ExpressionCompletionDescription> expectedCompletions{
|
||||
gd::ExpressionCompletionDescription::ForText(
|
||||
|
@@ -14,9 +14,10 @@
|
||||
|
||||
template <class TNode>
|
||||
bool CheckNodeAtLocationIs(gd::ExpressionParser2& parser,
|
||||
const gd::String& type,
|
||||
const gd::String& expression,
|
||||
size_t searchPosition) {
|
||||
auto node = parser.ParseExpression(expression);
|
||||
auto node = parser.ParseExpression(type, expression);
|
||||
REQUIRE(node != nullptr);
|
||||
return dynamic_cast<TNode*>(
|
||||
gd::ExpressionNodeLocationFinder::GetNodeAtPosition(
|
||||
@@ -25,9 +26,10 @@ bool CheckNodeAtLocationIs(gd::ExpressionParser2& parser,
|
||||
|
||||
template <class TNode>
|
||||
bool CheckParentNodeAtLocationIs(gd::ExpressionParser2& parser,
|
||||
const gd::String& type,
|
||||
const gd::String& expression,
|
||||
size_t searchPosition) {
|
||||
auto node = parser.ParseExpression(expression);
|
||||
auto node = parser.ParseExpression(type, expression);
|
||||
REQUIRE(node != nullptr);
|
||||
return dynamic_cast<TNode*>(
|
||||
gd::ExpressionNodeLocationFinder::GetParentNodeAtPosition(
|
||||
@@ -35,18 +37,20 @@ bool CheckParentNodeAtLocationIs(gd::ExpressionParser2& parser,
|
||||
}
|
||||
|
||||
bool CheckNoNodeAtLocation(gd::ExpressionParser2& parser,
|
||||
const gd::String& type,
|
||||
const gd::String& expression,
|
||||
size_t searchPosition) {
|
||||
auto node = parser.ParseExpression(expression);
|
||||
auto node = parser.ParseExpression(type, expression);
|
||||
REQUIRE(node != nullptr);
|
||||
return gd::ExpressionNodeLocationFinder::GetNodeAtPosition(
|
||||
*node, searchPosition) == nullptr;
|
||||
}
|
||||
|
||||
bool CheckNoParentNodeAtLocation(gd::ExpressionParser2& parser,
|
||||
const gd::String& type,
|
||||
const gd::String& expression,
|
||||
size_t searchPosition) {
|
||||
auto node = parser.ParseExpression(expression);
|
||||
auto node = parser.ParseExpression(type, expression);
|
||||
REQUIRE(node != nullptr);
|
||||
return gd::ExpressionNodeLocationFinder::GetParentNodeAtPosition(
|
||||
*node, searchPosition) == nullptr;
|
||||
@@ -59,21 +63,21 @@ TEST_CASE("ExpressionNodeLocationFinder", "[common][events]") {
|
||||
auto& layout1 = project.InsertNewLayout("Layout1", 0);
|
||||
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
|
||||
|
||||
gd::ExpressionParser2 parser;
|
||||
gd::ExpressionParser2 parser(platform, project, layout1);
|
||||
|
||||
SECTION("Empty expressions") {
|
||||
SECTION("Test 1") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::EmptyNode>(
|
||||
parser, "", 0) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "", 1) ==
|
||||
parser, "string", "", 0) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "string", "", 1) ==
|
||||
true);
|
||||
}
|
||||
SECTION("Test 2") {
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, " ", 0) ==
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "string", " ", 0) ==
|
||||
true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::EmptyNode>(
|
||||
parser, " ", 1) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, " ", 2) ==
|
||||
parser, "string", " ", 1) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "string", " ", 2) ==
|
||||
true);
|
||||
}
|
||||
}
|
||||
@@ -81,255 +85,270 @@ TEST_CASE("ExpressionNodeLocationFinder", "[common][events]") {
|
||||
SECTION("Valid text") {
|
||||
SECTION("Test 1") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser, "\"Hello world\"", 0) == true);
|
||||
parser, "string", "\"Hello world\"", 0) == true);
|
||||
}
|
||||
SECTION("Test 2") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser, "\"Hello world\"", 1) == true);
|
||||
parser, "string", "\"Hello world\"", 1) == true);
|
||||
}
|
||||
SECTION("Test 3") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser, "\"Hello world\"", 12) == true);
|
||||
parser, "string", "\"Hello world\"", 12) == true);
|
||||
}
|
||||
SECTION("Test 4") {
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "\"Hello world\"", 13) ==
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "string", "\"Hello world\"", 13) ==
|
||||
true);
|
||||
}
|
||||
SECTION("Test 5") {
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "\"Hello world\"", 99) ==
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "string", "\"Hello world\"", 99) ==
|
||||
true);
|
||||
}
|
||||
}
|
||||
SECTION("Valid text operators") {
|
||||
SECTION("Test 1") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser, "\"Hello \" + \"World\"", 1) == true);
|
||||
parser, "string", "\"Hello \" + \"World\"", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "\"Hello \" + \"World\"", 8) == true);
|
||||
parser, "string", "\"Hello \" + \"World\"", 8) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser, "\"Hello \" + \"World\"", 15) == true);
|
||||
parser, "string", "\"Hello \" + \"World\"", 15) == true);
|
||||
}
|
||||
}
|
||||
SECTION("Invalid texts") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(parser, "\"", 0) ==
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(parser, "string", "\"", 0) ==
|
||||
true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "\"", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(parser, "\"a", 1) ==
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "string", "\"", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(parser, "string", "\"a", 1) ==
|
||||
true);
|
||||
}
|
||||
|
||||
SECTION("Invalid parenthesis") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::SubExpressionNode>(
|
||||
parser, "((\"hello\"", 1) == true);
|
||||
parser, "string", "((\"hello\"", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser, "((\"hello\"", 2) == true);
|
||||
parser, "string", "((\"hello\"", 2) == true);
|
||||
}
|
||||
|
||||
SECTION("Invalid text operators") {
|
||||
SECTION("Test 1") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser, "\"Hello \" - \"World\"", 0) == true);
|
||||
parser, "string", "\"Hello \" - \"World\"", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser, "\"Hello \" - \"World\"", 1) == true);
|
||||
parser, "string", "\"Hello \" - \"World\"", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "\"Hello \" / \"World\"", 8) == true);
|
||||
parser, "string", "\"Hello \" / \"World\"", 8) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser, "\"Hello \" * \"World\"", 15) == true);
|
||||
parser, "string", "\"Hello \" * \"World\"", 15) == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Valid unary operators") {
|
||||
SECTION("Test 1") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::UnaryOperatorNode>(
|
||||
parser, "-123", 0) == true);
|
||||
parser, "number", "-123", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::UnaryOperatorNode>(
|
||||
parser, "+123", 0) == true);
|
||||
parser, "number", "+123", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "-123", 1) == true);
|
||||
parser, "number", "-123", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "-123", 2) == true);
|
||||
parser, "number", "-123", 2) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "-123", 3) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "-123", 4) == true);
|
||||
parser, "number", "-123", 3) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "number", "-123", 4) == true);
|
||||
}
|
||||
SECTION("Test 2") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::UnaryOperatorNode>(
|
||||
parser, "-+-123", 0) == true);
|
||||
parser, "number", "-+-123", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::UnaryOperatorNode>(
|
||||
parser, "-+-123", 1) == true);
|
||||
parser, "number", "-+-123", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::UnaryOperatorNode>(
|
||||
parser, "-+-123", 2) == true);
|
||||
parser, "number", "-+-123", 2) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "-+-123", 3) == true);
|
||||
parser, "number", "-+-123", 3) == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Invalid number operators") {
|
||||
SECTION("Test 1") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "12 ! 34", 0) == true);
|
||||
parser, "number", "12 ! 34", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "12 ! 34", 1) == true);
|
||||
parser, "number", "12 ! 34", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "12 ! 34", 2) == true);
|
||||
parser, "number", "12 ! 34", 2) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "12 ! 34", 3) == true);
|
||||
parser, "number", "12 ! 34", 3) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "12 ! 34", 4) == true);
|
||||
parser, "number", "12 ! 34", 4) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "12 ! 34", 5) == true);
|
||||
parser, "number", "12 ! 34", 5) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "12 ! 34", 6) == true);
|
||||
parser, "number", "12 ! 34", 6) == true);
|
||||
}
|
||||
SECTION("Test 2") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "1 / /2", 0) == true);
|
||||
parser, "number", "1 / /2", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "1 / /2", 1) == true);
|
||||
parser, "number", "1 / /2", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "1 / /2", 2) == true);
|
||||
parser, "number", "1 / /2", 2) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "1 / /2", 3) == true);
|
||||
parser, "number", "1 / /2", 3) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::EmptyNode>(
|
||||
parser, "1 / /2", 4) == true);
|
||||
parser, "number", "1 / /2", 4) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::EmptyNode>(
|
||||
parser, "1 / /2", 5) == true);
|
||||
parser, "number", "1 / /2", 5) == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Numbers and texts mismatchs") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(parser, "12+\"hello\"", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(parser, "12+\"hello\"", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(parser, "12+\"hello\"", 2) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(parser, "12+\"hello\"", 3) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(parser, "number", "12+\"hello\"", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(parser, "number", "12+\"hello\"", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(parser, "number", "12+\"hello\"", 2) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(parser, "number", "12+\"hello\"", 3) == true);
|
||||
}
|
||||
|
||||
SECTION("Numbers and texts mismatchs (parent node)") {
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "12+\"hello\"", 0) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "12+\"hello\"", 1) == true);
|
||||
REQUIRE(CheckNoParentNodeAtLocation(parser, "12+\"hello\"", 2) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "12+\"hello\"", 3) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "number", "12+\"hello\"", 0) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "number", "12+\"hello\"", 1) == true);
|
||||
REQUIRE(CheckNoParentNodeAtLocation(parser, "number", "12+\"hello\"", 2) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "number", "12+\"hello\"", 3) == true);
|
||||
}
|
||||
|
||||
SECTION("Valid objects") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::IdentifierNode>(
|
||||
parser, "HelloWorld1", 0) == true);
|
||||
parser, "object", "HelloWorld1", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::IdentifierNode>(
|
||||
parser, "HelloWorld1", 1) == true);
|
||||
parser, "object", "HelloWorld1", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::IdentifierNode>(
|
||||
parser, "HelloWorld1", 10) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "HelloWorld1", 11) == true);
|
||||
parser, "object", "HelloWorld1", 10) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "object", "HelloWorld1", 11) == true);
|
||||
}
|
||||
SECTION("Valid objects (parent node)") {
|
||||
REQUIRE(CheckNoParentNodeAtLocation(
|
||||
parser, "HelloWorld1", 0) == true);
|
||||
parser, "object", "HelloWorld1", 0) == true);
|
||||
}
|
||||
SECTION("Invalid objects") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::IdentifierNode>(
|
||||
parser, "a+b", 0) == true);
|
||||
parser, "object", "a+b", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "a+b", 1) == true);
|
||||
parser, "object", "a+b", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::IdentifierNode>(
|
||||
parser, "a+b", 2) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "a+b", 3) == true);
|
||||
parser, "object", "a+b", 2) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "object", "a+b", 3) == true);
|
||||
}
|
||||
SECTION("Valid function calls") {
|
||||
SECTION("Test 1") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "12 + MyExtension::GetNumber()", 0) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 0) ==
|
||||
true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "12 + MyExtension::GetNumber()", 1) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 1) ==
|
||||
true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "12 + MyExtension::GetNumber()", 2) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 2) ==
|
||||
true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "12 + MyExtension::GetNumber()", 3) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 3) ==
|
||||
true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "12 + MyExtension::GetNumber()", 4) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 4) ==
|
||||
true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "12 + MyExtension::GetNumber()", 5) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 5) ==
|
||||
true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "12 + MyExtension::GetNumber()", 27) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 27) ==
|
||||
true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "12 + MyExtension::GetNumber()", 28) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 28) ==
|
||||
true);
|
||||
REQUIRE(CheckNoNodeAtLocation(
|
||||
parser, "12 + MyExtension::GetNumber()", 29) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 29) ==
|
||||
true);
|
||||
}
|
||||
SECTION("Test 2") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
33) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
34) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
35) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
36) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
37) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
38) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
39) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
50) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
51) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
52) == true);
|
||||
}
|
||||
SECTION("Parent node") {
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "12 + MyExtension::GetNumber()", 0) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 0) ==
|
||||
true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(
|
||||
parser, "12 + MyExtension::GetNumber()", 6) ==
|
||||
parser, "number", "12 + MyExtension::GetNumber()", 6) ==
|
||||
true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
35) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
35) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser,
|
||||
"number",
|
||||
"MyExtension::GetNumberWith2Params(12, \"hello world\")",
|
||||
39) == true);
|
||||
}
|
||||
@@ -337,67 +356,66 @@ TEST_CASE("ExpressionNodeLocationFinder", "[common][events]") {
|
||||
|
||||
SECTION("Invalid function calls") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "Idontexist(12)", 0) == true);
|
||||
parser, "number", "Idontexist(12)", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "Idontexist(12)", 1) == true);
|
||||
parser, "number", "Idontexist(12)", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "Idontexist(12)", 2) == true);
|
||||
parser, "number", "Idontexist(12)", 2) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "Idontexist(12)", 10) == true);
|
||||
parser, "number", "Idontexist(12)", 10) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "Idontexist(12)", 11) == true);
|
||||
parser, "number", "Idontexist(12)", 11) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "Idontexist(12)", 12) == true);
|
||||
parser, "number", "Idontexist(12)", 12) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "Idontexist(12)", 13) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "Idontexist(12)", 14) ==
|
||||
parser, "number", "Idontexist(12)", 13) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "number", "Idontexist(12)", 14) ==
|
||||
true);
|
||||
}
|
||||
SECTION("Invalid function calls (parent node)") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(
|
||||
parser, "Idontexist(12)", 12) == true);
|
||||
parser, "number", "Idontexist(12)", 12) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "Idontexist(12)", 12) == true);
|
||||
parser, "number", "Idontexist(12)", 12) == true);
|
||||
}
|
||||
|
||||
SECTION("Unterminated function calls") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "Idontexist(", 0) == true);
|
||||
parser, "number", "Idontexist(", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "Idontexist(", 1) == true);
|
||||
parser, "number", "Idontexist(", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::FunctionCallNode>(
|
||||
parser, "Idontexist(", 10) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "Idontexist(", 11) == true);
|
||||
parser, "number", "Idontexist(", 10) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "number", "Idontexist(", 11) == true);
|
||||
}
|
||||
|
||||
SECTION("Valid variables") {
|
||||
SECTION("Test 1") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::IdentifierNode>(
|
||||
parser, "myVariable", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::IdentifierNode>(
|
||||
parser, "myVariable", 9) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "myVariable", 10) ==
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::VariableNode>(
|
||||
parser, "scenevar", "myVariable", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::VariableNode>(
|
||||
parser, "scenevar", "myVariable", 9) == true);
|
||||
REQUIRE(CheckNoNodeAtLocation(parser, "scenevar", "myVariable", 10) ==
|
||||
true);
|
||||
}
|
||||
SECTION("Test 2") {
|
||||
auto node = parser.ParseExpression("Var1.Child1");
|
||||
auto node = parser.ParseExpression("scenevar", "Var1.Child1");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
auto var1Node =
|
||||
gd::ExpressionNodeLocationFinder::GetNodeAtPosition(*node, 0);
|
||||
REQUIRE(dynamic_cast<gd::IdentifierNode*>(var1Node) != nullptr);
|
||||
REQUIRE(dynamic_cast<gd::IdentifierNode&>(*var1Node).identifierName == "Var1");
|
||||
REQUIRE(dynamic_cast<gd::VariableNode*>(var1Node) != nullptr);
|
||||
REQUIRE(dynamic_cast<gd::VariableNode&>(*var1Node).name == "Var1");
|
||||
|
||||
// It's actually the same node.
|
||||
auto child1Node =
|
||||
gd::ExpressionNodeLocationFinder::GetNodeAtPosition(*node, 4);
|
||||
REQUIRE(dynamic_cast<gd::IdentifierNode*>(child1Node) != nullptr);
|
||||
REQUIRE(dynamic_cast<gd::IdentifierNode&>(*child1Node).childIdentifierName ==
|
||||
REQUIRE(dynamic_cast<gd::VariableAccessorNode*>(child1Node) != nullptr);
|
||||
REQUIRE(dynamic_cast<gd::VariableAccessorNode&>(*child1Node).name ==
|
||||
"Child1");
|
||||
}
|
||||
SECTION("Test 3") {
|
||||
auto node = parser.ParseExpression(
|
||||
"myVariable[ \"My named children\" ].grandChild");
|
||||
"scenevar", "myVariable[ \"My named children\" ].grandChild");
|
||||
REQUIRE(node != nullptr);
|
||||
|
||||
auto myVariableNode =
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -21,15 +21,13 @@ TEST_CASE("ExpressionParser2 - Benchmarks", "[common][events]") {
|
||||
auto &layout1 = project.InsertNewLayout("Layout1", 0);
|
||||
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
|
||||
|
||||
gd::ExpressionParser2 parser;
|
||||
gd::ExpressionParser2 parser(platform, project, layout1);
|
||||
|
||||
auto parseExpression = [&parser, &project, &platform, &layout1](const gd::String &expression) {
|
||||
auto parseExpressionWithType = [&parser, &project, &platform, &layout1,
|
||||
auto parseExpression = [&parser](const gd::String &expression) {
|
||||
auto parseExpressionWithType = [&parser,
|
||||
&expression](const gd::String &type) {
|
||||
auto node = parser.ParseExpression(expression);
|
||||
auto node = parser.ParseExpression(type, expression);
|
||||
REQUIRE(node != nullptr);
|
||||
gd::ExpressionValidator validator(platform, project, layout1, type);
|
||||
node->Visit(validator);
|
||||
};
|
||||
|
||||
parseExpressionWithType("number");
|
||||
|
@@ -21,7 +21,7 @@ TEST_CASE("ExpressionParser2 - Naughty strings", "[common][events]") {
|
||||
auto &layout1 = project.InsertNewLayout("Layout1", 0);
|
||||
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
|
||||
|
||||
gd::ExpressionParser2 parser;
|
||||
gd::ExpressionParser2 parser(platform, project, layout1);
|
||||
|
||||
SECTION("Check that no naughty string crash the parser") {
|
||||
std::string inputFile = std::string(__FILE__) + "-blns.txt";
|
||||
@@ -31,9 +31,9 @@ TEST_CASE("ExpressionParser2 - Naughty strings", "[common][events]") {
|
||||
std::string line;
|
||||
size_t count = 0;
|
||||
while ( std::getline (myfile,line) ) {
|
||||
auto node1 = parser.ParseExpression(line.c_str());
|
||||
auto node1 = parser.ParseExpression("string", line.c_str());
|
||||
REQUIRE(node1 != nullptr);
|
||||
auto node2 = parser.ParseExpression(line.c_str());
|
||||
auto node2 = parser.ParseExpression("number", line.c_str());
|
||||
REQUIRE(node2 != nullptr);
|
||||
|
||||
count++;
|
||||
|
@@ -20,12 +20,12 @@ TEST_CASE("ExpressionParser2NodePrinter", "[common][events]") {
|
||||
auto &layout1 = project.InsertNewLayout("Layout1", 0);
|
||||
layout1.InsertNewObject(project, "MyExtension::Sprite", "MySpriteObject", 0);
|
||||
|
||||
gd::ExpressionParser2 parser;
|
||||
gd::ExpressionParser2 parser(platform, project, layout1);
|
||||
|
||||
auto testPrinter = [&parser](const gd::String &type,
|
||||
const gd::String &expression,
|
||||
const gd::String &expectedOutput = "") {
|
||||
auto node = parser.ParseExpression(expression);
|
||||
auto node = parser.ParseExpression(type, expression);
|
||||
REQUIRE(node != nullptr);
|
||||
gd::ExpressionParser2NodePrinter printer;
|
||||
node->Visit(printer);
|
||||
|
2
ExtLibs/Readme.md
Normal file
2
ExtLibs/Readme.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Uncompress here the external libraries needed: SFML.
|
||||
Refer to [the documentation](https://docs.gdevelop-app.com/GDCore%20Documentation/setup_dev_env.html) for more information and to get the download links of the libraries.
|
@@ -19,7 +19,8 @@ namespace gdjs {
|
||||
|
||||
constructor(runtimeScene, behaviorData, owner) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
this._relativeToOriginalWindowSize = !!behaviorData.relativeToOriginalWindowSize;
|
||||
this._relativeToOriginalWindowSize =
|
||||
!!behaviorData.relativeToOriginalWindowSize;
|
||||
this._leftEdgeAnchor = behaviorData.leftEdgeAnchor;
|
||||
this._rightEdgeAnchor = behaviorData.rightEdgeAnchor;
|
||||
this._topEdgeAnchor = behaviorData.topEdgeAnchor;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// @ts-check
|
||||
describe('gdjs.AnchorRuntimeBehavior', function () {
|
||||
describe.only('gdjs.AnchorRuntimeBehavior', function () {
|
||||
const runtimeGame = new gdjs.RuntimeGame({
|
||||
variables: [],
|
||||
resources: { resources: [] },
|
||||
|
@@ -95,10 +95,11 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
updateFontFamily(): void {
|
||||
this._pixiObject.textStyles.default.fontFamily = this._object._runtimeScene
|
||||
.getGame()
|
||||
.getFontManager()
|
||||
.getFontFamily(this._object._fontFamily);
|
||||
this._pixiObject.textStyles.default.fontFamily =
|
||||
this._object._runtimeScene
|
||||
.getGame()
|
||||
.getFontManager()
|
||||
.getFontFamily(this._object._fontFamily);
|
||||
this._pixiObject.dirty = true;
|
||||
}
|
||||
|
||||
|
@@ -169,5 +169,6 @@ namespace gdjs {
|
||||
return this._pixiObject.textHeight * this.getScale();
|
||||
}
|
||||
}
|
||||
export const BitmapTextRuntimeObjectRenderer = BitmapTextRuntimeObjectPixiRenderer;
|
||||
export const BitmapTextRuntimeObjectRenderer =
|
||||
BitmapTextRuntimeObjectPixiRenderer;
|
||||
}
|
||||
|
@@ -34,6 +34,7 @@ void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
std::make_shared<DestroyOutsideBehavior>(),
|
||||
std::shared_ptr<gd::BehaviorsSharedData>());
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
aut.AddCondition("ExtraBorder",
|
||||
_("Additional border"),
|
||||
_("Compare the additional border that the object must cross "
|
||||
@@ -46,7 +47,8 @@ void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.AddParameter("behavior", _("Behavior"), "DestroyOutside")
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced()
|
||||
.SetFunctionName("GetExtraBorder");
|
||||
.SetFunctionName("GetExtraBorder")
|
||||
.SetIncludeFile("DestroyOutsideBehavior/DestroyOutsideRuntimeBehavior.h");
|
||||
|
||||
aut.AddAction("ExtraBorder",
|
||||
_("Additional border"),
|
||||
@@ -61,5 +63,7 @@ void DeclareDestroyOutsideBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced()
|
||||
.SetFunctionName("SetExtraBorder")
|
||||
.SetGetter("GetExtraBorder");
|
||||
.SetGetter("GetExtraBorder")
|
||||
.SetIncludeFile("DestroyOutsideBehavior/DestroyOutsideRuntimeBehavior.h");
|
||||
#endif
|
||||
}
|
||||
|
@@ -414,9 +414,8 @@ namespace gdjs {
|
||||
return;
|
||||
}
|
||||
if (this.dialogueData.select) {
|
||||
this.selectedOption = gdjs.dialogueTree._normalizedOptionIndex(
|
||||
optionIndex
|
||||
);
|
||||
this.selectedOption =
|
||||
gdjs.dialogueTree._normalizedOptionIndex(optionIndex);
|
||||
this.selectedOptionUpdated = true;
|
||||
}
|
||||
};
|
||||
|
@@ -52,9 +52,8 @@ namespace gdjs {
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
|
||||
//Try mouse
|
||||
const mouseDraggableManager = DraggableManager.getMouseManager(
|
||||
runtimeScene
|
||||
);
|
||||
const mouseDraggableManager =
|
||||
DraggableManager.getMouseManager(runtimeScene);
|
||||
if (
|
||||
inputManager.isMouseButtonPressed(0) &&
|
||||
!mouseDraggableManager.isDragging(this)
|
||||
@@ -107,9 +106,8 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene) {
|
||||
const mouseDraggableManager = DraggableManager.getMouseManager(
|
||||
runtimeScene
|
||||
);
|
||||
const mouseDraggableManager =
|
||||
DraggableManager.getMouseManager(runtimeScene);
|
||||
mouseDraggableManager.leftPressedLastFrame = runtimeScene
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
@@ -174,9 +172,8 @@ namespace gdjs {
|
||||
if (!runtimeScene.touchDraggableManagers[touchId]) {
|
||||
//Create the shared manager if necessary.
|
||||
// @ts-ignore
|
||||
runtimeScene.touchDraggableManagers[
|
||||
touchId
|
||||
] = new TouchDraggableManager(runtimeScene, touchId);
|
||||
runtimeScene.touchDraggableManagers[touchId] =
|
||||
new TouchDraggableManager(runtimeScene, touchId);
|
||||
}
|
||||
// @ts-ignore
|
||||
return runtimeScene.touchDraggableManagers[touchId];
|
||||
|
@@ -6,7 +6,8 @@ namespace gdjs {
|
||||
},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const adjustmentFilter = (filter as unknown) as PIXI.filters.AdjustmentFilter;
|
||||
const adjustmentFilter =
|
||||
filter as unknown as PIXI.filters.AdjustmentFilter;
|
||||
if (parameterName === 'gamma') {
|
||||
adjustmentFilter.gamma = value;
|
||||
} else if (parameterName === 'saturation') {
|
||||
|
@@ -6,7 +6,8 @@ namespace gdjs {
|
||||
},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const advancedBloomFilter = (filter as unknown) as PIXI.filters.AdvancedBloomFilter;
|
||||
const advancedBloomFilter =
|
||||
filter as unknown as PIXI.filters.AdvancedBloomFilter;
|
||||
if (parameterName === 'threshold') {
|
||||
advancedBloomFilter.threshold = value;
|
||||
} else if (parameterName === 'bloomScale') {
|
||||
|
@@ -6,7 +6,7 @@ namespace gdjs {
|
||||
},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const asciiFilter = (filter as unknown) as PIXI.filters.AsciiFilter;
|
||||
const asciiFilter = filter as unknown as PIXI.filters.AsciiFilter;
|
||||
if (parameterName === 'size') {
|
||||
asciiFilter.size = value;
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ namespace gdjs {
|
||||
},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter;
|
||||
const bevelFilter = filter as unknown as PIXI.filters.BevelFilter;
|
||||
if (parameterName === 'rotation') {
|
||||
bevelFilter.rotation = value;
|
||||
} else if (parameterName === 'thickness') {
|
||||
@@ -21,16 +21,14 @@ namespace gdjs {
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {
|
||||
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter;
|
||||
const bevelFilter = filter as unknown as PIXI.filters.BevelFilter;
|
||||
if (parameterName === 'lightColor') {
|
||||
bevelFilter.lightColor = gdjs.PixiFiltersTools.rgbOrHexToHexNumber(
|
||||
value
|
||||
);
|
||||
bevelFilter.lightColor =
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value);
|
||||
}
|
||||
if (parameterName === 'shadowColor') {
|
||||
bevelFilter.shadowColor = gdjs.PixiFiltersTools.rgbOrHexToHexNumber(
|
||||
value
|
||||
);
|
||||
bevelFilter.shadowColor =
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value);
|
||||
}
|
||||
},
|
||||
updateBooleanParameter: function (filter, parameterName, value) {},
|
||||
|
@@ -9,7 +9,7 @@ namespace gdjs {
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
// @ts-ignore - unsure why PIXI.filters is not recognised.
|
||||
const colorMatrix = (filter as unknown) as PIXI.filters.ColorMatrixFilter;
|
||||
const colorMatrix = filter as unknown as PIXI.filters.ColorMatrixFilter;
|
||||
if (parameterName !== 'opacity') {
|
||||
return;
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ namespace gdjs {
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
// @ts-ignore - unsure why PIXI.filters is not recognised.
|
||||
const blendingModeFilter = (filter as unknown) as PIXI.filters.AlphaFilter;
|
||||
const blendingModeFilter = filter as unknown as PIXI.filters.AlphaFilter;
|
||||
if (parameterName === 'alpha') {
|
||||
blendingModeFilter.alpha = value;
|
||||
} else if (parameterName === 'blendmode') {
|
||||
|
@@ -9,7 +9,8 @@ namespace gdjs {
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
// @ts-ignore - unsure why PIXI.filters is not recognised.
|
||||
const brightnessFilter = (filter as unknown) as PIXI.filters.ColorMatrixFilter;
|
||||
const brightnessFilter =
|
||||
filter as unknown as PIXI.filters.ColorMatrixFilter;
|
||||
if (parameterName !== 'brightness') {
|
||||
return;
|
||||
}
|
||||
|
@@ -6,7 +6,8 @@ namespace gdjs {
|
||||
},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const bulgePinchFilter = (filter as unknown) as PIXI.filters.BulgePinchFilter;
|
||||
const bulgePinchFilter =
|
||||
filter as unknown as PIXI.filters.BulgePinchFilter;
|
||||
if (parameterName === 'centerX') {
|
||||
bulgePinchFilter.center[0] = value;
|
||||
} else if (parameterName === 'centerY') {
|
||||
|
@@ -19,7 +19,7 @@ namespace gdjs {
|
||||
},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const colorMapFilter = (filter as unknown) as PIXI.filters.ColorMapFilter;
|
||||
const colorMapFilter = filter as unknown as PIXI.filters.ColorMapFilter;
|
||||
if (parameterName === 'mix') {
|
||||
colorMapFilter.mix = gdjs.PixiFiltersTools.clampValue(
|
||||
value / 100,
|
||||
@@ -30,7 +30,7 @@ namespace gdjs {
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {},
|
||||
updateBooleanParameter: function (filter, parameterName, value) {
|
||||
const colorMapFilter = (filter as unknown) as PIXI.filters.ColorMapFilter;
|
||||
const colorMapFilter = filter as unknown as PIXI.filters.ColorMapFilter;
|
||||
if (parameterName === 'nearest') {
|
||||
colorMapFilter.nearest = value;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user