Compare commits

...

151 Commits

Author SHA1 Message Date
Florian Rival
26dd33854f Bump newIDE version 2019-01-30 22:17:33 +00:00
Florian Rival
1ed530d946 Add endless-up-runner and space-invaders examples 2019-01-30 21:55:11 +00:00
Florian Rival
b85008c269 Fix prettier 2019-01-30 21:52:49 +00:00
Florian Rival
08ddb6e519 Fix potential crash if new release without description 2019-01-30 21:35:12 +00:00
Florian Rival
d37c55e86f Update version of libGD.js 2019-01-28 23:43:12 +00:00
Florian Rival
e2c7e1a145 Merge pull request #780 from 4ian/feature/expression-parser-2
Use ExpressionParser2 as the default parser for expression in games
2019-01-28 23:36:07 +00:00
Florian Rival
6ebf40647e Bump newIDE version 2019-01-28 23:16:20 +00:00
Florian Rival
ed42f1c54a Fix wrong parameters in downhill-bike-physics-demo 2019-01-28 23:16:20 +00:00
Florian Rival
c94097acfb Fix deprecated usage of X and Y with point name 2019-01-28 23:16:20 +00:00
Florian Rival
9c6c8564fa Fix handling of object parameters in expressions 2019-01-28 23:16:20 +00:00
Florian Rival
4b33373296 Fix ConvertToString and code generation for strings with backlash/escaped characters 2019-01-28 23:16:20 +00:00
Florian Rival
7ce11c5252 Add expression parser test checking for big list of naughty strings 2019-01-28 23:16:20 +00:00
Florian Rival
0d864ce6a7 Update error message and add test case 2019-01-28 23:16:20 +00:00
Florian Rival
a6360152cd Fix typing 2019-01-28 23:16:20 +00:00
Florian Rival
827fdbf05a Bump GDevelop Core version 2019-01-28 23:16:20 +00:00
Florian Rival
a4c372d945 Convert PointX/PointY argument to a string 2019-01-28 23:16:20 +00:00
Florian Rival
93708cb2f3 Properly handle numbers with leading 0 (normalize them to remove the extra 0) 2019-01-28 23:16:19 +00:00
Florian Rival
3035bc9386 Improve error messages for empty expressions 2019-01-28 23:16:19 +00:00
Florian Rival
4c789967c3 Fix code generation of invalid variable expressions 2019-01-28 23:16:19 +00:00
Florian Rival
75797f2c41 Fix real-time error highlighting in case expression is being written 2019-01-28 23:16:19 +00:00
Florian Rival
571686f180 Add highlighting of errors 2019-01-28 23:16:19 +00:00
Florian Rival
df68978adc Add edge cases fixes and fuzzy tests for ExpressionParser2 2019-01-28 23:16:19 +00:00
Florian Rival
7a87fd9924 Add support for unary operator in ExpressionParser2 2019-01-28 23:16:19 +00:00
Florian Rival
8d1502cb20 Fix parsing of behaviors expressions 2019-01-28 23:16:19 +00:00
Florian Rival
34b5038bd5 Refactor to use the new ExpressionCodeGenerator (or old one with a flag) 2019-01-28 23:16:19 +00:00
Florian Rival
a9e1120f00 Add gd::ExpressionCodeGenerator::GenerateExpressionCode 2019-01-28 23:16:19 +00:00
Florian Rival
b14238c692 Use ExpressionParser2 for EventsVariablesFinder 2019-01-28 23:16:19 +00:00
Florian Rival
dfe4a75fbd Use ExpressionParser2 for EventsContextAnalyzer 2019-01-28 23:16:19 +00:00
Florian Rival
4fd88072e9 Improve ExpressionParser2 and use it for GenericExpressionField and EventsRefactorer 2019-01-28 23:16:19 +00:00
Florian Rival
f2e6f19c34 Add ExpressionParser2NodePrinter 2019-01-28 23:16:18 +00:00
Florian Rival
66029c62ed Add Variable code generation for ExpressionParser2 2019-01-28 23:16:18 +00:00
Florian Rival
43d78a74bd Enhance ExpressionParser2 and add ExpressionCodeGenerator 2019-01-28 23:16:18 +00:00
Florian Rival
0ec6ebad07 Add ExpressionParser2 and tests 2019-01-28 23:16:18 +00:00
Florian Rival
8743672038 Update links to social network pages/profiles 2019-01-28 23:02:31 +00:00
Florian Rival
3fd032d898 Fix potential crash when deleting events or instructions 2019-01-27 23:54:56 +00:00
Florian Rival
2b40f57189 Fix Duration parameter of Vibrate action 2019-01-24 23:12:37 +00:00
Wend1go
fc3f8a945b Add actions for loading/saving files (raw or JSON) to Filesystem (#884) 2019-01-24 22:04:43 +00:00
Florian Rival
ed24871130 Fix crash in profiler when using a lot of nested groups 2019-01-23 22:12:49 +00:00
Florian Rival
e416fb0586 Merge branch 'master' of github.com:4ian/GDevelop 2019-01-23 21:52:45 +00:00
Florian Rival
5778131deb Improve debugger performance 2019-01-23 21:52:31 +00:00
Todor Imreorov
8e81f78596 Remember zoom/grid/window mask state for scenes and external layouts (#892) 2019-01-23 21:23:09 +00:00
Todor Imreorov
1abdcaf0c0 Warn user when renaming resource that it might break objects (#899) 2019-01-23 19:14:24 +00:00
Florian Rival
4af867ba3a Fix expression transforming structure variable to JSON 2019-01-23 17:47:15 +00:00
Todor Imreorov
f75c2297d7 Fix "Locate File" and related menu options after a resource is renamed (#898) 2019-01-22 19:28:47 +01:00
Florian Rival
72c4f88936 Add screen-shake and update downhill-bike-physics-demo example 2019-01-21 16:48:10 +01:00
Florian Rival
34bcfdfee7 Customize the style of markdown rendered text 2019-01-20 20:54:47 +00:00
Florian Rival
7e78d4de5a Display changelog when launching a new version for first time
* Also display changelog in AboutDialog
2019-01-20 20:54:47 +00:00
Bouh
971b7a2322 Prevent renaming elements with an already existing name in Project Manager (#888) 2019-01-19 17:44:07 +00:00
Todor Imreorov
9a95aabc87 Add --disable-update-check option to disable check for updates (#887) 2019-01-19 16:28:38 +00:00
Florian Rival
53dcfa1cbf Fix enabling/disabling alert messages 2019-01-18 17:45:20 +00:00
Florian Rival
0ed7ccfb72 Set shortcut to close project to Ctrl/Cmd+Shift+W 2019-01-17 17:31:15 +00:00
Florian Rival
0fcd5cbbb9 Bump newIDE version 2019-01-17 17:30:48 +00:00
Florian Rival
fb6b959636 Add downhill-bike-physics-demo example 2019-01-14 22:42:26 +00:00
Florian Rival
1d7f0f9f94 Fix Prettier 2019-01-14 21:54:34 +00:00
Florian Rival
4be527c18a Try to prevent any crash by catching any exception when setting window title 2019-01-14 21:47:03 +00:00
Florian Rival
5e770d460d Merge branch 'master' of github.com:4ian/GDevelop 2019-01-14 21:25:31 +00:00
Florian Rival
73daf0e940 Fix Facebook instant games needing a bundle configuration file 2019-01-14 21:25:22 +00:00
Franco Maciel
58d88835c5 Fix initial motors speed in actions of Physics2 behavior (#872) 2019-01-14 21:09:09 +00:00
Florian Rival
0aa66837d4 Fix login dialog not showing on top of export dialog
Fix #868
2019-01-14 11:29:02 +00:00
Florian Rival
11349086c7 Update all remaining examples from old Physics engine to Physics Engine 2.0 2019-01-13 23:36:29 +00:00
Zat
d3d636744e Fix wheel joint argument definitions (#871) 2019-01-13 22:10:50 +00:00
Bouh
5baf2d9735 Fix sentence a FB Instant Game action (#869) 2019-01-13 19:13:04 +00:00
Florian Rival
d0daf0b5a8 Update bouncing-ball-and-rope example with new Physics engine 2019-01-12 17:35:39 +00:00
Florian Rival
21841e0bce Add Ragdoll example 2019-01-12 17:06:35 +00:00
Florian Rival
417ab2ff3d Gray out the deprecated Physics Engine category in InstructionSelector 2019-01-11 20:04:24 +00:00
Florian Rival
caee5fdcc7 Change default name of Physics2 behavior 2019-01-11 19:48:25 +00:00
Florian Rival
1fbd58fa75 Change wording of the old Physics extension 2019-01-11 19:48:25 +00:00
Florian Rival
389deadac5 Also improve flow typing of Debugger Toolbar
Note that the way translations are done might be changed later, but
this is for reference if needed.
2019-01-11 19:48:25 +00:00
Florian Rival
7d52165a82 Add deprecation alert for instructions of old Physics engine 2019-01-11 19:48:25 +00:00
Florian Rival
5e3e7e25fc Fix opening of ExpressionSelector not showing the top with the search field 2019-01-10 08:35:08 +00:00
Florian Rival
56afb11e2c Hide object drop-down list after an object is selected 2019-01-10 08:26:07 +00:00
Florian Rival
b6a0cfef32 Fix linter warning 2019-01-10 08:10:17 +00:00
Florian Rival
37c3a6d38a Add explicit "OK" button in message box to fix issue on Linux
See #856
2019-01-10 08:07:55 +00:00
Zat
30f830589c Add expressions relative to body to Physics2 behavior (#854) 2019-01-09 09:26:31 +00:00
Florian Rival
5f8546c3b9 Avoid crash of the debugger with Particle Emitters
This is done by using _renderer as the name for the renderer property,
with an underscore, which is filtered by the debugger when the game
is dumped.
2019-01-06 22:59:21 +00:00
Zat
4c2997b2d9 Add missing Physics2Behavior expressions (#848) 2019-01-06 20:43:12 +00:00
Franco Maciel
2338b5bfd6 Use AABB to check if cursor is on object (#852) 2019-01-06 20:23:19 +00:00
Franco Maciel
8a07e9b6c5 Prevent crash with repeated and aligned vertices in Physics2 behavior (#850) 2019-01-06 17:26:43 +00:00
Florian Rival
61303c7cf9 Fix Prettier 2019-01-06 00:59:07 +00:00
Florian Rival
43eaf30750 Fix error in Flow typing in recent Flow versions 2019-01-05 19:01:30 +00:00
Florian Rival
db278485fc Improve Flow typing 2019-01-05 18:42:19 +00:00
Florian Rival
3f5b42dc90 Fix tests of InstructionOrExpressionSelector and make them more robust against changes 2019-01-05 18:38:55 +00:00
Florian Rival
cd285b5676 Display icons in the list of instructions or expressions 2019-01-05 18:11:47 +00:00
Franco Maciel
509ac8966e Prevent undefined vertices in Physics2 behaviors (#845) 2019-01-05 17:03:42 +00:00
Florian Rival
bda2a10b5f Improve Flow typing of InstructionOrExpressionSelector 2019-01-05 17:03:11 +00:00
Florian Rival
841e1a66b6 Fix updating shared properties of Physics2 2019-01-05 13:52:18 +00:00
Franco Maciel
3fc588b6e3 Add a new editor (with Polygon support) for Physics2 engine (#825)
* Physics editor and custom polygon support
* Add shape preview
* Dynamic dimension labels in function of the shape
* Add polygon editor
* Preview box, circle and edge
* Prevent invalid properties values
* Add BehaviorsEditorService
2019-01-05 12:28:45 +00:00
Florian Rival
50ebf6e5a2 Add support for creating objects in JS extensions + example 2019-01-05 12:03:24 +00:00
Florian Rival
cbe33d2bd1 Improve/fix mistakes in gdjs.TextRuntimeObject documentation 2019-01-03 22:45:24 +00:00
Florian Rival
8c8c297adb Make mouse button labels more accessible 2019-01-03 21:07:18 +00:00
Florian Rival
a8d927994b Change the mouse button labels in newIDE 2019-01-03 21:07:18 +00:00
Florian Rival
1fb3231f98 Use constants to represents button in the game engine 2019-01-03 21:07:18 +00:00
Bouh
70a58f1bd4 Fix Middle mouse button handling (#841) 2019-01-03 18:34:03 +00:00
Franco Maciel
302bcb718f Fix initial opacity undefined 2019-01-03 13:59:08 +00:00
Florian Rival
857c706f48 Add help link for PanelSprite object editor 2018-12-30 22:55:11 +01:00
Wend1go
5b5f91c1f9 Add example for screenshot extension (#835) 2018-12-30 21:54:15 +01:00
Wend1go
0652e19190 Brighten up Screenshot icons to better fit the dark theme (#834) 2018-12-30 11:34:25 +01:00
Wend1go
5feb4caa31 Add FileSystem extension (special path, file existence and creating directory) (#828) 2018-12-29 20:11:53 +01:00
Florian Rival
1cd5519b93 Fix snapshot tests 2018-12-29 20:08:56 +01:00
Florian Rival
96761c461d Adapt descriptions of storage actions to make clear that no files are written 2018-12-29 18:27:21 +01:00
Florian Rival
1a82663968 Add dismissable alerts to warn/help the user 2018-12-27 18:50:15 +01:00
Florian Rival
9111b56eb3 Add GetAngle/Get(X|Y)Velocity to top-down behavior 2018-12-27 16:53:44 +01:00
Florian Rival
d7f22bcf26 Update isometric-game example 2018-12-27 14:02:05 +01:00
Florian Rival
b9b0ed812d Update Platformer example 2018-12-27 12:03:00 +01:00
Florian Rival
6734644df4 Fix non prettified files 2018-12-27 12:00:51 +01:00
Florian Rival
ddeff6bfae Add shortcut to open Project Manager and focus search field when opening 2018-12-27 11:56:01 +01:00
Florian Rival
8f10eac512 Fix snapshot tests 2018-12-27 11:37:31 +01:00
Florian Rival
162524f779 Automatically close project manager after opening functions 2018-12-27 11:19:32 +01:00
Wend1go
1da347b08b Add Screenshot extension (for games running on Windows/macOS/Linux) (#806)
* Add functionality to take screenshots, when running on Electron.
2018-12-27 11:07:42 +01:00
Florian Rival
01b7f81507 Fix regression on rounding of platformer object X position and skeleton collision 2018-12-26 23:22:10 +01:00
Florian Rival
5a3d2cc2b9 Reduce iterations of polygon benchmark 2018-12-26 23:22:10 +01:00
Florian Rival
cb659eee6d Add pixel-perfect-platform-engine and update other examples 2018-12-26 23:22:10 +01:00
Florian Rival
0f24410a2e Fix platform engine 1-pixel offset bug
* "Bug" is fixed by ignoring edges when doing collision tests for
the platform engine.
* Also add an option to round coordinates and ensure pixel-perfect
alignement of characters on platforms (on by default)
* Also add an optional parameter to ignore edges when
doing a collision test (or when separating objects)
2018-12-26 23:22:10 +01:00
Todor Imreorov
a31ea1475d Add button to choose a new file for a resource in ResourcePropertiesEditor (#822) 2018-12-26 17:55:59 +01:00
Todor Imreorov
0cecf685ca Autoclose project manager when opening an editor (#826) 2018-12-26 14:36:49 +01:00
Florian Rival
f39af51fda Add benchmark for polygon collision test and add test runner for Firefox 2018-12-26 13:45:45 +01:00
Florian Rival
704eaacc7e Enable back all GDJS tests 2018-12-26 12:52:51 +01:00
Florian Rival
1f7bec0ff1 Add option to set scale mode ("sampling") of the game to nearest ("pixel-perfect") 2018-12-25 23:27:09 +01:00
Florian Rival
69ffa45ea9 Fix touch/mouse handling regression 2018-12-25 21:37:11 +01:00
Florian Rival
2558052a61 Fix visual artifacts when rendering rescaled games.
Artifacts where visible on rescaled games, especially when canvas
was small and the game pixel perfect. This was due to changing
Pixi renderer size instead of scaling the canvas.

For a perfect "pixel perfect" rendering, "image-rendering: pixelated"
would be needed on the canvas (to be added as a game settings)
(see for instance: https://gablaxian.com/articles/creating-a-game-with-javascript/scaling-the-canvas)
2018-12-25 18:15:27 +01:00
Florian Rival
abf40200cb Fix prettier for ExamplesInformation.js (auto-generated file) 2018-12-24 19:36:27 +01:00
Florian Rival
2fd4459364 Add 2 example for the new Physics Engine 2018-12-24 18:34:10 +01:00
Florian Rival
2ed9088b58 Fix lint warnings 2018-12-24 18:02:39 +01:00
Florian Rival
f69b9132ad Add test case for JSON array with numbers 2018-12-24 14:02:58 +01:00
Franco Maciel
fb7d3d589d Fix LShift key code (#823) 2018-12-24 13:19:08 +01:00
Franco Maciel
87acba5105 Fix JSON array parser separators (#819) 2018-12-23 19:17:36 +01:00
Franco Maciel
2d314ff51b Add New physics behavior (Physics2) (#775) 2018-12-23 00:15:25 +01:00
Florian Rival
5054678193 Fix functions list rendering and always shown functions in project manager 2018-12-22 23:44:25 +01:00
Todor Imreorov
aaf9d318a9 Add error color to resources with missing files (#818) 2018-12-22 22:52:34 +01:00
Florian Rival
cc92445d4c Update READMEs with more links/information/commands 2018-12-22 16:39:19 +01:00
Florian Rival
1649591442 Add check-format to check non prettified files and add it to TravisCI 2018-12-22 12:09:04 +01:00
Florian Rival
77faff3919 Upgrade Prettier and run Prettier on newIDE/app/src to fix some files 2018-12-22 11:41:50 +01:00
Florian Rival
873280d818 Fix tests after libGD.js update 2018-12-22 00:05:21 +01:00
Florian Rival
238b6a2a09 Fix un/serialization of JSON arrays by gd::Serializer 2018-12-21 21:02:13 +01:00
Florian Rival
98d0d5102e Bump newIDE version 2018-12-20 22:05:25 +00:00
Florian Rival
47818846e7 Fix Jfxr not opening 2018-12-20 21:56:27 +00:00
Florian Rival
8276eda243 Bump newIDE version 2018-12-20 17:51:36 +00:00
Todor Imreorov
ca2e00bd91 Add input for setting FPS for animation playback speed (#814) 2018-12-20 16:08:44 +00:00
Franco Maciel
6177b0197e Don't load AdMob ads if already loading/showing (#817) 2018-12-19 15:20:04 +00:00
Florian Rival
fb65b56cb7 Remove Submit Your Example button from web-app 2018-12-18 08:46:26 +00:00
Todor Imreorov
6f780f79e9 Add field to change time between frames to AnimationPreview (#811) 2018-12-18 08:44:29 +00:00
Florian Rival
d31f0793d5 Set default time between frames to 0.08 2018-12-18 08:14:20 +00:00
Todor Imreorov
88c88ad1eb Add menu item to remove all resources with invalid paths (#812) 2018-12-17 21:25:39 +00:00
Franco Maciel
4202e2672d Add actions to set Sprite size in pixels (#808) 2018-12-17 16:45:47 +00:00
Florian Rival
f29cc503bf Fix version number not properly applied to Android/Cordova builds
Fix #804
2018-12-16 13:58:26 +00:00
Florian Rival
1aa81949ce Fix AdMob extension not loaded in web-app 2018-12-16 12:56:30 +00:00
Florian Rival
4593f09131 Fix empty menu options shown in scene editor context menu 2018-12-16 12:49:47 +00:00
Florian Rival
782ea0e0af Fix right click in CodeEditor that could trigger the event context menu 2018-12-16 12:42:17 +00:00
Florian Rival
8e893e660b Add hint text on ObjectSelector 2018-12-16 12:28:51 +00:00
Florian Rival
384346c54e Fix horizontal scrollbar displayed in events + prettify EventsSheet.css 2018-12-16 12:25:04 +00:00
Florian Rival
df3920cce3 Fix link to help page for mouse action/conditions 2018-12-16 12:17:29 +00:00
718 changed files with 144837 additions and 25882 deletions

View File

@@ -69,6 +69,7 @@ script:
- cd newIDE/app
- npm test
- npm run flow
- npm run check-format
- cd ../..
#GDJS game engine tests, disabled on Travis CI because ChromeHeadless can't be started.
#See them running on Semaphore-CI instead: https://semaphoreci.com/4ian/gd

View File

@@ -97,6 +97,7 @@
// Support for Flowtype:
"javascript.validate.enable": false,
"flow.useNPMPackagedFlow": true,
"flow.useLSP": false, // As we are in a monorepo, see https://github.com/flowtype/flow-for-vscode/issues/301
// Clang format styling (duplicated in scripts/CMakeClangUtils.txt)
"C_Cpp.clang_format_style": "{BasedOnStyle: Google, BinPackParameters: false, BinPackArguments: false}"

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 B

View File

@@ -0,0 +1,194 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 31.999999 32.000001"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="filesystem_create_folder.svg"
inkscape:export-filename="/home/matthias/Programme/GD_MyFork/GDevelop/Binaries/Output/Release_Windows/JsPlatform/Extensions/create_folder16.png"
inkscape:export-xdpi="45"
inkscape:export-ydpi="45">
<defs
id="defs4">
<inkscape:path-effect
effect="skeletal"
id="path-effect6855"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect6842"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect4583"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4234"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#617da1;fill-opacity:1;fill-rule:evenodd;stroke:#617da1;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4231"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.919596"
inkscape:cx="-14.99721"
inkscape:cy="14.343353"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:window-width="1920"
inkscape:window-height="1026"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-global="false"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="false"
inkscape:object-nodes="false"
inkscape:snap-smooth-nodes="false"
inkscape:snap-midpoints="false"
inkscape:snap-nodes="true"
units="px">
<inkscape:grid
type="xygrid"
id="grid6838" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="bg"
inkscape:groupmode="layer"
id="layer1"
style="opacity:0"
sodipodi:insensitive="true"
transform="translate(0,-1020.3622)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.48900003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5d3b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4136"
width="537.14288"
height="537.14288"
x="108.57143"
y="232.3622"
ry="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="vg"
transform="translate(0,-1020.3622)">
<path
style="opacity:1;fill:#80bbdb;fill-opacity:1;fill-rule:nonzero;stroke:#548dad;stroke-width:0.97142506;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 10.44448,1025.9309 c 0.65513,0 1.18165,0.5595 1.18165,1.2556 l 0,1.2733 16.256617,0 c 1.376723,0 2.484776,1.1774 2.484776,2.6403 l 0,13.0531 c 0,1.4629 -1.108053,2.6403 -2.484776,2.6403 l -23.7654964,0 c -1.3767228,0 -2.4847757,-1.1774 -2.4847757,-2.6403 l 0,-10.7551 0,-2.298 0,-3.9136 c 0,-0.6961 0.5265186,-1.2556 1.1816486,-1.2556 z"
id="rect4901"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sscssssssccsss" />
<path
style="opacity:1;fill:#5fa1c7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.1084458,1031.4784 0,0.7321 0,11.4039 c 0,1.5514 1.0713447,2.7998 2.4024592,2.7998 l 22.978188,0 c 1.331114,0 2.40246,-1.2484 2.40246,-2.7998 l 0,-12.136 -27.7831072,0 z"
id="path4919"
inkscape:connector-curvature="0" />
<path
sodipodi:type="star"
style="opacity:1;fill:#d9db30;fill-opacity:1;fill-rule:nonzero;stroke:#bec021;stroke-width:1.38540256;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4939"
sodipodi:sides="5"
sodipodi:cx="24.252151"
sodipodi:cy="1028.8562"
sodipodi:r1="7.8899426"
sodipodi:r2="3.9449718"
sodipodi:arg1="0.79249024"
sodipodi:arg2="1.4208088"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 29.791477,1034.4747 -4.949845,-1.7178 -4.221206,3.1037 0.104117,-5.2384 -4.256247,-3.0555 5.014193,-1.5197 1.590701,-4.9922 2.994825,4.2992 5.239353,-0.03 -3.163289,4.1767 z"
inkscape:transform-center-x="0.36431952"
inkscape:transform-center-y="-0.39846334" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

View File

@@ -0,0 +1,206 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 31.999999 32.000001"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="filesystem_file_delete.svg"
inkscape:export-filename="/home/matthias/Programme/GD_MyFork/GDevelop/Binaries/Output/Release_Windows/JsPlatform/Extensions/filesystem_file_delete32.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs4">
<inkscape:path-effect
effect="skeletal"
id="path-effect6855"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect6842"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect4583"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4234"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#617da1;fill-opacity:1;fill-rule:evenodd;stroke:#617da1;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4231"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="56.026486"
inkscape:cy="-2.8092946"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:window-width="1920"
inkscape:window-height="1026"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-global="false"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="false"
inkscape:object-nodes="false"
inkscape:snap-smooth-nodes="false"
inkscape:snap-midpoints="false"
inkscape:snap-nodes="true"
units="px"
inkscape:snap-grids="false">
<inkscape:grid
type="xygrid"
id="grid6838" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="bg"
inkscape:groupmode="layer"
id="layer1"
style="opacity:0"
sodipodi:insensitive="true"
transform="translate(0,-1020.3622)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.48900003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5d3b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4136"
width="537.14288"
height="537.14288"
x="108.57143"
y="232.3622"
ry="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="vg"
transform="translate(0,-1020.3622)">
<g
id="g4225"
transform="matrix(1.1128183,0,0,1.1128183,55.344213,-128.05315)">
<path
id="rect4177"
transform="translate(-9.5367432e-7,1020.3622)"
d="m -43.681641,13.882812 c -0.563451,0 -1.017578,0.452174 -1.017578,1.015626 l 0,22.210937 c 0,0.563451 0.454127,1.015625 1.017578,1.015625 l 16.652344,0 c 0.563451,0 1.017578,-0.452174 1.017578,-1.015625 l 0,-15.246094 -6.05664,-7.980469 -11.613282,0 z"
style="opacity:1;fill:#fcfdf1;fill-opacity:1;fill-rule:nonzero;stroke:#6e6f5e;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4218"
d="m -31.837816,1034.2449 0,7.043 c 0,0.3498 0.283047,0.6328 0.632812,0.6328 l 5.19336,0 -5.826172,-7.6758 z"
style="opacity:1;fill:#fcfdf1;fill-opacity:1;fill-rule:nonzero;stroke:#6e6f5e;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<rect
style="opacity:1;fill:#a6a6a6;fill-opacity:1;fill-rule:nonzero;stroke:#5a5a5a;stroke-width:0.99999934;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4158"
width="8.9121208"
height="8.7162371"
x="10.293939"
y="1038.0229" />
<rect
style="opacity:1;fill:#a6a6a6;fill-opacity:1;fill-rule:nonzero;stroke:#5a5a5a;stroke-width:0.99999934;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4160"
width="8.9631233"
height="2.6948419"
x="-516.44586"
y="897.6803"
inkscape:transform-center-x="-3.1829089"
inkscape:transform-center-y="-3.4427076"
transform="matrix(0.86246101,-0.50612351,0.50612351,0.86246101,0,0)" />
<rect
y="1044.6921"
x="8.1238213"
height="1.985044"
width="2.0916421"
id="rect4162"
style="opacity:1;fill:#a6a6a6;fill-opacity:1;fill-rule:nonzero;stroke:#5a5a5a;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 B

View File

@@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 31.999999 32.000001"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="filesystem_file.svg"
inkscape:export-filename="/home/matthias/Programme/GD_MyFork/GDevelop/Binaries/Output/Release_Windows/JsPlatform/Extensions/filesystem_file16.png"
inkscape:export-xdpi="45"
inkscape:export-ydpi="45">
<defs
id="defs4">
<inkscape:path-effect
effect="skeletal"
id="path-effect6855"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect6842"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect4583"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4234"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#617da1;fill-opacity:1;fill-rule:evenodd;stroke:#617da1;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4231"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.959798"
inkscape:cx="-51.539982"
inkscape:cy="23.000437"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:window-width="1920"
inkscape:window-height="1026"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-global="false"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="false"
inkscape:object-nodes="false"
inkscape:snap-smooth-nodes="false"
inkscape:snap-midpoints="false"
inkscape:snap-nodes="true"
units="px">
<inkscape:grid
type="xygrid"
id="grid6838" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="bg"
inkscape:groupmode="layer"
id="layer1"
style="opacity:0"
sodipodi:insensitive="true"
transform="translate(0,-1020.3622)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.48900003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5d3b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4136"
width="537.14288"
height="537.14288"
x="108.57143"
y="232.3622"
ry="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="vg"
transform="translate(0,-1020.3622)">
<g
id="g4225"
transform="matrix(1.1128183,0,0,1.1128183,55.344213,-128.05315)">
<path
id="rect4177"
transform="translate(-9.5367432e-7,1020.3622)"
d="m -43.681641,13.882812 c -0.563451,0 -1.017578,0.452174 -1.017578,1.015626 l 0,22.210937 c 0,0.563451 0.454127,1.015625 1.017578,1.015625 l 16.652344,0 c 0.563451,0 1.017578,-0.452174 1.017578,-1.015625 l 0,-15.246094 -6.05664,-7.980469 -11.613282,0 z"
style="opacity:1;fill:#fcfdf1;fill-opacity:1;fill-rule:nonzero;stroke:#6e6f5e;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4218"
d="m -31.837816,1034.2449 0,7.043 c 0,0.3498 0.283047,0.6328 0.632812,0.6328 l 5.19336,0 -5.826172,-7.6758 z"
style="opacity:1;fill:#fcfdf1;fill-opacity:1;fill-rule:nonzero;stroke:#6e6f5e;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

View File

@@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 31.999999 32.000001"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="filesystem_folder.svg"
inkscape:export-filename="/home/matthias/Programme/GD_MyFork/GDevelop/Binaries/Output/Release_Windows/JsPlatform/Extensions/filesystem_folder16.png"
inkscape:export-xdpi="45"
inkscape:export-ydpi="45">
<defs
id="defs4">
<inkscape:path-effect
effect="skeletal"
id="path-effect6855"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect6842"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect4583"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4234"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#617da1;fill-opacity:1;fill-rule:evenodd;stroke:#617da1;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4231"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.919596"
inkscape:cx="3.5385856"
inkscape:cy="13.013876"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:window-width="1920"
inkscape:window-height="1026"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-global="false"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="false"
inkscape:object-nodes="false"
inkscape:snap-smooth-nodes="false"
inkscape:snap-midpoints="false"
inkscape:snap-nodes="true"
units="px">
<inkscape:grid
type="xygrid"
id="grid6838" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="bg"
inkscape:groupmode="layer"
id="layer1"
style="opacity:0"
sodipodi:insensitive="true"
transform="translate(0,-1020.3622)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.48900003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5d3b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4136"
width="537.14288"
height="537.14288"
x="108.57143"
y="232.3622"
ry="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="vg"
transform="translate(0,-1020.3622)">
<path
style="opacity:1;fill:#80bbdb;fill-opacity:1;fill-rule:nonzero;stroke:#548dad;stroke-width:0.97142506;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 10.44448,1025.9309 c 0.65513,0 1.18165,0.5595 1.18165,1.2556 l 0,1.2733 16.256617,0 c 1.376723,0 2.484776,1.1774 2.484776,2.6403 l 0,13.0531 c 0,1.4629 -1.108053,2.6403 -2.484776,2.6403 l -23.7654964,0 c -1.3767228,0 -2.4847757,-1.1774 -2.4847757,-2.6403 l 0,-10.7551 0,-2.298 0,-3.9136 c 0,-0.6961 0.5265186,-1.2556 1.1816486,-1.2556 z"
id="rect4901"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sscssssssccsss" />
<path
style="opacity:1;fill:#5fa1c7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.1084458,1031.4784 0,0.7321 0,11.4039 c 0,1.5514 1.0713447,2.7998 2.4024592,2.7998 l 22.978188,0 c 1.331114,0 2.40246,-1.2484 2.40246,-2.7998 l 0,-12.136 -27.7831072,0 z"
id="path4919"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

View File

@@ -0,0 +1,203 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 31.999999 32.000001"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="filesystem_load_file.svg"
inkscape:export-filename="/home/matthias/Programme/GD_MyFork/GDevelop/Binaries/Output/Release_Windows/JsPlatform/Extensions/filesystem_load_file16.png"
inkscape:export-xdpi="45"
inkscape:export-ydpi="45">
<defs
id="defs4">
<inkscape:path-effect
effect="skeletal"
id="path-effect6855"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect6842"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect4583"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4234"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#617da1;fill-opacity:1;fill-rule:evenodd;stroke:#617da1;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4231"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="-15.256846"
inkscape:cy="-4.5327826"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="true"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:window-width="1920"
inkscape:window-height="1026"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-global="false"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-nodes="true"
units="px">
<inkscape:grid
type="xygrid"
id="grid6838" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="bg"
inkscape:groupmode="layer"
id="layer1"
style="opacity:0"
sodipodi:insensitive="true"
transform="translate(0,-1020.3622)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.48900003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5d3b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4136"
width="537.14288"
height="537.14288"
x="108.57143"
y="232.3622"
ry="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="vg"
transform="translate(0,-1020.3622)">
<g
id="g4206">
<path
id="rect4177"
d="m 6.7344825,1022.8736 c -0.6270186,0 -1.1323794,0.5032 -1.1323794,1.1303 l 0,24.7167 c 0,0.627 0.5053608,1.1302 1.1323794,1.1302 l 18.5310335,0 c 0.627018,0 1.132379,-0.5032 1.132379,-1.1302 l 0,-16.9661 -6.73994,-8.8809 -12.9234725,0 z"
style="opacity:1;fill:#fcfdf1;fill-opacity:1;fill-rule:nonzero;stroke:#6e6f5e;stroke-width:1.66922748;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4218"
d="m 19.914509,1022.8735 0,7.8376 c 0,0.3892 0.31498,0.7042 0.704204,0.7042 l 5.779267,0 -6.483471,-8.5418 z"
style="opacity:1;fill:#fcfdf1;fill-opacity:1;fill-rule:nonzero;stroke:#6e6f5e;stroke-width:1.66922748;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="g4202"
transform="translate(-0.22767735,0)">
<ellipse
style="opacity:1;fill:#d4d68c;fill-opacity:1;fill-rule:nonzero;stroke:#c8cb6c;stroke-width:0.69685775;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="ellipse4194"
cx="16.227676"
cy="1044.2556"
rx="7.8167491"
ry="1.7860432" />
<ellipse
ry="0.47607893"
rx="3.9621422"
cy="1044.1664"
cx="16.227676"
id="ellipse4198"
style="opacity:1;fill:#fcfdf1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.45964342;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<path
style="fill:#368fac;fill-opacity:1;fill-rule:evenodd;stroke:#2b7188;stroke-width:0.81720334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 15.999999,1032.9608 -4.451864,5.7416 2.225932,0 0,5.1577 4.451864,0 0,-5.1577 2.225932,0 z"
id="path4210"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 31.999999 32.000001"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="filesystem_path_exists.svg"
inkscape:export-filename="/home/matthias/Programme/GD_MyFork/GDevelop/Binaries/Output/Release_Windows/JsPlatform/Extensions/filesystem_path_exists16.png"
inkscape:export-xdpi="45"
inkscape:export-ydpi="45">
<defs
id="defs4">
<inkscape:path-effect
effect="skeletal"
id="path-effect6855"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect6842"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect4583"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4234"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#617da1;fill-opacity:1;fill-rule:evenodd;stroke:#617da1;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4231"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.919596"
inkscape:cx="3.5385856"
inkscape:cy="13.013876"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:window-width="1920"
inkscape:window-height="1026"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-global="false"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="false"
inkscape:object-nodes="false"
inkscape:snap-smooth-nodes="false"
inkscape:snap-midpoints="false"
inkscape:snap-nodes="true"
units="px">
<inkscape:grid
type="xygrid"
id="grid6838" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="bg"
inkscape:groupmode="layer"
id="layer1"
style="opacity:0"
sodipodi:insensitive="true"
transform="translate(0,-1020.3622)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.48900003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5d3b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4136"
width="537.14288"
height="537.14288"
x="108.57143"
y="232.3622"
ry="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="vg"
transform="translate(0,-1020.3622)">
<path
style="opacity:1;fill:#80bbdb;fill-opacity:1;fill-rule:nonzero;stroke:#548dad;stroke-width:0.97142506;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 10.44448,1025.9309 c 0.65513,0 1.18165,0.5595 1.18165,1.2556 l 0,1.2733 16.256617,0 c 1.376723,0 2.484776,1.1774 2.484776,2.6403 l 0,13.0531 c 0,1.4629 -1.108053,2.6403 -2.484776,2.6403 l -23.7654964,0 c -1.3767228,0 -2.4847757,-1.1774 -2.4847757,-2.6403 l 0,-10.7551 0,-2.298 0,-3.9136 c 0,-0.6961 0.5265186,-1.2556 1.1816486,-1.2556 z"
id="rect4901"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sscssssssccsss" />
<path
style="opacity:1;fill:#5fa1c7;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.1084458,1031.4784 0,0.7321 0,11.4039 c 0,1.5514 1.0713447,2.7998 2.4024592,2.7998 l 22.978188,0 c 1.331114,0 2.40246,-1.2484 2.40246,-2.7998 l 0,-12.136 -27.7831072,0 z"
id="path4919"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:33.25431824px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#9b80db;fill-opacity:1;stroke:#6e6f5e;stroke-width:1.19503343;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
x="5.8434677"
y="1048.4673"
id="text4229"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4231"
x="5.8434677"
y="1048.4673"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';fill:#9b80db;fill-opacity:1;stroke:#6e6f5e;stroke-width:1.19503343;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">?</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 984 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,203 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 31.999999 32.000001"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="filesystem_save_file.svg"
inkscape:export-filename="/home/matthias/Programme/GD_MyFork/GDevelop/Binaries/Output/Release_Windows/JsPlatform/Extensions/filesystem_save_file32.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs4">
<inkscape:path-effect
effect="skeletal"
id="path-effect6855"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect6842"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect4583"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4234"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#617da1;fill-opacity:1;fill-rule:evenodd;stroke:#617da1;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4231"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="30.546725"
inkscape:cy="-3.8184969"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="true"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:window-width="1920"
inkscape:window-height="1026"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-global="false"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-nodes="true"
units="px">
<inkscape:grid
type="xygrid"
id="grid6838" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="bg"
inkscape:groupmode="layer"
id="layer1"
style="opacity:0"
sodipodi:insensitive="true"
transform="translate(0,-1020.3622)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.48900003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5d3b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4136"
width="537.14288"
height="537.14288"
x="108.57143"
y="232.3622"
ry="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="vg"
transform="translate(0,-1020.3622)">
<g
id="g4206">
<path
id="rect4177"
d="m 6.7344825,1022.8736 c -0.6270186,0 -1.1323794,0.5032 -1.1323794,1.1303 l 0,24.7167 c 0,0.627 0.5053608,1.1302 1.1323794,1.1302 l 18.5310335,0 c 0.627018,0 1.132379,-0.5032 1.132379,-1.1302 l 0,-16.9661 -6.73994,-8.8809 -12.9234725,0 z"
style="opacity:1;fill:#fcfdf1;fill-opacity:1;fill-rule:nonzero;stroke:#6e6f5e;stroke-width:1.66922748;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4218"
d="m 19.914509,1022.8735 0,7.8376 c 0,0.3892 0.31498,0.7042 0.704204,0.7042 l 5.779267,0 -6.483471,-8.5418 z"
style="opacity:1;fill:#fcfdf1;fill-opacity:1;fill-rule:nonzero;stroke:#6e6f5e;stroke-width:1.66922748;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="g4202"
transform="translate(-0.22767735,0)">
<ellipse
style="opacity:1;fill:#d4d68c;fill-opacity:1;fill-rule:nonzero;stroke:#c8cb6c;stroke-width:0.69685775;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="ellipse4194"
cx="16.227676"
cy="1044.2556"
rx="7.8167491"
ry="1.7860432" />
<ellipse
ry="0.47607893"
rx="3.9621422"
cy="1044.1664"
cx="16.227676"
id="ellipse4198"
style="opacity:1;fill:#fcfdf1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.45964342;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<path
style="fill:#6aac36;fill-opacity:1;fill-rule:evenodd;stroke:#54882b;stroke-width:0.81720334;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 15.999999,1043.6019 -4.451864,-5.7416 2.225932,0 0,-5.1577 4.451864,0 0,5.1577 2.225932,0 z"
id="path4210"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 899 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 814 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1011 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,224 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 31.999999 32.000001"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="take_screenshot.svg"
inkscape:export-filename="/home/matthias/Programme/GD_MyFork/GDevelop/Binaries/Output/Release_Windows/JsPlatform/Extensions/take_screenshot16.png"
inkscape:export-xdpi="45"
inkscape:export-ydpi="45">
<defs
id="defs4">
<inkscape:path-effect
effect="skeletal"
id="path-effect6933"
is_visible="true"
pattern="m -9.5367432e-7,1025.3622 c 0,-2.76 2.23999995367432,-5 4.99999995367432,-5 2.76,0 5,2.24 5,5 0,2.76 -2.24,5 -5,5 -2.76,0 -4.99999995367432,-2.24 -4.99999995367432,-5 z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect6855"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect6842"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<inkscape:path-effect
effect="skeletal"
id="path-effect4583"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 Z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4234"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#617da1;fill-opacity:1;fill-rule:evenodd;stroke:#617da1;stroke-width:1pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4231"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313709"
inkscape:cx="0.48062283"
inkscape:cy="15.066705"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="true"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:window-width="1920"
inkscape:window-height="1026"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-global="false"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="false"
inkscape:object-nodes="false"
inkscape:snap-smooth-nodes="false"
inkscape:snap-midpoints="false"
inkscape:snap-nodes="true"
units="px">
<inkscape:grid
type="xygrid"
id="grid6838" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="bg"
inkscape:groupmode="layer"
id="layer1"
style="opacity:0"
sodipodi:insensitive="true"
transform="translate(0,-1020.3622)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.48900003;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5d3b0b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4136"
width="537.14288"
height="537.14288"
x="108.57143"
y="232.3622"
ry="0" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="vg"
transform="translate(0,-1020.3622)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#535353;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4139"
width="31.889814"
height="20.333548"
x="0.055091862"
y="1026.1954"
ry="2.8092401" />
<circle
style="opacity:1;fill:#8c8c8c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4208"
cx="15.999999"
cy="1038.0809"
r="6.34375" />
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4210"
width="5.0598979"
height="5.2740483"
x="2.8781402"
y="1028.0603"
ry="2.6370242" />
<rect
style="opacity:1;fill:#535353;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4212"
width="11.124999"
height="4.3597975"
x="19.03125"
y="1023.6198"
ry="1.2027028" />
<rect
ry="0.59375"
y="1024.6122"
x="20.748579"
height="2.375"
width="7.6903405"
id="rect4214"
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
r="4.75"
cy="1038.0809"
cx="15.999999"
id="circle4216"
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -3,6 +3,7 @@
#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"
@@ -13,8 +14,8 @@
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/Project.h"
using namespace std;
@@ -295,11 +296,14 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
if (!GetObjectsAndGroups().HasObjectNamed(objectInParameter) &&
!GetGlobalObjectsAndGroups().HasObjectNamed(objectInParameter) &&
!GetObjectsAndGroups().GetObjectGroups().Has(objectInParameter) &&
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(objectInParameter)) {
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(
objectInParameter)) {
condition.SetParameter(pNb, gd::Expression(""));
condition.SetType("");
} else if (!instrInfos.parameters[pNb].supplementaryInformation.empty() &&
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(), GetObjectsAndGroups(), objectInParameter) !=
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(),
GetObjectsAndGroups(),
objectInParameter) !=
instrInfos.parameters[pNb].supplementaryInformation) {
condition.SetParameter(pNb, gd::Expression(""));
condition.SetType("");
@@ -328,7 +332,8 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
gd::String objectName = condition.GetParameters().empty()
? ""
: condition.GetParameter(0).GetPlainString();
gd::String objectType = gd::GetTypeOfObject(GetGlobalObjectsAndGroups(), GetObjectsAndGroups(), objectName);
gd::String objectType = gd::GetTypeOfObject(
GetGlobalObjectsAndGroups(), GetObjectsAndGroups(), objectName);
if (!objectName.empty() &&
MetadataProvider::HasObjectCondition(
platform, objectType, condition.GetType()) &&
@@ -473,11 +478,14 @@ gd::String EventsCodeGenerator::GenerateActionCode(
if (!GetObjectsAndGroups().HasObjectNamed(objectInParameter) &&
!GetGlobalObjectsAndGroups().HasObjectNamed(objectInParameter) &&
!GetObjectsAndGroups().GetObjectGroups().Has(objectInParameter) &&
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(objectInParameter)) {
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(
objectInParameter)) {
action.SetParameter(pNb, gd::Expression(""));
action.SetType("");
} else if (!instrInfos.parameters[pNb].supplementaryInformation.empty() &&
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(), GetObjectsAndGroups(), objectInParameter) !=
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(),
GetObjectsAndGroups(),
objectInParameter) !=
instrInfos.parameters[pNb].supplementaryInformation) {
action.SetParameter(pNb, gd::Expression(""));
action.SetType("");
@@ -496,7 +504,8 @@ gd::String EventsCodeGenerator::GenerateActionCode(
gd::String objectName = action.GetParameters().empty()
? ""
: action.GetParameter(0).GetPlainString();
gd::String objectType = gd::GetTypeOfObject(GetGlobalObjectsAndGroups(), GetObjectsAndGroups(), objectName);
gd::String objectType = gd::GetTypeOfObject(
GetGlobalObjectsAndGroups(), GetObjectsAndGroups(), objectName);
if (MetadataProvider::HasObjectAction(
platform, objectType, action.GetType()) &&
!instrInfos.parameters.empty()) {
@@ -588,28 +597,18 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
gd::String argOutput;
if (ParameterMetadata::IsExpression("number", metadata.type)) {
CallbacksForGeneratingExpressionCode callbacks(argOutput, *this, context);
gd::ExpressionParser parser(parameter);
if (!parser.ParseMathExpression(platform, GetGlobalObjectsAndGroups(), GetObjectsAndGroups(), callbacks)) {
cout << "Error :" << parser.GetFirstError() << " in: " << parameter
<< endl;
argOutput = "0";
}
if (argOutput.empty()) argOutput = "0";
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, "number", parameter);
} else if (ParameterMetadata::IsExpression("string", metadata.type)) {
CallbacksForGeneratingExpressionCode callbacks(argOutput, *this, context);
gd::ExpressionParser parser(parameter);
if (!parser.ParseStringExpression(platform, GetGlobalObjectsAndGroups(), GetObjectsAndGroups(), callbacks)) {
cout << "Error in text expression" << parser.GetFirstError() << endl;
argOutput = "\"\"";
}
if (argOutput.empty()) argOutput = "\"\"";
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, "string", parameter);
} else if (ParameterMetadata::IsExpression("variable", metadata.type)) {
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, metadata.type, parameter, previousParameter);
} else if (ParameterMetadata::IsObject(metadata.type)) {
// It would be possible to run a gd::ExpressionCodeGenerator if later
// objects can have nested objects, or function returning objects.
argOutput = GenerateObject(parameter, metadata.type, context);
} else if (metadata.type == "relationalOperator") {
argOutput += parameter == "=" ? "==" : parameter;
if (argOutput != "==" && argOutput != "<" && argOutput != ">" &&
@@ -628,14 +627,12 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
}
argOutput = "\"" + argOutput + "\"";
} else if (metadata.type == "object" || metadata.type == "behavior") {
} else if (metadata.type == "behavior") {
argOutput = "\"" + ConvertToString(parameter) + "\"";
} else if (metadata.type == "key") {
argOutput = "\"" + ConvertToString(parameter) + "\"";
} else if (metadata.type == "objectvar" || metadata.type == "scenevar" ||
metadata.type == "globalvar" || metadata.type == "password" ||
metadata.type == "musicfile" || metadata.type == "soundfile" ||
metadata.type == "police") {
} else if (metadata.type == "password" || metadata.type == "musicfile" ||
metadata.type == "soundfile" || metadata.type == "police") {
argOutput = "\"" + ConvertToString(parameter) + "\"";
} else if (metadata.type == "mouse") {
argOutput = "\"" + ConvertToString(parameter) + "\"";
@@ -799,23 +796,10 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
}
gd::String EventsCodeGenerator::ConvertToString(gd::String plainString) {
for (size_t i = 0; i < plainString.length(); ++i) {
if (plainString[i] == '\\') {
if (i + 1 >= plainString.length() || plainString[i + 1] != '\"') {
if (i + 1 < plainString.length())
plainString.insert(i + 1, "\\");
else
plainString += ("\\");
++i;
}
} else if (plainString[i] == '"') {
plainString.insert(i, "\\");
++i;
}
}
plainString = plainString.FindAndReplace("\n", "\\n");
plainString = plainString.FindAndReplace("\\", "\\\\")
.FindAndReplace("\r", "\\r")
.FindAndReplace("\n", "\\n")
.FindAndReplace("\"", "\\\"");
return plainString;
}
@@ -831,10 +815,12 @@ std::vector<gd::String> EventsCodeGenerator::ExpandObjectsName(
// Note: this logic is duplicated in EventsContextAnalyzer::ExpandObjectsName
std::vector<gd::String> realObjects;
if (globalObjectsAndGroups.GetObjectGroups().Has(objectName))
realObjects =
globalObjectsAndGroups.GetObjectGroups().Get(objectName).GetAllObjectsNames();
realObjects = globalObjectsAndGroups.GetObjectGroups()
.Get(objectName)
.GetAllObjectsNames();
else if (objectsAndGroups.GetObjectGroups().Has(objectName))
realObjects = objectsAndGroups.GetObjectGroups().Get(objectName).GetAllObjectsNames();
realObjects =
objectsAndGroups.GetObjectGroups().Get(objectName).GetAllObjectsNames();
else
realObjects.push_back(objectName);
@@ -893,7 +879,9 @@ gd::String EventsCodeGenerator::GenerateObjectFunctionCall(
gd::String parametersStr,
gd::String defaultOutput,
gd::EventsCodeGenerationContext& context) {
return "TODO (GenerateObjectFunctionCall)";
// To be used for testing only.
return objectListName + "." + codeInfo.functionCallName + "(" +
parametersStr + ") ?? " + defaultOutput;
}
gd::String EventsCodeGenerator::GenerateObjectBehaviorFunctionCall(
@@ -904,7 +892,10 @@ gd::String EventsCodeGenerator::GenerateObjectBehaviorFunctionCall(
gd::String parametersStr,
gd::String defaultOutput,
gd::EventsCodeGenerationContext& context) {
return "TODO (GenerateObjectBehaviorFunctionCall)";
// To be used for testing only.
return objectListName + "::" + behaviorName + "." +
codeInfo.functionCallName + "(" + parametersStr + ") ?? " +
defaultOutput;
}
gd::String EventsCodeGenerator::GenerateFreeCondition(
@@ -1135,9 +1126,10 @@ EventsCodeGenerator::EventsCodeGenerator(gd::Project& project_,
maxCustomConditionsDepth(0),
maxConditionsListsSize(0){};
EventsCodeGenerator::EventsCodeGenerator(const gd::Platform& platform_,
gd::ObjectsContainer & globalObjectsAndGroups_,
const gd::ObjectsContainer & objectsAndGroups_)
EventsCodeGenerator::EventsCodeGenerator(
const gd::Platform& platform_,
gd::ObjectsContainer& globalObjectsAndGroups_,
const gd::ObjectsContainer& objectsAndGroups_)
: platform(platform_),
globalObjectsAndGroups(globalObjectsAndGroups_),
objectsAndGroups(objectsAndGroups_),

View File

@@ -1,3 +1,8 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EVENTSCODEGENERATOR_H
#define GDCORE_EVENTSCODEGENERATOR_H
@@ -22,18 +27,19 @@ class EventsCodeGenerationContext;
class ExpressionCodeGenerationInformation;
class InstructionMetadata;
class Platform;
}
} // namespace gd
namespace gd {
/**
* \brief Internal class used to generate code from events
* \todo For now, this class generates only C++ code for GD C++ Platform.
*
* \see CallbacksForGeneratingExpressionCode
*/
class GD_CORE_API EventsCodeGenerator {
// Compatiblity with old ExpressionParser
friend class CallbacksForGeneratingExpressionCode;
friend class VariableCodeGenerationCallbacks;
// end of compatibility code
friend class ExpressionCodeGenerator;
public:
/**
@@ -53,9 +59,9 @@ class GD_CORE_API EventsCodeGenerator {
* \brief Construct a code generator for the specified
* objects/groups and platform
*/
EventsCodeGenerator(const gd::Platform& platform,
gd::ObjectsContainer & globalObjectsAndGroups_,
const gd::ObjectsContainer & objectsAndGroups_);
EventsCodeGenerator(const gd::Platform& platform,
gd::ObjectsContainer& globalObjectsAndGroups_,
const gd::ObjectsContainer& objectsAndGroups_);
virtual ~EventsCodeGenerator(){};
/**
@@ -182,9 +188,9 @@ class GD_CORE_API EventsCodeGenerator {
virtual gd::String ConvertToString(gd::String plainString);
/**
* \brief Convert a plain string ( with line feed, quotes ) to a string that
* \brief Convert a plain string (with line feed, quotes) to a string that
can be inserted into code.
* The string construction must be explicit : for example, quotes must be
* The string construction must be explicit: for example, quotes must be
added if the target language need quotes.
*
* Usage example :
@@ -278,23 +284,31 @@ class GD_CORE_API EventsCodeGenerator {
void ReportError();
/**
* \brief Return true if an error has occurred during code generation ( in
* this case, generated code is not usable )
* \brief Return true if an error has occurred during code generation (in
* this case, generated code is not usable).
*
* \todo TODO: This is actually not used and should be moved to a more
* complete error reporting.
*/
bool ErrorOccurred() const { return errorOccurred; };
/**
* \brief Get the global objects/groups used for code generation.
*/
gd::ObjectsContainer& GetGlobalObjectsAndGroups() const { return globalObjectsAndGroups; }
gd::ObjectsContainer& GetGlobalObjectsAndGroups() const {
return globalObjectsAndGroups;
}
/**
* \brief Get the objects/groups used for code generation.
*/
const gd::ObjectsContainer& GetObjectsAndGroups() const { return objectsAndGroups; }
const gd::ObjectsContainer& GetObjectsAndGroups() const {
return objectsAndGroups;
}
/**
* \brief Return true if the code generation is done for a given project and layout.
* \brief Return true if the code generation is done for a given project and
* layout.
*/
bool HasProjectAndLayout() const { return hasProjectAndLayout; }
@@ -380,27 +394,36 @@ class GD_CORE_API EventsCodeGenerator {
* \brief Generate the code to notify the profiler of the beginning of a
* section.
*/
virtual gd::String GenerateProfilerSectionBegin(const gd::String& section) { return ""; };
virtual gd::String GenerateProfilerSectionBegin(const gd::String& section) {
return "";
};
/**
* \brief Generate the code to notify the profiler of the end of a section.
*/
virtual gd::String GenerateProfilerSectionEnd(const gd::String& section) { return ""; };
virtual gd::String GenerateProfilerSectionEnd(const gd::String& section) {
return "";
};
/**
* \brief Get the namespace to be used to store code generated objects/values/functions,
* with the extra "dot" at the end to be used to access to a property/member.
* \brief Get the namespace to be used to store code generated
* objects/values/functions, with the extra "dot" at the end to be used to
* access to a property/member.
*
* Example: "gdjs.something."
*/
virtual gd::String GetCodeNamespaceAccessor() { return ""; };
/**
* \brief Get the namespace to be used to store code generated objects/values/functions.
* \brief Get the namespace to be used to store code generated
* objects/values/functions.
*
* Example: "gdjs.something"
*/
virtual gd::String GetCodeNamespace() { return ""; };
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE };
protected:
/**
* \brief Generate the code for a single parameter.
@@ -456,6 +479,65 @@ class GD_CORE_API EventsCodeGenerator {
std::vector<std::pair<gd::String, gd::String> >*
supplementaryParametersTypes);
/**
* \brief Generate the code to get a variable.
*/
virtual gd::String GenerateGetVariable(
const gd::String& variableName,
const VariableScope& scope,
gd::EventsCodeGenerationContext& context,
const gd::String& objectName) {
if (scope == LAYOUT_VARIABLE) {
return "getLayoutVariable(" + variableName + ")";
} else if (scope == PROJECT_VARIABLE) {
return "getProjectVariable(" + variableName + ")";
}
return "getVariableForObject(" + objectName + ", " + variableName + ")";
}
/**
* \brief Generate the code to get the child of a variable.
*/
virtual gd::String GenerateVariableAccessor(gd::String childName) {
return ".getChild(" + ConvertToStringExplicit(childName) + ")";
};
/**
* \brief Generate the code to get the child of a variable,
* using generated the expression.
*/
virtual gd::String GenerateVariableBracketAccessor(
gd::String expressionCode) {
return ".getChild(" + expressionCode + ")";
};
/**
* \brief Generate the code to reference a variable which is
* in an empty/null state.
*/
virtual gd::String GenerateBadVariable() { return "fakeBadVariable"; }
/**
* \brief Generate the code to reference an object.
* \param objectName the name of the object.
* \param type what is the expected type (object, objectPtr...) in which the
* object must be generated.
* \param context The context for code generation
*/
virtual gd::String GenerateObject(const gd::String& objectName,
const gd::String& type,
gd::EventsCodeGenerationContext& context) {
return "fakeObjectListOf_" + objectName;
}
/**
* \brief Generate the code to reference an object which is
* in an empty/null state.
*/
virtual gd::String GenerateBadObject() { return "fakeNullObject"; }
/**
* \brief Call a function of the current object.
* \note The current object is the object being manipulated by a condition or
@@ -613,31 +695,34 @@ class GD_CORE_API EventsCodeGenerator {
std::size_t startFromArgument = 0);
/**
* \brief Must return an expression whose value is true.
* \brief Return the "true" keyword in the target language.
*/
gd::String GenerateTrue() const { return "true"; };
/**
* \brief Must return an expression whose value is false.
* \brief Return the "false" keyword in the target language.
*/
gd::String GenerateFalse() const { return "false"; };
/**
* \brief Generate the list of comma-separated arguments to be used to call a
* function. \param arguments The code already generated for the arguments
* function.
*
* \param arguments The code already generated for the arguments
* \param startFrom Index of the first argument, the previous will be ignored.
*/
virtual gd::String GenerateArgumentsList(
const std::vector<gd::String>& arguments, size_t startFrom = 0);
const gd::Platform& platform; ///< The platform being used.
gd::ObjectsContainer & globalObjectsAndGroups;
const gd::ObjectsContainer & objectsAndGroups;
bool hasProjectAndLayout; ///< true only if project and layout are valid references. If false, they should not be used.
gd::Project* project; ///< The project being used.
const gd::Layout* scene; ///< The scene being generated.
gd::ObjectsContainer& globalObjectsAndGroups;
const gd::ObjectsContainer& objectsAndGroups;
bool hasProjectAndLayout; ///< true only if project and layout are valid
///< references. If false, they should not be used.
gd::Project* project; ///< The project being used.
const gd::Layout* scene; ///< The scene being generated.
bool errorOccurred; ///< Must be set to true if an error occured.
bool compilationForRuntime; ///< Is set to true if the code generation is
@@ -652,7 +737,7 @@ class GD_CORE_API EventsCodeGenerator {
gd::String customCodeInMain; ///< Custom code inserted before events ( in
///< main function )
std::set<gd::String>
customGlobalDeclarations; ///< Custom global C++ declarations inserted
customGlobalDeclarations; ///< Custom global C++ declarations inserted
///< after includes
size_t maxCustomConditionsDepth; ///< The maximum depth value for all the
///< custom conditions created.

View File

@@ -0,0 +1,465 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ExpressionCodeGenerator.h"
#include <memory>
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.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/IDE/Events/ExpressionValidator.h"
#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());
auto node = parser.ParseExpression(type, expression, objectName);
gd::ExpressionValidator validator;
node->Visit(validator);
ExpressionCodeGenerator generator(codeGenerator, context);
if (!validator.GetErrors().empty()) {
std::cout << "Error: \"" << validator.GetErrors()[0]->GetMessage()
<< "\" in: \"" << expression << "\" (" << type << ")"
<< std::endl;
return generator.GenerateDefaultValue(type);
}
node->Visit(generator);
return generator.GetOutput();
}
void ExpressionCodeGenerator::OnVisitOperatorNode(OperatorNode& node) {
node.leftHandSide->Visit(*this);
output += " ";
output.push_back(node.op);
output += " ";
node.rightHandSide->Visit(*this);
}
void ExpressionCodeGenerator::OnVisitUnaryOperatorNode(
UnaryOperatorNode& node) {
output.push_back(node.op);
output += "("; // Add extra parenthesis to ensure that things like --2 are
// properly outputted as -(-2) (GDevelop don't have -- or ++
// operators, but JavaScript and C++ have).
node.factor->Visit(*this);
output += ")";
}
void ExpressionCodeGenerator::OnVisitSubExpressionNode(
SubExpressionNode& node) {
output += "(";
node.expression->Visit(*this);
output += ")";
}
void ExpressionCodeGenerator::OnVisitNumberNode(NumberNode& node) {
output += node.number;
}
void ExpressionCodeGenerator::OnVisitTextNode(TextNode& node) {
output += codeGenerator.ConvertToStringExplicit(node.text);
}
void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
// This "translation" from the type to an enum could be avoided
// if all types were moved to an enum.
EventsCodeGenerator::VariableScope scope =
node.type == "globalvar"
? gd::EventsCodeGenerator::PROJECT_VARIABLE
: ((node.type == "scenevar")
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
output += codeGenerator.GenerateGetVariable(
node.name, scope, context, node.objectName);
if (node.child) node.child->Visit(*this);
}
void ExpressionCodeGenerator::OnVisitVariableAccessorNode(
VariableAccessorNode& node) {
output += codeGenerator.GenerateVariableAccessor(node.name);
if (node.child) node.child->Visit(*this);
}
void ExpressionCodeGenerator::OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) {
ExpressionCodeGenerator generator(codeGenerator, context);
node.expression->Visit(generator);
output +=
codeGenerator.GenerateVariableBracketAccessor(generator.GetOutput());
if (node.child) node.child->Visit(*this);
}
void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
if (gd::ParameterMetadata::IsObject(node.type)) {
output +=
codeGenerator.GenerateObject(node.identifierName, node.type, context);
} else {
output += "/* Error during generation, unrecognized identifier type: " +
codeGenerator.ConvertToString(node.type) + " with value " +
codeGenerator.ConvertToString(node.identifierName) + " */ " +
codeGenerator.ConvertToStringExplicit(node.identifierName);
}
}
void ExpressionCodeGenerator::OnVisitFunctionNode(FunctionNode& node) {
if (gd::MetadataProvider::IsBadExpressionMetadata(node.expressionMetadata)) {
output += "/* Error during generation, function not found: " +
codeGenerator.ConvertToString(node.functionName) + " for type " +
node.type + " */ " + GenerateDefaultValue(node.type);
return;
}
if (!node.objectName.empty()) {
if (!node.behaviorName.empty()) {
output += GenerateBehaviorFunctionCode(node.type,
node.objectName,
node.behaviorName,
node.parameters,
node.expressionMetadata);
} else {
output += GenerateObjectFunctionCode(
node.type, node.objectName, node.parameters, node.expressionMetadata);
}
} else {
output +=
GenerateFreeFunctionCode(node.parameters, node.expressionMetadata);
}
}
gd::String ExpressionCodeGenerator::GenerateFreeFunctionCode(
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata) {
codeGenerator.AddIncludeFiles(
expressionMetadata.codeExtraInformation.GetIncludeFiles());
// Launch custom code generator if needed
if (expressionMetadata.codeExtraInformation.HasCustomCodeGenerator()) {
return expressionMetadata.codeExtraInformation.customCodeGenerator(
PrintParameters(parameters), codeGenerator, context);
}
gd::String parametersCode =
GenerateParametersCodes(parameters, expressionMetadata, 0);
return expressionMetadata.codeExtraInformation.functionCallName + "(" +
parametersCode + ")";
}
gd::String ExpressionCodeGenerator::GenerateObjectFunctionCode(
const gd::String& type,
const gd::String& objectName,
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata) {
const gd::ObjectsContainer& globalObjectsAndGroups =
codeGenerator.GetGlobalObjectsAndGroups();
const gd::ObjectsContainer& objectsAndGroups =
codeGenerator.GetObjectsAndGroups();
codeGenerator.AddIncludeFiles(
expressionMetadata.codeExtraInformation.GetIncludeFiles());
// Launch custom code generator if needed
if (expressionMetadata.codeExtraInformation.HasCustomCodeGenerator()) {
return expressionMetadata.codeExtraInformation.customCodeGenerator(
PrintParameters(parameters), codeGenerator, context);
}
// Prepare parameters
gd::String parametersCode = GenerateParametersCodes(
parameters,
expressionMetadata,
// By convention, the first parameter is the object
1);
gd::String functionOutput = GenerateDefaultValue(type);
// Get object(s) concerned by function call
std::vector<gd::String> realObjects =
codeGenerator.ExpandObjectsName(objectName, 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);
codeGenerator.AddIncludeFiles(objInfo.includeFiles);
functionOutput = codeGenerator.GenerateObjectFunctionCall(
realObjects[i],
objInfo,
expressionMetadata.codeExtraInformation,
parametersCode,
functionOutput,
context);
}
return functionOutput;
}
gd::String ExpressionCodeGenerator::GenerateBehaviorFunctionCode(
const gd::String& type,
const gd::String& objectName,
const gd::String& behaviorName,
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata) {
const gd::ObjectsContainer& globalObjectsAndGroups =
codeGenerator.GetGlobalObjectsAndGroups();
const gd::ObjectsContainer& objectsAndGroups =
codeGenerator.GetObjectsAndGroups();
codeGenerator.AddIncludeFiles(
expressionMetadata.codeExtraInformation.GetIncludeFiles());
// Launch custom code generator if needed
if (expressionMetadata.codeExtraInformation.HasCustomCodeGenerator()) {
return expressionMetadata.codeExtraInformation.customCodeGenerator(
PrintParameters(parameters), codeGenerator, context);
}
// Prepare parameters
gd::String parametersCode = GenerateParametersCodes(
parameters,
expressionMetadata,
// By convention, the first parameters are the object and behavior
2);
// Get object(s) concerned by function call
std::vector<gd::String> realObjects =
codeGenerator.ExpandObjectsName(objectName, context);
gd::String functionOutput = GenerateDefaultValue(type);
gd::String behaviorType = gd::GetTypeOfBehavior(
globalObjectsAndGroups, objectsAndGroups, behaviorName);
const BehaviorMetadata& autoInfo = MetadataProvider::GetBehaviorMetadata(
codeGenerator.GetPlatform(), behaviorType);
for (std::size_t i = 0; i < realObjects.size(); ++i) {
context.ObjectsListNeeded(realObjects[i]);
codeGenerator.AddIncludeFiles(autoInfo.includeFiles);
functionOutput = codeGenerator.GenerateObjectBehaviorFunctionCall(
realObjects[i],
behaviorName,
autoInfo,
expressionMetadata.codeExtraInformation,
parametersCode,
functionOutput,
context);
}
return functionOutput;
}
gd::String ExpressionCodeGenerator::GenerateParametersCodes(
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata,
size_t initialParameterIndex) {
size_t nonCodeOnlyParameterIndex = 0;
gd::String parametersCode;
for (std::size_t i = initialParameterIndex;
i < expressionMetadata.parameters.size();
++i) {
if (i != initialParameterIndex) parametersCode += ", ";
auto& parameterMetadata = expressionMetadata.parameters[i];
if (!parameterMetadata.IsCodeOnly()) {
ExpressionCodeGenerator generator(codeGenerator, context);
if (nonCodeOnlyParameterIndex < parameters.size()) {
parameters[nonCodeOnlyParameterIndex]->Visit(generator);
parametersCode += generator.GetOutput();
} else if (parameterMetadata.IsOptional()) {
// Optional parameters default value were not parsed at the time of the
// expression parsing. Parse them now.
ExpressionParser2 parser(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups());
auto node = parser.ParseExpression(parameterMetadata.GetType(),
parameterMetadata.GetDefaultValue());
node->Visit(generator);
parametersCode += generator.GetOutput();
} else {
parametersCode +=
"/* Error during generation, parameter not existing in the nodes "
"*/ " +
GenerateDefaultValue(parameterMetadata.GetType());
}
nonCodeOnlyParameterIndex++;
} else {
parametersCode +=
codeGenerator.GenerateParameterCodes(parameterMetadata.GetExtraInfo(),
parameterMetadata,
context,
"",
nullptr);
}
}
return parametersCode;
}
std::vector<gd::Expression> ExpressionCodeGenerator::PrintParameters(
const std::vector<std::unique_ptr<ExpressionNode>>& parameters) {
// Printing parameters is only useful because custom code generator of
// expression require to get the parameters of the expression as strings
// (gd::Expression). Once the old ExpressionParser is removed, custom
// code generator can be reworked to directly take the parsed nodes,
// avoiding an extra and useless printing/parsing of their parameters.
std::vector<gd::Expression> printedParameters;
for (auto& parameter : parameters) {
printedParameters.push_back(
gd::ExpressionParser2NodePrinter::PrintNode(*parameter));
}
return printedParameters;
}
gd::String ExpressionCodeGenerator::GenerateDefaultValue(
const gd::String& type) {
if (gd::ParameterMetadata::IsExpression("variable", type)) {
return codeGenerator.GenerateBadVariable();
}
if (gd::ParameterMetadata::IsObject(type)) {
return codeGenerator.GenerateBadObject();
}
return (type == "string") ? "\"\"" : "0";
}
void ExpressionCodeGenerator::OnVisitEmptyNode(EmptyNode& node) {
output += GenerateDefaultValue(node.type);
}
} // namespace gd

View File

@@ -0,0 +1,117 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef GDCORE_ExpressionCodeGenerator_H
#define GDCORE_ExpressionCodeGenerator_H
#include <memory>
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/String.h"
namespace gd {
class Expression;
class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
class EventsCodeGenerationContext;
class EventsCodeGenerator;
} // namespace gd
namespace gd {
/**
* \brief Generate code for a parsed expression.
*
* Almost all code generation is dedicated to the gd::EventsCodeGenerator,
* so that it can be adapted to the target.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
public:
ExpressionCodeGenerator(EventsCodeGenerator& codeGenerator_,
EventsCodeGenerationContext& context_)
: codeGenerator(codeGenerator_), context(context_){};
virtual ~ExpressionCodeGenerator(){};
/**
* Helper to generate the code for an expression.
* If expression is invalid, a default generated value is returned (0 for
* number expression, empty string for strings).
*
* \param codeGenerator The code generator to use to output code.
* \param context The context of the code generation.
* \param type The type of the expression (see gd::ExpressionParser2).
* \param expression The expression to parse and generate code for.
* \param object The object the expression refers too (only for "objectvar"
* type).
*
* \see see gd::ExpressionParser2
*/
static gd::String GenerateExpressionCode(EventsCodeGenerator& codeGenerator,
EventsCodeGenerationContext& context,
const gd::String& type,
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:
void OnVisitSubExpressionNode(SubExpressionNode& node) override;
void OnVisitOperatorNode(OperatorNode& node) override;
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override;
void OnVisitNumberNode(NumberNode& node) override;
void OnVisitTextNode(TextNode& node) override;
void OnVisitVariableNode(VariableNode& node) override;
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override;
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override;
void OnVisitIdentifierNode(IdentifierNode& node) override;
void OnVisitFunctionNode(FunctionNode& node) override;
void OnVisitEmptyNode(EmptyNode& node) override;
private:
gd::String GenerateFreeFunctionCode(
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata);
gd::String GenerateObjectFunctionCode(
const gd::String& type,
const gd::String& objectName,
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata);
gd::String GenerateBehaviorFunctionCode(
const gd::String& type,
const gd::String& objectName,
const gd::String& behaviorName,
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata);
gd::String GenerateParametersCodes(
const std::vector<std::unique_ptr<ExpressionNode>>& parameters,
const ExpressionMetadata& expressionMetadata,
size_t initialParameterIndex);
gd::String GenerateDefaultValue(const gd::String& type);
static std::vector<gd::Expression> PrintParameters(
const std::vector<std::unique_ptr<ExpressionNode>>& parameters);
gd::String output;
EventsCodeGenerator& codeGenerator;
EventsCodeGenerationContext& context;
static bool useOldExpressionParser;
};
} // namespace gd
#endif // GDCORE_ExpressionCodeGenerator_H
#endif

View File

@@ -11,28 +11,18 @@
#include "GDCore/String.h"
namespace gd {
class ExpressionMetadata;
}
namespace gd {
class Expression;
}
namespace gd {
class Project;
}
namespace gd {
class Layout;
}
namespace gd {
class Layout;
}
namespace gd {
class EventsCodeGenerationContext;
}
namespace gd {
class EventsCodeGenerator;
}
namespace gd {
// TODO: Replace and remove (ExpressionCodeGenerator)
/**
* \brief Used to generate code from expressions.
*

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

@@ -10,12 +10,15 @@
#include <string>
#include <vector>
#include "GDCore/Events/Parsers/VariableParser.h"
#include "GDCpp/Runtime/String.h"
#include "GDCore/String.h"
#include "EventsCodeGenerator.h"
namespace gd {
class EventsCodeGenerator;
class EventsCodeGenerationContext;
} // namespace gd
// TODO: Replace and remove (ExpressionCodeGenerator)
namespace gd {
/**
* \brief Callbacks called to generate the code for getting a variable.
*
@@ -36,8 +39,6 @@ class EventsCodeGenerationContext;
*/
class VariableCodeGenerationCallbacks : public gd::VariableParserCallbacks {
public:
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE };
/**
* \brief Default constructor for generating code for a layout/global
* variable. \param output The string in which the code will be generated.
@@ -49,7 +50,7 @@ class VariableCodeGenerationCallbacks : public gd::VariableParserCallbacks {
VariableCodeGenerationCallbacks(gd::String& output,
gd::EventsCodeGenerator& codeGenerator_,
gd::EventsCodeGenerationContext& context_,
const VariableScope& scope_);
const gd::EventsCodeGenerator::VariableScope& scope_);
/**
* \brief Default constructor for generating code for an object variable.
@@ -86,9 +87,11 @@ class VariableCodeGenerationCallbacks : public gd::VariableParserCallbacks {
gd::String& output;
gd::EventsCodeGenerator& codeGenerator;
gd::EventsCodeGenerationContext& context;
VariableScope scope;
gd::EventsCodeGenerator::VariableScope scope;
const gd::String object; ///< The object name, when scope == OBJECT_VARIABLE.
};
}
#endif // VARIABLEPARSERCALLBACKS_H
#endif

View File

@@ -717,9 +717,6 @@ bool ExpressionParser::ParseStringExpression(const gd::Platform& platform,
firstErrorPos = functionNameEnd;
firstErrorStr = _("Incorrect number of parameters");
for (std::size_t i = 0; i < parameters.size(); ++i)
cout << "Param:" << parameters[i].GetPlainString() << endl;
return false;
}

View File

@@ -0,0 +1,220 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include <algorithm>
#include <memory>
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Expression.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
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(
const gd::Platform& platform_,
const gd::ObjectsContainer& globalObjectsContainer_,
const gd::ObjectsContainer& objectsContainer_)
: expression(""),
currentPosition(0),
platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_) {}
namespace {
/**
* Return the minimum number of parameters, starting from a given parameter
* (by convention, 1 for object functions and 2 for behavior functions).
*/
size_t GetMinimumParametersNumber(
const std::vector<gd::ParameterMetadata>& parameters,
size_t initialParameterIndex) {
size_t nb = 0;
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
if (!parameters[i].optional && !parameters[i].codeOnly) nb++;
}
return nb;
}
/**
* Return the maximum number of parameters, starting from a given parameter
* (by convention, 1 for object functions and 2 for behavior functions).
*/
size_t GetMaximumParametersNumber(
const std::vector<gd::ParameterMetadata>& parameters,
size_t initialParameterIndex) {
size_t nb = 0;
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
if (!parameters[i].codeOnly) nb++;
}
return nb;
}
} // namespace
std::unique_ptr<ExpressionParserDiagnostic> ExpressionParser2::ValidateFunction(
const gd::FunctionNode& function, size_t functionStartPosition) {
if (gd::MetadataProvider::IsBadExpressionMetadata(
function.expressionMetadata)) {
return gd::make_unique<ExpressionParserError>(
"invalid_function_name",
_("Cannot find an expression with this name: ") +
function.functionName + "\n" +
_("Double check that you've not made any typo in the name."),
functionStartPosition,
GetCurrentPosition());
}
size_t minParametersCount = GetMinimumParametersNumber(
function.expressionMetadata.parameters,
WrittenParametersFirstIndex(function.objectName, function.behaviorName));
size_t maxParametersCount = GetMaximumParametersNumber(
function.expressionMetadata.parameters,
WrittenParametersFirstIndex(function.objectName, function.behaviorName));
if (function.parameters.size() < minParametersCount ||
function.parameters.size() > maxParametersCount) {
gd::String expectedCountMessage =
minParametersCount == maxParametersCount
? _("The number of parameters must be exactly ") +
gd::String::From(minParametersCount)
: _("The number of parameters must be: ") +
gd::String::From(minParametersCount) + "-" +
gd::String::From(maxParametersCount);
if (function.parameters.size() < minParametersCount) {
return gd::make_unique<ExpressionParserError>(
"too_few_parameters",
"You have not entered enough parameters for the expression. " +
expectedCountMessage,
functionStartPosition,
GetCurrentPosition());
}
}
return gd::make_unique<ExpressionParserDiagnostic>();
}
std::unique_ptr<TextNode> ExpressionParser2::ReadText() {
SkipWhitespace();
if (!IsAnyChar("\"")) {
auto text = gd::make_unique<TextNode>("");
text->diagnostic =
RaiseSyntaxError(_("A text must start with a double quote (\")."));
return text;
}
SkipChar();
gd::String parsedText = "";
bool textParsingHasEnded = false;
bool expectEscapedCharacter = false;
while (!IsEndReached() && !textParsingHasEnded) {
if (GetCurrentChar() == '"') {
if (expectEscapedCharacter) {
parsedText += '"';
expectEscapedCharacter = false;
} else {
textParsingHasEnded = true;
}
} else if (GetCurrentChar() == '\\') {
if (expectEscapedCharacter) {
parsedText += '\\';
expectEscapedCharacter = false;
} else {
expectEscapedCharacter = true;
}
} else {
if (expectEscapedCharacter) {
parsedText += '\\';
}
parsedText += GetCurrentChar();
}
currentPosition++;
}
auto text = gd::make_unique<TextNode>(parsedText);
if (!textParsingHasEnded) {
text->diagnostic =
RaiseSyntaxError(_("A text must end with a double quote (\"). Add a "
"double quote to terminate the text."));
}
return text;
}
std::unique_ptr<NumberNode> ExpressionParser2::ReadNumber() {
SkipWhitespace();
gd::String parsedNumber;
bool numberHasStarted = false;
bool digitFound = false;
bool dotFound = false;
while (!IsEndReached()) {
if (IsAnyChar("0")) {
numberHasStarted = true;
digitFound = true;
if (!parsedNumber.empty()) { // Ignore leading 0s.
parsedNumber += GetCurrentChar();
}
} else if (IsAnyChar("123456789")) {
numberHasStarted = true;
digitFound = true;
parsedNumber += GetCurrentChar();
} else if (IsAnyChar(".") && !dotFound) {
numberHasStarted = true;
dotFound = true;
if (parsedNumber == "") {
parsedNumber += "0."; //Normalize by adding a leading 0, only in this case.
} else {
parsedNumber += ".";
}
} else {
break;
}
currentPosition++;
}
// parsedNumber can be empty in the only case where we have only seen
// 0s (one or more), so normalize it to a single 0.
if (parsedNumber.empty()) {
parsedNumber = "0";
}
// Note that parsedNumber can finish by a dot (1., 2., 0.). This is
// valid in most languages so we allow this.
auto number = gd::make_unique<NumberNode>(parsedNumber);
if (!numberHasStarted || !digitFound) {
number->diagnostic = RaiseSyntaxError(
_("A number was expected. You must enter a number here."));
}
return number;
}
} // namespace gd

View File

@@ -0,0 +1,763 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONPARSER2_H
#define GDCORE_EXPRESSIONPARSER2_H
#include <memory>
#include <utility>
#include <vector>
#include "ExpressionParser2Node.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
#include "GDCore/String.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
namespace gd {
class Expression;
class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
} // namespace gd
namespace gd {
/** \brief Parse an expression, returning a tree of node corresponding
* to the parsed expression.
*
* This is a LL(1) parser. This could be extracted to a generic/reusable
* parser by refactoring out the dependency on gd::MetadataProvider (injecting
* instead functions to be called to query supported functions).
*
* \see gd::ExpressionParserDiagnostic
* \see gd::ExpressionNode
*/
class GD_CORE_API ExpressionParser2 {
public:
ExpressionParser2(const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_);
virtual ~ExpressionParser2(){};
/**
* Parse the given expression with the specified type.
*
* \param type Type of the expression: "string", "number",
* type supported by gd::ParameterMetadata::IsObject, types supported by
* gd::ParameterMetadata::IsExpression or "unknown". \param expression The
* expression to parse \param objectName Specify the object name, only for the
* case of "objectvar" type.
*
* \return The node representing the expression as a parsed tree.
*/
std::unique_ptr<ExpressionNode> ParseExpression(
const gd::String &type,
const gd::String &expression_,
const gd::String &objectName = "") {
expression = expression_;
currentPosition = 0;
return Start(type, objectName);
}
private:
/** \name Grammar
* Each method is a part of the grammar.
*/
///@{
std::unique_ptr<ExpressionNode> Start(const gd::String &type,
const gd::String &objectName = "") {
auto expression = Expression(type, objectName);
// Check for extra characters at the end of the expression
if (!IsEndReached()) {
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)."));
return std::move(op);
}
return expression;
}
std::unique_ptr<ExpressionNode> Expression(
const gd::String &type, const gd::String &objectName = "") {
SkipWhitespace();
size_t expressionStartPosition = GetCurrentPosition();
std::unique_ptr<ExpressionNode> leftHandSide = Term(type, objectName);
SkipWhitespace();
if (IsEndReached()) return leftHandSide;
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);
return std::move(op);
}
if (type == "string") {
leftHandSide->diagnostic = RaiseSyntaxError(
"You must add the operator + between texts or expressions. For "
"example: \"Your name: \" + VariableString(PlayerName).");
} else if (type == "number") {
leftHandSide->diagnostic = RaiseSyntaxError(
"No operator found. Did you forget to enter an operator (like +, -, "
"* or /) between numbers or expressions?");
} else {
leftHandSide->diagnostic = RaiseSyntaxError(
"More than one term was found. Verify that your expression is "
"properly written.");
}
auto op = gd::make_unique<OperatorNode>();
op->op = ' ';
op->leftHandSide = std::move(leftHandSide);
op->rightHandSide = Expression(type, objectName);
return std::move(op);
}
std::unique_ptr<ExpressionNode> Term(const gd::String &type,
const gd::String &objectName) {
SkipWhitespace();
std::unique_ptr<ExpressionNode> factor = Factor(type, objectName);
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 (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);
SkipWhitespace();
factor = std::move(op);
}
return factor;
};
std::unique_ptr<ExpressionNode> Factor(const gd::String &type,
const gd::String &objectName) {
SkipWhitespace();
size_t expressionStartPosition = GetCurrentPosition();
std::unique_ptr<ExpressionNode> factor;
if (IsAnyChar(QUOTE)) {
factor = ReadText();
if (type == "number")
factor->diagnostic =
RaiseTypeError(_("You entered a text, but a number was expected."),
expressionStartPosition);
else if (type != "string")
factor->diagnostic = RaiseTypeError(
_("You entered a text, but this type was expected:") + type,
expressionStartPosition);
} else if (IsAnyChar(UNARY_OPERATORS)) {
auto unaryOperator = gd::make_unique<UnaryOperatorNode>(GetCurrentChar());
unaryOperator->diagnostic = ValidateUnaryOperator(type, GetCurrentChar());
SkipChar();
unaryOperator->factor = Factor(type, objectName);
factor = std::move(unaryOperator);
} else if (IsAnyChar(NUMBER_FIRST_CHAR)) {
factor = ReadNumber();
if (type == "string")
factor->diagnostic = RaiseTypeError(
_("You entered a number, but a text was expected (in quotes)."),
expressionStartPosition);
else if (type != "number")
factor->diagnostic = RaiseTypeError(
_("You entered a number, but this type was expected:") + type,
expressionStartPosition);
} else if (IsAnyChar("(")) {
SkipChar();
factor = SubExpression(type, objectName);
if (!IsAnyChar(")")) {
factor->diagnostic =
RaiseSyntaxError(_("Missing a closing parenthesis. Add a closing "
"parenthesis for each opening parenthesis."));
}
SkipIfIsAnyChar(")");
} else if (IsIdentifierAllowedChar()) {
// This is a place where the grammar differs according to the
// type being expected.
if (gd::ParameterMetadata::IsExpression("variable", type)) {
factor = Variable(type, objectName);
} else {
factor = Identifier(type);
}
} else {
factor = ReadUntilWhitespace(type);
factor->diagnostic = RaiseEmptyError(type, expressionStartPosition);
}
return factor;
}
std::unique_ptr<SubExpressionNode> SubExpression(
const gd::String &type, const gd::String &objectName) {
return std::move(
gd::make_unique<SubExpressionNode>(Expression(type, objectName)));
};
std::unique_ptr<IdentifierOrFunctionOrEmptyNode> Identifier(
const gd::String &type) {
size_t identifierStartPosition = GetCurrentPosition();
gd::String name = ReadIdentifierName();
SkipWhitespace();
if (IsNamespaceSeparator()) {
SkipNamespaceSeparator();
name += NAMESPACE_SEPARATOR;
name += ReadIdentifierName();
}
if (IsAnyChar("(")) {
SkipChar();
return FreeFunction(type, name, identifierStartPosition);
} else if (IsAnyChar(DOT)) {
SkipChar();
return ObjectFunctionOrBehaviorFunction(
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\")."),
identifierStartPosition);
} else if (type == "number") {
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,
identifierStartPosition);
}
return std::move(identifier);
}
}
std::unique_ptr<VariableNode> Variable(const gd::String &type,
const gd::String &objectName) {
size_t identifierStartPosition = GetCurrentPosition();
gd::String name = ReadIdentifierName();
auto variable = gd::make_unique<VariableNode>(type, name, objectName);
variable->child = VariableAccessorOrVariableBracketAccessor();
return std::move(variable);
}
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
VariableAccessorOrVariableBracketAccessor() {
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode> child;
SkipWhitespace();
if (IsAnyChar("[")) {
SkipChar();
child =
gd::make_unique<VariableBracketAccessorNode>(Expression("string"));
if (!IsAnyChar("]")) {
child->diagnostic =
RaiseSyntaxError(_("Missing a closing bracket. Add a closing "
"bracket for each opening bracket."));
}
SkipIfIsAnyChar("]");
child->child = VariableAccessorOrVariableBracketAccessor();
} else if (IsAnyChar(DOT)) {
SkipChar();
SkipWhitespace();
child = gd::make_unique<VariableAccessorNode>(ReadIdentifierName());
child->child = VariableAccessorOrVariableBracketAccessor();
}
return child;
}
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
// This could be improved to have the type passed to a single
// GetExpressionMetadata function.
const gd::ExpressionMetadata &metadata =
type == "number" ? MetadataProvider::GetExpressionMetadata(
platform, functionFullName)
: MetadataProvider::GetStrExpressionMetadata(
platform, functionFullName);
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, functionStartPosition);
return std::move(function);
}
std::unique_ptr<FunctionOrEmptyNode> ObjectFunctionOrBehaviorFunction(
const gd::String &type,
const gd::String &objectName,
size_t functionStartPosition) {
gd::String objectFunctionOrBehaviorName = ReadIdentifierName();
SkipWhitespace();
if (IsNamespaceSeparator()) {
SkipNamespaceSeparator();
return BehaviorFunction(type,
objectName,
objectFunctionOrBehaviorName,
functionStartPosition);
} else if (IsAnyChar("(")) {
SkipChar();
gd::String objectType =
GetTypeOfObject(globalObjectsContainer, objectsContainer, objectName);
// This could be improved to have the type passed to a single
// GetExpressionMetadata function.
const gd::ExpressionMetadata &metadata =
type == "number"
? MetadataProvider::GetObjectExpressionMetadata(
platform, objectType, objectFunctionOrBehaviorName)
: MetadataProvider::GetObjectStrExpressionMetadata(
platform, objectType, objectFunctionOrBehaviorName);
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, functionStartPosition);
return std::move(function);
}
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)."));
return std::move(node);
}
std::unique_ptr<FunctionOrEmptyNode> BehaviorFunction(
const gd::String &type,
const gd::String &objectName,
const gd::String &behaviorName,
size_t functionStartPosition) {
gd::String functionName = ReadIdentifierName();
SkipWhitespace();
if (IsAnyChar("(")) {
SkipChar();
gd::String behaviorType = GetTypeOfBehavior(
globalObjectsContainer, objectsContainer, behaviorName);
// This could be improved to have the type passed to a single
// GetExpressionMetadata function.
const gd::ExpressionMetadata &metadata =
type == "number" ? MetadataProvider::GetBehaviorExpressionMetadata(
platform, behaviorType, functionName)
: MetadataProvider::GetBehaviorStrExpressionMetadata(
platform, behaviorType, functionName);
auto parametersAndError =
Parameters(metadata.parameters, objectName, behaviorName);
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, functionStartPosition);
return std::move(function);
} else {
auto node = gd::make_unique<EmptyNode>(type);
node->diagnostic = RaiseSyntaxError(
_("An opening parenthesis was expected here to call a function."));
return std::move(node);
}
}
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
// second one.
size_t parameterIndex =
WrittenParametersFirstIndex(objectName, behaviorName);
while (!IsEndReached()) {
SkipWhitespace();
if (IsAnyChar(")")) {
SkipChar();
return std::make_pair(std::move(parameters), nullptr);
} else {
if (parameterIndex < parameterMetadata.size()) {
const gd::String &type = parameterMetadata[parameterIndex].GetType();
if (parameterMetadata[parameterIndex].IsCodeOnly()) {
// Do nothing, code only parameters are not written in expressions.
} else if (gd::ParameterMetadata::IsExpression("number", type)) {
parameters.push_back(Expression("number"));
} else if (gd::ParameterMetadata::IsExpression("string", type)) {
parameters.push_back(Expression("string"));
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
parameters.push_back(Expression(type, objectName));
} else if (gd::ParameterMetadata::IsObject(type)) {
parameters.push_back(Expression(type));
} else {
size_t parameterStartPosition = GetCurrentPosition();
parameters.push_back(Expression("unknown"));
parameters.back()->diagnostic =
gd::make_unique<ExpressionParserError>(
"unknown_parameter_type",
_("This function is improperly set up. Reach out to the "
"extension developer or a GDevelop maintainer to fix "
"this issue"),
parameterStartPosition,
GetCurrentPosition());
}
} else {
size_t parameterStartPosition = GetCurrentPosition();
parameters.push_back(Expression("unknown"));
parameters.back()
->diagnostic = gd::make_unique<ExpressionParserError>(
"extra_parameter",
_("This parameter was not expected by this expression. Remove it "
"or verify that you've entered the proper expression name."),
parameterStartPosition,
GetCurrentPosition());
}
SkipWhitespace();
SkipIfIsAnyChar(PARAMETERS_SEPARATOR);
parameterIndex++;
}
}
return std::make_pair(
std::move(parameters),
RaiseSyntaxError(_("The list of parameters is not terminated. Add a "
"closing parenthesis to end the parameters.")));
}
///@}
/** \name Validators
* Return a diagnostic if any error is found
*/
///@{
std::unique_ptr<ExpressionParserDiagnostic> ValidateFunction(
const gd::FunctionNode &function, size_t functionStartPosition);
std::unique_ptr<ExpressionParserDiagnostic> ValidateOperator(
const gd::String &type, gd::String::value_type operatorChar) {
if (type == "number") {
if (operatorChar == '+' || operatorChar == '-' || operatorChar == '/' ||
operatorChar == '*') {
return gd::make_unique<ExpressionParserDiagnostic>();
}
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("You've used an operator that is not supported. Operator should be "
"either +, -, / or *."),
GetCurrentPosition());
} else if (type == "string") {
if (operatorChar == '+') {
return gd::make_unique<ExpressionParserDiagnostic>();
}
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("You've used an operator that is not supported. Only + can be used "
"to concatenate texts."),
GetCurrentPosition());
} else if (gd::ParameterMetadata::IsObject(type)) {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("Operators (+, -, /, *) can't be used with an object name. Remove the operator."),
GetCurrentPosition());
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("Operators (+, -, /, *) can't be used in variable names. Remove "
"the operator from the variable name."),
GetCurrentPosition());
}
return gd::make_unique<ExpressionParserDiagnostic>();
}
std::unique_ptr<ExpressionParserDiagnostic> ValidateUnaryOperator(
const gd::String &type, gd::String::value_type operatorChar) {
if (type == "number") {
if (operatorChar == '+' || operatorChar == '-') {
return gd::make_unique<ExpressionParserDiagnostic>();
}
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("You've used an \"unary\" operator that is not supported. Operator "
"should be "
"either + or -."),
GetCurrentPosition());
} else if (type == "string") {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("You've used an operator that is not supported. Only + can be used "
"to concatenate texts, and must be placed between two texts (or "
"expressions)."),
GetCurrentPosition());
} else if (gd::ParameterMetadata::IsObject(type)) {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("Operators (+, -) can't be used with an object name. Remove the operator."),
GetCurrentPosition());
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("Operators (+, -) can't be used in variable names. Remove "
"the operator from the variable name."),
GetCurrentPosition());
}
return gd::make_unique<ExpressionParserDiagnostic>();
}
///@}
/** \name Parsing tokens
* Read tokens or characters
*/
///@{
void SkipChar() { currentPosition++; }
void SkipWhitespace() {
while (currentPosition < expression.size() &&
WHITESPACES.find(expression[currentPosition]) != gd::String::npos) {
currentPosition++;
}
}
void SkipIfIsAnyChar(const gd::String &allowedCharacters) {
if (IsAnyChar(allowedCharacters)) {
currentPosition++;
}
}
void SkipNamespaceSeparator() {
// Namespace separator is a special kind of delimiter as it is 2 characters
// long
if (IsNamespaceSeparator()) {
currentPosition += NAMESPACE_SEPARATOR.size();
}
}
bool IsAnyChar(const gd::String &allowedCharacters) {
if (currentPosition < expression.size() &&
allowedCharacters.find(expression[currentPosition]) !=
gd::String::npos) {
return true;
}
return false;
}
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;
}
return false;
}
bool IsNamespaceSeparator() {
// Namespace separator is a special kind of delimiter as it is 2 characters
// long
return (currentPosition + NAMESPACE_SEPARATOR.size() <= expression.size() &&
expression.substr(currentPosition, NAMESPACE_SEPARATOR.size()) ==
NAMESPACE_SEPARATOR);
}
bool IsEndReached() { return currentPosition >= expression.size(); }
gd::String ReadIdentifierName() {
gd::String name;
while (currentPosition < expression.size() &&
(IsIdentifierAllowedChar()
// Allow whitespace in identifier name for compatibility
|| expression[currentPosition] == ' ')) {
name += expression[currentPosition];
currentPosition++;
}
// 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).
size_t lastCharacterPos = name.find_last_not_of(WHITESPACES);
if (!name.empty() && (lastCharacterPos + 1) < name.size()) {
name.erase(lastCharacterPos + 1);
}
return name;
}
std::unique_ptr<TextNode> ReadText();
std::unique_ptr<NumberNode> ReadNumber();
std::unique_ptr<EmptyNode> ReadUntilWhitespace(gd::String type) {
gd::String text;
while (currentPosition < expression.size() &&
WHITESPACES.find(expression[currentPosition]) == gd::String::npos) {
text += expression[currentPosition];
currentPosition++;
}
return gd::make_unique<EmptyNode>(type, text);
}
std::unique_ptr<EmptyNode> ReadUntilEnd(gd::String type) {
gd::String text;
while (currentPosition < expression.size()) {
text += expression[currentPosition];
currentPosition++;
}
return gd::make_unique<EmptyNode>(type, text);
}
size_t GetCurrentPosition() { return currentPosition; }
gd::String::value_type GetCurrentChar() {
if (currentPosition < expression.size()) {
return expression[currentPosition];
}
return '\n'; // Should not arise, unless GetCurrentChar was called when
// IsEndReached() is true (which is a logical error).
}
///@}
/** \name Raising errors
* Helpers to attach errors to nodes
*/
///@{
std::unique_ptr<ExpressionParserError> RaiseSyntaxError(
const gd::String &message) {
return std::move(gd::make_unique<ExpressionParserError>(
"syntax_error", message, GetCurrentPosition()));
}
std::unique_ptr<ExpressionParserError> RaiseTypeError(
const gd::String &message, size_t beginningPosition) {
return std::move(gd::make_unique<ExpressionParserError>(
"type_error", message, beginningPosition, GetCurrentPosition()));
}
std::unique_ptr<ExpressionParserError> RaiseEmptyError(
const gd::String &type, size_t beginningPosition) {
gd::String message;
if (type == "number") {
message = _("You must enter a number or a valid expression call.");
} else if (type == "string") {
message = _(
"You must enter a text (between quotes) or a valid expression call.");
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
message = _("You must enter a variable name.");
} else if (gd::ParameterMetadata::IsObject(type)) {
message = _("You must enter a valid object name.");
} else {
message = _("You must enter a valid expression.");
}
return std::move(RaiseTypeError(message, beginningPosition));
}
///@}
static size_t WrittenParametersFirstIndex(const gd::String &objectName,
const gd::String &behaviorName) {
// By convention, object is always the first parameter, and behavior the
// second one.
return !behaviorName.empty() ? 2 : (!objectName.empty() ? 1 : 0);
}
gd::String expression;
std::size_t currentPosition;
const gd::Platform &platform;
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;
};
} // namespace gd
#endif // GDCORE_EXPRESSIONPARSER2_H

View File

@@ -0,0 +1,10 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ExpressionParser2Node.h"
namespace gd {
gd::String ExpressionParserDiagnostic::noMessage = "";
}

View File

@@ -0,0 +1,294 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONPARSER2NODES_H
#define GDCORE_EXPRESSIONPARSER2NODES_H
#include <memory>
#include <vector>
#include "ExpressionParser2NodeWorker.h"
#include "GDCore/String.h"
namespace gd {
class Expression;
class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
} // namespace gd
namespace gd {
/**
* \brief A diagnostic that can be attached to a gd::ExpressionNode.
*/
struct ExpressionParserDiagnostic {
virtual bool IsError() { return false; }
virtual const gd::String &GetMessage() { return noMessage; }
virtual size_t GetStartPosition() { return 0; }
virtual size_t GetEndPosition() { return 0; }
private:
static gd::String noMessage;
};
/**
* \brief An error that can be attached to a gd::ExpressionNode.
*/
struct ExpressionParserError : public ExpressionParserDiagnostic {
ExpressionParserError(const gd::String &type_,
const gd::String &message_,
size_t 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_),
startPosition(startPosition_),
endPosition(endPosition_){};
virtual ~ExpressionParserError(){};
bool IsError() override { return true; }
const gd::String &GetMessage() override { return message; }
size_t GetStartPosition() override { return startPosition; }
size_t GetEndPosition() override { return endPosition; }
private:
gd::String type;
gd::String message;
size_t startPosition;
size_t endPosition;
};
/**
* \brief The base node, from which all nodes in the tree of
* an expression inherits from.
*/
struct ExpressionNode {
virtual ~ExpressionNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker){};
std::unique_ptr<ExpressionParserDiagnostic> diagnostic;
};
struct SubExpressionNode : public ExpressionNode {
SubExpressionNode(std::unique_ptr<ExpressionNode> expression_)
: expression(std::move(expression_)){};
virtual ~SubExpressionNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitSubExpressionNode(*this);
};
std::unique_ptr<ExpressionNode> expression;
};
/**
* \brief An operator node. For example: "lhs + rhs".
*/
struct OperatorNode : public ExpressionNode {
virtual ~OperatorNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitOperatorNode(*this);
};
std::unique_ptr<ExpressionNode> leftHandSide;
std::unique_ptr<ExpressionNode> rightHandSide;
gd::String::value_type op;
};
/**
* \brief A unary operator node. For example: "-2".
*/
struct UnaryOperatorNode : public ExpressionNode {
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::value_type op;
};
/**
* \brief A number node. For example: "123".
*/
struct NumberNode : public ExpressionNode {
NumberNode(const gd::String &number_) : number(number_){};
virtual ~NumberNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitNumberNode(*this);
};
gd::String number;
};
/**
* \brief A text node. For example: "Hello World".
*/
struct TextNode : public ExpressionNode {
TextNode(const gd::String &text_) : text(text_){};
virtual ~TextNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitTextNode(*this);
};
gd::String text;
};
struct VariableAccessorOrVariableBracketAccessorNode : public ExpressionNode {
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode> child;
};
/**
* \brief A variable, potentially with accessor to its children.
*
* Example: MyVariable or MyVariable.MyChildren
*
* \see gd::VariableAccessorNode
* \see gd::VariableBracketAccessorNode
*/
struct VariableNode : public ExpressionNode {
VariableNode(const gd::String &type_,
const gd::String &name_,
const gd::String &objectName_)
: type(type_), name(name_), objectName(objectName_){};
virtual ~VariableNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitVariableNode(*this);
};
gd::String type;
gd::String name;
gd::String objectName;
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
child; // Can be nullptr if no accessor
};
/**
* \brief A bracket accessor of a variable. Example: MyChild
* in MyVariable.MyChild
*/
struct VariableAccessorNode
: public VariableAccessorOrVariableBracketAccessorNode {
VariableAccessorNode(const gd::String &name_) : name(name_){};
virtual ~VariableAccessorNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitVariableAccessorNode(*this);
};
gd::String name;
};
/**
* \brief A bracket accessor of a variable. Example: ["MyChild"]
* (in MyVariable["MyChild"]).
*/
struct VariableBracketAccessorNode
: public VariableAccessorOrVariableBracketAccessorNode {
VariableBracketAccessorNode(std::unique_ptr<ExpressionNode> expression_)
: expression(std::move(expression_)){};
virtual ~VariableBracketAccessorNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitVariableBracketAccessorNode(*this);
};
std::unique_ptr<ExpressionNode> expression;
};
struct IdentifierOrFunctionOrEmptyNode : public ExpressionNode {};
/**
* \brief An identifier node, usually representing an object.
*/
struct IdentifierNode : public IdentifierOrFunctionOrEmptyNode {
IdentifierNode(const gd::String &identifierName_, const gd::String &type_)
: identifierName(identifierName_), type(type_){};
virtual ~IdentifierNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitIdentifierNode(*this);
};
gd::String identifierName;
gd::String type;
};
struct FunctionOrEmptyNode : public IdentifierOrFunctionOrEmptyNode {
virtual ~FunctionOrEmptyNode(){};
void Visit(ExpressionParser2NodeWorker &worker) override{};
};
/**
* \brief A function node. For example: "MyExtension::MyFunction(1, 2)".
*/
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_){};
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_){};
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 ~FunctionNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitFunctionNode(*this);
};
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;
};
/**
* \brief An empty node, used when parsing failed/a syntax error was
* encountered and any other node could not make sense.
*/
struct EmptyNode : public FunctionOrEmptyNode {
EmptyNode(const gd::String &type_, const gd::String &text_ = "")
: type(type_), text(text_){};
virtual ~EmptyNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitEmptyNode(*this);
};
gd::String type;
gd::String text;
};
} // namespace gd
#endif

