Compare commits

...

34 Commits

Author SHA1 Message Date
Florian Rival
24091db88b Add deploy step to upload GDJS (and extensions) Runtime for web-app 2020-02-05 22:09:16 +00:00
Florian Rival
4ec3f1f082 Merge pull request #1406 from 4ian/refactor/emscripten-1.39
Upgrade to Emscripten 1.39.6
2020-02-05 21:58:31 +00:00
Florian Rival
991378e004 Remove debug message 2020-02-05 21:42:28 +00:00
Florian Rival
dfaee92d24 Fix GDevelop.js tests on Windows 2020-02-05 21:35:28 +00:00
Florian Rival
b07c71cb9c Exclude emsdk from tests in GDevelop.js 2020-02-05 21:27:41 +00:00
Florian Rival
cb0c0f903f Avoid full rebuild when changing a CMake parameter in GDevelop.js 2020-02-05 20:52:03 +00:00
Florian Rival
a81a121a8d Fix test coverage not running with Node environment 2020-02-02 20:24:31 +00:00
Florian Rival
7bf892c7eb Upgrade to Emscripten 1.39.6 2020-02-02 19:32:09 +00:00
Aurélien Vivet
ce4fdbe4f8 Add option to search in event texts (comments, group names) (#1398) 2020-02-01 18:45:15 +00:00
Florian Rival
d82bbdc1af Create CNAME for hosting on editor.gdevelop-app.com
This file is required by GitHub when using a custom domain with GitHub pages.
Now required because of using Cloudflare directly instead of Cloudfront.
2020-02-01 14:01:33 +00:00
Florian Rival
62dca91637 Fix formatting 2020-02-01 13:00:51 +00:00
Florian Rival
1e1c5f7206 Fix drag'n'drop of selected event invalidating the event in memory (potential crash) 2020-02-01 12:33:50 +00:00
Florian Rival
7c9e6ee6f1 Prevent larger texts in landscape mode on Safari iOS 2020-01-30 21:29:55 +00:00
Florian Rival
5690de71c5 Remove useless define in GDevelop.js 2020-01-30 08:24:48 +00:00
Florian Rival
eae2a06a4e Improve export speed (~20%) by memoizing mangled names 2020-01-28 23:57:37 +00:00
Florian Rival
4affa25672 Fix compilation on recent compilers
Fix compilation with latest Emscripten
2020-01-28 22:49:54 +00:00
Florian Rival
7b30f63cb1 Remove unused variables 2020-01-27 23:15:27 +00:00
Arthur Pacaud
574bdaaf41 Refactor SpriteRuntimeObject types to add prefix "Sprite" (#1378)
Also remove useless parseFloat
2020-01-27 22:54:28 +00:00
Florian Rival
bff43ee771 Remove dead code related to old ExpressionParser 2020-01-27 22:08:48 +00:00
Aurélien Vivet
9b9b6c5996 Fix usage of getFontFamily in BBText instance renderer (#1399) 2020-01-27 20:51:07 +00:00
Florian Rival
721872e45b Fix race condition between extension loading and GDJS development watcher 2020-01-27 20:18:35 +00:00
Arthur Pacaud
edd9ec94cf Add @arthuro555 to credits (#1396) 2020-01-27 18:21:18 +00:00
Florian Rival
c986c52409 Add document explaining platforms and exporters 2020-01-26 20:43:39 +00:00
Aurélien Vivet
168b8d3fea Simplify the Loop checkbox in Sprite editor (#1397) 2020-01-26 17:20:47 +00:00
Florian Rival
47025329dd Remove remaining old functions to register objects/behaviors 2020-01-26 10:53:49 +00:00
Aurélien Vivet
9f05a65ed2 Add font selector for BBText object (#1394) 2020-01-25 19:44:13 +00:00
Florian Rival
370c6d03ad Update estimated build time for electron builds 2020-01-20 21:32:30 +00:00
Aurélien Vivet
b650ff3aa5 Improve credits (#1391) 2020-01-20 20:34:56 +00:00
Florian Rival
285ff6f5f5 Update the script to extract expressions reference 2020-01-19 15:29:59 +00:00
Florian Rival
81f292941f Add help button in ExpressionSelector to open expressions reference 2020-01-19 14:12:25 +00:00
Florian Rival
eb27ba7c86 Improve script to extract expressions reference documentation
Still need to add parameters
2020-01-19 12:27:51 +00:00
Florian Rival
01a844c356 Refactor import-GDJS-Runtime script to use Node.js 2020-01-18 14:27:36 +00:00
Arthur Pacaud
054e48227c Make object and behavior registering more explicit (#1379) 2020-01-17 22:49:24 +00:00
Florian Rival
9adc40a55d Add script to extract all the expressions available in GDevelop 2020-01-16 23:44:26 +00:00
158 changed files with 5896 additions and 8786 deletions

View File

@@ -19,7 +19,7 @@ jobs:
- run:
name: Install Emscripten (for GDevelop.js)
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install sdk-fastcomp-1.37.37-64bit && ./emsdk activate sdk-fastcomp-1.37.37-64bit && cd ..
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
- run:
name: Install Wine for Electron builder

3
.gitignore vendored
View File

@@ -44,9 +44,6 @@
/Binaries/**/JsPlatform/*.dll.a
/Binaries/Output/Release_Windows/newIDE
*.autosave
/Binaries/Output/libGD.js/Release
/Binaries/Output/libGD.js/Debug
/Binaries/Output/libGD.js/libGD.raw.js
!/GDCpp/scripts/bcp.exe
!/scripts/libgettextlib-0-17.dll
!/scripts/libgettextsrc-0-17.dll

View File

@@ -24,7 +24,7 @@ addons:
- /$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)/commit/$(git rev-parse HEAD)
- /$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)/latest
paths:
- Binaries/Output/libGD.js/Release
- Binaries/embuild/GDevelop.js
apt:
sources:
- ubuntu-toolchain-r-test
@@ -63,8 +63,8 @@ install:
# Install Emscripten (for GDevelop.js)
- git clone https://github.com/juj/emsdk.git
- cd emsdk
- ./emsdk install sdk-fastcomp-1.37.37-64bit
- ./emsdk activate sdk-fastcomp-1.37.37-64bit
- ./emsdk install 1.39.6
- ./emsdk activate 1.39.6
- source ./emsdk_env.sh
- cd ..
# Install GDevelop.js dependencies and compile it

View File

@@ -83,7 +83,8 @@
"__threading_support": "cpp",
"any": "cpp",
"array": "cpp",
"cinttypes": "cpp"
"cinttypes": "cpp",
"numeric": "cpp"
},
"files.exclude": {
"Binaries/*build*": true,

View File

@@ -51,7 +51,12 @@ file(GLOB_RECURSE formatted_source_files tests/* GDCore/Events/* GDCore/Extensio
list(REMOVE_ITEM formatted_source_files "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.h" "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs_dialogs_bitmaps.cpp")
gd_add_clang_utils(GDCore "${formatted_source_files}")
add_library(GDCore SHARED ${source_files})
IF(EMSCRIPTEN)
# Emscripten treats all libraries as static libraries
add_library(GDCore STATIC ${source_files})
ELSE()
add_library(GDCore SHARED ${source_files})
ENDIF()
add_dependencies(GDCore GDVersion)
IF(EMSCRIPTEN)
set_target_properties(GDCore PROPERTIES SUFFIX ".bc")

View File

@@ -12,6 +12,15 @@ using namespace std;
namespace gd {
vector<gd::String> CommentEvent::GetAllSearchableStrings() const {
vector<gd::String> allSearchableStrings;
allSearchableStrings.push_back(com1);
allSearchableStrings.push_back(com2); ///< Com2 is deprecated
return allSearchableStrings;
}
void CommentEvent::SerializeTo(SerializerElement &element) const {
element.AddChild("color")
.SetAttribute("r", r)

View File

@@ -7,10 +7,11 @@
#define COMMENTEVENT_H
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
namespace gd {
class Layout;
class Project;
}
} // namespace gd
namespace gd {
@@ -45,6 +46,8 @@ class GD_CORE_API CommentEvent : public gd::BaseEvent {
const gd::String& GetComment() const { return com1; }
void SetComment(const gd::String& comment) { com1 = comment; }
virtual std::vector<gd::String> GetAllSearchableStrings() const;
virtual void SerializeTo(SerializerElement& element) const;
virtual void UnserializeFrom(gd::Project& project,
const SerializerElement& element);

View File

@@ -5,10 +5,6 @@
*/
#include "ForEachEvent.h"
#include <iostream>
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Serialization/SerializerElement.h"

View File

@@ -19,6 +19,14 @@ namespace gd {
GroupEvent::GroupEvent()
: BaseEvent(), creationTime(0), colorR(74), colorG(176), colorB(228) {}
vector<gd::String> GroupEvent::GetAllSearchableStrings() const {
vector<gd::String> allSearchableStrings;
allSearchableStrings.push_back(name);
return allSearchableStrings;
}
void GroupEvent::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", name);
element.SetAttribute("source", source);

View File

@@ -106,6 +106,8 @@ class GD_CORE_API GroupEvent : public gd::BaseEvent {
virtual const gd::EventsList& GetSubEvents() const { return events; };
virtual gd::EventsList& GetSubEvents() { return events; };
virtual std::vector<gd::String> GetAllSearchableStrings() const;
virtual void SerializeTo(SerializerElement& element) const;
virtual void UnserializeFrom(gd::Project& project,
const SerializerElement& element);

View File

@@ -5,9 +5,6 @@
*/
#include "RepeatEvent.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Serialization/SerializerElement.h"

View File

@@ -6,9 +6,6 @@
#if defined(GD_IDE_ONLY)
#include "WhileEvent.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Serialization/SerializerElement.h"

View File

@@ -4,8 +4,6 @@
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Parsers/ExpressionParser.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"

View File

@@ -35,10 +35,6 @@ namespace gd {
* \brief Internal class used to generate code from events
*/
class GD_CORE_API EventsCodeGenerator {
// Compatiblity with old ExpressionParser
friend class CallbacksForGeneratingExpressionCode;
friend class VariableCodeGenerationCallbacks;
// end of compatibility code
friend class ExpressionCodeGenerator;
public:

View File

@@ -24,117 +24,14 @@
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
// Compatibility with old ExpressionParser
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/CodeGeneration/VariableParserCallbacks.h"
#include "GDCore/Events/Parsers/ExpressionParser.h"
#include "GDCore/Events/Parsers/VariableParser.h"
// end of compatibility code
namespace gd {
bool ExpressionCodeGenerator::useOldExpressionParser = false;
gd::String ExpressionCodeGenerator::GenerateExpressionCode(
EventsCodeGenerator& codeGenerator,
EventsCodeGenerationContext& context,
const gd::String& type,
const gd::String& expression,
const gd::String& objectName) {
// Compatibility with old ExpressionParser
if (useOldExpressionParser) {
if (type == "number") {
gd::String code = "";
gd::CallbacksForGeneratingExpressionCode callbacks(
code, codeGenerator, context);
gd::ExpressionParser parser(expression);
if (!parser.ParseMathExpression(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
callbacks) ||
code.empty()) {
std::cout << "Error (old ExpressionParser): \""
<< parser.GetFirstError() << "\" in: \"" << expression
<< "\" (number)" << std::endl;
code = "0";
}
return code;
} else if (type == "string") {
gd::String code = "";
gd::CallbacksForGeneratingExpressionCode callbacks(
code, codeGenerator, context);
gd::ExpressionParser parser(expression);
if (!parser.ParseStringExpression(
codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
callbacks) ||
code.empty()) {
std::cout << "Error (old ExpressionParser): \""
<< parser.GetFirstError() << "\" in: \"" << expression
<< "\" (string)" << std::endl;
code = "\"\"";
}
return code;
} else if (type == "scenevar") {
gd::String code = "";
gd::VariableCodeGenerationCallbacks callbacks(
code,
codeGenerator,
context,
gd::EventsCodeGenerator::LAYOUT_VARIABLE);
gd::VariableParser parser(expression);
if (!parser.Parse(callbacks)) {
std::cout << "Error (old VariableParser) :" << parser.GetFirstError()
<< " in: " << expression << std::endl;
code = codeGenerator.GenerateBadVariable();
}
return code;
} else if (type == "globalvar") {
gd::String code = "";
gd::VariableCodeGenerationCallbacks callbacks(
code,
codeGenerator,
context,
gd::EventsCodeGenerator::PROJECT_VARIABLE);
gd::VariableParser parser(expression);
if (!parser.Parse(callbacks)) {
std::cout << "Error (old VariableParser) :" << parser.GetFirstError()
<< " in: " << expression << std::endl;
code = codeGenerator.GenerateBadVariable();
}
return code;
} else if (type == "objectvar") {
gd::String code = "";
// Object is either the object of the previous parameter or, if it is
// empty, the object being picked by the instruction.
gd::String object =
objectName.empty() ? context.GetCurrentObject() : objectName;
gd::VariableCodeGenerationCallbacks callbacks(
code, codeGenerator, context, object);
gd::VariableParser parser(expression);
if (!parser.Parse(callbacks)) {
std::cout << "Error (old VariableParser) :" << parser.GetFirstError()
<< " in: " << expression << std::endl;
code = codeGenerator.GenerateBadVariable();
}
return code;
}
std::cout << "Type error (old ExpressionParser): type \"" << type
<< "\" is not supported" << std::endl;
return "/* Error during code generation: type " + type +
" is not supported for old ExpressionParser. */ 0";
}
// end of compatibility code
gd::ExpressionParser2 parser(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups());

View File

@@ -60,11 +60,6 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
const gd::String& expression,
const gd::String& objectName = "");
static void UseOldExpressionParser(bool enable) {
useOldExpressionParser = enable;
};
static bool IsUsingOldExpressionParser() { return useOldExpressionParser; };
const gd::String& GetOutput() { return output; };
protected:
@@ -107,11 +102,9 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
gd::String output;
EventsCodeGenerator& codeGenerator;
EventsCodeGenerationContext& context;
static bool useOldExpressionParser;
};
} // namespace gd
#endif // GDCORE_ExpressionCodeGenerator_H
#endif
#endif

View File

@@ -1,229 +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 "ExpressionsCodeGeneration.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/Parsers/ExpressionParser.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
using namespace std;
namespace gd {
CallbacksForGeneratingExpressionCode::CallbacksForGeneratingExpressionCode(
gd::String& plainExpression_,
EventsCodeGenerator& codeGenerator_,
EventsCodeGenerationContext& context_)
: plainExpression(plainExpression_),
codeGenerator(codeGenerator_),
context(context_) {}
void CallbacksForGeneratingExpressionCode::OnConstantToken(gd::String text) {
plainExpression += text;
};
void CallbacksForGeneratingExpressionCode::OnStaticFunction(
gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
codeGenerator.AddIncludeFiles(
expressionInfo.codeExtraInformation.GetIncludeFiles());
// Launch custom code generator if needed
if (expressionInfo.codeExtraInformation.HasCustomCodeGenerator()) {
plainExpression += expressionInfo.codeExtraInformation.customCodeGenerator(
parameters, codeGenerator, context);
return;
}
// Special case: For strings expressions, function without name is a string.
if (GetReturnType() == "string" && functionName.empty()) {
if (parameters.empty()) return;
plainExpression +=
codeGenerator.ConvertToStringExplicit(parameters[0].GetPlainString());
return;
}
// Prepare parameters
std::vector<gd::String> parametersCode =
codeGenerator.GenerateParametersCodes(
parameters, expressionInfo.parameters, context);
gd::String parametersStr;
for (std::size_t i = 0; i < parametersCode.size(); ++i) {
if (i != 0) parametersStr += ", ";
parametersStr += parametersCode[i];
}
plainExpression += expressionInfo.codeExtraInformation.functionCallName +
"(" + parametersStr + ")";
};
void CallbacksForGeneratingExpressionCode::OnObjectFunction(
gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
const gd::ObjectsContainer& globalObjectsAndGroups = codeGenerator.GetGlobalObjectsAndGroups();
const gd::ObjectsContainer& objectsAndGroups = codeGenerator.GetObjectsAndGroups();
codeGenerator.AddIncludeFiles(
expressionInfo.codeExtraInformation.GetIncludeFiles());
if (parameters.empty()) return;
// Launch custom code generator if needed
if (expressionInfo.codeExtraInformation.HasCustomCodeGenerator()) {
plainExpression += expressionInfo.codeExtraInformation.customCodeGenerator(
parameters, codeGenerator, context);
return;
}
// Prepare parameters
std::vector<gd::String> parametersCode =
codeGenerator.GenerateParametersCodes(
parameters, expressionInfo.parameters, context);
gd::String parametersStr;
for (std::size_t i = 1; i < parametersCode.size(); ++i) {
if (i != 1) parametersStr += ", ";
parametersStr += parametersCode[i];
}
gd::String output = GetReturnType() == "string" ? "\"\"" : "0";
// Get object(s) concerned by function call
std::vector<gd::String> realObjects =
codeGenerator.ExpandObjectsName(parameters[0].GetPlainString(), context);
for (std::size_t i = 0; i < realObjects.size(); ++i) {
context.ObjectsListNeeded(realObjects[i]);
gd::String objectType = gd::GetTypeOfObject(globalObjectsAndGroups, objectsAndGroups, realObjects[i]);
const ObjectMetadata& objInfo = MetadataProvider::GetObjectMetadata(
codeGenerator.GetPlatform(), objectType);
// Build gd::String to access the object
codeGenerator.AddIncludeFiles(objInfo.includeFiles);
output = codeGenerator.GenerateObjectFunctionCall(
realObjects[i],
objInfo,
expressionInfo.codeExtraInformation,
parametersStr,
output,
context);
}
plainExpression += output;
};
void CallbacksForGeneratingExpressionCode::OnObjectBehaviorFunction(
gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
const gd::ObjectsContainer& globalObjectsAndGroups = codeGenerator.GetGlobalObjectsAndGroups();
const gd::ObjectsContainer& objectsAndGroups = codeGenerator.GetObjectsAndGroups();
codeGenerator.AddIncludeFiles(
expressionInfo.codeExtraInformation.GetIncludeFiles());
if (parameters.size() < 2) return;
// Launch custom code generator if needed
if (expressionInfo.codeExtraInformation.HasCustomCodeGenerator()) {
plainExpression += expressionInfo.codeExtraInformation.customCodeGenerator(
parameters, codeGenerator, context);
return;
}
// Prepare parameters
std::vector<gd::String> parametersCode =
codeGenerator.GenerateParametersCodes(
parameters, expressionInfo.parameters, context);
gd::String parametersStr;
for (std::size_t i = 2; i < parametersCode.size(); ++i) {
if (i != 2) parametersStr += ", ";
parametersStr += parametersCode[i];
}
// Get object(s) concerned by function call
std::vector<gd::String> realObjects =
codeGenerator.ExpandObjectsName(parameters[0].GetPlainString(), context);
gd::String output = GetReturnType() == "string" ? "\"\"" : "0";
for (std::size_t i = 0; i < realObjects.size(); ++i) {
context.ObjectsListNeeded(realObjects[i]);
// Cast the object if needed
gd::String behaviorType =
gd::GetTypeOfBehavior(globalObjectsAndGroups, objectsAndGroups, parameters[1].GetPlainString());
const BehaviorMetadata& autoInfo = MetadataProvider::GetBehaviorMetadata(
codeGenerator.GetPlatform(), behaviorType);
// Build gd::String to access the behavior
codeGenerator.AddIncludeFiles(autoInfo.includeFiles);
output = codeGenerator.GenerateObjectBehaviorFunctionCall(
realObjects[i],
parameters[1].GetPlainString(),
autoInfo,
expressionInfo.codeExtraInformation,
parametersStr,
output,
context);
}
plainExpression += output;
};
bool CallbacksForGeneratingExpressionCode::OnSubMathExpression(
const gd::Platform& platform,
const gd::ObjectsContainer& globalObjectsAndGroups,
const gd::ObjectsContainer& objectsAndGroups,
gd::Expression& expression) {
gd::String newExpression;
CallbacksForGeneratingExpressionCode callbacks(
newExpression, codeGenerator, context);
gd::ExpressionParser parser(expression.GetPlainString());
if (!parser.ParseMathExpression(platform, globalObjectsAndGroups, objectsAndGroups, callbacks)) {
#if defined(GD_IDE_ONLY)
firstErrorStr = callbacks.GetFirstError();
firstErrorPos = callbacks.GetFirstErrorPosition();
#endif
return false;
}
return true;
}
bool CallbacksForGeneratingExpressionCode::OnSubTextExpression(
const gd::Platform& platform,
const gd::ObjectsContainer& globalObjectsAndGroups,
const gd::ObjectsContainer& objectsAndGroups,
gd::Expression& expression) {
gd::String newExpression;
CallbacksForGeneratingExpressionCode callbacks(
newExpression, codeGenerator, context);
gd::ExpressionParser parser(expression.GetPlainString());
if (!parser.ParseStringExpression(platform, globalObjectsAndGroups, objectsAndGroups, callbacks)) {
#if defined(GD_IDE_ONLY)
firstErrorStr = callbacks.GetFirstError();
firstErrorPos = callbacks.GetFirstErrorPosition();
#endif
return false;
}
return true;
}
} // namespace gd

View File

@@ -1,77 +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 EXPRESSIONSCODEGENERATION_H
#define EXPRESSIONSCODEGENERATION_H
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser.h"
#include "GDCore/String.h"
namespace gd {
class ExpressionMetadata;
class Expression;
class Project;
class Layout;
class Layout;
class EventsCodeGenerationContext;
class EventsCodeGenerator;
}
namespace gd {
// TODO: Replace and remove (ExpressionCodeGenerator)
/**
* \brief Used to generate code from expressions.
*
* Usage example :
* \code
* gd::String expressionOutputCppCode;
*
* CallbacksForGeneratingExpressionCode callbacks(expressionOutputCppCode,
* codeGenerator, context); gd::ExpressionParser
* parser(theOriginalGameDevelopExpression);
* parser.ParseStringExpression(platform, project, scene, callbacks);
*
* if (expressionOutputCppCode.empty()) expressionOutputCppCode = "\"\""; //If
* generation failed, we make sure output code is not empty. \endcode \see
* EventsCodeGenerator
*/
class GD_CORE_API CallbacksForGeneratingExpressionCode
: public gd::ParserCallbacks {
public:
CallbacksForGeneratingExpressionCode(gd::String& output,
EventsCodeGenerator& codeGenerator_,
EventsCodeGenerationContext& context_);
virtual ~CallbacksForGeneratingExpressionCode(){};
void OnConstantToken(gd::String text);
void OnStaticFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo);
void OnObjectFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo);
void OnObjectBehaviorFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo);
bool OnSubMathExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression);
bool OnSubTextExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression);
private:
gd::String& plainExpression;
EventsCodeGenerator& codeGenerator;
EventsCodeGenerationContext& context;
};
} // namespace gd
#endif // EXPRESSIONSCODEGENERATION_H

View File

@@ -1,68 +0,0 @@
/*
* GDevelop C++ Platform
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#include "VariableParserCallbacks.h"
#include <string>
#include <vector>
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h"
#include "GDCore/Events/Parsers/VariableParser.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/Object.h"
#include "GDCore/Project/Project.h"
using namespace std;
namespace gd {
VariableCodeGenerationCallbacks::VariableCodeGenerationCallbacks(
gd::String& output_,
gd::EventsCodeGenerator& codeGenerator_,
gd::EventsCodeGenerationContext& context_,
const gd::EventsCodeGenerator::VariableScope& scope_)
: output(output_),
codeGenerator(codeGenerator_),
context(context_),
scope(scope_) {
if (scope == gd::EventsCodeGenerator::OBJECT_VARIABLE) {
std::cout << "ERROR: Initializing VariableCodeGenerationCallbacks with "
"OBJECT_VARIABLE without object.";
}
}
VariableCodeGenerationCallbacks::VariableCodeGenerationCallbacks(
gd::String& output_,
gd::EventsCodeGenerator& codeGenerator_,
gd::EventsCodeGenerationContext& context_,
const gd::String& object_)
: output(output_),
codeGenerator(codeGenerator_),
context(context_),
scope(gd::EventsCodeGenerator::OBJECT_VARIABLE),
object(object_) {}
void VariableCodeGenerationCallbacks::OnRootVariable(gd::String variableName) {
output += codeGenerator.GenerateGetVariable(variableName, scope, context, object);
}
void VariableCodeGenerationCallbacks::OnChildVariable(gd::String variableName) {
output += codeGenerator.GenerateVariableAccessor(variableName);
}
void VariableCodeGenerationCallbacks::OnChildSubscript(
gd::String stringExpression) {
gd::String argumentCode = gd::ExpressionCodeGenerator::GenerateExpressionCode(
codeGenerator, context, "string", stringExpression);
output += codeGenerator.GenerateVariableBracketAccessor(argumentCode);
}
}
#endif

View File

@@ -1,97 +0,0 @@
/*
* GDevelop C++ Platform
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef VARIABLEPARSERCALLBACKS_H
#define VARIABLEPARSERCALLBACKS_H
#include <string>
#include <vector>
#include "GDCore/Events/Parsers/VariableParser.h"
#include "GDCore/String.h"
#include "EventsCodeGenerator.h"
namespace gd {
class EventsCodeGenerationContext;
} // namespace gd
// TODO: Replace and remove (ExpressionCodeGenerator)
namespace gd {
/**
* \brief Callbacks called to generate the code for getting a variable.
*
* Usage example:
\code
VariableCodeGenerationCallbacks callbacks(output, eventsCodeGenerator,
context, VariableCodeGenerationCallbacks::LAYOUT_VARIABLE);
gd::VariableParser parser(parameter);
if ( !parser.Parse(callbacks) )
{
//Error during parsing the variable name:
output = "runtimeContext->GetSceneVariables().GetBadVariable()";
}
//"output" now contains the C++ code to return the variable.
\endcode
*/
class VariableCodeGenerationCallbacks : public gd::VariableParserCallbacks {
public:
/**
* \brief Default constructor for generating code for a layout/global
* variable. \param output The string in which the code will be generated.
* \param codeGenerator The code generator being used.
* \param context The current code generation context.
* \param scope The scope of the variable being accessed: LAYOUT_VARIABLE,
* PROJECT_VARIABLE.
*/
VariableCodeGenerationCallbacks(gd::String& output,
gd::EventsCodeGenerator& codeGenerator_,
gd::EventsCodeGenerationContext& context_,
const gd::EventsCodeGenerator::VariableScope& scope_);
/**
* \brief Default constructor for generating code for an object variable.
* \param output The string in which the code will be generated.
* \param codeGenerator The code generator being used.
* \param context The current code generation context.
* \param object The name of the object
*/
VariableCodeGenerationCallbacks(gd::String& output,
gd::EventsCodeGenerator& codeGenerator_,
gd::EventsCodeGenerationContext& context_,
const gd::String& object);
/**
* \brief Called when the first variable has been parsed.
* \param variableName The variable name.
*/
virtual void OnRootVariable(gd::String variableName);
/**
* \brief Called when accessing the child of a structure variable.
* \param variableName The child variable name.
*/
virtual void OnChildVariable(gd::String variableName);
/**
* \brief Called when accessing the child of a structure variable using a
* string expression in square brackets. \param variableName The expression
* used to access the child variable.
*/
virtual void OnChildSubscript(gd::String stringExpression);
private:
gd::String& output;
gd::EventsCodeGenerator& codeGenerator;
gd::EventsCodeGenerationContext& context;
gd::EventsCodeGenerator::VariableScope scope;
const gd::String object; ///< The object name, when scope == OBJECT_VARIABLE.
};
}
#endif // VARIABLEPARSERCALLBACKS_H
#endif

View File

@@ -90,8 +90,8 @@ class GD_CORE_API BaseEvent {
bool HasSubEvents() const;
/**
* Event must be able to return all conditions std::vector they have.
* Used to preprocess the conditions.
* \brief Return a list of all conditions of the event.
* \note Used to preprocess or search in the conditions.
*/
virtual std::vector<gd::InstructionsList*> GetAllConditionsVectors() {
std::vector<gd::InstructionsList*> noConditions;
@@ -104,8 +104,8 @@ class GD_CORE_API BaseEvent {
};
/**
* Event must be able to return all actions std::vector they have.
* Used to preprocess the actions.
* \brief Return a list of all actions of the event.
* \note Used to preprocess or search in the actions.
*/
virtual std::vector<gd::InstructionsList*> GetAllActionsVectors() {
std::vector<gd::InstructionsList*> noActions;
@@ -118,8 +118,17 @@ class GD_CORE_API BaseEvent {
};
/**
* Event must be able to return all expressions they have.
* Used to preprocess the expressions.
* \brief Return a list of all strings of the event.
* \note Used to preprocess or search in the event strings.
*/
virtual std::vector<gd::String> GetAllSearchableStrings() const {
std::vector<gd::String> noSearchableStrings;
return noSearchableStrings;
};
/**
* \brief Return a list of all expressions of the event.
* \note Used to preprocess or search in the expressions.
*/
virtual std::vector<gd::Expression*> GetAllExpressions() {
std::vector<gd::Expression*> noExpr;

View File

@@ -99,6 +99,23 @@ bool EventsList::Contains(const gd::BaseEvent& eventToSearch,
return false;
}
bool EventsList::MoveEventToAnotherEventsList(const gd::BaseEvent& eventToMove,
gd::EventsList& newEventsList,
std::size_t newPosition) {
for (std::size_t i = 0; i < GetEventsCount(); ++i) {
if (events[i].get() == &eventToMove) {
std::shared_ptr<BaseEvent> event = events[i];
events.erase(events.begin() + i);
newEventsList.InsertEvent(event, newPosition);
return true;
}
}
return false;
}
EventsList::EventsList(const EventsList& other) { Init(other); }
EventsList& EventsList::operator=(const EventsList& other) {

View File

@@ -52,7 +52,8 @@ class GD_CORE_API EventsList {
* \brief Insert the specified event to the list.
* \note The event passed by parameter is not copied.
* \param event The smart pointer to the event that must be inserted into the
* list \param position Insertion position. If the position is invalid, the
* list
* \param position Insertion position. If the position is invalid, the
* object is inserted at the end of the objects list.
*/
void InsertEvent(std::shared_ptr<gd::BaseEvent> event,
@@ -142,6 +143,25 @@ class GD_CORE_API EventsList {
*/
bool Contains(const gd::BaseEvent& eventToSearch,
bool recursive = true) const;
/**
* Move the specified event, that must be in the events list, to another
* events list *without* invalidating the event (i.e: without
* destroying/cloning it) in memory.
*
* \warning newEventsList is supposed not to be contained inside the event
* (you should not try
* to move an event inside one of its children/grand children events).
*
* \param eventToMove The event to be moved
* \param newEventsList The new events list
* \param newPosition The position in the new events list
* \return true if the move was made, false otherwise (for example, if
* eventToMove is not found in the list)
*/
bool MoveEventToAnotherEventsList(const gd::BaseEvent& eventToMove,
gd::EventsList& newEventsList,
std::size_t newPosition);
///@}
/** \name std::vector API compatibility

View File

@@ -1,897 +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/Parsers/ExpressionParser.h"
#include <algorithm>
#include <iostream>
#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/Platform.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
namespace gd {
gd::String ExpressionParser::parserSeparators = " ,+-*/%.<>=&|;()#^![]{}";
size_t ExpressionParser::GetMinimalParametersNumber(
const std::vector<gd::ParameterMetadata>& parametersInfos) {
size_t nb = 0;
for (std::size_t i = 0; i < parametersInfos.size(); ++i) {
if (!parametersInfos[i].optional && !parametersInfos[i].codeOnly) nb++;
}
return nb;
}
size_t ExpressionParser::GetMaximalParametersNumber(
const std::vector<gd::ParameterMetadata>& parametersInfos) {
size_t nb = 0;
for (std::size_t i = 0; i < parametersInfos.size(); ++i) {
if (!parametersInfos[i].codeOnly) nb++;
}
return nb;
}
/**
* Add blank parameters when code-only parameters are expected.
* \param Parameters information
* \param vector of parameters without code only parameters.
*/
std::vector<gd::Expression> CompleteParameters(
const std::vector<gd::ParameterMetadata>& parametersInfo,
const std::vector<gd::Expression>& parameters) {
std::vector<gd::Expression> completeParameters = parameters;
for (std::size_t i = 0; i < parametersInfo.size();
++i) // Code only parameters are not included in expressions parameters.
{
if (parametersInfo[i].codeOnly) {
if (i > completeParameters.size()) {
cout << "Bad parameter count in expression.";
}
if (i >= completeParameters.size())
completeParameters.push_back(gd::Expression(""));
else
completeParameters.insert(completeParameters.begin() + i,
gd::Expression(""));
} else {
if (i >= completeParameters.size()) {
completeParameters.push_back(gd::Expression(""));
}
}
}
return completeParameters;
}
bool ExpressionParser::ValidSyntax(const gd::String& str) {
static const gd::String numerics = "0123456789.e";
static const gd::String operators = "+/*-%";
size_t parenthesisLevel = 0;
gd::String lastOperator;
bool parsingNumber = false;
bool parsingScientificNotationNumber = false;
bool parsingDecimalNumber = false;
bool requestNumber = false;
gd::String lastNumber;
bool numberWasParsedLast = false;
for (auto it = str.begin(); it != str.end(); ++it) {
char32_t currentChar = *it;
if (currentChar == U' ' || currentChar == U'\n') {
if (requestNumber) {
firstErrorStr = _("Number expected");
return false;
}
if (parsingNumber) {
parsingNumber = false;
parsingScientificNotationNumber = false;
parsingDecimalNumber = false;
requestNumber = false;
lastNumber.clear();
numberWasParsedLast = true;
}
} else if (numerics.find(currentChar) != gd::String::npos) {
requestNumber = false;
if (currentChar == U'.') {
if (!parsingNumber) {
firstErrorStr = _("Syntax error");
return false;
}
if (parsingDecimalNumber) {
firstErrorStr = _("Syntax error in a number.");
return false;
}
parsingDecimalNumber = true;
}
if (currentChar == U'e') {
if (parsingScientificNotationNumber) {
firstErrorStr = _("Syntax error in a number.");
return false;
}
parsingScientificNotationNumber = true;
requestNumber = true;
}
if (numberWasParsedLast) {
firstErrorStr = _("Operator missing before a number");
return false;
}
parsingNumber = true;
lastNumber += currentChar;
} else if (currentChar == U')') {
if (requestNumber) {
firstErrorStr = _("Number expected");
return false;
}
if (parsingNumber) {
parsingNumber = false;
parsingScientificNotationNumber = false;
parsingDecimalNumber = false;
lastNumber.clear();
numberWasParsedLast = true;
}
if (!numberWasParsedLast) {
firstErrorStr = _("Superfluous operator before a paranthesis");
return false;
}
if (parenthesisLevel > 0)
parenthesisLevel--;
else {
firstErrorStr = _("Bad closing paranthesis");
return false;
}
auto previousIt = it;
--previousIt;
if (*previousIt == U'(') {
firstErrorStr = _("Empty paranthesis");
return false;
}
} else if (currentChar == U'(') {
if (requestNumber) {
firstErrorStr = _("Number expected");
return false;
}
if (parsingNumber) {
parsingNumber = false;
parsingScientificNotationNumber = false;
parsingDecimalNumber = false;
lastNumber.clear();
numberWasParsedLast = true;
}
if (numberWasParsedLast) {
firstErrorStr = _("Operator missing before a paranthesis");
return false;
}
parenthesisLevel++;
numberWasParsedLast = false;
} else if (operators.find(currentChar) != gd::String::npos) {
if (currentChar == U'-' && parsingNumber &&
parsingScientificNotationNumber) {
lastNumber += currentChar;
requestNumber = true;
} else {
if (requestNumber) {
firstErrorStr = _("Number expected");
return false;
}
if (parsingNumber) {
parsingNumber = false;
parsingScientificNotationNumber = false;
parsingDecimalNumber = false;
lastNumber.clear();
numberWasParsedLast = true;
}
if (currentChar != U'-' && currentChar != U'+' &&
!numberWasParsedLast) {
firstErrorStr = _("Operators without any number between them");
return false;
}
numberWasParsedLast = false;
}
} else {
firstErrorStr = _("Syntax error");
return false;
}
}
if (parsingNumber) {
parsingNumber = false;
parsingScientificNotationNumber = false;
parsingDecimalNumber = false;
lastNumber.clear();
numberWasParsedLast = true;
} else if (requestNumber) {
firstErrorStr = _("Number expected");
return false;
}
if (parenthesisLevel != 0) {
firstErrorStr = _("Paranthesis mismatch");
return false;
}
if (!numberWasParsedLast) {
firstErrorStr = _("Alone operator at the end of the expression");
return false;
}
return true;
}
bool ExpressionParser::ParseMathExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::ParserCallbacks& callbacks) {
callbacks.SetReturnType("expression");
gd::String expression = expressionPlainString;
size_t parsePosition = 0;
size_t firstPointPos = expression.find(".");
size_t firstParPos = expression.find("(");
gd::String expressionWithoutFunctions;
gd::String nonFunctionToken;
size_t nonFunctionTokenStartPos = gd::String::npos;
while (firstPointPos != string::npos || firstParPos != string::npos) {
// Identify name
size_t nameEnd = firstPointPos < firstParPos ? firstPointPos : firstParPos;
size_t nameStart = expression.find_last_of(parserSeparators, nameEnd - 1);
nameStart++;
gd::String nameBefore = expression.substr(nameStart, nameEnd - nameStart);
gd::String objectName = nameBefore.FindAndReplace("~", " ");
// Identify function name
gd::String functionName = nameBefore;
size_t functionNameEnd = nameEnd;
vector<gd::Expression> parameters;
bool nameIsFunction = firstPointPos > firstParPos;
if (!nameIsFunction) {
parameters.push_back(gd::Expression(objectName));
functionNameEnd = expression.find_first_of(" (", nameEnd);
if (nameEnd + 1 < expression.length())
functionName =
expression.substr(nameEnd + 1, functionNameEnd - (nameEnd + 1));
if (functionNameEnd == string::npos) {
functionName = "";
functionNameEnd = expression.length() - 1;
}
}
// Now we're going to identify the expression
gd::ExpressionMetadata instructionInfos;
if (functionName.substr(0, functionName.length() - 1)
.find_first_of(parserSeparators) == string::npos) {
bool functionFound = false;
bool staticFunctionFound = false;
bool objectFunctionFound = false;
bool behaviorFunctionFound = false;
// First try to bind to a static expression
if (nameIsFunction &&
MetadataProvider::HasExpression(platform, functionName)) {
functionFound = true;
staticFunctionFound = true;
instructionInfos =
MetadataProvider::GetExpressionMetadata(platform, functionName);
}
// Then search in object expression
else if (!nameIsFunction &&
MetadataProvider::HasObjectExpression(
platform,
gd::GetTypeOfObject(project, layout, objectName),
functionName)) {
functionFound = true;
objectFunctionFound = true;
instructionInfos = MetadataProvider::GetObjectExpressionMetadata(
platform,
gd::GetTypeOfObject(project, layout, objectName),
functionName);
}
// And in behaviors expressions
else if (!nameIsFunction) {
size_t firstDoublePoints = functionName.find("::");
if (firstDoublePoints != string::npos) {
gd::String autoName = functionName.substr(0, firstDoublePoints);
if (firstDoublePoints + 2 < functionName.length())
functionName = functionName.substr(firstDoublePoints + 2,
functionName.length());
else
functionName = "";
if (MetadataProvider::HasBehaviorExpression(
platform,
gd::GetTypeOfBehavior(project, layout, autoName),
functionName)) {
parameters.push_back(gd::Expression(autoName));
functionFound = true;
behaviorFunctionFound = true;
instructionInfos = MetadataProvider::GetBehaviorExpressionMetadata(
platform,
gd::GetTypeOfBehavior(project, layout, autoName),
functionName);
// Verify that object has behavior.
vector<gd::String> behaviors =
gd::GetBehaviorsOfObject(project, layout, objectName);
if (find(behaviors.begin(), behaviors.end(), autoName) ==
behaviors.end()) {
cout << "Bad behavior requested" << endl;
functionFound = false;
}
}
}
}
if (functionFound) // Add the function
{
// Identify parameters
size_t parametersEnd = expression.find_first_of("(", functionNameEnd);
gd::String currentParameterStr;
char32_t previousChar = '(';
bool takeSymbolsInAccount = true;
if (parametersEnd != string::npos) {
size_t level = 0;
parametersEnd++;
while (parametersEnd < expression.length() &&
!(expression[parametersEnd] == ')' && level == 0)) {
// Be sure we are not in quotes
if (expression[parametersEnd] == U'\"' && previousChar != U'\\')
takeSymbolsInAccount = !takeSymbolsInAccount;
// So as to be sure paranthesis don't belong to a parameter
if (expression[parametersEnd] == U'(' && takeSymbolsInAccount)
level++;
if (expression[parametersEnd] == U')' && takeSymbolsInAccount)
level--;
// Add the character to the current parameter or terminate the
// latter
if ((expression[parametersEnd] == U',' && level == 0) &&
takeSymbolsInAccount) {
parameters.push_back(currentParameterStr);
currentParameterStr.clear();
} else
currentParameterStr += expression[parametersEnd];
previousChar = expression[parametersEnd];
parametersEnd++;
}
if (currentParameterStr.find_first_not_of(" ") !=
string::npos) // Add last parameter if needed
{
parameters.push_back(currentParameterStr);
}
// Testing function call is properly closed
if (parametersEnd == expression.length() ||
expression[parametersEnd] != U')') {
firstErrorStr = _("Paranthesis not closed");
firstErrorPos = parametersEnd - 1;
return false;
}
// Testing the number of parameters
if (parameters.size() >
GetMaximalParametersNumber(instructionInfos.parameters) ||
parameters.size() <
GetMinimalParametersNumber(instructionInfos.parameters)) {
firstErrorPos = functionNameEnd;
firstErrorStr = _("Incorrect number of parameters");
firstErrorStr += " ";
firstErrorStr += _("Expected (maximum) :");
firstErrorStr += gd::String::From(
GetMaximalParametersNumber(instructionInfos.parameters));
return false;
}
// Preparing parameters
parameters =
CompleteParameters(instructionInfos.parameters, parameters);
for (std::size_t i = 0; i < instructionInfos.parameters.size(); ++i) {
if (!PrepareParameter(platform,
project,
layout,
callbacks,
parameters[i],
instructionInfos.parameters[i],
functionNameEnd))
return false;
}
} else {
firstErrorPos = functionNameEnd;
firstErrorStr = _("Parameters' parenthesis missing");
return false;
}
callbacks.OnConstantToken(
nonFunctionToken +
expression.substr(parsePosition, nameStart - parsePosition));
expressionWithoutFunctions +=
expression.substr(parsePosition, nameStart - parsePosition);
nonFunctionToken.clear();
nonFunctionTokenStartPos = gd::String::npos;
if (objectFunctionFound)
callbacks.OnObjectFunction(
functionName, parameters, instructionInfos);
else if (behaviorFunctionFound)
callbacks.OnObjectBehaviorFunction(
functionName, parameters, instructionInfos);
else if (staticFunctionFound)
callbacks.OnStaticFunction(
functionName, parameters, instructionInfos);
if (objectFunctionFound || behaviorFunctionFound || staticFunctionFound)
expressionWithoutFunctions += "0";
parsePosition = parametersEnd + 1;
firstPointPos = expression.find(".", parametersEnd + 1);
firstParPos = expression.find("(", parametersEnd + 1);
} else // Math function or math constant : Pass it.
{
nonFunctionToken += expression.substr(
parsePosition, functionNameEnd + 1 - parsePosition);
expressionWithoutFunctions += expression.substr(
parsePosition, functionNameEnd + 1 - parsePosition);
nonFunctionTokenStartPos = (nonFunctionTokenStartPos != gd::String::npos
? nonFunctionTokenStartPos
: parsePosition);
parsePosition = functionNameEnd + 1;
firstPointPos = expression.find(".", functionNameEnd + 1);
firstParPos = expression.find("(", functionNameEnd + 1);
}
} else // Not a function call : Pass it
{
nonFunctionToken +=
expression.substr(parsePosition, nameEnd + 1 - parsePosition);
expressionWithoutFunctions +=
expression.substr(parsePosition, nameEnd + 1 - parsePosition);
nonFunctionTokenStartPos = (nonFunctionTokenStartPos != gd::String::npos
? nonFunctionTokenStartPos
: parsePosition);
parsePosition = nameEnd + 1;
firstPointPos = expression.find(".", nameEnd + 1);
firstParPos = expression.find("(", nameEnd + 1);
}
}
if (parsePosition < expression.length() || !nonFunctionToken.empty())
callbacks.OnConstantToken(
nonFunctionToken +
expression.substr(parsePosition, expression.length()));
expressionWithoutFunctions +=
expression.substr(parsePosition, expression.length());
return ValidSyntax(expressionWithoutFunctions);
}
bool ExpressionParser::ParseStringExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::ParserCallbacks& callbacks) {
callbacks.SetReturnType("string");
gd::String expression = expressionPlainString;
size_t parsePosition = 0;
// Searching for first token.
size_t firstPointPos = expression.find(".");
size_t firstParPos = expression.find("(");
size_t firstQuotePos = expression.find("\"");
if (firstPointPos == string::npos && firstParPos == string::npos &&
firstQuotePos == string::npos) {
firstErrorPos = 0;
firstErrorStr =
_("The expression is invalid or empty. Enter a text ( surrounded by "
"quotes ) or a function.");
return false;
}
while (firstPointPos != string::npos || firstParPos != string::npos ||
firstQuotePos != string::npos) {
if (firstQuotePos < firstPointPos &&
firstQuotePos < firstParPos) // Adding a constant text
{
callbacks.OnConstantToken(
expression.substr(parsePosition, firstQuotePos - parsePosition));
// Finding start and end of quotes
size_t finalQuotePosition = expression.find("\"", firstQuotePos + 1);
while (finalQuotePosition ==
expression.find("\\\"", finalQuotePosition - 1) + 1)
finalQuotePosition = expression.find("\"", finalQuotePosition + 1);
if (finalQuotePosition == string::npos) {
firstErrorPos = firstQuotePos;
firstErrorStr = _("Quotes not closed.");
return false;
}
// Generating final text, by replacing \" by quotes
gd::String finalText = expression.substr(
firstQuotePos + 1, finalQuotePosition - (firstQuotePos + 1));
size_t foundPos = finalText.find("\\\"");
while (foundPos != string::npos) {
if (foundPos != string::npos) finalText.replace(foundPos, 2, "\"");
foundPos = finalText.find("\\\"", foundPos);
}
// Adding constant text instruction
//(Function without name is considered as a constant text)
vector<gd::Expression> parameters;
parameters.push_back(finalText);
gd::ExpressionMetadata noParametersInfo;
callbacks.OnStaticFunction("", parameters, noParametersInfo);
parsePosition = finalQuotePosition + 1;
} else // Adding a function
{
// Identify name
size_t nameEnd =
firstPointPos < firstParPos ? firstPointPos : firstParPos;
size_t nameStart = expression.find_last_of(parserSeparators, nameEnd - 1);
nameStart++;
callbacks.OnConstantToken(
expression.substr(parsePosition, nameStart - parsePosition));
gd::String nameBefore = expression.substr(nameStart, nameEnd - nameStart);
gd::String objectName = nameBefore.FindAndReplace("~", " ");
// Identify function name
gd::String functionName = nameBefore;
size_t functionNameEnd = nameEnd;
vector<gd::Expression> parameters;
bool nameIsFunction = firstPointPos > firstParPos;
if (!nameIsFunction) {
parameters.push_back(gd::Expression(objectName));
functionNameEnd = expression.find_first_of("( ", nameEnd);
if (nameEnd + 1 < expression.length())
functionName =
expression.substr(nameEnd + 1, functionNameEnd - (nameEnd + 1));
}
// Identify parameters
size_t parametersEnd = expression.find_first_of("(", functionNameEnd) + 1;
char32_t previousChar = U'(';
bool takeSymbolsInAccount = true;
size_t level = 0;
gd::String currentParameterStr;
while (parametersEnd < expression.length() &&
!(expression[parametersEnd] == U')' && level == 0)) {
// Be sure we are not in quotes
if (expression[parametersEnd] == U'\"' && previousChar != U'\\')
takeSymbolsInAccount = !takeSymbolsInAccount;
// So as to be sure paranthesis don't belong to a parameter
if (expression[parametersEnd] == U'(' && takeSymbolsInAccount) level++;
if (expression[parametersEnd] == U')' && takeSymbolsInAccount) level--;
// Add the character to the current parameter or terminate the latter
if ((expression[parametersEnd] == ',' && level == 0) &&
takeSymbolsInAccount) {
gd::Expression currentParameter(currentParameterStr);
parameters.push_back(currentParameter);
currentParameterStr.clear();
} else
currentParameterStr += expression[parametersEnd];
previousChar = expression[parametersEnd];
parametersEnd++;
}
if (parametersEnd == expression.length() ||
expression[parametersEnd] != U')') {
firstErrorPos = parametersEnd - 1;
firstErrorStr = _("Paranthesis not closed");
return false;
}
if (currentParameterStr.find_first_not_of(" ") !=
string::npos) // Add last parameter if needed
{
gd::Expression lastParameter(currentParameterStr);
parameters.push_back(lastParameter);
}
bool functionFound = false;
// First try to bind to a static str expression
if (nameIsFunction &&
MetadataProvider::HasStrExpression(platform, functionName)) {
functionFound = true;
const gd::ExpressionMetadata& expressionInfo =
MetadataProvider::GetStrExpressionMetadata(platform, functionName);
// Testing the number of parameters
if (parameters.size() >
GetMaximalParametersNumber(expressionInfo.parameters) ||
parameters.size() <
GetMinimalParametersNumber(expressionInfo.parameters)) {
firstErrorPos = functionNameEnd;
firstErrorStr = _("Incorrect number of parameters");
return false;
}
// Preparing parameters
parameters = CompleteParameters(expressionInfo.parameters, parameters);
for (std::size_t i = 0;
i < parameters.size() && i < expressionInfo.parameters.size();
++i) {
if (!PrepareParameter(platform,
project,
layout,
callbacks,
parameters[i],
expressionInfo.parameters[i],
functionNameEnd))
return false;
}
callbacks.OnStaticFunction(functionName, parameters, expressionInfo);
}
// Then an object member expression
else if (!nameIsFunction &&
MetadataProvider::HasObjectStrExpression(
platform,
gd::GetTypeOfObject(project, layout, objectName),
functionName)) {
functionFound = true;
const gd::ExpressionMetadata& expressionInfo =
MetadataProvider::GetObjectStrExpressionMetadata(
platform,
gd::GetTypeOfObject(project, layout, nameBefore),
functionName);
// Testing the number of parameters
if (parameters.size() >
GetMaximalParametersNumber(expressionInfo.parameters) ||
parameters.size() <
GetMinimalParametersNumber(expressionInfo.parameters)) {
firstErrorPos = functionNameEnd;
firstErrorStr = _("Incorrect number of parameters");
return false;
}
// Preparing parameters
parameters = CompleteParameters(expressionInfo.parameters, parameters);
for (std::size_t i = 0;
i < parameters.size() && i < expressionInfo.parameters.size();
++i) {
if (!PrepareParameter(platform,
project,
layout,
callbacks,
parameters[i],
expressionInfo.parameters[i],
functionNameEnd))
return false;
}
callbacks.OnObjectFunction(functionName, parameters, expressionInfo);
}
// And search behaviors expressions
else {
size_t firstDoublePoints = functionName.find("::");
if (firstDoublePoints != string::npos) {
gd::String autoName = functionName.substr(0, firstDoublePoints);
if (firstDoublePoints + 2 < functionName.length())
functionName = functionName.substr(firstDoublePoints + 2,
functionName.length());
else
functionName = "";
if (MetadataProvider::HasBehaviorStrExpression(
platform,
gd::GetTypeOfBehavior(project, layout, autoName),
functionName)) {
parameters.push_back(gd::Expression(autoName));
functionFound = true;
const gd::ExpressionMetadata& expressionInfo =
MetadataProvider::GetBehaviorStrExpressionMetadata(
platform,
gd::GetTypeOfBehavior(project, layout, autoName),
functionName);
// Verify that object has behavior.
vector<gd::String> behaviors =
gd::GetBehaviorsOfObject(project, layout, objectName);
if (find(behaviors.begin(), behaviors.end(), autoName) ==
behaviors.end()) {
cout << "Bad behavior requested" << endl;
functionFound = false;
} else {
// Testing the number of parameters
if (parameters.size() >
GetMaximalParametersNumber(expressionInfo.parameters) ||
parameters.size() <
GetMinimalParametersNumber(expressionInfo.parameters)) {
firstErrorPos = functionNameEnd;
firstErrorStr = _("Incorrect number of parameters");
return false;
}
// Preparing parameters
parameters =
CompleteParameters(expressionInfo.parameters, parameters);
for (std::size_t i = 0; i < parameters.size() &&
i < expressionInfo.parameters.size();
++i) {
if (!PrepareParameter(platform,
project,
layout,
callbacks,
parameters[i],
expressionInfo.parameters[i],
functionNameEnd))
return false;
}
callbacks.OnObjectBehaviorFunction(
functionName, parameters, expressionInfo);
}
}
}
}
// Note : _No_ support for implicit conversion from math result to string
if (!functionFound) // Function was not found
{
firstErrorPos = nameStart;
firstErrorStr = _("Function not recognized.");
return false;
}
parsePosition = parametersEnd + 1;
}
// Searching for next token
size_t firstPlusPos = expression.find("+", parsePosition);
firstPointPos = expression.find(".", parsePosition);
firstParPos = expression.find("(", parsePosition);
firstQuotePos = expression.find("\"", parsePosition);
// Checking for a + between token
if ((firstPointPos != string::npos || firstParPos != string::npos ||
firstQuotePos != string::npos)) {
size_t nextTokenPos = firstPointPos;
if (firstParPos < nextTokenPos) nextTokenPos = firstParPos;
if (firstQuotePos < nextTokenPos) nextTokenPos = firstQuotePos;
if (nextTokenPos < firstPlusPos) {
firstErrorPos = nextTokenPos;
firstErrorStr = _("Symbol missing between two +.");
return false;
} else if (expression.find("+", firstPlusPos + 1) < nextTokenPos) {
firstErrorPos = firstPlusPos;
firstErrorStr = _("Symbol missing between two +.");
return false;
}
}
}
if (expression.substr(parsePosition, expression.length())
.find_first_not_of(" \n") != gd::String::npos) {
firstErrorPos = parsePosition;
firstErrorStr = _("Bad symbol at the end of the expression.");
return false;
}
return true;
}
bool ExpressionParser::PrepareParameter(
const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
ParserCallbacks& callbacks,
gd::Expression& parameter,
const gd::ParameterMetadata& parametersInfo,
const size_t positionInExpression) {
if (ParameterMetadata::IsExpression("number", parametersInfo.type)) {
if (parametersInfo.optional && parameter.GetPlainString().empty())
parameter = parametersInfo.GetDefaultValue().empty()
? gd::Expression("0")
: gd::Expression(parametersInfo.GetDefaultValue());
if (!callbacks.OnSubMathExpression(platform, project, layout, parameter)) {
firstErrorStr = callbacks.firstErrorStr;
firstErrorPos = callbacks.firstErrorPos + positionInExpression;
return false;
}
} else if (ParameterMetadata::IsExpression("string", parametersInfo.type)) {
if (parametersInfo.optional && parameter.GetPlainString().empty())
parameter = parametersInfo.GetDefaultValue().empty()
? gd::Expression("\"\"")
: gd::Expression(parametersInfo.GetDefaultValue());
if (!callbacks.OnSubTextExpression(platform, project, layout, parameter)) {
firstErrorStr = callbacks.firstErrorStr;
firstErrorPos = callbacks.firstErrorPos + positionInExpression;
return false;
}
}
return true;
}
ExpressionParser::ExpressionParser(const gd::String& expressionPlainString_)
: expressionPlainString(expressionPlainString_) {}
} // namespace gd

View File

@@ -1,179 +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 GDCORE_EXPRESSIONPARSER_H
#define GDCORE_EXPRESSIONPARSER_H
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Expression;
class ParserCallbacks;
class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
}
namespace gd {
/** \brief Parse an expression
*
* Parse an expression, calling callbacks when a token is reached
* \see gd::ParserCallbacks
*/
class GD_CORE_API ExpressionParser {
public:
ExpressionParser(const gd::String &expressionPlainString_);
virtual ~ExpressionParser(){};
/**
* \brief Parse the expression, calling each functor when necessary
* \return True if expression was correctly parsed.
*/
bool ParseMathExpression(const gd::Platform &platform,
const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
gd::ParserCallbacks &callbacks);
/**
* \brief Parse the expression, calling each functor when necessary
* \return True if expression was correctly parsed.
*/
bool ParseStringExpression(const gd::Platform &platform,
const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
gd::ParserCallbacks &callbacks);
/**
* \brief Return the description of the error that was found
*/
const gd::String &GetFirstError() { return firstErrorStr; }
/**
* \brief Return the position of the error that was found
* \return The position, or gd::String::npos if no error is found
*/
size_t GetFirstErrorPosition() { return firstErrorPos; }
private:
gd::String firstErrorStr;
size_t firstErrorPos;
/**
* Tool function to add a parameter
*/
bool AddParameterToList(const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
ParserCallbacks &,
std::vector<gd::Expression> &parameters,
gd::String parameterStr,
std::vector<gd::ParameterMetadata> parametersInfos,
const size_t positionInExpression);
/**
* Tool function to prepare a parameter
*/
bool PrepareParameter(const gd::Platform &platform,
const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
ParserCallbacks &,
gd::Expression &parameter,
const gd::ParameterMetadata &parametersInfo,
const size_t positionInExpression);
/**
* Return the minimal number of parameters which can be used when calling an
* expression ( i.e. ParametersCount-OptionalParameters-CodeOnlyParameters )
*/
size_t GetMinimalParametersNumber(
const std::vector<gd::ParameterMetadata> &parametersInfos);
/**
* Return the maximal number of parameters which can be used when calling an
* expression ( i.e. ParametersCount-CodeOnlyParameters )
*/
size_t GetMaximalParametersNumber(
const std::vector<gd::ParameterMetadata> &parametersInfos);
bool ValidSyntax(const gd::String &str);
gd::String expressionPlainString;
static gd::String parserSeparators;
};
/** \brief Callbacks called by parser during parsing
*
* Parser will call the appropriate functions during parsing, allowing to do
* special works. \see gd::ExpressionParser
*/
class GD_CORE_API ParserCallbacks {
friend class ExpressionParser;
public:
ParserCallbacks() : returnType("expression"){};
virtual ~ParserCallbacks(){};
/**
* \brief Get the type of the expression for which callbacks are used:
* "expression" or "string".
*/
const gd::String &GetReturnType() { return returnType; }
virtual void OnConstantToken(gd::String text) = 0;
virtual void OnStaticFunction(
gd::String functionName,
const std::vector<gd::Expression> &parameters,
const gd::ExpressionMetadata &expressionInfo) = 0;
virtual void OnObjectFunction(
gd::String functionName,
const std::vector<gd::Expression> &parameters,
const gd::ExpressionMetadata &expressionInfo) = 0;
virtual void OnObjectBehaviorFunction(
gd::String functionName,
const std::vector<gd::Expression> &parameters,
const gd::ExpressionMetadata &expressionInfo) = 0;
virtual bool OnSubMathExpression(const gd::Platform &platform,
const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
gd::Expression &expression) = 0;
virtual bool OnSubTextExpression(const gd::Platform &platform,
const gd::ObjectsContainer &project,
const gd::ObjectsContainer &layout,
gd::Expression &expression) = 0;
/**
* \brief Return the description of the error that was found
*/
const gd::String &GetFirstError() { return firstErrorStr; }
/**
* \brief Return the position of the error that was found
* \return The position, or gd::String::npos if no error is found
*/
size_t GetFirstErrorPosition() { return firstErrorPos; }
protected:
gd::String firstErrorStr;
size_t firstErrorPos;
private:
/**
* \brief Set the return type of the expression: Done by ExpressionParser
* according to which Parse* method is called. \see gd::ExpressionParser
*/
void SetReturnType(gd::String type) { returnType = type; }
gd::String returnType; // The type of the expression ("expression" (default),
// "string"...)
};
} // namespace gd
#endif // GDEXPRESSIONPARSER_H

View File

@@ -1,141 +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/Parsers/VariableParser.h"
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Layout;
}
namespace gd {
class Project;
}
namespace gd {
class Platform;
}
#include "GDCore/Tools/Localization.h"
namespace gd {
VariableParser::~VariableParser() {}
bool VariableParser::Parse(VariableParserCallbacks& callbacks_) {
callbacks = &callbacks_;
rootVariableParsed = false;
firstErrorStr.clear();
firstErrorPos = 0;
currentPositionIt = expression.begin();
currentTokenType = TS_INVALID;
currentToken.clear();
S();
return firstErrorStr == "";
}
void VariableParser::ReadToken() {
currentTokenType = TS_INVALID;
currentToken.clear();
while (currentPositionIt != expression.end()) {
char32_t currentChar = *currentPositionIt;
if (currentChar == U'[' || currentChar == U']' || currentChar == U'.') {
if (currentTokenType == TS_VARNAME)
return; // We've parsed a variable name.
}
if (currentChar == U'[') {
currentTokenType = TS_OPENING_BRACKET;
currentToken.clear();
++currentPositionIt;
return;
} else if (currentChar == U']') {
currentTokenType = TS_CLOSING_BRACKET;
currentToken.clear();
++currentPositionIt;
return;
} else if (currentChar == U'.') {
currentTokenType = TS_PERIOD;
currentToken.clear();
++currentPositionIt;
return;
}
currentTokenType = TS_VARNAME; // We're parsing a variable name.
currentToken.push_back(currentChar);
++currentPositionIt;
}
// Can be reached if we are at the end of the expression. In this case,
// currentTokenType will be either TS_VARNAME or TS_INVALID.
}
void VariableParser::S() {
ReadToken();
if (currentTokenType != TS_VARNAME) {
firstErrorStr = _("Expecting a variable name.");
firstErrorPos = std::distance<gd::String::const_iterator>(
expression.begin(), currentPositionIt);
return;
}
if (!rootVariableParsed) {
rootVariableParsed = true;
if (callbacks) callbacks->OnRootVariable(currentToken);
} else if (callbacks)
callbacks->OnChildVariable(currentToken);
X();
}
void VariableParser::X() {
ReadToken();
if (currentTokenType == TS_INVALID)
return; // Ended parsing.
else if (currentTokenType == TS_PERIOD)
S();
else if (currentTokenType == TS_OPENING_BRACKET) {
gd::String strExpr = SkipStringExpression();
ReadToken();
if (currentTokenType != TS_CLOSING_BRACKET) {
firstErrorStr = _("Expecting ]");
firstErrorPos = std::distance<gd::String::const_iterator>(
expression.begin(), currentPositionIt);
return;
}
if (callbacks) callbacks->OnChildSubscript(strExpr);
X();
}
}
gd::String VariableParser::SkipStringExpression() {
gd::String stringExpression;
bool insideStringLiteral = false;
bool lastCharacterWasBackslash = false;
unsigned int nestedBracket = 0;
while (currentPositionIt != expression.end()) {
char32_t currentChar = *currentPositionIt;
if (currentChar == U'\"') {
if (!insideStringLiteral)
insideStringLiteral = true;
else if (!lastCharacterWasBackslash)
insideStringLiteral = false;
} else if (currentChar == U'[' && !insideStringLiteral) {
nestedBracket++;
} else if (currentChar == U']' && !insideStringLiteral) {
if (nestedBracket == 0)
return stringExpression; // Found the end of the string litteral.
nestedBracket--;
}
lastCharacterWasBackslash = currentChar == U'\\';
stringExpression.push_back(currentChar);
++currentPositionIt;
}
// End of the expression reached (so expression is invalid by the way)
return stringExpression;
}
} // namespace gd

View File

@@ -1,148 +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 GDCORE_VARIABLEPARSER_H
#define GDCORE_VARIABLEPARSER_H
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Layout;
}
namespace gd {
class Project;
}
namespace gd {
class Platform;
}
namespace gd {
class VariableParserCallbacks;
}
namespace gd {
/** \brief Parse a variable expression.
*
* Parse an variable expression ( like
myVariable.child["subchild"+ToString(i)].subsubchild ),
* calling callbacks when a token is reached.
*
* Usage example:
\code
//...
//VariableCodeGenerationCallbacks is a class inheriting from
gd::VariableParserCallbacks VariableCodeGenerationCallbacks callbacks(output,
*this, context, VariableCodeGenerationCallbacks::PROJECT_VARIABLE);
gd::VariableParser parser(parameter);
if ( !parser.Parse(callbacks) )
cout << "Error :" << parser.GetFirstError() << " in: "<< parameter <<
endl;
\endcode
*
* Here is the parsed grammar: <br>
* S -> VarName X <br>
* X -> e | . S | [StringExpression] X <br>
*
* where e = nothing (end of expression), StringExpression = A valid string
expression and
* S is the start.
*
* \see gd::VariableParserCallbacks
*/
class GD_CORE_API VariableParser {
public:
/**
* \brief Default constructor
* \param expressionPlainString The string representing the expression to be
* parsed.
*/
VariableParser(const gd::String& expressionPlainString_)
: currentPositionIt(), expression(expressionPlainString_){};
virtual ~VariableParser();
/**
* Parse the expression, calling each callback when necessary.
* \param callbacks The callbacks to be called.
* \return true if expression was correctly parsed.
* \see gd::VariableParserCallbacks
*/
bool Parse(VariableParserCallbacks& callbacks);
/**
* \brief Return the description of the error that was found
*/
const gd::String& GetFirstError() { return firstErrorStr; }
/**
* \brief Return the position of the error that was found
* \return The position, or gd::String::npos if no error is found
*/
size_t GetFirstErrorPosition() { return firstErrorPos; }
gd::String firstErrorStr;
size_t firstErrorPos;
private:
void S();
void X();
/**
* \brief Skip the string expression, starting from the current position.
* \return The string expression skipped. currentPosition is now put on the
* closing bracket.
*/
gd::String SkipStringExpression();
void ReadToken();
enum TokenType {
TS_PERIOD,
TS_OPENING_BRACKET,
TS_CLOSING_BRACKET,
TS_VARNAME,
TS_INVALID
};
TokenType currentTokenType;
gd::String currentToken;
gd::String::const_iterator currentPositionIt;
gd::String expression;
VariableParserCallbacks* callbacks;
bool rootVariableParsed;
};
/**
* \brief Callbacks called by VariableParser when parsing a variable expression.
*/
class GD_CORE_API VariableParserCallbacks {
public:
/**
* \brief Called when the first variable has been parsed. ( varName1 in
* varName1.child for example. ) \param variableName The variable name.
*/
virtual void OnRootVariable(gd::String variableName) = 0;
/**
* \brief Called when accessing the child of a structure variable. ( child in
* varName1.child for example. ) \param variableName The child variable name.
*/
virtual void OnChildVariable(gd::String variableName) = 0;
/**
* \brief Called when accessing the child of a structure variable using a
* string expression in square brackets. ( "subscript" in
* varName1["subscript"] for example. )
*
* \param variableName The expression used to access the child variable.
*/
virtual void OnChildSubscript(gd::String stringExpression) = 0;
};
} // namespace gd
#endif // GDEXPRESSIONPARSER_H

View File

@@ -8,10 +8,15 @@
#include "GDCore/CommonTools.h"
#include "GDCore/String.h"
EventsCodeNameMangler *EventsCodeNameMangler::_singleton = NULL;
EventsCodeNameMangler *EventsCodeNameMangler::_singleton = nullptr;
gd::String EventsCodeNameMangler::GetMangledObjectsListName(
const gd::String& EventsCodeNameMangler::GetMangledObjectsListName(
const gd::String &originalObjectName) {
auto it = mangledObjectNames.find(originalObjectName);
if (it != mangledObjectNames.end()) {
return it->second;
}
gd::String partiallyMangledName = originalObjectName;
static const gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -27,11 +32,17 @@ gd::String EventsCodeNameMangler::GetMangledObjectsListName(
}
}
return "GD" + partiallyMangledName + "Objects";
mangledObjectNames[originalObjectName] = "GD" + partiallyMangledName + "Objects";
return mangledObjectNames[originalObjectName];
}
gd::String EventsCodeNameMangler::GetExternalEventsFunctionMangledName(
const gd::String& EventsCodeNameMangler::GetExternalEventsFunctionMangledName(
const gd::String &externalEventsName) {
auto it = mangledExternalEventsNames.find(externalEventsName);
if (it != mangledExternalEventsNames.end()) {
return it->second;
}
gd::String partiallyMangledName = externalEventsName;
static const gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -47,23 +58,24 @@ gd::String EventsCodeNameMangler::GetExternalEventsFunctionMangledName(
}
}
return "GDExternalEvents" + partiallyMangledName;
mangledExternalEventsNames[externalEventsName] = "GDExternalEvents" + partiallyMangledName;
return mangledExternalEventsNames[externalEventsName];
}
gd::String ManObjListName(const gd::String &objectName) {
const gd::String& ManObjListName(const gd::String &objectName) {
return EventsCodeNameMangler::Get()->GetMangledObjectsListName(objectName);
}
EventsCodeNameMangler *EventsCodeNameMangler::Get() {
if (NULL == _singleton) _singleton = new EventsCodeNameMangler;
if (nullptr == _singleton) _singleton = new EventsCodeNameMangler;
return (static_cast<EventsCodeNameMangler *>(_singleton));
}
void EventsCodeNameMangler::DestroySingleton() {
if (NULL != _singleton) {
if (nullptr != _singleton) {
delete _singleton;
_singleton = NULL;
_singleton = nullptr;
}
}

View File

@@ -6,26 +6,34 @@
#if defined(GD_IDE_ONLY)
#ifndef EVENTSCODENAMEMANGLER_H
#define EVENTSCODENAMEMANGLER_H
#include <unordered_map>
#include "GDCore/String.h"
/**
* Manage name mangling, so as to ensure all names used in code are valid.
* \brief Mangle object names, so as to ensure all names used in code are valid.
*
* \see ManObjListName
*/
class GD_CORE_API EventsCodeNameMangler {
public:
/**
* Get the mangled name from a name : All characters that are not 0-9, a-z,
* Get the mangled name from a name: All characters that are not 0-9, a-z,
* A-Z or _ are replaced by "_"+AsciiCodeOfTheCharacter.
*
* The mangled name is memoized as this is intensively used during project
* export and events code generation.
*/
gd::String GetMangledObjectsListName(const gd::String &originalObjectName);
const gd::String &GetMangledObjectsListName(
const gd::String &originalObjectName);
/**
* Get the mangled function name to be used to call external events named \a
* externalEventsName.
*
* The mangled name is memoized as this is intensively used during project
* export and events code generation.
*/
gd::String GetExternalEventsFunctionMangledName(
const gd::String &GetExternalEventsFunctionMangledName(
const gd::String &externalEventsName);
static EventsCodeNameMangler *Get();
@@ -35,14 +43,22 @@ class GD_CORE_API EventsCodeNameMangler {
EventsCodeNameMangler(){};
virtual ~EventsCodeNameMangler(){};
static EventsCodeNameMangler *_singleton;
std::unordered_map<gd::String, gd::String>
mangledObjectNames; ///< Memoized results of mangling for objects
std::unordered_map<gd::String, gd::String>
mangledExternalEventsNames; ///< Memoized results of mangling for
/// external events
};
/**
* Shortcut to
* EventsCodeNameMangler::Get()->GetMangledObjectsListName(objectName). \see
* EventsCodeNameMangler \return Mangled object name
* Shortcut for
* `EventsCodeNameMangler::Get()->GetMangledObjectsListName(objectName)`.
*
* \see EventsCodeNameMangler
* \return Mangled object name
*/
gd::String GD_CORE_API ManObjListName(const gd::String &objectName);
const gd::String &GD_CORE_API ManObjListName(const gd::String &objectName);
#endif // EVENTSCODENAMEMANGLER_H
#endif

View File

@@ -14,8 +14,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
gd::PlatformExtension& extension) {
extension
.SetExtensionInformation("BuiltinObject",
_("Base object"),
_("Base object"),
_("Features for all objects"),
_("Common features that can be used for all objects in GDevelop."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects/base_object/events");

View File

@@ -595,7 +595,8 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
gd::String search,
bool matchCase,
bool inConditions,
bool inActions) {
bool inActions,
bool inEventStrings) {
vector<EventsSearchResult> results;
for (std::size_t i = 0; i < events.size(); ++i) {
@@ -631,6 +632,16 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
}
}
if (inEventStrings) {
if (!eventAddedInResults &&
SearchStringInEvent(project, layout, events[i], search, matchCase)) {
results.push_back(EventsSearchResult(
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
&events,
i));
}
}
if (events[i].CanHaveSubEvents()) {
vector<EventsSearchResult> subResults =
SearchInEvents(project,
@@ -639,7 +650,8 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
search,
matchCase,
inConditions,
inActions);
inActions,
inEventStrings);
std::copy(
subResults.begin(), subResults.end(), std::back_inserter(results));
}
@@ -711,6 +723,22 @@ bool EventsRefactorer::SearchStringInConditions(
return false;
}
bool EventsRefactorer::SearchStringInEvent(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::BaseEvent& event,
gd::String search,
bool matchCase) {
for (gd::String str : event.GetAllSearchableStrings()) {
if (matchCase) {
if (str.find(search) != gd::String::npos) return true;
} else {
if (str.FindCaseInsensitive(search) != gd::String::npos) return true;
}
}
return false;
}
EventsSearchResult::EventsSearchResult(std::weak_ptr<gd::BaseEvent> event_,
gd::EventsList* eventsList_,
std::size_t positionInList_)

View File

@@ -103,7 +103,8 @@ class GD_CORE_API EventsRefactorer {
gd::String search,
bool matchCase,
bool inConditions,
bool inAction);
bool inActions,
bool inEventStrings);
/**
* Replace all occurrences of a gd::String in events
@@ -202,6 +203,11 @@ class GD_CORE_API EventsRefactorer {
gd::InstructionsList& conditions,
gd::String search,
bool matchCase);
static bool SearchStringInEvent(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::BaseEvent& events,
gd::String search,
bool matchCase);
EventsRefactorer(){};
};

View File

@@ -1,59 +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/ExpressionsCorrectnessTesting.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Expression.h"
#include "GDCore/Events/Parsers/ExpressionParser.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
namespace gd {
CallbacksForExpressionCorrectnessTesting::
CallbacksForExpressionCorrectnessTesting(const gd::ObjectsContainer& project_,
const gd::ObjectsContainer& layout_)
: project(project_), layout(layout_) {}
bool CallbacksForExpressionCorrectnessTesting::OnSubMathExpression(
const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
CallbacksForExpressionCorrectnessTesting callbacks(project, layout);
gd::ExpressionParser parser(expression.GetPlainString());
if (!parser.ParseMathExpression(platform, project, layout, callbacks)) {
#if defined(GD_IDE_ONLY)
firstErrorStr = callbacks.GetFirstError();
firstErrorPos = callbacks.GetFirstErrorPosition();
#endif
return false;
}
return true;
}
bool CallbacksForExpressionCorrectnessTesting::OnSubTextExpression(
const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
CallbacksForExpressionCorrectnessTesting callbacks(project, layout);
gd::ExpressionParser parser(expression.GetPlainString());
if (!parser.ParseStringExpression(platform, project, layout, callbacks)) {
#if defined(GD_IDE_ONLY)
firstErrorStr = callbacks.GetFirstError();
firstErrorPos = callbacks.GetFirstErrorPosition();
#endif
return false;
}
return true;
}
} // namespace gd

View File

@@ -1,75 +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 GDCORE_EXPRESSIONSCORRECTNESSTESTING_H
#define GDCORE_EXPRESSIONSCORRECTNESSTESTING_H
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser.h"
#include "GDCore/String.h"
namespace gd {
class ExpressionMetadata;
class Expression;
class Project;
class Layout;
}
namespace gd {
// TODO: Replace and remove (ExpressionValidator)
/**
* \brief Parser callbacks used to check expressions correctness
*
* Usage example:
* \code
* gd::CallbacksForExpressionCorrectnessTesting callbacks(game, scene);
* gd::ExpressionParser expressionParser(expression);
* if ( !expressionParser.ParseMathExpression(game, scene, callbacks) )
* //Expression is not valid
* else
* //Expression is correct
* \endcode
*
* \see gd::ExpressionParser
* \see gd::ParserCallbacks
*
* \ingroup IDE
*/
class GD_CORE_API CallbacksForExpressionCorrectnessTesting
: public gd::ParserCallbacks {
public:
CallbacksForExpressionCorrectnessTesting(const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout);
virtual ~CallbacksForExpressionCorrectnessTesting(){};
void OnConstantToken(gd::String text){};
void OnStaticFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo){};
void OnObjectFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo){};
void OnObjectBehaviorFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo){};
bool OnSubMathExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression);
bool OnSubTextExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression);
private:
const gd::ObjectsContainer& project;
const gd::ObjectsContainer& layout;
};
} // namespace gd
#endif // GDCORE_EXPRESSIONSCORRECTNESSTESTING_H

View File

@@ -10,34 +10,49 @@
namespace gd {
gd::String SceneNameMangler::GetMangledSceneName(gd::String sceneName) {
static const gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const gd::String allowedExceptFirst = "0123456789";
SceneNameMangler *SceneNameMangler::_singleton = nullptr;
std::size_t i = 0;
for (auto it = sceneName.begin(); it != sceneName.end(); ++it) {
char32_t character = *it;
if (allowedCharacters.find(character) == gd::String::npos &&
(allowedExceptFirst.find(character) == gd::String::npos ||
i == 0)) // Also disallow some characters to be in first position
{
// Replace the character by an underscore and its unicode codepoint (in
// base 10)
auto it2 = it;
++it2;
sceneName.replace(it, it2, "_" + gd::String::From(character));
// The iterator it may have been invalidated:
// re-assign it with a new iterator pointing to the same position.
it = sceneName.begin();
std::advance(it, i);
}
++i;
const gd::String &SceneNameMangler::GetMangledSceneName(
const gd::String &sceneName) {
auto it = mangledSceneNames.find(sceneName);
if (it != mangledSceneNames.end()) {
return it->second;
}
return sceneName;
gd::String partiallyMangledName = sceneName;
static const gd::String alwaysAllowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const gd::String allowedExceptFirstCharacters = "0123456789";
for (size_t i = 0; i < partiallyMangledName.size();
++i) // Replace all unallowed letter by an underscore and the unicode
// code point of the letter
{
if (alwaysAllowedCharacters.find_first_of(
std::u32string(1, partiallyMangledName[i])) == gd::String::npos &&
(i == 0 ||
allowedExceptFirstCharacters.find(
std::u32string(1, partiallyMangledName[i])) == gd::String::npos)) {
char32_t unallowedChar = partiallyMangledName[i];
partiallyMangledName.replace(i, 1, "_" + gd::String::From(unallowedChar));
}
}
mangledSceneNames[sceneName] = partiallyMangledName;
return mangledSceneNames[sceneName];
}
SceneNameMangler *SceneNameMangler::Get() {
if (nullptr == _singleton) _singleton = new SceneNameMangler;
return (static_cast<SceneNameMangler *>(_singleton));
}
void SceneNameMangler::DestroySingleton() {
if (nullptr != _singleton) {
delete _singleton;
_singleton = nullptr;
}
}
} // namespace gd

View File

@@ -6,12 +6,14 @@
#ifndef SCENENAMEMANGLER_H
#define SCENENAMEMANGLER_H
#include <unordered_map>
#include "GDCore/String.h"
namespace gd {
/**
* \brief Used to mangle the name of a scene
* \brief Mangle the name of a scene, so that it can be used in code or file
* names.
*
* \ingroup IDE
*/
@@ -21,12 +23,22 @@ class GD_CORE_API SceneNameMangler {
* \brief Mangle the name of a scene, replacing all characters that are not
* 0-9, a-z or A-Z by "_"+UnicodeCodePointOfTheCharacter. The first character
* must be a letter, otherwise it is also replaced in the same manner.
*
* The mangled name is memoized as this is intensively used during project
* export and events code generation.
*/
static gd::String GetMangledSceneName(gd::String sceneName);
const gd::String& GetMangledSceneName(const gd::String& sceneName);
static SceneNameMangler* Get();
static void DestroySingleton();
private:
SceneNameMangler(){};
virtual ~SceneNameMangler(){};
static SceneNameMangler* _singleton;
std::unordered_map<gd::String, gd::String>
mangledSceneNames; ///< Memoized results of mangling
};
} // namespace gd

View File

@@ -8,8 +8,8 @@
#define GDCORE_EVENTSFUNCTIONEXTENSION_H
#include <vector>
#include "GDCore/Project/EventsFunctionsContainer.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsFunctionsContainer.h"
#include "GDCore/String.h"
#include "GDCore/Tools/SerializableWithNameList.h"
namespace gd {
@@ -59,7 +59,8 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
}
const gd::String& GetShortDescription() const { return shortDescription; };
EventsFunctionsExtension& SetShortDescription(const gd::String& shortDescription_) {
EventsFunctionsExtension& SetShortDescription(
const gd::String& shortDescription_) {
shortDescription = shortDescription_;
return *this;
}
@@ -97,15 +98,15 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
/**
* \brief Return a reference to the list of the events based behaviors.
*/
SerializableWithNameList<EventsBasedBehavior>& GetEventsBasedBehaviors() {
gd::SerializableWithNameList<EventsBasedBehavior>& GetEventsBasedBehaviors() {
return eventsBasedBehaviors;
}
/**
* \brief Return a const reference to the list of the events based behaviors.
*/
const SerializableWithNameList<EventsBasedBehavior>& GetEventsBasedBehaviors()
const {
const gd::SerializableWithNameList<EventsBasedBehavior>&
GetEventsBasedBehaviors() const {
return eventsBasedBehaviors;
}
@@ -139,7 +140,7 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
gd::String fullName;
gd::String tags;
gd::String author;
SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
};
} // namespace gd

View File

@@ -63,7 +63,7 @@ Layout::Layout()
void Layout::SetName(const gd::String& name_) {
name = name_;
mangledName = gd::SceneNameMangler::GetMangledSceneName(name);
mangledName = gd::SceneNameMangler::Get()->GetMangledSceneName(name);
};
bool Layout::HasBehaviorSharedData(const gd::String& behaviorName) {

View File

@@ -25,11 +25,11 @@ gd::String GetTranslation(const char* str) { // TODO: Inline?
// }
ensureCache.prepare();
var translatedStr = getTranslation(Pointer_stringify($0));
var translatedStr = getTranslation(UTF8ToString($0));
return ensureString(translatedStr);
},
str);
return gd::String(translatedStr); // TODO: Is copying necessary?
}
} // namespace gd
#endif
#endif

View File

@@ -11,16 +11,31 @@
TEST_CASE("SceneNameMangler", "[common]") {
SECTION("Basics") {
REQUIRE(gd::SceneNameMangler::GetMangledSceneName(
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(
u8"TotallyCorrectSceneName") == u8"TotallyCorrectSceneName");
REQUIRE(gd::SceneNameMangler::GetMangledSceneName(
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(
u8"TotallyCorrectSceneName") == u8"TotallyCorrectSceneName");
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(
u8"Totally NOT CorrectSceneName") ==
u8"Totally_32NOT_32CorrectSceneName");
REQUIRE(gd::SceneNameMangler::GetMangledSceneName(u8"Nouvelle scène") ==
u8"Nouvelle_32sc_232ne");
REQUIRE(gd::SceneNameMangler::GetMangledSceneName(u8"A test Ԙ") ==
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(
u8"Totally NOT CorrectSceneName") ==
u8"Totally_32NOT_32CorrectSceneName");
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(
u8"Nouvelle scène") == u8"Nouvelle_32sc_232ne");
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(
u8"Nouvelle scène") == u8"Nouvelle_32sc_232ne");
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(u8"A test Ԙ") ==
u8"A_32test_32_1304");
REQUIRE(gd::SceneNameMangler::GetMangledSceneName(u8"1 Nouvelle scène") ==
u8"_49_32Nouvelle_32sc_232ne");
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(u8"A test Ԙ") ==
u8"A_32test_32_1304");
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(
u8"1 Nouvelle scène") == u8"_49_32Nouvelle_32sc_232ne");
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(
u8"1 Nouvelle scène") == u8"_49_32Nouvelle_32sc_232ne");
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(
u8"汉语") == u8"_27721_35821");
REQUIRE(gd::SceneNameMangler::Get()->GetMangledSceneName(
u8"汉语") == u8"_27721_35821");
}
}

