Compare commits

..

7 Commits

Author SHA1 Message Date
Florian Rival
a97948cdf3 Add logging for startup times 2019-10-01 11:34:51 +01:00
Florian Rival
0a86424f15 Rename TemporaryInstances to InstancesAdder and use it in SceneEditor
There is a unique place where the logic to create instances is now.
2019-10-01 00:14:54 +01:00
Florian Rival
95930c5bfd Refactor drag'n'drop in SortableVirtualizedItemListi and objects drag to scene
* Use a drop indicator and remove react-sortable-hoc
* Drag to scene can now follow the cursor with a temporary instance, to get an immediate feedback/preview of the object

TODO: Refactor the instance creation to use TemporaryInstances
2019-09-30 23:23:43 +01:00
Florian Rival
fac1246445 Refactor InstructionsList to use DropTarget 2019-09-29 16:50:40 +01:00
Florian Rival
9772520d24 Move Utils/DragDropHelpers into UI/DragAndDrop 2019-09-29 16:29:20 +01:00
Florian Rival
86eef2dab4 Refactor Instruction to use DragSourceAndDropTarget
* Fix error "Expected to find a valid target" when dragging instructions on top of a subinstructions list (react-dnd does not support well having a drop target/source inside another in these conditions it seems)
2019-09-29 16:14:46 +01:00
Florian Rival
809c04f88e Use SortableVirtualizedItemList for ObjectsList implementation 2019-09-29 14:21:44 +01:00
1532 changed files with 61248 additions and 152444 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 1.39.6 && ./emsdk activate 1.39.6 && cd ..
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install sdk-1.37.37-64bit && ./emsdk activate sdk-1.37.37-64bit && cd ..
- run:
name: Install Wine for Electron builder
@@ -60,7 +60,7 @@ jobs:
# Build GDevelop IDE
- run:
name: Build GDevelop IDE
command: cd newIDE/electron-app && npm run build -- --mac zip --win --linux tar.gz --publish=never
command: cd newIDE/electron-app && npm run build -- --mac --win --linux tar.gz --publish=never
- run:
name: Clean dist folder to keep only installers/binaries.

8
.gitignore vendored
View File