View File

@@ -0,0 +1,124 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONNODEPRINTER_H
#define GDCORE_EXPRESSIONNODEPRINTER_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 Print the expression corresponding to a set of nodes
* (i.e: this is doing the inverse operation of gd::ExpressionParser2).
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionParser2NodePrinter
: public ExpressionParser2NodeWorker {
public:
ExpressionParser2NodePrinter(){};
virtual ~ExpressionParser2NodePrinter(){};
static gd::String PrintNode(gd::ExpressionNode& node) {
gd::ExpressionParser2NodePrinter printer;
node.Visit(printer);
return printer.GetOutput();
}
/**
* \brief Get the string corresponding to the expression nodes.
*/
const gd::String& GetOutput() { return output; };
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
output += "(";
node.expression->Visit(*this);
output += ")";
}
void OnVisitOperatorNode(OperatorNode& node) override {
node.leftHandSide->Visit(*this);
if (node.op == ' ') {
// There is no "space" operator. If it's there, it's because
// an operator could not be found (that's an error). Add only
// a whitespace between terms.
output += " ";
} else {
output += " ";
output.push_back(node.op);
output += " ";
}
node.rightHandSide->Visit(*this);
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
output.push_back(node.op);
node.factor->Visit(*this);
}
void OnVisitNumberNode(NumberNode& node) override { output += node.number; }
void OnVisitTextNode(TextNode& node) override {
output +=
"\"" +
node.text.FindAndReplace("\\", "\\\\").FindAndReplace("\"", "\\\"") +
"\"";
}
void OnVisitVariableNode(VariableNode& node) override {
output += node.name;
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
output += "." + node.name;
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
output += "[";
node.expression->Visit(*this);
output += "]";
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
output += node.identifierName;
}
void OnVisitFunctionNode(FunctionNode& node) override {
if (!node.behaviorName.empty()) {
output +=
node.objectName + "." + node.behaviorName + "::" + node.functionName;
} else if (!node.objectName.empty()) {
output += node.objectName + "." + node.functionName;
} else {
output += node.functionName;
}
output += "(";
bool isFirst = true;
for (auto& parameterNode : node.parameters) {
if (!isFirst) output += ", ";
parameterNode->Visit(*this);
isFirst = false;
}
output += ")";
}
void OnVisitEmptyNode(EmptyNode& node) override { output += node.text; }
private:
gd::String output;
};
} // namespace gd
#endif // GDCORE_EXPRESSIONNODEPRINTER_H