View File

@@ -1,67 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
/**
* @file Tests covering common features of GDevelop Core.
*/
#include "GDCore/Events/Parsers/VariableParser.h"
#include "GDCore/String.h"
#include "catch.hpp"
namespace {
class TestVariableParserCallbacks : public gd::VariableParserCallbacks {
public:
TestVariableParserCallbacks(gd::String &debugStr)
: VariableParserCallbacks(), debugStr(debugStr) {}
virtual void OnRootVariable(gd::String variableName) {
debugStr += "OnRootVariable(" + variableName + ")\n";
}
virtual void OnChildVariable(gd::String variableName) {
debugStr += "OnChildVariable(" + variableName + ")\n";
}
virtual void OnChildSubscript(gd::String stringExpression) {
debugStr += "OnChildSubscript(" + stringExpression + ")\n";
}
private:
gd::String &debugStr;
};
} // namespace
TEST_CASE("VariableParser", "[common][events]") {
SECTION("Basics") {
{
gd::String str;
TestVariableParserCallbacks callbacks(str);
gd::VariableParser parser("myVar");
parser.Parse(callbacks);
REQUIRE(str == "OnRootVariable(myVar)\n");
}
{
gd::String str;
TestVariableParserCallbacks callbacks(str);
gd::VariableParser parser("myVar.child1.child2");
parser.Parse(callbacks);
REQUIRE(str ==
"OnRootVariable(myVar)\nOnChildVariable(child1)\nOnChildVariable("
"child2)\n");
}
{
gd::String str;
TestVariableParserCallbacks callbacks(str);
gd::VariableParser parser("myVar[ToString(i) + \"é\"].child");
parser.Parse(callbacks);
REQUIRE(str ==
"OnRootVariable(myVar)\nOnChildSubscript(ToString(i) + "
"\"é\")\nOnChildVariable(child)\n");
}
}
}