@@ -1,5 +1,8 @@
/Core/GDCore/Tools/VersionPriv.h
/docs
/docs/GDJS Runtime Documentation
/docs/GDJS Documentation
/docs/GDCpp Documentation
/docs/GDCore Documentation
/ExtLibs/SFML
/ExtLibs/*.7z
/scripts/logs/*.txt
@@ -44,6 +47,9 @@
/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/embuild/GDevelop.js
- Binaries/Output/libGD.js/Release
apt:
sources:
- ubuntu-toolchain-r-test
@@ -48,7 +48,7 @@ before_install:
#use SFML.
- "export DISPLAY=:99.0"
# This workaround is required to avoid libstdc++ errors (Emscripten requires a recent version of libstdc++)
- wget -q -O libstdc++6 http://security.ubuntu.com/ubuntu/pool/main/g/gcc-5/libstdc++6_5.4.0-6ubuntu1~16.04.12_amd64.deb
- wget -q -O libstdc++6 http://security.ubuntu.com/ubuntu/pool/main/g/gcc-5/libstdc++6_5.4.0-6ubuntu1~16.04.10_amd64.deb
- sudo dpkg --force-all -i libstdc++6
install:
@@ -63,8 +63,8 @@ install:
# Install Emscripten (for GDevelop.js)
- git clone https://github.com/juj/emsdk.git
- cd emsdk
- ./emsdk install 1.39.6
- ./emsdk activate 1.39.6
- ./emsdk install sdk-1.37.37-64bit
- ./emsdk activate sdk-1.37.37-64bit
- source ./emsdk_env.sh
- cd ..
# Install GDevelop.js dependencies and compile it

View File

@@ -2,7 +2,6 @@
{
"files.associations": {
"*.idl": "java",
"Fastfile": "ruby",
"iosfwd": "cpp",
"functional": "cpp",
"type_traits": "cpp",
@@ -81,10 +80,7 @@
"__hash": "cpp",
"__debug": "cpp",
"__threading_support": "cpp",
"any": "cpp",
"array": "cpp",
"cinttypes": "cpp",
"numeric": "cpp"
"any": "cpp"
},
"files.exclude": {
"Binaries/*build*": true,

View File

@@ -51,12 +51,7 @@ 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}")
IF(EMSCRIPTEN)
# Emscripten treats all libraries as static libraries
add_library(GDCore STATIC ${source_files})
ELSE()
add_library(GDCore SHARED ${source_files})
ENDIF()
add_library(GDCore SHARED ${source_files})
add_dependencies(GDCore GDVersion)
IF(EMSCRIPTEN)
set_target_properties(GDCore PROPERTIES SUFFIX ".bc")

View File

@@ -1,25 +1,592 @@
/**
* \mainpage GDevelop Core
* \image html gdlogo.png
* \section welcome GDevelop Core documentation
* \section welcome Welcome
*
* The **GDevelop Core** library contains the structure of a GDevelop game, classes and tools that are used by the *platforms* and the *GDevelop IDE*.
* The **GDevelop Core** library contains the main concepts, classes and tools that are used by the *platforms* and the *GDevelop IDE*.<br>
* This ensures that the IDE, or any tool based on GDevelop Core, is able to work with projects based on any arbitrary platform.
*
* Two official platforms are available for GDevelop:
* - The *C++ Platform* (GDCpp) to create native games.
* - The *JS Platform* (GDJS) to create HTML5 games.
*
* \section gettingstarted Getting started
* First, please refer to these pages to install the required tools and to get help about setting up a basic extension:<br>
*
* In most cases, you should start by <a href="https://github.com/4ian/GDevelop/blob/master/newIDE/README.md">installing and launching the development version of GDevelop</a>.
* -# \subpage setupDevEnv
* -# \ref overview
* -# \ref writeANewExtension
*
* - If you're interested in writing extensions for GDevelop, read <a href="https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md">the documentation about extensions</a>.
* - If you want to dig more into how GDevelop is architectured and work on the core, read <a href="https://github.com/4ian/GDevelop/blob/master/Core/GDevelop-Architecture-Overview.md">GDevelop Architecture Overview</a>. Then, you can browse this reference to get more information about a class or function.
* You can also read \subpage recommendedToolsAndConventions.
*
* \section other Other documentations
* \section aboutdoc About this documentation
*
* GDevelop is architectured around a `Core` (this library), platforms (`GDJS`, `GDCpp`) and extensions (`Extensions` folder). The editor (`newIDE` folder) is using all of these libraries.
* If you never used GDevelop Core before, take a look at \ref overview.
*
* As everything that is developed around GDevelop is based on this library, you should take a look at it quite often: platforms, extensions
* and the IDE are intensively using the classes and tools offered by GDCore.
* When developing an extension for the C++ or JS platform, read these documentations:
*
* - [Open GDevelop C++ Platform documentation](../GDCpp Documentation/index.html)
* - [Open GDevelop JS Platform documentation](../GDJS Documentation/index.html)
* - <a href="https://github.com/4ian/GDevelop/blob/master/newIDE/README.md">Getting started with the editor</a>
* - <a href="https://github.com/4ian/GDevelop/blob/master/newIDE/README-extensions.md">Getting started with the extensions</a>
*
*/
/**
* \page setupDevEnv Setting up the development environment
*
* If you didn't already downloaded GDevelop, get and extract the source from [GitHub](https://github.com/4ian/GD).
*
* Follow these steps to be able to compile GDevelop, it's super easy:
*
* <b>Windows</b>
*
* -# \subpage installWinCompiler
* -# \ref installAndUseCMake
* <br>
*
* <b>GNU/Linux</b>
* -# \subpage installLinuxLib
* -# \subpage installAndUseCMake
*
* <b>OS X</b>
* -# \subpage installMacOSTools
* -# \ref installAndUseCMake
*
* See the recommended tools and conventions for working on GDevelop on this page:
* \subpage recommendedToolsAndConventions
*/
/**
* \page installWinCompiler (Windows) Install TDM-GCC compiler
*
* GDevelop is compiled with TDM-GCC under Windows.<br>
* So as to prevent incompatibilities between the compiler (and the standard C++ library provided with) used by GDevelop and
* the compiler used by the extensions, GDevelop require the extensions and the platforms to use the same version of TDM-GCC.
*
* While a recent GCC version should work, if you compile GDevelop for an "official" distribution it's better
* to use the specific version provided here.
*
* \section installWinCompiler_download Download
*
* Download the current version of the compiler used by GDevelop on Windows here:
*
* https://sourceforge.net/projects/tdm-gcc/files/TDM-GCC%20Installer/Previous/1.1309.0/tdm-gcc-4.9.2.exe/download
*
* \section installWinCompiler_install Installation
*
* The installation is fairly simple :<br>
* <br>
* - Launch the installer.<br>
* - Choose Create.<br>
\image html compilerInstall1.png
* - Choose an installation directory.<br>
\image html compilerInstall2.png
* - Choose the components to be installed. You don't have to change anything, the default options are good enough.<br>
\image html compilerInstall3.png
* - Click on install so as to launch the installation process.<br>
*/
/**
* \page installAndUseCMake (All) Install CMake & launch the build
*
* Building is done using CMake: it is an open-source build system that can generate build files for lots of IDE and build tools (Makefiles...).
*
* \section installAndUseCMake_download Download and install CMake
*
* First, install CMake:
* Download it [here](http://www.cmake.org/cmake/resources/software.html) for Windows, get it using your package manager if you're
* using a Linux distribution or using Homebrew for Mac OS X.
*
* \section installAndUseCMake_use Using CMake to generate the build files
* Using CMake is not difficult and require only a few clicks/commands to enter. Windows users may use
* the GUI as shown in the next section. Linux and Mac OS X users may prefer to use the command line as shown
* as the end of this page.
*
* \subsection installAndUseCMake_use_gui Using the GUI
*
* - Start the CMake user interface (_cmake-gui_). Choose the GD root directory as the source directory, and Binaries/build as the directory where to build the binaries:
\image html usecmake1.png
* - Click on *Configure*. If asked to create the build directory, answer yes. Choose then your favorite generator: *MinGW Makefiles* (on Windows) or *Unix Makefiles* (on Linux/OS X) generate a traditional Makefile that can be built using the
* *mingw32-make* (on Windows) or *make* (on Linux/OS X) command. You can also choose the *Ninja* generator to use the [Ninja build system](http://martine.github.io/ninja/).
\image html usecmake2.png
* - When you click on Finish, CMake do a first configuration. If **errors occurred*, make sure that you have download all required development libraries.
* - Adjust any variable if necessary (no changes is needed by default), then click on Generate.
\image html usecmake3.png
* - You can then launch a terminal/command prompt, go to the build folder (`cd path/to/GD/Binaries/build`) and launch the build
* using the generator you've choosen: `mingw32-make`, or `make` on Linux/OS X.
*
* \subsection installAndUseCMake_use_cmd Using the command line
*
* Using the commandline with CMake is also easy:
*
* ~~~~~~~~~~~~~~~~~~~~~
* cd /path/to/GD/Binaries
* mkdir build
* cd build
* cmake ../..
* make
* ~~~~~~~~~~~~~~~~~~~~~
*
* For Windows, replace `cmake ../..` by `cmake ../.. -G "MinGW Makefiles"` and `make` by `mingw32-make`.
*
* or using the fast [Ninja build system](http://martine.github.io/ninja/) :
* ~~~~~~~~~~~~~~~~~~~~~
* cd /path/to/GD/Binaries
* mkdir build
* cd build
* cmake ../.. -G "Ninja"
* ninja
* ~~~~~~~~~~~~~~~~~~~~~
*
* \section installAndUseCMake_launch Launch GDevelop
*
* Binaries are created into *Binaries/Output/Release_{OS}* folder.
*
* To launch GDevelop in Windows, double click on **GDIDE**. For Linux, launch **StartGDevelop.sh**.
*/
/**
* \page installLinuxLib (Linux) Install development files
*
* \section installLibs Install development libraries
*
* GDevelop is compiled with gcc under Linux.<br>
* You need to have some packages to be installed before starting to build GD. These packages can vary according to the distribution you use.
* On Ubuntu, you may want to install these packages:
\code
sudo apt-get install libopenal-dev
sudo apt-get install libjpeg-dev
sudo apt-get install libglew-dev
sudo apt-get install libudev-dev
sudo apt-get install libxrandr-dev
sudo apt-get install libsndfile1-dev
sudo apt-get install libglu1-mesa-dev
sudo apt-get install libfreetype6-dev
\endcode
* Make sure you also have some basic tools installed:
\code
sudo apt-get install build-essential
sudo apt-get install p7zip-full
sudo apt-get install curl
\endcode
*
* If you want to package the app, you can also install:
\code
sudo apt-get install devscripts
\endcode
*
*
* \subsection installcmake Install CMake
* You'll need CMake to build GDevelop: See more on \subpage installAndUseCMake.
*/
/**
* \page installMacOSTools (Mac OS X) Install development tools
*
* Make sure that you have Apple Developer Tools installed (if you have Xcode and git, that should be the case).
*
* \section installTools Install development tools
*
* The simplest way of installing dependencies required by GDevelop is to use [Homebrew](http://brew.sh/). Install it
* and install these packages, using the terminal:
\code
brew install cmake
brew install p7zip
brew install pkgconfig
brew install freetype
\endcode
* If you want to generate the documentation and translations, install Doxygen and Gettext:
\code
brew install doxygen
brew install gettext
\endcode
*
* \section launchCompilation Launch compilation
*
* You should be able to compile GD using CMake. Go with a terminal to the GD source folder:
\code
cd /path/to/GD
mkdir build && cd build
cmake ../..
make -j4
\endcode
*
* More information about compilation here: \ref installAndUseCMake
*/
/**
* \page recommendedToolsAndConventions Recommended tools and advices to work with GD
*
* \section git Git and GitHub
*
* Git is an amazing *version control system*. If you never used it before, take a look at some tutorials, there
* are plenty of them on the internet.<br>
* Windows users could be interested in using [TortoiseGit](code.google.com/p/tortoisegit) or the official
* [GitHub client](https://windows.github.com/).
*
* \subsection pullrequest Submitting code thanks to Pull Request.
*
* Using *Pull request*, you can easily submit your changes so that they are integrated into the official
* GDevelop repository (http://github.com/4ian/gd).
*
* See this article on *GitHub help* about pull requests: https://help.github.com/articles/using-pull-requests.<br>
* Pull requests are extremely easy to use and the best way to contribute to GD!
*
* ------
*
* \section codingstyle Coding style
*
* As a rule of thumb, try to retain the original coding style used in a file when editing it, or look at other
* files when creating a new extension/dialog/feature/class.
*
* For both C++ and Javascript, *code indentation* should be 4 spaces (or tab set to a width of 4 spaces).<br>
* Lines should be cutted when reaching column 110 so that two files can be displayed side-by-side on a same screen.
* When cutting a line, indent the new lines with an additional 4 spaces.
*
* \subsection cpp C++
*
* *Naming* conventions:
* - Classes should be *CamelCase* (starting with a capital).
* - All variables (including member variables) should be *camelCase* (no capital for the first letter).
* - All functions (including class methods) should be *CamelCase* (starting with a capital).
*
* *Comments*:
* - Comment your classes and functions using *Doxygen* comments.
*
* \subsection js Javascript
*
* *Naming* conventions:
* - "Classes" should be *CamelCase* (starting with a capital).
* - All variables (including member variables) should be *camelCase* (no capital for the first letter).
* - All functions (including class methods) should be *camelCase* (no capital for the first letter).
*
* *Comments*:
* - Comment your classes and functions using *yuidoc* comments.
*/
/**
* \page overview Overview of GDCore
*
* \section platformstructure Structure of a platform
*
* A platform for GDevelop Core is a class inheriting from gd::Platform.<br>
* They contains the extensions of the platform (see below) and offer various methods, like gd::Platform::GetProjectExporters which
* is called by the IDE to export a gd::Project to a stand-alone game.
*
* \subsection platformloading Platforms loading
* A platform is stored in memory and managed by gd::PlatformManager. It loaded from a dynamic library file (.dll on windows, .so on Linux)
* thanks to gd::PlatformLoader.<br>
* It is responsibility of the IDE, or any other application using GDCore,
* to call the appropriate method of gd::PlatformLoader to trigger the loading of the platforms when needed.
*
* gd::PlatformLoader search for two symbols in the dynamic library file: *CreateGDPlatform* and
* *DestroyGDPlatform*. These symbols must exists and must create (or destroy) the platform class. For example:
*
* ~~~~~~~~~~~~~~~~~~~~~
* extern "C" gd::Platform * GD_API CreateGDPlatform() {
* return &JsPlatform::Get(); //Return the singleton object representing the JS Platform
* }
*
* extern "C" void GD_API DestroyGDPlatform() {
* JsPlatform::DestroySingleton(); //Destroy the singleton.
* }
* ~~~~~~~~~~~~~~~~~~~~~
*
* The platform dynamic library file is often located inside <i>GDevelop directory</i>/xxxPlatform (*xxx* being replaced by the platform acronym).
*
* In this folder, the platform can store basically anything it needs. For example, both GDJS and GDCpp are storing a folder called *Runtime* containing
* the game engine.
* If there is a sub directory called *Extensions*, the gd::PlatformLoader tries to load the extensions contained inside (see below).
*
* \section extensionsstructure Structure of an extension
*
* **Extensions** are seen by GDevelop Core as classes inheriting from gd::PlatformExtension.<br>
* They are stored inside the platform they belong to, and they are also loaded from a dynamic library file thanks to gd::ExtensionsLoader. The main
* job of an extension is to <b>declare</b> everything it provides: objects, actions and conditions, behaviors, expressions.<br>
* This is done directly using the standard method provided by gd::PlatformExtension, notably:
* - gd::PlatformExtension::AddCondition and gd::PlatformExtension::AddAction,
* - gd::PlatformExtension::AddExpression (and gd::PlatformExtension::AddStrExpression),
* - gd::PlatformExtension::AddObject and gd::PlatformExtension::AddBehavior
*
*
* Some platforms (like the C++ Platform) offer another base class which must be used instead of gd::PlatformExtension when declaring a platorm: as this base class
* inherits from gd::PlatformExtension, standard methods still work, but you may be able to declare some others features (the C++ Platform offers
* the possibility of declaring debugger related functions).
*
* \subsection extensionloading Extensions loading
*
* A single dynamic library file can contains an extension for more than one platform:<br>
* You just have to declare a class deriving from gd::PlatformExtension for each platform supported, and a creation function for each platform
* (the C++ platform expects a function called *CreateGDExtension* while JS Platform search for a function called *CreateGDJSExtension*).
*
* \subsection extensionexample Edit or write a new extension
*
* Refer to these pages for more information about extensions:
* - \subpage AboutExtensionCpp
* - \subpage writeANewExtension
*
* \section utf8section UTF8 strings
*
* Most parts of the codebase support UTF8 strings thanks to gd::String class. gd::String is a wrapper around std::string, exposing a similar
* interface as well as a few tool member functions and operators that are all UTF8 aware.
*
* Its usage is easy, especially if you're familiar with std::string. Some extra functions can be really useful, in particular
* the ones to convert the string from/to a number.
*
\code
gd::String str = "Hello";
str += " world";
str += " " + gd::String::From(2);
//str now contains "Hello world 2";
gd::String twopointfiveStr = "2.5";
double twopointfive = twopointfive.To<double>();
//twopointfive == 2.5
\endcode
*
*
* For more information, see the complete reference of the class. Tests cases have also been made for most functions.
*/
/**
* \page writeANewExtension Write a new extension
*
* \section writeANewExtension_createNewExtension Create a new extension
*
* Creation of a new extension can be made by following these steps:<br>
*
* - Copy the directory of an extension and rename it:
* \image html createnew1.png
* - Rename then the sources files :
* \image html createnew2.png
* - Open the *CMakeLists.txt* file and replace every occurrence of the extension old name with the new name.<br>
* - Open all the source files and again, replace every occurrence of the extension old name with the new name.<br>
* - In the *Extensions* directory, open the *CMakeLists.txt* file and add a line such as <code>ADD_SUBDIRECTORY(MyExtension)</code>.
* You can then start to modify the extension.<br>
* If your extension is fairly simple, you can create it from the AES Extension. <br>
* If your extension need an object, you can use for instance the TextObject Extension as a starting point.<br>
* <br>
* - You can compile your extension by relaunching CMake like described [here](\ref installAndUseCMake). After doing that, just compile as usual.
*
*/
/**
* \page AboutExtensionCpp About Extension.cpp
*
* An extension has to define (usually in a file called *Extension.cpp* for the C++ Platform or *JsExtension.cpp* for the JS Platform)
* a class that is derived from the gd::PlatformExtension class. This class contains, in its constructor, the declarations
* of everything that is provided by the extension.
* \section extensionDeclaration Declare the extension information
* The declarations are made using the methods provided by gd::PlatformExtension.
*
* The first declaration if often the information about the extension:
* \code
Extension()
{
SetExtensionInformation("TextObject",
_("Text object"),
_("Extension allowing to use an object displaying a text."),
"Florian Rival",
"Open Source (MIT License)");
* \endcode
The first parameter is the name of the extension. Choose carefully the name of the extension, as projects are directly referring to it.
* \section instructionsDeclaration Declare actions, conditions and expressions
Actions are declared like this :
* \code
AddAction("ActionName",
_("Name displayed to users"),
_("Description"),
_("Sentence displayed in event editor"),
_("Category"),
"path-to-an-24-by-24-icon-file.png",
"path-to-an-16-by-16-icon-file.png")
.AddParameter("theTypeOfTheParameter", _("Parameter1"))
.AddParameter("theTypeOfTheParameter", _("Parameter2"))
.SetFunctionName("MyFunctionName").SetIncludeFile("MyExtension/MyIncludeFile.h");
* \endcode
* Declare conditions and expressions in a similar way.<br>
* Parameters are added using gd::InstructionMetadata::AddParameter.
*
* The last line set the function name that will be called when generating the code of an event using the action:<br>
* You can either do it after declaring the function, or later using this syntax:
*
* \code
GetAllActions()["ExtensionName::ActionName"].SetFunctionName("MyFunctionName");
* \endcode
*
* Both methods are ok, but the latest allows to use the same code to declare an extension for the C++ and JS platform,
* then customize the names of the functions to call.
*
* \section objectsDeclaration Declare objects
*
* Adding an object is made using gd::PlatformExtension::AddObject method.
*
* \code
gd::ObjectMetadata & obj = AddObject<MyObject>(
"Name",
_("Name displayed to users"),
_("Description"),
"path-to-a-32-by-32-icon.png");
* \endcode
*
* The *C++ platform* also requires that you call *AddRuntimeObject* to declare the RuntimeObject class associated to the object being declared:<br>
* It has two template parameters: the first one is the corresponding object class declared with *AddObject* (class inheriting from *gd::Object*) and the
* second one is the *RuntimeObject* class.
* You must pass as parameter the metadata from the object previously declared and the name of the class inheriting from RuntimeObject.
*
* You will also want to specify the .h file associated to the object using gd::ObjectMetadata::SetIncludeFile. For example:
* \code
//obj is the gd::ObjectMetadata returned when you called AddObject.
AddRuntimeObject<TextObject, RuntimeTextObject>(obj, "RuntimeTextObject");
obj.SetIncludeFile("TextObject/TextObject.h");
* \endcode
*
* You can then declare the actions, conditions, and expressions related to the objects, using the AddAction/AddCondition/AddExpression methods provided
* by <i>obj</i>.
* \section eventsDeclaration Declaring events
*
* Events are declared like this :
* \code
AddEvent("Name",
_("Name displayed to users"),
"Description",
"Group",
"path-to-a-16-by-16-icon.png",
std::make_shared<EventClassName>())
* \endcode
*
* The event must be able to generate its code when events are being translated to C++ or Javascript:<br>
* This is done by calling SetCodeGenerator. For example:
*
* \code
AddEvent("Standard",
_("Standard event"),
_("Standard event: Actions are run if conditions are fulfilled."),
"",
"res/eventaddicon.png",
std::make_shared<gd::StandardEvent>())
.SetCodeGenerator(std::shared_ptr<gd::EventMetadata::CodeGenerator>(codeGen));
* \endcode
* \section behaviorsDeclaration Declaring the behaviors
Behaviors are declared like objects:
* \code
gd::BehaviorMetadata & aut = AddBehavior("Name",
_("Name displayed to users"),
_("DefaultNameUsedInEditor"),
_("Description."),
"Group",
"path-to-a-32-by-32-icon.png",
"BehaviorClassName",
std::make_shared<BehaviorClassName>(),
std::make_shared<BehaviorSharedDataClassName>());
* \endcode
* The last line can be replaced by <code>std::shared_ptr<gd::BehaviorsSharedData>()</code> if no shared data are being used.
*
* You can then declare the actions, conditions, and expressions related to the behavior like objects:<br>
* Call AddAction/AddCondition/AddExpression on the <i>aut</i> object.
* \section excludingNonRuntimeDeclaration (C++ platform) Excluding elements declaration from runtime
* When your extension is compiled for the C++ platform Runtime, GDevelop does not known anything about action/condition or even events classes.<br>
* You have then to exclude all actions/conditions/expressions/events declaration from extension at runtime (only Extension/Object/Behaviors declarations have to be kept).
* Use the *<code>GD_IDE_ONLY</code> define* to achieve this goal, as demonstrated in this skeleton of a complete extension declaration:
* \code
class Extension : public ExtensionBase //For C++ platform, extensions must derive from ExtensionBase
{
public:
Extension()
{
SetExtensionInformation("MyExtension",
_("Extension name"),
_("Extension declaration"),
"Author",
"license");
#if defined(GD_IDE_ONLY)
AddAction(...);
AddCondition(...);
AddExpression(...);
#endif
{
gd::ObjectMetadata & obj = AddObject("ObjectName",
_("Object name"),
_("Description"),
"CppPlatform/Extensions/myicon.png",
&CreateMyObject,
&DestroyMyObject);
AddRuntimeObject(obj, "RuntimeObjectName", CreateRuntimeObjectName);
#if defined(GD_IDE_ONLY)
obj.SetIncludeFile("MyExtension/MyIncludeFile.h");
obj.AddAction(...);
obj.AddCondition(...);
obj.AddExpression(...);
#endif
}
{
gd::BehaviorMetadata & aut = AddBehavior("BehaviorName",
_("Behavior name"),
"defaultGDname",
_("Description"),
"",
"CppPlatform/Extensions/myicon.png",
"PhysicsBehavior",
std::make_shared<BehaviorClassName>(),
std::make_shared<BehaviorSharedDataClassName>());
#if defined(GD_IDE_ONLY)
behaviorInfo.SetIncludeFile("MyExtension/MyIncludeFile.h");
aut.AddAction(...);
aut.AddCondition(...);
aut.AddExpression(...);
#endif
}
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
};
virtual ~Extension() {};
};
// Used by GDevelop to create the extension class
// -- Do not need to be modified. --
extern "C" ExtensionBase * GD_EXTENSION_API CreateGDExtension() {
return new Extension;
}
* \endcode
*/
/**

View File

@@ -12,15 +12,6 @@ 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,11 +7,10 @@
#define COMMENTEVENT_H
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
namespace gd {
class Layout;
class Project;
} // namespace gd
}
namespace gd {
@@ -46,8 +45,6 @@ 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,6 +5,10 @@
*/
#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"
@@ -31,17 +35,12 @@ vector<gd::InstructionsList*> ForEachEvent::GetAllActionsVectors() {
return allActions;
}
vector<pair<gd::Expression*, gd::ParameterMetadata> >
ForEachEvent::GetAllExpressionsWithMetadata() {
vector<pair<gd::Expression*, gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("object");
allExpressionsWithMetadata.push_back(
std::make_pair(&objectsToPick, metadata));
vector<gd::Expression*> ForEachEvent::GetAllExpressions() {
vector<gd::Expression*> allExpressions;
allExpressions.push_back(&objectsToPick);
return allExpressionsWithMetadata;
return allExpressions;
}
vector<const gd::InstructionsList*> ForEachEvent::GetAllConditionsVectors()
const {
vector<const gd::InstructionsList*> allConditions;
@@ -57,15 +56,11 @@ vector<const gd::InstructionsList*> ForEachEvent::GetAllActionsVectors() const {
return allActions;
}
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
ForEachEvent::GetAllExpressionsWithMetadata() const {
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("object");
allExpressionsWithMetadata.push_back(
std::make_pair(&objectsToPick, metadata));
vector<const gd::Expression*> ForEachEvent::GetAllExpressions() const {
vector<const gd::Expression*> allExpressions;
allExpressions.push_back(&objectsToPick);
return allExpressionsWithMetadata;
return allExpressions;
}
void ForEachEvent::SerializeTo(SerializerElement& element) const {

View File

@@ -50,13 +50,10 @@ class GD_CORE_API ForEachEvent : public gd::BaseEvent {
virtual std::vector<const gd::InstructionsList*> GetAllConditionsVectors()
const;
virtual std::vector<const gd::InstructionsList*> GetAllActionsVectors() const;
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() const;
virtual std::vector<const gd::Expression*> GetAllExpressions() const;
virtual std::vector<gd::InstructionsList*> GetAllConditionsVectors();
virtual std::vector<gd::InstructionsList*> GetAllActionsVectors();
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
GetAllExpressionsWithMetadata();
virtual std::vector<gd::Expression*> GetAllExpressions();
virtual void SerializeTo(SerializerElement& element) const;
virtual void UnserializeFrom(gd::Project& project,

View File

@@ -19,14 +19,6 @@ 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,8 +106,6 @@ 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,6 +5,9 @@
*/
#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"
@@ -31,15 +34,11 @@ vector<gd::InstructionsList*> RepeatEvent::GetAllActionsVectors() {
return allActions;
}
vector<pair<gd::Expression*, gd::ParameterMetadata> >
RepeatEvent::GetAllExpressionsWithMetadata() {
vector<pair<gd::Expression*, gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("expression");
allExpressionsWithMetadata.push_back(
std::make_pair(&repeatNumberExpression, metadata));
vector<gd::Expression*> RepeatEvent::GetAllExpressions() {
vector<gd::Expression*> allExpressions;
allExpressions.push_back(&repeatNumberExpression);
return allExpressionsWithMetadata;
return allExpressions;
}
vector<const gd::InstructionsList*> RepeatEvent::GetAllConditionsVectors()
@@ -57,15 +56,11 @@ vector<const gd::InstructionsList*> RepeatEvent::GetAllActionsVectors() const {
return allActions;
}
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
RepeatEvent::GetAllExpressionsWithMetadata() const {
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
allExpressionsWithMetadata;
auto metadata = gd::ParameterMetadata().SetType("expression");
allExpressionsWithMetadata.push_back(
std::make_pair(&repeatNumberExpression, metadata));
vector<const gd::Expression*> RepeatEvent::GetAllExpressions() const {
vector<const gd::Expression*> allExpressions;
allExpressions.push_back(&repeatNumberExpression);
return allExpressionsWithMetadata;
return allExpressions;
}
void RepeatEvent::SerializeTo(SerializerElement& element) const {

View File

@@ -45,14 +45,11 @@ class GD_CORE_API RepeatEvent : public gd::BaseEvent {
virtual std::vector<gd::InstructionsList*> GetAllConditionsVectors();
virtual std::vector<gd::InstructionsList*> GetAllActionsVectors();
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
GetAllExpressionsWithMetadata();
virtual std::vector<gd::Expression*> GetAllExpressions();
virtual std::vector<const gd::InstructionsList*> GetAllConditionsVectors()
const;
virtual std::vector<const gd::InstructionsList*> GetAllActionsVectors() const;
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() const;
virtual std::vector<const gd::Expression*> GetAllExpressions() const;
virtual void SerializeTo(SerializerElement& element) const;
virtual void UnserializeFrom(gd::Project& project,

View File

@@ -6,6 +6,9 @@
#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

@@ -1,58 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include <iostream>
#include "EffectsCodeGenerator.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Effect.h"
#include "GDCore/Project/Layer.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
namespace gd {
void ExposeProjectEffects(
const gd::Project& project,
const std::function<void(const gd::Effect& effect)>& worker) {
// See also gd::Project::ExposeResources for a method that traverse the whole
// project (this time for resources) and
// WholeProjectRefactorer::ExposeProjectEvents.
// Add layouts effects
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
auto& layout = project.GetLayout(s);
for (std::size_t l = 0; l < layout.GetLayersCount(); ++l) {
auto& layer = layout.GetLayer(l);
for (std::size_t e = 0; e < layer.GetEffectsCount(); ++e) {
auto& effect = layer.GetEffect(e);
worker(effect);
}
}
}
}
void EffectsCodeGenerator::GenerateEffectsIncludeFiles(
const gd::Platform& platform,
const gd::Project& project,
std::set<gd::String>& includeFiles) {
ExposeProjectEffects(
project, [&platform, &includeFiles](const gd::Effect& effect) {
// TODO: this browse all the extensions every time we're trying to find
// a new effect. Might be a good idea to rework MetadataProvider to be
// faster (not sure if it is a bottleneck at all though - but could be
// for events code generation).
const gd::EffectMetadata& effectMetadata =
MetadataProvider::GetEffectMetadata(platform,
effect.GetEffectType());
for (auto& includeFile : effectMetadata.GetIncludeFiles())
includeFiles.insert(includeFile);
});
}
} // namespace gd

View File

@@ -1,35 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EffectsCodeGenerator_H
#define GDCORE_EffectsCodeGenerator_H
#include <set>
#include <utility>
#include <vector>
#include "GDCore/String.h"
namespace gd {
class Project;
class Platform;
} // namespace gd
namespace gd {
/**
* \brief Internal class used to generate code from events
*/
class GD_CORE_API EffectsCodeGenerator {
public:
/**
* \brief Add all the include files required by the project effects.
*/
static void GenerateEffectsIncludeFiles(const gd::Platform& platform,
const gd::Project& project,
std::set<gd::String>& includeFiles);
};
} // namespace gd
#endif // GDCORE_EffectsCodeGenerator_H

View File

@@ -1,11 +1,11 @@
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include <algorithm>
#include <utility>
#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"
@@ -541,7 +541,6 @@ gd::String EventsCodeGenerator::GenerateActionCode(
if (MetadataProvider::HasBehaviorAction(
platform, behaviorType, action.GetType()) &&
instrInfos.parameters.size() >= 2) {
std::vector<gd::String> realObjects =
ExpandObjectsName(objectName, context);
for (std::size_t i = 0; i < realObjects.size(); ++i) {
@@ -631,7 +630,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
argOutput = "\"" + argOutput + "\"";
} else if (ParameterMetadata::IsBehavior(metadata.type)) {
argOutput = GenerateGetBehaviorNameCode(parameter);
argOutput = "\"" + ConvertToString(parameter) + "\"";
} else if (metadata.type == "key") {
argOutput = "\"" + ConvertToString(parameter) + "\"";
} else if (metadata.type == "password" || metadata.type == "musicfile" ||
@@ -663,7 +662,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
if (argOutput.empty()) {
if (!metadata.type.empty())
cout << "Warning: Unknown type of parameter \"" << metadata.type
<< "\"." << std::endl;
<< "\".";
argOutput += "\"" + ConvertToString(parameter) + "\"";
}
}

View File

@@ -35,6 +35,10 @@ 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,14 +24,117 @@
#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());
@@ -127,7 +230,7 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
}
}
void ExpressionCodeGenerator::OnVisitFunctionCallNode(FunctionCallNode& node) {
void ExpressionCodeGenerator::OnVisitFunctionNode(FunctionNode& node) {
if (gd::MetadataProvider::IsBadExpressionMetadata(node.expressionMetadata)) {
output += "/* Error during generation, function not found: " +
codeGenerator.ConvertToString(node.functionName) + " for type " +
@@ -359,8 +462,4 @@ void ExpressionCodeGenerator::OnVisitEmptyNode(EmptyNode& node) {
output += GenerateDefaultValue(node.type);
}
void ExpressionCodeGenerator::OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) {
output += GenerateDefaultValue(node.type);
}
} // namespace gd

View File

@@ -60,6 +60,11 @@ 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:
@@ -73,8 +78,7 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override;
void OnVisitIdentifierNode(IdentifierNode& node) override;
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override;
void OnVisitFunctionCallNode(FunctionCallNode& node) override;
void OnVisitFunctionNode(FunctionNode& node) override;
void OnVisitEmptyNode(EmptyNode& node) override;
private:
@@ -103,9 +107,11 @@ 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

@@ -0,0 +1,229 @@
/*
* 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

@@ -0,0 +1,77 @@
/*
* 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

@@ -0,0 +1,68 @@
/*
* 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

@@ -0,0 +1,97 @@
/*
* 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

@@ -12,7 +12,6 @@
#include <vector>
#include "GDCore/Events/Instruction.h"
#include "GDCore/Events/InstructionsList.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
namespace gd {
class EventsList;
@@ -91,8 +90,8 @@ class GD_CORE_API BaseEvent {
bool HasSubEvents() const;
/**
* \brief Return a list of all conditions of the event.
* \note Used to preprocess or search in the conditions.
* Event must be able to return all conditions std::vector they have.
* Used to preprocess the conditions.
*/
virtual std::vector<gd::InstructionsList*> GetAllConditionsVectors() {
std::vector<gd::InstructionsList*> noConditions;
@@ -105,8 +104,8 @@ class GD_CORE_API BaseEvent {
};
/**
* \brief Return a list of all actions of the event.
* \note Used to preprocess or search in the actions.
* Event must be able to return all actions std::vector they have.
* Used to preprocess the actions.
*/
virtual std::vector<gd::InstructionsList*> GetAllActionsVectors() {
std::vector<gd::InstructionsList*> noActions;
@@ -119,26 +118,15 @@ class GD_CORE_API BaseEvent {
};
/**
* \brief Return a list of all strings of the event.
* \note Used to preprocess or search in the event strings.
* Event must be able to return all expressions they have.
* Used to preprocess the expressions.
*/
virtual std::vector<gd::String> GetAllSearchableStrings() const {
std::vector<gd::String> noSearchableStrings;
return noSearchableStrings;
};
/**
* \brief Return a list of all expressions of the event, each with their associated metadata.
* \note Used to preprocess or search in the expressions of the event.
*/
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() {
std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> > noExpr;
virtual std::vector<gd::Expression*> GetAllExpressions() {
std::vector<gd::Expression*> noExpr;
return noExpr;
};
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() const {
std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> > noExpr;
virtual std::vector<const gd::Expression*> GetAllExpressions() const {
std::vector<const gd::Expression*> noExpr;
return noExpr;
};

View File

@@ -99,23 +99,6 @@ 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,8 +52,7 @@ 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,
@@ -143,25 +142,6 @@ 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

@@ -0,0 +1,897 @@
/*
* 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.defaultValue.empty()
? gd::Expression("0")
: gd::Expression(parametersInfo.defaultValue);
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.defaultValue.empty()
? gd::Expression("\"\"")
: gd::Expression(parametersInfo.defaultValue);
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

@@ -0,0 +1,179 @@
/*
* 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

@@ -22,6 +22,15 @@ using namespace std;
namespace gd {
gd::String ExpressionParser2::NUMBER_FIRST_CHAR = ".0123456789";
gd::String ExpressionParser2::DOT = ".";
gd::String ExpressionParser2::PARAMETERS_SEPARATOR = ",";
gd::String ExpressionParser2::QUOTE = "\"";
gd::String ExpressionParser2::BRACKETS = "()[]{}";
gd::String ExpressionParser2::EXPRESSION_OPERATORS = "+-<>?^=\\:!";
gd::String ExpressionParser2::TERM_OPERATORS = "/*";
gd::String ExpressionParser2::UNARY_OPERATORS = "+-";
gd::String ExpressionParser2::WHITESPACES = " \n\r";
gd::String ExpressionParser2::NAMESPACE_SEPARATOR = "::";
ExpressionParser2::ExpressionParser2(
@@ -67,7 +76,7 @@ size_t GetMaximumParametersNumber(
} // namespace
std::unique_ptr<ExpressionParserDiagnostic> ExpressionParser2::ValidateFunction(
const gd::FunctionCallNode& function, size_t functionStartPosition) {
const gd::FunctionNode& function, size_t functionStartPosition) {
if (gd::MetadataProvider::IsBadExpressionMetadata(
function.expressionMetadata)) {
return gd::make_unique<ExpressionParserError>(
@@ -109,13 +118,11 @@ std::unique_ptr<ExpressionParserDiagnostic> ExpressionParser2::ValidateFunction(
}
std::unique_ptr<TextNode> ExpressionParser2::ReadText() {
size_t textStartPosition = GetCurrentPosition();
SkipAllWhitespaces();
if (!CheckIfChar(IsQuote)) {
SkipWhitespace();
if (!IsAnyChar("\"")) {
auto text = gd::make_unique<TextNode>("");
text->diagnostic =
RaiseSyntaxError(_("A text must start with a double quote (\")."));
text->location = ExpressionParserLocation(textStartPosition, GetCurrentPosition());
return text;
}
SkipChar();
@@ -150,7 +157,6 @@ std::unique_ptr<TextNode> ExpressionParser2::ReadText() {
}
auto text = gd::make_unique<TextNode>(parsedText);
text->location = ExpressionParserLocation(textStartPosition, GetCurrentPosition());
if (!textParsingHasEnded) {
text->diagnostic =
RaiseSyntaxError(_("A text must end with a double quote (\"). Add a "
@@ -161,25 +167,24 @@ std::unique_ptr<TextNode> ExpressionParser2::ReadText() {
}
std::unique_ptr<NumberNode> ExpressionParser2::ReadNumber() {
size_t numberStartPosition = GetCurrentPosition();
SkipAllWhitespaces();
SkipWhitespace();
gd::String parsedNumber;
bool numberHasStarted = false;
bool digitFound = false;
bool dotFound = false;
while (!IsEndReached()) {
if (CheckIfChar(IsZeroDigit)) {
if (IsAnyChar("0")) {
numberHasStarted = true;
digitFound = true;
if (!parsedNumber.empty()) { // Ignore leading 0s.
parsedNumber += GetCurrentChar();
}
} else if (CheckIfChar(IsNonZeroDigit)) {
} else if (IsAnyChar("123456789")) {
numberHasStarted = true;
digitFound = true;
parsedNumber += GetCurrentChar();
} else if (CheckIfChar(IsDot) && !dotFound) {
} else if (IsAnyChar(".") && !dotFound) {
numberHasStarted = true;
dotFound = true;
if (parsedNumber == "") {
@@ -204,7 +209,6 @@ std::unique_ptr<NumberNode> ExpressionParser2::ReadNumber() {
// valid in most languages so we allow this.
auto number = gd::make_unique<NumberNode>(parsedNumber);
number->location = ExpressionParserLocation(numberStartPosition, GetCurrentPosition());
if (!numberHasStarted || !digitFound) {
number->diagnostic = RaiseSyntaxError(
_("A number was expected. You must enter a number here."));

View File

@@ -48,9 +48,8 @@ class GD_CORE_API ExpressionParser2 {
*
* \param type Type of the expression: "string", "number",
* type supported by gd::ParameterMetadata::IsObject, types supported by
* gd::ParameterMetadata::IsExpression or "unknown".
* \param expression The expression to parse
* \param objectName Specify the object name, only for the
* gd::ParameterMetadata::IsExpression or "unknown". \param expression The
* expression to parse \param objectName Specify the object name, only for the
* case of "objectvar" type.
*
* \return The node representing the expression as a parsed tree.
@@ -72,21 +71,18 @@ class GD_CORE_API ExpressionParser2 {
///@{
std::unique_ptr<ExpressionNode> Start(const gd::String &type,
const gd::String &objectName = "") {
size_t expressionStartPosition = GetCurrentPosition();
auto expression = Expression(type, objectName);
// Check for extra characters at the end of the expression
if (!IsEndReached()) {
auto op = gd::make_unique<OperatorNode>(type, ' ');
auto op = gd::make_unique<OperatorNode>();
op->op = ' ';
op->leftHandSide = std::move(expression);
op->rightHandSide = ReadUntilEnd("unknown");
op->rightHandSide->diagnostic = RaiseSyntaxError(
_("The expression has extra character at the end that should be "
"removed (or completed if your expression is not finished)."));
op->location = ExpressionParserLocation(expressionStartPosition,
GetCurrentPosition());
return std::move(op);
}
@@ -95,24 +91,22 @@ class GD_CORE_API ExpressionParser2 {
std::unique_ptr<ExpressionNode> Expression(
const gd::String &type, const gd::String &objectName = "") {
SkipAllWhitespaces();
SkipWhitespace();
size_t expressionStartPosition = GetCurrentPosition();
std::unique_ptr<ExpressionNode> leftHandSide = Term(type, objectName);
SkipAllWhitespaces();
SkipWhitespace();
if (IsEndReached()) return leftHandSide;
if (CheckIfChar(IsExpressionEndingChar)) return leftHandSide;
if (CheckIfChar(IsExpressionOperator)) {
auto op = gd::make_unique<OperatorNode>(type, GetCurrentChar());
if (IsAnyChar(",)]")) return leftHandSide;
if (IsAnyChar(EXPRESSION_OPERATORS)) {
auto op = gd::make_unique<OperatorNode>();
op->op = GetCurrentChar();
op->leftHandSide = std::move(leftHandSide);
op->diagnostic = ValidateOperator(type, GetCurrentChar());
SkipChar();
op->rightHandSide = Expression(type, objectName);
op->location = ExpressionParserLocation(expressionStartPosition,
GetCurrentPosition());
return std::move(op);
}
@@ -130,35 +124,31 @@ class GD_CORE_API ExpressionParser2 {
"properly written.");
}
auto op = gd::make_unique<OperatorNode>(type, ' ');
auto op = gd::make_unique<OperatorNode>();
op->op = ' ';
op->leftHandSide = std::move(leftHandSide);
op->rightHandSide = Expression(type, objectName);
op->location =
ExpressionParserLocation(expressionStartPosition, GetCurrentPosition());
return std::move(op);
}
std::unique_ptr<ExpressionNode> Term(const gd::String &type,
const gd::String &objectName) {
SkipAllWhitespaces();
SkipWhitespace();
size_t expressionStartPosition = GetCurrentPosition();
std::unique_ptr<ExpressionNode> factor = Factor(type, objectName);
SkipAllWhitespaces();
SkipWhitespace();
// This while loop is used instead of a recursion (like in Expression)
// to guarantee the proper operator precedence. (Expression could also
// be reworked to use a while loop).
while (CheckIfChar(IsTermOperator)) {
auto op = gd::make_unique<OperatorNode>(type, GetCurrentChar());
while (IsAnyChar(TERM_OPERATORS)) {
auto op = gd::make_unique<OperatorNode>();
op->op = GetCurrentChar();
op->leftHandSide = std::move(factor);
op->diagnostic = ValidateOperator(type, GetCurrentChar());
SkipChar();
op->rightHandSide = Factor(type, objectName);
op->location = ExpressionParserLocation(expressionStartPosition,
GetCurrentPosition());
SkipAllWhitespaces();
SkipWhitespace();
factor = std::move(op);
}
@@ -168,12 +158,12 @@ class GD_CORE_API ExpressionParser2 {
std::unique_ptr<ExpressionNode> Factor(const gd::String &type,
const gd::String &objectName) {
SkipAllWhitespaces();
SkipWhitespace();
size_t expressionStartPosition = GetCurrentPosition();
std::unique_ptr<ExpressionNode> factor;
if (CheckIfChar(IsQuote)) {
if (IsAnyChar(QUOTE)) {
factor = ReadText();
if (type == "number")
factor->diagnostic =
@@ -183,17 +173,14 @@ class GD_CORE_API ExpressionParser2 {
factor->diagnostic = RaiseTypeError(
_("You entered a text, but this type was expected:") + type,
expressionStartPosition);
} else if (CheckIfChar(IsUnaryOperator)) {
auto unaryOperator =
gd::make_unique<UnaryOperatorNode>(type, GetCurrentChar());
} else if (IsAnyChar(UNARY_OPERATORS)) {
auto unaryOperator = gd::make_unique<UnaryOperatorNode>(GetCurrentChar());
unaryOperator->diagnostic = ValidateUnaryOperator(type, GetCurrentChar());
SkipChar();
unaryOperator->factor = Factor(type, objectName);
unaryOperator->location = ExpressionParserLocation(
expressionStartPosition, GetCurrentPosition());
factor = std::move(unaryOperator);
} else if (CheckIfChar(IsNumberFirstChar)) {
} else if (IsAnyChar(NUMBER_FIRST_CHAR)) {
factor = ReadNumber();
if (type == "string")
factor->diagnostic = RaiseTypeError(
@@ -203,16 +190,16 @@ class GD_CORE_API ExpressionParser2 {
factor->diagnostic = RaiseTypeError(
_("You entered a number, but this type was expected:") + type,
expressionStartPosition);
} else if (CheckIfChar(IsOpeningParenthesis)) {
} else if (IsAnyChar("(")) {
SkipChar();
factor = SubExpression(type, objectName);
if (!CheckIfChar(IsClosingParenthesis)) {
if (!IsAnyChar(")")) {
factor->diagnostic =
RaiseSyntaxError(_("Missing a closing parenthesis. Add a closing "
"parenthesis for each opening parenthesis."));
}
SkipIfChar(IsClosingParenthesis);
SkipIfIsAnyChar(")");
} else if (IsIdentifierAllowedChar()) {
// This is a place where the grammar differs according to the
// type being expected.
@@ -231,132 +218,92 @@ class GD_CORE_API ExpressionParser2 {
std::unique_ptr<SubExpressionNode> SubExpression(
const gd::String &type, const gd::String &objectName) {
size_t expressionStartPosition = GetCurrentPosition();
auto subExpression =
gd::make_unique<SubExpressionNode>(type, Expression(type, objectName));
subExpression->location =
ExpressionParserLocation(expressionStartPosition, GetCurrentPosition());
return std::move(subExpression);
return std::move(
gd::make_unique<SubExpressionNode>(Expression(type, objectName)));
};
std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
Identifier(const gd::String &type) {
auto identifierAndLocation = ReadIdentifierName();
gd::String name = identifierAndLocation.name;
auto nameLocation = identifierAndLocation.location;
std::unique_ptr<IdentifierOrFunctionOrEmptyNode> Identifier(
const gd::String &type) {
size_t identifierStartPosition = GetCurrentPosition();
gd::String name = ReadIdentifierName();
SkipAllWhitespaces();
SkipWhitespace();
// We consider a namespace separator to be allowed here and be part of the
// function name (or object name, but object names are not allowed to
// contain a ":"). This is because functions from extensions have their
// extension name prefix, and separated by the namespace separator. This
// could maybe be refactored to create different nodes in the future.
if (IsNamespaceSeparator()) {
SkipNamespaceSeparator();
SkipAllWhitespaces();
auto postNamespaceIdentifierAndLocation = ReadIdentifierName();
name += NAMESPACE_SEPARATOR;
name += postNamespaceIdentifierAndLocation.name;
ExpressionParserLocation completeNameLocation(
nameLocation.GetStartPosition(),
postNamespaceIdentifierAndLocation.location.GetEndPosition());
nameLocation = completeNameLocation;
name += ReadIdentifierName();
}
if (CheckIfChar(IsOpeningParenthesis)) {
ExpressionParserLocation openingParenthesisLocation = SkipChar();
return FreeFunction(type, name, nameLocation, openingParenthesisLocation);
} else if (CheckIfChar(IsDot)) {
ExpressionParserLocation dotLocation = SkipChar();
SkipAllWhitespaces();
if (IsAnyChar("(")) {
SkipChar();
return FreeFunction(type, name, identifierStartPosition);
} else if (IsAnyChar(DOT)) {
SkipChar();
return ObjectFunctionOrBehaviorFunction(
type, name, nameLocation, dotLocation);
type, name, identifierStartPosition);
} else {
auto identifier = gd::make_unique<IdentifierNode>(name, type);
if (type == "string") {
identifier->diagnostic =
RaiseTypeError(_("You must wrap your text inside double quotes "
"(example: \"Hello world\")."),
nameLocation.GetStartPosition());
identifierStartPosition);
} else if (type == "number") {
identifier->diagnostic = RaiseTypeError(
_("You must enter a number."), nameLocation.GetStartPosition());
identifier->diagnostic = RaiseTypeError(_("You must enter a number."),
identifierStartPosition);
} else if (!gd::ParameterMetadata::IsObject(type)) {
identifier->diagnostic = RaiseTypeError(
_("You've entered a name, but this type was expected:") + type,
nameLocation.GetStartPosition());
identifierStartPosition);
}
identifier->location = ExpressionParserLocation(
nameLocation.GetStartPosition(), GetCurrentPosition());
return std::move(identifier);
}
}
std::unique_ptr<VariableNode> Variable(const gd::String &type,
const gd::String &objectName) {
auto identifierAndLocation = ReadIdentifierName();
const gd::String &name = identifierAndLocation.name;
const auto &nameLocation = identifierAndLocation.location;
size_t identifierStartPosition = GetCurrentPosition();
gd::String name = ReadIdentifierName();
auto variable = gd::make_unique<VariableNode>(type, name, objectName);
variable->child = VariableAccessorOrVariableBracketAccessor();
variable->location = ExpressionParserLocation(
nameLocation.GetStartPosition(), GetCurrentPosition());
variable->nameLocation = nameLocation;
return std::move(variable);
}
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
VariableAccessorOrVariableBracketAccessor() {
size_t childStartPosition = GetCurrentPosition();
SkipAllWhitespaces();
if (CheckIfChar(IsOpeningSquareBracket)) {
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode> child;
SkipWhitespace();
if (IsAnyChar("[")) {
SkipChar();
auto child =
child =
gd::make_unique<VariableBracketAccessorNode>(Expression("string"));
if (!CheckIfChar(IsClosingSquareBracket)) {
if (!IsAnyChar("]")) {
child->diagnostic =
RaiseSyntaxError(_("Missing a closing bracket. Add a closing "
"bracket for each opening bracket."));
}
SkipIfChar(IsClosingSquareBracket);
SkipIfIsAnyChar("]");
child->child = VariableAccessorOrVariableBracketAccessor();
child->location =
ExpressionParserLocation(childStartPosition, GetCurrentPosition());
} else if (IsAnyChar(DOT)) {
SkipChar();
SkipWhitespace();
return std::move(child);
} else if (CheckIfChar(IsDot)) {
auto dotLocation = SkipChar();
SkipAllWhitespaces();
auto identifierAndLocation = ReadIdentifierName();
auto child =
gd::make_unique<VariableAccessorNode>(identifierAndLocation.name);
child = gd::make_unique<VariableAccessorNode>(ReadIdentifierName());
child->child = VariableAccessorOrVariableBracketAccessor();
child->nameLocation = identifierAndLocation.location;
child->dotLocation = dotLocation;
child->location =
ExpressionParserLocation(childStartPosition, GetCurrentPosition());
return std::move(child);
}
return std::move(
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>());
return child;
}
std::unique_ptr<FunctionCallNode> FreeFunction(
const gd::String &type,
const gd::String &functionFullName,
const ExpressionParserLocation &identifierLocation,
const ExpressionParserLocation &openingParenthesisLocation) {
std::unique_ptr<FunctionNode> FreeFunction(const gd::String &type,
const gd::String &functionFullName,
size_t functionStartPosition) {
// TODO: error if trying to use function for type != "number" && != "string"
// + Test for it
@@ -368,49 +315,32 @@ class GD_CORE_API ExpressionParser2 {
: MetadataProvider::GetStrExpressionMetadata(
platform, functionFullName);
auto parametersNode = Parameters(metadata.parameters);
auto function = gd::make_unique<FunctionCallNode>(
type, std::move(parametersNode.parameters), metadata, functionFullName);
function->diagnostic = std::move(parametersNode.diagnostic);
auto parametersAndError = Parameters(metadata.parameters);
auto function = gd::make_unique<FunctionNode>(
type, std::move(parametersAndError.first), metadata, functionFullName);
function->diagnostic = std::move(parametersAndError.second);
if (!function->diagnostic)
function->diagnostic =
ValidateFunction(*function, identifierLocation.GetStartPosition());
function->diagnostic = ValidateFunction(*function, functionStartPosition);
function->location = ExpressionParserLocation(
identifierLocation.GetStartPosition(), GetCurrentPosition());
function->functionNameLocation = identifierLocation;
function->openingParenthesisLocation = openingParenthesisLocation;
function->closingParenthesisLocation =
parametersNode.closingParenthesisLocation;
return std::move(function);
}
std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode>
ObjectFunctionOrBehaviorFunction(
std::unique_ptr<FunctionOrEmptyNode> ObjectFunctionOrBehaviorFunction(
const gd::String &type,
const gd::String &objectName,
const ExpressionParserLocation &objectNameLocation,
const ExpressionParserLocation &objectNameDotLocation) {
auto identifierAndLocation = ReadIdentifierName();
const gd::String &objectFunctionOrBehaviorName = identifierAndLocation.name;
const auto &objectFunctionOrBehaviorNameLocation =
identifierAndLocation.location;
size_t functionStartPosition) {
gd::String objectFunctionOrBehaviorName = ReadIdentifierName();
SkipAllWhitespaces();
SkipWhitespace();
if (IsNamespaceSeparator()) {
ExpressionParserLocation namespaceSeparatorLocation =
SkipNamespaceSeparator();
SkipAllWhitespaces();
SkipNamespaceSeparator();
return BehaviorFunction(type,
objectName,
objectFunctionOrBehaviorName,
objectNameLocation,
objectNameDotLocation,
objectFunctionOrBehaviorNameLocation,
namespaceSeparatorLocation);
} else if (CheckIfChar(IsOpeningParenthesis)) {
ExpressionParserLocation openingParenthesisLocation = SkipChar();
functionStartPosition);
} else if (IsAnyChar("(")) {
SkipChar();
gd::String objectType =
GetTypeOfObject(globalObjectsContainer, objectsContainer, objectName);
@@ -424,60 +354,40 @@ class GD_CORE_API ExpressionParser2 {
: MetadataProvider::GetObjectStrExpressionMetadata(
platform, objectType, objectFunctionOrBehaviorName);
auto parametersNode = Parameters(metadata.parameters, objectName);
auto function = gd::make_unique<FunctionCallNode>(
type,
objectName,
std::move(parametersNode.parameters),
metadata,
objectFunctionOrBehaviorName);
function->diagnostic = std::move(parametersNode.diagnostic);
auto parametersAndError = Parameters(metadata.parameters, objectName);
auto function =
gd::make_unique<FunctionNode>(type,
objectName,
std::move(parametersAndError.first),
metadata,
objectFunctionOrBehaviorName);
function->diagnostic = std::move(parametersAndError.second);
if (!function->diagnostic)
function->diagnostic =
ValidateFunction(*function, objectNameLocation.GetStartPosition());
ValidateFunction(*function, functionStartPosition);
function->location = ExpressionParserLocation(
objectNameLocation.GetStartPosition(), GetCurrentPosition());
function->objectNameLocation = objectNameLocation;
function->objectNameDotLocation = objectNameDotLocation;
function->functionNameLocation = objectFunctionOrBehaviorNameLocation;
function->openingParenthesisLocation = openingParenthesisLocation;
function->closingParenthesisLocation =
parametersNode.closingParenthesisLocation;
return std::move(function);
}
auto node = gd::make_unique<ObjectFunctionNameNode>(
type, objectName, objectFunctionOrBehaviorName);
auto node = gd::make_unique<EmptyNode>(type);
node->diagnostic = RaiseSyntaxError(
_("An opening parenthesis (for an object expression), or double colon "
"(::) was expected (for a behavior expression)."));
node->location = ExpressionParserLocation(
objectNameLocation.GetStartPosition(), GetCurrentPosition());
node->objectNameLocation = objectNameLocation;
node->objectNameDotLocation = objectNameDotLocation;
node->objectFunctionOrBehaviorNameLocation =
objectFunctionOrBehaviorNameLocation;
return std::move(node);
}
std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode> BehaviorFunction(
std::unique_ptr<FunctionOrEmptyNode> BehaviorFunction(
const gd::String &type,
const gd::String &objectName,
const gd::String &behaviorName,
const ExpressionParserLocation &objectNameLocation,
const ExpressionParserLocation &objectNameDotLocation,
const ExpressionParserLocation &behaviorNameLocation,
const ExpressionParserLocation &behaviorNameNamespaceSeparatorLocation) {
auto identifierAndLocation = ReadIdentifierName();
const gd::String &functionName = identifierAndLocation.name;
const auto &functionNameLocation = identifierAndLocation.location;
size_t functionStartPosition) {
gd::String functionName = ReadIdentifierName();
SkipAllWhitespaces();
SkipWhitespace();
if (CheckIfChar(IsOpeningParenthesis)) {
ExpressionParserLocation openingParenthesisLocation = SkipChar();
if (IsAnyChar("(")) {
SkipChar();
gd::String behaviorType = GetTypeOfBehavior(
globalObjectsContainer, objectsContainer, behaviorName);
@@ -490,61 +400,35 @@ class GD_CORE_API ExpressionParser2 {
: MetadataProvider::GetBehaviorStrExpressionMetadata(
platform, behaviorType, functionName);
auto parametersNode =
auto parametersAndError =
Parameters(metadata.parameters, objectName, behaviorName);
auto function = gd::make_unique<FunctionCallNode>(
type,
objectName,
behaviorName,
std::move(parametersNode.parameters),
metadata,
functionName);
function->diagnostic = std::move(parametersNode.diagnostic);
auto function =
gd::make_unique<FunctionNode>(type,
objectName,
behaviorName,
std::move(parametersAndError.first),
metadata,
functionName);
function->diagnostic = std::move(parametersAndError.second);
if (!function->diagnostic)
function->diagnostic =
ValidateFunction(*function, objectNameLocation.GetStartPosition());
ValidateFunction(*function, functionStartPosition);
function->location = ExpressionParserLocation(
objectNameLocation.GetStartPosition(), GetCurrentPosition());
function->objectNameLocation = objectNameLocation;
function->objectNameDotLocation = objectNameDotLocation;
function->behaviorNameLocation = behaviorNameLocation;
function->behaviorNameNamespaceSeparatorLocation =
behaviorNameNamespaceSeparatorLocation;
function->openingParenthesisLocation = openingParenthesisLocation;
function->closingParenthesisLocation =
parametersNode.closingParenthesisLocation;
function->functionNameLocation = functionNameLocation;
return std::move(function);
} else {
auto node = gd::make_unique<ObjectFunctionNameNode>(
type, objectName, behaviorName, functionName);
auto node = gd::make_unique<EmptyNode>(type);
node->diagnostic = RaiseSyntaxError(
_("An opening parenthesis was expected here to call a function."));
node->location = ExpressionParserLocation(
objectNameLocation.GetStartPosition(), GetCurrentPosition());
node->objectNameLocation = objectNameLocation;
node->objectNameDotLocation = objectNameDotLocation;
node->objectFunctionOrBehaviorNameLocation = behaviorNameLocation;
node->behaviorNameNamespaceSeparatorLocation =
behaviorNameNamespaceSeparatorLocation;
node->behaviorFunctionNameLocation = functionNameLocation;
return std::move(node);
}
}
// A temporary node that will be integrated into function nodes.
struct ParametersNode {
std::vector<std::unique_ptr<ExpressionNode>> parameters;
std::unique_ptr<gd::ExpressionParserError> diagnostic;
ExpressionParserLocation closingParenthesisLocation;
};
ParametersNode Parameters(
std::vector<gd::ParameterMetadata> parameterMetadata,
const gd::String &objectName = "",
const gd::String &behaviorName = "") {
std::pair<std::vector<std::unique_ptr<ExpressionNode>>,
std::unique_ptr<gd::ExpressionParserError>>
Parameters(std::vector<gd::ParameterMetadata> parameterMetadata,
const gd::String &objectName = "",
const gd::String &behaviorName = "") {
std::vector<std::unique_ptr<ExpressionNode>> parameters;
// By convention, object is always the first parameter, and behavior the
@@ -553,12 +437,11 @@ class GD_CORE_API ExpressionParser2 {
WrittenParametersFirstIndex(objectName, behaviorName);
while (!IsEndReached()) {
SkipAllWhitespaces();
SkipWhitespace();
if (CheckIfChar(IsClosingParenthesis)) {
auto closingParenthesisLocation = SkipChar();
return ParametersNode{
std::move(parameters), nullptr, closingParenthesisLocation};
if (IsAnyChar(")")) {
SkipChar();
return std::make_pair(std::move(parameters), nullptr);
} else {
if (parameterIndex < parameterMetadata.size()) {
const gd::String &type = parameterMetadata[parameterIndex].GetType();
@@ -596,18 +479,16 @@ class GD_CORE_API ExpressionParser2 {
GetCurrentPosition());
}
SkipAllWhitespaces();
SkipIfChar(IsParameterSeparator);
SkipWhitespace();
SkipIfIsAnyChar(PARAMETERS_SEPARATOR);
parameterIndex++;
}
}
ExpressionParserLocation invalidClosingParenthesisLocation;
return ParametersNode{
return std::make_pair(
std::move(parameters),
RaiseSyntaxError(_("The list of parameters is not terminated. Add a "
"closing parenthesis to end the parameters.")),
invalidClosingParenthesisLocation};
"closing parenthesis to end the parameters.")));
}
///@}
@@ -616,7 +497,7 @@ class GD_CORE_API ExpressionParser2 {
*/
///@{
std::unique_ptr<ExpressionParserDiagnostic> ValidateFunction(
const gd::FunctionCallNode &function, size_t functionStartPosition);
const gd::FunctionNode &function, size_t functionStartPosition);
std::unique_ptr<ExpressionParserDiagnostic> ValidateOperator(
const gd::String &type, gd::String::value_type operatorChar) {
@@ -644,8 +525,7 @@ class GD_CORE_API ExpressionParser2 {
} else if (gd::ParameterMetadata::IsObject(type)) {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("Operators (+, -, /, *) can't be used with an object name. Remove "
"the operator."),
_("Operators (+, -, /, *) can't be used with an object name. Remove the operator."),
GetCurrentPosition());
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
return gd::make_unique<ExpressionParserError>(
@@ -681,8 +561,7 @@ class GD_CORE_API ExpressionParser2 {
} else if (gd::ParameterMetadata::IsObject(type)) {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("Operators (+, -) can't be used with an object name. Remove the "
"operator."),
_("Operators (+, -) can't be used with an object name. Remove the operator."),
GetCurrentPosition());
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
return gd::make_unique<ExpressionParserError>(
@@ -700,131 +579,53 @@ class GD_CORE_API ExpressionParser2 {
* Read tokens or characters
*/
///@{
ExpressionParserLocation SkipChar() {
size_t startPosition = currentPosition;
return ExpressionParserLocation(startPosition, ++currentPosition);
}
void SkipChar() { currentPosition++; }
void SkipAllWhitespaces() {
void SkipWhitespace() {
while (currentPosition < expression.size() &&
IsWhitespace(expression[currentPosition])) {
WHITESPACES.find(expression[currentPosition]) != gd::String::npos) {
currentPosition++;
}
}
void SkipIfChar(
const std::function<bool(gd::String::value_type)> &predicate) {
if (CheckIfChar(predicate)) {
void SkipIfIsAnyChar(const gd::String &allowedCharacters) {
if (IsAnyChar(allowedCharacters)) {
currentPosition++;
}
}
ExpressionParserLocation SkipNamespaceSeparator() {
size_t startPosition = currentPosition;
void SkipNamespaceSeparator() {
// Namespace separator is a special kind of delimiter as it is 2 characters
// long
if (IsNamespaceSeparator()) {
currentPosition += NAMESPACE_SEPARATOR.size();
}
return ExpressionParserLocation(startPosition, currentPosition);
}
bool CheckIfChar(
const std::function<bool(gd::String::value_type)> &predicate) {
if (currentPosition >= expression.size()) return false;
gd::String::value_type character = expression[currentPosition];
return predicate(character);
}
bool IsIdentifierAllowedChar() {
if (currentPosition >= expression.size()) return false;
gd::String::value_type character = expression[currentPosition];
// Quickly compare if the character is a number or ASCII character.
if ((character >= '0' && character <= '9') ||
(character >= 'A' && character <= 'Z') ||
(character >= 'a' && character <= 'z'))
return true;
// Otherwise do the full check against separators forbidden in identifiers.
if (!IsParameterSeparator(character) && !IsDot(character) &&
!IsQuote(character) && !IsBracket(character) &&
!IsExpressionOperator(character) && !IsTermOperator(character)) {
bool IsAnyChar(const gd::String &allowedCharacters) {
if (currentPosition < expression.size() &&
allowedCharacters.find(expression[currentPosition]) !=
gd::String::npos) {
return true;
}
return false;
}
static bool IsWhitespace(gd::String::value_type character) {
return character == ' ' || character == '\n' || character == '\r';
}
bool IsIdentifierAllowedChar() {
if (currentPosition < expression.size() &&
PARAMETERS_SEPARATOR.find(expression[currentPosition]) ==
gd::String::npos &&
DOT.find(expression[currentPosition]) == gd::String::npos &&
QUOTE.find(expression[currentPosition]) == gd::String::npos &&
BRACKETS.find(expression[currentPosition]) == gd::String::npos &&
EXPRESSION_OPERATORS.find(expression[currentPosition]) ==
gd::String::npos &&
TERM_OPERATORS.find(expression[currentPosition]) == gd::String::npos) {
return true;
}
static bool IsParameterSeparator(gd::String::value_type character) {
return character == ',';
}
static bool IsDot(gd::String::value_type character) {
return character == '.';
}
static bool IsQuote(gd::String::value_type character) {
return character == '"';
}
static bool IsBracket(gd::String::value_type character) {
return character == '(' || character == ')' || character == '[' ||
character == ']' || character == '{' || character == '}';
}
static bool IsOpeningParenthesis(gd::String::value_type character) {
return character == '(';
}
static bool IsClosingParenthesis(gd::String::value_type character) {
return character == ')';
}
static bool IsOpeningSquareBracket(gd::String::value_type character) {
return character == '[';
}
static bool IsClosingSquareBracket(gd::String::value_type character) {
return character == ']';
}
static bool IsExpressionEndingChar(gd::String::value_type character) {
return character == ',' || IsClosingParenthesis(character) ||
IsClosingSquareBracket(character);
}
static bool IsExpressionOperator(gd::String::value_type character) {
return character == '+' || character == '-' || character == '<' ||
character == '>' || character == '?' || character == '^' ||
character == '=' || character == '\\' || character == ':' ||
character == '!';
}
static bool IsUnaryOperator(gd::String::value_type character) {
return character == '+' || character == '-';
}
static bool IsTermOperator(gd::String::value_type character) {
return character == '/' || character == '*';
}
static bool IsNumberFirstChar(gd::String::value_type character) {
return character == '.' || (character >= '0' && character <= '9');
}
static bool IsNonZeroDigit(gd::String::value_type character) {
return (character >= '1' && character <= '9');
}
static bool IsZeroDigit(gd::String::value_type character) {
return character == '0';
return false;
}
bool IsNamespaceSeparator() {
@@ -837,20 +638,12 @@ class GD_CORE_API ExpressionParser2 {
bool IsEndReached() { return currentPosition >= expression.size(); }
// A temporary node used when reading an identifier
struct IdentifierAndLocation {
gd::String ReadIdentifierName() {
gd::String name;
ExpressionParserLocation location;
};
IdentifierAndLocation ReadIdentifierName() {
gd::String name;
size_t startPosition = currentPosition;
while (currentPosition < expression.size() &&
(IsIdentifierAllowedChar()
// Allow whitespace in identifier name for compatibility
||
expression[currentPosition] == ' ')) {
|| expression[currentPosition] == ' ')) {
name += expression[currentPosition];
currentPosition++;
}
@@ -858,23 +651,12 @@ class GD_CORE_API ExpressionParser2 {
// Trim whitespace at the end (we allow them for compatibility inside
// the name, but after the last character that is not whitespace, they
// should be ignore again).
if (!name.empty() && IsWhitespace(name[name.size() - 1])) {
size_t lastCharacterPos = name.size() - 1;
while (lastCharacterPos < name.size() &&
IsWhitespace(name[lastCharacterPos])) {
lastCharacterPos--;
}
if ((lastCharacterPos + 1) < name.size()) {
name.erase(lastCharacterPos + 1);
}
size_t lastCharacterPos = name.find_last_not_of(WHITESPACES);
if (!name.empty() && (lastCharacterPos + 1) < name.size()) {
name.erase(lastCharacterPos + 1);
}
IdentifierAndLocation identifierAndLocation{
name,
// The location is ignoring the trailing whitespace (only whitespace
// inside the identifier are allowed for compatibility).
ExpressionParserLocation(startPosition, startPosition + name.size())};
return identifierAndLocation;
return name;
}
std::unique_ptr<TextNode> ReadText();
@@ -882,32 +664,24 @@ class GD_CORE_API ExpressionParser2 {
std::unique_ptr<NumberNode> ReadNumber();
std::unique_ptr<EmptyNode> ReadUntilWhitespace(gd::String type) {
size_t startPosition = GetCurrentPosition();
gd::String text;
while (currentPosition < expression.size() &&
!IsWhitespace(expression[currentPosition])) {
WHITESPACES.find(expression[currentPosition]) == gd::String::npos) {
text += expression[currentPosition];
currentPosition++;
}
auto node = gd::make_unique<EmptyNode>(type, text);
node->location =
ExpressionParserLocation(startPosition, GetCurrentPosition());
return node;
return gd::make_unique<EmptyNode>(type, text);
}
std::unique_ptr<EmptyNode> ReadUntilEnd(gd::String type) {
size_t startPosition = GetCurrentPosition();
gd::String text;
while (currentPosition < expression.size()) {
text += expression[currentPosition];
currentPosition++;
}
auto node = gd::make_unique<EmptyNode>(type, text);
node->location =
ExpressionParserLocation(startPosition, GetCurrentPosition());
return node;
return gd::make_unique<EmptyNode>(type, text);
}
size_t GetCurrentPosition() { return currentPosition; }
@@ -972,6 +746,15 @@ class GD_CORE_API ExpressionParser2 {
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
static gd::String NUMBER_FIRST_CHAR;
static gd::String DOT;
static gd::String PARAMETERS_SEPARATOR;
static gd::String QUOTE;
static gd::String BRACKETS;
static gd::String EXPRESSION_OPERATORS;
static gd::String TERM_OPERATORS;
static gd::String UNARY_OPERATORS;
static gd::String WHITESPACES;
static gd::String NAMESPACE_SEPARATOR;
};

View File

@@ -20,24 +20,6 @@ class ExpressionMetadata;
namespace gd {
struct ExpressionParserLocation {
ExpressionParserLocation() : isValid(false){};
ExpressionParserLocation(size_t position)
: isValid(true), startPosition(position), endPosition(position){};
ExpressionParserLocation(size_t startPosition_, size_t endPosition_)
: isValid(true),
startPosition(startPosition_),
endPosition(endPosition_){};
size_t GetStartPosition() const { return startPosition; }
size_t GetEndPosition() const { return endPosition; }
bool IsValid() const { return isValid; }
private:
bool isValid;
size_t startPosition;
size_t endPosition;
};
/**
* \brief A diagnostic that can be attached to a gd::ExpressionNode.
*/
@@ -58,25 +40,30 @@ struct ExpressionParserError : public ExpressionParserDiagnostic {
ExpressionParserError(const gd::String &type_,
const gd::String &message_,
size_t position_)
: type(type_), message(message_), location(position_){};
: type(type_),
message(message_),
startPosition(position_),
endPosition(position_){};
ExpressionParserError(const gd::String &type_,
const gd::String &message_,
size_t startPosition_,
size_t endPosition_)
: type(type_),
message(message_),
location(startPosition_, endPosition_){};
startPosition(startPosition_),
endPosition(endPosition_){};
virtual ~ExpressionParserError(){};
bool IsError() override { return true; }
const gd::String &GetMessage() override { return message; }
size_t GetStartPosition() override { return location.GetStartPosition(); }
size_t GetEndPosition() override { return location.GetEndPosition(); }
size_t GetStartPosition() override { return startPosition; }
size_t GetEndPosition() override { return endPosition; }
private:
gd::String type;
gd::String message;
ExpressionParserLocation location;
size_t startPosition;
size_t endPosition;
};
/**
@@ -88,26 +75,16 @@ struct ExpressionNode {
virtual void Visit(ExpressionParser2NodeWorker &worker){};
std::unique_ptr<ExpressionParserDiagnostic> diagnostic;
ExpressionParserLocation location; ///< The location of the entire node. Some
///nodes might have other locations stored
///inside them. For example, a function
///can store the position of the object
///name, the dot, the function name,
///etc...
};
struct SubExpressionNode : public ExpressionNode {
SubExpressionNode(const gd::String &type_,
std::unique_ptr<ExpressionNode> expression_)
: type(type_), expression(std::move(expression_)){};
SubExpressionNode(std::unique_ptr<ExpressionNode> expression_)
: expression(std::move(expression_)){};
virtual ~SubExpressionNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitSubExpressionNode(*this);
};
gd::String type; // "string", "number", type supported by
// gd::ParameterMetadata::IsObject, types supported by
// gd::ParameterMetadata::IsExpression or "unknown".
std::unique_ptr<ExpressionNode> expression;
};
@@ -115,8 +92,6 @@ struct SubExpressionNode : public ExpressionNode {
* \brief An operator node. For example: "lhs + rhs".
*/
struct OperatorNode : public ExpressionNode {
OperatorNode(const gd::String &type_, gd::String::value_type op_)
: type(type_), op(op_){};
virtual ~OperatorNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitOperatorNode(*this);
@@ -124,9 +99,6 @@ struct OperatorNode : public ExpressionNode {
std::unique_ptr<ExpressionNode> leftHandSide;
std::unique_ptr<ExpressionNode> rightHandSide;
gd::String type; // "string", "number", type supported by
// gd::ParameterMetadata::IsObject, types supported by
// gd::ParameterMetadata::IsExpression or "unknown".
gd::String::value_type op;
};
@@ -134,17 +106,13 @@ struct OperatorNode : public ExpressionNode {
* \brief A unary operator node. For example: "-2".
*/
struct UnaryOperatorNode : public ExpressionNode {
UnaryOperatorNode(const gd::String &type_, gd::String::value_type op_)
: type(type_), op(op_){};
UnaryOperatorNode(gd::String::value_type op_) : op(op_){};
virtual ~UnaryOperatorNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitUnaryOperatorNode(*this);
};
std::unique_ptr<ExpressionNode> factor;
gd::String type; // "string", "number", type supported by
// gd::ParameterMetadata::IsObject, types supported by
// gd::ParameterMetadata::IsExpression or "unknown".
gd::String::value_type op;
};
@@ -202,8 +170,6 @@ struct VariableNode : public ExpressionNode {
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
child; // Can be nullptr if no accessor
ExpressionParserLocation nameLocation;
};
/**
@@ -219,8 +185,6 @@ struct VariableAccessorNode
};
gd::String name;
ExpressionParserLocation nameLocation;
ExpressionParserLocation dotLocation;
};
/**
@@ -239,14 +203,12 @@ struct VariableBracketAccessorNode
std::unique_ptr<ExpressionNode> expression;
};
struct IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode
: public ExpressionNode {};
struct IdentifierOrFunctionOrEmptyNode : public ExpressionNode {};
/**
* \brief An identifier node, usually representing an object or a function name.
* \brief An identifier node, usually representing an object.
*/
struct IdentifierNode
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
struct IdentifierNode : public IdentifierOrFunctionOrEmptyNode {
IdentifierNode(const gd::String &identifierName_, const gd::String &type_)
: identifierName(identifierName_), type(type_){};
virtual ~IdentifierNode(){};
@@ -258,142 +220,64 @@ struct IdentifierNode
gd::String type;
};
struct FunctionCallOrObjectFunctionNameOrEmptyNode
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
virtual ~FunctionCallOrObjectFunctionNameOrEmptyNode(){};
struct FunctionOrEmptyNode : public IdentifierOrFunctionOrEmptyNode {
virtual ~FunctionOrEmptyNode(){};
void Visit(ExpressionParser2NodeWorker &worker) override{};
};
/**
* \brief The name of a function to call on an object or the behavior
* For example: "MyObject.Function" or "MyObject.Physics" or
* "MyObject.Physics::LinearVelocity".
* \brief A function node. For example: "MyExtension::MyFunction(1, 2)".
*/
struct ObjectFunctionNameNode
: public FunctionCallOrObjectFunctionNameOrEmptyNode {
ObjectFunctionNameNode(const gd::String &type_,
const gd::String &objectName_,
const gd::String &objectFunctionOrBehaviorName_)
: type(type_),
objectName(objectName_),
objectFunctionOrBehaviorName(objectFunctionOrBehaviorName_) {}
ObjectFunctionNameNode(const gd::String &type_,
const gd::String &objectName_,
const gd::String &behaviorName_,
const gd::String &behaviorFunctionName_)
: type(type_),
objectName(objectName_),
objectFunctionOrBehaviorName(behaviorName_),
behaviorFunctionName(behaviorFunctionName_) {}
virtual ~ObjectFunctionNameNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitObjectFunctionNameNode(*this);
};
gd::String type; // This could be removed if the type ("string", "number",
// type supported by gd::ParameterMetadata::IsObject, types
// supported by gd::ParameterMetadata::IsExpression or
// "unknown") was stored in ExpressionMetadata.
gd::String objectName;
gd::String objectFunctionOrBehaviorName; ///< Behavior name if
///`behaviorFunctionName` is not
///empty.
gd::String behaviorFunctionName; ///< If empty, then
///objectFunctionOrBehaviorName is filled
///with the behavior name.
ExpressionParserLocation
objectNameLocation; ///< Location of the object name.
ExpressionParserLocation
objectNameDotLocation; ///< Location of the "." after the object name.
ExpressionParserLocation objectFunctionOrBehaviorNameLocation; ///< Location
///of object
///function
///name or
///behavior
///name.
ExpressionParserLocation
behaviorNameNamespaceSeparatorLocation; ///< Location of the "::"
///separator, if any.
ExpressionParserLocation behaviorFunctionNameLocation; ///< Location of the
///behavior function
///name, if any.
};
/**
* \brief A function call node (either free function, object function or object
* behavior function).
* For example: "MyExtension::MyFunction(1, 2)", "MyObject.Function()" or
* "MyObject.Physics::LinearVelocity()".
*/
struct FunctionCallNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
FunctionCallNode(const gd::String &type_,
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
const ExpressionMetadata &expressionMetadata_,
const gd::String &functionName_)
struct FunctionNode : public FunctionOrEmptyNode {
FunctionNode(const gd::String &type_,
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
const ExpressionMetadata &expressionMetadata_,
const gd::String &functionName_)
: type(type_),
parameters(std::move(parameters_)),
expressionMetadata(expressionMetadata_),
functionName(functionName_){};
FunctionCallNode(const gd::String &type_,
const gd::String &objectName_,
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
const ExpressionMetadata &expressionMetadata_,
const gd::String &functionName_)
FunctionNode(const gd::String &type_,
const gd::String &objectName_,
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
const ExpressionMetadata &expressionMetadata_,
const gd::String &functionName_)
: type(type_),
objectName(objectName_),
parameters(std::move(parameters_)),
expressionMetadata(expressionMetadata_),
functionName(functionName_){};
FunctionCallNode(const gd::String &type_,
const gd::String &objectName_,
const gd::String &behaviorName_,
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
const ExpressionMetadata &expressionMetadata_,
const gd::String &functionName_)
FunctionNode(const gd::String &type_,
const gd::String &objectName_,
const gd::String &behaviorName_,
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
const ExpressionMetadata &expressionMetadata_,
const gd::String &functionName_)
: type(type_),
objectName(objectName_),
behaviorName(behaviorName_),
parameters(std::move(parameters_)),
expressionMetadata(expressionMetadata_),
functionName(functionName_){};
virtual ~FunctionCallNode(){};
virtual ~FunctionNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitFunctionCallNode(*this);
worker.OnVisitFunctionNode(*this);
};
gd::String type; // This could be removed if the type ("string", "number",
// type supported by gd::ParameterMetadata::IsObject, types
// supported by gd::ParameterMetadata::IsExpression or
// "unknown") was stored in ExpressionMetadata.
gd::String type; // This could be removed if the type ("string" or "number")
// was stored in ExpressionMetadata.
gd::String objectName;
gd::String behaviorName;
std::vector<std::unique_ptr<ExpressionNode>> parameters;
const ExpressionMetadata &expressionMetadata;
gd::String functionName;
ExpressionParserLocation
functionNameLocation; ///< Location of the function name.
ExpressionParserLocation
objectNameLocation; ///< Location of the object name, if any.
ExpressionParserLocation
objectNameDotLocation; ///< Location of the "." after the object name.
ExpressionParserLocation
behaviorNameLocation; ///< Location of the behavior name, if any.
ExpressionParserLocation
behaviorNameNamespaceSeparatorLocation; ///< Location of the "::"
///separator, if any.
ExpressionParserLocation
openingParenthesisLocation; ///< Location of the "(".
ExpressionParserLocation
closingParenthesisLocation; ///< Location of the ")".
};
/**
* \brief An empty node, used when parsing failed/a syntax error was
* encountered and any other node could not make sense.
*/
struct EmptyNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
struct EmptyNode : public FunctionOrEmptyNode {
EmptyNode(const gd::String &type_, const gd::String &text_ = "")
: type(type_), text(text_){};
virtual ~EmptyNode(){};
@@ -401,12 +285,10 @@ struct EmptyNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
worker.OnVisitEmptyNode(*this);
};
gd::String type; // "string", "number", type supported by
// gd::ParameterMetadata::IsObject, types supported by
// gd::ParameterMetadata::IsExpression or "unknown".
gd::String type;
gd::String text;
};
} // namespace gd
#endif
#endif

View File

@@ -92,15 +92,7 @@ class GD_CORE_API ExpressionParser2NodePrinter
void OnVisitIdentifierNode(IdentifierNode& node) override {
output += node.identifierName;
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (!node.behaviorFunctionName.empty()) {
output +=
node.objectName + "." + node.objectFunctionOrBehaviorName + "::" + node.behaviorFunctionName;
} else {
output += node.objectName + "." + node.objectFunctionOrBehaviorName;
}
};
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
void OnVisitFunctionNode(FunctionNode& node) override {
if (!node.behaviorName.empty()) {
output +=
node.objectName + "." + node.behaviorName + "::" + node.functionName;

View File

@@ -16,11 +16,10 @@ class TextNode;
class VariableNode;
class VariableAccessorNode;
class VariableBracketAccessorNode;
class IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode;
class IdentifierOrFunctionOrEmptyNode;
class IdentifierNode;
class FunctionCallOrObjectFunctionNameOrEmptyNode;
class ObjectFunctionNameNode;
class FunctionCallNode;
class FunctionOrEmptyNode;
class FunctionNode;
class EmptyNode;
} // namespace gd
@@ -43,11 +42,10 @@ class GD_CORE_API ExpressionParser2NodeWorker {
friend class VariableNode;
friend class VariableAccessorNode;
friend class VariableBracketAccessorNode;
friend class IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode;
friend class IdentifierOrFunctionOrEmptyNode;
friend class IdentifierNode;
friend class FunctionCallOrObjectFunctionNameOrEmptyNode;
friend class ObjectFunctionNameNode;
friend class FunctionCallNode;
friend class FunctionOrEmptyNode;
friend class FunctionNode;
friend class EmptyNode;
public:
@@ -64,11 +62,10 @@ class GD_CORE_API ExpressionParser2NodeWorker {
virtual void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) = 0;
virtual void OnVisitIdentifierNode(IdentifierNode& node) = 0;
virtual void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) = 0;
virtual void OnVisitFunctionCallNode(FunctionCallNode& node) = 0;
virtual void OnVisitFunctionNode(FunctionNode& node) = 0;
virtual void OnVisitEmptyNode(EmptyNode& node) = 0;
};
} // namespace gd
#endif
#endif

View File

@@ -0,0 +1,141 @@
/*
* 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

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

View File

@@ -6,34 +6,26 @@
#if defined(GD_IDE_ONLY)
#ifndef EVENTSCODENAMEMANGLER_H
#define EVENTSCODENAMEMANGLER_H
#include <unordered_map>
#include "GDCore/String.h"
/**
* \brief Mangle object names, so as to ensure all names used in code are valid.
* Manage name mangling, 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.
*/
const gd::String &GetMangledObjectsListName(
const gd::String &originalObjectName);
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.
*/
const gd::String &GetExternalEventsFunctionMangledName(
gd::String GetExternalEventsFunctionMangledName(
const gd::String &externalEventsName);
static EventsCodeNameMangler *Get();
@@ -43,22 +35,14 @@ 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 for
* `EventsCodeNameMangler::Get()->GetMangledObjectsListName(objectName)`.
*
* \see EventsCodeNameMangler
* \return Mangled object name
* Shortcut to
* EventsCodeNameMangler::Get()->GetMangledObjectsListName(objectName). \see
* EventsCodeNameMangler \return Mangled object name
*/
const gd::String &GD_CORE_API ManObjListName(const gd::String &objectName);
gd::String GD_CORE_API ManObjListName(const gd::String &objectName);
#endif // EVENTSCODENAMEMANGLER_H
#endif

View File

@@ -35,11 +35,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
.AddParameter("expression", _("Channel identifier"))
.AddParameter("yesorno", _("Repeat the sound"), "", true)
.SetDefaultValue("no")
.AddParameter("expression", _("Volume"), "", true)
.SetParameterLongDescription(_("From 0 to 100, 100 by default."))
.AddParameter(
"expression", _("Volume (from 0 to 100, 100 by default)"), "", true)
.SetDefaultValue("100")
.AddParameter("expression", _("Pitch (speed)"), "", true)
.SetParameterLongDescription(_("1 by default."))
.AddParameter("expression", _("Pitch (speed) (1 by default)"), "", true)
.SetDefaultValue("1")
.MarkAsAdvanced();
@@ -94,11 +93,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
.AddParameter("expression", _("Channel identifier"))
.AddParameter("yesorno", _("Repeat the sound"), "", true)
.SetDefaultValue("no")
.AddParameter("expression", _("Volume"), "", true)
.SetParameterLongDescription(_("From 0 to 100, 100 by default."))
.AddParameter(
"expression", _("Volume (from 0 to 100, 100 by default)"), "", true)
.SetDefaultValue("100")
.AddParameter("expression", _("Pitch (speed)"), "", true)
.SetParameterLongDescription(_("1 by default."))
.AddParameter("expression", _("Pitch (speed) (1 by default)"), "", true)
.SetDefaultValue("1")
.MarkAsAdvanced();
@@ -143,97 +141,117 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
_("Volume of the sound on a channel"),
_("This action modifies the volume of the sound on the "
"specified channel. The volume is between 0 and 100."),
_("the volume of the sound on channel _PARAM1_"),
_("Do _PARAM2__PARAM3_ to the volume of the sound on channel "
"_PARAM1_"),
_("Audio/Sounds on channels"),
"res/actions/sonVolume24.png",
"res/actions/sonVolume.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction("ModVolumeMusicCanal",
_("Volume of the music on a channel"),
_("This action modifies the volume of the music on the "
"specified channel. The volume is between 0 and 100."),
_("the volume of the music on channel _PARAM1_"),
_("Do _PARAM2__PARAM3_ to the volume of the music on channel "
"_PARAM1_"),
_("Audio/Music on channels"),
"res/actions/musicVolume24.png",
"res/actions/musicVolume.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction("ModGlobalVolume",
_("Game global volume"),
_("This action modifies the global volume of the game. The "
"volume is between 0 and 100."),
_("the global sound level"),
_("Do _PARAM1__PARAM2_ to global sound level"),
_("Audio"),
"res/actions/volume24.png",
"res/actions/volume.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardOperatorParameters("number")
.MarkAsSimple();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsSimple()
.SetManipulatedType("number");
extension
.AddAction("ModPitchSoundChannel",
_("Pitch of the sound of a channel"),
_("This action modifies the pitch (speed) of the sound on a "
"channel.\n1 is the default pitch."),
_("the pitch of the sound on channel _PARAM1_"),
_("Do _PARAM2__PARAM3_ to the pitch of the sound on channel "
"_PARAM1_"),
_("Audio/Sounds on channels"),
"res/actions/son24.png",
"res/actions/son.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction("ModPitchMusicChannel",
_("Pitch of the music on a channel"),
_("This action modifies the pitch of the music on the "
"specified channel. 1 is the default pitch"),
_("the pitch of the music on channel _PARAM1_"),
_("Do _PARAM2__PARAM3_ to the pitch of the music on channel "
"_PARAM1_"),
_("Audio/Music on channels"),
"res/actions/music24.png",
"res/actions/music.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction("ModPlayingOffsetSoundChannel",
_("Playing offset of the sound on a channel"),
_("This action modifies the playing offset of the sound on a "
"channel"),
_("the playing offset of the sound on channel _PARAM1_"),
_("Do _PARAM2__PARAM3_ to the playing offset of the sound on "
"channel _PARAM1_"),
_("Audio/Sounds on channels"),
"res/actions/son24.png",
"res/actions/son.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction("ModPlayingOffsetMusicChannel",
_("Playing offset of the music on a channel"),
_("This action modifies the playing offset of the music on "
"the specified channel"),
_("the playing offset of the music on channel _PARAM1_"),
_("Do _PARAM2__PARAM3_ to the playing offset of the music on "
"channel _PARAM1_"),
_("Audio/Music on channels"),
"res/actions/music24.png",
"res/actions/music.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction("PlaySound",
@@ -247,11 +265,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
.AddParameter("soundfile", _("Audio file (or audio resource name)"))
.AddParameter("yesorno", _("Repeat the sound"), "", true)
.SetDefaultValue("no")
.AddParameter("expression", _("Volume"), "", true)
.SetParameterLongDescription(_("From 0 to 100, 100 by default."))
.AddParameter(
"expression", _("Volume (from 0 to 100, 100 by default)"), "", true)
.SetDefaultValue("100")
.AddParameter("expression", _("Pitch (speed)"), "", true)
.SetParameterLongDescription(_("1 by default."))
.AddParameter("expression", _("Pitch (speed) (1 by default)"), "", true)
.SetDefaultValue("1")
.MarkAsSimple();
@@ -267,11 +284,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
.AddParameter("musicfile", _("Audio file (or audio resource name)"))
.AddParameter("yesorno", _("Repeat the sound"), "", true)
.SetDefaultValue("no")
.AddParameter("expression", _("Volume"), "", true)
.SetParameterLongDescription(_("From 0 to 100, 100 by default."))
.AddParameter(
"expression", _("Volume (from 0 to 100, 100 by default)"), "", true)
.SetDefaultValue("100")
.AddParameter("expression", _("Pitch (speed)"), "", true)
.SetParameterLongDescription(_("1 by default."))
.AddParameter("expression", _("Pitch (speed) (1 by default)"), "", true)
.SetDefaultValue("1")
.MarkAsSimple();
@@ -353,14 +369,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
_("Volume of the sound on a channel"),
_("Test the volume of the sound on the specified channel. The volume "
"is between 0 and 100."),
_("the volume of the sound on channel _PARAM1_"),
_("The volume of the sound on channel _PARAM1_ is _PARAM2__PARAM3_"),
_("Audio/Sounds on channels"),
"res/conditions/sonVolume24.png",
"res/conditions/sonVolume.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Volume to test"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition(
@@ -368,26 +386,30 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
_("Volume of the music on a channel"),
_("Test the volume of the music on a specified channel. The volume "
"is between 0 and 100."),
_("the volume of the music on channel _PARAM1_"),
_("The volume of the music on channel _PARAM1_ is _PARAM2__PARAM3_"),
_("Audio/Music on channels"),
"res/conditions/musicVolume24.png",
"res/conditions/musicVolume.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Volume to test"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition(
"GlobalVolume",
_("Global volume"),
_("Test the global sound level. The volume is between 0 and 100."),
_("the global game volume"),
_("The global game volume is _PARAM1__PARAM2_"),
_("Audio"),
"res/conditions/volume24.png",
"res/conditions/volume.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardRelationalOperatorParameters("number");
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Volume to test"))
.SetManipulatedType("number");
extension
.AddCondition(
@@ -395,14 +417,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
_("Pitch of the sound of a channel"),
_("Test the pitch of the sound on the specified channel. 1 is the "
"default pitch."),
_("the pitch of the sound on channel _PARAM1_"),
_("The pitch of the sound on channel _PARAM1_ is _PARAM2__PARAM3_"),
_("Audio/Sounds on channels"),
"res/conditions/sonVolume24.png",
"res/conditions/sonVolume.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Pitch to test"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition(
@@ -410,42 +434,50 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
_("Pitch of the music on a channel"),
_("Test the pitch (speed) of the music on a specified channel. 1 is "
"the default pitch."),
_("the pitch of the music on channel _PARAM1_"),
_("The pitch of the music on channel _PARAM1_ is _PARAM2__PARAM3_"),
_("Audio/Music on channels"),
"res/conditions/musicVolume24.png",
"res/conditions/musicVolume.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Pitch to test"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition(
"SoundChannelPlayingOffset",
_("Playing offset of the sound on a channel"),
_("Test the playing offset of the sound on the specified channel."),
_("the playing offset of the sound on channel _PARAM1_"),
_("The playing offset of the sound on channel _PARAM1_ is "
"_PARAM2__PARAM3_"),
_("Audio/Sounds on channels"),
"res/conditions/sonVolume24.png",
"res/conditions/sonVolume.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Playing position (in seconds)"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition(
"MusicChannelPlayingOffset",
_("Playing offset of the music on a channel"),
_("Test the playing offset of the music on the specified channel."),
_("the playing offset of the music on channel _PARAM1_"),
_("The playing offset of the music on channel _PARAM1_ is "
"_PARAM2__PARAM3_"),
_("Audio/Music on channels"),
"res/conditions/musicVolume24.png",
"res/conditions/musicVolume.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Playing position (in seconds)"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddExpression("SoundChannelPlayingOffset",

View File

@@ -13,12 +13,11 @@ namespace gd {
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
gd::PlatformExtension& extension) {
extension
.SetExtensionInformation(
"BuiltinObject",
_("Features for all objects"),
_("Common features that can be used for all objects in GDevelop."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionInformation("BuiltinObject",
_("Base object"),
_("Base object"),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/objects/base_object/events");
gd::ObjectMetadata& obj = extension.AddObject<gd::Object>(
@@ -28,59 +27,67 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddCondition("PosX",
_("Compare X position of an object"),
_("Compare the X position of the object."),
_("the X position"),
_("The X position of _PARAM0_ is _PARAM1__PARAM2_"),
_("Position"),
"res/conditions/position24.png",
"res/conditions/position.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsSimple();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("X position"))
.MarkAsSimple()
.SetManipulatedType("number");
obj.AddAction("MettreX",
_("X position of an object"),
_("Change the X position of an object."),
_("the X position"),
_("Do _PARAM1__PARAM2_ to the X position of _PARAM0_"),
_("Position"),
"res/actions/position24.png",
"res/actions/position.png")
.AddParameter("object", _("Object"))
.UseStandardOperatorParameters("number")
.MarkAsSimple();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsSimple()
.SetManipulatedType("number");
obj.AddCondition("PosY",
_("Compare Y position of an object"),
_("Compare the Y position of an object."),
_("the Y position"),
_("The Y position of _PARAM0_ is _PARAM1__PARAM2_"),
_("Position"),
"res/conditions/position24.png",
"res/conditions/position.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsSimple();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Y position"))
.MarkAsSimple()
.SetManipulatedType("number");
obj.AddAction("MettreY",
_("Y position of an object"),
_("Change the Y position of an object."),
_("the Y position"),
_("Do _PARAM1__PARAM2_ to the Y position of _PARAM0_"),
_("Position"),
"res/actions/position24.png",
"res/actions/position.png")
.AddParameter("object", _("Object"))
.UseStandardOperatorParameters("number")
.MarkAsSimple();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsSimple()
.SetManipulatedType("number");
obj.AddAction("MettreXY",
_("Position of an object"),
_("Change the position of an object."),
_("Change the position of _PARAM0_: _PARAM1_ _PARAM2_ (x "
"axis), _PARAM3_ _PARAM4_ (y axis)"),
_("Position"),
"res/actions/position24.png",
"res/actions/position.png")
obj.AddAction(
"MettreXY",
_("Position of an object"),
_("Change the position of an object."),
_("Do _PARAM1__PARAM2_;_PARAM3__PARAM4_ to the position of _PARAM0_"),
_("Position"),
"res/actions/position24.png",
"res/actions/position.png")
.AddParameter("object", _("Object"))
.AddParameter("operator", _("Modification's sign"))
@@ -110,13 +117,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("SetAngle",
_("Angle"),
_("Change the angle of rotation of an object."),
_("the angle"),
_("Do _PARAM1__PARAM2_ to angle of _PARAM0_"),
_("Angle"),
"res/actions/direction24.png",
"res/actions/direction.png")
.AddParameter("object", _("Object"))
.UseStandardOperatorParameters("number");
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("Rotate",
_("Rotate"),
@@ -143,8 +152,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle to rotate towards (in degrees)"))
.AddParameter("expression", _("Angular speed (in degrees per second)"))
.SetParameterLongDescription(_("Enter 0 for an immediate rotation."))
.AddParameter(
"expression",
_("Angular speed (in degrees per second) (0 for immediate rotation)"))
.AddCodeOnlyParameter("currentScene", "");
obj.AddAction(
@@ -160,8 +170,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("X position"))
.AddParameter("expression", _("Y position"))
.AddParameter("expression", _("Angular speed (in degrees per second)"))
.SetParameterLongDescription(_("Enter 0 for an immediate rotation."))
.AddParameter(
"expression",
_("Angular speed (in degrees per second) (0 for immediate rotation)"))
.AddCodeOnlyParameter("currentScene", "")
.MarkAsAdvanced();
@@ -239,7 +250,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("Arreter",
_("Stop the object"),
_("Stop the object by deleting all of its forces."),
_("Stop _PARAM0_ (remove all forces)"),
_("Stop object _PARAM0_"),
_("Movement"),
"res/actions/arreter24.png",
"res/actions/arreter.png")
@@ -250,7 +261,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("Delete",
_("Delete an object"),
_("Delete the specified object."),
_("Delete _PARAM0_"),
_("Delete object _PARAM0_"),
_("Objects"),
"res/actions/delete24.png",
"res/actions/delete.png")
@@ -262,13 +273,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("ChangePlan",
_("Z order"),
_("Modify the Z-order of an object"),
_("the z-order"),
_("Do _PARAM1__PARAM2_ to Z-order of _PARAM0_"),
_("Z order"),
"res/actions/planicon24.png",
"res/actions/planicon.png")
.AddParameter("object", _("Object"))
.UseStandardOperatorParameters("number");
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("ChangeLayer",
_("Layer"),
@@ -286,26 +299,31 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("ModVarObjet",
_("Modify a variable of an object"),
_("Modify the value of a variable of an object"),
_("the variable _PARAM1_"),
_("Do _PARAM2__PARAM3_ to variable _PARAM1_ of _PARAM0_"),
_("Variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("number");
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("ModVarObjetTxt",
_("Modify the text of a variable of an object"),
_("Modify the text of a variable of an object"),
_("the text of variable _PARAM1_"),
_("Variables"),
"res/actions/var24.png",
"res/actions/var.png")
obj.AddAction(
"ModVarObjetTxt",
_("Modify the text of a variable of an object"),
_("Modify the text of a variable of an object"),
_("Do _PARAM2__PARAM3_ to the text of variable _PARAM1_ of _PARAM0_"),
_("Variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardOperatorParameters("string");
.AddParameter("operator", _("Modification's sign"))
.AddParameter("string", _("Text"))
.SetManipulatedType("string");
obj.AddCondition(
"ObjectVariableChildExists",
@@ -346,7 +364,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("Cache",
_("Hide"),
_("Hide the specified object."),
_("Hide _PARAM0_"),
_("Hide the object _PARAM0_"),
_("Visibility"),
"res/actions/visibilite24.png",
"res/actions/visibilite.png")
@@ -357,7 +375,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("Montre",
_("Show"),
_("Show the specified object"),
_("Show _PARAM0_"),
_("Show object _PARAM0_"),
_("Visibility"),
"res/actions/visibilite24.png",
"res/actions/visibilite.png")
@@ -369,26 +387,30 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddCondition("Angle",
_("Angle"),
_("Compare the angle of the specified object."),
_("the angle (in degrees)"),
_("Angle of _PARAM0_ is _PARAM1__PARAM2_ deg."),
_("Angle"),
"res/conditions/direction24.png",
"res/conditions/direction.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare (in degrees)"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddCondition("Plan",
_("Compare Z order"),
_("Compare the Z-order of the specified object."),
_("the z Order"),
_("Z Order of _PARAM0_ is _PARAM1__PARAM2_"),
_("Z order"),
"res/conditions/planicon24.png",
"res/conditions/planicon.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Z order"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddCondition("Layer",
_("Compare layer"),
@@ -405,7 +427,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddCondition("Visible",
_("Visibility of an object"),
_("Check if an object is visible."),
_("_PARAM0_ is visible (not marked as hidden)"),
_("The object _PARAM0_ is visible"),
_("Visibility"),
"res/conditions/visibilite24.png",
"res/conditions/visibilite.png")
@@ -438,14 +460,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddCondition("Vitesse",
_("Speed"),
_("Compare the overall speed of an object"),
_("the overall speed"),
_("Overall speed of _PARAM0_ is _PARAM1__PARAM2_"),
_("Movement"),
"res/conditions/vitesse24.png",
"res/conditions/vitesse.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Speed"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddCondition("AngleOfDisplacement",
_("Angle of movement"),
@@ -464,26 +488,31 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddCondition("VarObjet",
_("Value of an object's variable"),
_("Compare the value of a variable of an object."),
_("the variable _PARAM1_"),
_("Variable _PARAM1_ of _PARAM0_ is _PARAM2__PARAM3_"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters("number");
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.SetManipulatedType("number");
obj.AddCondition("VarObjetTxt",
_("Text of an object's variable"),
_("Compare the text of a variable of an object."),
_("the text of variable _PARAM1_"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
obj.AddCondition(
"VarObjetTxt",
_("Text of an object's variable"),
_("Compare the text of a variable of an object."),
_("The text of variable _PARAM1_ of _PARAM0_ is _PARAM2__PARAM3_"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("object", _("Object"))
.AddParameter("objectvar", _("Variable"))
.UseStandardRelationalOperatorParameters("string");
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("string", _("Text to test"))
.SetManipulatedType("string");
obj.AddCondition("VarObjetDef",
_("Variable defined"),
@@ -633,23 +662,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Y position of the point"))
.MarkAsSimple();
extension
.AddCondition("SourisSurObjet",
_("The cursor/touch is on an object"),
_("Test if the cursor is over an object, or if the object "
"is being touched."),
_("The cursor/touch is on _PARAM0_"),
_("Mouse and touch"),
"res/conditions/surObjet24.png",
"res/conditions/surObjet.png")
.AddParameter("objectList", _("Object"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("yesorno", _("Accurate test (yes by default)"), "", true)
.SetDefaultValue("yes")
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsSimple();
obj.AddCondition(
"ObjectTimer",
_("Value of a timer"),
@@ -894,13 +906,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/create24.png",
"res/actions/create.png")
.AddCodeOnlyParameter("objectsContext", "")
.AddParameter("objectListWithoutPicking", _("Group of potential objects"))
.SetParameterLongDescription(
_("Group containing objects that can be created by the action."))
.AddParameter("string", _("Name of the object to create"))
.SetParameterLongDescription(_(
"Text representing the name of the object to create. If no objects "
"with this name are found in the group, no object will be created."))
.AddParameter(
"objectListWithoutPicking",
_("Groups containing objects that can be created by the action"))
.AddParameter("string",
_("Text representing the name of the object to create"))
.AddParameter("expression", _("X position"))
.AddParameter("expression", _("Y position"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
@@ -909,12 +919,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
extension
.AddAction("AjoutObjConcern",
_("Pick all instances"),
_("Pick all instances of the specified object(s). When you "
"pick all instances, "
_("Pick all objects"),
_("Pick all the specified objects. When you pick all objects, "
"the next conditions and actions of this event work on all "
"of them."),
_("Pick all instances of _PARAM1_"),
_("Pick all _PARAM1_ objects"),
_("Objects"),
"res/actions/add24.png",
"res/actions/add.png")
@@ -1036,13 +1045,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"compare that number to a value. If previous conditions on the "
"objects have not been used, this condition counts how many of "
"these objects exist in the current scene."),
_("the number of _PARAM0_ objects"),
_("The number of _PARAM0_ objects is _PARAM1__PARAM2_"),
_("Objects"),
"res/conditions/nbObjet24.png",
"res/conditions/nbObjet.png")
.AddParameter("objectList", _("Object"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsSimple();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.MarkAsSimple()
.SetManipulatedType("number");
extension
.AddCondition(
@@ -1102,14 +1113,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Ray source Y position"))
.AddParameter("expression", _("Ray angle (in degrees)"))
.AddParameter("expression", _("Ray maximum distance (in pixels)"))
.AddParameter("scenevar", _("Result X position scene variable"))
.SetParameterLongDescription(
_("Scene variable where to store the X position of the intersection. "
"If no intersection is found, the variable won't be changed."))
.AddParameter("scenevar", _("Result Y position scene variable"))
.SetParameterLongDescription(
_("Scene variable where to store the Y position of the intersection. "
"If no intersection is found, the variable won't be changed."))
.AddParameter(
"scenevar",
_("Variable where to store the X position of the intersection"))
.AddParameter(
"scenevar",
_("Variable where to store the Y position of the intersection"))
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsAdvanced();
@@ -1132,14 +1141,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Ray source Y position"))
.AddParameter("expression", _("Ray target X position"))
.AddParameter("expression", _("Ray target Y position"))
.AddParameter("scenevar", _("Result X position scene variable"))
.SetParameterLongDescription(
_("Scene variable where to store the X position of the intersection. "
"If no intersection is found, the variable won't be changed."))
.AddParameter("scenevar", _("Result Y position scene variable"))
.SetParameterLongDescription(
_("Scene variable where to store the Y position of the intersection. "
"If no intersection is found, the variable won't be changed."))
.AddParameter(
"scenevar",
_("Variable where to store the X position of the intersection"))
.AddParameter(
"scenevar",
_("Variable where to store the Y position of the intersection"))
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsAdvanced();

View File

@@ -24,73 +24,86 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddCondition("CameraX",
_("Camera center X position"),
_("Compare the X position of the center of a camera."),
_("the X position of camera _PARAM4_ (layer: _PARAM3_)"),
_("X position of camera _PARAM4_ is _PARAM1__PARAM2_ "
"(layer: _PARAM3_)"),
_("Layers and cameras"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardRelationalOperatorParameters("number")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0")
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition("CameraY",
_("Camera center Y position"),
_("Compare the Y position of the center of a camera."),
_("the Y position of camera _PARAM4_ (layer: _PARAM3_)"),
_("The Y position of camera _PARAM4_ is _PARAM1__PARAM2_ "
"(layer: _PARAM3_)"),
_("Layers and cameras"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardRelationalOperatorParameters("number")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"))
.SetDefaultValue("0")
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction(
"CameraX",
_("Camera center X position"),
_("Change the X position of the center of the specified camera."),
_("the X position of camera _PARAM4_ (layer: _PARAM3_)"),
_("Do _PARAM1__PARAM2_ to X position of camera _PARAM4_ (layer: "
"_PARAM3_)"),
_("Layers and cameras"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardOperatorParameters("number")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0")
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction(
"CameraY",
_("Camera center Y position"),
_("Change the Y position of the center of the specified camera."),
_("the Y position of camera _PARAM4_ (layer: _PARAM3_)"),
_("Do _PARAM1__PARAM2_ to Y position of camera _PARAM4_ (layer: "
"_PARAM3_)"),
_("Layers and cameras"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardOperatorParameters("number")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0")
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition("CameraWidth",
_("Width of a camera"),
_("Test the width of a camera of a layer"),
_("the width of camera _PARAM2_ of layer _PARAM1_"),
_("The width of camera _PARAM2_ of layer _PARAM1_ is "
"_PARAM3__PARAM4_"),
_("Layers and cameras"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
@@ -98,14 +111,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition("CameraHeight",
_("Height of a camera"),
_("Test the height of a camera of a layer"),
_("the height of camera _PARAM2_ of layer _PARAM1_"),
_("The height of camera _PARAM2_ of layer _PARAM1_ is "
"_PARAM3__PARAM4_"),
_("Layers and cameras"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
@@ -113,40 +129,48 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition("CameraAngle",
_("Angle of a camera of a layer"),
_("Test a camera angle."),
_("the angle of camera (layer: _PARAM3_, camera: _PARAM4_)"),
_("Angle of camera is _PARAM1__PARAM2_ (layer: _PARAM3_, "
"camera: _PARAM4_)"),
_("Layers and cameras"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardRelationalOperatorParameters("number")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0")
.MarkAsAdvanced();
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction("RotateCamera",
_("Change camera angle"),
_("This action modifies the angle of a camera in the "
"specified layer."),
_("the angle of camera (layer: _PARAM3_, camera: _PARAM4_)"),
_("Do _PARAM1__PARAM2_ to angle of camera (layer: _PARAM3_, "
"camera: _PARAM4_)"),
_("Layers and cameras"),
"res/actions/camera24.png",
"res/actions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardOperatorParameters("number")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0");
.SetDefaultValue("0")
.SetManipulatedType("number");
extension
.AddAction("AddCamera",
@@ -356,10 +380,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
extension
.AddAction(
"SetLayerEffectParameter",
_("Effect parameter (number)"),
_("Change the value of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Effect parameter"),
_("Change the parameter of an effect"),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
_("Layers and cameras/Effects"),
"res/conditions/camera24.png",
@@ -373,13 +395,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.MarkAsAdvanced();
extension
.AddAction(
"SetLayerEffectStringParameter",
_("Effect parameter (string)"),
_("Change the value (string) of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM3_ to _PARAM4_ for effect _PARAM2_ of layer _PARAM1_"),
.AddCondition(
"LayerEffectEnabled",
_("Layer effect is enabled"),
_("The effect on a layer is enabled"),
_("Effect _PARAM2_ on layer _PARAM1_ is enabled"),
_("Layers and cameras/Effects"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
@@ -387,18 +407,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("string", _("Effect"))
.AddParameter("string", _("Parameter name"))
.AddParameter("string", _("New value"))
.MarkAsAdvanced();
extension
.AddAction(
"SetLayerEffectBooleanParameter",
_("Effect parameter (enable or disable)"),
_("Enable or disable a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Enable _PARAM3_ for effect _PARAM2_ of layer _PARAM1_: _PARAM4_"),
"EnableLayerEffect",
_("Enable layer effect"),
_("Enable an effect on a layer"),
_("Enable effect _PARAM2_ on layer _PARAM1_: _PARAM3_"),
_("Layers and cameras/Effects"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
@@ -406,36 +422,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("string", _("Effect"))
.AddParameter("string", _("Parameter name"))
.AddParameter("yesorno", _("Enable this parameter"))
.MarkAsAdvanced();
extension
.AddCondition("LayerEffectEnabled",
_("Layer effect is enabled"),
_("The effect on a layer is enabled"),
_("Effect _PARAM2_ on layer _PARAM1_ is enabled"),
_("Layers and cameras/Effects"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("string", _("Effect"))
.MarkAsAdvanced();
extension
.AddAction("EnableLayerEffect",
_("Enable layer effect"),
_("Enable an effect on a layer"),
_("Enable effect _PARAM2_ on layer _PARAM1_: _PARAM3_"),
_("Layers and cameras/Effects"),
"res/conditions/camera24.png",
"res/conditions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("string", _("Effect"))
.AddParameter("yesorno", _("Enable"), "", true)
.MarkAsAdvanced();
@@ -444,15 +430,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"LayerTimeScale",
_("Layer time scale"),
_("Compare the time scale applied to the objects of the layer."),
_("the time scale of layer _PARAM1_"),
_("The time scale of layer _PARAM1_ is _PARAM2__PARAM3_"),
_("Layers and cameras/Time"),
"res/conditions/time24.png",
"res/conditions/time.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction(

View File

@@ -98,7 +98,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddAction(
"LireFichierExp",
_("Read a value"),
_("Read the value saved in the specified element and store it in a scene"
_("Read the value saved in the specified element and store it in a "
"variable.\nSpecify the structure leading to the element using / "
"(example : Root/Level/Current)\nSpaces are forbidden in element "
"names."),
@@ -115,7 +115,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddAction(
"LireFichierTxt",
_("Read a text"),
_("Read the text saved in the specified element and store it in a scene "
_("Read the text saved in the specified element and store it in a "
"variable.\nSpecify the structure leading to the element using / "
"(example : Root/Level/Current)\nSpaces are forbidden in element "
"names."),

View File

@@ -37,14 +37,17 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsJoystickExtension(
.AddCondition("JoystickAxis",
_("Value of an axis of a joystick"),
_("Test the value of an axis of a joystick."),
_("the value of the axis _PARAM2_ of joystick _PARAM1_"),
_("The value of the axis _PARAM2_ of joystick _PARAM1_ is "
"_PARAM3__PARAM4_"),
_("Joystick"),
"res/conditions/joystick24.png",
"res/conditions/joystick.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Joystick number (first joystick: 0)"))
.AddParameter("joyaxis", _("Axis"))
.UseStandardRelationalOperatorParameters("number");
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.SetManipulatedType("number");
extension
.AddAction(

View File

@@ -21,16 +21,6 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
#if defined(GD_IDE_ONLY)
extension
.AddExpression("clamp",
_("Clamp (restrict a value to a given range)"),
_("Restrict a value to a given range"),
_("Mathematical tools"),
"res/mathfunction.png")
.AddParameter("expression", _("Value"))
.AddParameter("expression", _("Min"))
.AddParameter("expression", _("Max"));
extension
.AddExpression("AngleDifference",
_("Difference between two angles"),
@@ -332,7 +322,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("trunc",
_("Truncation"),
_("Truncate a number"),
_("Troncate a number"),
_("Mathematical tools"),
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));

View File

@@ -21,6 +21,23 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
.SetExtensionHelpPath("/all-features/mouse-touch");
#if defined(GD_IDE_ONLY)
extension
.AddCondition("SourisSurObjet",
_("The cursor/touch is on an object"),
_("Test if the cursor is over an object, or if the object "
"is being touched."),
_("The cursor/touch is on _PARAM0_"),
_("Mouse and touch"),
"res/conditions/surObjet24.png",
"res/conditions/surObjet.png")
.AddParameter("objectList", _("Object"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("yesorno", _("Accurate test (yes by default)"), "", true)
.SetDefaultValue("yes")
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsSimple();
extension
.AddCondition(
"IsMouseWheelScrollingUp",
@@ -147,31 +164,35 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
.AddCondition("SourisX",
_("Cursor X position"),
_("Compare the X position of the cursor or of a touch."),
_("the cursor X position"),
_("Cursor X position is _PARAM1__PARAM2_"),
_("Mouse and touch"),
"res/conditions/mouse24.png",
"res/conditions/mouse.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardRelationalOperatorParameters("number")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("X position"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0");
.SetDefaultValue("0")
.SetManipulatedType("number");
extension
.AddCondition("SourisY",
_("Cursor Y position"),
_("Compare the Y position of the cursor or of a touch."),
_("the cursor Y position"),
_("Cursor Y position is _PARAM1__PARAM2_"),
_("Mouse and touch"),
"res/conditions/mouse24.png",
"res/conditions/mouse.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardRelationalOperatorParameters("number")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Y position"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0");
.SetDefaultValue("0")
.SetManipulatedType("number");
extension
.AddCondition("SourisBouton",
@@ -203,33 +224,37 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
.AddCondition("TouchX",
_("Touch X position"),
_("Compare the X position of a specific touch."),
_("the touch #_PARAM1_ X position"),
_("Touch #_PARAM1_ X position is _PARAM2__PARAM3_"),
_("Mouse and touch/Multitouch"),
"res/conditions/touch24.png",
"res/conditions/touch.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Touch identifier"))
.UseStandardRelationalOperatorParameters("number")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("X position"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0");
.SetDefaultValue("0")
.SetManipulatedType("number");
extension
.AddCondition("TouchY",
_("Touch Y position"),
_("Compare the Y position of a specific touch."),
_("the touch #_PARAM1_ Y position"),
_("Touch #_PARAM1_ Y position is _PARAM2__PARAM3_"),
_("Mouse and touch/Multitouch"),
"res/conditions/touch24.png",
"res/conditions/touch.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Touch identifier"))
.UseStandardRelationalOperatorParameters("number")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Y position"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.SetDefaultValue("0");
.SetDefaultValue("0")
.SetManipulatedType("number");
extension
.AddCondition(

View File

@@ -26,31 +26,29 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
"SendRequest",
_("Send a request to a web page"),
_("Send a request to the specified web page.\n\nPlease note that for "
"the web games, the game must be hosted on the same host "
"the web platform games, the game must be hosted on the same host "
"as specified below, except if the server is configured to answer "
"to all requests (cross-domain requests)."),
_("Send _PARAM3_ request to _PARAM0__PARAM1_ with body: _PARAM2_"),
_("Network"),
"res/actions/net24.png",
"res/actions/net.png")
.AddParameter("string", _("Host, with protocol"))
.SetParameterLongDescription(
_("Example: \"http://example.com/\"."))
.AddParameter("string", _("Path"))
.SetParameterLongDescription(_("Example: \"/user/123\" or \"/some-page.php\"."))
.AddParameter("string", _("Host (example: http://www.some-server.org/)"))
.AddParameter("string", _("Path to page (Example: /page.php)"))
.AddParameter("string", _("Request body content"))
.AddParameter("string", _("Method: \"POST\" or \"GET\""), "", true)
.SetParameterLongDescription(_("If empty, \"GET\" will be used."))
.AddParameter(
"string",
_("Method: \"POST\" or \"GET\" (if empty, GET will be used)"),
"",
true)
.SetDefaultValue("\"GET\"")
.AddParameter("string", _("Content type"), "", true)
.SetParameterLongDescription(
_("If empty, \"application/x-www-form-urlencoded\" will be used."))
.AddParameter("scenevar", _("Reponse scene variable"), "", true)
.SetParameterLongDescription(
_("The response of the server will be stored, as a string, in this "
"variable. If the server returns *JSON*, you may want to use the "
"action \"Convert JSON to a scene variable\" afterwards, to "
"explore the results with a *structure variable*."))
.AddParameter(
"string",
_("Content type (application/x-www-form-urlencoded by default)"),
"",
true)
.AddParameter(
"scenevar", _("Store the response in this variable"), "", true)
.MarkAsComplex();
extension
@@ -70,8 +68,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
extension
.AddAction(
"JSONToVariableStructure",
_("Convert JSON to a scene variable"),
_("Parse a JSON object and store it into a scene variable"),
_("Convert JSON to a variable"),
_("Parse a JSON object and store it into a variable"),
_("Parse JSON string _PARAM0_ and store it into variable _PARAM1_"),
_("Network"),
"res/actions/net24.png",
@@ -111,11 +109,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
extension
.AddStrExpression("ToJSON",
_("Convert scene variable to JSON"),
_("Convert a scene variable to JSON"),
_("Convert variable to JSON"),
_("Convert a variable to JSON"),
_("Conversion"),
"res/conditions/toujours24.png")
.AddParameter("scenevar", _("Scene variable to be stringified"));
.AddParameter("scenevar", _("The variable to be stringified"));
extension
.AddStrExpression("GlobalVarToJSON",

View File

@@ -91,18 +91,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
.AddCodeOnlyParameter("currentScene", "")
.MarkAsSimple();
extension
.AddCondition("SceneJustResumed",
_("Scene just resumed"),
_("The scene has just resumed after being paused."),
_("Scene just resumed"),
_("Scene"),
"res/conditions/depart24.png",
"res/conditions/depart.png")
.SetHelpPath("/interface/scene-editor/events")
.AddCodeOnlyParameter("currentScene", "")
.MarkAsSimple();
extension
.AddAction("Scene",
_("Change the scene"),

View File

@@ -31,30 +31,35 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
#if defined(GD_IDE_ONLY)
obj.AddAction("Opacity",
_("Change sprite opacity"),
_("Change Sprite opacity"),
_("Change the opacity of a Sprite. 0 is fully transparent, 255 "
"is opaque (default)."),
_("the opacity"),
_("Do _PARAM1__PARAM2_ to the opacity of _PARAM0_"),
_("Visibility"),
"res/actions/opacity24.png",
"res/actions/opacity.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
.MarkAsSimple();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value (between 0 and 255)"))
.MarkAsSimple()
.SetManipulatedType("number");
obj.AddAction("ChangeAnimation",
_("Change the animation"),
_("Change the animation of the object, using the animation "
"number in the animations list."),
_("the number of the animation"),
_("Do _PARAM1__PARAM2_ to the number of current animation of "
"_PARAM0_"),
_("Animations and images"),
"res/actions/animation24.png",
"res/actions/animation.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
.MarkAsSimple();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsSimple()
.SetManipulatedType("number");
obj.AddAction("SetAnimationName",
_("Change the animation (by name)"),
@@ -75,31 +80,35 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Change the direction of the object.\nIf the object is set to "
"automatically rotate, the direction is its angle.\nIf the object "
"is in 8 directions mode, the valid directions are 0..7"),
_("the direction"),
_("Do _PARAM1__PARAM2_ to the direction of _PARAM0_"),
_("Direction"),
"res/actions/direction24.png",
"res/actions/direction.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddAction("ChangeSprite",
_("Current frame"),
_("Modify the current frame of the object"),
_("the animation frame"),
_("Do _PARAM1__PARAM2_ to animation frame of _PARAM0_"),
_("Animations and images"),
"res/actions/sprite24.png",
"res/actions/sprite.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddAction("PauseAnimation",
_("Pause the animation"),
_("Pause the animation of the object"),
_("Pause the animation of _PARAM0_"),
_("Pause the current animation of the object"),
_("Pause the current animation of _PARAM0_"),
_("Animations and images"),
"res/actions/animation24.png",
"res/actions/animation.png")
@@ -109,8 +118,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
obj.AddAction("PlayAnimation",
_("Play the animation"),
_("Play the animation of the object"),
_("Play the animation of _PARAM0_"),
_("Play the current animation of the object"),
_("Play the current animation of _PARAM0_"),
_("Animations and images"),
"res/actions/animation24.png",
"res/actions/animation.png")
@@ -123,14 +132,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Animation speed scale"),
_("Modify the animation speed scale (1 = the default speed, >1 = "
"faster and <1 = slower)."),
_("the animation speed scale"),
_("Do _PARAM1__PARAM2_ to the animation speed scale of _PARAM0_"),
_("Animations and images"),
"res/actions/animation24.png",
"res/actions/animation.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
.MarkAsSimple();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsSimple()
.SetManipulatedType("number");
obj.AddAction("TourneVersPos",
_("Rotate an object toward a position"),
@@ -151,79 +162,91 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
obj.AddAction("ChangeScale",
_("Scale"),
_("Modify the scale of the specified object."),
_("the scale"),
_("Do _PARAM1__PARAM2_ to the scale of _PARAM0_"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced();
obj.AddAction("ChangeScaleWidth",
_("Scale on X axis"),
_("Modify the scale of the width of an object."),
_("the width's scale"),
_("Do _PARAM1__PARAM2_ to the width's scale of _PARAM0_"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddAction("ChangeScaleHeight",
_("Scale on Y axis"),
_("Modify the scale of the height of an object."),
_("the height's scale"),
_("Do _PARAM1__PARAM2_ to the height's scale of _PARAM0_"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddAction("ChangeWidth",
_("Width"),
_("Change the width of a Sprite object."),
_("the width"),
_("Do _PARAM1__PARAM2_ to the width of _PARAM0_"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddAction("ChangeHeight",
_("Height"),
_("Change the height of a Sprite object."),
_("the height"),
_("Do _PARAM1__PARAM2_ to the height of _PARAM0_"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddCondition(
"Animation",
_("Current animation"),
_("Compare the number of the animation played by the object."),
_("the number of the animation"),
_("Compare the number of the current animation of the object."),
_("The number of the current animation of _PARAM0_ is "
"_PARAM1__PARAM2_"),
_("Animations and images"),
"res/conditions/animation24.png",
"res/conditions/animation.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Number to test"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddCondition("AnimationName",
_("Current animation name"),
_("Check the animation by played by the object."),
_("Check the current animation of the object."),
_("The animation of _PARAM0_ is _PARAM1_"),
_("Animations and images"),
"res/conditions/animation24.png",
@@ -239,29 +262,33 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Compare the direction of the object. If 8 direction mode is "
"activated for the sprite, the value taken for direction will be "
"from 0 to 7. Otherwise, the direction is in degrees."),
_("the direction"),
_("Direction of _PARAM0_ is _PARAM1__PARAM2_"),
_("Direction"),
"res/conditions/direction24.png",
"res/conditions/direction.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number");
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Direction to test"))
.SetManipulatedType("number");
obj.AddCondition("Sprite",
_("Current frame"),
_("Compare the index of the current frame in the animation displayed by the specified object. The first frame in an animation starts at index 0."),
_("the animation frame"),
_("Test the number of the current animation frame."),
_("The animation frame of _PARAM0_ is _PARAM1__PARAM2_"),
_("Animations and images"),
"res/conditions/sprite24.png",
"res/conditions/sprite.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Animation frame to test"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddCondition("AnimStopped",
_("Animation paused"),
_("Check if the animation of an object is paused."),
_("Test if the animation of an object is paused"),
_("The animation of _PARAM0_ is paused"),
_("Animations and images"),
"res/conditions/animation24.png",
@@ -285,52 +312,62 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
obj.AddCondition("ScaleWidth",
_("Scale on X axis"),
_("Compare the scale of the width of an object."),
_("the width's scale"),
_("The width's scale of _PARAM0_ is _PARAM1__PARAM2_"),
_("Size"),
"res/conditions/scaleWidth24.png",
"res/conditions/scaleWidth.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddCondition("ScaleHeight",
_("Scale on Y axis"),
_("Compare the scale of the height of an object."),
_("the height's scale"),
_("The height's scale of _PARAM0_ is _PARAM1__PARAM2_"),
_("Size"),
"res/conditions/scaleHeight24.png",
"res/conditions/scaleHeight.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddCondition("Opacity",
_("Opacity"),
_("Compare the opacity of a Sprite, between 0 (fully "
"transparent) to 255 (opaque)."),
_("the opacity"),
_("The opacity of _PARAM0_ is _PARAM1__PARAM2_"),
_("Visibility"),
"res/conditions/opacity24.png",
"res/conditions/opacity.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
.MarkAsSimple();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.MarkAsSimple()
.SetManipulatedType("number");
obj.AddCondition(
"BlendMode",
_("Blend mode"),
_("Compare the number of the blend mode currently used by an object"),
_("the number of the current blend mode"),
_("The number of the current blend mode of _PARAM0_ is "
"_PARAM1__PARAM2_"),
_("Effects"),
"res/conditions/opacity24.png",
"res/conditions/opacity.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression",
_("Value to compare (0: Alpha, 1: Add, 2: Multiply, 3: None)"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddAction("CopyImageOnImageOfSprite",
_("Copy an image on the current one of an object"),
@@ -380,7 +417,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
obj.AddAction("ChangeBlendMode",
_("Blend mode"),
_("Change the number of the blend mode of an object.\nThe "
"default blend mode is 0 (Normal)."),
"default blend mode is 0 (Alpha)."),
_("Change Blend mode of _PARAM0_ to _PARAM1_"),
_("Effects"),
"res/actions/color24.png",
@@ -388,7 +425,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("expression",
_("Mode (0: Normal, 1: Add, 2: Multiply, 3: Screen)"))
_("Mode (0 : Alpha, 1 : Add, 2 : Multiply, 3 : None)"))
.MarkAsSimple();
obj.AddAction("FlipX",

View File

@@ -38,13 +38,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
.AddCondition("TimeScale",
_("Time scale"),
_("Test the time scale."),
_("the time scale"),
_("The time scale is _PARAM1__PARAM2_"),
_("Timers and time"),
"res/conditions/time24.png",
"res/conditions/time.png")
.AddCodeOnlyParameter("currentScene", "")
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition("TimerPaused",
@@ -121,16 +123,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
extension
.AddExpression("TimeDelta",
_("Time elapsed since the last frame"),
_("Time elapsed since the last frame rendered on screen"),
_("Time elapsed since the last image"),
_("Time elapsed since the last image"),
_("Time"),
"res/actions/time.png")
.AddCodeOnlyParameter("currentScene", "");
extension
.AddExpression("TempsFrame",
_("Time elapsed since the last frame"),
_("Time elapsed since the last frame rendered on screen"),
_("Time elapsed since the last image"),
_("Time elapsed since the last image"),
_("Time"),
"res/actions/time.png")
.SetHidden()
@@ -138,8 +140,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
extension
.AddExpression("ElapsedTime",
_("Time elapsed since the last frame"),
_("Time elapsed since the last frame rendered on screen"),
_("Time elapsed since the last image"),
_("Time elapsed since the last image"),
_("Time"),
"res/actions/time.png")
.SetHidden()

View File

@@ -25,23 +25,27 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.AddCondition("VarScene",
_("Value of a scene variable"),
_("Compare the value of a scene variable."),
_("the scene variable _PARAM0_"),
_("Scene variable _PARAM0_ is _PARAM1__PARAM2_"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardRelationalOperatorParameters("number");
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.SetManipulatedType("number");
extension
.AddCondition("VarSceneTxt",
_("Text of a scene variable"),
_("Compare the text of a scene variable."),
_("the text of scene variable _PARAM0_"),
_("The text of scene variable _PARAM0_ is _PARAM1__PARAM2_"),
_("Variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardRelationalOperatorParameters("string");
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("string", _("Text to compare"))
.SetManipulatedType("string");
extension
.AddCondition(
@@ -85,26 +89,30 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.AddCondition("VarGlobal",
_("Value of a global variable"),
_("Compare the value of a global variable."),
_("the global variable _PARAM0_"),
_("Global variable _PARAM0_ is _PARAM1__PARAM2_"),
_("Variables/Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value to compare"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddCondition(
"VarGlobalTxt",
_("Text of a global variable"),
_("Compare the text of a global variable."),
_("the text of the global variable _PARAM0_"),
_("The text of the global variable _PARAM0_ is _PARAM1__PARAM2_"),
_("Variables/Global variables"),
"res/conditions/var24.png",
"res/conditions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardRelationalOperatorParameters("string")
.MarkAsAdvanced();
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("string", _("Text to compare"))
.MarkAsAdvanced()
.SetManipulatedType("string");
extension
.AddCondition("VarGlobalDef",
@@ -123,48 +131,56 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
.AddAction("ModVarScene",
_("Value of a scene variable"),
_("Modify the value of a scene variable."),
_("the scene variable _PARAM0_"),
_("Do _PARAM1__PARAM2_ to scene variable _PARAM0_"),
_("Variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardOperatorParameters("number");
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
extension
.AddAction("ModVarSceneTxt",
_("String of a scene variable"),
_("Modify the text of a scene variable."),
_("the text of scene variable _PARAM0_"),
_("Do _PARAM1__PARAM2_ to the text of scene variable _PARAM0_"),
_("Variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("scenevar", _("Variable"))
.UseStandardOperatorParameters("string");
.AddParameter("operator", _("Modification's sign"))
.AddParameter("string", _("Text"))
.SetManipulatedType("string");
extension
.AddAction("ModVarGlobal",
_("Value of a global variable"),
_("Modify the value of a global variable"),
_("the global variable _PARAM0_"),
_("Do _PARAM1__PARAM2_ to global variable _PARAM0_"),
_("Variables/Global variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardOperatorParameters("number")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
extension
.AddAction(
"ModVarGlobalTxt",
_("String of a global variable"),
_("Modify the text of a global variable."),
_("the text of global variable _PARAM0_"),
_("Do _PARAM1__PARAM2_ to the text of global variable _PARAM0_"),
_("Variables/Global variables"),
"res/actions/var24.png",
"res/actions/var.png")
.AddParameter("globalvar", _("Variable"))
.UseStandardOperatorParameters("string")
.MarkAsAdvanced();
.AddParameter("operator", _("Modification's sign"))
.AddParameter("string", _("Text"))
.MarkAsAdvanced()
.SetManipulatedType("string");
extension
.AddAction("VariableRemoveChild",

View File

@@ -27,7 +27,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
_("De/activate fullscreen"),
_("This action activates or deactivates fullscreen."),
_("Activate fullscreen: _PARAM1_ (keep aspect ratio: _PARAM2_)"),
_("Game's window and resolution"),
_("Game's window"),
"res/actions/fullscreen24.png",
"res/actions/fullscreen.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -41,11 +41,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetWindowMargins",
_("Change the window's margins"),
_("This action changes the margins, in pixels, between the "
"game frame and the window borders."),
_("This action changes the margins, in pixels, of the game's "
"window."),
_("Set margins of game window to "
"_PARAM1_;_PARAM2_;_PARAM3_;_PARAM4_"),
_("Game's window and resolution"),
_("Game's window"),
"res/actions/window24.png",
"res/actions/window.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -55,93 +55,28 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
.AddParameter("expression", _("Left"));
extension
.AddAction("SetGameResolutionSize",
_("Change the resolution of the game"),
_("Changes the resolution of the game, effectively changing "
"the game area size. This won't change the size of the "
"window in which the game is running."),
_("Set game resolution to _PARAM1_x_PARAM2_"),
_("Game's window and resolution"),
.AddAction("SetWindowSize",
_("Change the size of the window"),
_("This action changes the size of the game's window."),
_("Change window size: _PARAM1_x_PARAM2_"),
_("Game's window"),
"res/actions/window24.png",
"res/actions/window.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Width"))
.AddParameter("expression", _("Height"));
extension
.AddAction(
"SetWindowSize",
_("Change the size of the game window"),
_("This action changes the size of the game window. Note that this "
"will only work on platform supporting this operation: games "
"running in browsers or on mobile phones can not update their "
"window size. Game resolution can still be updated."),
_("Set game window size to _PARAM1_x_PARAM2_ (also update game "
"resolution: _PARAM3_)"),
_("Game's window and resolution"),
"res/actions/window24.png",
"res/actions/window.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Width"))
.AddParameter("expression", _("Height"))
.AddParameter("yesorno",
_("Also update the game resolution? If not, the game will "
"be stretched or reduced to fit in the window."));
extension
.AddAction("CenterWindow",
_("Center the game window on the screen"),
_("This action centers the game window on the screen. This "
"only works on Windows, macOS and Linux (not when the game "
"is executed in a web-browser or on iOS/Android)."),
_("Center the game window"),
_("Game's window and resolution"),
"res/actions/window24.png",
"res/actions/window.png")
.AddCodeOnlyParameter("currentScene", "");
extension
.AddAction("SetGameResolutionResizeMode",
_("Change the game resolution resize mode"),
_("Set if the width or the height of the game resolution "
"should be changed to fit the game window - or if the game "
"resolution should not be updated automatically."),
_("Set game resolution resize mode to _PARAM1_"),
_("Game's window and resolution"),
"res/actions/window24.png",
"res/actions/window.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("stringWithSelector",
_("Resize mode"),
"[\"adaptWidth\", \"adaptHeight\", \"\"]",
false)
.SetParameterLongDescription(
_("Empty to disable resizing. \"adaptWidth\" will update the game "
"width to fit in the window or screen. \"adaptHeight\" will do the "
"same but with the game height."));
extension
.AddAction("SetAdaptGameResolutionAtRuntime",
_("Automatically adapt the game resolution"),
_("Set if the game resolution should be automatically adapted "
"when the game window or screen size change. This will only "
"be the case if the game resolution resize mode is "
"configured to adapt the width or the height of the game."),
_("Automatically adapt the game resolution: _PARAM1_"),
_("Game's window and resolution"),
"res/actions/window24.png",
"res/actions/window.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("yesorno",
_("Update resolution during the game to fit the screen or "
"window size?"));
.AddParameter(
"yesorno",
_("Do you want to use this size as the default size for new scene "
"cameras\?\n(Yes to change the size of the game's viewable "
"area,\nNo to stretch the game to the window's size)."));
extension
.AddAction("SetWindowIcon",
_("Change the window's icon"),
_("This action changes the icon of the game's window."),
_("Use _PARAM1_ as the icon for the game's window."),
_("Game's window and resolution"),
_("Game's window"),
"res/actions/window24.png",
"res/actions/window.png")
.AddCodeOnlyParameter("currentScene", "")
@@ -152,7 +87,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
_("Change the window's title"),
_("This action changes the title of the game's window."),
_("Change window title to _PARAM1_"),
_("Game's window and resolution"),
_("Game's window"),
"res/actions/window24.png",
"res/actions/window.png")
.AddCodeOnlyParameter("currentScene", "")

View File

@@ -59,8 +59,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddCondition(
group,
icon,
smallicon)
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
.SetHelpPath(GetHelpPath());
return conditionsInfos[nameWithNamespace];
#endif
}
@@ -84,8 +83,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddAction(
group,
icon,
smallicon)
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
.SetHelpPath(GetHelpPath());
return actionsInfos[nameWithNamespace];
#endif
}
@@ -109,8 +107,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedCondition(
group,
icon,
smallicon)
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
.SetHelpPath(GetHelpPath());
return conditionsInfos[nameWithNamespace];
#endif
}
@@ -134,8 +131,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedAction(
group,
icon,
smallicon)
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
.SetHelpPath(GetHelpPath());
return actionsInfos[nameWithNamespace];
#endif
}

View File

@@ -1,25 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "EffectMetadata.h"
namespace gd {
EffectMetadata::EffectMetadata(const gd::String& type_) : type(type_) {}
EffectMetadata& EffectMetadata::SetIncludeFile(const gd::String& includeFile) {
includeFiles.clear();
includeFiles.push_back(includeFile);
return *this;
}
EffectMetadata& EffectMetadata::AddIncludeFile(const gd::String& includeFile) {
if (std::find(includeFiles.begin(), includeFiles.end(), includeFile) ==
includeFiles.end())
includeFiles.push_back(includeFile);
return *this;
}
} // namespace gd

View File

@@ -1,121 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef EFFECTMETADATA_H
#define EFFECTMETADATA_H
#include <functional>
#include <map>
#include <memory>
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"
namespace gd {
/**
* \brief Contains user-friendly information about an effect.
*
* \ingroup Events
*/
class GD_CORE_API EffectMetadata {
public:
/**
* \brief Construct an effect metadata, with the given type
*/
EffectMetadata(const gd::String& type_);
/**
* \brief Default constructor, only used for initializing `badEffectMetadata`.
*/
EffectMetadata() {}
virtual ~EffectMetadata(){};
/**
* \brief Set the name shown to the user.
*/
EffectMetadata& SetFullName(const gd::String& fullname_) {
fullname = fullname_;
return *this;
};
/**
* \brief Set the description shown to the user.
*/
EffectMetadata& SetDescription(const gd::String& description_) {
description = description_;
return *this;
};
/**
* Set the help path of the effect, relative to the documentation root.
*/
EffectMetadata& SetHelpPath(const gd::String& path) {
helpPath = path;
return *this;
}
/**
* \brief Clear any existing include file and add the specified include file.
*/
EffectMetadata& SetIncludeFile(const gd::String& includeFile);
/**
* \brief Add a file to the already existing include files.
*/
EffectMetadata& AddIncludeFile(const gd::String& includeFile);
/**
* \brief Return a reference to the properties of this effect.
*/
std::map<gd::String, gd::PropertyDescriptor>& GetProperties() {
return properties;
}
/**
* \brief Return a (const) reference to the properties of this effect.
*/
const std::map<gd::String, gd::PropertyDescriptor>& GetProperties() const {
return properties;
}
/**
* \brief Get the help path of the effect, relative to the documentation root.
*/
const gd::String& GetHelpPath() const { return helpPath; }
/**
* \brief Get the type of the effect (its internal name, like "BlackAndWhite").
*/
const gd::String& GetType() const { return type; }
/**
* \brief Get the user facing name of the effect (like "Black and White").
*/
const gd::String& GetFullName() const { return fullname; }
/**
* \brief Get the user friendly description of the effect.
*/
const gd::String& GetDescription() const { return description; }
/**
* \brief Get the required include files for this effect.
*/
const std::vector<gd::String>& GetIncludeFiles() const {
return includeFiles;
}
private:
gd::String extensionNamespace;
gd::String type;
gd::String helpPath;
gd::String fullname;
gd::String description;
std::vector<gd::String> includeFiles;
std::map<gd::String, gd::PropertyDescriptor> properties;
};
} // namespace gd
#endif // EFFECTMETADATA_H

View File

@@ -200,17 +200,7 @@ class GD_CORE_API ExpressionMetadata {
* \see AddParameter
*/
ExpressionMetadata& SetDefaultValue(gd::String defaultValue_) {
if (!parameters.empty()) parameters.back().SetDefaultValue(defaultValue_);
return *this;
};
/**
* \brief Set the long description shown in the editor for the last added parameter.
*
* \see AddParameter
*/
ExpressionMetadata &SetParameterLongDescription(gd::String longDescription) {
if (!parameters.empty()) parameters.back().SetLongDescription(longDescription);
if (!parameters.empty()) parameters.back().defaultValue = defaultValue_;
return *this;
};

View File

@@ -3,24 +3,23 @@
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "InstructionMetadata.h"
#include <algorithm>
#include "GDCore/CommonTools.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Localization.h"
#include "InstructionMetadata.h"
namespace gd {
InstructionMetadata::InstructionMetadata()
: sentence("Unknown or unsupported instruction"), // Avoid translating this
// string, so that it's
// safe and *fast* to use
// a InstructionMetadata.
: sentence(
"Unknown or unsupported instruction"), // Avoid translating this
// string, so that it's safe
// and *fast* to use a
// InstructionMetadata.
canHaveSubInstructions(false),
hidden(true),
usageComplexity(5),
isPrivate(false),
isObjectInstruction(false),
isBehaviorInstruction(false) {}
isPrivate(false) {}
InstructionMetadata::InstructionMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
@@ -41,9 +40,8 @@ InstructionMetadata::InstructionMetadata(const gd::String& extensionNamespace_,
extensionNamespace(extensionNamespace_),
hidden(false),
usageComplexity(5),
isPrivate(false),
isObjectInstruction(false),
isBehaviorInstruction(false) {}
isPrivate(false) {
}
ParameterMetadata::ParameterMetadata() : optional(false), codeOnly(false) {}
@@ -88,82 +86,11 @@ InstructionMetadata& InstructionMetadata::AddCodeOnlyParameter(
return *this;
}
InstructionMetadata& InstructionMetadata::UseStandardOperatorParameters(
const gd::String& type) {
SetManipulatedType(type);
AddParameter("operator", _("Modification's sign"));
AddParameter(type == "number" ? "expression" : type, _("Value"));
size_t operatorParamIndex = parameters.size() - 2;
size_t valueParamIndex = parameters.size() - 1;
if (isObjectInstruction || isBehaviorInstruction) {
gd::String templateSentence =
_("Change <subject> of _PARAM0_: <operator> <value>");
sentence =
templateSentence.FindAndReplace("<subject>", sentence)
.FindAndReplace(
"<operator>",
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
.FindAndReplace("<value>",
"_PARAM" + gd::String::From(valueParamIndex) + "_");
} else {
gd::String templateSentence = _("Change <subject>: <operator> <value>");
sentence =
templateSentence.FindAndReplace("<subject>", sentence)
.FindAndReplace(
"<operator>",
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
.FindAndReplace("<value>",
"_PARAM" + gd::String::From(valueParamIndex) + "_");
}
return *this;
}
InstructionMetadata&
InstructionMetadata::UseStandardRelationalOperatorParameters(
const gd::String& type) {
SetManipulatedType(type);
AddParameter("relationalOperator", _("Sign of the test"));
AddParameter(type == "number" ? "expression" : type, _("Value to compare"));
size_t operatorParamIndex = parameters.size() - 2;
size_t valueParamIndex = parameters.size() - 1;
if (isObjectInstruction || isBehaviorInstruction) {
gd::String templateSentence = _("<subject> of _PARAM0_ <operator> <value>");
sentence =
templateSentence.FindAndReplace("<subject>", sentence)
.FindAndReplace(
"<operator>",
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
.FindAndReplace("<value>",
"_PARAM" + gd::String::From(valueParamIndex) + "_");
} else {
gd::String templateSentence = _("<subject> <operator> <value>");
sentence =
templateSentence.FindAndReplace("<subject>", sentence)
.FindAndReplace(
"<operator>",
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
.FindAndReplace("<value>",
"_PARAM" + gd::String::From(valueParamIndex) + "_");
}
return *this;
}
void ParameterMetadata::SerializeTo(SerializerElement& element) const {
element.SetAttribute("type", type);
element.SetAttribute("supplementaryInformation", supplementaryInformation);
element.SetAttribute("optional", optional);
element.SetAttribute("description", description);
element.SetAttribute("longDescription", longDescription);
element.SetAttribute("codeOnly", codeOnly);
element.SetAttribute("defaultValue", defaultValue);
element.SetAttribute("name", name);
@@ -175,7 +102,6 @@ void ParameterMetadata::UnserializeFrom(const SerializerElement& element) {
element.GetStringAttribute("supplementaryInformation");
optional = element.GetBoolAttribute("optional");
description = element.GetStringAttribute("description");
longDescription = element.GetStringAttribute("longDescription");
codeOnly = element.GetBoolAttribute("codeOnly");
defaultValue = element.GetStringAttribute("defaultValue");
name = element.GetStringAttribute("name");

View File

@@ -139,19 +139,6 @@ class GD_CORE_API ParameterMetadata {
return *this;
}
/**
* \brief Get the user friendly, long description for the parameter.
*/
const gd::String &GetLongDescription() const { return longDescription; }
/**
* \brief Set the user friendly, long description for the parameter.
*/
ParameterMetadata &SetLongDescription(const gd::String &longDescription_) {
longDescription = longDescription_;
return *this;
}
/**
* \brief Return true if the type of the parameter is "object", "objectPtr" or
* "objectList".
@@ -220,12 +207,11 @@ class GD_CORE_API ParameterMetadata {
gd::String description; ///< Description shown in editor
bool codeOnly; ///< True if parameter is relative to code generation only,
///< i.e. must not be shown in editor
gd::String defaultValue; ///< Used as a default value in editor or if an
///< optional parameter is empty.
private:
gd::String longDescription; ///< Long description shown in the editor.
gd::String defaultValue; ///< Used as a default value in editor or if an
///< optional parameter is empty.
gd::String name; ///< The name of the parameter to be used in code
///< generation. Optional.
gd::String name; ///< The name of the parameter to be used in code
///< generation. Optional.
};
/**
@@ -333,93 +319,44 @@ class GD_CORE_API InstructionMetadata {
bool IsHidden() const { return hidden; }
/**
* \brief Add a parameter to the instruction metadata.
*
* \param type One of the type handled by GDevelop. This
* \brief Add a parameter to the instruction ( condition or action )
* information class. \param type One of the type handled by GDevelop. This
* will also determine the type of the argument used when calling the function
* in the generated code.
* in the generated code. \see EventsCodeGenerator::GenerateParametersCodes
* \param description Description for parameter
* \param optionalObjectType If type is "object", this parameter will describe
* which objects are allowed. If it is empty, all objects are allowed.
* \param parameterIsOptional true if the parameter must be optional, false
* which objects are allowed. If it is empty, all objects are allowed. \param
* parameterIsOptional true if the parameter must be optional, false
* otherwise.
*
* \see EventsCodeGenerator::GenerateParametersCodes
*/
InstructionMetadata &AddParameter(const gd::String &type,
const gd::String &label,
const gd::String &description,
const gd::String &optionalObjectType = "",
bool parameterIsOptional = false);
/**
* \brief Add a parameter not displayed in editor.
*
* \param type One of the type handled by GDevelop. This will also determine
* the type of the argument used when calling the function in the generated
* code. \param supplementaryInformation Depends on `type`. For example, when
* `type == "inlineCode"`, the content of supplementaryInformation is inserted
* in the generated code.
*
* \see EventsCodeGenerator::GenerateParametersCodes
* the type of the argument used when calling the function in C++ code. \see
* EventsCodeGenerator::GenerateParametersCodes \param
* supplementaryInformation Can be used if needed. For example, when type ==
* "inlineCode", the content of supplementaryInformation is inserted in the
* generated C++ code.
*/
InstructionMetadata &AddCodeOnlyParameter(
const gd::String &type, const gd::String &supplementaryInformation);
/**
* \brief Set the default value used in editor (or if an optional parameter is
* empty during code generation) for the last added parameter.
* empty during code generation) for the latest added parameter.
*
* \see AddParameter
*/
InstructionMetadata &SetDefaultValue(const gd::String &defaultValue_) {
if (!parameters.empty()) parameters.back().SetDefaultValue(defaultValue_);
InstructionMetadata &SetDefaultValue(gd::String defaultValue_) {
if (!parameters.empty()) parameters.back().defaultValue = defaultValue_;
return *this;
};
/**
* \brief Set the long description shown in the editor for the last added
* parameter.
*
* \see AddParameter
*/
InstructionMetadata &SetParameterLongDescription(
const gd::String &longDescription) {
if (!parameters.empty())
parameters.back().SetLongDescription(longDescription);
return *this;
};
/**
* \brief Add the default parameters for an instruction manipulating the
* specified type ("string", "number") with the default operators.
*/
InstructionMetadata &UseStandardOperatorParameters(const gd::String &type);
/**
* \brief Add the default parameters for an instruction comparing the
* specified type ("string", "number") with the default relational operators.
*/
InstructionMetadata &UseStandardRelationalOperatorParameters(
const gd::String &type);
/**
* \brief Mark the instruction as an object instruction. Automatically called
* when using `AddAction`/`AddCondition` on an `ObjectMetadata`.
*/
InstructionMetadata &SetIsObjectInstruction() {
isObjectInstruction = true;
return *this;
}
/**
* \brief Mark the instruction as a behavior instruction. Automatically called
* when using `AddAction`/`AddCondition` on a `BehaviorMetadata`.
*/
InstructionMetadata &SetIsBehaviorInstruction() {
isBehaviorInstruction = true;
return *this;
}
/**
* \brief Consider that the instruction is easy for an user to understand.
*/
@@ -488,7 +425,7 @@ class GD_CORE_API InstructionMetadata {
* obj.AddAction("String",
* _("Change the string"),
* _("Change the string of a text"),
* _("the string"),
* _("Do _PARAM1__PARAM2_ to the string of _PARAM0_"),
* _("Text"),
* "CppPlatform/Extensions/text24.png",
* "CppPlatform/Extensions/text.png");
@@ -621,8 +558,6 @@ class GD_CORE_API InstructionMetadata {
int usageComplexity; ///< Evaluate the instruction from 0 (simple&easy to
///< use) to 10 (complex to understand)
bool isPrivate;
bool isObjectInstruction;
bool isBehaviorInstruction;
};
} // namespace gd

View File

@@ -8,7 +8,6 @@
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/String.h"
@@ -19,7 +18,6 @@ namespace gd {
gd::BehaviorMetadata MetadataProvider::badBehaviorInfo;
gd::ObjectMetadata MetadataProvider::badObjectInfo;
gd::EffectMetadata MetadataProvider::badEffectMetadata;
gd::InstructionMetadata MetadataProvider::badInstructionMetadata;
gd::ExpressionMetadata MetadataProvider::badExpressionMetadata;
gd::ExpressionMetadata MetadataProvider::badStrExpressionMetadata;
@@ -65,26 +63,6 @@ const ObjectMetadata& MetadataProvider::GetObjectMetadata(
return GetExtensionAndObjectMetadata(platform, objectType).GetMetadata();
}
ExtensionAndMetadata<EffectMetadata>
MetadataProvider::GetExtensionAndEffectMetadata(const gd::Platform& platform,
gd::String type) {
for (auto& extension : platform.GetAllPlatformExtensions()) {
auto objectsTypes = extension->GetExtensionEffectTypes();
for (std::size_t j = 0; j < objectsTypes.size(); ++j) {
if (objectsTypes[j] == type)
return ExtensionAndMetadata<EffectMetadata>(
*extension, extension->GetEffectMetadata(type));
}
}
return ExtensionAndMetadata<EffectMetadata>(badExtension, badEffectMetadata);
}
const EffectMetadata& MetadataProvider::GetEffectMetadata(
const gd::Platform& platform, gd::String objectType) {
return GetExtensionAndEffectMetadata(platform, objectType).GetMetadata();
}
ExtensionAndMetadata<InstructionMetadata>
MetadataProvider::GetExtensionAndActionMetadata(const gd::Platform& platform,
gd::String actionType) {

View File

@@ -10,7 +10,6 @@
namespace gd {
class BehaviorMetadata;
class ObjectMetadata;
class EffectMetadata;
class ExpressionMetadata;
class ExpressionMetadata;
class Platform;
@@ -72,12 +71,6 @@ class GD_CORE_API MetadataProvider {
static ExtensionAndMetadata<ObjectMetadata> GetExtensionAndObjectMetadata(
const gd::Platform& platform, gd::String type);
/**
* Get the metadata about an effect, and its associated extension.
*/
static ExtensionAndMetadata<EffectMetadata> GetExtensionAndEffectMetadata(
const gd::Platform& platform, gd::String type);
/**
* Get the metadata of an action, and its associated extension.
* Works for object, behaviors and static actions.
@@ -158,12 +151,6 @@ class GD_CORE_API MetadataProvider {
static const ObjectMetadata& GetObjectMetadata(const gd::Platform& platform,
gd::String type);
/**
* Get the metadata about an effect.
*/
static const EffectMetadata& GetEffectMetadata(const gd::Platform& platform,
gd::String type);
/**
* Get the metadata of an action.
* Works for object, behaviors and static actions.
@@ -321,7 +308,6 @@ class GD_CORE_API MetadataProvider {
static PlatformExtension badExtension;
static BehaviorMetadata badBehaviorInfo;
static ObjectMetadata badObjectInfo;
static EffectMetadata badEffectMetadata;
static gd::InstructionMetadata badInstructionMetadata;
static gd::ExpressionMetadata badExpressionMetadata;
static gd::ExpressionMetadata badStrExpressionMetadata;

View File

@@ -77,8 +77,7 @@ gd::InstructionMetadata& ObjectMetadata::AddCondition(
group,
icon,
smallicon)
.SetHelpPath(GetHelpPath())
.SetIsObjectInstruction();
.SetHelpPath(GetHelpPath());
return conditionsInfos[nameWithNamespace];
#endif
}
@@ -102,8 +101,7 @@ gd::InstructionMetadata& ObjectMetadata::AddAction(
group,
icon,
smallicon)
.SetHelpPath(GetHelpPath())
.SetIsObjectInstruction();
.SetHelpPath(GetHelpPath());
return actionsInfos[nameWithNamespace];
#endif
}

View File

@@ -67,7 +67,7 @@ void ParameterMetadataTools::IterateOverParameters(
pNb < parameters.size() ? parameters[pNb].GetPlainString() : "";
const gd::String& parameterValueOrDefault =
parameterValue.empty() && parameterMetadata.optional
? parameterMetadata.GetDefaultValue()
? parameterMetadata.defaultValue
: parameterValue;
fn(parameterMetadata, parameterValueOrDefault, lastObjectName);
@@ -100,4 +100,4 @@ size_t ParameterMetadataTools::GetObjectParameterIndexFor(
return gd::String::npos;
}
} // namespace gd
} // namespace gd

View File

@@ -14,19 +14,19 @@ using namespace std;
namespace gd {
Platform::Platform(): enableExtensionLoadingLogs(true) {}
Platform::Platform() {}
Platform::~Platform() {}
bool Platform::AddExtension(std::shared_ptr<gd::PlatformExtension> extension) {
if (!extension) return false;
if (enableExtensionLoadingLogs) std::cout << "Loading " << extension->GetName() << "...";
std::cout << "Loading " << extension->GetName() << "...";
if (IsExtensionLoaded(extension->GetName())) {
if (enableExtensionLoadingLogs) std::cout << " (replacing existing extension)";
std::cout << " (replacing existing extension)";
RemoveExtension(extension->GetName());
}
if (enableExtensionLoadingLogs) std::cout << std::endl;
std::cout << std::endl;
extensionsLoaded.push_back(extension);

View File

@@ -156,12 +156,6 @@ class GD_CORE_API Platform {
///@}
/**
* \brief Activate or disable the logs on the standard output when
* loading an extension.
*/
void EnableExtensionLoadingLogs(bool enable) { enableExtensionLoadingLogs = enable; };
/**
* \brief Called when the IDE is about to shut down: Take this opportunity for
* erasing for example any temporary file.
@@ -180,7 +174,6 @@ class GD_CORE_API Platform {
extensionsLoaded; ///< Extensions of the platform
std::map<gd::String, CreateFunPtr>
creationFunctionTable; ///< Creation functions for objects
bool enableExtensionLoadingLogs;
};
} // namespace gd

View File

@@ -162,13 +162,6 @@ gd::BehaviorMetadata& PlatformExtension::AddBehavior(
return behaviorsInfo[nameWithNamespace];
}
gd::EffectMetadata& PlatformExtension::AddEffect(const gd::String& name) {
gd::String nameWithNamespace =
GetNameSpace().empty() ? name : GetNameSpace() + name;
effectsMetadata[nameWithNamespace] = EffectMetadata(nameWithNamespace);
return effectsMetadata[nameWithNamespace];
}
gd::EventMetadata& PlatformExtension::AddEvent(
const gd::String& name_,
const gd::String& fullname_,
@@ -214,14 +207,6 @@ std::vector<gd::String> PlatformExtension::GetExtensionObjectsTypes() const {
return objects;
}
std::vector<gd::String> PlatformExtension::GetExtensionEffectTypes() const {
std::vector<gd::String> effectNames;
for (auto& it : effectsMetadata)
effectNames.push_back(it.first);
return effectNames;
}
gd::ObjectMetadata& PlatformExtension::GetObjectMetadata(
const gd::String& objectType) {
if (objectsInfos.find(objectType) != objectsInfos.end())
@@ -242,16 +227,6 @@ gd::BehaviorMetadata& PlatformExtension::GetBehaviorMetadata(
return badBehaviorMetadata;
}
gd::EffectMetadata& PlatformExtension::GetEffectMetadata(
const gd::String& effectName) {
if (effectsMetadata.find(effectName) != effectsMetadata.end())
return effectsMetadata.find(effectName)->second;
std::cout << "Warning: Effect with name \"" << effectName
<< "\" not found in an extension!" << std::endl;
return badEffectMetadata;
}
std::vector<gd::String> PlatformExtension::GetBehaviorsTypes() const {
std::vector<gd::String> behaviors;
@@ -404,7 +379,6 @@ void PlatformExtension::SetNameSpace(gd::String nameSpace_) {
name == "BuiltinCommonConversions" ||
name == "BuiltinStringInstructions" ||
name == "BuiltinMathematicalTools" ||
name == "Effects" || // Well-known effects are not namespaced.
name == "CommonDialogs") // New name for BuiltinInterface
{
nameSpace = "";

View File

@@ -14,7 +14,6 @@
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
#include "GDCore/Extensions/Metadata/EventMetadata.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/String.h"
#include "GDCore/Tools/VersionPriv.h"
@@ -24,7 +23,6 @@ class InstructionMetadata;
class ExpressionMetadata;
class ObjectMetadata;
class BehaviorMetadata;
class EffectMetadata;
class BaseEvent;
class EventMetadata;
class EventCodeGenerator;
@@ -208,12 +206,6 @@ class GD_CORE_API PlatformExtension {
std::shared_ptr<gd::Behavior> instance,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
/**
* \brief Declare a new effect as being part of the extension.
* \param name The internal name of the effect (also called effect type).
*/
gd::EffectMetadata& AddEffect(const gd::String& name_);
/**
* \brief Declare a new event as being part of the extension.
* \note This method does nothing when used for GD C++ runtime.
@@ -292,12 +284,6 @@ class GD_CORE_API PlatformExtension {
*/
CreateFunPtr GetObjectCreationFunctionPtr(gd::String objectType) const;
/**
* \brief Return a vector containing all the effect types provided by the
* extension.
*/
std::vector<gd::String> GetExtensionEffectTypes() const;
/**
* \brief Create a custom event.
*
@@ -332,11 +318,6 @@ class GD_CORE_API PlatformExtension {
*/
BehaviorMetadata& GetBehaviorMetadata(const gd::String& behaviorType);
/**
* \brief Return the metadata for the effect with the given name.
*/
EffectMetadata& GetEffectMetadata(const gd::String& effectName);
/**
* \brief Return a map containing all the events provided by the extension
*/
@@ -474,7 +455,6 @@ class GD_CORE_API PlatformExtension {
std::map<gd::String, gd::ObjectMetadata> objectsInfos;
std::map<gd::String, gd::BehaviorMetadata> behaviorsInfo;
std::map<gd::String, gd::EffectMetadata> effectsMetadata;
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
@@ -485,7 +465,6 @@ class GD_CORE_API PlatformExtension {
ObjectMetadata badObjectMetadata;
BehaviorMetadata badBehaviorMetadata;
EffectMetadata badEffectMetadata;
#if defined(GD_IDE_ONLY)
static std::map<gd::String, gd::InstructionMetadata>
badConditionsMetadata; ///< Used when a condition is not found in the

View File

@@ -100,6 +100,13 @@ class GD_CORE_API AbstractFileSystem {
virtual bool CopyFile(const gd::String& file,
const gd::String& destination) = 0;
/**
* \brief Copy a whole directory
* \return true if the operation succeeded.
*/
virtual bool CopyDir(const gd::String& source,
const gd::String& destination) = 0;
/**
* \brief Write the content of a string to a file.
* \return true if the operation succeeded.

View File

@@ -63,16 +63,7 @@ class GD_CORE_API ExpressionObjectsAnalyzer
context.AddObjectName(node.identifierName);
}
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (!node.objectName.empty()) {
context.AddObjectName(node.objectName);
if (!node.behaviorFunctionName.empty()) {
context.AddBehaviorName(node.objectName, node.objectFunctionOrBehaviorName);
}
}
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
void OnVisitFunctionNode(FunctionNode& node) override {
if (!node.objectName.empty()) {
context.AddObjectName(node.objectName);

View File

@@ -35,7 +35,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
virtual ~ExpressionObjectRenamer(){};
static bool Rename(gd::ExpressionNode & node, const gd::String& objectName, const gd::String& objectNewName) {
if (ExpressionValidator::HasNoErrors(node)) {
if (ExpressionValidator::HasNoErrors(node)) {
ExpressionObjectRenamer renamer(objectName, objectNewName);
node.Visit(renamer);
@@ -77,13 +77,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
node.identifierName = objectNewName;
}
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (node.objectName == objectName) {
hasDoneRenaming = true;
node.objectName = objectNewName;
}
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
void OnVisitFunctionNode(FunctionNode& node) override {
if (node.objectName == objectName) {
hasDoneRenaming = true;
node.objectName = objectNewName;
@@ -113,7 +107,7 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
virtual ~ExpressionObjectFinder(){};
static bool CheckIfHasObject(gd::ExpressionNode & node, const gd::String & objectName) {
if (ExpressionValidator::HasNoErrors(node)) {
if (ExpressionValidator::HasNoErrors(node)) {
ExpressionObjectFinder finder(objectName);
node.Visit(finder);
@@ -154,12 +148,7 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
hasObject = true;
}
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (node.objectName == objectName) {
hasObject = true;
}
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
void OnVisitFunctionNode(FunctionNode& node) override {
if (node.objectName == objectName) {
hasObject = true;
}
@@ -195,7 +184,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
"number", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
actions[aId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -205,7 +194,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
"string", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
actions[aId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -248,7 +237,7 @@ bool EventsRefactorer::RenameObjectInConditions(
"number", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
conditions[cId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -258,7 +247,7 @@ bool EventsRefactorer::RenameObjectInConditions(
"string", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
conditions[cId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -279,43 +268,6 @@ bool EventsRefactorer::RenameObjectInConditions(
return somethingModified;
}
bool EventsRefactorer::RenameObjectInEventParameters(
const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
gd::String newName) {
bool somethingModified = false;
if (gd::ParameterMetadata::IsObject(parameterMetadata.GetType()) &&
expression.GetPlainString() == oldName)
expression = gd::Expression(newName);
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", parameterMetadata.GetType())) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", expression.GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", parameterMetadata.GetType())) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", expression.GetPlainString());
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
return somethingModified;
}
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
@@ -337,15 +289,6 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
platform, project, layout, *actionsVectors[j], oldName, newName);
}
vector<pair<gd::Expression*, gd::ParameterMetadata>> expressionsWithMetadata =
events[i].GetAllExpressionsWithMetadata();
for (std::size_t j = 0; j < expressionsWithMetadata.size(); ++j) {
gd::Expression* expression = expressionsWithMetadata[j].first;
gd::ParameterMetadata parameterMetadata = expressionsWithMetadata[j].second;
bool somethingModified = RenameObjectInEventParameters(
platform, project, layout, *expression, parameterMetadata, oldName, newName);
}
if (events[i].CanHaveSubEvents())
RenameObjectInEvents(platform,
project,
@@ -380,7 +323,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
"number", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
break;
@@ -391,7 +334,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
"string", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
break;
@@ -441,7 +384,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
"number", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
break;
@@ -452,7 +395,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
"string", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
break;
@@ -652,8 +595,7 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
gd::String search,
bool matchCase,
bool inConditions,
bool inActions,
bool inEventStrings) {
bool inActions) {
vector<EventsSearchResult> results;
for (std::size_t i = 0; i < events.size(); ++i) {
@@ -689,16 +631,6 @@ 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,
@@ -707,8 +639,7 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
search,
matchCase,
inConditions,
inActions,
inEventStrings);
inActions);
std::copy(
subResults.begin(), subResults.end(), std::back_inserter(results));
}
@@ -780,22 +711,6 @@ 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

@@ -8,7 +8,6 @@
#include <memory>
#include <vector>
#include "GDCore/Events/Instruction.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
namespace gd {
class EventsList;
@@ -104,8 +103,7 @@ class GD_CORE_API EventsRefactorer {
gd::String search,
bool matchCase,
bool inConditions,
bool inActions,
bool inEventStrings);
bool inAction);
/**
* Replace all occurrences of a gd::String in events
@@ -147,20 +145,6 @@ class GD_CORE_API EventsRefactorer {
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
/**
* Replace all occurrences of an object name by another name in an expression
* with the specified metadata
* ( include : objects or objects in math/text expressions ).
*
* \return true if something was modified.
*/
static bool RenameObjectInEventParameters(const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
gd::String newName);
/**
* Remove all conditions of the list using an object
@@ -218,11 +202,6 @@ 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

@@ -63,8 +63,7 @@ class GD_CORE_API ExpressionParameterSearcher
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
void OnVisitFunctionNode(FunctionNode& node) override {
bool considerFunction = objectName.empty() || node.objectName == objectName;
for (size_t i = 0; i < node.parameters.size() &&
i < node.expressionMetadata.parameters.size();

View File

@@ -1,366 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
#define GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
#include <memory>
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
namespace gd {
class Expression;
class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
} // namespace gd
namespace gd {
/**
* \brief Describe completions to be shown to the user.
*
* The IDE is responsible for actually *searching* and showing the completions -
* this is only describing what must be listed.
*/
struct ExpressionCompletionDescription {
public:
/**
* The different kind of completions that can be described.
*/
enum CompletionKind {
Object,
Behavior,
Expression,
Variable,
};
/**
* \brief Create a completion for an object with the given prefix
*/
static ExpressionCompletionDescription ForObject(const gd::String& type_,
const gd::String& prefix_) {
return ExpressionCompletionDescription(Object, type_, prefix_);
}
/**
* \brief Create a completion for a behavior with the given prefix of
* the specified object
*/
static ExpressionCompletionDescription ForBehavior(
const gd::String& prefix_, const gd::String& objectName_) {
return ExpressionCompletionDescription(Behavior, "", prefix_, objectName_);
}
/**
* \brief Create a completion for a variable with the given prefix
*/
static ExpressionCompletionDescription ForVariable(
const gd::String& type_, const gd::String& prefix_) {
return ExpressionCompletionDescription(Variable, type_, prefix_);
}
/**
* \brief Create a completion for an expression (free, object or behavior
* expression) with the given prefix
*/
static ExpressionCompletionDescription ForExpression(
const gd::String& type_,
const gd::String& prefix_,
const gd::String& objectName_ = "",
const gd::String& behaviorName_ = "") {
return ExpressionCompletionDescription(
Expression, type_, prefix_, objectName_, behaviorName_);
}
/** Check if two description of completions are equal */
bool operator==(const ExpressionCompletionDescription& other) const {
return completionKind == other.completionKind && type == other.type &&
prefix == other.prefix && objectName == other.objectName &&
behaviorName == other.behaviorName;
};
/** \brief Return the kind of the completion */
CompletionKind GetCompletionKind() const { return completionKind; }
/**
* \brief Return the type of the completion (same type as types supported in
* expressions)
* (in other words, for expression this is the type of what must be returned).
*/
const gd::String& GetType() const { return type; }
/**
* \brief Return the prefix currently entered and that must be completed.
*/
const gd::String& GetPrefix() const { return prefix; }
/**
* \brief Return the object name, if completing an object expression or a
* behavior.
*/
const gd::String& GetObjectName() const { return objectName; }
/**
* \brief Return the behavior name, if completing an object behavior
* expression.
*
* \warning If completing a behavior, the behavior (partial) name is returned
* by `GetPrefix`.
*/
const gd::String& GetBehaviorName() const { return behaviorName; }
/**
* \brief Set if the completion description is exact, i.e: it's not used
* to complete anything. Rather, it should display information about what is
* described by the completion.
*/
ExpressionCompletionDescription& SetIsExact(bool isExact_) {
isExact = isExact_;
return *this;
}
/**
* \brief Check if the completion description is exact, i.e: it's not
* used to complete anything. Rather, it should display information
* about what is described by the completion.
*/
bool IsExact() const { return isExact; }
/** Default constructor, only to be used by Emscripten bindings. */
ExpressionCompletionDescription() : completionKind(Object){};
private:
ExpressionCompletionDescription(CompletionKind completionKind_,
const gd::String& type_,
const gd::String& prefix_,
const gd::String& objectName_ = "",
const gd::String& behaviorName_ = "")
: completionKind(completionKind_),
type(type_),
prefix(prefix_),
objectName(objectName_),
behaviorName(behaviorName_),
isExact(false) {}
CompletionKind completionKind;
gd::String type;
gd::String prefix;
gd::String objectName;
gd::String behaviorName;
bool isExact;
};
/**
* \brief Turn an ExpressionCompletionDescription to a string.
*/
std::ostream& operator<<(std::ostream& os,
ExpressionCompletionDescription const& value) {
os << "{ " << value.GetCompletionKind() << ", " << value.GetType() << ", "
<< value.GetPrefix() << ", " << value.GetObjectName() << ", "
<< value.GetBehaviorName() << ", "
<< (value.IsExact() ? "exact" : "non-exact") << " }";
return os;
}
/**
* \brief Returns the list of completion descriptions for an expression node.
*
* \see gd::ExpressionCompletionDescription
*/
class GD_CORE_API ExpressionCompletionFinder
: public ExpressionParser2NodeWorker {
public:
/**
* \brief Given the expression, find the node at the specified location
* and returns completions for it.
*/
static std::vector<ExpressionCompletionDescription>
GetCompletionDescriptionsFor(gd::ExpressionNode& node,
size_t searchedPosition) {
gd::ExpressionNode* nodeAtLocation =
gd::ExpressionNodeLocationFinder::GetNodeAtPosition(node,
searchedPosition);
if (nodeAtLocation == nullptr) {
std::vector<ExpressionCompletionDescription> emptyCompletions;
return emptyCompletions;
}
gd::ExpressionCompletionFinder autocompletionProvider(searchedPosition);
nodeAtLocation->Visit(autocompletionProvider);
return autocompletionProvider.GetCompletionDescriptions();
}
/**
* \brief Return the completions found for the visited node.
*/
const std::vector<ExpressionCompletionDescription>&
GetCompletionDescriptions() {
return completions;
};
virtual ~ExpressionCompletionFinder(){};
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
completions.push_back(
ExpressionCompletionDescription::ForObject(node.type, ""));
completions.push_back(
ExpressionCompletionDescription::ForExpression(node.type, ""));
}
void OnVisitOperatorNode(OperatorNode& node) override {
completions.push_back(
ExpressionCompletionDescription::ForObject(node.type, ""));
completions.push_back(
ExpressionCompletionDescription::ForExpression(node.type, ""));
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
completions.push_back(
ExpressionCompletionDescription::ForObject(node.type, ""));
completions.push_back(
ExpressionCompletionDescription::ForExpression(node.type, ""));
}
void OnVisitNumberNode(NumberNode& node) override {
// No completions
}
void OnVisitTextNode(TextNode& node) override {
// No completions
}
void OnVisitVariableNode(VariableNode& node) override {
completions.push_back(
ExpressionCompletionDescription::ForVariable(node.type, node.name));
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
// No completions
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
// No completions
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
if (gd::ParameterMetadata::IsObject(node.type)) {
// Only show completions of objects if an object is required
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.identifierName));
} else {
// Show completions for expressions and objects otherwise.
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.identifierName));
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, node.identifierName));
}
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (!node.behaviorFunctionName.empty() ||
node.behaviorNameNamespaceSeparatorLocation.IsValid()) {
// Behavior function (or behavior function being written, with the
// function name missing)
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.objectName));
} else if (IsCaretOn(node.objectNameDotLocation) ||
IsCaretOn(node.objectFunctionOrBehaviorNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForBehavior(
node.objectFunctionOrBehaviorName, node.objectName));
} else if (IsCaretOn(node.behaviorNameNamespaceSeparatorLocation) ||
IsCaretOn(node.behaviorFunctionNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type,
node.behaviorFunctionName,
node.objectName,
node.objectFunctionOrBehaviorName));
}
} else {
// Object function or behavior name
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.objectName));
} else if (IsCaretOn(node.objectNameDotLocation) ||
IsCaretOn(node.objectFunctionOrBehaviorNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForBehavior(
node.objectFunctionOrBehaviorName, node.objectName));
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, node.objectFunctionOrBehaviorName, node.objectName));
}
}
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
bool isCaretOnParenthesis = IsCaretOn(node.openingParenthesisLocation) ||
IsCaretOn(node.closingParenthesisLocation);
if (!node.behaviorName.empty()) {
// Behavior function
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.objectName));
} else if (IsCaretOn(node.objectNameDotLocation) ||
IsCaretOn(node.behaviorNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForBehavior(
node.behaviorName, node.objectName));
} else {
completions.push_back(
ExpressionCompletionDescription::ForExpression(node.type,
node.functionName,
node.objectName,
node.behaviorName)
.SetIsExact(isCaretOnParenthesis));
}
} else if (!node.objectName.empty()) {
// Object function
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type, node.objectName));
} else {
// Add completions for behaviors, because we could imagine that the user
// wants to move from an object function to a behavior function, and so
// need behavior completions. Do this unless we're on the parenthesis
// (at which point we're only showing informative message about the
// function).
if (!isCaretOnParenthesis) {
completions.push_back(ExpressionCompletionDescription::ForBehavior(
node.functionName, node.objectName));
}
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, node.functionName, node.objectName)
.SetIsExact(isCaretOnParenthesis));
}
} else {
// Free function
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type, node.functionName)
.SetIsExact(isCaretOnParenthesis));
}
}
void OnVisitEmptyNode(EmptyNode& node) override {
completions.push_back(
ExpressionCompletionDescription::ForObject(node.type, node.text));
completions.push_back(
ExpressionCompletionDescription::ForExpression(node.type, node.text));
}
private:
bool IsCaretOn(const ExpressionParserLocation& location,
bool inclusive = false) {
if (!location.IsValid()) return false;
return (location.GetStartPosition() <= searchedPosition &&
((!inclusive && searchedPosition < location.GetEndPosition()) ||
(inclusive && searchedPosition <= location.GetEndPosition())));
}
ExpressionCompletionFinder(size_t searchedPosition_)
: searchedPosition(searchedPosition_){};
std::vector<ExpressionCompletionDescription> completions;
size_t searchedPosition;
};
} // namespace gd
#endif // GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H

View File

@@ -1,126 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONNODELOCATIONFINDER_H
#define GDCORE_EXPRESSIONNODELOCATIONFINDER_H
#include <memory>
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
namespace gd {
class Expression;
class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
} // namespace gd
namespace gd {
/**
* \brief Find the deepest node at the specified location in an expression.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionNodeLocationFinder
: public ExpressionParser2NodeWorker {
public:
/**
* \brief Initialize the finder to search at the specified position.
*/
ExpressionNodeLocationFinder(size_t searchedPosition_)
: searchedPosition(searchedPosition_), foundNode(nullptr){};
virtual ~ExpressionNodeLocationFinder(){};
/**
* \brief Helper function to find the deepest node at the search position, if
* any.
*/
static ExpressionNode* GetNodeAtPosition(gd::ExpressionNode& node,
size_t searchedPosition) {
gd::ExpressionNodeLocationFinder finder(searchedPosition);
node.Visit(finder);
return finder.GetNode();
}
/**
* \brief Return the deepest node found at the search position, if any.
*/
ExpressionNode* GetNode() { return foundNode; };
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
CheckSearchPositionInNode(node);
node.expression->Visit(*this);
}
void OnVisitOperatorNode(OperatorNode& node) override {
if (CheckSearchPositionInNode(node)) {
node.leftHandSide->Visit(*this);
node.rightHandSide->Visit(*this);
}
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
CheckSearchPositionInNode(node);
node.factor->Visit(*this);
}
void OnVisitNumberNode(NumberNode& node) override {
CheckSearchPositionInNode(node);
}
void OnVisitTextNode(TextNode& node) override {
CheckSearchPositionInNode(node);
}
void OnVisitVariableNode(VariableNode& node) override {
if (CheckSearchPositionInNode(node)) {
if (node.child) node.child->Visit(*this);
}
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
if (CheckSearchPositionInNode(node)) {
if (node.child) node.child->Visit(*this);
}
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
if (CheckSearchPositionInNode(node)) {
node.expression->Visit(*this);
if (node.child) node.child->Visit(*this);
}
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
CheckSearchPositionInNode(node);
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
CheckSearchPositionInNode(node);
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
CheckSearchPositionInNode(node);
for (auto& parameter : node.parameters) {
parameter->Visit(*this);
}
}
void OnVisitEmptyNode(EmptyNode& node) override {
CheckSearchPositionInNode(node, /*inclusive=*/true);
}
private:
bool CheckSearchPositionInNode(ExpressionNode& node, bool inclusive = false) {
if (node.location.GetStartPosition() <= searchedPosition &&
((!inclusive && searchedPosition < node.location.GetEndPosition()) ||
(inclusive && searchedPosition <= node.location.GetEndPosition()))) {
foundNode = &node;
return true;
}
return false;
}
size_t searchedPosition;
ExpressionNode* foundNode;
};
} // namespace gd
#endif // GDCORE_EXPRESSIONNODELOCATIONFINDER_H

View File

@@ -83,10 +83,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
void OnVisitIdentifierNode(IdentifierNode& node) override {
ReportAnyError(node);
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
ReportAnyError(node);
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
void OnVisitFunctionNode(FunctionNode& node) override {
ReportAnyError(node);
for (auto& parameter : node.parameters) {
parameter->Visit(*this);

View File

@@ -0,0 +1,59 @@
/*
* 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

@@ -0,0 +1,75 @@
/*
* 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

@@ -1,179 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
namespace gd {
/**
* \brief Go through the nodes and change the position of a parameter of the
* given function.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionParameterMover
: public ExpressionParser2NodeWorker {
public:
ExpressionParameterMover(const gd::ObjectsContainer& globalObjectsContainer_,
const gd::ObjectsContainer& objectsContainer_,
const gd::String& behaviorType_,
const gd::String& objectType_,
const gd::String& functionName_,
std::size_t oldIndex_,
std::size_t newIndex_)
: hasDoneMoving(false),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
behaviorType(behaviorType_),
objectType(objectType_),
functionName(functionName_),
oldIndex(oldIndex_),
newIndex(newIndex_){};
virtual ~ExpressionParameterMover(){};
bool HasDoneMoving() const { return hasDoneMoving; }
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
node.expression->Visit(*this);
}
void OnVisitOperatorNode(OperatorNode& node) override {
node.leftHandSide->Visit(*this);
node.rightHandSide->Visit(*this);
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
node.factor->Visit(*this);
}
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
node.expression->Visit(*this);
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
auto moveParameter =
[this](std::vector<std::unique_ptr<gd::ExpressionNode>>& parameters) {
if (oldIndex >= parameters.size() || newIndex >= parameters.size())
return;
auto movedParameterNode = std::move(parameters[oldIndex]);
parameters.erase(parameters.begin() + oldIndex);
parameters.insert(parameters.begin() + newIndex,
std::move(movedParameterNode));
};
if (node.functionName == functionName) {
if (behaviorType.empty() && !objectType.empty() &&
!node.objectName.empty()) {
// Move parameter of an object function
const gd::String& thisObjectType = gd::GetTypeOfObject(
globalObjectsContainer, objectsContainer, node.objectName);
if (thisObjectType == behaviorType) {
moveParameter(node.parameters);
hasDoneMoving = true;
}
} else if (!behaviorType.empty() && !node.behaviorName.empty()) {
// Move parameter of a behavior function
const gd::String& thisBehaviorType = gd::GetTypeOfBehavior(
globalObjectsContainer, objectsContainer, node.behaviorName);
if (thisBehaviorType == behaviorType) {
moveParameter(node.parameters);
hasDoneMoving = true;
}
} else if (behaviorType.empty() && objectType.empty()) {
// Move parameter of a free function
moveParameter(node.parameters);
hasDoneMoving = true;
}
}
for (auto& parameter : node.parameters) {
parameter->Visit(*this);
}
}
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
bool hasDoneMoving;
const gd::ObjectsContainer& globalObjectsContainer;
const gd::ObjectsContainer& objectsContainer;
const gd::String& behaviorType; // The behavior type of the function which
// must have a parameter moved (optional).
const gd::String& objectType; // The object type of the function which
// must have a parameter moved (optional). If
// `behaviorType` is not empty, it takes
// precedence over `objectType`.
const gd::String& functionName;
std::size_t oldIndex;
std::size_t newIndex;
};
bool ExpressionsParameterMover::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
auto& metadata = isCondition ? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
pNb < instruction.GetParametersCount();
++pNb) {
const gd::String& type = metadata.parameters[pNb].type;
const gd::String& expression =
instruction.GetParameter(pNb).GetPlainString();
gd::ExpressionParser2 parser(
platform, GetGlobalObjectsContainer(), GetObjectsContainer());
auto node = gd::ParameterMetadata::IsExpression("number", type)
? parser.ParseExpression("number", expression)
: (gd::ParameterMetadata::IsExpression("string", type)
? parser.ParseExpression("string", expression)
: std::unique_ptr<gd::ExpressionNode>());
if (node) {
ExpressionParameterMover mover(GetGlobalObjectsContainer(),
GetObjectsContainer(),
behaviorType,
objectType,
functionName,
oldIndex,
newIndex);
node->Visit(mover);
if (mover.HasDoneMoving()) {
instruction.SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
}
}
return false;
}
ExpressionsParameterMover::~ExpressionsParameterMover() {}
} // namespace gd

View File

@@ -1,85 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef ExpressionsParameterMover_H
#define ExpressionsParameterMover_H
#include <map>
#include <memory>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class Platform;
class EventsList;
} // namespace gd
namespace gd {
/**
* \brief Move in expressions, in parameters of actions or conditions, a
* parameter from one position to another.
*
* \see InstructionsParameterMover
* \ingroup IDE
*/
class GD_CORE_API ExpressionsParameterMover
: public ArbitraryEventsWorkerWithContext {
public:
ExpressionsParameterMover(const gd::Platform &platform_)
: platform(platform_){};
virtual ~ExpressionsParameterMover();
ExpressionsParameterMover &SetFreeExpressionMovedParameter(
const gd::String &functionName_,
std::size_t oldIndex_,
std::size_t newIndex_) {
objectType = "";
behaviorType = "";
functionName = functionName_;
oldIndex = oldIndex_;
newIndex = newIndex_;
return *this;
}
ExpressionsParameterMover &SetObjectExpressionMovedParameter(
const gd::String &objectType_,
const gd::String &functionName_,
std::size_t oldIndex_,
std::size_t newIndex_) {
objectType = objectType_;
behaviorType = "";
functionName = functionName_;
oldIndex = oldIndex_;
newIndex = newIndex_;
return *this;
};
ExpressionsParameterMover &SetBehaviorExpressionMovedParameter(
const gd::String &behaviorType_,
const gd::String &functionName_,
std::size_t oldIndex_,
std::size_t newIndex_) {
objectType = "";
behaviorType = behaviorType_;
functionName = functionName_;
oldIndex = oldIndex_;
newIndex = newIndex_;
return *this;
};
private:
bool DoVisitInstruction(gd::Instruction &instruction,
bool isCondition) override;
const gd::Platform &platform;
gd::String functionName;
std::size_t oldIndex;
std::size_t newIndex;
gd::String behaviorType;
gd::String objectType;
};
} // namespace gd
#endif // ExpressionsParameterMover_H

View File

@@ -71,41 +71,13 @@ class GD_CORE_API ExpressionFunctionRenamer
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (!node.behaviorFunctionName.empty()) {
// Behavior function name
if (!behaviorType.empty() &&
node.behaviorFunctionName == oldFunctionName) {
const gd::String& thisBehaviorType =
gd::GetTypeOfBehavior(globalObjectsContainer,
objectsContainer,
node.objectFunctionOrBehaviorName);
if (thisBehaviorType == behaviorType) {
node.behaviorFunctionName = newFunctionName;
hasDoneRenaming = true;
}
}
} else {
// Object function name
if (behaviorType.empty() && !objectType.empty() &&
node.objectFunctionOrBehaviorName == oldFunctionName) {
const gd::String& thisObjectType = gd::GetTypeOfObject(
globalObjectsContainer, objectsContainer, node.objectName);
if (thisObjectType == objectType) {
node.objectFunctionOrBehaviorName = newFunctionName;
hasDoneRenaming = true;
}
}
}
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
void OnVisitFunctionNode(FunctionNode& node) override {
if (node.functionName == oldFunctionName) {
if (behaviorType.empty() && !objectType.empty() &&
!node.objectName.empty()) {
if (!objectType.empty() && !node.objectName.empty()) {
// Replace an object function
const gd::String& thisObjectType = gd::GetTypeOfObject(
globalObjectsContainer, objectsContainer, node.objectName);
if (thisObjectType == objectType) {
if (thisObjectType == behaviorType) {
node.functionName = newFunctionName;
hasDoneRenaming = true;
}
@@ -117,7 +89,7 @@ class GD_CORE_API ExpressionFunctionRenamer
node.functionName = newFunctionName;
hasDoneRenaming = true;
}
} else if (behaviorType.empty() && objectType.empty()) {
} else {
// Replace a free function
node.functionName = newFunctionName;
hasDoneRenaming = true;
@@ -134,11 +106,9 @@ class GD_CORE_API ExpressionFunctionRenamer
const gd::ObjectsContainer& globalObjectsContainer;
const gd::ObjectsContainer& objectsContainer;
const gd::String& behaviorType; // The behavior type for which the expression
// must be replaced (optional).
// must be replaced (optional)
const gd::String& objectType; // The object type for which the expression
// must be replaced (optional). If
// `behaviorType` is not empty, it takes
// precedence over `objectType`.
// must be replaced (optional)
const gd::String& oldFunctionName;
const gd::String& newFunctionName;
};

View File

@@ -1,37 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/InstructionsParameterMover.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
bool InstructionsParameterMover::DoVisitInstruction(
gd::Instruction& instruction, bool isCondition) {
if (instruction.GetType() == instructionType) {
std::vector<gd::Expression> updatedParameters = instruction.GetParameters();
if (oldIndex < updatedParameters.size() ||
newIndex < updatedParameters.size()) {
gd::Expression movedParameter = updatedParameters[oldIndex];
updatedParameters.erase(updatedParameters.begin() + oldIndex);
updatedParameters.insert(updatedParameters.begin() + newIndex,
movedParameter);
instruction.SetParameters(updatedParameters);
}
}
return false;
}
InstructionsParameterMover::~InstructionsParameterMover() {}
} // namespace gd

View File

@@ -1,53 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef InstructionsParameterMover_H
#define InstructionsParameterMover_H
#include <map>
#include <memory>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class Project;
class EventsList;
} // namespace gd
namespace gd {
/**
* \brief Reorder the parameters of the instruction with the specified
* type in events, moving the parameter at the specified \a oldIndex to
* \a newIndex.
*
* \see ExpressionsParameterMover
* \ingroup IDE
*/
class GD_CORE_API InstructionsParameterMover : public ArbitraryEventsWorker {
public:
InstructionsParameterMover(const gd::Project& project_,
const gd::String& instructionType_,
std::size_t oldIndex_,
std::size_t newIndex_)
: project(project_),
instructionType(instructionType_),
oldIndex(oldIndex_),
newIndex(newIndex_){};
virtual ~InstructionsParameterMover();
private:
bool DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) override;
const gd::Project& project;
gd::String instructionType;
std::size_t oldIndex;
std::size_t newIndex;
};
} // namespace gd
#endif // InstructionsParameterMover_H

View File

@@ -4,7 +4,6 @@
* reserved. This project is released under the MIT License.
*/
#include "ProjectStripper.h"
#include "GDCore/Project/ExternalEvents.h"
#include "GDCore/Project/ExternalLayout.h"
#include "GDCore/Project/Layout.h"
@@ -21,8 +20,61 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project& project) {
project.GetLayout(i).GetObjectGroups().Clear();
project.GetLayout(i).GetEvents().Clear();
}
}
project.ClearEventsFunctionsExtensions();
void GD_CORE_API ProjectStripper::StripProjectForLayoutEdition(
gd::Project& project, const gd::String& layoutName) {
while (project.GetExternalEventsCount() > 0)
project.RemoveExternalEvents(project.GetExternalEvents(0).GetName());
for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) {
auto& layout = project.GetLayout(i);
if (layoutName == layout.GetName()) continue;
project.GetLayout(i).GetEvents().Clear();
project.GetLayout(i).GetInitialInstances().Clear();
}
for (unsigned int i = 0; i < project.GetExternalEventsCount(); ++i) {
project.GetExternalEvents(i).GetEvents().Clear();
}
for (unsigned int i = 0; i < project.GetExternalLayoutsCount(); ++i) {
project.GetExternalLayout(i).GetInitialInstances().Clear();
}
}
void GD_CORE_API ProjectStripper::StripProjectForExternalLayoutEdition(
gd::Project& project, const gd::String& externalLayoutName) {
while (project.GetExternalEventsCount() > 0)
project.RemoveExternalEvents(project.GetExternalEvents(0).GetName());
gd::String associatedLayoutName;
if (project.HasExternalLayoutNamed(externalLayoutName)) {
associatedLayoutName =
project.GetExternalLayout(externalLayoutName).GetAssociatedLayout();
}
for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) {
auto& layout = project.GetLayout(i);
if (!associatedLayoutName.empty() &&
associatedLayoutName == layout.GetName())
continue;
project.GetLayout(i).GetEvents().Clear();
project.GetLayout(i).GetInitialInstances().Clear();
}
for (unsigned int i = 0; i < project.GetExternalEventsCount(); ++i) {
project.GetExternalEvents(i).GetEvents().Clear();
}
for (unsigned int i = 0; i < project.GetExternalLayoutsCount(); ++i) {
auto& externalLayout = project.GetExternalLayout(i);
if (externalLayoutName == externalLayout.GetName()) continue;
externalLayout.GetInitialInstances().Clear();
}
}
} // namespace gd

View File

@@ -28,6 +28,23 @@ class GD_CORE_API ProjectStripper {
*/
static void StripProjectForExport(gd::Project& project);
/**
* \brief Strip project to keep only the full content of the specified
* layout. The content of other layouts, external events and external layouts
* is removed.
*/
static void StripProjectForLayoutEdition(gd::Project& project,
const gd::String& layoutName);
/**
* \brief Strip project to keep only the full content of the specified
* external layout and the associated layout.
* The content of other layouts, external events and external layouts is
* removed.
*/
static void StripProjectForExternalLayoutEdition(
gd::Project& project, const gd::String& externalLayoutName);
private:
ProjectStripper(){};
virtual ~ProjectStripper(){};

View File

@@ -10,49 +10,34 @@
namespace gd {
SceneNameMangler *SceneNameMangler::_singleton = nullptr;
const gd::String &SceneNameMangler::GetMangledSceneName(
const gd::String &sceneName) {
auto it = mangledSceneNames.find(sceneName);
if (it != mangledSceneNames.end()) {
return it->second;
}
gd::String partiallyMangledName = sceneName;
static const gd::String alwaysAllowedCharacters =
gd::String SceneNameMangler::GetMangledSceneName(gd::String sceneName) {
static const gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const gd::String allowedExceptFirstCharacters = "0123456789";
static const gd::String allowedExceptFirst = "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));
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;
}
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;
}
return sceneName;
}
} // namespace gd

View File

@@ -6,14 +6,12 @@
#ifndef SCENENAMEMANGLER_H
#define SCENENAMEMANGLER_H
#include <unordered_map>
#include "GDCore/String.h"
namespace gd {
/**
* \brief Mangle the name of a scene, so that it can be used in code or file
* names.
* \brief Used to mangle the name of a scene
*
* \ingroup IDE
*/
@@ -23,22 +21,12 @@ 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.
*/
const gd::String& GetMangledSceneName(const gd::String& sceneName);
static SceneNameMangler* Get();
static void DestroySingleton();
static gd::String GetMangledSceneName(gd::String sceneName);
private:
SceneNameMangler(){};
virtual ~SceneNameMangler(){};
static SceneNameMangler* _singleton;
std::unordered_map<gd::String, gd::String>
mangledSceneNames; ///< Memoized results of mangling
};
} // namespace gd

View File

@@ -9,9 +9,7 @@
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Events/EventsRefactorer.h"
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
#include "GDCore/IDE/Events/InstructionsParameterMover.h"
#include "GDCore/IDE/EventsFunctionTools.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
@@ -87,8 +85,7 @@ void WholeProjectRefactorer::ExposeProjectEvents(
void WholeProjectRefactorer::ExposeProjectEvents(
gd::Project& project, gd::ArbitraryEventsWorkerWithContext& worker) {
// See also gd::Project::ExposeResources for a method that traverse the whole
// project (this time for resources) and ExposeProjectEffects (this time for
// effects).
// project (this time for resources).
// Add layouts events
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
@@ -334,6 +331,9 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
}
}
/**
* \brief Refactor the project after an events function is renamed
*/
void WholeProjectRefactorer::RenameEventsFunction(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
@@ -391,76 +391,6 @@ void WholeProjectRefactorer::RenameBehaviorEventsFunction(
}
}
void WholeProjectRefactorer::MoveEventsFunctionParameter(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::String& functionName,
std::size_t oldIndex,
std::size_t newIndex) {
if (!eventsFunctionsExtension.HasEventsFunctionNamed(functionName)) return;
const gd::EventsFunction& eventsFunction =
eventsFunctionsExtension.GetEventsFunction(functionName);
const gd::String& eventsFunctionType = GetEventsFunctionFullType(
eventsFunctionsExtension.GetName(), functionName);
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
project, eventsFunctionType, oldIndex, newIndex);
ExposeProjectEvents(project, mover);
} else if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::Expression ||
eventsFunction.GetFunctionType() ==
gd::EventsFunction::StringExpression) {
gd::ExpressionsParameterMover mover =
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
mover.SetFreeExpressionMovedParameter(
eventsFunctionType, oldIndex, newIndex);
ExposeProjectEvents(project, mover);
}
}
void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedBehavior& eventsBasedBehavior,
const gd::String& functionName,
std::size_t oldIndex,
std::size_t newIndex) {
auto& eventsFunctions = eventsBasedBehavior.GetEventsFunctions();
if (!eventsFunctions.HasEventsFunctionNamed(functionName)) return;
const gd::EventsFunction& eventsFunction =
eventsFunctions.GetEventsFunction(functionName);
const gd::String& eventsFunctionType =
GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName(),
functionName);
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
project, eventsFunctionType, oldIndex, newIndex);
ExposeProjectEvents(project, mover);
} else if (eventsFunction.GetFunctionType() ==
gd::EventsFunction::Expression ||
eventsFunction.GetFunctionType() ==
gd::EventsFunction::StringExpression) {
gd::ExpressionsParameterMover mover =
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
mover.SetBehaviorExpressionMovedParameter(
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName()),
functionName,
oldIndex,
newIndex);
ExposeProjectEvents(project, mover);
}
}
void WholeProjectRefactorer::RenameBehaviorProperty(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
@@ -470,17 +400,7 @@ void WholeProjectRefactorer::RenameBehaviorProperty(
auto& properties = eventsBasedBehavior.GetPropertyDescriptors();
if (!properties.Has(oldPropertyName)) return;
// Order is important: we first rename the expressions then the instructions,
// to avoid being unable to fetch the metadata (the types of parameters) of
// instructions after they are renamed.
gd::ExpressionsRenamer expressionRenamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
expressionRenamer.SetReplacedBehaviorExpression(
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName()),
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
ExposeProjectEvents(project, expressionRenamer);
const auto& property = properties.Get(oldPropertyName);
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
project,
@@ -505,6 +425,15 @@ void WholeProjectRefactorer::RenameBehaviorProperty(
eventsBasedBehavior.GetName(),
EventsBasedBehavior::GetPropertyConditionName(newPropertyName)));
ExposeProjectEvents(project, conditionRenamer);
gd::ExpressionsRenamer expressionRenamer =
gd::ExpressionsRenamer(project.GetCurrentPlatform());
expressionRenamer.SetReplacedBehaviorExpression(
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
eventsBasedBehavior.GetName()),
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
ExposeProjectEvents(project, expressionRenamer);
}
void WholeProjectRefactorer::RenameEventsBasedBehavior(

View File

@@ -50,10 +50,7 @@ class GD_CORE_API WholeProjectRefactorer {
gd::ArbitraryEventsWorkerWithContext& worker);
/**
* \brief Refactor the project **before** an events function extension is renamed.
*
* \warning Do the renaming of the specified extension after calling this.
* This is because the extension is expected to have its old name for the refactoring.
* \brief Refactor the project after an events function extension is renamed
*/
static void RenameEventsFunctionsExtension(
gd::Project& project,
@@ -62,10 +59,7 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& newName);
/**
* \brief Refactor the project **before** an events function is renamed.
*
* \warning Do the renaming of the specified function after calling this.
* This is because the function is expected to have its old name for the refactoring.
* \brief Refactor the project after an events function is renamed
*/
static void RenameEventsFunction(
gd::Project& project,
@@ -74,11 +68,8 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& newFunctionName);
/**
* \brief Refactor the project **before** an events function of a behavior is
* \brief Refactor the project after an events function of a behavior is
* renamed.
*
* \warning Do the renaming of the specified function after calling this.
* This is because the function is expected to have its old name for the refactoring.
*/
static void RenameBehaviorEventsFunction(
gd::Project& project,
@@ -88,40 +79,8 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& newFunctionName);
/**
* \brief Refactor the project **before** an events function parameter
* is moved.
*
* \warning Do the move of the specified function parameters after calling this.
* This is because the function is expected to be in its old state for the refactoring.
*/
static void MoveEventsFunctionParameter(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::String& functionName,
std::size_t oldIndex,
std::size_t newIndex);
/**
* \brief Refactor the project **before** the parameter of an events function of a
* behavior is moved.
*
* \warning Do the move of the specified function parameters after calling this.
* This is because the function is expected to be in its old state for the refactoring.
*/
static void MoveBehaviorEventsFunctionParameter(
gd::Project& project,
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
const gd::EventsBasedBehavior& eventsBasedBehavior,
const gd::String& functionName,
std::size_t oldIndex,
std::size_t newIndex);
/**
* \brief Refactor the project **before** a property of a behavior is
* \brief Refactor the project after a property of a behavior is
* renamed.
*
* \warning Do the renaming of the specified property after calling this.
* This is because the property is expected to have its old name for the refactoring.
*/
static void RenameBehaviorProperty(
gd::Project& project,
@@ -131,10 +90,7 @@ class GD_CORE_API WholeProjectRefactorer {
const gd::String& newPropertyName);
/**
* \brief Refactor the project **before** a behavior is renamed.
*
* \warning Do the renaming of the specified behavior after calling this.
* This is because the behavior is expected to have its old name for the refactoring.
* \brief Refactor the project after a behavior is renamed.
*/
static void RenameEventsBasedBehavior(
gd::Project& project,
@@ -181,7 +137,7 @@ class GD_CORE_API WholeProjectRefactorer {
bool isObjectGroup);
/**
* \brief Refactor the events function after an object or group is removed
* \brief Refactor the events function after an object or group is renamed
*
* This will update the events of the function and groups.
*/

View File

@@ -12,60 +12,21 @@ namespace gd {
#if defined(GD_IDE_ONLY)
void Effect::SerializeTo(SerializerElement& element) const {
element.SetAttribute("name", GetName());
element.SetAttribute("effectType", GetEffectType());
SerializerElement& doubleParametersElement =
element.AddChild("doubleParameters");
for (auto& parameter : doubleParameters)
doubleParametersElement.AddChild(parameter.first)
.SetValue(parameter.second);
SerializerElement& stringParametersElement =
element.AddChild("stringParameters");
for (auto& parameter : stringParameters)
stringParametersElement.AddChild(parameter.first)
.SetValue(parameter.second);
SerializerElement& booleanParametersElement =
element.AddChild("booleanParameters");
for (auto& parameter : booleanParameters)
booleanParametersElement.AddChild(parameter.first)
.SetValue(parameter.second);
element.SetAttribute("effectName", GetEffectName());
SerializerElement& parametersElement = element.AddChild("parameters");
for (auto& parameter : parameters)
parametersElement.AddChild(parameter.first).SetValue(parameter.second);
}
#endif
void Effect::UnserializeFrom(const SerializerElement& element) {
SetName(element.GetStringAttribute("name"));
SetEffectType(element.GetStringAttribute(
"effectType",
"",
// Compatibility with GD <= 5.0.0-beta83
"effectName"
// end of compatibility code
));
SetEffectName(element.GetStringAttribute("effectName"));
doubleParameters.clear();
const SerializerElement& doubleParametersElement =
element.GetChild("doubleParameters",
0,
// Compatibility with GD <= 5.0.0-beta83
"parameters"
// end of compatibility code
);
for (auto& child : doubleParametersElement.GetAllChildren())
SetDoubleParameter(child.first, child.second->GetValue().GetDouble());
stringParameters.clear();
const SerializerElement& stringParametersElement =
element.GetChild("stringParameters");
for (auto& child : stringParametersElement.GetAllChildren())
SetStringParameter(child.first, child.second->GetValue().GetString());
booleanParameters.clear();
const SerializerElement& booleanParametersElement =
element.GetChild("booleanParameters");
for (auto& child : booleanParametersElement.GetAllChildren())
SetBooleanParameter(child.first, child.second->GetValue().GetBool());
parameters.clear();
const SerializerElement& parametersElement = element.GetChild("parameters");
for (auto& child : parametersElement.GetAllChildren())
SetParameter(child.first, child.second->GetValue().GetDouble());
}
} // namespace gd

View File

@@ -27,51 +27,17 @@ class GD_CORE_API Effect {
void SetName(const gd::String& name_) { name = name_; }
const gd::String& GetName() const { return name; }
void SetEffectType(const gd::String& effectType_) {
effectType = effectType_;
void SetEffectName(const gd::String& effectName_) {
effectName = effectName_;
}
const gd::String& GetEffectType() const { return effectType; }
const gd::String& GetEffectName() const { return effectName; }
void SetDoubleParameter(const gd::String& name, double value) {
doubleParameters[name] = value;
void SetParameter(const gd::String& name, double value) {
parameters[name] = value;
}
double GetDoubleParameter(const gd::String& name) {
return doubleParameters[name];
}
void SetStringParameter(const gd::String& name, const gd::String& value) {
stringParameters[name] = value;
}
const gd::String& GetStringParameter(const gd::String& name) {
return stringParameters[name];
}
void SetBooleanParameter(const gd::String& name, bool value) {
booleanParameters[name] = value;
}
bool GetBooleanParameter(const gd::String& name) {
return booleanParameters[name];
}
const std::map<gd::String, double>& GetAllDoubleParameters() const {
return doubleParameters;
}
const std::map<gd::String, gd::String>& GetAllStringParameters() const {
return stringParameters;
}
const std::map<gd::String, bool>& GetAllBooleanParameters() const {
return booleanParameters;
}
void ClearParameters() {
doubleParameters.clear();
stringParameters.clear();
booleanParameters.clear();
double GetParameter(const gd::String& name) { return parameters[name]; }
const std::map<gd::String, double>& GetAllParameters() const {
return parameters;
}
#if defined(GD_IDE_ONLY)
@@ -87,11 +53,9 @@ class GD_CORE_API Effect {
void UnserializeFrom(const SerializerElement& element);
private:
gd::String name; ///< The name of the layer.
gd::String effectType; ///< The name of the effect to apply.
std::map<gd::String, double> doubleParameters; ///< Values of parameters being doubles, keyed by names.
std::map<gd::String, gd::String> stringParameters; ///< Values of parameters being strings, keyed by names.
std::map<gd::String, bool> booleanParameters; ///< Values of parameters being booleans, keyed by names.
gd::String name; ///< The name of the layer
gd::String effectName; ///< The name of the effect to apply
std::map<gd::String, double> parameters;
};
} // namespace gd

View File

@@ -70,19 +70,6 @@ void EventsFunctionsExtension::UnserializeFrom(
"eventsBasedBehavior", project, element.GetChild("eventsBasedBehaviors"));
}
bool EventsFunctionsExtension::IsExtensionLifecycleEventsFunction(
const gd::String& eventsFunctionName) {
// The list of all supported lifecycle events function names.
// If adding a new one, code generator(s) must be updated.
return eventsFunctionName == "onFirstSceneLoaded" ||
eventsFunctionName == "onSceneLoaded" ||
eventsFunctionName == "onScenePreEvents" ||
eventsFunctionName == "onScenePostEvents" ||
eventsFunctionName == "onScenePaused" ||
eventsFunctionName == "onSceneResumed" ||
eventsFunctionName == "onSceneUnloading";
}
} // namespace gd
#endif

View File

@@ -8,8 +8,8 @@
#define GDCORE_EVENTSFUNCTIONEXTENSION_H
#include <vector>
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsFunctionsContainer.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/String.h"
#include "GDCore/Tools/SerializableWithNameList.h"
namespace gd {
@@ -59,8 +59,7 @@ 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;
}
@@ -98,15 +97,15 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
/**
* \brief Return a reference to the list of the events based behaviors.
*/
gd::SerializableWithNameList<EventsBasedBehavior>& GetEventsBasedBehaviors() {
SerializableWithNameList<EventsBasedBehavior>& GetEventsBasedBehaviors() {
return eventsBasedBehaviors;
}
/**
* \brief Return a const reference to the list of the events based behaviors.
*/
const gd::SerializableWithNameList<EventsBasedBehavior>&
GetEventsBasedBehaviors() const {
const SerializableWithNameList<EventsBasedBehavior>& GetEventsBasedBehaviors()
const {
return eventsBasedBehaviors;
}
@@ -125,12 +124,6 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
const gd::SerializerElement& element);
///@}
/** \name Lifecycle event functions
*/
///@{
static bool IsExtensionLifecycleEventsFunction(const gd::String& eventsFunctionName);
///@}
private:
/**
* Initialize object using another object. Used by copy-ctor and assign-op.
@@ -146,7 +139,7 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
gd::String fullName;
gd::String tags;
gd::String author;
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
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::Get()->GetMangledSceneName(name);
mangledName = gd::SceneNameMangler::GetMangledSceneName(name);
};
bool Layout::HasBehaviorSharedData(const gd::String& behaviorName) {

View File

@@ -7,7 +7,6 @@
#include "Project.h"
#include <stdio.h>
#include <stdlib.h>
#include <cctype>
#include <SFML/System/Utf.hpp>
#include <fstream>
#include <map>
@@ -60,7 +59,6 @@ Project::Project()
minFPS(20),
verticalSync(false),
scaleMode("linear"),
adaptGameResolutionAtRuntime(true),
sizeOnStartupMode("adaptWidth"),
imageManager(std::make_shared<ImageManager>())
#if defined(GD_IDE_ONLY)
@@ -521,9 +519,6 @@ void Project::RemoveEventsFunctionsExtension(const gd::String& name) {
eventsFunctionsExtensions.erase(eventsFunctionExtension);
}
void Project::ClearEventsFunctionsExtensions() {
eventsFunctionsExtensions.clear();
}
#endif
void Project::UnserializeFrom(const SerializerElement& element) {
@@ -579,8 +574,9 @@ void Project::UnserializeFrom(const SerializerElement& element) {
element.GetChild("properties", 0, "Info");
SetName(propElement.GetChild("name", 0, "Nom").GetValue().GetString());
SetVersion(propElement.GetStringAttribute("version", "1.0.0"));
SetGameResolutionSize(
propElement.GetChild("windowWidth", 0, "WindowW").GetValue().GetInt(),
SetDefaultWidth(
propElement.GetChild("windowWidth", 0, "WindowW").GetValue().GetInt());
SetDefaultHeight(
propElement.GetChild("windowHeight", 0, "WindowH").GetValue().GetInt());
SetMaximumFPS(
propElement.GetChild("maxFPS", 0, "FPSmax").GetValue().GetInt());
@@ -589,8 +585,6 @@ void Project::UnserializeFrom(const SerializerElement& element) {
SetVerticalSyncActivatedByDefault(
propElement.GetChild("verticalSync").GetValue().GetBool());
SetScaleMode(propElement.GetStringAttribute("scaleMode", "linear"));
SetAdaptGameResolutionAtRuntime(
propElement.GetBoolAttribute("adaptGameResolutionAtRuntime", false));
SetSizeOnStartupMode(propElement.GetStringAttribute("sizeOnStartupMode", ""));
#if defined(GD_IDE_ONLY)
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
@@ -857,8 +851,8 @@ void Project::SerializeTo(SerializerElement& element) const {
propElement.AddChild("name").SetValue(GetName());
propElement.SetAttribute("version", GetVersion());
propElement.AddChild("author").SetValue(GetAuthor());
propElement.AddChild("windowWidth").SetValue(GetGameResolutionWidth());
propElement.AddChild("windowHeight").SetValue(GetGameResolutionHeight());
propElement.AddChild("windowWidth").SetValue(GetMainWindowDefaultWidth());
propElement.AddChild("windowHeight").SetValue(GetMainWindowDefaultHeight());
propElement.AddChild("latestCompilationDirectory")
.SetValue(GetLastCompilationDirectory());
propElement.AddChild("maxFPS").SetValue(GetMaximumFPS());
@@ -866,7 +860,6 @@ void Project::SerializeTo(SerializerElement& element) const {
propElement.AddChild("verticalSync")
.SetValue(IsVerticalSynchronizationEnabledByDefault());
propElement.SetAttribute("scaleMode", scaleMode);
propElement.SetAttribute("adaptGameResolutionAtRuntime", adaptGameResolutionAtRuntime);
propElement.SetAttribute("sizeOnStartupMode", sizeOnStartupMode);
propElement.SetAttribute("projectFile", gameFile);
propElement.SetAttribute("folderProject", folderProject);
@@ -949,21 +942,22 @@ void Project::SerializeTo(SerializerElement& element) const {
#endif
}
bool Project::ValidateName(const gd::String& name) {
bool Project::ValidateObjectName(const gd::String& name) {
if (name.empty()) return false;
if (isdigit(name[0])) return false;
gd::String allowedCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
return !(name.find_first_not_of(allowedCharacters) != gd::String::npos);
}
gd::String Project::GetBadObjectNameWarning() {
return _("Please use only letters, digits\nand underscores ( _ ).");
}
void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
// See also gd::WholeProjectRefactorer::ExposeProjectEvents for a method that
// traverse the whole project (this time for events) and ExposeProjectEffects
// (this time for effects). Ideally, this method could be moved outside of
// gd::Project.
// traverse the whole project (this time for events). Ideally, this method
// could be moved outside of gd::Project.
// Add project resources
worker.ExposeResources(&GetResourcesManager());
@@ -1064,7 +1058,6 @@ void Project::Init(const gd::Project& game) {
minFPS = game.minFPS;
verticalSync = game.verticalSync;
scaleMode = game.scaleMode;
adaptGameResolutionAtRuntime = game.adaptGameResolutionAtRuntime;
sizeOnStartupMode = game.sizeOnStartupMode;
#if defined(GD_IDE_ONLY)

View File

@@ -8,7 +8,6 @@
#define GDCORE_PROJECT_H
#include <memory>
#include <vector>
#include "GDCore/Project/LoadingScreen.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
#include "GDCore/Project/ObjectsContainer.h"
@@ -201,36 +200,22 @@ class GD_CORE_API Project : public ObjectsContainer {
* the first time. To change the width at runtime, use the functions related
* to RuntimeScene.renderWindow
*/
void SetGameResolutionSize(unsigned int width, unsigned int height) {
windowWidth = width;
windowHeight = height;
}
void SetDefaultWidth(unsigned int width) { windowWidth = width; }
/**
* \brief Returns the default game resolution width.
* Get the default width of the project main window
*/
unsigned int GetGameResolutionWidth() const { return windowWidth; }
unsigned int GetMainWindowDefaultWidth() const { return windowWidth; }
/**
* \brief Returns the default game resolution height.
* Change the default height of the project main window
*/
unsigned int GetGameResolutionHeight() const { return windowHeight; }
void SetDefaultHeight(unsigned int height) { windowHeight = height; }
/**
* \brief Returns true if the game resolution should be adapted to the window
* size at runtime.
* Return the default height of the project main window
*/
bool GetAdaptGameResolutionAtRuntime() const {
return adaptGameResolutionAtRuntime;
}
/**
* \brief Set if the game resolution should be adapted to the window size at
* runtime. \see SetSizeOnStartupMode
*/
void SetAdaptGameResolutionAtRuntime(bool adaptGameResolutionAtRuntime_) {
adaptGameResolutionAtRuntime = adaptGameResolutionAtRuntime_;
}
unsigned int GetMainWindowDefaultHeight() const { return windowHeight; }
/**
* \brief Get how the game size should be adapted to the screen.
@@ -461,27 +446,22 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t GetLayoutsCount() const;
/**
* \brief Add a new empty layout called "name" at the specified
* \brief \brief Adds a new empty layout called "name" at the specified
* position in the layout list.
*/
gd::Layout& InsertNewLayout(const gd::String& name, std::size_t position);
/**
* \brief Add a new layout constructed from the layout passed as
* parameter.
* \param layout The layout that must be copied and inserted
* into the project
* \param position Insertion position. Even if the position
* \brief \brief Adds a new layout constructed from the layout passed as
* parameter. \note No pointer or reference must be kept on the layout passed
* as parameter. \param layout The layout that must be copied and inserted
* into the project \param position Insertion position. Even if the position
* is invalid, the layout must be inserted at the end of the layout list.
*
* \note No pointer or reference must be kept on the layout passed
* as parameter.
*
*/
gd::Layout& InsertLayout(const Layout& layout, std::size_t position);
/**
* \brief Delete layout named "name".
* Must delete layout named "name".
*/
void RemoveLayout(const gd::String& name);
@@ -598,7 +578,7 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t position);
/**
* \brief Delete external events named "name".
* Must delete external events named "name".
*/
void RemoveExternalEvents(const gd::String& name);
#endif
@@ -679,7 +659,7 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t position);
/**
* \brief Delete external layout named "name".
* Must delete external layout named "name".
*/
void RemoveExternalLayout(const gd::String& name);
@@ -700,37 +680,37 @@ class GD_CORE_API Project : public ObjectsContainer {
///@{
#if defined(GD_IDE_ONLY)
/**
* \brief Check if events functions extension called "name" exists.
* Return true if events functions extension called "name" exists.
*/
bool HasEventsFunctionsExtensionNamed(const gd::String& name) const;
/**
* \brief Return a reference to the events functions extension called "name".
* Return a reference to the events functions extension called "name".
*/
EventsFunctionsExtension& GetEventsFunctionsExtension(const gd::String& name);
/**
* \brief Return a reference to the events functions extension called "name".
* Return a reference to the events functions extension called "name".
*/
const EventsFunctionsExtension& GetEventsFunctionsExtension(
const gd::String& name) const;
/**
* \brief Return a reference to the events functions extension at position
* "index" in the list
* Return a reference to the events functions extension at position "index" in
* the list
*/
EventsFunctionsExtension& GetEventsFunctionsExtension(std::size_t index);
/**
* \brief Return a reference to the events functions extension at position
* "index" in the list
* Return a reference to the events functions extension at position "index" in
* the list
*/
const EventsFunctionsExtension& GetEventsFunctionsExtension(
std::size_t index) const;
/**
* \brief Return the position of the events functions extension called "name"
* in the list.
* Return the position of the events functions extension called "name" in the
* list
*/
std::size_t GetEventsFunctionsExtensionPosition(const gd::String& name) const;
@@ -742,7 +722,7 @@ class GD_CORE_API Project : public ObjectsContainer {
void SwapEventsFunctionsExtensions(std::size_t first, std::size_t second);
/**
* \brief Returns the number of events functions extension.
* Return the number of events functions extension.
*/
std::size_t GetEventsFunctionsExtensionsCount() const;
@@ -765,14 +745,9 @@ class GD_CORE_API Project : public ObjectsContainer {
std::size_t position);
/**
* \brief Delete the events functions extension named "name".
* Must delete the events functions extension named "name".
*/
void RemoveEventsFunctionsExtension(const gd::String& name);
/**
* \brief Remove all the events functions extensions.
*/
void ClearEventsFunctionsExtensions();
#endif
///@}
@@ -854,10 +829,21 @@ class GD_CORE_API Project : public ObjectsContainer {
///@{
/**
* Return true if \a name is valid (can be used safely for an object,
* behavior, events function name, etc...).
* Return true if \a objectName can be used as name for an object.
*
* Default implementation check if objectName is only composed of a-z,A-Z,0-9
* or _ characters an if does not conflict with an expression.
*/
static bool ValidateName(const gd::String& name);
static bool ValidateObjectName(const gd::String& objectName);
/**
* Return a message that will be displayed when an invalid object name has
* been entered.
*
* \note This message will be displayed by the IDE into a tooltip.
*/
static gd::String GetBadObjectNameWarning();
///@}
/** \name External source files
@@ -938,8 +924,6 @@ class GD_CORE_API Project : public ObjectsContainer {
///< are below this number )
bool verticalSync; ///< If true, must activate vertical synchronization.
gd::String scaleMode;
bool adaptGameResolutionAtRuntime; ///< Should the game resolution be adapted
///< to the window size at runtime
gd::String
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
///< "adaptWidth", "adaptHeight" or empty

View File

@@ -16,7 +16,6 @@ void PropertyDescriptor::SerializeTo(SerializerElement& element) const {
element.AddChild("value").SetStringValue(currentValue);
element.AddChild("type").SetStringValue(type);
element.AddChild("label").SetStringValue(label);
element.AddChild("description").SetStringValue(description);
SerializerElement& extraInformationElement =
element.AddChild("extraInformation");
extraInformationElement.ConsiderAsArray();
@@ -30,7 +29,6 @@ void PropertyDescriptor::UnserializeFrom(const SerializerElement& element) {
currentValue = element.GetChild("value").GetStringValue();
type = element.GetChild("type").GetStringValue();
label = element.GetChild("label").GetStringValue();
description = element.GetChild("description").GetStringValue();
extraInformation.clear();
const SerializerElement& extraInformationElement =

View File

@@ -16,15 +16,12 @@ namespace gd {
/**
* \brief Used to describe a property shown in a property grid.
* \see gd::Object
* \see gd::EffectMetadata
*/
class GD_CORE_API PropertyDescriptor {
public:
/**
* \brief Create a property being a simple gd::String with the specified
* value.
*
* \param propertyValue The value of the property.
* value. \param propertyValue The value of the property.
*/
PropertyDescriptor(gd::String propertyValue)
: currentValue(propertyValue), type("string"), label(""), hidden(false) {}
@@ -67,14 +64,6 @@ class GD_CORE_API PropertyDescriptor {
return *this;
}
/**
* \brief Change the description displayed to the user, if any.
*/
PropertyDescriptor& SetDescription(gd::String description_) {
description = description_;
return *this;
}
/**
* \brief Add an information about the property.
* \note The information are arbitrary and are interpreted by the class
@@ -90,7 +79,6 @@ class GD_CORE_API PropertyDescriptor {
const gd::String& GetValue() const { return currentValue; }
const gd::String& GetType() const { return type; }
const gd::String& GetLabel() const { return label; }
const gd::String& GetDescription() const { return description; }
const std::vector<gd::String>& GetExtraInfo() const {
return extraInformation;
}
@@ -128,7 +116,6 @@ class GD_CORE_API PropertyDescriptor {
type; ///< The type of the property. This is arbitrary and interpreted by
///< the class responsible for updating the property grid.
gd::String label; //< The user-friendly property name
gd::String description; //< The user-friendly property description
std::vector<gd::String>
extraInformation; ///< Can be used to store for example the available
///< choices, if a property is a displayed as a combo

View File

@@ -5,9 +5,7 @@
*/
#include "GDCore/Project/Variable.h"
#include <sstream>
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/String.h"
#include "GDCore/TinyXml/tinyxml.h"
@@ -21,7 +19,9 @@ namespace gd {
*/
double Variable::GetValue() const {
if (!isNumber) {
value = str.To<double>();
stringstream ss;
ss << str;
ss >> value;
isNumber = true;
}
@@ -30,7 +30,9 @@ double Variable::GetValue() const {
const gd::String& Variable::GetString() const {
if (isNumber) {
str = gd::String::From(value);
stringstream s;
s << (value);
str = s.str();
isNumber = false;
}
@@ -74,7 +76,6 @@ const Variable& Variable::GetChild(const gd::String& name) const {
void Variable::RemoveChild(const gd::String& name) {
if (!isStructure) return;
children.erase(name);
isStructure = !children.empty();
}
bool Variable::RenameChild(const gd::String& oldName,
@@ -189,7 +190,6 @@ void Variable::RemoveRecursively(const gd::Variable& variableToRemove) {
it++;
}
}
isStructure = !children.empty();
}
Variable::Variable(const Variable& other)

View File

@@ -95,14 +95,6 @@ void Serializer::FromXML(SerializerElement& element,
}
#endif
gd::String Serializer::ToEscapedXMLString(const gd::String& str) {
return str.FindAndReplace("&", "&amp;")
.FindAndReplace("'", "&apos;")
.FindAndReplace("\"", "&quot;")
.FindAndReplace("<", "&lt;")
.FindAndReplace(">", "&gt;");
}
namespace {
/**

View File

@@ -27,26 +27,14 @@ class GD_CORE_API Serializer {
static void FromXML(SerializerElement& element,
const TiXmlElement* xmlElement);
#endif
/**
* \brief Escape a string for inclusion in a XML tag
*/
static gd::String ToEscapedXMLString(const gd::String& str);
///@}
/** \name JSON serialization.
* Serialize a SerializerElement from/to JSON.
*/
///@{
/**
* \brief Serialize a gd::SerializerElement to a JSON string.
*/
static gd::String ToJSON(const SerializerElement& element);
static SerializerElement FromJSON(const std::string& json);
/**
* \brief Parse a JSON string and returns a gd::SerializerElement for it.
*/
static SerializerElement FromJSON(const gd::String& json) {
return FromJSON(json.ToUTF8());
}

View File

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

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