View File

@@ -0,0 +1,10 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "ExpressionParser2NodeWorker.h"
namespace gd {
ExpressionParser2NodeWorker::~ExpressionParser2NodeWorker(){};
}

View File

@@ -0,0 +1,71 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONPARSER2NODEWORKER_H
#define GDCORE_EXPRESSIONPARSER2NODEWORKER_H
namespace gd {
class ExpressionNode;
class SubExpressionNode;
class OperatorNode;
class UnaryOperatorNode;
class NumberNode;
class TextNode;
class VariableNode;
class VariableAccessorNode;
class VariableBracketAccessorNode;
class IdentifierOrFunctionOrEmptyNode;
class IdentifierNode;
class FunctionOrEmptyNode;
class FunctionNode;
class EmptyNode;
} // namespace gd
namespace gd {
/**
* \brief The interface for any worker class ("visitor" pattern)
* that want to interact with the nodes of a parsed expression.
*
* \see gd::ExpressionParser2
* \see gd::ExpressionNode
*/
class GD_CORE_API ExpressionParser2NodeWorker {
friend class ExpressionNode;
friend class SubExpressionNode;
friend class OperatorNode;
friend class UnaryOperatorNode;
friend class NumberNode;
friend class TextNode;
friend class VariableNode;
friend class VariableAccessorNode;
friend class VariableBracketAccessorNode;
friend class IdentifierOrFunctionOrEmptyNode;
friend class IdentifierNode;
friend class FunctionOrEmptyNode;
friend class FunctionNode;
friend class EmptyNode;
public:
virtual ~ExpressionParser2NodeWorker();
protected:
virtual void OnVisitSubExpressionNode(SubExpressionNode& node) = 0;
virtual void OnVisitOperatorNode(OperatorNode& node) = 0;
virtual void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) = 0;
virtual void OnVisitNumberNode(NumberNode& node) = 0;
virtual void OnVisitTextNode(TextNode& node) = 0;
virtual void OnVisitVariableNode(VariableNode& node) = 0;
virtual void OnVisitVariableAccessorNode(VariableAccessorNode& node) = 0;
virtual void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) = 0;
virtual void OnVisitIdentifierNode(IdentifierNode& node) = 0;
virtual void OnVisitFunctionNode(FunctionNode& node) = 0;
virtual void OnVisitEmptyNode(EmptyNode& node) = 0;
};
} // namespace gd
#endif