View File

@@ -1,6 +1,8 @@
#Clone SFML from its official directory using Git
# Clone SFML from its official directory using Git. Only
# do it if not already cloned to avoid triggering a whole
# recompilation every time CMake is run.
find_package(Git)
if(GIT_FOUND)
if(GIT_FOUND AND NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/SFML/readme.txt")
message( "Cloning SFML in ExtLibs/SFML with Git..." )
execute_process(
COMMAND ${GIT_EXECUTABLE} clone "https://www.github.com/SFML/SFML.git" SFML
@@ -11,7 +13,7 @@ if(GIT_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} reset --hard 2.4.1
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SFML
OUTPUT_QUIET)
OUTPUT_QUIET)
message( "Applying the patches..." )
file(GLOB SFML_PATCHES

View File

@@ -24,7 +24,7 @@ gdjs.AnchorRuntimeBehavior = function(runtimeScene, behaviorData, owner)
};
gdjs.AnchorRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.AnchorRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "AnchorBehavior::AnchorBehavior";
gdjs.registerBehavior("AnchorBehavior::AnchorBehavior", gdjs.AnchorRuntimeBehavior);
gdjs.AnchorRuntimeBehavior.HorizontalAnchor = {
NONE: 0,

View File

@@ -85,7 +85,8 @@ module.exports = {
objectProperties.set(
'fontFamily',
new gd.PropertyDescriptor(objectContent.fontFamily)
.setType('string')
.setType('resource')
.addExtraInfo('font')
.setLabel(_('Base font family'))
);
@@ -515,11 +516,25 @@ module.exports = {
.getValue();
this._pixiObject.textStyles.default.fontSize = `${fontSize}px`;
const fontFamily = this._associatedObject
const fontResourceName = this._associatedObject
.getProperties(this.project)
.get('fontFamily')
.getValue();
this._pixiObject.textStyles.default.fontFamily = fontFamily;
if (this._fontResourceName !== fontResourceName) {
this._fontResourceName = fontResourceName;
this._pixiResourcesLoader
.loadFontFamily(this._project, fontResourceName)
.then(fontFamily => {
// Once the font is loaded, we can use the given fontFamily.
this._pixiObject.textStyles.default.fontFamily = fontFamily;
})
.catch(err => {
// Ignore errors
console.warn('Unable to load font family', err);
});
}
const wordWrap = this._associatedObject
.getProperties(this.project)

View File

@@ -13,7 +13,10 @@ gdjs.BBTextRuntimeObjectPixiRenderer = function(runtimeObject, runtimeScene) {
if (this._pixiObject === undefined) {
this._pixiObject = new MultiStyleText(runtimeObject._text, {
default: {
fontFamily: runtimeObject._fontFamily,
fontFamily: runtimeScene
.getGame()
.getFontManager()
.getFontFamily(runtimeObject._fontFamily),
fontSize: runtimeObject._fontSize + 'px',
fill: runtimeObject._color,
tagStyle: 'bbcode',

View File

@@ -56,7 +56,7 @@ gdjs.BBTextRuntimeObject = function(runtimeScene, objectData) {
gdjs.BBTextRuntimeObject.prototype = Object.create(
gdjs.RuntimeObject.prototype
);
gdjs.BBTextRuntimeObject.thisIsARuntimeObjectConstructor = 'BBText::BBText';
gdjs.registerObject('BBText::BBText', gdjs.BBTextRuntimeObject);
gdjs.BBTextRuntimeObject.prototype.getRendererObject = function() {
return this._renderer.getRendererObject();

View File

@@ -50,13 +50,18 @@ function(gd_add_extension_target target_name source_files)
IF(target_name STREQUAL "")
MESSAGE(ERROR "You called gd_add_extension_target without specifying a target name")
ENDIF()
SET(platform_directory ${ARGV2})
IF(NOT platform_directory)
SET(platform_directory "CppPlatform")
ENDIF()
add_library(${target_name} SHARED ${source_files})
IF(EMSCRIPTEN)
# Emscripten treats all libraries as static libraries
add_library(${target_name} STATIC ${source_files})
ELSE()
add_library(${target_name} SHARED ${source_files})
ENDIF()
set_target_properties(${target_name} PROPERTIES PREFIX "")
set_target_properties(${target_name} PROPERTIES COMPILE_DEFINITIONS "${${target_name}_extra_definitions}")
set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/${platform_directory}/Extensions")

View File

@@ -18,7 +18,7 @@ gdjs.DestroyOutsideRuntimeBehavior = function(runtimeScene, behaviorData, owner)
};
gdjs.DestroyOutsideRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.DestroyOutsideRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "DestroyOutsideBehavior::DestroyOutside";
gdjs.registerBehavior("DestroyOutsideBehavior::DestroyOutside", gdjs.DestroyOutsideRuntimeBehavior);
gdjs.DestroyOutsideRuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {

View File

@@ -23,7 +23,7 @@ gdjs.DraggableRuntimeBehavior = function(runtimeScene, behaviorData, owner)
};
gdjs.DraggableRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.DraggableRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "DraggableBehavior::Draggable";
gdjs.registerBehavior("DraggableBehavior::Draggable", gdjs.DraggableRuntimeBehavior);
gdjs.DraggableRuntimeBehavior.prototype.onDeActivate = function() {
this._endDrag();

View File

@@ -20,7 +20,7 @@ gdjs.DummyRuntimeBehavior = function(runtimeScene, behaviorData, owner)
};
gdjs.DummyRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.DummyRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "MyDummyExtension::DummyBehavior";
gdjs.registerBehavior("MyDummyExtension::DummyBehavior", gdjs.DummyRuntimeBehavior);
gdjs.DummyRuntimeBehavior.prototype.onDeActivate = function() {
};

View File

@@ -22,8 +22,7 @@ gdjs.DummyRuntimeObject = function(runtimeScene, objectData) {
};
gdjs.DummyRuntimeObject.prototype = Object.create(gdjs.RuntimeObject.prototype);
gdjs.DummyRuntimeObject.thisIsARuntimeObjectConstructor =
"MyDummyExtension::DummyObject"; //Replace by your extension + object name.
gdjs.registerObject("MyDummyExtension::DummyObject", gdjs.DummyRuntimeObject); //Replace by your extension + object name.
gdjs.DummyRuntimeObject.prototype.getRendererObject = function() {
return this._renderer.getRendererObject();

View File

@@ -21,7 +21,7 @@ gdjs.DummyWithSharedDataRuntimeBehavior = function(runtimeScene, behaviorData, o
};
gdjs.DummyWithSharedDataRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.DummyWithSharedDataRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "MyDummyExtension::DummyBehaviorWithSharedData";
gdjs.registerBehavior("MyDummyExtension::DummyBehaviorWithSharedData", gdjs.DummyRuntimeBehavior);
gdjs.DummyWithSharedDataRuntimeBehavior.prototype.onDeActivate = function() {
};

View File

@@ -78,8 +78,7 @@ gdjs.PanelSpriteRuntimeObject = function(runtimeScene, panelSpriteObjectData) {
gdjs.PanelSpriteRuntimeObject.prototype = Object.create(
gdjs.RuntimeObject.prototype
);
gdjs.PanelSpriteRuntimeObject.thisIsARuntimeObjectConstructor =
'PanelSpriteObject::PanelSprite';
gdjs.registerObject("PanelSpriteObject::PanelSprite", gdjs.PanelSpriteRuntimeObject);
gdjs.PanelSpriteRuntimeObject.prototype.getRendererObject = function() {
return this._renderer.getRendererObject();

View File

@@ -164,7 +164,7 @@ gdjs.ParticleEmitterObject = function(runtimeScene, particleObjectData){
this.onCreated();
};
gdjs.ParticleEmitterObject.prototype = Object.create(gdjs.RuntimeObject.prototype);
gdjs.ParticleEmitterObject.thisIsARuntimeObjectConstructor = "ParticleSystem::ParticleEmitter";
gdjs.registerObject("ParticleSystem::ParticleEmitter", gdjs.ParticleEmitterObject);
gdjs.ParticleEmitterObject.prototype.setX = function(x){
if(this.x !== x) this._posDirty = true;

View File

@@ -102,7 +102,7 @@ gdjs.PathfindingObstacleRuntimeBehavior = function(runtimeScene, behaviorData, o
};
gdjs.PathfindingObstacleRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.PathfindingObstacleRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "PathfindingBehavior::PathfindingObstacleBehavior";
gdjs.registerBehavior("PathfindingBehavior::PathfindingObstacleBehavior", gdjs.PathfindingObstacleRuntimeBehavior);
gdjs.PathfindingObstacleRuntimeBehavior.prototype.onDestroy = function() {
if ( this._manager && this._registeredInManager ) this._manager.removeObstacle(this);

View File

@@ -46,7 +46,7 @@ gdjs.PathfindingRuntimeBehavior = function(runtimeScene, behaviorData, owner)
};
gdjs.PathfindingRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.PathfindingRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "PathfindingBehavior::PathfindingBehavior";
gdjs.registerBehavior("PathfindingBehavior::PathfindingBehavior", gdjs.PathfindingRuntimeBehavior);
gdjs.PathfindingRuntimeBehavior.prototype.setCellWidth = function(width) {
this._cellWidth = width;

View File

@@ -238,8 +238,7 @@ gdjs.Physics2RuntimeBehavior = function(runtimeScene, behaviorData, owner) {
gdjs.Physics2RuntimeBehavior.prototype = Object.create(
gdjs.RuntimeBehavior.prototype
);
gdjs.Physics2RuntimeBehavior.thisIsARuntimeBehaviorConstructor =
'Physics2::Physics2Behavior';
gdjs.registerBehavior('Physics2::Physics2Behavior', gdjs.Physics2RuntimeBehavior);
gdjs.Physics2RuntimeBehavior.prototype.b2Vec2 = function(x, y) {
this._tempb2Vec2.set_x(x);

View File

@@ -145,7 +145,7 @@ gdjs.PhysicsRuntimeBehavior = function(runtimeScene, behaviorData, owner)
};
gdjs.PhysicsRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.PhysicsRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "PhysicsBehavior::PhysicsBehavior";
gdjs.registerBehavior("PhysicsBehavior::PhysicsBehavior", gdjs.PhysicsRuntimeBehavior);
gdjs.PhysicsRuntimeBehavior.prototype.onDeActivate = function() {
if ( this._box2DBody !== null ) {

View File

@@ -63,7 +63,7 @@ gdjs.PlatformerObjectRuntimeBehavior = function(runtimeScene, behaviorData, owne
};
gdjs.PlatformerObjectRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.PlatformerObjectRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "PlatformBehavior::PlatformerObjectBehavior";
gdjs.registerBehavior("PlatformBehavior::PlatformerObjectBehavior", gdjs.PlatformerObjectRuntimeBehavior);
gdjs.PlatformerObjectRuntimeBehavior.prototype.doStepPreEvents = function(runtimeScene)
{

View File

@@ -100,7 +100,7 @@ gdjs.PlatformRuntimeBehavior = function(runtimeScene, behaviorData, owner)
};
gdjs.PlatformRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.PlatformRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "PlatformBehavior::PlatformBehavior";
gdjs.registerBehavior("PlatformBehavior::PlatformBehavior", gdjs.PlatformRuntimeBehavior);
gdjs.PlatformRuntimeBehavior.LADDER = 2;
gdjs.PlatformRuntimeBehavior.JUMPTHRU = 1;

View File

@@ -64,7 +64,7 @@ gdjs.ShapePainterRuntimeObject = function(runtimeScene, shapePainterObjectData)
};
gdjs.ShapePainterRuntimeObject.prototype = Object.create( gdjs.RuntimeObject.prototype );
gdjs.ShapePainterRuntimeObject.thisIsARuntimeObjectConstructor = "PrimitiveDrawing::Drawer";
gdjs.registerObject("PrimitiveDrawing::Drawer", gdjs.ShapePainterRuntimeObject);
gdjs.ShapePainterRuntimeObject.prototype.getRendererObject = function() {
return this._renderer.getRendererObject();

View File

@@ -33,7 +33,7 @@ gdjs.SkeletonRuntimeObject = function(runtimeScene, objectData){
this.onCreated();
};
gdjs.SkeletonRuntimeObject.prototype = Object.create(gdjs.RuntimeObject.prototype);
gdjs.SkeletonRuntimeObject.thisIsARuntimeObjectConstructor = "SkeletonObject::Skeleton";
gdjs.registerObject("SkeletonObject::Skeleton", gdjs.SkeletonRuntimeObject);
gdjs.SkeletonRuntimeObject.prototype.extraInitializationFromInitialInstance = function(initialInstanceData) {
if(initialInstanceData.customSize){

View File

@@ -33,7 +33,7 @@ gdjs.TextEntryRuntimeObject = function(runtimeScene, textEntryObjectData)
};
gdjs.TextEntryRuntimeObject.prototype = Object.create( gdjs.RuntimeObject.prototype );
gdjs.TextEntryRuntimeObject.thisIsARuntimeObjectConstructor = "TextEntryObject::TextEntry";
gdjs.registerObject("TextEntryObject::TextEntry", gdjs.TextEntryRuntimeObject);
gdjs.TextEntryRuntimeObject.prototype.onDestroyFromScene = function(runtimeScene) {
gdjs.RuntimeObject.prototype.onDestroyFromScene.call(this, runtimeScene);

View File

@@ -115,7 +115,7 @@ gdjs.TextRuntimeObject = function(runtimeScene, textObjectData)
};
gdjs.TextRuntimeObject.prototype = Object.create( gdjs.RuntimeObject.prototype );
gdjs.TextRuntimeObject.thisIsARuntimeObjectConstructor = "TextObject::Text";
gdjs.registerObject("TextObject::Text", gdjs.TextRuntimeObject);
gdjs.TextRuntimeObject.prototype.getRendererObject = function() {
return this._renderer.getRendererObject();

View File

@@ -41,7 +41,7 @@ gdjs.TiledSpriteRuntimeObject = function(runtimeScene, tiledSpriteObjectData)
};
gdjs.TiledSpriteRuntimeObject.prototype = Object.create( gdjs.RuntimeObject.prototype );
gdjs.TiledSpriteRuntimeObject.thisIsARuntimeObjectConstructor = "TiledSpriteObject::TiledSprite";
gdjs.registerObject("TiledSpriteObject::TiledSprite", gdjs.TiledSpriteRuntimeObject);
gdjs.TiledSpriteRuntimeObject.prototype.getRendererObject = function() {
return this._renderer.getRendererObject();

View File

@@ -36,7 +36,7 @@ gdjs.TopDownMovementRuntimeBehavior = function(runtimeScene, behaviorData, owner
};
gdjs.TopDownMovementRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.TopDownMovementRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "TopDownMovementBehavior::TopDownMovementBehavior";
gdjs.registerBehavior("TopDownMovementBehavior::TopDownMovementBehavior", gdjs.TopDownMovementRuntimeBehavior);
gdjs.TopDownMovementRuntimeBehavior.prototype.setAcceleration = function(acceleration) {
this._acceleration = acceleration;

View File

@@ -18,8 +18,7 @@ gdjs.TweenRuntimeBehavior.prototype = Object.create(
gdjs.RuntimeBehavior.prototype
);
gdjs.TweenRuntimeBehavior.thisIsARuntimeBehaviorConstructor =
"Tween::TweenBehavior";
gdjs.registerBehavior("Tween::TweenBehavior", gdjs.TweenRuntimeBehavior);
gdjs.TweenRuntimeBehavior.easings = [
"linear",

View File

@@ -17,7 +17,7 @@
* video will have the same state for this video (paused/playing, current time,
* volume, etc...).
*
* @memberof gdjs
* @memberOf gdjs
* @class VideoRuntimeObject
* @extends RuntimeObject
* @param {gdjs.RuntimeScene} runtimeScene The {@link gdjs.RuntimeScene} the object belongs to
@@ -50,7 +50,7 @@ gdjs.VideoRuntimeObject = function(runtimeScene, videoObjectData) {
};
gdjs.VideoRuntimeObject.prototype = Object.create(gdjs.RuntimeObject.prototype);
gdjs.VideoRuntimeObject.thisIsARuntimeObjectConstructor = "Video::VideoObject";
gdjs.registerObject("Video::VideoObject", gdjs.VideoRuntimeObject);
gdjs.VideoRuntimeObject.prototype.getRendererObject = function() {
return this._renderer.getRendererObject();

View File

@@ -6,11 +6,6 @@
#if defined(GD_IDE_ONLY)
#include "CppCodeEvent.h"
#include <fstream>
#include <iostream>
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Project/Layout.h"

View File

@@ -542,7 +542,7 @@ gd::String EventsCodeGenerator::GenerateSceneEventsCompleteCode(
output += codeGenerator.GetCustomCodeOutsideMain() +
"\n"
"extern \"C\" int GDSceneEvents" +
gd::SceneNameMangler::GetMangledSceneName(scene.GetName()) +
gd::SceneNameMangler::Get()->GetMangledSceneName(scene.GetName()) +
"(RuntimeContext * runtimeContext)\n"
"{\n" +
"runtimeContext->StartNewFrame();\n" + wholeEventsCode +

View File

@@ -5,9 +5,6 @@
*/
#include "GDCpp/Extensions/Builtin/VariablesExtension.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCpp/Runtime/CommonTools.h"
#include "GDCpp/Runtime/Project/Layout.h"

View File

@@ -191,7 +191,7 @@ int main( int argc, char *p_argv[] )
sceneStack.OnLoadScene([&codeLibraryName](RuntimeScene & scene) {
if (!codeLibraryName.empty() &&
!scene.GetCodeExecutionEngine()->LoadFromDynamicLibrary(codeLibraryName,
"GDSceneEvents"+gd::SceneNameMangler::GetMangledSceneName(scene.GetName())))
"GDSceneEvents"+gd::SceneNameMangler::Get()->GetMangledSceneName(scene.GetName())))
{
return false;
}

View File

@@ -50,11 +50,13 @@ list(REMOVE_ITEM formatted_source_files "${CMAKE_CURRENT_SOURCE_DIR}/GDJS/IDE/Di
list(REMOVE_ITEM formatted_source_files "${CMAKE_CURRENT_SOURCE_DIR}/GDJS/IDE/mongoose/mongoose.c" "${CMAKE_CURRENT_SOURCE_DIR}/GDJS/IDE/mongoose/mongoose.h")
gd_add_clang_utils(GDJS "${formatted_source_files}")
add_library(
GDJS
SHARED
${source_files}
)
IF(EMSCRIPTEN)
# Emscripten treats all libraries as static libraries
add_library(GDJS STATIC ${source_files})
ELSE()
add_library(GDJS SHARED ${source_files})
ENDIF()
IF(EMSCRIPTEN)
set_target_properties(GDJS PROPERTIES SUFFIX ".bc")
ELSEIF(WIN32)
@@ -75,21 +77,3 @@ ELSE()
target_link_libraries(GDJS GDCore)
target_link_libraries(GDJS ${sfml_LIBRARIES})
ENDIF()
#Post build tasks
###
IF(EMSCRIPTEN)
#Nothing.
ELSE()
IF(WIN32)
add_custom_target(GDJS_Runtime
ALL
COMMAND "${GD_base_dir}/GDJS/scripts/CopyRuntimeToGD.bat" ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/JsPlatform/Runtime
WORKING_DIRECTORY ${GD_base_dir}/GDJS/scripts)
ELSE()
add_custom_target(GDJS_Runtime
ALL
COMMAND bash "CopyRuntimeToGD.sh" ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}/JsPlatform/Runtime
WORKING_DIRECTORY ${GD_base_dir}/GDJS/scripts)
ENDIF()
ENDIF()

View File

@@ -4,12 +4,7 @@
*/
#include "JsCodeEvent.h"
#include <fstream>
#include <iostream>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Project/Layout.h"

View File

@@ -105,7 +105,7 @@ CODE_NAMESPACE.RUNTIME_BEHAVIOR_CLASSNAME = function(runtimeScene, behaviorData,
};
CODE_NAMESPACE.RUNTIME_BEHAVIOR_CLASSNAME.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
CODE_NAMESPACE.RUNTIME_BEHAVIOR_CLASSNAME.thisIsARuntimeBehaviorConstructor = "EXTENSION_NAME::BEHAVIOR_NAME";
gdjs.registerBehavior("EXTENSION_NAME::BEHAVIOR_NAME", CODE_NAMESPACE.RUNTIME_BEHAVIOR_CLASSNAME);
// Properties:
PROPERTIES_CODE

View File

@@ -97,7 +97,7 @@ gd::String EventsCodeGenerator::GenerateSceneEventsCompleteCode(
// Export the symbols to avoid them being stripped by the Closure Compiler:
output += "gdjs['" +
gd::SceneNameMangler::GetMangledSceneName(scene.GetName()) +
gd::SceneNameMangler::Get()->GetMangledSceneName(scene.GetName()) +
"Code']" + " = " + codeGenerator.GetCodeNamespace() + ";\n";
includeFiles.insert(codeGenerator.GetIncludeFiles().begin(),
@@ -1057,7 +1057,7 @@ gd::String EventsCodeGenerator::GenerateBooleanFullName(
gd::String EventsCodeGenerator::GetCodeNamespace() {
if (HasProjectAndLayout()) {
return "gdjs." +
gd::SceneNameMangler::GetMangledSceneName(GetLayout().GetName()) +
gd::SceneNameMangler::Get()->GetMangledSceneName(GetLayout().GetName()) +
"Code";
} else if (!codeNamespace.empty()) {
return codeNamespace;

View File

@@ -5,9 +5,6 @@
*/
#include "JoystickExtension.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Tools/Localization.h"

View File

@@ -4,11 +4,6 @@
* reserved. This project is released under the MIT License.
*/
#include "KeyboardExtension.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Tools/Localization.h"

View File

@@ -4,10 +4,6 @@
* reserved. This project is released under the MIT License.
*/
#include "MathematicalToolsExtension.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Tools/Localization.h"

View File

@@ -4,10 +4,6 @@
* reserved. This project is released under the MIT License.
*/
#include "MouseExtension.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Tools/Localization.h"

View File

@@ -4,10 +4,6 @@
* reserved. This project is released under the MIT License.
*/
#include "TimeExtension.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
#include "GDCore/Extensions/Builtin/AllBuiltinExtensions.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Tools/Localization.h"

View File

@@ -296,7 +296,7 @@ bool ExporterHelper::ExportCordovaFiles(const gd::Project &project,
gd::String jsonVersion =
gd::Serializer::ToJSON(gd::SerializerElement(project.GetVersion()));
gd::String jsonMangledName = gd::Serializer::ToJSON(gd::SerializerElement(
gd::SceneNameMangler::GetMangledSceneName(project.GetName())
gd::SceneNameMangler::Get()->GetMangledSceneName(project.GetName())
.LowerCase()
.FindAndReplace(" ", "-")));
@@ -421,7 +421,7 @@ bool ExporterHelper::ExportElectronFiles(const gd::Project &project,
gd::String jsonVersion =
gd::Serializer::ToJSON(gd::SerializerElement(project.GetVersion()));
gd::String jsonMangledName = gd::Serializer::ToJSON(gd::SerializerElement(
gd::SceneNameMangler::GetMangledSceneName(project.GetName())
gd::SceneNameMangler::Get()->GetMangledSceneName(project.GetName())
.LowerCase()
.FindAndReplace(" ", "-")));

View File

@@ -23,8 +23,6 @@ cc.game.onStart = function(){
if(!cc.sys.isNative && document.getElementById("cocosLoading")) //If referenced loading.js, please remove it
document.body.removeChild(document.getElementById("cocosLoading"));
gdjs.registerObjects();
gdjs.registerBehaviors();
gdjs.registerGlobalCallbacks();
var game = new gdjs.RuntimeGame(gdjs.projectData, {});

View File

@@ -20,8 +20,6 @@
navigator.splashscreen.hide();
//Initialization
gdjs.registerObjects();
gdjs.registerBehaviors();
gdjs.registerGlobalCallbacks();
var game = new gdjs.RuntimeGame(gdjs.projectData, {}/*GDJS_ADDITIONAL_SPEC*/);

View File

@@ -24,7 +24,7 @@
/* GDJS_CUSTOM_STYLE */
</style>
<!-- Facebook Instant Games SDK (see https://developers.facebook.com/docs/games/instant-games/getting-started/quickstart) -->
<script src="https://connect.facebook.net/en_US/fbinstant.6.0.js"></script>
@@ -40,8 +40,6 @@
(function() {
//Initialization
gdjs.registerObjects();
gdjs.registerBehaviors();
gdjs.registerGlobalCallbacks();
var game = new gdjs.RuntimeGame(gdjs.projectData, {}/*GDJS_ADDITIONAL_SPEC*/);
@@ -54,7 +52,7 @@
game.getRenderer().bindStandardEvents(game.getInputManager(), window, document);
FBInstant.initializeAsync()
.then(function() {
.then(function() {
//Load all assets and start the game
game.loadAllAssets(function() {
FBInstant.startGameAsync()

View File

@@ -15,7 +15,7 @@ window.gdjs = {
* Contains functions used by events (this is a convention only, functions can actually
* by anywhere).
* @namespace
* @memberof gdjs
* @memberOf gdjs
*/
evtTools: {},
callbacksRuntimeSceneLoaded: [],
@@ -91,73 +91,37 @@ gdjs.toDegrees = function(angleInRadians) {
return (angleInRadians * 180) / 3.14159;
};
/**
* Register the runtime objects that can be used in runtimeScene.<br>
* Objects must be part of gdjs and have their property "thisIsARuntimeObjectConstructor"
* defined and set to the name of the type of the object so as to be recognized.
* Register a runtime object (class extending {@link gdjs.RuntimeObject}) that can be used in a scene.
*
* The name of the type of the object must be complete, with the namespace if any. For
* example, if you are providing a Text object in the TextObject extension, the full name
* of the type of the object is "TextObject::Text".
*
* @param {string} objectTypeName The name of the type of the Object.
* @param Ctor The constructor of the Object.
*/
gdjs.registerObjects = function() {
gdjs.objectsTypes.clear();
for (var p in this) {
if (this.hasOwnProperty(p)) {
if (gdjs[p].thisIsARuntimeObjectConstructor != undefined) {
gdjs.objectsTypes.put(gdjs[p].thisIsARuntimeObjectConstructor, gdjs[p]);
}
}
}
gdjs.registerObject = function(objectTypeName, Ctor){
gdjs.objectsTypes.put(objectTypeName, Ctor)
};
/**
* Register the runtime behaviors that can be used bt runtimeObject.
*
* Behavior must be a property on gdjs (or on a inner object, but not on any object nested below)
* and have a property "thisIsARuntimeBehaviorConstructor" defined and set
* to the type of the behavior to be recognized.
* Register a runtime behavior (class extending {@link gdjs.RuntimeBehavior}) that can be used by a
* {@link gdjs.RuntimeObject}.
*
* The type of the behavior must be complete, with the namespace of the extension. For
* example, if you are providing a Draggable behavior in the DraggableBehavior extension,
* the full name of the type of the behavior is "DraggableBehavior::Draggable".
*
* @param {string} behaviorTypeName The name of the type of the behavior.
* @param Ctor The constructor of the Object.
*/
gdjs.registerBehaviors = function() {
gdjs.behaviorsTypes.clear();
for (var gdjsProperty in this) {
if (this.hasOwnProperty(gdjsProperty)) {
// Search in object inside gdjs.
var innerObject = gdjs[gdjsProperty];
if (innerObject.thisIsARuntimeBehaviorConstructor != undefined) {
gdjs.behaviorsTypes.put(
innerObject.thisIsARuntimeBehaviorConstructor,
innerObject
);
} else if (
Object.prototype.toString.call(innerObject) !== '[object Array]' &&
typeof innerObject === 'object' &&
innerObject !== null
) {
// Also search inside objects contained in gdjs.
for (var innerObjectProperty in innerObject) {
if (innerObject.hasOwnProperty(innerObjectProperty)) {
var innerInnerObject = innerObject[innerObjectProperty];
if (
innerInnerObject !== null &&
typeof innerInnerObject === 'function' &&
innerInnerObject.thisIsARuntimeBehaviorConstructor != undefined
) {
gdjs.behaviorsTypes.put(
innerInnerObject.thisIsARuntimeBehaviorConstructor,
innerInnerObject
);
}
}
}
}
}
}
gdjs.registerBehavior = function(behaviorTypeName, Ctor){
gdjs.behaviorsTypes.put(
behaviorTypeName,
Ctor
);
};
/**
@@ -225,7 +189,7 @@ gdjs.registerGlobalCallbacks = function() {
/**
* Get the constructor of an object.
*
* @param name {String} The name of the type of the object.
* @param {string} name The name of the type of the object.
*/
gdjs.getObjectConstructor = function(name) {
if (name !== undefined && gdjs.objectsTypes.containsKey(name))
@@ -238,7 +202,7 @@ gdjs.getObjectConstructor = function(name) {
/**
* Get the constructor of a behavior.
*
* @param name {String} The name of the type of the behavior.
* @param {string} name The name of the type of the behavior.
*/
gdjs.getBehaviorConstructor = function(name) {
if (name !== undefined && gdjs.behaviorsTypes.containsKey(name))

View File

@@ -35,8 +35,6 @@
(function() {
//Initialization
gdjs.registerObjects();
gdjs.registerBehaviors();
gdjs.registerGlobalCallbacks();
var game = new gdjs.RuntimeGame(gdjs.projectData, {}/*GDJS_ADDITIONAL_SPEC*/);

View File

@@ -144,7 +144,6 @@ gdjs.RuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
*/
gdjs.RuntimeBehavior.prototype.onDestroy = function() {
}
};
//Notify gdjs this.the runtimeBehavior exists.
gdjs.RuntimeBehavior.thisIsARuntimeBehaviorConstructor = "";
gdjs.registerBehavior("", gdjs.RuntimeBehavior);

View File

@@ -33,8 +33,7 @@
* @param {gdjs.RuntimeScene} runtimeScene The {@link gdjs.RuntimeScene} the object belongs to.
* @param {ObjectData} objectData The initial properties of the object.
*/
gdjs.RuntimeObject = function(runtimeScene, objectData)
{
gdjs.RuntimeObject = function(runtimeScene, objectData) {
this.name = objectData.name || "";
this._nameId = gdjs.RuntimeObject.getNameIdentifier(this.name);
this.type = objectData.type || "";
@@ -1488,5 +1487,4 @@ gdjs.RuntimeObject.getNameIdentifier = function(name) {
return newIdentifier;
};
//Notify gdjs the RuntimeObject exists.
gdjs.RuntimeObject.thisIsARuntimeObjectConstructor = "";
gdjs.registerObject("", gdjs.RuntimeObject);

View File

@@ -5,53 +5,53 @@
*/
/**
* @typedef {Object} Point Represents a point in a frame
* @property {number} x X position of the point
* @property {number} y Y position of the point
* @typedef {Object} SpritePoint Represents a point in a coordinate system.
* @property {number} x X position of the point.
* @property {number} y Y position of the point.
*/
/**
* @typedef {Object} CustomPointData Represents a custom point in a frame
* @property {string} name Name of the point
* @property {number} x X position of the point
* @property {number} y Y position of the point
* @typedef {Object} SpriteCustomPointData Represents a custom point in a frame.
* @property {string} name Name of the point.
* @property {number} x X position of the point.
* @property {number} y Y position of the point.
*/
/**
* @typedef {Object} CenterPointData Represents the center point in a frame
* @typedef {Object} SpriteCenterPointData Represents the center point in a frame.
* @property {boolean} automatic Is the center automatically computed?
* @property {number} x X position of the point
* @property {number} y Y position of the point
* @property {number} x X position of the point.
* @property {number} y Y position of the point.
*/
/**
* @typedef {Object} FrameData Represents a {@link gdjs.SpriteAnimationFrame}
* @property {string} [image] The resource name of the image used in this frame
* @property {Array<customPointData>} [points] The points of the frame
* @property {point} originPoint The origin point
* @property {centerPointData} centerPoint The center of the frame
* @typedef {Object} SpriteFrameData Represents a {@link gdjs.SpriteAnimationFrame}.
* @property {string} [image] The resource name of the image used in this frame.
* @property {Array<SpriteCustomPointData>} [points] The points of the frame.
* @property {SpritePoint} originPoint The origin point.
* @property {SpriteCenterPointData} centerPoint The center of the frame.
* @property {boolean} hasCustomCollisionMask Is The collision mask custom?
* @property {Array<Array<point>>} [customCollisionMask] The collision mask if it is custom
* @property {Array<Array<SpritePoint>>} [customCollisionMask] The collision mask if it is custom.
*/
/**
* @typedef {Object} DirectionData Represents the data of a {@link gdjs.SpriteAnimationDirection}
* @property {number} timeBetweenFrames Time between each frame, in seconds
* @typedef {Object} SpriteDirectionData Represents the data of a {@link gdjs.SpriteAnimationDirection}.
* @property {number} timeBetweenFrames Time between each frame, in seconds.
* @property {boolean} looping Is the animation looping?
* @property {Array<gdjs.SpriteAnimationFrame>} sprites The list of frames
* @property {Array<SpriteFrameData>} sprites The list of frames.
*/
/**
* @typedef {Object} AnimationData Represents the data of a {@link gdjs.SpriteAnimation}
* @property {string} [name] The name of the animation
* @typedef {Object} SpriteAnimationData Represents the data of a {@link gdjs.SpriteAnimation}.
* @property {string} [name] The name of the animation.
* @property {boolean} useMultipleDirections Does the animation use multiple {@link gdjs.SpriteAnimationDirection}?
* @property {Array<DirectionData>} directions The list of {@link DirectionData} representing {@link gdjs.SpriteAnimationDirection} instances
* @property {Array<SpriteDirectionData>} directions The list of {@link SpriteDirectionData} representing {@link gdjs.SpriteAnimationDirection} instances.
*/
/**
* @typedef {Object} SpriteObjectDataType
* @property {boolean} updateIfNotVisible Update the object even if he is not visible?
* @property {Array<AnimationData>} animations The list of {@link AnimationData} representing {@link gdjs.SpriteAnimation} instances
* @typedef {Object} SpriteObjectDataType Represents the data of a {@link gdjs.SpriteRuntimeObject}.
* @property {boolean} updateIfNotVisible Update the object even if he is not visible?.
* @property {Array<SpriteAnimationData>} animations The list of {@link SpriteAnimationData} representing {@link gdjs.SpriteAnimation} instances.
*
* @typedef {ObjectData & SpriteObjectDataType} SpriteObjectData
*/
@@ -62,27 +62,26 @@
* It contains the texture displayed as well as information like the points position
* or the collision mask.
*
* @memberof gdjs
* @memberOf gdjs
* @class SpriteAnimationFrame
* @param {gdjs.ImageManager} imageManager The game image manager
* @param {FrameData} frameData The frame data used to initialize the frame
* @param {SpriteFrameData} frameData The frame data used to initialize the frame
*/
gdjs.SpriteAnimationFrame = function(imageManager, frameData)
{
/** @type {string} */
this.image = frameData ? frameData.image : ""; //TODO: Rename in imageName, and do not store it in the object?
/** @type {PIXI.Texture} */
this.texture = gdjs.SpriteRuntimeObjectRenderer.getAnimationFrame(imageManager, this.image);
if ( this.center === undefined ) {
/** @type {Point} */
/** @type {SpritePoint} */
this.center = { x:0, y:0 };
};
}
if ( this.origin === undefined ) {
/** @type {Point} */
/** @type {SpritePoint} */
this.origin = { x:0, y:0 }
};
}
/** @type {boolean} */
this.hasCustomHitBoxes = false;
if ( this.customHitBoxes === undefined ) {
@@ -96,23 +95,23 @@ gdjs.SpriteAnimationFrame = function(imageManager, frameData)
//Initialize points:
for(var i = 0, len = frameData.points.length;i<len;++i) {
/** @type {CustomPointData} */
/** @type {SpriteCustomPointData} */
var ptData = frameData.points[i];
/** @type {Point} */
var point = {x:parseFloat(ptData.x), y:parseFloat(ptData.y)};
/** @type {SpritePoint} */
var point = {x: ptData.x, y: ptData.y};
this.points.put(ptData.name, point);
}
/** @type {Point} */
/** @type {SpritePoint} */
var origin = frameData.originPoint;
this.origin.x = parseFloat(origin.x);
this.origin.y = parseFloat(origin.y);
this.origin.x = origin.x;
this.origin.y = origin.y;
/** @type {CenterPointData} */
/** @type {SpriteCenterPointData} */
var center = frameData.centerPoint;
if ( center.automatic !== true ) {
this.center.x = parseFloat(center.x);
this.center.y = parseFloat(center.y);
this.center.x = center.x;
this.center.y = center.y;
}
else {
this.center.x = gdjs.SpriteRuntimeObjectRenderer.getAnimationFrameWidth(this.texture)/2;
@@ -123,22 +122,22 @@ gdjs.SpriteAnimationFrame = function(imageManager, frameData)
if ( frameData.hasCustomCollisionMask ) {
this.hasCustomHitBoxes = true;
for(var i = 0, len = frameData.customCollisionMask.length;i<len;++i) {
/** @type {Array<Point>} */
/** @type {Array<SpritePoint>} */
var polygonData = frameData.customCollisionMask[i];
//Add a polygon, if necessary (Avoid recreating a polygon if it already exists).
if ( i >= this.customHitBoxes.length ) this.customHitBoxes.push(new gdjs.Polygon());
for(var j = 0, len2 = polygonData.length;j<len2;++j) {
/** @type {Point} */
/** @type {SpritePoint} */
var pointData = polygonData[j];
//Add a point, if necessary (Avoid recreating a point if it already exists).
if ( j >= this.customHitBoxes[i].vertices.length )
this.customHitBoxes[i].vertices.push([0,0]);
this.customHitBoxes[i].vertices[j][0] = parseFloat(pointData.x, 10);
this.customHitBoxes[i].vertices[j][1] = parseFloat(pointData.y, 10);
this.customHitBoxes[i].vertices[j][0] = pointData.x;
this.customHitBoxes[i].vertices[j][1] = pointData.y;
}
this.customHitBoxes[i].vertices.length = j;
@@ -155,11 +154,11 @@ gdjs.SpriteAnimationFrame = function(imageManager, frameData)
* Get a point of the frame.<br>
* If the point does not exist, the origin is returned.
* @param {string} name The point's name
* @return {Point} The requested point. If it doesn't exists returns the origin point.
* @return {SpritePoint} The requested point. If it doesn't exists returns the origin point.
*/
gdjs.SpriteAnimationFrame.prototype.getPoint = function(name) {
if ( name == "Centre" || name == "Center") return this.center;
else if ( name == "Origin" ) return this.origin;
if ( name === "Centre" || name === "Center") return this.center;
else if ( name === "Origin" ) return this.origin;
return this.points.containsKey(name) ? this.points.get(name) : this.origin;
};
@@ -168,14 +167,14 @@ gdjs.SpriteAnimationFrame.prototype.getPoint = function(name) {
* Represents a direction of an animation of a {@link gdjs.SpriteRuntimeObject}.
*
* @class SpriteAnimationDirection
* @memberof gdjs
* @memberOf gdjs
* @param {gdjs.ImageManager} imageManager The game image manager
* @param {DirectionData} directionData The direction data used to initialize the direction
* @param {SpriteDirectionData} directionData The direction data used to initialize the direction
*/
gdjs.SpriteAnimationDirection = function(imageManager, directionData)
{
/** @type {number} */
this.timeBetweenFrames = directionData ? parseFloat(directionData.timeBetweenFrames) :
this.timeBetweenFrames = directionData ? directionData.timeBetweenFrames :
1.0;
/** @type {boolean} */
this.loop = !!directionData.looping;
@@ -185,7 +184,7 @@ gdjs.SpriteAnimationDirection = function(imageManager, directionData)
this.frames = [];
}
for(var i = 0, len = directionData.sprites.length;i<len;++i) {
/** @type {frameData} */
/** @type {SpriteFrameData} */
var frameData = directionData.sprites[i];
if ( i < this.frames.length )
@@ -200,9 +199,9 @@ gdjs.SpriteAnimationDirection = function(imageManager, directionData)
* Represents an animation of a {@link SpriteRuntimeObject}.
*
* @class SpriteAnimation
* @memberof gdjs
* @memberOf gdjs
* @param {gdjs.ImageManager} imageManager The game image manager
* @param {AnimationData} animData The animation data used to initialize the animation
* @param {SpriteAnimationData} animData The animation data used to initialize the animation
*/
gdjs.SpriteAnimation = function(imageManager, animData)
{
@@ -214,7 +213,7 @@ gdjs.SpriteAnimation = function(imageManager, animData)
/** @type {Array<gdjs.SpriteAnimationDirection>} */
if ( this.directions === undefined ) this.directions = [];
for(var i = 0, len = animData.directions.length;i<len;++i) {
/** @type {DirectionData} */
/** @type {SpriteDirectionData} */
var directionData = animData.directions[i];
if ( i < this.directions.length )
@@ -229,7 +228,7 @@ gdjs.SpriteAnimation = function(imageManager, animData)
* The SpriteRuntimeObject represents an object that can display images.
*
* @class SpriteRuntimeObject
* @memberof gdjs
* @memberOf gdjs
* @extends gdjs.RuntimeObject
* @param {gdjs.RuntimeScene} runtimeScene The scene the object belongs to
* @param {SpriteObjectData} spriteObjectData The object data used to initialize the object
@@ -271,7 +270,7 @@ gdjs.SpriteRuntimeObject = function(runtimeScene, spriteObjectData) {
this._animations = [];
}
for(var i = 0, len = spriteObjectData.animations.length;i<len;++i) {
/** @type {AnimationData} */
/** @type {SpriteAnimationData} */
var animData = spriteObjectData.animations[i];
if ( i < this._animations.length )
@@ -304,12 +303,13 @@ gdjs.SpriteRuntimeObject = function(runtimeScene, spriteObjectData) {
};
gdjs.SpriteRuntimeObject.prototype = Object.create( gdjs.RuntimeObject.prototype );
gdjs.SpriteRuntimeObject.thisIsARuntimeObjectConstructor = "Sprite"; //Notify gdjs of the object existence.
gdjs.registerObject("Sprite", gdjs.SpriteRuntimeObject); //Notify gdjs of the object existence.
//Others initialization and internal state management :
/**
* Initialize the extra parameters that could be set for an instance.
* @param {{numberProperties: Array<{name: string, value: number}>, customSize: {width: number, height: number}}} initialInstanceData The extra parameters
*/
gdjs.SpriteRuntimeObject.prototype.extraInitializationFromInitialInstance = function(initialInstanceData) {
if ( initialInstanceData.numberProperties ) {
@@ -585,7 +585,7 @@ gdjs.SpriteRuntimeObject.prototype.hasAnimationEnded = function() {
if ( this._animations[this._currentAnimation].loop ) return false;
var direction = this._animations[this._currentAnimation].directions[this._currentDirection];
return this._currentFrame == direction.frames.length-1;
return this._currentFrame === direction.frames.length-1;
};
gdjs.SpriteRuntimeObject.prototype.animationPaused = function() {

View File

@@ -14,7 +14,6 @@
"jsdoc-autoprivate": "0.0.1"
},
"scripts": {
"copy-runtime-to-ide": "echo \"Use scripts/CopyRuntimeToGD.sh (or .bat on Windows)\"",
"check-types": "tsc"
}
}

View File

@@ -1,14 +0,0 @@
::This script copies the runtimes files (i.e: the javascript files located into the Runtime
::folder and in the Extensions folder) to the GDevelop folder.
@echo off
cd /d %~dp0
set destDir=%1
if [%destDir%]==[] set destDir="..\..\Binaries\Output\Release_Windows\JsPlatform\Runtime"
echo Copying GDJS and extensions runtime files (*.js) to %destDir%...
xcopy "..\Runtime"\* %destDir%\* /S /E /D /Y /Q
xcopy "..\..\Extensions"\*.js %destDir%\Extensions\*.js /S /E /D /Y /Q /EXCLUDE:FilesExcludedFromCopy
echo ✅ Copied GDJS and extensions runtime files (*.js) to %destDir%.

View File

@@ -1,18 +0,0 @@
#!/bin/bash
#Get the destination, or copy by default to release directory
DESTINATION=../../Binaries/Output/Release_Linux/JsPlatform/Runtime/
if [ "$(uname)" == "Darwin" ]; then
DESTINATION=../../Binaries/Output/Release_Darwin/JsPlatform/Runtime/
fi
if [ ! $# -eq 0 ]; then
DESTINATION=$1
fi
#Copy all js files
echo " Copying GDJS and extensions runtime files (*.js) to '$DESTINATION'..."
mkdir -p "$DESTINATION"
cp -R ../Runtime/* "$DESTINATION"
rsync -r -u --include=*.js --include=*/ --exclude=* ../../Extensions/ "$DESTINATION"/Extensions/
echo "✅ Copied GDJS and extensions runtime files (*.js) to '$DESTINATION'."

View File

@@ -1,3 +1 @@
gdjs.registerObjects();
gdjs.registerBehaviors();
gdjs.registerGlobalCallbacks();

View File

@@ -11,7 +11,7 @@ gdjs.TestRuntimeBehavior = function(runtimeScene, behaviorData, owner)
};
gdjs.TestRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.TestRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "TestBehavior::TestBehavior";
gdjs.registerBehavior("TestBehavior::TestBehavior", gdjs.TestRuntimeBehavior);
gdjs.TestRuntimeBehavior.prototype.onCreated = function() {
this.owner.getVariables().get("lastState").setString('created');

View File

@@ -3,7 +3,7 @@
* an example to start a new object, take a look at gdjs.DummyRuntimeObject
* in the Extensions folder.
*
* @memberof gdjs
* @memberOf gdjs
* @class TestRuntimeObject
* @extends RuntimeObject
*/
@@ -16,8 +16,7 @@ gdjs.TestRuntimeObject = function(runtimeScene, objectData) {
};
gdjs.TestRuntimeObject.prototype = Object.create(gdjs.RuntimeObject.prototype);
gdjs.TestRuntimeObject.thisIsARuntimeObjectConstructor =
'TestObject::TestObject';
gdjs.registerObject('TestObject::TestObject', gdjs.TestRuntimeObject);
gdjs.TestRuntimeObject.prototype.getRendererObject = function() {
return {};

View File

@@ -65,7 +65,7 @@ bool BehaviorJsImplementation::UpdateProperty(gd::SerializerElement& behaviorCon
throw 'updateProperty is not defined on a BehaviorJsImplementation.';
self['updateProperty'](
wrapPointer($1, Module['SerializerElement']), Pointer_stringify($2), Pointer_stringify($3));
wrapPointer($1, Module['SerializerElement']), UTF8ToString($2), UTF8ToString($3));
},
(int)this,
(int)&behaviorContent,

View File

@@ -73,8 +73,8 @@ bool BehaviorSharedDataJsImplementation::UpdateProperty(
throw 'updateProperty is not defined on a BehaviorSharedDataJsImplementation.';
self['updateProperty'](wrapPointer($1, Module['SerializerElement']),
Pointer_stringify($2),
Pointer_stringify($3));
UTF8ToString($2),
UTF8ToString($3));
},
(int)this,
(int)&behaviorSharedDataContent,

View File

@@ -184,7 +184,7 @@ interface VariablesContainer {
[Ref] Variable Get([Const] DOMString name);
[Ref] Variable GetAt(unsigned long index);
[Const, Ref] DOMString GetNameAt(unsigned long index);
[Ref] Variable Insert([Const] DOMString name, [Const, Ref] Variable var, unsigned long index);
[Ref] Variable Insert([Const] DOMString name, [Const, Ref] Variable variable, unsigned long index);
[Ref] Variable InsertNew([Const] DOMString name, unsigned long index);
void Remove([Const] DOMString name);
boolean Rename([Const] DOMString oldName, [Const] DOMString newName);
@@ -1053,6 +1053,7 @@ interface ObjectMetadata {
[Const, Ref] DOMString GetFullName();
[Const, Ref] DOMString GetDescription();
[Const, Ref] DOMString GetIconFilename();
[Const, Ref] DOMString GetHelpPath();
[Const, Ref] InstructionMetadata AddCondition([Const] DOMString name,
[Const] DOMString fullname,
@@ -1093,6 +1094,7 @@ interface BehaviorMetadata {
[Const, Ref] DOMString GetDescription();
[Const, Ref] DOMString GetGroup();
[Const, Ref] DOMString GetIconFilename();
[Const, Ref] DOMString GetHelpPath();
[Const, Ref] InstructionMetadata AddScopedCondition([Const] DOMString name,
[Const] DOMString fullname,
@@ -1270,6 +1272,7 @@ interface EventsList {
void RemoveEvent([Const, Ref] BaseEvent event);
unsigned long GetEventsCount();
boolean Contains([Const, Ref] BaseEvent event, boolean recursive);
boolean MoveEventToAnotherEventsList([Const, Ref] BaseEvent eventToMove, [Ref] EventsList newEventsList, unsigned long newPosition);
boolean IsEmpty();
void Clear();
@@ -1526,7 +1529,7 @@ interface EventsRefactorer {
void STATIC_RenameObjectInEvents([Const, Ref] Platform platform, [Ref] ObjectsContainer project, [Ref] ObjectsContainer layout, [Ref] EventsList events, [Const] DOMString oldName, [Const] DOMString newName);
void STATIC_RemoveObjectInEvents([Const, Ref] Platform platform, [Ref] ObjectsContainer project, [Ref] ObjectsContainer layout, [Ref] EventsList events, [Const] DOMString name);
void STATIC_ReplaceStringInEvents([Ref] ObjectsContainer project, [Ref] ObjectsContainer layout, [Ref] EventsList events, [Const] DOMString toReplace, [Const] DOMString newString, boolean matchCase, boolean inConditions, boolean inActions);
[Value] VectorEventsSearchResult STATIC_SearchInEvents([Ref] ObjectsContainer project, [Ref] ObjectsContainer layout, [Ref] EventsList events, [Const] DOMString search, boolean matchCase, boolean inConditions, boolean inActions);
[Value] VectorEventsSearchResult STATIC_SearchInEvents([Ref] ObjectsContainer project, [Ref] ObjectsContainer layout, [Ref] EventsList events, [Const] DOMString search, boolean matchCase, boolean inConditions, boolean inActions, boolean inEventStrings);
};
interface WholeProjectRefactorer {
@@ -1644,29 +1647,6 @@ interface MetadataProvider {
boolean STATIC_HasBehaviorStrExpression([Const, Ref] Platform p, [Const] DOMString autoType, [Const] DOMString type);
};
interface ParserCallbacks {
[Const, Ref] DOMString GetFirstError();
unsigned long GetFirstErrorPosition();
};
interface ExpressionParser {
void ExpressionParser([Const] DOMString expression);
boolean ParseMathExpression([Const, Ref] Platform platform, [Const, Ref] Project project, [Const, Ref] Layout layout, [Ref] ParserCallbacks callbacks);
boolean ParseStringExpression([Const, Ref] Platform platform, [Const, Ref] Project project, [Const, Ref] Layout layout, [Ref] ParserCallbacks callbacks);
[Const, Ref] DOMString GetFirstError();
unsigned long GetFirstErrorPosition();
};
interface CallbacksForExpressionCorrectnessTesting {
void CallbacksForExpressionCorrectnessTesting([Const, Ref] Project project, [Const, Ref] Layout layout);
//Inherited from ParserCallbacks:
[Const, Ref] DOMString GetFirstError();
unsigned long GetFirstErrorPosition();
};
interface ExpressionParserDiagnostic {
boolean IsError();
[Const, Ref] DOMString GetMessage();
@@ -1704,11 +1684,6 @@ interface ExpressionParser2 {
[Value] UniquePtrExpressionNode ParseExpression([Const] DOMString type, [Const] DOMString expression);
};
interface ExpressionCodeGenerator {
void STATIC_UseOldExpressionParser(boolean enable);
boolean STATIC_IsUsingOldExpressionParser();
};
enum EventsFunction_FunctionType {
"EventsFunction::Action",
"EventsFunction::Condition",
@@ -1807,7 +1782,7 @@ interface NamedPropertyDescriptorsList {
interface EventsFunctionsExtension {
void EventsFunctionsExtension();
[Ref] EventsFunctionsExtension SetNamespace([Const] DOMString namespace);
[Ref] EventsFunctionsExtension SetNamespace([Const] DOMString namespace_);
[Const, Ref] DOMString GetNamespace();
[Ref] EventsFunctionsExtension SetVersion([Const] DOMString version);
[Const, Ref] DOMString GetVersion();

View File

@@ -42,7 +42,7 @@ ObjectJsImplementation::GetProperties(gd::Project&) const {
if (!self.hasOwnProperty('getProperties'))
throw 'getProperties is not defined on a ObjectJsImplementation.';
var objectContent = JSON.parse(Pointer_stringify($1));
var objectContent = JSON.parse(UTF8ToString($1));
var newProperties = self['getProperties'](objectContent);
if (!newProperties)
throw 'getProperties returned nothing in a gd::ObjectJsImplementation.';
@@ -64,9 +64,9 @@ bool ObjectJsImplementation::UpdateProperty(const gd::String& arg0,
var self = Module['getCache'](Module['ObjectJsImplementation'])[$0];
if (!self.hasOwnProperty('updateProperty'))
throw 'updateProperty is not defined on a ObjectJsImplementation.';
var objectContent = JSON.parse(Pointer_stringify($1));
var objectContent = JSON.parse(UTF8ToString($1));
self['updateProperty'](
objectContent, Pointer_stringify($2), Pointer_stringify($3));
objectContent, UTF8ToString($2), UTF8ToString($3));
return ensureString(JSON.stringify(objectContent));
},
(int)this,
@@ -91,7 +91,7 @@ ObjectJsImplementation::GetInitialInstanceProperties(
if (!self.hasOwnProperty('getInitialInstanceProperties'))
throw 'getInitialInstanceProperties is not defined on a ObjectJsImplementation.';
var objectContent = JSON.parse(Pointer_stringify($1));
var objectContent = JSON.parse(UTF8ToString($1));
var newProperties = self['getInitialInstanceProperties'](
objectContent,
wrapPointer($2, Module['InitialInstance']),
@@ -124,12 +124,12 @@ bool ObjectJsImplementation::UpdateInitialInstanceProperty(
var self = Module['getCache'](Module['ObjectJsImplementation'])[$0];
if (!self.hasOwnProperty('updateInitialInstanceProperty'))
throw 'updateInitialInstanceProperty is not defined on a ObjectJsImplementation.';
var objectContent = JSON.parse(Pointer_stringify($1));
var objectContent = JSON.parse(UTF8ToString($1));
return self['updateInitialInstanceProperty'](
objectContent,
wrapPointer($2, Module['InitialInstance']),
Pointer_stringify($3),
Pointer_stringify($4),
UTF8ToString($3),
UTF8ToString($4),
wrapPointer($5, Module['Project']),
wrapPointer($6, Module['Layout']));
},

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