View File

@@ -134,7 +134,7 @@ gd::String VariableParser::SkipStringExpression() {
++currentPositionIt;
}
// End of the expression reached ( So expression is invalid by the way )
// End of the expression reached (so expression is invalid by the way)
return stringExpression;
}

View File

@@ -40,13 +40,14 @@ gd::VariableParserCallbacks VariableCodeGenerationCallbacks callbacks(output,
gd::VariableParser parser(parameter);
if ( !parser.Parse(callbacks) )
cout << "Error :" << parser.GetFirstError() << " in: "<< parameter <<
endl; \endcode
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
* where e = nothing (end of expression), StringExpression = A valid string
expression and
* S is the start.
*

View File

@@ -16,11 +16,75 @@
#include "GDCore/Serialization/Serializer.h"
#include "GDCore/Serialization/SerializerElement.h"
#include "GDCore/Tools/Log.h"
#include "GDCore/Tools/VersionWrapper.h"
using namespace std;
namespace {
bool AddQuotesToFunctionCall(gd::String& expressionStr,
const gd::String& functionName) {
bool changedSomething = false;
size_t functionCallPos = expressionStr.find(functionName + "(");
while (functionCallPos != gd::String::npos) {
size_t pos = functionCallPos + functionName.size() + 1;
// Skip whitespace
while (pos < expressionStr.size() && expressionStr[pos] == ' ') pos++;
if (pos < expressionStr.size()) {
changedSomething = true;
// Insert the first quote
expressionStr.insert(pos, "\"");
pos++;
// Escape the argument
while (pos < expressionStr.size() && expressionStr[pos] != ')') {
if (expressionStr[pos] == '"') {
expressionStr.insert(pos,
"\\"); // Insert a backslash to escape the quote
pos++;
}
pos++;
}
// Insert the last quote
if (pos < expressionStr.size() && expressionStr[pos] == ')') {
expressionStr.insert(pos, "\"");
pos++;
}
}
functionCallPos = expressionStr.find(functionName + "(", pos + 1);
}
return changedSomething;
}
} // namespace
namespace gd {
void EventsListSerialization::UpdateInstructionsFromGD4097(
gd::Project& project, gd::InstructionsList& list) {
for (std::size_t i = 0; i < list.size(); ++i) {
gd::Instruction& instr = list[i];
for (std::size_t j = 0; j < instr.GetParametersCount(); ++j) {
gd::String expressionStr = instr.GetParameter(j).GetPlainString();
bool changedSomething = false;
changedSomething |= AddQuotesToFunctionCall(expressionStr, "PointX");
changedSomething |= AddQuotesToFunctionCall(expressionStr, "PointY");
if (changedSomething) {
std::cout << "(Debug) Converted \""
<< instr.GetParameter(j).GetPlainString() << "\" to \""
<< expressionStr << "\"" << std::endl;
instr.SetParameter(j, gd::Expression(expressionStr));
}
}
}
}
void EventsListSerialization::UpdateInstructionsFromGD31x(
gd::Project& project, gd::InstructionsList& list) {
for (std::size_t i = 0; i < list.size(); ++i) {
@@ -256,6 +320,18 @@ void gd::EventsListSerialization::UnserializeInstructionsFrom(
if (project.GetLastSaveGDMajorVersion() < 3)
UpdateInstructionsFromGD2x(
project, instructions, elem.HasChild("action", "Action"));
// Compatibility with GD <= 4.0.97
if (VersionWrapper::IsOlderOrEqual(project.GetLastSaveGDMajorVersion(),
project.GetLastSaveGDMinorVersion(),
project.GetLastSaveGDBuildVersion(),
0,
4,
0,
97,
0)) {
UpdateInstructionsFromGD4097(project, instructions);
}
// end of compatibility code
}

View File

@@ -72,6 +72,16 @@ class GD_CORE_API EventsListSerialization {
*/
static void UpdateInstructionsFromGD31x(gd::Project& project,
gd::InstructionsList& list);
/**
* \brief Internal method called when opening events created with GD <= 4.0.97
*
* PointX/PointY would previously take a name of a point without quotes.
* This is not providing any value and inconsistent with everything else.
* Add quotes around them.
*/
static void UpdateInstructionsFromGD4097(gd::Project& project,
gd::InstructionsList& list);
};
} // namespace gd

View File

@@ -176,15 +176,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddCodeOnlyParameter("currentScene", "")
.MarkAsAdvanced();
obj.AddAction("AddForceXY",
_("Add a force"),
_("Add a force to an object. The object will move according to "
"all of the forces it has."),
_("Add to _PARAM0_ _PARAM3_ force of _PARAM1_ p/s on X axis and "
"_PARAM2_ p/s on Y axis"),
_("Movement"),
"res/actions/force24.png",
"res/actions/force.png")
obj.AddAction(
"AddForceXY",
_("Add a force"),
_("Add a force to an object. The object will move according to "
"all of the forces it has."),
_("Add to _PARAM0_ _PARAM3_ force of _PARAM1_ p/s on X axis and "
"_PARAM2_ p/s on Y axis"),
_("Movement"),
"res/actions/force24.png",
"res/actions/force.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Speed on X axis (in pixels per second)"))
@@ -551,13 +552,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("yesorno", _("Activate?"))
.MarkAsAdvanced();
obj.AddAction("AddForceVers",
_("Add a force to move toward an object"),
_("Add a force to an object to make it move toward another."),
_("Move _PARAM0_ to _PARAM1_ with _PARAM3_ force of _PARAM2_ pixels"),
_("Movement"),
"res/actions/forceVers24.png",
"res/actions/forceVers.png")
obj.AddAction(
"AddForceVers",
_("Add a force to move toward an object"),
_("Add a force to an object to make it move toward another."),
_("Move _PARAM0_ to _PARAM1_ with _PARAM3_ force of _PARAM2_ pixels"),
_("Movement"),
"res/actions/forceVers24.png",
"res/actions/forceVers.png")
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Target Object"))
@@ -640,6 +642,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectList", _("Objects"))
.AddParameter("yesorno",
_("Ignore objects that are touching each other on their "
"edges, but are not overlapping (default: no)"),
"",
true)
.SetDefaultValue("no")
.MarkAsSimple();
obj.AddCondition("CollisionPoint",
@@ -654,13 +662,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Y position of the point"))
.MarkAsSimple();
obj.AddCondition("ObjectTimer",
_("Value of a timer"),
_("Test the elapsed time of a timer."),
_("The timer _PARAM1_ of _PARAM0_ is greater than _PARAM2_ seconds"),
_("Timers"),
"res/conditions/timer24.png",
"res/conditions/timer.png")
obj.AddCondition(
"ObjectTimer",
_("Value of a timer"),
_("Test the elapsed time of a timer."),
_("The timer _PARAM1_ of _PARAM0_ is greater than _PARAM2_ seconds"),
_("Timers"),
"res/conditions/timer24.png",
"res/conditions/timer.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Timer's name"))
.AddParameter("expression", _("Time in seconds"));
@@ -863,10 +872,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"));
obj.AddExpression("ObjectTimerElapsedTime",
_("Timer value"),
_("Value of a timer"),
_("Timers"),
"res/actions/time.png")
_("Timer value"),
_("Value of a timer"),
_("Timers"),
"res/actions/time.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Timer's name"));
@@ -1046,6 +1055,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectList", _("Object"))
.AddParameter("objectList", _("Object"))
.AddCodeOnlyParameter("conditionInverted", "")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("yesorno",
_("Ignore objects that are touching each other on their "
"edges, but are not overlapping (default: no)"),
"",
true)
.SetDefaultValue("no")
.MarkAsSimple();
extension

View File

@@ -13,9 +13,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
gd::PlatformExtension& extension) {
extension
.SetExtensionInformation("BuiltinFile",
_("Storage and files"),
_("Storage"),
_("Built-in extension providing functions "
"to store data and manipulate files."),
"to store data."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/all-features/storage");
@@ -26,55 +26,55 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
"GroupExists",
_("Existence of a group"),
_("Check if an element (example : PlayerState/CurrentLevel) exists "
"in the file.\nSpaces are forbidden in element names."),
_("_PARAM1_ exists in file _PARAM0_"),
"in the stored data.\nSpaces are forbidden in element names."),
_("_PARAM1_ exists in storage _PARAM0_"),
_("Storage"),
"res/conditions/fichier24.png",
"res/conditions/fichier.png")
.AddParameter("file", _("Filename"))
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.MarkAsAdvanced();
extension
.AddAction(
"LoadFile",
_("Load a structured file in memory"),
_("This action loads the structured file in memory, so you can write "
"and read it.\nYou can open and write without using this action, "
"but it will be slower.\nIf you use this action, do not forget to "
"unload the file from memory.\n\nFor the native platform, the file "
"format is XML."),
_("Load structured file _PARAM0_ in memory"),
_("Load a storage in memory"),
_("This action loads the specified storage in memory, so you can "
"write and read it.\nYou can open and write without using this "
"action, but it will be slower.\nIf you use this action, do not "
"forget to unload the storage from memory."),
_("Load storage _PARAM0_ in memory"),
_("Storage"),
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("file", _("File"))
.AddParameter("string", _("Storage name"))
.MarkAsAdvanced();
extension
.AddAction("UnloadFile",
_("Close a structured file"),
_("This action closes the structured file previously loaded "
_("Close a storage"),
_("This action closes the structured data previously loaded "
"in memory, saving all changes made."),
_("Close structured file _PARAM0_"),
_("Close structured data _PARAM0_"),
_("Storage"),
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("file", _("File"))
.AddParameter("string", _("Storage name"))
.MarkAsAdvanced();
extension
.AddAction("EcrireFichierExp",
_("Write a value"),
_("Write the result of the expression in the file, in the "
"specified element.\nSpecify the structure leading to the "
"element using / (example : Root/Level/Current)\nSpaces are "
"forbidden in element names."),
_("Write _PARAM2_ in _PARAM1_ of file _PARAM0_"),
_("Storage"),
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("file", _("File"))
.AddAction(
"EcrireFichierExp",
_("Write a value"),
_("Write the result of the expression in the stored data, in the "
"specified element.\nSpecify the structure leading to the "
"element using / (example : Root/Level/Current)\nSpaces are "
"forbidden in element names."),
_("Write _PARAM2_ in _PARAM1_ of storage _PARAM0_"),
_("Storage"),
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddParameter("expression", _("Expression"));
@@ -82,14 +82,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddAction(
"EcrireFichierTxt",
_("Write a text"),
_("Write the text in the file, in the specified element.\nSpecify "
_("Write the text in the specified storage, in the specified "
"element.\nSpecify "
"the structure leading to the element using / (example : "
"Root/Level/Current)\nSpaces are forbidden in element names."),
_("Write _PARAM2_ in _PARAM1_ of file _PARAM0_"),
_("Write _PARAM2_ in _PARAM1_ of storage _PARAM0_"),
_("Storage"),
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("file", _("File"))
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddParameter("string", _("Text"));
@@ -101,11 +102,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
"variable.\nSpecify the structure leading to the element using / "
"(example : Root/Level/Current)\nSpaces are forbidden in element "
"names."),
_("Read _PARAM1_ from file _PARAM0_ and store value in _PARAM3_"),
_("Read _PARAM1_ from storage _PARAM0_ and store value in _PARAM3_"),
_("Storage"),
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("file", _("File"))
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("scenevar", _("Scene variables"));
@@ -118,11 +119,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
"variable.\nSpecify the structure leading to the element using / "
"(example : Root/Level/Current)\nSpaces are forbidden in element "
"names."),
_("Read _PARAM1_ from file _PARAM0_ and store as text in _PARAM3_"),
_("Read _PARAM1_ from storage _PARAM0_ and store as text in "
"_PARAM3_"),
_("Storage"),
"res/actions/fichier24.png",
"res/actions/fichier.png")
.AddParameter("file", _("File"))
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("scenevar", _("Scene variables"));
@@ -131,36 +133,37 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
.AddAction("DeleteGroupFichier",
_("Delete an element"),
_("This action deletes the specified element from the "
"structured file.\nSpecify the structure leading to the "
"specified storage.\nSpecify the structure leading to the "
"element using / (example : Root/Level/Current)\nSpaces are "
"forbidden in element names."),
_("Delete _PARAM1_ from the file _PARAM0_"),
_("Delete _PARAM1_ from storage _PARAM0_"),
_("Storage"),
"res/actions/delete24.png",
"res/actions/delete.png")
.AddParameter("file", _("Filename"))
.AddParameter("string", _("Storage name"))
.AddParameter("string", _("Group"))
.MarkAsAdvanced();
extension
.AddAction("DeleteFichier",
_("Delete a file"),
_("Delete the file."),
_("Delete the file _PARAM0_"),
_("Files"),
"res/actions/delete24.png",
"res/actions/delete.png")
.AddParameter("file", _("Filename"));
.AddAction(
"DeleteFichier",
_("Clear a storage"),
_("Clear the specified storage, removing all data saved in it."),
_("Delete storage _PARAM0_"),
_("Storage"),
"res/actions/delete24.png",
"res/actions/delete.png")
.AddParameter("string", _("Storage name"));
extension
.AddCondition("FileExists",
_("A file exists"),
_("Test if the file exists."),
_("File _PARAM0_ exists"),
_("Files"),
_("A storage exists"),
_("Test if the specified storage exists."),
_("Storage _PARAM0_ exists"),
_("Storage"),
"res/conditions/fichier24.png",
"res/conditions/fichier.png")
.AddParameter("file", _("Filename"))
.AddParameter("string", _("Storage name"))
.MarkAsAdvanced();
extension

View File

@@ -18,7 +18,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
_("Built-in extension that enables the use of a mouse"),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/events/mouse-touch");
.SetExtensionHelpPath("/all-features/mouse-touch");
#if defined(GD_IDE_ONLY)
extension

View File

@@ -15,7 +15,7 @@ using namespace std;
namespace gd {
Direction::Direction() : loop(false), timeBetweenFrame(1) {}
Direction::Direction() : loop(false), timeBetweenFrame(0.08) {}
Direction::~Direction(){};

View File

@@ -200,6 +200,34 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddAction("ChangeWidth",
_("Width"),
_("Change the width of a Sprite object."),
_("Do _PARAM1__PARAM2_ to the width of _PARAM0_"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddAction("ChangeHeight",
_("Height"),
_("Change the height of a Sprite object."),
_("Do _PARAM1__PARAM2_ to the height of _PARAM0_"),
_("Size"),
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.MarkAsAdvanced()
.SetManipulatedType("number");
obj.AddCondition(
"Animation",
_("Current animation"),
@@ -464,7 +492,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/position.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("", _("Name of the point"), "", true);
.AddParameter("string", _("Name of the point"), "", true);
obj.AddExpression("Y",
_("Y position of a point"),
@@ -473,7 +501,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/position.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("", _("Name of the point"), "", true);
.AddParameter("string", _("Name of the point"), "", true);
obj.AddExpression("PointX",
_("X position of a point"),
@@ -482,7 +510,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/position.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("", _("Name of the point"));
.AddParameter("string", _("Name of the point"));
obj.AddExpression("PointY",
_("Y position of a point"),
@@ -491,7 +519,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"res/actions/position.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("", _("Name of the point"));
.AddParameter("string", _("Name of the point"));
obj.AddExpression("Direc",
_("Direction"),

View File

@@ -146,7 +146,9 @@ class GD_CORE_API ParameterMetadata {
/**
* \brief Return true if the type of the parameter is "object", "objectPtr" or
* "objectList". \see gd::ParameterMetadata::GetType
* "objectList".
*
* \see gd::ParameterMetadata::GetType
*/
static bool IsObject(const gd::String &parameterType) {
return parameterType == "object" || parameterType == "objectPtr" ||
@@ -155,8 +157,8 @@ class GD_CORE_API ParameterMetadata {
}
/**
* \brief Return true if the type of the parameter is "object", "objectPtr" or
* "objectList". \see gd::ParameterMetadata::GetType
* \brief Return true if the type of the parameter is an expression of the
* given type.
*/
static bool IsExpression(const gd::String &type,
const gd::String &parameterType) {
@@ -167,6 +169,9 @@ class GD_CORE_API ParameterMetadata {
return parameterType == "string" || parameterType == "layer" ||
parameterType == "color" || parameterType == "file" ||
parameterType == "joyaxis";
} else if (type == "variable") {
return parameterType == "objectvar" || parameterType == "globalvar" ||
parameterType == "scenevar";
}
return false;
}

View File

@@ -19,8 +19,8 @@ class PlatformExtension;
namespace gd {
/**
* \brief A container for metadata about an object/behavior/instruction/expression
* and its associated extension.
* \brief A container for metadata about an
* object/behavior/instruction/expression and its associated extension.
*/
template <class T>
class ExtensionAndMetadata {
@@ -34,8 +34,7 @@ class ExtensionAndMetadata {
* \warning Please do not use.
* \private
*/
ExtensionAndMetadata()
: extension(nullptr), metadata(nullptr){};
ExtensionAndMetadata() : extension(nullptr), metadata(nullptr){};
/**
* \brief Get the associated extension.
@@ -296,6 +295,11 @@ class GD_CORE_API MetadataProvider {
gd::String behaviorType,
gd::String name);
static bool IsBadExpressionMetadata(const gd::ExpressionMetadata& metadata) {
return &metadata == &badExpressionMetadata ||
&metadata == &badStrExpressionMetadata;
}
virtual ~MetadataProvider();
private:

View File

@@ -19,7 +19,7 @@ class GD_CORE_API PropertyDescriptor {
* value. \param propertyValue The value of the property.
*/
PropertyDescriptor(gd::String propertyValue)
: currentValue(propertyValue), type("string") {}
: currentValue(propertyValue), type("string"), label("") {}
/**
* \brief Empty constructor creating an empty property to be displayed.
@@ -51,6 +51,14 @@ class GD_CORE_API PropertyDescriptor {
return *this;
}
/**
* \brief Change the label displayed in the property grid.
*/
PropertyDescriptor& SetLabel(gd::String label_) {
label = label_;
return *this;
}
/**
* \brief Add an information about the property.
* \note The information are arbitrary and are interpreted by the class
@@ -65,6 +73,7 @@ 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 std::vector<gd::String>& GetExtraInfo() const {
return extraInformation;
}
@@ -74,6 +83,7 @@ class GD_CORE_API PropertyDescriptor {
gd::String
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
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

@@ -9,102 +9,71 @@
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
class CallbacksForListingObjects : public gd::ParserCallbacks {
/**
* \brief Go through the nodes and report any object found.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionObjectsAnalyzer
: public ExpressionParser2NodeWorker {
public:
CallbacksForListingObjects(const gd::Platform& platform_,
const gd::ObjectsContainer& project_,
const gd::ObjectsContainer& layout_,
EventsContext& context_)
: platform(platform_),
project(project_),
layout(layout_),
context(context_){};
virtual ~CallbacksForListingObjects(){};
ExpressionObjectsAnalyzer(EventsContext& context_) : context(context_){};
virtual ~ExpressionObjectsAnalyzer(){};
virtual void OnConstantToken(gd::String text){};
virtual void OnStaticFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
for (std::size_t i = 0;
i < parameters.size() && i < expressionInfo.parameters.size();
++i) {
EventsContextAnalyzer::AnalyzeParameter(platform,
project,
layout,
expressionInfo.parameters[i],
parameters[i],
context);
}
};
virtual void OnObjectFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
for (std::size_t i = 0;
i < parameters.size() && i < expressionInfo.parameters.size();
++i) {
EventsContextAnalyzer::AnalyzeParameter(platform,
project,
layout,
expressionInfo.parameters[i],
parameters[i],
context);
}
};
virtual void OnObjectBehaviorFunction(
gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
for (std::size_t i = 0;
i < parameters.size() && i < expressionInfo.parameters.size();
++i) {
EventsContextAnalyzer::AnalyzeParameter(platform,
project,
layout,
expressionInfo.parameters[i],
parameters[i],
context);
}
};
virtual bool OnSubMathExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
CallbacksForListingObjects callbacks(platform, project, layout, context);
gd::ExpressionParser parser(expression.GetPlainString());
parser.ParseMathExpression(platform, project, layout, callbacks);
return true;
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
node.expression->Visit(*this);
}
virtual bool OnSubTextExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
CallbacksForListingObjects callbacks(platform, project, layout, context);
gd::ExpressionParser parser(expression.GetPlainString());
parser.ParseStringExpression(platform, project, layout, callbacks);
return true;
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 {
if (gd::ParameterMetadata::IsObject(node.type)) {
context.AddObjectName(node.identifierName);
}
}
void OnVisitFunctionNode(FunctionNode& node) override {
if (!node.objectName.empty()) {
context.AddObjectName(node.objectName);
}
for (auto& parameter : node.parameters) {
parameter->Visit(*this);
}
}
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
const gd::Platform& platform;
const gd::ObjectsContainer& project;
const gd::ObjectsContainer& layout;
EventsContext& context;
};
@@ -142,15 +111,17 @@ void EventsContextAnalyzer::AnalyzeParameter(
if (ParameterMetadata::IsObject(type)) {
context.AddObjectName(value);
} else if (ParameterMetadata::IsExpression("number", type)) {
CallbacksForListingObjects callbacks(platform, project, layout, context);
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", value);
gd::ExpressionParser parser(value);
parser.ParseMathExpression(platform, project, layout, callbacks);
ExpressionObjectsAnalyzer analyzer(context);
node->Visit(analyzer);
} else if (ParameterMetadata::IsExpression("string", type)) {
CallbacksForListingObjects callbacks(platform, project, layout, context);
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", value);
gd::ExpressionParser parser(value);
parser.ParseStringExpression(platform, project, layout, callbacks);
ExpressionObjectsAnalyzer analyzer(context);
node->Visit(analyzer);
}
}

View File

@@ -8,200 +8,159 @@
#include <memory>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Events/Parsers/ExpressionParser.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Events/EventsList.h"
using namespace std;
namespace gd {
class CallbacksForRenamingObject : public gd::ParserCallbacks {
/**
* \brief Go through the nodes and change the given object name to a new one.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
public:
CallbacksForRenamingObject(gd::String& plainExpression_,
gd::String oldName_,
gd::String newName_)
: plainExpression(plainExpression_),
newName(newName_),
oldName(oldName_){};
virtual ~CallbacksForRenamingObject(){};
ExpressionObjectRenamer(const gd::String& objectName_,
const gd::String& objectNewName_)
: hasDoneRenaming(false), objectName(objectName_), objectNewName(objectNewName_){};
virtual ~ExpressionObjectRenamer(){};
virtual void OnConstantToken(gd::String text) { plainExpression += text; };
static bool Rename(gd::ExpressionNode & node, const gd::String& objectName, const gd::String& objectNewName) {
if (ExpressionValidator::HasNoErrors(node)) {
ExpressionObjectRenamer renamer(objectName, objectNewName);
node.Visit(renamer);
virtual void OnStaticFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
// Special case : Function without name is a litteral string.
if (functionName.empty()) {
if (parameters.empty()) return;
plainExpression += "\"" + parameters[0].GetPlainString() + "\"";
return;
return renamer.HasDoneRenaming();
}
gd::String parametersStr;
for (std::size_t i = 0; i < parameters.size(); ++i) {
if (i < expressionInfo.parameters.size() &&
expressionInfo.parameters[i].codeOnly)
continue; // Skip code only parameter which are not included in
// function calls.
if (!parametersStr.empty()) parametersStr += ",";
parametersStr += parameters[i].GetPlainString();
}
plainExpression += functionName + "(" + parametersStr + ")";
};
virtual void OnObjectFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
if (parameters.empty()) return;
gd::String parametersStr;
for (std::size_t i = 1; i < parameters.size(); ++i) {
if (i < expressionInfo.parameters.size() &&
expressionInfo.parameters[i].codeOnly)
continue; // Skip code only parameter which are not included in
// function calls.
if (!parametersStr.empty()) parametersStr += ",";
parametersStr += parameters[i].GetPlainString();
}
plainExpression += (parameters[0].GetPlainString() == oldName
? newName
: parameters[0].GetPlainString()) +
"." + functionName + "(" + parametersStr + ")";
};
virtual void OnObjectBehaviorFunction(
gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
if (parameters.size() < 2) return;
gd::String parametersStr;
for (std::size_t i = 2; i < parameters.size(); ++i) {
if (i < expressionInfo.parameters.size() &&
expressionInfo.parameters[i].codeOnly)
continue; // Skip code only parameter which are not included in
// function calls.
if (!parametersStr.empty()) parametersStr += ",";
parametersStr += parameters[i].GetPlainString();
}
plainExpression += (parameters[0].GetPlainString() == oldName
? newName
: parameters[0].GetPlainString()) +
"." + parameters[1].GetPlainString() +
"::" + functionName + "(" + parametersStr + ")";
};
virtual bool OnSubMathExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
// TODO: Add support for renaming in sub expressions. This is not working
// as the parser does not handle change made to the expression.
gd::String newExpression;
CallbacksForRenamingObject callbacks(newExpression, oldName, newName);
gd::ExpressionParser parser(expression.GetPlainString());
if (!parser.ParseMathExpression(platform, project, layout, callbacks))
return false;
expression = gd::Expression(newExpression); // This change won't be picked up by the parser
return true;
return false;
}
virtual bool OnSubTextExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
// TODO: Add support for renaming in sub expressions. This is not working
// as the parser does not handle change made to the expression.
gd::String newExpression;
bool HasDoneRenaming() const { return hasDoneRenaming; }
CallbacksForRenamingObject callbacks(newExpression, oldName, newName);
gd::ExpressionParser parser(expression.GetPlainString());
if (!parser.ParseStringExpression(platform, project, layout, callbacks))
return false;
expression = gd::Expression(newExpression); // This change won't be picked up by the parser
return true;
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 {
if (gd::ParameterMetadata::IsObject(node.type) && node.identifierName == objectName) {
hasDoneRenaming = true;
node.identifierName = objectNewName;
}
}
void OnVisitFunctionNode(FunctionNode& node) override {
if (node.objectName == objectName) {
hasDoneRenaming = true;
node.objectName = objectNewName;
}
for (auto& parameter : node.parameters) {
parameter->Visit(*this);
}
}
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
gd::String& plainExpression;
gd::String newName;
gd::String oldName;
bool hasDoneRenaming;
const gd::String& objectName;
const gd::String& objectNewName;
};
class CallbacksForRemovingObject : public gd::ParserCallbacks {
/**
* \brief Go through the nodes and check if the given object is being used
* in the expression.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
public:
CallbacksForRemovingObject(gd::String name_)
: objectPresent(false), name(name_){};
virtual ~CallbacksForRemovingObject(){};
ExpressionObjectFinder(const gd::String& objectName_)
: hasObject(false), objectName(objectName_) {};
virtual ~ExpressionObjectFinder(){};
bool objectPresent; // True if the object is present in the expression
static bool CheckIfHasObject(gd::ExpressionNode & node, const gd::String & objectName) {
if (ExpressionValidator::HasNoErrors(node)) {
ExpressionObjectFinder finder(objectName);
node.Visit(finder);
virtual void OnConstantToken(gd::String text){};
return finder.HasFoundObject();
}
virtual void OnStaticFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo){};
virtual void OnObjectFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
if (parameters.empty()) return;
if (parameters[0].GetPlainString() == name) objectPresent = true;
};
virtual void OnObjectBehaviorFunction(
gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
if (parameters.empty()) return;
if (parameters[0].GetPlainString() == name) objectPresent = true;
};
virtual bool OnSubMathExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
CallbacksForRemovingObject callbacks(name);
gd::ExpressionParser parser(expression.GetPlainString());
if (!parser.ParseMathExpression(platform, project, layout, callbacks))
return false;
if (callbacks.objectPresent) objectPresent = true;
return true;
return false;
}
virtual bool OnSubTextExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
CallbacksForRemovingObject callbacks(name);
bool HasFoundObject() const { return hasObject; }
gd::ExpressionParser parser(expression.GetPlainString());
if (!parser.ParseStringExpression(platform, project, layout, callbacks))
return false;
if (callbacks.objectPresent) objectPresent = true;
return true;
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 {
if (gd::ParameterMetadata::IsObject(node.type) && node.identifierName == objectName) {
hasObject = true;
}
}
void OnVisitFunctionNode(FunctionNode& node) override {
if (node.objectName == objectName) {
hasObject = true;
}
for (auto& parameter : node.parameters) {
parameter->Visit(*this);
}
}
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
gd::String name;
bool hasObject;
const gd::String& objectName;
};
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
@@ -221,34 +180,23 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
actions[aId].GetParameter(pNb).GetPlainString() == oldName)
actions[aId].SetParameter(pNb, gd::Expression(newName));
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression("number", instrInfos.parameters[pNb].type)) {
gd::String newExpression;
gd::String oldExpression =
actions[aId].GetParameter(pNb).GetPlainString();
CallbacksForRenamingObject callbacks(newExpression, oldName, newName);
gd::ExpressionParser parser(oldExpression);
if (parser.ParseMathExpression(platform, project, layout, callbacks) &&
newExpression != oldExpression) {
somethingModified = true;
actions[aId].SetParameter(pNb, gd::Expression(newExpression));
else if (ParameterMetadata::IsExpression(
"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));
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression("string", instrInfos.parameters[pNb].type)) {
gd::String newExpression;
gd::String oldExpression =
actions[aId].GetParameter(pNb).GetPlainString();
CallbacksForRenamingObject callbacks(newExpression, oldName, newName);
gd::ExpressionParser parser(oldExpression);
if (parser.ParseStringExpression(
platform, project, layout, callbacks) &&
newExpression != oldExpression) {
somethingModified = true;
actions[aId].SetParameter(pNb, gd::Expression(newExpression));
else if (ParameterMetadata::IsExpression(
"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));
}
}
}
@@ -285,31 +233,23 @@ bool EventsRefactorer::RenameObjectInConditions(
conditions[cId].GetParameter(pNb).GetPlainString() == oldName)
conditions[cId].SetParameter(pNb, gd::Expression(newName));
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression("number", instrInfos.parameters[pNb].type)) {
gd::String newExpression;
gd::String oldExpression =
conditions[cId].GetParameter(pNb).GetPlainString();
CallbacksForRenamingObject callbacks(newExpression, oldName, newName);
gd::ExpressionParser parser(oldExpression);
if (parser.ParseMathExpression(platform, project, layout, callbacks)) {
somethingModified = true;
conditions[cId].SetParameter(pNb, gd::Expression(newExpression));
else if (ParameterMetadata::IsExpression(
"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));
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression("string", instrInfos.parameters[pNb].type)) {
gd::String newExpression;
gd::String oldExpression =
conditions[cId].GetParameter(pNb).GetPlainString();
CallbacksForRenamingObject callbacks(newExpression, oldName, newName);
gd::ExpressionParser parser(oldExpression);
if (parser.ParseMathExpression(platform, project, layout, callbacks)) {
somethingModified = true;
conditions[cId].SetParameter(pNb, gd::Expression(newExpression));
else if (ParameterMetadata::IsExpression(
"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));
}
}
}
@@ -378,33 +318,30 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
gd::InstructionMetadata instrInfos =
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// Replace object's name in parameters
// Find object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type) &&
actions[aId].GetParameter(pNb).GetPlainString() == name) {
deleteMe = true;
break;
}
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression("number", instrInfos.parameters[pNb].type)) {
CallbacksForRemovingObject callbacks(name);
gd::ExpressionParser parser(
actions[aId].GetParameter(pNb).GetPlainString());
if (parser.ParseMathExpression(platform, project, layout, callbacks) &&
callbacks.objectPresent) {
// Find object's name in expressions
else if (ParameterMetadata::IsExpression(
"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;
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression("string", instrInfos.parameters[pNb].type)) {
CallbacksForRemovingObject callbacks(name);
gd::ExpressionParser parser(
actions[aId].GetParameter(pNb).GetPlainString());
if (parser.ParseStringExpression(
platform, project, layout, callbacks) &&
callbacks.objectPresent) {
// Find object's name in text expressions
else if (ParameterMetadata::IsExpression(
"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;
}
@@ -442,33 +379,30 @@ bool EventsRefactorer::RemoveObjectInConditions(
gd::InstructionMetadata instrInfos = MetadataProvider::GetConditionMetadata(
platform, conditions[cId].GetType());
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
// Replace object's name in parameters
// Find object's name in parameters
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type) &&
conditions[cId].GetParameter(pNb).GetPlainString() == name) {
deleteMe = true;
break;
}
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression("number", instrInfos.parameters[pNb].type)) {
CallbacksForRemovingObject callbacks(name);
gd::ExpressionParser parser(
conditions[cId].GetParameter(pNb).GetPlainString());
if (parser.ParseMathExpression(platform, project, layout, callbacks) &&
callbacks.objectPresent) {
// Find object's name in expressions
else if (ParameterMetadata::IsExpression(
"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;
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression("string", instrInfos.parameters[pNb].type)) {
CallbacksForRemovingObject callbacks(name);
gd::ExpressionParser parser(
conditions[cId].GetParameter(pNb).GetPlainString());
if (parser.ParseStringExpression(
platform, project, layout, callbacks) &&
callbacks.objectPresent) {
// Find object's name in text expressions
else if (ParameterMetadata::IsExpression(
"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;
}

View File

@@ -7,7 +7,9 @@
#include "EventsVariablesFinder.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Events/Parsers/ExpressionParser.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
@@ -20,85 +22,70 @@ using namespace std;
namespace gd {
class CallbacksForSearchingVariable : public gd::ParserCallbacks {
/**
* \brief Go through the nodes and change the given object name to a new one.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionParameterSearcher
: public ExpressionParser2NodeWorker {
public:
CallbacksForSearchingVariable(std::set<gd::String>& results_,
const gd::String& parameterType_,
const gd::String& objectName_ = "")
ExpressionParameterSearcher(std::set<gd::String>& results_,
const gd::String& parameterType_,
const gd::String& objectName_ = "")
: results(results_),
parameterType(parameterType_),
objectName(objectName_){};
virtual ~CallbacksForSearchingVariable(){};
virtual ~ExpressionParameterSearcher(){};
virtual void OnConstantToken(gd::String text) {}
virtual void OnStaticFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
SearchInParameters(parameters, expressionInfo);
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
node.expression->Visit(*this);
}
virtual void OnObjectFunction(gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
SearchInParameters(parameters, expressionInfo);
void OnVisitOperatorNode(OperatorNode& node) override {
node.leftHandSide->Visit(*this);
node.rightHandSide->Visit(*this);
}
virtual void OnObjectBehaviorFunction(
gd::String functionName,
const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
SearchInParameters(parameters, expressionInfo);
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
node.factor->Visit(*this);
}
virtual bool OnSubMathExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
CallbacksForSearchingVariable callbacks(results, parameterType, objectName);
gd::ExpressionParser parser(expression.GetPlainString());
parser.ParseMathExpression(platform, project, layout, callbacks);
return true;
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
if (node.child) node.child->Visit(*this);
}
virtual bool OnSubTextExpression(const gd::Platform& platform,
const gd::ObjectsContainer& project,
const gd::ObjectsContainer& layout,
gd::Expression& expression) {
CallbacksForSearchingVariable callbacks(results, parameterType, objectName);
gd::ExpressionParser parser(expression.GetPlainString());
parser.ParseStringExpression(platform, project, layout, callbacks);
return true;
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
if (node.child) node.child->Visit(*this);
}
void SearchInParameters(const std::vector<gd::Expression>& parameters,
const gd::ExpressionMetadata& expressionInfo) {
gd::String lastObjectParameter = "";
for (std::size_t i = 0; i < parameters.size(); ++i) {
if (i >= expressionInfo.parameters.size()) break;
// The parameter has the searched type...
if (expressionInfo.parameters[i].type == parameterType) {
//...remember the value of the parameter.
if (objectName.empty() || objectName == lastObjectParameter)
results.insert(parameters[i].GetPlainString());
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
node.expression->Visit(*this);
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& 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();
++i) {
auto& parameterMetadata = node.expressionMetadata.parameters[i];
if (considerFunction && parameterMetadata.GetType() == parameterType) {
// Store the value of the parameter
results.insert(
gd::ExpressionParser2NodePrinter::PrintNode(*node.parameters[i]));
} else {
node.parameters[i]->Visit(*this);
}
// Remember the value of the last "object" parameter.
else if (gd::ParameterMetadata::IsObject(
expressionInfo.parameters[i].type))
lastObjectParameter = parameters[i].GetPlainString();
}
}
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
std::set<gd::String>& results; ///< Reference to the std::set where arguments
std::set<gd::String>& results; ///< Reference to the std::set where argument
///< values must be stored.
gd::String parameterType; ///< The name of the parameter to be searched for
gd::String
objectName; ///< If not empty, parameters will be taken into account only
///< if the last object parameter is filled with this value.
gd::String parameterType; ///< The type of the parameters to be searched for.
gd::String objectName; ///< If not empty, parameters will be taken into
///< account only if related to this object.
};
std::set<gd::String> EventsVariablesFinder::FindAllGlobalVariables(
@@ -174,22 +161,26 @@ std::set<gd::String> EventsVariablesFinder::FindArgumentsInInstructions(
results.insert(instructions[aId].GetParameter(pNb).GetPlainString());
}
// Search in expressions
else if (ParameterMetadata::IsExpression("number", instrInfos.parameters[pNb].type)) {
CallbacksForSearchingVariable callbacks(
results, parameterType, objectName);
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"number", instructions[aId].GetParameter(pNb).GetPlainString());
gd::ExpressionParser parser(
instructions[aId].GetParameter(pNb).GetPlainString());
parser.ParseMathExpression(platform, project, layout, callbacks);
ExpressionParameterSearcher searcher(
results, parameterType, objectName);
node->Visit(searcher);
}
// Search in gd::String expressions
else if (ParameterMetadata::IsExpression("string", instrInfos.parameters[pNb].type)) {
CallbacksForSearchingVariable callbacks(
results, parameterType, objectName);
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"number", instructions[aId].GetParameter(pNb).GetPlainString());
gd::ExpressionParser parser(
instructions[aId].GetParameter(pNb).GetPlainString());
parser.ParseStringExpression(platform, project, layout, callbacks);
ExpressionParameterSearcher searcher(
results, parameterType, objectName);
node->Visit(searcher);
}
// Remember the value of the last "object" parameter.
else if (gd::ParameterMetadata::IsObject(

View File

@@ -15,7 +15,7 @@ class Platform;
class Object;
class Project;
class Layout;
}
} // namespace gd
namespace gd {
@@ -23,7 +23,7 @@ namespace gd {
* \brief Perform a search over a project or a layout, searching for layout,
* global or object variables.
*
* \todo Refactor this class using ArbitraryEventsWorker!
* \todo Refactor this class using ArbitraryEventsWorker
*
* \ingroup IDE
*/
@@ -31,16 +31,21 @@ class EventsVariablesFinder {
public:
/**
* Construct a list containing the name of all global variables used in the
* project. \param project The project to be scanned \return A std::set
* containing the names of all global variables used
* project.
*
* \param project The project to be scanned
* \return A std::set containing the names of all global variables used
*/
static std::set<gd::String> FindAllGlobalVariables(
const gd::Platform& platform, const gd::Project& project);
/**
* Construct a list containing the name of all layout variables used in the
* layout. \param project The project \param layout The layout to be scanned
* \return A std::set containing the names of all layout variables used
* layout.
*
* \param project The project
* \param layout The layout to be scanned
* \return A std::set containing the names of all layout variables used.
*/
static std::set<gd::String> FindAllLayoutVariables(
const gd::Platform& platform,
@@ -49,9 +54,12 @@ class EventsVariablesFinder {
/**
* Construct a list containing the name of all object variables used in the
* layout. \param project The project \param layout The layout to use. \param
* object The object to be scanned \return A std::set containing the names of
* all object variables used
* layout.
*
* \param project The project
* \param layout The layout to use.
* \param object The object to be scanned
* \return A std::set containing the names of all object variables used.
*/
static std::set<gd::String> FindAllObjectVariables(
const gd::Platform& platform,
@@ -62,12 +70,15 @@ class EventsVariablesFinder {
private:
/**
* Construct a list of the value of the arguments for parameters of type @
* parameterType \param project The project used \param project The layout
* used \param instructions The instructions to be analyzed \param
* instructionsAreConditions True if the instructions are conditions. \param
* parameterType The parameters type to be analyzed \param objectName If not
* empty, parameters will be taken into account only if the last object
* parameter is filled with this value.
* parameterType
*
* \param project The project used
* \param project The layout used
* \param instructions The instructions to be analyzed
* \param instructionsAreConditions True if the instructions are conditions.
* \param parameterType The parameters type to be analyzed
* \param objectName If not empty, parameters will be taken into account only
* if the last object parameter is filled with this value.
*
* \return A std::set filled with the values used for all parameters of the
* specified type
@@ -83,10 +94,14 @@ class EventsVariablesFinder {
/**
* Construct a list of the value of the arguments for parameters of type @
* parameterType \param project The project used \param project The layout
* used \param events The events to be analyzed \param parameterType The
* parameters type to be analyzed \param objectName If not empty, parameters
* will be taken into account only if the last object parameter is filled with
* parameterType
*
* \param project The project used
* \param project The layout used
* \param events The events to be analyzed
* \param parameterType The parameters type to be analyzed
* \param objectName If not empty, parameters will be taken into account
* only if the last object parameter is filled with
* this value.
*
* \return A std::set filled with the values used for all parameters of the

View File

@@ -0,0 +1,106 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONVALIDATOR_H
#define GDCORE_EXPRESSIONVALIDATOR_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 Validate that an expression is properly written by returning
* any error attached to the nodes during parsing.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
public:
ExpressionValidator(){};
virtual ~ExpressionValidator(){};
/**
* \brief Helper function to check if a given node does not contain
* any error.
*/
static bool HasNoErrors(gd::ExpressionNode& node) {
gd::ExpressionValidator validator;
node.Visit(validator);
return validator.GetErrors().empty();
}
/**
* \brief Get all the errors
*
* No errors means that the expression is valid.
*/
const std::vector<ExpressionParserDiagnostic*>& GetErrors() {
return errors;
};
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
ReportAnyError(node);
node.expression->Visit(*this);
}
void OnVisitOperatorNode(OperatorNode& node) override {
node.leftHandSide->Visit(*this);
ReportAnyError(node);
node.rightHandSide->Visit(*this);
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
ReportAnyError(node);
node.factor->Visit(*this);
}
void OnVisitNumberNode(NumberNode& node) override { ReportAnyError(node); }
void OnVisitTextNode(TextNode& node) override { ReportAnyError(node); }
void OnVisitVariableNode(VariableNode& node) override {
ReportAnyError(node);
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
ReportAnyError(node);
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
ReportAnyError(node);
node.expression->Visit(*this);
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
ReportAnyError(node);
}
void OnVisitFunctionNode(FunctionNode& node) override {
ReportAnyError(node);
for (auto& parameter : node.parameters) {
parameter->Visit(*this);
}
}
void OnVisitEmptyNode(EmptyNode& node) override { ReportAnyError(node); }
private:
void ReportAnyError(ExpressionNode& node) {
if (node.diagnostic && node.diagnostic->IsError()) {
errors.push_back(node.diagnostic.get());
}
}
std::vector<ExpressionParserDiagnostic*> errors;
};
} // namespace gd
#endif // GDCORE_EXPRESSIONVALIDATOR_H

View File

@@ -19,6 +19,8 @@ class Layout;
namespace gd {
// TODO: Replace and remove (ExpressionValidator)
/**
* \brief Parser callbacks used to check expressions correctness
*

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