mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
464 Commits
refactor/s
...
feature/vi
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cba3a4e87a | ||
![]() |
15dc2fcdd0 | ||
![]() |
b21fdc1ac2 | ||
![]() |
ad4c53898a | ||
![]() |
7a0745a977 | ||
![]() |
69b3c23f1d | ||
![]() |
5f52b6d7e3 | ||
![]() |
dfdbd5c5a0 | ||
![]() |
958f89fb49 | ||
![]() |
661d329170 | ||
![]() |
66ce941d46 | ||
![]() |
d4023efe0f | ||
![]() |
815bd92469 | ||
![]() |
8685defaa8 | ||
![]() |
ad89af6ad5 | ||
![]() |
0428417295 | ||
![]() |
54c0424785 | ||
![]() |
f316d28fe3 | ||
![]() |
104b6c2800 | ||
![]() |
0ac504c0ab | ||
![]() |
0508da60e5 | ||
![]() |
2e511c75bf | ||
![]() |
b76df0247d | ||
![]() |
816fb242be | ||
![]() |
a4b452b037 | ||
![]() |
0d5fbdabc9 | ||
![]() |
268beb256a | ||
![]() |
e33e61d2fd | ||
![]() |
07d770148f | ||
![]() |
2a5b5ee4a2 | ||
![]() |
0420ad8888 | ||
![]() |
0e69a87eec | ||
![]() |
9b178bc985 | ||
![]() |
85cfb644c3 | ||
![]() |
2ba2b3b509 | ||
![]() |
a23a8904f6 | ||
![]() |
1311a8b4c5 | ||
![]() |
e8a1af0ef1 | ||
![]() |
bc1095759e | ||
![]() |
125e76bd20 | ||
![]() |
758afea620 | ||
![]() |
cf63960282 | ||
![]() |
deffe37013 | ||
![]() |
0f30c2d614 | ||
![]() |
9d015b9cd1 | ||
![]() |
fc5905b7f4 | ||
![]() |
18be9f5450 | ||
![]() |
31c8d04def | ||
![]() |
77eff757cd | ||
![]() |
c2fedf23b9 | ||
![]() |
6870a53aed | ||
![]() |
92015e8182 | ||
![]() |
2704c654d8 | ||
![]() |
e1242e5397 | ||
![]() |
51d306f98f | ||
![]() |
689904bda5 | ||
![]() |
5b53ffe015 | ||
![]() |
eb2da55504 | ||
![]() |
38cd264bf8 | ||
![]() |
c179730dc4 | ||
![]() |
8109621920 | ||
![]() |
bd0aaa73c7 | ||
![]() |
6d21753288 | ||
![]() |
6993a2f2f9 | ||
![]() |
8e538425c4 | ||
![]() |
3e7e45da41 | ||
![]() |
15eec269c3 | ||
![]() |
91072f7328 | ||
![]() |
39334c6e55 | ||
![]() |
5f1a7bd72d | ||
![]() |
9ed2665542 | ||
![]() |
ee338f6657 | ||
![]() |
8f876c51dc | ||
![]() |
23a409b80d | ||
![]() |
4e0f9ebec4 | ||
![]() |
2ca593ba2b | ||
![]() |
c63bb625e5 | ||
![]() |
c57e172299 | ||
![]() |
a9cdeae475 | ||
![]() |
931b945b21 | ||
![]() |
e2f21b8d3c | ||
![]() |
6ab2cb1384 | ||
![]() |
f8e0288a44 | ||
![]() |
ff48589661 | ||
![]() |
50bdca3c44 | ||
![]() |
00eda8ced8 | ||
![]() |
7ca5ef6e6c | ||
![]() |
ff8f7e5877 | ||
![]() |
c8739e3c24 | ||
![]() |
69eacedc2b | ||
![]() |
e5f229e3f7 | ||
![]() |
74e43f2b43 | ||
![]() |
a04f641415 | ||
![]() |
2e5a9e2cfa | ||
![]() |
cd4bfd767a | ||
![]() |
d9135636fe | ||
![]() |
88e08ab7d8 | ||
![]() |
6a3af0d57a | ||
![]() |
95b4091085 | ||
![]() |
5556766059 | ||
![]() |
1332582a03 | ||
![]() |
77177063d8 | ||
![]() |
ed7ddd2b67 | ||
![]() |
990f59d093 | ||
![]() |
6326c185f4 | ||
![]() |
9c6972ec0a | ||
![]() |
814577edff | ||
![]() |
a8ea4b8fe7 | ||
![]() |
494666e690 | ||
![]() |
e5a24e3e32 | ||
![]() |
68771be104 | ||
![]() |
9d2bff9442 | ||
![]() |
6a08fb9a86 | ||
![]() |
c96c3ff1a2 | ||
![]() |
788d557f0e | ||
![]() |
4f17d526ab | ||
![]() |
bc27364bb8 | ||
![]() |
1fd719fb41 | ||
![]() |
f7e93c2a13 | ||
![]() |
c268b19264 | ||
![]() |
6baef705eb | ||
![]() |
fe8295a6e3 | ||
![]() |
de616de3fc | ||
![]() |
9e725c58b5 | ||
![]() |
37028de2f4 | ||
![]() |
509dd8ff10 | ||
![]() |
4c38bcffa8 | ||
![]() |
90c2cc7e44 | ||
![]() |
bd6e4206a2 | ||
![]() |
9cf5755a90 | ||
![]() |
11c29f444e | ||
![]() |
11475b9cf3 | ||
![]() |
e5476f5712 | ||
![]() |
e7457c7564 | ||
![]() |
fd015f9ee4 | ||
![]() |
394eb9488c | ||
![]() |
dd771ea3d1 | ||
![]() |
140c7f52cb | ||
![]() |
cb14f7cfa5 | ||
![]() |
93e8dd4002 | ||
![]() |
b91a2da81c | ||
![]() |
d6f99c5841 | ||
![]() |
d2dc352c2a | ||
![]() |
f3dc69ea68 | ||
![]() |
f4522291fc | ||
![]() |
60d7901054 | ||
![]() |
b19e71fe85 | ||
![]() |
2b9524651f | ||
![]() |
680aa3fa6b | ||
![]() |
25f8bddfcf | ||
![]() |
a02e5952a3 | ||
![]() |
b382b99ece | ||
![]() |
f6b16da334 | ||
![]() |
130912f3c8 | ||
![]() |
49418351d4 | ||
![]() |
cbad5de106 | ||
![]() |
1e33a1c6f0 | ||
![]() |
997c251a07 | ||
![]() |
a14e854f4e | ||
![]() |
b0af6c88fe | ||
![]() |
08b1f3b5fe | ||
![]() |
b392192def | ||
![]() |
1759e85b84 | ||
![]() |
a3d223ae39 | ||
![]() |
d2fa8c43cf | ||
![]() |
dc0dcb673f | ||
![]() |
fa2c1bed79 | ||
![]() |
8489cc3e70 | ||
![]() |
0150e197b0 | ||
![]() |
f5a6ca0246 | ||
![]() |
a53b63680c | ||
![]() |
2489a26a08 | ||
![]() |
2346e41936 | ||
![]() |
0b5980d0b6 | ||
![]() |
99fc0b7b46 | ||
![]() |
fb45454951 | ||
![]() |
9abfa741ce | ||
![]() |
980081516a | ||
![]() |
f1bed6ead9 | ||
![]() |
e139c0218b | ||
![]() |
ffd0cf8808 | ||
![]() |
ae87d3298e | ||
![]() |
6b7a9dd39c | ||
![]() |
5a3686d6a3 | ||
![]() |
bfef000cc6 | ||
![]() |
c000a735bb | ||
![]() |
21e034863e | ||
![]() |
72b883654b | ||
![]() |
b1152b9059 | ||
![]() |
7d48b85d42 | ||
![]() |
fb8926dd66 | ||
![]() |
9ce195e371 | ||
![]() |
f88f8b60d6 | ||
![]() |
4eb8ddfba6 | ||
![]() |
aaab3cb212 | ||
![]() |
6b3ce705aa | ||
![]() |
988a7fdb9d | ||
![]() |
11592b11c4 | ||
![]() |
e8791fcdf9 | ||
![]() |
e661923fd3 | ||
![]() |
61c57059fa | ||
![]() |
922019eef0 | ||
![]() |
79ca28fbdb | ||
![]() |
124079c50f | ||
![]() |
2e42fc01be | ||
![]() |
770aad5672 | ||
![]() |
bef1b9fb1e | ||
![]() |
831dce0f51 | ||
![]() |
2da4e79d06 | ||
![]() |
804a07c56e | ||
![]() |
b367f13116 | ||
![]() |
581d7716f7 | ||
![]() |
19de7aefbc | ||
![]() |
57759aa1b8 | ||
![]() |
07876afc28 | ||
![]() |
b9029fba4d | ||
![]() |
c4ba357296 | ||
![]() |
a47acbb82a | ||
![]() |
f1f93c9be0 | ||
![]() |
f56d864efb | ||
![]() |
017f8cf554 | ||
![]() |
d8546c5547 | ||
![]() |
0bc6e41709 | ||
![]() |
943fac772d | ||
![]() |
327e4cb6a3 | ||
![]() |
277989f329 | ||
![]() |
2bdae4ed14 | ||
![]() |
4bfbd7c78f | ||
![]() |
7b76564dda | ||
![]() |
41a2b87dd0 | ||
![]() |
397781bb98 | ||
![]() |
b4fa741717 | ||
![]() |
6e16bd764f | ||
![]() |
1071b66c92 | ||
![]() |
9ff6d91717 | ||
![]() |
bda1eb01d2 | ||
![]() |
dfcaf472c7 | ||
![]() |
c8a9da6aea | ||
![]() |
daa50931ae | ||
![]() |
f84a97a4f2 | ||
![]() |
10d5c403a7 | ||
![]() |
15471e6e28 | ||
![]() |
7ccebc69fa | ||
![]() |
4c57fbc01f | ||
![]() |
ed58ebd3be | ||
![]() |
9cae4fb264 | ||
![]() |
83e7314863 | ||
![]() |
8ec56164af | ||
![]() |
ba0c4a9bc4 | ||
![]() |
8706dc727d | ||
![]() |
7ee9facb34 | ||
![]() |
4190cbda88 | ||
![]() |
aa73b01bbc | ||
![]() |
b242c7863f | ||
![]() |
41550ee10f | ||
![]() |
7af0999f59 | ||
![]() |
93e0ccc163 | ||
![]() |
94303fccc2 | ||
![]() |
33949fd93c | ||
![]() |
bd40bb892c | ||
![]() |
c2cf935bd9 | ||
![]() |
c7d5ab8013 | ||
![]() |
e8c93a5622 | ||
![]() |
348459481a | ||
![]() |
e7348f08c4 | ||
![]() |
ef96adee92 | ||
![]() |
66b3ec1686 | ||
![]() |
b77eb123e8 | ||
![]() |
dcba4272e0 | ||
![]() |
c2dd5a0a09 | ||
![]() |
a6ae265705 | ||
![]() |
94fb2fede6 | ||
![]() |
7bcaf55342 | ||
![]() |
cc9632e7c1 | ||
![]() |
3ff5dd7cd2 | ||
![]() |
1193e1bbd0 | ||
![]() |
9c55b0acc6 | ||
![]() |
d03c1964cb | ||
![]() |
e5695aacf6 | ||
![]() |
8e6d2da9f7 | ||
![]() |
5c043fd04a | ||
![]() |
4edbd9d377 | ||
![]() |
c6f21955a3 | ||
![]() |
03cc406459 | ||
![]() |
c5d855b768 | ||
![]() |
2aba1c57c4 | ||
![]() |
9614549436 | ||
![]() |
f1730c239d | ||
![]() |
acb19bf8ed | ||
![]() |
4d63fbcca0 | ||
![]() |
eb19b6ba21 | ||
![]() |
d2747782b4 | ||
![]() |
8202e6b38e | ||
![]() |
6deb4fa122 | ||
![]() |
3990064da9 | ||
![]() |
a315eabdce | ||
![]() |
faa02d4459 | ||
![]() |
8b294ae369 | ||
![]() |
cb43eb7780 | ||
![]() |
765295fc5d | ||
![]() |
beb3bde4a8 | ||
![]() |
fe5b519917 | ||
![]() |
8661fbef07 | ||
![]() |
afd11d2480 | ||
![]() |
c5ad9715df | ||
![]() |
4362e8dd42 | ||
![]() |
372fa46709 | ||
![]() |
c43cfcd49e | ||
![]() |
c471a0af6d | ||
![]() |
b1ea60e1d2 | ||
![]() |
f745907f9d | ||
![]() |
92df124a92 | ||
![]() |
96f26c89ab | ||
![]() |
3f6428dfcc | ||
![]() |
22c6a57394 | ||
![]() |
dc942e6abc | ||
![]() |
f9430a0da1 | ||
![]() |
94ac7166ed | ||
![]() |
88b20240ff | ||
![]() |
af93149f6a | ||
![]() |
732a716be4 | ||
![]() |
11b660e05d | ||
![]() |
6155606d20 | ||
![]() |
89e3853296 | ||
![]() |
df655f2269 | ||
![]() |
6b6ec6f06f | ||
![]() |
d80a47e569 | ||
![]() |
9cf9d09f3a | ||
![]() |
8fa23c5463 | ||
![]() |
1c65e3c655 | ||
![]() |
b1e292e04e | ||
![]() |
e2f8f70d54 | ||
![]() |
d04faa039b | ||
![]() |
4e59573042 | ||
![]() |
07fce517d6 | ||
![]() |
ac90b982ac | ||
![]() |
4df974a4d7 | ||
![]() |
cebf1e2a84 | ||
![]() |
650676cc6e | ||
![]() |
a3614a85b8 | ||
![]() |
ef52fec3ca | ||
![]() |
ca6f11b55a | ||
![]() |
7015962aa0 | ||
![]() |
4df7f0d10f | ||
![]() |
8c7ffe319a | ||
![]() |
710c2f0304 | ||
![]() |
727fa8a538 | ||
![]() |
f45e4c2049 | ||
![]() |
3bdf612f8e | ||
![]() |
4f7c91190e | ||
![]() |
5ed0c57e48 | ||
![]() |
3955612e3b | ||
![]() |
8eede20b07 | ||
![]() |
3df9b29c3e | ||
![]() |
280906dd3a | ||
![]() |
94e81ddf40 | ||
![]() |
392e602651 | ||
![]() |
0d60a54fa7 | ||
![]() |
e95a336dd2 | ||
![]() |
b8ccf02f70 | ||
![]() |
a564a484a7 | ||
![]() |
b9c1f5f6a7 | ||
![]() |
243bc93fe5 | ||
![]() |
d544319302 | ||
![]() |
0fa5988995 | ||
![]() |
746b2f5480 | ||
![]() |
2cc7c8740e | ||
![]() |
aa30052dca | ||
![]() |
beb1cf0631 | ||
![]() |
78640d74c8 | ||
![]() |
7becb0be4b | ||
![]() |
6c789b7eb0 | ||
![]() |
f743a785ad | ||
![]() |
bac8aa14fa | ||
![]() |
3ebb483e32 | ||
![]() |
4fbbd34d40 | ||
![]() |
24091db88b | ||
![]() |
4ec3f1f082 | ||
![]() |
991378e004 | ||
![]() |
dfaee92d24 | ||
![]() |
b07c71cb9c | ||
![]() |
cb0c0f903f | ||
![]() |
a81a121a8d | ||
![]() |
7bf892c7eb | ||
![]() |
ce4fdbe4f8 | ||
![]() |
d82bbdc1af | ||
![]() |
62dca91637 | ||
![]() |
1e1c5f7206 | ||
![]() |
7c9e6ee6f1 | ||
![]() |
5690de71c5 | ||
![]() |
eae2a06a4e | ||
![]() |
4affa25672 | ||
![]() |
7b30f63cb1 | ||
![]() |
574bdaaf41 | ||
![]() |
bff43ee771 | ||
![]() |
9b9b6c5996 | ||
![]() |
721872e45b | ||
![]() |
edd9ec94cf | ||
![]() |
c986c52409 | ||
![]() |
168b8d3fea | ||
![]() |
47025329dd | ||
![]() |
9f05a65ed2 | ||
![]() |
370c6d03ad | ||
![]() |
b650ff3aa5 | ||
![]() |
285ff6f5f5 | ||
![]() |
81f292941f | ||
![]() |
eb27ba7c86 | ||
![]() |
01a844c356 | ||
![]() |
054e48227c | ||
![]() |
9adc40a55d | ||
![]() |
034c734568 | ||
![]() |
b65aed4c02 | ||
![]() |
adbcef8f59 | ||
![]() |
44dbbd7138 | ||
![]() |
3e63e34d61 | ||
![]() |
dc976003b7 | ||
![]() |
fb3002cd77 | ||
![]() |
b25752907f | ||
![]() |
72da63afcb | ||
![]() |
ab5a593ab3 | ||
![]() |
71dcb20b7b | ||
![]() |
61ffb40dee | ||
![]() |
07152639d1 | ||
![]() |
6655a949ec | ||
![]() |
99312c71e0 | ||
![]() |
3abb5a393d | ||
![]() |
010b52ced6 | ||
![]() |
7a1ce790d4 | ||
![]() |
fbdf530e00 | ||
![]() |
ee1e67a367 | ||
![]() |
5eded536b8 | ||
![]() |
fa511d5faa | ||
![]() |
a0887a1982 | ||
![]() |
975a5a44cc | ||
![]() |
252315d0d1 | ||
![]() |
cbd7a70059 | ||
![]() |
d9a8f79926 | ||
![]() |
a417e3c9db | ||
![]() |
7530b4e137 | ||
![]() |
e0adc2a924 | ||
![]() |
a4227dac78 | ||
![]() |
4e76f28fd3 | ||
![]() |
3b89284fd2 | ||
![]() |
dd8a0c7158 | ||
![]() |
641d87b097 | ||
![]() |
64dbab1bce | ||
![]() |
dc4e68dd21 | ||
![]() |
9d3cd9f110 | ||
![]() |
eb5687dc7b | ||
![]() |
9eb548452a | ||
![]() |
4ac3516336 | ||
![]() |
e3aed61390 | ||
![]() |
479584c3ef | ||
![]() |
3fc3d1e235 | ||
![]() |
448e543658 | ||
![]() |
eb1abbd539 | ||
![]() |
48420c6b79 | ||
![]() |
a6d7c032ac | ||
![]() |
2f8840b2cf | ||
![]() |
5df3afdb67 | ||
![]() |
df2185a505 | ||
![]() |
1d67453454 | ||
![]() |
217cd9639f | ||
![]() |
9f91654628 |
@@ -19,7 +19,7 @@ jobs:
|
||||
|
||||
- run:
|
||||
name: Install Emscripten (for GDevelop.js)
|
||||
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install sdk-fastcomp-1.37.37-64bit && ./emsdk activate sdk-fastcomp-1.37.37-64bit && cd ..
|
||||
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
|
||||
|
||||
- run:
|
||||
name: Install Wine for Electron builder
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
# Build GDevelop IDE
|
||||
- run:
|
||||
name: Build GDevelop IDE
|
||||
command: cd newIDE/electron-app && npm run build -- --mac --win --linux tar.gz --publish=never
|
||||
command: cd newIDE/electron-app && npm run build -- --mac zip --win --linux tar.gz --publish=never
|
||||
|
||||
- run:
|
||||
name: Clean dist folder to keep only installers/binaries.
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -44,9 +44,6 @@
|
||||
/Binaries/**/JsPlatform/*.dll.a
|
||||
/Binaries/Output/Release_Windows/newIDE
|
||||
*.autosave
|
||||
/Binaries/Output/libGD.js/Release
|
||||
/Binaries/Output/libGD.js/Debug
|
||||
/Binaries/Output/libGD.js/libGD.raw.js
|
||||
!/GDCpp/scripts/bcp.exe
|
||||
!/scripts/libgettextlib-0-17.dll
|
||||
!/scripts/libgettextsrc-0-17.dll
|
||||
|
@@ -24,7 +24,7 @@ addons:
|
||||
- /$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)/commit/$(git rev-parse HEAD)
|
||||
- /$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)/latest
|
||||
paths:
|
||||
- Binaries/Output/libGD.js/Release
|
||||
- Binaries/embuild/GDevelop.js
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
@@ -63,8 +63,8 @@ install:
|
||||
# Install Emscripten (for GDevelop.js)
|
||||
- git clone https://github.com/juj/emsdk.git
|
||||
- cd emsdk
|
||||
- ./emsdk install sdk-fastcomp-1.37.37-64bit
|
||||
- ./emsdk activate sdk-fastcomp-1.37.37-64bit
|
||||
- ./emsdk install 1.39.6
|
||||
- ./emsdk activate 1.39.6
|
||||
- source ./emsdk_env.sh
|
||||
- cd ..
|
||||
# Install GDevelop.js dependencies and compile it
|
||||
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -83,7 +83,9 @@
|
||||
"__threading_support": "cpp",
|
||||
"any": "cpp",
|
||||
"array": "cpp",
|
||||
"cinttypes": "cpp"
|
||||
"cinttypes": "cpp",
|
||||
"numeric": "cpp",
|
||||
"__memory": "cpp"
|
||||
},
|
||||
"files.exclude": {
|
||||
"Binaries/*build*": true,
|
||||
|
@@ -75,6 +75,11 @@ else()
|
||||
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support (with GNU extensions). Please use a different C++ compiler.")
|
||||
endif()
|
||||
|
||||
# Mark some warnings as errors
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-stack-address")
|
||||
endif()
|
||||
|
||||
#Define common directories:
|
||||
set(GD_base_dir ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
|
@@ -51,7 +51,12 @@ file(GLOB_RECURSE formatted_source_files tests/* GDCore/Events/* GDCore/Extensio
|
||||
list(REMOVE_ITEM formatted_source_files "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs.h" "${CMAKE_CURRENT_SOURCE_DIR}/GDCore/IDE/Dialogs/GDCoreDialogs_dialogs_bitmaps.cpp")
|
||||
gd_add_clang_utils(GDCore "${formatted_source_files}")
|
||||
|
||||
add_library(GDCore SHARED ${source_files})
|
||||
IF(EMSCRIPTEN)
|
||||
# Emscripten treats all libraries as static libraries
|
||||
add_library(GDCore STATIC ${source_files})
|
||||
ELSE()
|
||||
add_library(GDCore SHARED ${source_files})
|
||||
ENDIF()
|
||||
add_dependencies(GDCore GDVersion)
|
||||
IF(EMSCRIPTEN)
|
||||
set_target_properties(GDCore PROPERTIES SUFFIX ".bc")
|
||||
|
@@ -12,6 +12,15 @@ using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
vector<gd::String> CommentEvent::GetAllSearchableStrings() const {
|
||||
vector<gd::String> allSearchableStrings;
|
||||
|
||||
allSearchableStrings.push_back(com1);
|
||||
allSearchableStrings.push_back(com2); ///< Com2 is deprecated
|
||||
|
||||
return allSearchableStrings;
|
||||
}
|
||||
|
||||
void CommentEvent::SerializeTo(SerializerElement &element) const {
|
||||
element.AddChild("color")
|
||||
.SetAttribute("r", r)
|
||||
|
@@ -7,10 +7,11 @@
|
||||
#define COMMENTEVENT_H
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
namespace gd {
|
||||
class Layout;
|
||||
class Project;
|
||||
}
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -45,6 +46,8 @@ class GD_CORE_API CommentEvent : public gd::BaseEvent {
|
||||
const gd::String& GetComment() const { return com1; }
|
||||
void SetComment(const gd::String& comment) { com1 = comment; }
|
||||
|
||||
virtual std::vector<gd::String> GetAllSearchableStrings() const;
|
||||
|
||||
virtual void SerializeTo(SerializerElement& element) const;
|
||||
virtual void UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element);
|
||||
|
@@ -5,10 +5,6 @@
|
||||
*/
|
||||
|
||||
#include "ForEachEvent.h"
|
||||
#include <iostream>
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
@@ -35,12 +31,17 @@ vector<gd::InstructionsList*> ForEachEvent::GetAllActionsVectors() {
|
||||
return allActions;
|
||||
}
|
||||
|
||||
vector<gd::Expression*> ForEachEvent::GetAllExpressions() {
|
||||
vector<gd::Expression*> allExpressions;
|
||||
allExpressions.push_back(&objectsToPick);
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
ForEachEvent::GetAllExpressionsWithMetadata() {
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
allExpressionsWithMetadata;
|
||||
auto metadata = gd::ParameterMetadata().SetType("object");
|
||||
allExpressionsWithMetadata.push_back(
|
||||
std::make_pair(&objectsToPick, metadata));
|
||||
|
||||
return allExpressions;
|
||||
return allExpressionsWithMetadata;
|
||||
}
|
||||
|
||||
vector<const gd::InstructionsList*> ForEachEvent::GetAllConditionsVectors()
|
||||
const {
|
||||
vector<const gd::InstructionsList*> allConditions;
|
||||
@@ -56,11 +57,15 @@ vector<const gd::InstructionsList*> ForEachEvent::GetAllActionsVectors() const {
|
||||
return allActions;
|
||||
}
|
||||
|
||||
vector<const gd::Expression*> ForEachEvent::GetAllExpressions() const {
|
||||
vector<const gd::Expression*> allExpressions;
|
||||
allExpressions.push_back(&objectsToPick);
|
||||
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
ForEachEvent::GetAllExpressionsWithMetadata() const {
|
||||
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
allExpressionsWithMetadata;
|
||||
auto metadata = gd::ParameterMetadata().SetType("object");
|
||||
allExpressionsWithMetadata.push_back(
|
||||
std::make_pair(&objectsToPick, metadata));
|
||||
|
||||
return allExpressions;
|
||||
return allExpressionsWithMetadata;
|
||||
}
|
||||
|
||||
void ForEachEvent::SerializeTo(SerializerElement& element) const {
|
||||
|
@@ -50,10 +50,13 @@ class GD_CORE_API ForEachEvent : public gd::BaseEvent {
|
||||
virtual std::vector<const gd::InstructionsList*> GetAllConditionsVectors()
|
||||
const;
|
||||
virtual std::vector<const gd::InstructionsList*> GetAllActionsVectors() const;
|
||||
virtual std::vector<const gd::Expression*> GetAllExpressions() const;
|
||||
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
GetAllExpressionsWithMetadata() const;
|
||||
|
||||
virtual std::vector<gd::InstructionsList*> GetAllConditionsVectors();
|
||||
virtual std::vector<gd::InstructionsList*> GetAllActionsVectors();
|
||||
virtual std::vector<gd::Expression*> GetAllExpressions();
|
||||
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
GetAllExpressionsWithMetadata();
|
||||
|
||||
virtual void SerializeTo(SerializerElement& element) const;
|
||||
virtual void UnserializeFrom(gd::Project& project,
|
||||
|
@@ -19,6 +19,14 @@ namespace gd {
|
||||
GroupEvent::GroupEvent()
|
||||
: BaseEvent(), creationTime(0), colorR(74), colorG(176), colorB(228) {}
|
||||
|
||||
vector<gd::String> GroupEvent::GetAllSearchableStrings() const {
|
||||
vector<gd::String> allSearchableStrings;
|
||||
|
||||
allSearchableStrings.push_back(name);
|
||||
|
||||
return allSearchableStrings;
|
||||
}
|
||||
|
||||
void GroupEvent::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", name);
|
||||
element.SetAttribute("source", source);
|
||||
|
@@ -106,6 +106,8 @@ class GD_CORE_API GroupEvent : public gd::BaseEvent {
|
||||
virtual const gd::EventsList& GetSubEvents() const { return events; };
|
||||
virtual gd::EventsList& GetSubEvents() { return events; };
|
||||
|
||||
virtual std::vector<gd::String> GetAllSearchableStrings() const;
|
||||
|
||||
virtual void SerializeTo(SerializerElement& element) const;
|
||||
virtual void UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element);
|
||||
|
@@ -5,9 +5,6 @@
|
||||
*/
|
||||
|
||||
#include "RepeatEvent.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
@@ -34,11 +31,15 @@ vector<gd::InstructionsList*> RepeatEvent::GetAllActionsVectors() {
|
||||
return allActions;
|
||||
}
|
||||
|
||||
vector<gd::Expression*> RepeatEvent::GetAllExpressions() {
|
||||
vector<gd::Expression*> allExpressions;
|
||||
allExpressions.push_back(&repeatNumberExpression);
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
RepeatEvent::GetAllExpressionsWithMetadata() {
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
allExpressionsWithMetadata;
|
||||
auto metadata = gd::ParameterMetadata().SetType("expression");
|
||||
allExpressionsWithMetadata.push_back(
|
||||
std::make_pair(&repeatNumberExpression, metadata));
|
||||
|
||||
return allExpressions;
|
||||
return allExpressionsWithMetadata;
|
||||
}
|
||||
|
||||
vector<const gd::InstructionsList*> RepeatEvent::GetAllConditionsVectors()
|
||||
@@ -56,11 +57,15 @@ vector<const gd::InstructionsList*> RepeatEvent::GetAllActionsVectors() const {
|
||||
return allActions;
|
||||
}
|
||||
|
||||
vector<const gd::Expression*> RepeatEvent::GetAllExpressions() const {
|
||||
vector<const gd::Expression*> allExpressions;
|
||||
allExpressions.push_back(&repeatNumberExpression);
|
||||
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
RepeatEvent::GetAllExpressionsWithMetadata() const {
|
||||
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
allExpressionsWithMetadata;
|
||||
auto metadata = gd::ParameterMetadata().SetType("expression");
|
||||
allExpressionsWithMetadata.push_back(
|
||||
std::make_pair(&repeatNumberExpression, metadata));
|
||||
|
||||
return allExpressions;
|
||||
return allExpressionsWithMetadata;
|
||||
}
|
||||
|
||||
void RepeatEvent::SerializeTo(SerializerElement& element) const {
|
||||
|
@@ -45,11 +45,14 @@ class GD_CORE_API RepeatEvent : public gd::BaseEvent {
|
||||
|
||||
virtual std::vector<gd::InstructionsList*> GetAllConditionsVectors();
|
||||
virtual std::vector<gd::InstructionsList*> GetAllActionsVectors();
|
||||
virtual std::vector<gd::Expression*> GetAllExpressions();
|
||||
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
GetAllExpressionsWithMetadata();
|
||||
|
||||
virtual std::vector<const gd::InstructionsList*> GetAllConditionsVectors()
|
||||
const;
|
||||
virtual std::vector<const gd::InstructionsList*> GetAllActionsVectors() const;
|
||||
virtual std::vector<const gd::Expression*> GetAllExpressions() const;
|
||||
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
GetAllExpressionsWithMetadata() const;
|
||||
|
||||
virtual void SerializeTo(SerializerElement& element) const;
|
||||
virtual void UnserializeFrom(gd::Project& project,
|
||||
|
@@ -6,9 +6,6 @@
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "WhileEvent.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
|
@@ -1,11 +1,11 @@
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
||||
#include "GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h"
|
||||
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser.h"
|
||||
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
@@ -630,7 +630,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
|
||||
argOutput = "\"" + argOutput + "\"";
|
||||
} else if (ParameterMetadata::IsBehavior(metadata.type)) {
|
||||
argOutput = "\"" + ConvertToString(parameter) + "\"";
|
||||
argOutput = GenerateGetBehaviorNameCode(parameter);
|
||||
} else if (metadata.type == "key") {
|
||||
argOutput = "\"" + ConvertToString(parameter) + "\"";
|
||||
} else if (metadata.type == "password" || metadata.type == "musicfile" ||
|
||||
@@ -662,7 +662,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
if (argOutput.empty()) {
|
||||
if (!metadata.type.empty())
|
||||
cout << "Warning: Unknown type of parameter \"" << metadata.type
|
||||
<< "\".";
|
||||
<< "\"." << std::endl;
|
||||
argOutput += "\"" + ConvertToString(parameter) + "\"";
|
||||
}
|
||||
}
|
||||
@@ -1111,6 +1111,33 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
|
||||
}
|
||||
}
|
||||
|
||||
size_t EventsCodeGenerator::GenerateSingleUsageUniqueIdForEventsList() {
|
||||
return eventsListNextUniqueId++;
|
||||
}
|
||||
|
||||
size_t EventsCodeGenerator::GenerateSingleUsageUniqueIdFor(
|
||||
const Instruction* instruction) {
|
||||
if (!instruction) {
|
||||
std::cout << "ERROR: During code generation, a null pointer was passed to "
|
||||
"GenerateSingleUsageUniqueIdFor."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// Base the unique id on the adress in memory so that the same instruction
|
||||
// in memory will get the same id across different code generations.
|
||||
size_t uniqueId = (size_t)instruction;
|
||||
|
||||
// While in most case this function is called a single time for each instruction,
|
||||
// it's possible for an instruction to be appearing more than once in the events,
|
||||
// if we used links. In this case, simply increment the unique id to be sure that
|
||||
// ids are effectively uniques, and stay stable (given the same order of links).
|
||||
while (instructionUniqueIds.find(uniqueId) != instructionUniqueIds.end()) {
|
||||
uniqueId++;
|
||||
}
|
||||
instructionUniqueIds.insert(uniqueId);
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GetObjectListName(
|
||||
const gd::String& name, const gd::EventsCodeGenerationContext& context) {
|
||||
return ManObjListName(name);
|
||||
@@ -1139,7 +1166,8 @@ EventsCodeGenerator::EventsCodeGenerator(gd::Project& project_,
|
||||
errorOccurred(false),
|
||||
compilationForRuntime(false),
|
||||
maxCustomConditionsDepth(0),
|
||||
maxConditionsListsSize(0){};
|
||||
maxConditionsListsSize(0),
|
||||
eventsListNextUniqueId(0){};
|
||||
|
||||
EventsCodeGenerator::EventsCodeGenerator(
|
||||
const gd::Platform& platform_,
|
||||
@@ -1154,6 +1182,7 @@ EventsCodeGenerator::EventsCodeGenerator(
|
||||
errorOccurred(false),
|
||||
compilationForRuntime(false),
|
||||
maxCustomConditionsDepth(0),
|
||||
maxConditionsListsSize(0){};
|
||||
maxConditionsListsSize(0),
|
||||
eventsListNextUniqueId(0){};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -35,10 +36,6 @@ namespace gd {
|
||||
* \brief Internal class used to generate code from events
|
||||
*/
|
||||
class GD_CORE_API EventsCodeGenerator {
|
||||
// Compatiblity with old ExpressionParser
|
||||
friend class CallbacksForGeneratingExpressionCode;
|
||||
friend class VariableCodeGenerationCallbacks;
|
||||
// end of compatibility code
|
||||
friend class ExpressionCodeGenerator;
|
||||
|
||||
public:
|
||||
@@ -127,7 +124,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
*
|
||||
*/
|
||||
std::vector<gd::String> GenerateParametersCodes(
|
||||
const std::vector<gd::Expression> & parameters,
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const std::vector<gd::ParameterMetadata>& parametersInfo,
|
||||
EventsCodeGenerationContext& context,
|
||||
std::vector<std::pair<gd::String, gd::String> >*
|
||||
@@ -415,6 +412,29 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
|
||||
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE };
|
||||
|
||||
/**
|
||||
* Generate a single unique number for the specified instruction.
|
||||
*
|
||||
* This is useful for instructions that need to identify themselves in the
|
||||
* generated code like the "Trigger Once" conditions. The id is stable across
|
||||
* code generations if the instructions are the same objects in memory.
|
||||
*
|
||||
* Note that if this function is called multiple times with the same
|
||||
* instruction, the unique number returned will be *different*. This is
|
||||
* because a single instruction might appear at multiple places in events due
|
||||
* to the usage of links.
|
||||
*/
|
||||
size_t GenerateSingleUsageUniqueIdFor(const gd::Instruction* instruction);
|
||||
|
||||
/**
|
||||
* Generate a single unique number for an events list.
|
||||
*
|
||||
* This is useful to create unique function names for events list, that are
|
||||
* stable across code generation given the exact same list of events. They are
|
||||
* *not* stable if events are moved/reorganized.
|
||||
*/
|
||||
size_t GenerateSingleUsageUniqueIdForEventsList();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Generate the code for a single parameter.
|
||||
@@ -708,7 +728,8 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
/**
|
||||
* Generate the getter to get the name of the specified behavior.
|
||||
*/
|
||||
virtual gd::String GenerateGetBehaviorNameCode(const gd::String& behaviorName);
|
||||
virtual gd::String GenerateGetBehaviorNameCode(
|
||||
const gd::String& behaviorName);
|
||||
|
||||
const gd::Platform& platform; ///< The platform being used.
|
||||
|
||||
@@ -736,6 +757,11 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
size_t maxCustomConditionsDepth; ///< The maximum depth value for all the
|
||||
///< custom conditions created.
|
||||
size_t maxConditionsListsSize; ///< The maximum size of a list of conditions.
|
||||
|
||||
std::set<size_t>
|
||||
instructionUniqueIds; ///< The unique ids generated for instructions.
|
||||
size_t eventsListNextUniqueId; ///< The next identifier to use for an events
|
||||
///< list function name.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -24,117 +24,14 @@
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
|
||||
// Compatibility with old ExpressionParser
|
||||
#include "GDCore/Events/CodeGeneration/ExpressionsCodeGeneration.h"
|
||||
#include "GDCore/Events/CodeGeneration/VariableParserCallbacks.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser.h"
|
||||
#include "GDCore/Events/Parsers/VariableParser.h"
|
||||
// end of compatibility code
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool ExpressionCodeGenerator::useOldExpressionParser = false;
|
||||
|
||||
gd::String ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
EventsCodeGenerator& codeGenerator,
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& type,
|
||||
const gd::String& expression,
|
||||
const gd::String& objectName) {
|
||||
// Compatibility with old ExpressionParser
|
||||
if (useOldExpressionParser) {
|
||||
if (type == "number") {
|
||||
gd::String code = "";
|
||||
gd::CallbacksForGeneratingExpressionCode callbacks(
|
||||
code, codeGenerator, context);
|
||||
gd::ExpressionParser parser(expression);
|
||||
if (!parser.ParseMathExpression(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
callbacks) ||
|
||||
code.empty()) {
|
||||
std::cout << "Error (old ExpressionParser): \""
|
||||
<< parser.GetFirstError() << "\" in: \"" << expression
|
||||
<< "\" (number)" << std::endl;
|
||||
code = "0";
|
||||
}
|
||||
|
||||
return code;
|
||||
} else if (type == "string") {
|
||||
gd::String code = "";
|
||||
gd::CallbacksForGeneratingExpressionCode callbacks(
|
||||
code, codeGenerator, context);
|
||||
gd::ExpressionParser parser(expression);
|
||||
if (!parser.ParseStringExpression(
|
||||
codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
callbacks) ||
|
||||
code.empty()) {
|
||||
std::cout << "Error (old ExpressionParser): \""
|
||||
<< parser.GetFirstError() << "\" in: \"" << expression
|
||||
<< "\" (string)" << std::endl;
|
||||
code = "\"\"";
|
||||
}
|
||||
|
||||
return code;
|
||||
} else if (type == "scenevar") {
|
||||
gd::String code = "";
|
||||
gd::VariableCodeGenerationCallbacks callbacks(
|
||||
code,
|
||||
codeGenerator,
|
||||
context,
|
||||
gd::EventsCodeGenerator::LAYOUT_VARIABLE);
|
||||
|
||||
gd::VariableParser parser(expression);
|
||||
if (!parser.Parse(callbacks)) {
|
||||
std::cout << "Error (old VariableParser) :" << parser.GetFirstError()
|
||||
<< " in: " << expression << std::endl;
|
||||
code = codeGenerator.GenerateBadVariable();
|
||||
}
|
||||
return code;
|
||||
} else if (type == "globalvar") {
|
||||
gd::String code = "";
|
||||
gd::VariableCodeGenerationCallbacks callbacks(
|
||||
code,
|
||||
codeGenerator,
|
||||
context,
|
||||
gd::EventsCodeGenerator::PROJECT_VARIABLE);
|
||||
|
||||
gd::VariableParser parser(expression);
|
||||
if (!parser.Parse(callbacks)) {
|
||||
std::cout << "Error (old VariableParser) :" << parser.GetFirstError()
|
||||
<< " in: " << expression << std::endl;
|
||||
code = codeGenerator.GenerateBadVariable();
|
||||
}
|
||||
return code;
|
||||
} else if (type == "objectvar") {
|
||||
gd::String code = "";
|
||||
|
||||
// Object is either the object of the previous parameter or, if it is
|
||||
// empty, the object being picked by the instruction.
|
||||
gd::String object =
|
||||
objectName.empty() ? context.GetCurrentObject() : objectName;
|
||||
|
||||
gd::VariableCodeGenerationCallbacks callbacks(
|
||||
code, codeGenerator, context, object);
|
||||
|
||||
gd::VariableParser parser(expression);
|
||||
if (!parser.Parse(callbacks)) {
|
||||
std::cout << "Error (old VariableParser) :" << parser.GetFirstError()
|
||||
<< " in: " << expression << std::endl;
|
||||
code = codeGenerator.GenerateBadVariable();
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
std::cout << "Type error (old ExpressionParser): type \"" << type
|
||||
<< "\" is not supported" << std::endl;
|
||||
return "/* Error during code generation: type " + type +
|
||||
" is not supported for old ExpressionParser. */ 0";
|
||||
}
|
||||
// end of compatibility code
|
||||
|
||||
gd::ExpressionParser2 parser(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetGlobalObjectsAndGroups(),
|
||||
codeGenerator.GetObjectsAndGroups());
|
||||
@@ -230,7 +127,7 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionCodeGenerator::OnVisitFunctionNode(FunctionNode& node) {
|
||||
void ExpressionCodeGenerator::OnVisitFunctionCallNode(FunctionCallNode& node) {
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(node.expressionMetadata)) {
|
||||
output += "/* Error during generation, function not found: " +
|
||||
codeGenerator.ConvertToString(node.functionName) + " for type " +
|
||||
@@ -462,4 +359,8 @@ void ExpressionCodeGenerator::OnVisitEmptyNode(EmptyNode& node) {
|
||||
output += GenerateDefaultValue(node.type);
|
||||
}
|
||||
|
||||
void ExpressionCodeGenerator::OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) {
|
||||
output += GenerateDefaultValue(node.type);
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -60,11 +60,6 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
|
||||
const gd::String& expression,
|
||||
const gd::String& objectName = "");
|
||||
|
||||
static void UseOldExpressionParser(bool enable) {
|
||||
useOldExpressionParser = enable;
|
||||
};
|
||||
static bool IsUsingOldExpressionParser() { return useOldExpressionParser; };
|
||||
|
||||
const gd::String& GetOutput() { return output; };
|
||||
|
||||
protected:
|
||||
@@ -78,7 +73,8 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override;
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override;
|
||||
void OnVisitFunctionNode(FunctionNode& node) override;
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override;
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override;
|
||||
void OnVisitEmptyNode(EmptyNode& node) override;
|
||||
|
||||
private:
|
||||
@@ -107,11 +103,9 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
|
||||
gd::String output;
|
||||
EventsCodeGenerator& codeGenerator;
|
||||
EventsCodeGenerationContext& context;
|
||||
|
||||
static bool useOldExpressionParser;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_ExpressionCodeGenerator_H
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ExpressionsCodeGeneration.h"
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser.h"
|
||||
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
|
||||
#include "GDCore/Extensions/Metadata/BehaviorMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
CallbacksForGeneratingExpressionCode::CallbacksForGeneratingExpressionCode(
|
||||
gd::String& plainExpression_,
|
||||
EventsCodeGenerator& codeGenerator_,
|
||||
EventsCodeGenerationContext& context_)
|
||||
: plainExpression(plainExpression_),
|
||||
codeGenerator(codeGenerator_),
|
||||
context(context_) {}
|
||||
|
||||
void CallbacksForGeneratingExpressionCode::OnConstantToken(gd::String text) {
|
||||
plainExpression += text;
|
||||
};
|
||||
|
||||
void CallbacksForGeneratingExpressionCode::OnStaticFunction(
|
||||
gd::String functionName,
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const gd::ExpressionMetadata& expressionInfo) {
|
||||
codeGenerator.AddIncludeFiles(
|
||||
expressionInfo.codeExtraInformation.GetIncludeFiles());
|
||||
|
||||
// Launch custom code generator if needed
|
||||
if (expressionInfo.codeExtraInformation.HasCustomCodeGenerator()) {
|
||||
plainExpression += expressionInfo.codeExtraInformation.customCodeGenerator(
|
||||
parameters, codeGenerator, context);
|
||||
return;
|
||||
}
|
||||
|
||||
// Special case: For strings expressions, function without name is a string.
|
||||
if (GetReturnType() == "string" && functionName.empty()) {
|
||||
if (parameters.empty()) return;
|
||||
plainExpression +=
|
||||
codeGenerator.ConvertToStringExplicit(parameters[0].GetPlainString());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare parameters
|
||||
std::vector<gd::String> parametersCode =
|
||||
codeGenerator.GenerateParametersCodes(
|
||||
parameters, expressionInfo.parameters, context);
|
||||
gd::String parametersStr;
|
||||
for (std::size_t i = 0; i < parametersCode.size(); ++i) {
|
||||
if (i != 0) parametersStr += ", ";
|
||||
parametersStr += parametersCode[i];
|
||||
}
|
||||
|
||||
plainExpression += expressionInfo.codeExtraInformation.functionCallName +
|
||||
"(" + parametersStr + ")";
|
||||
};
|
||||
|
||||
void CallbacksForGeneratingExpressionCode::OnObjectFunction(
|
||||
gd::String functionName,
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const gd::ExpressionMetadata& expressionInfo) {
|
||||
const gd::ObjectsContainer& globalObjectsAndGroups = codeGenerator.GetGlobalObjectsAndGroups();
|
||||
const gd::ObjectsContainer& objectsAndGroups = codeGenerator.GetObjectsAndGroups();
|
||||
|
||||
codeGenerator.AddIncludeFiles(
|
||||
expressionInfo.codeExtraInformation.GetIncludeFiles());
|
||||
if (parameters.empty()) return;
|
||||
|
||||
// Launch custom code generator if needed
|
||||
if (expressionInfo.codeExtraInformation.HasCustomCodeGenerator()) {
|
||||
plainExpression += expressionInfo.codeExtraInformation.customCodeGenerator(
|
||||
parameters, codeGenerator, context);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare parameters
|
||||
std::vector<gd::String> parametersCode =
|
||||
codeGenerator.GenerateParametersCodes(
|
||||
parameters, expressionInfo.parameters, context);
|
||||
gd::String parametersStr;
|
||||
for (std::size_t i = 1; i < parametersCode.size(); ++i) {
|
||||
if (i != 1) parametersStr += ", ";
|
||||
parametersStr += parametersCode[i];
|
||||
}
|
||||
|
||||
gd::String output = GetReturnType() == "string" ? "\"\"" : "0";
|
||||
|
||||
// Get object(s) concerned by function call
|
||||
std::vector<gd::String> realObjects =
|
||||
codeGenerator.ExpandObjectsName(parameters[0].GetPlainString(), context);
|
||||
for (std::size_t i = 0; i < realObjects.size(); ++i) {
|
||||
context.ObjectsListNeeded(realObjects[i]);
|
||||
|
||||
gd::String objectType = gd::GetTypeOfObject(globalObjectsAndGroups, objectsAndGroups, realObjects[i]);
|
||||
const ObjectMetadata& objInfo = MetadataProvider::GetObjectMetadata(
|
||||
codeGenerator.GetPlatform(), objectType);
|
||||
|
||||
// Build gd::String to access the object
|
||||
codeGenerator.AddIncludeFiles(objInfo.includeFiles);
|
||||
output = codeGenerator.GenerateObjectFunctionCall(
|
||||
realObjects[i],
|
||||
objInfo,
|
||||
expressionInfo.codeExtraInformation,
|
||||
parametersStr,
|
||||
output,
|
||||
context);
|
||||
}
|
||||
|
||||
plainExpression += output;
|
||||
};
|
||||
|
||||
void CallbacksForGeneratingExpressionCode::OnObjectBehaviorFunction(
|
||||
gd::String functionName,
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const gd::ExpressionMetadata& expressionInfo) {
|
||||
const gd::ObjectsContainer& globalObjectsAndGroups = codeGenerator.GetGlobalObjectsAndGroups();
|
||||
const gd::ObjectsContainer& objectsAndGroups = codeGenerator.GetObjectsAndGroups();
|
||||
|
||||
codeGenerator.AddIncludeFiles(
|
||||
expressionInfo.codeExtraInformation.GetIncludeFiles());
|
||||
if (parameters.size() < 2) return;
|
||||
|
||||
// Launch custom code generator if needed
|
||||
if (expressionInfo.codeExtraInformation.HasCustomCodeGenerator()) {
|
||||
plainExpression += expressionInfo.codeExtraInformation.customCodeGenerator(
|
||||
parameters, codeGenerator, context);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare parameters
|
||||
std::vector<gd::String> parametersCode =
|
||||
codeGenerator.GenerateParametersCodes(
|
||||
parameters, expressionInfo.parameters, context);
|
||||
gd::String parametersStr;
|
||||
for (std::size_t i = 2; i < parametersCode.size(); ++i) {
|
||||
if (i != 2) parametersStr += ", ";
|
||||
parametersStr += parametersCode[i];
|
||||
}
|
||||
|
||||
// Get object(s) concerned by function call
|
||||
std::vector<gd::String> realObjects =
|
||||
codeGenerator.ExpandObjectsName(parameters[0].GetPlainString(), context);
|
||||
|
||||
gd::String output = GetReturnType() == "string" ? "\"\"" : "0";
|
||||
for (std::size_t i = 0; i < realObjects.size(); ++i) {
|
||||
context.ObjectsListNeeded(realObjects[i]);
|
||||
|
||||
// Cast the object if needed
|
||||
gd::String behaviorType =
|
||||
gd::GetTypeOfBehavior(globalObjectsAndGroups, objectsAndGroups, parameters[1].GetPlainString());
|
||||
const BehaviorMetadata& autoInfo = MetadataProvider::GetBehaviorMetadata(
|
||||
codeGenerator.GetPlatform(), behaviorType);
|
||||
|
||||
// Build gd::String to access the behavior
|
||||
codeGenerator.AddIncludeFiles(autoInfo.includeFiles);
|
||||
output = codeGenerator.GenerateObjectBehaviorFunctionCall(
|
||||
realObjects[i],
|
||||
parameters[1].GetPlainString(),
|
||||
autoInfo,
|
||||
expressionInfo.codeExtraInformation,
|
||||
parametersStr,
|
||||
output,
|
||||
context);
|
||||
}
|
||||
|
||||
plainExpression += output;
|
||||
};
|
||||
|
||||
bool CallbacksForGeneratingExpressionCode::OnSubMathExpression(
|
||||
const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& globalObjectsAndGroups,
|
||||
const gd::ObjectsContainer& objectsAndGroups,
|
||||
gd::Expression& expression) {
|
||||
gd::String newExpression;
|
||||
|
||||
CallbacksForGeneratingExpressionCode callbacks(
|
||||
newExpression, codeGenerator, context);
|
||||
|
||||
gd::ExpressionParser parser(expression.GetPlainString());
|
||||
if (!parser.ParseMathExpression(platform, globalObjectsAndGroups, objectsAndGroups, callbacks)) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
firstErrorStr = callbacks.GetFirstError();
|
||||
firstErrorPos = callbacks.GetFirstErrorPosition();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CallbacksForGeneratingExpressionCode::OnSubTextExpression(
|
||||
const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& globalObjectsAndGroups,
|
||||
const gd::ObjectsContainer& objectsAndGroups,
|
||||
gd::Expression& expression) {
|
||||
gd::String newExpression;
|
||||
|
||||
CallbacksForGeneratingExpressionCode callbacks(
|
||||
newExpression, codeGenerator, context);
|
||||
|
||||
gd::ExpressionParser parser(expression.GetPlainString());
|
||||
if (!parser.ParseStringExpression(platform, globalObjectsAndGroups, objectsAndGroups, callbacks)) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
firstErrorStr = callbacks.GetFirstError();
|
||||
firstErrorPos = callbacks.GetFirstErrorPosition();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EXPRESSIONSCODEGENERATION_H
|
||||
#define EXPRESSIONSCODEGENERATION_H
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Parsers/ExpressionParser.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class ExpressionMetadata;
|
||||
class Expression;
|
||||
class Project;
|
||||
class Layout;
|
||||
class Layout;
|
||||
class EventsCodeGenerationContext;
|
||||
class EventsCodeGenerator;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
// TODO: Replace and remove (ExpressionCodeGenerator)
|
||||
|
||||
/**
|
||||
* \brief Used to generate code from expressions.
|
||||
*
|
||||
* Usage example :
|
||||
* \code
|
||||
* gd::String expressionOutputCppCode;
|
||||
*
|
||||
* CallbacksForGeneratingExpressionCode callbacks(expressionOutputCppCode,
|
||||
* codeGenerator, context); gd::ExpressionParser
|
||||
* parser(theOriginalGameDevelopExpression);
|
||||
* parser.ParseStringExpression(platform, project, scene, callbacks);
|
||||
*
|
||||
* if (expressionOutputCppCode.empty()) expressionOutputCppCode = "\"\""; //If
|
||||
* generation failed, we make sure output code is not empty. \endcode \see
|
||||
* EventsCodeGenerator
|
||||
*/
|
||||
class GD_CORE_API CallbacksForGeneratingExpressionCode
|
||||
: public gd::ParserCallbacks {
|
||||
public:
|
||||
CallbacksForGeneratingExpressionCode(gd::String& output,
|
||||
EventsCodeGenerator& codeGenerator_,
|
||||
EventsCodeGenerationContext& context_);
|
||||
virtual ~CallbacksForGeneratingExpressionCode(){};
|
||||
|
||||
void OnConstantToken(gd::String text);
|
||||
void OnStaticFunction(gd::String functionName,
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const gd::ExpressionMetadata& expressionInfo);
|
||||
void OnObjectFunction(gd::String functionName,
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const gd::ExpressionMetadata& expressionInfo);
|
||||
void OnObjectBehaviorFunction(gd::String functionName,
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const gd::ExpressionMetadata& expressionInfo);
|
||||
bool OnSubMathExpression(const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::Expression& expression);
|
||||
bool OnSubTextExpression(const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::Expression& expression);
|
||||
|
||||
private:
|
||||
gd::String& plainExpression;
|
||||
EventsCodeGenerator& codeGenerator;
|
||||
EventsCodeGenerationContext& context;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // EXPRESSIONSCODEGENERATION_H
|
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* GDevelop C++ Platform
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "VariableParserCallbacks.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Events/CodeGeneration/ExpressionCodeGenerator.h"
|
||||
#include "GDCore/Events/Parsers/VariableParser.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
VariableCodeGenerationCallbacks::VariableCodeGenerationCallbacks(
|
||||
gd::String& output_,
|
||||
gd::EventsCodeGenerator& codeGenerator_,
|
||||
gd::EventsCodeGenerationContext& context_,
|
||||
const gd::EventsCodeGenerator::VariableScope& scope_)
|
||||
: output(output_),
|
||||
codeGenerator(codeGenerator_),
|
||||
context(context_),
|
||||
scope(scope_) {
|
||||
if (scope == gd::EventsCodeGenerator::OBJECT_VARIABLE) {
|
||||
std::cout << "ERROR: Initializing VariableCodeGenerationCallbacks with "
|
||||
"OBJECT_VARIABLE without object.";
|
||||
}
|
||||
}
|
||||
|
||||
VariableCodeGenerationCallbacks::VariableCodeGenerationCallbacks(
|
||||
gd::String& output_,
|
||||
gd::EventsCodeGenerator& codeGenerator_,
|
||||
gd::EventsCodeGenerationContext& context_,
|
||||
const gd::String& object_)
|
||||
: output(output_),
|
||||
codeGenerator(codeGenerator_),
|
||||
context(context_),
|
||||
scope(gd::EventsCodeGenerator::OBJECT_VARIABLE),
|
||||
object(object_) {}
|
||||
|
||||
void VariableCodeGenerationCallbacks::OnRootVariable(gd::String variableName) {
|
||||
output += codeGenerator.GenerateGetVariable(variableName, scope, context, object);
|
||||
}
|
||||
|
||||
void VariableCodeGenerationCallbacks::OnChildVariable(gd::String variableName) {
|
||||
output += codeGenerator.GenerateVariableAccessor(variableName);
|
||||
}
|
||||
|
||||
void VariableCodeGenerationCallbacks::OnChildSubscript(
|
||||
gd::String stringExpression) {
|
||||
gd::String argumentCode = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator, context, "string", stringExpression);
|
||||
|
||||
output += codeGenerator.GenerateVariableBracketAccessor(argumentCode);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* GDevelop C++ Platform
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef VARIABLEPARSERCALLBACKS_H
|
||||
#define VARIABLEPARSERCALLBACKS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Parsers/VariableParser.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "EventsCodeGenerator.h"
|
||||
namespace gd {
|
||||
class EventsCodeGenerationContext;
|
||||
} // namespace gd
|
||||
|
||||
// TODO: Replace and remove (ExpressionCodeGenerator)
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Callbacks called to generate the code for getting a variable.
|
||||
*
|
||||
* Usage example:
|
||||
\code
|
||||
VariableCodeGenerationCallbacks callbacks(output, eventsCodeGenerator,
|
||||
context, VariableCodeGenerationCallbacks::LAYOUT_VARIABLE);
|
||||
|
||||
gd::VariableParser parser(parameter);
|
||||
if ( !parser.Parse(callbacks) )
|
||||
{
|
||||
//Error during parsing the variable name:
|
||||
output = "runtimeContext->GetSceneVariables().GetBadVariable()";
|
||||
}
|
||||
|
||||
//"output" now contains the C++ code to return the variable.
|
||||
\endcode
|
||||
*/
|
||||
class VariableCodeGenerationCallbacks : public gd::VariableParserCallbacks {
|
||||
public:
|
||||
/**
|
||||
* \brief Default constructor for generating code for a layout/global
|
||||
* variable. \param output The string in which the code will be generated.
|
||||
* \param codeGenerator The code generator being used.
|
||||
* \param context The current code generation context.
|
||||
* \param scope The scope of the variable being accessed: LAYOUT_VARIABLE,
|
||||
* PROJECT_VARIABLE.
|
||||
*/
|
||||
VariableCodeGenerationCallbacks(gd::String& output,
|
||||
gd::EventsCodeGenerator& codeGenerator_,
|
||||
gd::EventsCodeGenerationContext& context_,
|
||||
const gd::EventsCodeGenerator::VariableScope& scope_);
|
||||
/**
|
||||
|
||||
* \brief Default constructor for generating code for an object variable.
|
||||
* \param output The string in which the code will be generated.
|
||||
* \param codeGenerator The code generator being used.
|
||||
* \param context The current code generation context.
|
||||
* \param object The name of the object
|
||||
*/
|
||||
VariableCodeGenerationCallbacks(gd::String& output,
|
||||
gd::EventsCodeGenerator& codeGenerator_,
|
||||
gd::EventsCodeGenerationContext& context_,
|
||||
const gd::String& object);
|
||||
|
||||
/**
|
||||
* \brief Called when the first variable has been parsed.
|
||||
* \param variableName The variable name.
|
||||
*/
|
||||
virtual void OnRootVariable(gd::String variableName);
|
||||
|
||||
/**
|
||||
* \brief Called when accessing the child of a structure variable.
|
||||
* \param variableName The child variable name.
|
||||
*/
|
||||
virtual void OnChildVariable(gd::String variableName);
|
||||
|
||||
/**
|
||||
* \brief Called when accessing the child of a structure variable using a
|
||||
* string expression in square brackets. \param variableName The expression
|
||||
* used to access the child variable.
|
||||
*/
|
||||
virtual void OnChildSubscript(gd::String stringExpression);
|
||||
|
||||
private:
|
||||
gd::String& output;
|
||||
gd::EventsCodeGenerator& codeGenerator;
|
||||
gd::EventsCodeGenerationContext& context;
|
||||
gd::EventsCodeGenerator::VariableScope scope;
|
||||
const gd::String object; ///< The object name, when scope == OBJECT_VARIABLE.
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // VARIABLEPARSERCALLBACKS_H
|
||||
#endif
|
@@ -12,6 +12,7 @@
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Events/InstructionsList.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class EventsList;
|
||||
@@ -90,8 +91,8 @@ class GD_CORE_API BaseEvent {
|
||||
bool HasSubEvents() const;
|
||||
|
||||
/**
|
||||
* Event must be able to return all conditions std::vector they have.
|
||||
* Used to preprocess the conditions.
|
||||
* \brief Return a list of all conditions of the event.
|
||||
* \note Used to preprocess or search in the conditions.
|
||||
*/
|
||||
virtual std::vector<gd::InstructionsList*> GetAllConditionsVectors() {
|
||||
std::vector<gd::InstructionsList*> noConditions;
|
||||
@@ -104,8 +105,8 @@ class GD_CORE_API BaseEvent {
|
||||
};
|
||||
|
||||
/**
|
||||
* Event must be able to return all actions std::vector they have.
|
||||
* Used to preprocess the actions.
|
||||
* \brief Return a list of all actions of the event.
|
||||
* \note Used to preprocess or search in the actions.
|
||||
*/
|
||||
virtual std::vector<gd::InstructionsList*> GetAllActionsVectors() {
|
||||
std::vector<gd::InstructionsList*> noActions;
|
||||
@@ -118,15 +119,26 @@ class GD_CORE_API BaseEvent {
|
||||
};
|
||||
|
||||
/**
|
||||
* Event must be able to return all expressions they have.
|
||||
* Used to preprocess the expressions.
|
||||
* \brief Return a list of all strings of the event.
|
||||
* \note Used to preprocess or search in the event strings.
|
||||
*/
|
||||
virtual std::vector<gd::Expression*> GetAllExpressions() {
|
||||
std::vector<gd::Expression*> noExpr;
|
||||
virtual std::vector<gd::String> GetAllSearchableStrings() const {
|
||||
std::vector<gd::String> noSearchableStrings;
|
||||
return noSearchableStrings;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Return a list of all expressions of the event, each with their associated metadata.
|
||||
* \note Used to preprocess or search in the expressions of the event.
|
||||
*/
|
||||
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
GetAllExpressionsWithMetadata() {
|
||||
std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> > noExpr;
|
||||
return noExpr;
|
||||
};
|
||||
virtual std::vector<const gd::Expression*> GetAllExpressions() const {
|
||||
std::vector<const gd::Expression*> noExpr;
|
||||
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
GetAllExpressionsWithMetadata() const {
|
||||
std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> > noExpr;
|
||||
return noExpr;
|
||||
};
|
||||
|
||||
|
@@ -99,6 +99,23 @@ bool EventsList::Contains(const gd::BaseEvent& eventToSearch,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsList::MoveEventToAnotherEventsList(const gd::BaseEvent& eventToMove,
|
||||
gd::EventsList& newEventsList,
|
||||
std::size_t newPosition) {
|
||||
|
||||
for (std::size_t i = 0; i < GetEventsCount(); ++i) {
|
||||
if (events[i].get() == &eventToMove) {
|
||||
std::shared_ptr<BaseEvent> event = events[i];
|
||||
events.erase(events.begin() + i);
|
||||
|
||||
newEventsList.InsertEvent(event, newPosition);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EventsList::EventsList(const EventsList& other) { Init(other); }
|
||||
|
||||
EventsList& EventsList::operator=(const EventsList& other) {
|
||||
|
@@ -52,7 +52,8 @@ class GD_CORE_API EventsList {
|
||||
* \brief Insert the specified event to the list.
|
||||
* \note The event passed by parameter is not copied.
|
||||
* \param event The smart pointer to the event that must be inserted into the
|
||||
* list \param position Insertion position. If the position is invalid, the
|
||||
* list
|
||||
* \param position Insertion position. If the position is invalid, the
|
||||
* object is inserted at the end of the objects list.
|
||||
*/
|
||||
void InsertEvent(std::shared_ptr<gd::BaseEvent> event,
|
||||
@@ -142,6 +143,25 @@ class GD_CORE_API EventsList {
|
||||
*/
|
||||
bool Contains(const gd::BaseEvent& eventToSearch,
|
||||
bool recursive = true) const;
|
||||
|
||||
/**
|
||||
* Move the specified event, that must be in the events list, to another
|
||||
* events list *without* invalidating the event (i.e: without
|
||||
* destroying/cloning it) in memory.
|
||||
*
|
||||
* \warning newEventsList is supposed not to be contained inside the event
|
||||
* (you should not try
|
||||
* to move an event inside one of its children/grand children events).
|
||||
*
|
||||
* \param eventToMove The event to be moved
|
||||
* \param newEventsList The new events list
|
||||
* \param newPosition The position in the new events list
|
||||
* \return true if the move was made, false otherwise (for example, if
|
||||
* eventToMove is not found in the list)
|
||||
*/
|
||||
bool MoveEventToAnotherEventsList(const gd::BaseEvent& eventToMove,
|
||||
gd::EventsList& newEventsList,
|
||||
std::size_t newPosition);
|
||||
///@}
|
||||
|
||||
/** \name std::vector API compatibility
|
||||
|
@@ -4,9 +4,12 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Expression.h"
|
||||
#include "GDCore/Events/InstructionsList.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -15,18 +18,14 @@ namespace gd {
|
||||
|
||||
gd::Expression Instruction::badExpression("");
|
||||
|
||||
Instruction::Instruction(gd::String type_)
|
||||
: type(type_),
|
||||
inverted(false) {
|
||||
Instruction::Instruction(gd::String type_) : type(type_), inverted(false) {
|
||||
parameters.reserve(8);
|
||||
}
|
||||
|
||||
Instruction::Instruction(gd::String type_,
|
||||
const std::vector<gd::Expression>& parameters_,
|
||||
bool inverted_)
|
||||
: type(type_),
|
||||
inverted(inverted_),
|
||||
parameters(parameters_) {
|
||||
: type(type_), inverted(inverted_), parameters(parameters_) {
|
||||
parameters.reserve(8);
|
||||
}
|
||||
|
||||
@@ -56,4 +55,17 @@ void Instruction::SetParameter(std::size_t nb, const gd::Expression& val) {
|
||||
parameters[nb] = val;
|
||||
}
|
||||
|
||||
std::shared_ptr<Instruction> GD_CORE_API
|
||||
CloneRememberingOriginalElement(std::shared_ptr<Instruction> instruction) {
|
||||
std::shared_ptr<Instruction> copy =
|
||||
std::make_shared<Instruction>(*instruction);
|
||||
// Original instruction is either the original instruction of the copied
|
||||
// instruction, or the instruction copied.
|
||||
copy->originalInstruction = instruction->originalInstruction.expired()
|
||||
? instruction
|
||||
: instruction->originalInstruction;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -5,7 +5,9 @@
|
||||
*/
|
||||
#ifndef INSTRUCTION_H
|
||||
#define INSTRUCTION_H
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Expression.h"
|
||||
#include "GDCore/Events/InstructionsList.h"
|
||||
#include "GDCore/String.h"
|
||||
@@ -131,6 +133,17 @@ class GD_CORE_API Instruction {
|
||||
*/
|
||||
inline gd::InstructionsList& GetSubInstructions() { return subInstructions; };
|
||||
|
||||
/**
|
||||
* \brief Return the original instruction this instruction was copied from.
|
||||
*
|
||||
* Useful to get reference to the original instruction in memory during code
|
||||
* generation, to ensure stable unique identifiers.
|
||||
*/
|
||||
std::weak_ptr<Instruction> GetOriginalInstruction() { return originalInstruction; };
|
||||
|
||||
friend std::shared_ptr<Instruction> CloneRememberingOriginalElement(
|
||||
std::shared_ptr<Instruction> instruction);
|
||||
|
||||
private:
|
||||
gd::String type; ///< Instruction type
|
||||
bool inverted; ///< True if the instruction if inverted. Only applicable for
|
||||
@@ -139,9 +152,23 @@ class GD_CORE_API Instruction {
|
||||
parameters; ///< Vector containing the parameters
|
||||
gd::InstructionsList subInstructions; ///< Sub instructions, if applicable.
|
||||
|
||||
std::weak_ptr<Instruction>
|
||||
originalInstruction; ///< Pointer used to remember which gd::Instruction
|
||||
///< this instruction was copied from. Useful to
|
||||
///< ensure the stability of code generation (as
|
||||
///< some part of code generation uses the pointer
|
||||
///< to the instruction as a unique identifier).
|
||||
|
||||
static gd::Expression badExpression;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clone the given instruction, returning an instruction for which
|
||||
* `GetOriginalInstruction()` returns the originally copied instruction.
|
||||
*/
|
||||
std::shared_ptr<Instruction> GD_CORE_API
|
||||
CloneRememberingOriginalElement(std::shared_ptr<Instruction> instruction);
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // INSTRUCTION_H
|
||||
|
@@ -1,897 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Events/Parsers/ExpressionParser.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Expression.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
gd::String ExpressionParser::parserSeparators = " ,+-*/%.<>=&|;()#^![]{}";
|
||||
|
||||
size_t ExpressionParser::GetMinimalParametersNumber(
|
||||
const std::vector<gd::ParameterMetadata>& parametersInfos) {
|
||||
size_t nb = 0;
|
||||
for (std::size_t i = 0; i < parametersInfos.size(); ++i) {
|
||||
if (!parametersInfos[i].optional && !parametersInfos[i].codeOnly) nb++;
|
||||
}
|
||||
|
||||
return nb;
|
||||
}
|
||||
|
||||
size_t ExpressionParser::GetMaximalParametersNumber(
|
||||
const std::vector<gd::ParameterMetadata>& parametersInfos) {
|
||||
size_t nb = 0;
|
||||
for (std::size_t i = 0; i < parametersInfos.size(); ++i) {
|
||||
if (!parametersInfos[i].codeOnly) nb++;
|
||||
}
|
||||
|
||||
return nb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add blank parameters when code-only parameters are expected.
|
||||
* \param Parameters information
|
||||
* \param vector of parameters without code only parameters.
|
||||
*/
|
||||
std::vector<gd::Expression> CompleteParameters(
|
||||
const std::vector<gd::ParameterMetadata>& parametersInfo,
|
||||
const std::vector<gd::Expression>& parameters) {
|
||||
std::vector<gd::Expression> completeParameters = parameters;
|
||||
for (std::size_t i = 0; i < parametersInfo.size();
|
||||
++i) // Code only parameters are not included in expressions parameters.
|
||||
{
|
||||
if (parametersInfo[i].codeOnly) {
|
||||
if (i > completeParameters.size()) {
|
||||
cout << "Bad parameter count in expression.";
|
||||
}
|
||||
|
||||
if (i >= completeParameters.size())
|
||||
completeParameters.push_back(gd::Expression(""));
|
||||
else
|
||||
completeParameters.insert(completeParameters.begin() + i,
|
||||
gd::Expression(""));
|
||||
} else {
|
||||
if (i >= completeParameters.size()) {
|
||||
completeParameters.push_back(gd::Expression(""));
|
||||
}
|
||||
}
|
||||
}
|
||||
return completeParameters;
|
||||
}
|
||||
|
||||
bool ExpressionParser::ValidSyntax(const gd::String& str) {
|
||||
static const gd::String numerics = "0123456789.e";
|
||||
static const gd::String operators = "+/*-%";
|
||||
|
||||
size_t parenthesisLevel = 0;
|
||||
gd::String lastOperator;
|
||||
|
||||
bool parsingNumber = false;
|
||||
bool parsingScientificNotationNumber = false;
|
||||
bool parsingDecimalNumber = false;
|
||||
bool requestNumber = false;
|
||||
gd::String lastNumber;
|
||||
bool numberWasParsedLast = false;
|
||||
|
||||
for (auto it = str.begin(); it != str.end(); ++it) {
|
||||
char32_t currentChar = *it;
|
||||
if (currentChar == U' ' || currentChar == U'\n') {
|
||||
if (requestNumber) {
|
||||
firstErrorStr = _("Number expected");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsingNumber) {
|
||||
parsingNumber = false;
|
||||
parsingScientificNotationNumber = false;
|
||||
parsingDecimalNumber = false;
|
||||
requestNumber = false;
|
||||
lastNumber.clear();
|
||||
numberWasParsedLast = true;
|
||||
}
|
||||
} else if (numerics.find(currentChar) != gd::String::npos) {
|
||||
requestNumber = false;
|
||||
|
||||
if (currentChar == U'.') {
|
||||
if (!parsingNumber) {
|
||||
firstErrorStr = _("Syntax error");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsingDecimalNumber) {
|
||||
firstErrorStr = _("Syntax error in a number.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
parsingDecimalNumber = true;
|
||||
}
|
||||
|
||||
if (currentChar == U'e') {
|
||||
if (parsingScientificNotationNumber) {
|
||||
firstErrorStr = _("Syntax error in a number.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
parsingScientificNotationNumber = true;
|
||||
requestNumber = true;
|
||||
}
|
||||
|
||||
if (numberWasParsedLast) {
|
||||
firstErrorStr = _("Operator missing before a number");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
parsingNumber = true;
|
||||
lastNumber += currentChar;
|
||||
} else if (currentChar == U')') {
|
||||
if (requestNumber) {
|
||||
firstErrorStr = _("Number expected");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsingNumber) {
|
||||
parsingNumber = false;
|
||||
parsingScientificNotationNumber = false;
|
||||
parsingDecimalNumber = false;
|
||||
lastNumber.clear();
|
||||
numberWasParsedLast = true;
|
||||
}
|
||||
|
||||
if (!numberWasParsedLast) {
|
||||
firstErrorStr = _("Superfluous operator before a paranthesis");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parenthesisLevel > 0)
|
||||
parenthesisLevel--;
|
||||
else {
|
||||
firstErrorStr = _("Bad closing paranthesis");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto previousIt = it;
|
||||
--previousIt;
|
||||
if (*previousIt == U'(') {
|
||||
firstErrorStr = _("Empty paranthesis");
|
||||
|
||||
return false;
|
||||
}
|
||||
} else if (currentChar == U'(') {
|
||||
if (requestNumber) {
|
||||
firstErrorStr = _("Number expected");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsingNumber) {
|
||||
parsingNumber = false;
|
||||
parsingScientificNotationNumber = false;
|
||||
parsingDecimalNumber = false;
|
||||
lastNumber.clear();
|
||||
numberWasParsedLast = true;
|
||||
}
|
||||
|
||||
if (numberWasParsedLast) {
|
||||
firstErrorStr = _("Operator missing before a paranthesis");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
parenthesisLevel++;
|
||||
numberWasParsedLast = false;
|
||||
} else if (operators.find(currentChar) != gd::String::npos) {
|
||||
if (currentChar == U'-' && parsingNumber &&
|
||||
parsingScientificNotationNumber) {
|
||||
lastNumber += currentChar;
|
||||
requestNumber = true;
|
||||
} else {
|
||||
if (requestNumber) {
|
||||
firstErrorStr = _("Number expected");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsingNumber) {
|
||||
parsingNumber = false;
|
||||
parsingScientificNotationNumber = false;
|
||||
parsingDecimalNumber = false;
|
||||
lastNumber.clear();
|
||||
numberWasParsedLast = true;
|
||||
}
|
||||
|
||||
if (currentChar != U'-' && currentChar != U'+' &&
|
||||
!numberWasParsedLast) {
|
||||
firstErrorStr = _("Operators without any number between them");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
numberWasParsedLast = false;
|
||||
}
|
||||
} else {
|
||||
firstErrorStr = _("Syntax error");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (parsingNumber) {
|
||||
parsingNumber = false;
|
||||
parsingScientificNotationNumber = false;
|
||||
parsingDecimalNumber = false;
|
||||
lastNumber.clear();
|
||||
numberWasParsedLast = true;
|
||||
} else if (requestNumber) {
|
||||
firstErrorStr = _("Number expected");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parenthesisLevel != 0) {
|
||||
firstErrorStr = _("Paranthesis mismatch");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!numberWasParsedLast) {
|
||||
firstErrorStr = _("Alone operator at the end of the expression");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExpressionParser::ParseMathExpression(const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::ParserCallbacks& callbacks) {
|
||||
callbacks.SetReturnType("expression");
|
||||
gd::String expression = expressionPlainString;
|
||||
|
||||
size_t parsePosition = 0;
|
||||
|
||||
size_t firstPointPos = expression.find(".");
|
||||
size_t firstParPos = expression.find("(");
|
||||
|
||||
gd::String expressionWithoutFunctions;
|
||||
gd::String nonFunctionToken;
|
||||
size_t nonFunctionTokenStartPos = gd::String::npos;
|
||||
|
||||
while (firstPointPos != string::npos || firstParPos != string::npos) {
|
||||
// Identify name
|
||||
size_t nameEnd = firstPointPos < firstParPos ? firstPointPos : firstParPos;
|
||||
size_t nameStart = expression.find_last_of(parserSeparators, nameEnd - 1);
|
||||
nameStart++;
|
||||
|
||||
gd::String nameBefore = expression.substr(nameStart, nameEnd - nameStart);
|
||||
gd::String objectName = nameBefore.FindAndReplace("~", " ");
|
||||
|
||||
// Identify function name
|
||||
gd::String functionName = nameBefore;
|
||||
size_t functionNameEnd = nameEnd;
|
||||
vector<gd::Expression> parameters;
|
||||
|
||||
bool nameIsFunction = firstPointPos > firstParPos;
|
||||
if (!nameIsFunction) {
|
||||
parameters.push_back(gd::Expression(objectName));
|
||||
functionNameEnd = expression.find_first_of(" (", nameEnd);
|
||||
if (nameEnd + 1 < expression.length())
|
||||
functionName =
|
||||
expression.substr(nameEnd + 1, functionNameEnd - (nameEnd + 1));
|
||||
if (functionNameEnd == string::npos) {
|
||||
functionName = "";
|
||||
functionNameEnd = expression.length() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we're going to identify the expression
|
||||
gd::ExpressionMetadata instructionInfos;
|
||||
|
||||
if (functionName.substr(0, functionName.length() - 1)
|
||||
.find_first_of(parserSeparators) == string::npos) {
|
||||
bool functionFound = false;
|
||||
bool staticFunctionFound = false;
|
||||
bool objectFunctionFound = false;
|
||||
bool behaviorFunctionFound = false;
|
||||
|
||||
// First try to bind to a static expression
|
||||
if (nameIsFunction &&
|
||||
MetadataProvider::HasExpression(platform, functionName)) {
|
||||
functionFound = true;
|
||||
staticFunctionFound = true;
|
||||
instructionInfos =
|
||||
MetadataProvider::GetExpressionMetadata(platform, functionName);
|
||||
}
|
||||
// Then search in object expression
|
||||
else if (!nameIsFunction &&
|
||||
MetadataProvider::HasObjectExpression(
|
||||
platform,
|
||||
gd::GetTypeOfObject(project, layout, objectName),
|
||||
functionName)) {
|
||||
functionFound = true;
|
||||
objectFunctionFound = true;
|
||||
instructionInfos = MetadataProvider::GetObjectExpressionMetadata(
|
||||
platform,
|
||||
gd::GetTypeOfObject(project, layout, objectName),
|
||||
functionName);
|
||||
}
|
||||
// And in behaviors expressions
|
||||
else if (!nameIsFunction) {
|
||||
size_t firstDoublePoints = functionName.find("::");
|
||||
if (firstDoublePoints != string::npos) {
|
||||
gd::String autoName = functionName.substr(0, firstDoublePoints);
|
||||
if (firstDoublePoints + 2 < functionName.length())
|
||||
functionName = functionName.substr(firstDoublePoints + 2,
|
||||
functionName.length());
|
||||
else
|
||||
functionName = "";
|
||||
|
||||
if (MetadataProvider::HasBehaviorExpression(
|
||||
platform,
|
||||
gd::GetTypeOfBehavior(project, layout, autoName),
|
||||
functionName)) {
|
||||
parameters.push_back(gd::Expression(autoName));
|
||||
functionFound = true;
|
||||
behaviorFunctionFound = true;
|
||||
|
||||
instructionInfos = MetadataProvider::GetBehaviorExpressionMetadata(
|
||||
platform,
|
||||
gd::GetTypeOfBehavior(project, layout, autoName),
|
||||
functionName);
|
||||
|
||||
// Verify that object has behavior.
|
||||
vector<gd::String> behaviors =
|
||||
gd::GetBehaviorsOfObject(project, layout, objectName);
|
||||
if (find(behaviors.begin(), behaviors.end(), autoName) ==
|
||||
behaviors.end()) {
|
||||
cout << "Bad behavior requested" << endl;
|
||||
functionFound = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (functionFound) // Add the function
|
||||
{
|
||||
// Identify parameters
|
||||
size_t parametersEnd = expression.find_first_of("(", functionNameEnd);
|
||||
gd::String currentParameterStr;
|
||||
char32_t previousChar = '(';
|
||||
bool takeSymbolsInAccount = true;
|
||||
if (parametersEnd != string::npos) {
|
||||
size_t level = 0;
|
||||
parametersEnd++;
|
||||
|
||||
while (parametersEnd < expression.length() &&
|
||||
!(expression[parametersEnd] == ')' && level == 0)) {
|
||||
// Be sure we are not in quotes
|
||||
if (expression[parametersEnd] == U'\"' && previousChar != U'\\')
|
||||
takeSymbolsInAccount = !takeSymbolsInAccount;
|
||||
|
||||
// So as to be sure paranthesis don't belong to a parameter
|
||||
if (expression[parametersEnd] == U'(' && takeSymbolsInAccount)
|
||||
level++;
|
||||
if (expression[parametersEnd] == U')' && takeSymbolsInAccount)
|
||||
level--;
|
||||
|
||||
// Add the character to the current parameter or terminate the
|
||||
// latter
|
||||
if ((expression[parametersEnd] == U',' && level == 0) &&
|
||||
takeSymbolsInAccount) {
|
||||
parameters.push_back(currentParameterStr);
|
||||
currentParameterStr.clear();
|
||||
} else
|
||||
currentParameterStr += expression[parametersEnd];
|
||||
|
||||
previousChar = expression[parametersEnd];
|
||||
parametersEnd++;
|
||||
}
|
||||
if (currentParameterStr.find_first_not_of(" ") !=
|
||||
string::npos) // Add last parameter if needed
|
||||
{
|
||||
parameters.push_back(currentParameterStr);
|
||||
}
|
||||
|
||||
// Testing function call is properly closed
|
||||
if (parametersEnd == expression.length() ||
|
||||
expression[parametersEnd] != U')') {
|
||||
firstErrorStr = _("Paranthesis not closed");
|
||||
firstErrorPos = parametersEnd - 1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Testing the number of parameters
|
||||
if (parameters.size() >
|
||||
GetMaximalParametersNumber(instructionInfos.parameters) ||
|
||||
parameters.size() <
|
||||
GetMinimalParametersNumber(instructionInfos.parameters)) {
|
||||
firstErrorPos = functionNameEnd;
|
||||
firstErrorStr = _("Incorrect number of parameters");
|
||||
firstErrorStr += " ";
|
||||
firstErrorStr += _("Expected (maximum) :");
|
||||
firstErrorStr += gd::String::From(
|
||||
GetMaximalParametersNumber(instructionInfos.parameters));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Preparing parameters
|
||||
parameters =
|
||||
CompleteParameters(instructionInfos.parameters, parameters);
|
||||
for (std::size_t i = 0; i < instructionInfos.parameters.size(); ++i) {
|
||||
if (!PrepareParameter(platform,
|
||||
project,
|
||||
layout,
|
||||
callbacks,
|
||||
parameters[i],
|
||||
instructionInfos.parameters[i],
|
||||
functionNameEnd))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
firstErrorPos = functionNameEnd;
|
||||
firstErrorStr = _("Parameters' parenthesis missing");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
callbacks.OnConstantToken(
|
||||
nonFunctionToken +
|
||||
expression.substr(parsePosition, nameStart - parsePosition));
|
||||
expressionWithoutFunctions +=
|
||||
expression.substr(parsePosition, nameStart - parsePosition);
|
||||
nonFunctionToken.clear();
|
||||
nonFunctionTokenStartPos = gd::String::npos;
|
||||
|
||||
if (objectFunctionFound)
|
||||
callbacks.OnObjectFunction(
|
||||
functionName, parameters, instructionInfos);
|
||||
else if (behaviorFunctionFound)
|
||||
callbacks.OnObjectBehaviorFunction(
|
||||
functionName, parameters, instructionInfos);
|
||||
else if (staticFunctionFound)
|
||||
callbacks.OnStaticFunction(
|
||||
functionName, parameters, instructionInfos);
|
||||
|
||||
if (objectFunctionFound || behaviorFunctionFound || staticFunctionFound)
|
||||
expressionWithoutFunctions += "0";
|
||||
|
||||
parsePosition = parametersEnd + 1;
|
||||
firstPointPos = expression.find(".", parametersEnd + 1);
|
||||
firstParPos = expression.find("(", parametersEnd + 1);
|
||||
} else // Math function or math constant : Pass it.
|
||||
{
|
||||
nonFunctionToken += expression.substr(
|
||||
parsePosition, functionNameEnd + 1 - parsePosition);
|
||||
expressionWithoutFunctions += expression.substr(
|
||||
parsePosition, functionNameEnd + 1 - parsePosition);
|
||||
nonFunctionTokenStartPos = (nonFunctionTokenStartPos != gd::String::npos
|
||||
? nonFunctionTokenStartPos
|
||||
: parsePosition);
|
||||
parsePosition = functionNameEnd + 1;
|
||||
firstPointPos = expression.find(".", functionNameEnd + 1);
|
||||
firstParPos = expression.find("(", functionNameEnd + 1);
|
||||
}
|
||||
} else // Not a function call : Pass it
|
||||
{
|
||||
nonFunctionToken +=
|
||||
expression.substr(parsePosition, nameEnd + 1 - parsePosition);
|
||||
expressionWithoutFunctions +=
|
||||
expression.substr(parsePosition, nameEnd + 1 - parsePosition);
|
||||
nonFunctionTokenStartPos = (nonFunctionTokenStartPos != gd::String::npos
|
||||
? nonFunctionTokenStartPos
|
||||
: parsePosition);
|
||||
parsePosition = nameEnd + 1;
|
||||
firstPointPos = expression.find(".", nameEnd + 1);
|
||||
firstParPos = expression.find("(", nameEnd + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (parsePosition < expression.length() || !nonFunctionToken.empty())
|
||||
callbacks.OnConstantToken(
|
||||
nonFunctionToken +
|
||||
expression.substr(parsePosition, expression.length()));
|
||||
|
||||
expressionWithoutFunctions +=
|
||||
expression.substr(parsePosition, expression.length());
|
||||
|
||||
return ValidSyntax(expressionWithoutFunctions);
|
||||
}
|
||||
|
||||
bool ExpressionParser::ParseStringExpression(const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::ParserCallbacks& callbacks) {
|
||||
callbacks.SetReturnType("string");
|
||||
gd::String expression = expressionPlainString;
|
||||
|
||||
size_t parsePosition = 0;
|
||||
|
||||
// Searching for first token.
|
||||
size_t firstPointPos = expression.find(".");
|
||||
size_t firstParPos = expression.find("(");
|
||||
size_t firstQuotePos = expression.find("\"");
|
||||
|
||||
if (firstPointPos == string::npos && firstParPos == string::npos &&
|
||||
firstQuotePos == string::npos) {
|
||||
firstErrorPos = 0;
|
||||
firstErrorStr =
|
||||
_("The expression is invalid or empty. Enter a text ( surrounded by "
|
||||
"quotes ) or a function.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
while (firstPointPos != string::npos || firstParPos != string::npos ||
|
||||
firstQuotePos != string::npos) {
|
||||
if (firstQuotePos < firstPointPos &&
|
||||
firstQuotePos < firstParPos) // Adding a constant text
|
||||
{
|
||||
callbacks.OnConstantToken(
|
||||
expression.substr(parsePosition, firstQuotePos - parsePosition));
|
||||
|
||||
// Finding start and end of quotes
|
||||
size_t finalQuotePosition = expression.find("\"", firstQuotePos + 1);
|
||||
while (finalQuotePosition ==
|
||||
expression.find("\\\"", finalQuotePosition - 1) + 1)
|
||||
finalQuotePosition = expression.find("\"", finalQuotePosition + 1);
|
||||
|
||||
if (finalQuotePosition == string::npos) {
|
||||
firstErrorPos = firstQuotePos;
|
||||
firstErrorStr = _("Quotes not closed.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generating final text, by replacing \" by quotes
|
||||
gd::String finalText = expression.substr(
|
||||
firstQuotePos + 1, finalQuotePosition - (firstQuotePos + 1));
|
||||
|
||||
size_t foundPos = finalText.find("\\\"");
|
||||
while (foundPos != string::npos) {
|
||||
if (foundPos != string::npos) finalText.replace(foundPos, 2, "\"");
|
||||
foundPos = finalText.find("\\\"", foundPos);
|
||||
}
|
||||
|
||||
// Adding constant text instruction
|
||||
//(Function without name is considered as a constant text)
|
||||
vector<gd::Expression> parameters;
|
||||
parameters.push_back(finalText);
|
||||
gd::ExpressionMetadata noParametersInfo;
|
||||
|
||||
callbacks.OnStaticFunction("", parameters, noParametersInfo);
|
||||
|
||||
parsePosition = finalQuotePosition + 1;
|
||||
} else // Adding a function
|
||||
{
|
||||
// Identify name
|
||||
size_t nameEnd =
|
||||
firstPointPos < firstParPos ? firstPointPos : firstParPos;
|
||||
size_t nameStart = expression.find_last_of(parserSeparators, nameEnd - 1);
|
||||
nameStart++;
|
||||
|
||||
callbacks.OnConstantToken(
|
||||
expression.substr(parsePosition, nameStart - parsePosition));
|
||||
|
||||
gd::String nameBefore = expression.substr(nameStart, nameEnd - nameStart);
|
||||
gd::String objectName = nameBefore.FindAndReplace("~", " ");
|
||||
|
||||
// Identify function name
|
||||
gd::String functionName = nameBefore;
|
||||
size_t functionNameEnd = nameEnd;
|
||||
vector<gd::Expression> parameters;
|
||||
|
||||
bool nameIsFunction = firstPointPos > firstParPos;
|
||||
if (!nameIsFunction) {
|
||||
parameters.push_back(gd::Expression(objectName));
|
||||
functionNameEnd = expression.find_first_of("( ", nameEnd);
|
||||
if (nameEnd + 1 < expression.length())
|
||||
functionName =
|
||||
expression.substr(nameEnd + 1, functionNameEnd - (nameEnd + 1));
|
||||
}
|
||||
|
||||
// Identify parameters
|
||||
size_t parametersEnd = expression.find_first_of("(", functionNameEnd) + 1;
|
||||
char32_t previousChar = U'(';
|
||||
bool takeSymbolsInAccount = true;
|
||||
size_t level = 0;
|
||||
gd::String currentParameterStr;
|
||||
while (parametersEnd < expression.length() &&
|
||||
!(expression[parametersEnd] == U')' && level == 0)) {
|
||||
// Be sure we are not in quotes
|
||||
if (expression[parametersEnd] == U'\"' && previousChar != U'\\')
|
||||
takeSymbolsInAccount = !takeSymbolsInAccount;
|
||||
|
||||
// So as to be sure paranthesis don't belong to a parameter
|
||||
if (expression[parametersEnd] == U'(' && takeSymbolsInAccount) level++;
|
||||
if (expression[parametersEnd] == U')' && takeSymbolsInAccount) level--;
|
||||
|
||||
// Add the character to the current parameter or terminate the latter
|
||||
if ((expression[parametersEnd] == ',' && level == 0) &&
|
||||
takeSymbolsInAccount) {
|
||||
gd::Expression currentParameter(currentParameterStr);
|
||||
parameters.push_back(currentParameter);
|
||||
|
||||
currentParameterStr.clear();
|
||||
} else
|
||||
currentParameterStr += expression[parametersEnd];
|
||||
|
||||
previousChar = expression[parametersEnd];
|
||||
parametersEnd++;
|
||||
}
|
||||
|
||||
if (parametersEnd == expression.length() ||
|
||||
expression[parametersEnd] != U')') {
|
||||
firstErrorPos = parametersEnd - 1;
|
||||
firstErrorStr = _("Paranthesis not closed");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (currentParameterStr.find_first_not_of(" ") !=
|
||||
string::npos) // Add last parameter if needed
|
||||
{
|
||||
gd::Expression lastParameter(currentParameterStr);
|
||||
parameters.push_back(lastParameter);
|
||||
}
|
||||
|
||||
bool functionFound = false;
|
||||
|
||||
// First try to bind to a static str expression
|
||||
if (nameIsFunction &&
|
||||
MetadataProvider::HasStrExpression(platform, functionName)) {
|
||||
functionFound = true;
|
||||
const gd::ExpressionMetadata& expressionInfo =
|
||||
MetadataProvider::GetStrExpressionMetadata(platform, functionName);
|
||||
|
||||
// Testing the number of parameters
|
||||
if (parameters.size() >
|
||||
GetMaximalParametersNumber(expressionInfo.parameters) ||
|
||||
parameters.size() <
|
||||
GetMinimalParametersNumber(expressionInfo.parameters)) {
|
||||
firstErrorPos = functionNameEnd;
|
||||
firstErrorStr = _("Incorrect number of parameters");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Preparing parameters
|
||||
parameters = CompleteParameters(expressionInfo.parameters, parameters);
|
||||
for (std::size_t i = 0;
|
||||
i < parameters.size() && i < expressionInfo.parameters.size();
|
||||
++i) {
|
||||
if (!PrepareParameter(platform,
|
||||
project,
|
||||
layout,
|
||||
callbacks,
|
||||
parameters[i],
|
||||
expressionInfo.parameters[i],
|
||||
functionNameEnd))
|
||||
return false;
|
||||
}
|
||||
|
||||
callbacks.OnStaticFunction(functionName, parameters, expressionInfo);
|
||||
}
|
||||
// Then an object member expression
|
||||
else if (!nameIsFunction &&
|
||||
MetadataProvider::HasObjectStrExpression(
|
||||
platform,
|
||||
gd::GetTypeOfObject(project, layout, objectName),
|
||||
functionName)) {
|
||||
functionFound = true;
|
||||
const gd::ExpressionMetadata& expressionInfo =
|
||||
MetadataProvider::GetObjectStrExpressionMetadata(
|
||||
platform,
|
||||
gd::GetTypeOfObject(project, layout, nameBefore),
|
||||
functionName);
|
||||
|
||||
// Testing the number of parameters
|
||||
if (parameters.size() >
|
||||
GetMaximalParametersNumber(expressionInfo.parameters) ||
|
||||
parameters.size() <
|
||||
GetMinimalParametersNumber(expressionInfo.parameters)) {
|
||||
firstErrorPos = functionNameEnd;
|
||||
firstErrorStr = _("Incorrect number of parameters");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Preparing parameters
|
||||
parameters = CompleteParameters(expressionInfo.parameters, parameters);
|
||||
for (std::size_t i = 0;
|
||||
i < parameters.size() && i < expressionInfo.parameters.size();
|
||||
++i) {
|
||||
if (!PrepareParameter(platform,
|
||||
project,
|
||||
layout,
|
||||
callbacks,
|
||||
parameters[i],
|
||||
expressionInfo.parameters[i],
|
||||
functionNameEnd))
|
||||
return false;
|
||||
}
|
||||
|
||||
callbacks.OnObjectFunction(functionName, parameters, expressionInfo);
|
||||
}
|
||||
// And search behaviors expressions
|
||||
else {
|
||||
size_t firstDoublePoints = functionName.find("::");
|
||||
if (firstDoublePoints != string::npos) {
|
||||
gd::String autoName = functionName.substr(0, firstDoublePoints);
|
||||
if (firstDoublePoints + 2 < functionName.length())
|
||||
functionName = functionName.substr(firstDoublePoints + 2,
|
||||
functionName.length());
|
||||
else
|
||||
functionName = "";
|
||||
|
||||
if (MetadataProvider::HasBehaviorStrExpression(
|
||||
platform,
|
||||
gd::GetTypeOfBehavior(project, layout, autoName),
|
||||
functionName)) {
|
||||
parameters.push_back(gd::Expression(autoName));
|
||||
functionFound = true;
|
||||
|
||||
const gd::ExpressionMetadata& expressionInfo =
|
||||
MetadataProvider::GetBehaviorStrExpressionMetadata(
|
||||
platform,
|
||||
gd::GetTypeOfBehavior(project, layout, autoName),
|
||||
functionName);
|
||||
|
||||
// Verify that object has behavior.
|
||||
vector<gd::String> behaviors =
|
||||
gd::GetBehaviorsOfObject(project, layout, objectName);
|
||||
if (find(behaviors.begin(), behaviors.end(), autoName) ==
|
||||
behaviors.end()) {
|
||||
cout << "Bad behavior requested" << endl;
|
||||
functionFound = false;
|
||||
} else {
|
||||
// Testing the number of parameters
|
||||
if (parameters.size() >
|
||||
GetMaximalParametersNumber(expressionInfo.parameters) ||
|
||||
parameters.size() <
|
||||
GetMinimalParametersNumber(expressionInfo.parameters)) {
|
||||
firstErrorPos = functionNameEnd;
|
||||
firstErrorStr = _("Incorrect number of parameters");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Preparing parameters
|
||||
parameters =
|
||||
CompleteParameters(expressionInfo.parameters, parameters);
|
||||
for (std::size_t i = 0; i < parameters.size() &&
|
||||
i < expressionInfo.parameters.size();
|
||||
++i) {
|
||||
if (!PrepareParameter(platform,
|
||||
project,
|
||||
layout,
|
||||
callbacks,
|
||||
parameters[i],
|
||||
expressionInfo.parameters[i],
|
||||
functionNameEnd))
|
||||
return false;
|
||||
}
|
||||
|
||||
callbacks.OnObjectBehaviorFunction(
|
||||
functionName, parameters, expressionInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note : _No_ support for implicit conversion from math result to string
|
||||
|
||||
if (!functionFound) // Function was not found
|
||||
{
|
||||
firstErrorPos = nameStart;
|
||||
firstErrorStr = _("Function not recognized.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
parsePosition = parametersEnd + 1;
|
||||
}
|
||||
|
||||
// Searching for next token
|
||||
size_t firstPlusPos = expression.find("+", parsePosition);
|
||||
firstPointPos = expression.find(".", parsePosition);
|
||||
firstParPos = expression.find("(", parsePosition);
|
||||
firstQuotePos = expression.find("\"", parsePosition);
|
||||
|
||||
// Checking for a + between token
|
||||
if ((firstPointPos != string::npos || firstParPos != string::npos ||
|
||||
firstQuotePos != string::npos)) {
|
||||
size_t nextTokenPos = firstPointPos;
|
||||
if (firstParPos < nextTokenPos) nextTokenPos = firstParPos;
|
||||
if (firstQuotePos < nextTokenPos) nextTokenPos = firstQuotePos;
|
||||
|
||||
if (nextTokenPos < firstPlusPos) {
|
||||
firstErrorPos = nextTokenPos;
|
||||
firstErrorStr = _("Symbol missing between two +.");
|
||||
|
||||
return false;
|
||||
} else if (expression.find("+", firstPlusPos + 1) < nextTokenPos) {
|
||||
firstErrorPos = firstPlusPos;
|
||||
firstErrorStr = _("Symbol missing between two +.");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (expression.substr(parsePosition, expression.length())
|
||||
.find_first_not_of(" \n") != gd::String::npos) {
|
||||
firstErrorPos = parsePosition;
|
||||
firstErrorStr = _("Bad symbol at the end of the expression.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExpressionParser::PrepareParameter(
|
||||
const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
ParserCallbacks& callbacks,
|
||||
gd::Expression& parameter,
|
||||
const gd::ParameterMetadata& parametersInfo,
|
||||
const size_t positionInExpression) {
|
||||
if (ParameterMetadata::IsExpression("number", parametersInfo.type)) {
|
||||
if (parametersInfo.optional && parameter.GetPlainString().empty())
|
||||
parameter = parametersInfo.GetDefaultValue().empty()
|
||||
? gd::Expression("0")
|
||||
: gd::Expression(parametersInfo.GetDefaultValue());
|
||||
|
||||
if (!callbacks.OnSubMathExpression(platform, project, layout, parameter)) {
|
||||
firstErrorStr = callbacks.firstErrorStr;
|
||||
firstErrorPos = callbacks.firstErrorPos + positionInExpression;
|
||||
|
||||
return false;
|
||||
}
|
||||
} else if (ParameterMetadata::IsExpression("string", parametersInfo.type)) {
|
||||
if (parametersInfo.optional && parameter.GetPlainString().empty())
|
||||
parameter = parametersInfo.GetDefaultValue().empty()
|
||||
? gd::Expression("\"\"")
|
||||
: gd::Expression(parametersInfo.GetDefaultValue());
|
||||
|
||||
if (!callbacks.OnSubTextExpression(platform, project, layout, parameter)) {
|
||||
firstErrorStr = callbacks.firstErrorStr;
|
||||
firstErrorPos = callbacks.firstErrorPos + positionInExpression;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ExpressionParser::ExpressionParser(const gd::String& expressionPlainString_)
|
||||
: expressionPlainString(expressionPlainString_) {}
|
||||
|
||||
} // namespace gd
|
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONPARSER_H
|
||||
#define GDCORE_EXPRESSIONPARSER_H
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ParserCallbacks;
|
||||
class ObjectsContainer;
|
||||
class Platform;
|
||||
class ParameterMetadata;
|
||||
class ExpressionMetadata;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/** \brief Parse an expression
|
||||
*
|
||||
* Parse an expression, calling callbacks when a token is reached
|
||||
* \see gd::ParserCallbacks
|
||||
*/
|
||||
class GD_CORE_API ExpressionParser {
|
||||
public:
|
||||
ExpressionParser(const gd::String &expressionPlainString_);
|
||||
virtual ~ExpressionParser(){};
|
||||
|
||||
/**
|
||||
* \brief Parse the expression, calling each functor when necessary
|
||||
* \return True if expression was correctly parsed.
|
||||
*/
|
||||
bool ParseMathExpression(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
gd::ParserCallbacks &callbacks);
|
||||
|
||||
/**
|
||||
* \brief Parse the expression, calling each functor when necessary
|
||||
* \return True if expression was correctly parsed.
|
||||
*/
|
||||
bool ParseStringExpression(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
gd::ParserCallbacks &callbacks);
|
||||
|
||||
/**
|
||||
* \brief Return the description of the error that was found
|
||||
*/
|
||||
const gd::String &GetFirstError() { return firstErrorStr; }
|
||||
|
||||
/**
|
||||
* \brief Return the position of the error that was found
|
||||
* \return The position, or gd::String::npos if no error is found
|
||||
*/
|
||||
size_t GetFirstErrorPosition() { return firstErrorPos; }
|
||||
|
||||
private:
|
||||
gd::String firstErrorStr;
|
||||
size_t firstErrorPos;
|
||||
|
||||
/**
|
||||
* Tool function to add a parameter
|
||||
*/
|
||||
bool AddParameterToList(const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
ParserCallbacks &,
|
||||
std::vector<gd::Expression> ¶meters,
|
||||
gd::String parameterStr,
|
||||
std::vector<gd::ParameterMetadata> parametersInfos,
|
||||
const size_t positionInExpression);
|
||||
|
||||
/**
|
||||
* Tool function to prepare a parameter
|
||||
*/
|
||||
bool PrepareParameter(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
ParserCallbacks &,
|
||||
gd::Expression ¶meter,
|
||||
const gd::ParameterMetadata ¶metersInfo,
|
||||
const size_t positionInExpression);
|
||||
|
||||
/**
|
||||
* Return the minimal number of parameters which can be used when calling an
|
||||
* expression ( i.e. ParametersCount-OptionalParameters-CodeOnlyParameters )
|
||||
*/
|
||||
size_t GetMinimalParametersNumber(
|
||||
const std::vector<gd::ParameterMetadata> ¶metersInfos);
|
||||
|
||||
/**
|
||||
* Return the maximal number of parameters which can be used when calling an
|
||||
* expression ( i.e. ParametersCount-CodeOnlyParameters )
|
||||
*/
|
||||
size_t GetMaximalParametersNumber(
|
||||
const std::vector<gd::ParameterMetadata> ¶metersInfos);
|
||||
|
||||
bool ValidSyntax(const gd::String &str);
|
||||
|
||||
gd::String expressionPlainString;
|
||||
static gd::String parserSeparators;
|
||||
};
|
||||
|
||||
/** \brief Callbacks called by parser during parsing
|
||||
*
|
||||
* Parser will call the appropriate functions during parsing, allowing to do
|
||||
* special works. \see gd::ExpressionParser
|
||||
*/
|
||||
class GD_CORE_API ParserCallbacks {
|
||||
friend class ExpressionParser;
|
||||
|
||||
public:
|
||||
ParserCallbacks() : returnType("expression"){};
|
||||
virtual ~ParserCallbacks(){};
|
||||
|
||||
/**
|
||||
* \brief Get the type of the expression for which callbacks are used:
|
||||
* "expression" or "string".
|
||||
*/
|
||||
const gd::String &GetReturnType() { return returnType; }
|
||||
|
||||
virtual void OnConstantToken(gd::String text) = 0;
|
||||
|
||||
virtual void OnStaticFunction(
|
||||
gd::String functionName,
|
||||
const std::vector<gd::Expression> ¶meters,
|
||||
const gd::ExpressionMetadata &expressionInfo) = 0;
|
||||
|
||||
virtual void OnObjectFunction(
|
||||
gd::String functionName,
|
||||
const std::vector<gd::Expression> ¶meters,
|
||||
const gd::ExpressionMetadata &expressionInfo) = 0;
|
||||
|
||||
virtual void OnObjectBehaviorFunction(
|
||||
gd::String functionName,
|
||||
const std::vector<gd::Expression> ¶meters,
|
||||
const gd::ExpressionMetadata &expressionInfo) = 0;
|
||||
|
||||
virtual bool OnSubMathExpression(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
gd::Expression &expression) = 0;
|
||||
virtual bool OnSubTextExpression(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
gd::Expression &expression) = 0;
|
||||
|
||||
/**
|
||||
* \brief Return the description of the error that was found
|
||||
*/
|
||||
const gd::String &GetFirstError() { return firstErrorStr; }
|
||||
|
||||
/**
|
||||
* \brief Return the position of the error that was found
|
||||
* \return The position, or gd::String::npos if no error is found
|
||||
*/
|
||||
size_t GetFirstErrorPosition() { return firstErrorPos; }
|
||||
|
||||
protected:
|
||||
gd::String firstErrorStr;
|
||||
size_t firstErrorPos;
|
||||
|
||||
private:
|
||||
/**
|
||||
* \brief Set the return type of the expression: Done by ExpressionParser
|
||||
* according to which Parse* method is called. \see gd::ExpressionParser
|
||||
*/
|
||||
void SetReturnType(gd::String type) { returnType = type; }
|
||||
|
||||
gd::String returnType; // The type of the expression ("expression" (default),
|
||||
// "string"...)
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDEXPRESSIONPARSER_H
|
@@ -22,15 +22,6 @@ 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(
|
||||
@@ -76,7 +67,7 @@ size_t GetMaximumParametersNumber(
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<ExpressionParserDiagnostic> ExpressionParser2::ValidateFunction(
|
||||
const gd::FunctionNode& function, size_t functionStartPosition) {
|
||||
const gd::FunctionCallNode& function, size_t functionStartPosition) {
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(
|
||||
function.expressionMetadata)) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
@@ -118,11 +109,13 @@ std::unique_ptr<ExpressionParserDiagnostic> ExpressionParser2::ValidateFunction(
|
||||
}
|
||||
|
||||
std::unique_ptr<TextNode> ExpressionParser2::ReadText() {
|
||||
SkipWhitespace();
|
||||
if (!IsAnyChar("\"")) {
|
||||
size_t textStartPosition = GetCurrentPosition();
|
||||
SkipAllWhitespaces();
|
||||
if (!CheckIfChar(IsQuote)) {
|
||||
auto text = gd::make_unique<TextNode>("");
|
||||
text->diagnostic =
|
||||
RaiseSyntaxError(_("A text must start with a double quote (\")."));
|
||||
text->location = ExpressionParserLocation(textStartPosition, GetCurrentPosition());
|
||||
return text;
|
||||
}
|
||||
SkipChar();
|
||||
@@ -157,6 +150,7 @@ std::unique_ptr<TextNode> ExpressionParser2::ReadText() {
|
||||
}
|
||||
|
||||
auto text = gd::make_unique<TextNode>(parsedText);
|
||||
text->location = ExpressionParserLocation(textStartPosition, GetCurrentPosition());
|
||||
if (!textParsingHasEnded) {
|
||||
text->diagnostic =
|
||||
RaiseSyntaxError(_("A text must end with a double quote (\"). Add a "
|
||||
@@ -167,24 +161,25 @@ std::unique_ptr<TextNode> ExpressionParser2::ReadText() {
|
||||
}
|
||||
|
||||
std::unique_ptr<NumberNode> ExpressionParser2::ReadNumber() {
|
||||
SkipWhitespace();
|
||||
size_t numberStartPosition = GetCurrentPosition();
|
||||
SkipAllWhitespaces();
|
||||
gd::String parsedNumber;
|
||||
|
||||
bool numberHasStarted = false;
|
||||
bool digitFound = false;
|
||||
bool dotFound = false;
|
||||
while (!IsEndReached()) {
|
||||
if (IsAnyChar("0")) {
|
||||
if (CheckIfChar(IsZeroDigit)) {
|
||||
numberHasStarted = true;
|
||||
digitFound = true;
|
||||
if (!parsedNumber.empty()) { // Ignore leading 0s.
|
||||
parsedNumber += GetCurrentChar();
|
||||
}
|
||||
} else if (IsAnyChar("123456789")) {
|
||||
} else if (CheckIfChar(IsNonZeroDigit)) {
|
||||
numberHasStarted = true;
|
||||
digitFound = true;
|
||||
parsedNumber += GetCurrentChar();
|
||||
} else if (IsAnyChar(".") && !dotFound) {
|
||||
} else if (CheckIfChar(IsDot) && !dotFound) {
|
||||
numberHasStarted = true;
|
||||
dotFound = true;
|
||||
if (parsedNumber == "") {
|
||||
@@ -209,6 +204,7 @@ std::unique_ptr<NumberNode> ExpressionParser2::ReadNumber() {
|
||||
// valid in most languages so we allow this.
|
||||
|
||||
auto number = gd::make_unique<NumberNode>(parsedNumber);
|
||||
number->location = ExpressionParserLocation(numberStartPosition, GetCurrentPosition());
|
||||
if (!numberHasStarted || !digitFound) {
|
||||
number->diagnostic = RaiseSyntaxError(
|
||||
_("A number was expected. You must enter a number here."));
|
||||
|
@@ -48,8 +48,9 @@ class GD_CORE_API ExpressionParser2 {
|
||||
*
|
||||
* \param type Type of the expression: "string", "number",
|
||||
* type supported by gd::ParameterMetadata::IsObject, types supported by
|
||||
* gd::ParameterMetadata::IsExpression or "unknown". \param expression The
|
||||
* expression to parse \param objectName Specify the object name, only for the
|
||||
* gd::ParameterMetadata::IsExpression or "unknown".
|
||||
* \param expression The expression to parse
|
||||
* \param objectName Specify the object name, only for the
|
||||
* case of "objectvar" type.
|
||||
*
|
||||
* \return The node representing the expression as a parsed tree.
|
||||
@@ -71,18 +72,21 @@ class GD_CORE_API ExpressionParser2 {
|
||||
///@{
|
||||
std::unique_ptr<ExpressionNode> Start(const gd::String &type,
|
||||
const gd::String &objectName = "") {
|
||||
size_t expressionStartPosition = GetCurrentPosition();
|
||||
auto expression = Expression(type, objectName);
|
||||
|
||||
// Check for extra characters at the end of the expression
|
||||
if (!IsEndReached()) {
|
||||
auto op = gd::make_unique<OperatorNode>();
|
||||
op->op = ' ';
|
||||
auto op = gd::make_unique<OperatorNode>(type, ' ');
|
||||
op->leftHandSide = std::move(expression);
|
||||
op->rightHandSide = ReadUntilEnd("unknown");
|
||||
|
||||
op->rightHandSide->diagnostic = RaiseSyntaxError(
|
||||
_("The expression has extra character at the end that should be "
|
||||
"removed (or completed if your expression is not finished)."));
|
||||
|
||||
op->location = ExpressionParserLocation(expressionStartPosition,
|
||||
GetCurrentPosition());
|
||||
return std::move(op);
|
||||
}
|
||||
|
||||
@@ -91,22 +95,24 @@ class GD_CORE_API ExpressionParser2 {
|
||||
|
||||
std::unique_ptr<ExpressionNode> Expression(
|
||||
const gd::String &type, const gd::String &objectName = "") {
|
||||
SkipWhitespace();
|
||||
SkipAllWhitespaces();
|
||||
|
||||
size_t expressionStartPosition = GetCurrentPosition();
|
||||
std::unique_ptr<ExpressionNode> leftHandSide = Term(type, objectName);
|
||||
|
||||
SkipWhitespace();
|
||||
SkipAllWhitespaces();
|
||||
|
||||
if (IsEndReached()) return leftHandSide;
|
||||
if (IsAnyChar(",)]")) return leftHandSide;
|
||||
if (IsAnyChar(EXPRESSION_OPERATORS)) {
|
||||
auto op = gd::make_unique<OperatorNode>();
|
||||
op->op = GetCurrentChar();
|
||||
if (CheckIfChar(IsExpressionEndingChar)) return leftHandSide;
|
||||
if (CheckIfChar(IsExpressionOperator)) {
|
||||
auto op = gd::make_unique<OperatorNode>(type, GetCurrentChar());
|
||||
op->leftHandSide = std::move(leftHandSide);
|
||||
op->diagnostic = ValidateOperator(type, GetCurrentChar());
|
||||
SkipChar();
|
||||
op->rightHandSide = Expression(type, objectName);
|
||||
|
||||
op->location = ExpressionParserLocation(expressionStartPosition,
|
||||
GetCurrentPosition());
|
||||
return std::move(op);
|
||||
}
|
||||
|
||||
@@ -124,31 +130,35 @@ class GD_CORE_API ExpressionParser2 {
|
||||
"properly written.");
|
||||
}
|
||||
|
||||
auto op = gd::make_unique<OperatorNode>();
|
||||
op->op = ' ';
|
||||
auto op = gd::make_unique<OperatorNode>(type, ' ');
|
||||
op->leftHandSide = std::move(leftHandSide);
|
||||
op->rightHandSide = Expression(type, objectName);
|
||||
op->location =
|
||||
ExpressionParserLocation(expressionStartPosition, GetCurrentPosition());
|
||||
return std::move(op);
|
||||
}
|
||||
|
||||
std::unique_ptr<ExpressionNode> Term(const gd::String &type,
|
||||
const gd::String &objectName) {
|
||||
SkipWhitespace();
|
||||
SkipAllWhitespaces();
|
||||
|
||||
size_t expressionStartPosition = GetCurrentPosition();
|
||||
std::unique_ptr<ExpressionNode> factor = Factor(type, objectName);
|
||||
SkipWhitespace();
|
||||
|
||||
SkipAllWhitespaces();
|
||||
|
||||
// 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();
|
||||
while (CheckIfChar(IsTermOperator)) {
|
||||
auto op = gd::make_unique<OperatorNode>(type, GetCurrentChar());
|
||||
op->leftHandSide = std::move(factor);
|
||||
op->diagnostic = ValidateOperator(type, GetCurrentChar());
|
||||
SkipChar();
|
||||
op->rightHandSide = Factor(type, objectName);
|
||||
SkipWhitespace();
|
||||
op->location = ExpressionParserLocation(expressionStartPosition,
|
||||
GetCurrentPosition());
|
||||
SkipAllWhitespaces();
|
||||
|
||||
factor = std::move(op);
|
||||
}
|
||||
@@ -158,12 +168,12 @@ class GD_CORE_API ExpressionParser2 {
|
||||
|
||||
std::unique_ptr<ExpressionNode> Factor(const gd::String &type,
|
||||
const gd::String &objectName) {
|
||||
SkipWhitespace();
|
||||
SkipAllWhitespaces();
|
||||
|
||||
size_t expressionStartPosition = GetCurrentPosition();
|
||||
std::unique_ptr<ExpressionNode> factor;
|
||||
|
||||
if (IsAnyChar(QUOTE)) {
|
||||
if (CheckIfChar(IsQuote)) {
|
||||
factor = ReadText();
|
||||
if (type == "number")
|
||||
factor->diagnostic =
|
||||
@@ -173,14 +183,17 @@ class GD_CORE_API ExpressionParser2 {
|
||||
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());
|
||||
} else if (CheckIfChar(IsUnaryOperator)) {
|
||||
auto unaryOperator =
|
||||
gd::make_unique<UnaryOperatorNode>(type, GetCurrentChar());
|
||||
unaryOperator->diagnostic = ValidateUnaryOperator(type, GetCurrentChar());
|
||||
SkipChar();
|
||||
unaryOperator->factor = Factor(type, objectName);
|
||||
|
||||
unaryOperator->location = ExpressionParserLocation(
|
||||
expressionStartPosition, GetCurrentPosition());
|
||||
factor = std::move(unaryOperator);
|
||||
} else if (IsAnyChar(NUMBER_FIRST_CHAR)) {
|
||||
} else if (CheckIfChar(IsNumberFirstChar)) {
|
||||
factor = ReadNumber();
|
||||
if (type == "string")
|
||||
factor->diagnostic = RaiseTypeError(
|
||||
@@ -190,16 +203,16 @@ class GD_CORE_API ExpressionParser2 {
|
||||
factor->diagnostic = RaiseTypeError(
|
||||
_("You entered a number, but this type was expected:") + type,
|
||||
expressionStartPosition);
|
||||
} else if (IsAnyChar("(")) {
|
||||
} else if (CheckIfChar(IsOpeningParenthesis)) {
|
||||
SkipChar();
|
||||
factor = SubExpression(type, objectName);
|
||||
|
||||
if (!IsAnyChar(")")) {
|
||||
if (!CheckIfChar(IsClosingParenthesis)) {
|
||||
factor->diagnostic =
|
||||
RaiseSyntaxError(_("Missing a closing parenthesis. Add a closing "
|
||||
"parenthesis for each opening parenthesis."));
|
||||
}
|
||||
SkipIfIsAnyChar(")");
|
||||
SkipIfChar(IsClosingParenthesis);
|
||||
} else if (IsIdentifierAllowedChar()) {
|
||||
// This is a place where the grammar differs according to the
|
||||
// type being expected.
|
||||
@@ -218,92 +231,132 @@ class GD_CORE_API ExpressionParser2 {
|
||||
|
||||
std::unique_ptr<SubExpressionNode> SubExpression(
|
||||
const gd::String &type, const gd::String &objectName) {
|
||||
return std::move(
|
||||
gd::make_unique<SubExpressionNode>(Expression(type, objectName)));
|
||||
size_t expressionStartPosition = GetCurrentPosition();
|
||||
auto subExpression =
|
||||
gd::make_unique<SubExpressionNode>(type, Expression(type, objectName));
|
||||
subExpression->location =
|
||||
ExpressionParserLocation(expressionStartPosition, GetCurrentPosition());
|
||||
|
||||
return std::move(subExpression);
|
||||
};
|
||||
|
||||
std::unique_ptr<IdentifierOrFunctionOrEmptyNode> Identifier(
|
||||
const gd::String &type) {
|
||||
size_t identifierStartPosition = GetCurrentPosition();
|
||||
gd::String name = ReadIdentifierName();
|
||||
std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
|
||||
Identifier(const gd::String &type) {
|
||||
auto identifierAndLocation = ReadIdentifierName();
|
||||
gd::String name = identifierAndLocation.name;
|
||||
auto nameLocation = identifierAndLocation.location;
|
||||
|
||||
SkipWhitespace();
|
||||
SkipAllWhitespaces();
|
||||
|
||||
// We consider a namespace separator to be allowed here and be part of the
|
||||
// function name (or object name, but object names are not allowed to
|
||||
// contain a ":"). This is because functions from extensions have their
|
||||
// extension name prefix, and separated by the namespace separator. This
|
||||
// could maybe be refactored to create different nodes in the future.
|
||||
if (IsNamespaceSeparator()) {
|
||||
SkipNamespaceSeparator();
|
||||
SkipAllWhitespaces();
|
||||
|
||||
auto postNamespaceIdentifierAndLocation = ReadIdentifierName();
|
||||
name += NAMESPACE_SEPARATOR;
|
||||
name += ReadIdentifierName();
|
||||
name += postNamespaceIdentifierAndLocation.name;
|
||||
ExpressionParserLocation completeNameLocation(
|
||||
nameLocation.GetStartPosition(),
|
||||
postNamespaceIdentifierAndLocation.location.GetEndPosition());
|
||||
nameLocation = completeNameLocation;
|
||||
}
|
||||
|
||||
if (IsAnyChar("(")) {
|
||||
SkipChar();
|
||||
return FreeFunction(type, name, identifierStartPosition);
|
||||
} else if (IsAnyChar(DOT)) {
|
||||
SkipChar();
|
||||
if (CheckIfChar(IsOpeningParenthesis)) {
|
||||
ExpressionParserLocation openingParenthesisLocation = SkipChar();
|
||||
return FreeFunction(type, name, nameLocation, openingParenthesisLocation);
|
||||
} else if (CheckIfChar(IsDot)) {
|
||||
ExpressionParserLocation dotLocation = SkipChar();
|
||||
SkipAllWhitespaces();
|
||||
return ObjectFunctionOrBehaviorFunction(
|
||||
type, name, identifierStartPosition);
|
||||
type, name, nameLocation, dotLocation);
|
||||
} else {
|
||||
auto identifier = gd::make_unique<IdentifierNode>(name, type);
|
||||
if (type == "string") {
|
||||
identifier->diagnostic =
|
||||
RaiseTypeError(_("You must wrap your text inside double quotes "
|
||||
"(example: \"Hello world\")."),
|
||||
identifierStartPosition);
|
||||
nameLocation.GetStartPosition());
|
||||
} else if (type == "number") {
|
||||
identifier->diagnostic = RaiseTypeError(_("You must enter a number."),
|
||||
identifierStartPosition);
|
||||
identifier->diagnostic = RaiseTypeError(
|
||||
_("You must enter a number."), nameLocation.GetStartPosition());
|
||||
} else if (!gd::ParameterMetadata::IsObject(type)) {
|
||||
identifier->diagnostic = RaiseTypeError(
|
||||
_("You've entered a name, but this type was expected:") + type,
|
||||
identifierStartPosition);
|
||||
nameLocation.GetStartPosition());
|
||||
}
|
||||
|
||||
identifier->location = ExpressionParserLocation(
|
||||
nameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
return std::move(identifier);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<VariableNode> Variable(const gd::String &type,
|
||||
const gd::String &objectName) {
|
||||
size_t identifierStartPosition = GetCurrentPosition();
|
||||
auto identifierAndLocation = ReadIdentifierName();
|
||||
const gd::String &name = identifierAndLocation.name;
|
||||
const auto &nameLocation = identifierAndLocation.location;
|
||||
|
||||
gd::String name = ReadIdentifierName();
|
||||
auto variable = gd::make_unique<VariableNode>(type, name, objectName);
|
||||
variable->child = VariableAccessorOrVariableBracketAccessor();
|
||||
|
||||
variable->location = ExpressionParserLocation(
|
||||
nameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
variable->nameLocation = nameLocation;
|
||||
return std::move(variable);
|
||||
}
|
||||
|
||||
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
|
||||
VariableAccessorOrVariableBracketAccessor() {
|
||||
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode> child;
|
||||
SkipWhitespace();
|
||||
if (IsAnyChar("[")) {
|
||||
size_t childStartPosition = GetCurrentPosition();
|
||||
|
||||
SkipAllWhitespaces();
|
||||
if (CheckIfChar(IsOpeningSquareBracket)) {
|
||||
SkipChar();
|
||||
child =
|
||||
auto child =
|
||||
gd::make_unique<VariableBracketAccessorNode>(Expression("string"));
|
||||
|
||||
if (!IsAnyChar("]")) {
|
||||
if (!CheckIfChar(IsClosingSquareBracket)) {
|
||||
child->diagnostic =
|
||||
RaiseSyntaxError(_("Missing a closing bracket. Add a closing "
|
||||
"bracket for each opening bracket."));
|
||||
}
|
||||
SkipIfIsAnyChar("]");
|
||||
SkipIfChar(IsClosingSquareBracket);
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
} else if (IsAnyChar(DOT)) {
|
||||
SkipChar();
|
||||
SkipWhitespace();
|
||||
child->location =
|
||||
ExpressionParserLocation(childStartPosition, GetCurrentPosition());
|
||||
|
||||
child = gd::make_unique<VariableAccessorNode>(ReadIdentifierName());
|
||||
return std::move(child);
|
||||
} else if (CheckIfChar(IsDot)) {
|
||||
auto dotLocation = SkipChar();
|
||||
SkipAllWhitespaces();
|
||||
|
||||
auto identifierAndLocation = ReadIdentifierName();
|
||||
auto child =
|
||||
gd::make_unique<VariableAccessorNode>(identifierAndLocation.name);
|
||||
child->child = VariableAccessorOrVariableBracketAccessor();
|
||||
child->nameLocation = identifierAndLocation.location;
|
||||
child->dotLocation = dotLocation;
|
||||
child->location =
|
||||
ExpressionParserLocation(childStartPosition, GetCurrentPosition());
|
||||
|
||||
return std::move(child);
|
||||
}
|
||||
|
||||
return child;
|
||||
return std::move(
|
||||
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>());
|
||||
}
|
||||
|
||||
std::unique_ptr<FunctionNode> FreeFunction(const gd::String &type,
|
||||
const gd::String &functionFullName,
|
||||
size_t functionStartPosition) {
|
||||
std::unique_ptr<FunctionCallNode> FreeFunction(
|
||||
const gd::String &type,
|
||||
const gd::String &functionFullName,
|
||||
const ExpressionParserLocation &identifierLocation,
|
||||
const ExpressionParserLocation &openingParenthesisLocation) {
|
||||
// TODO: error if trying to use function for type != "number" && != "string"
|
||||
// + Test for it
|
||||
|
||||
@@ -315,32 +368,49 @@ class GD_CORE_API ExpressionParser2 {
|
||||
: 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);
|
||||
auto parametersNode = Parameters(metadata.parameters);
|
||||
auto function = gd::make_unique<FunctionCallNode>(
|
||||
type, std::move(parametersNode.parameters), metadata, functionFullName);
|
||||
function->diagnostic = std::move(parametersNode.diagnostic);
|
||||
if (!function->diagnostic)
|
||||
function->diagnostic = ValidateFunction(*function, functionStartPosition);
|
||||
function->diagnostic =
|
||||
ValidateFunction(*function, identifierLocation.GetStartPosition());
|
||||
|
||||
function->location = ExpressionParserLocation(
|
||||
identifierLocation.GetStartPosition(), GetCurrentPosition());
|
||||
function->functionNameLocation = identifierLocation;
|
||||
function->openingParenthesisLocation = openingParenthesisLocation;
|
||||
function->closingParenthesisLocation =
|
||||
parametersNode.closingParenthesisLocation;
|
||||
return std::move(function);
|
||||
}
|
||||
|
||||
std::unique_ptr<FunctionOrEmptyNode> ObjectFunctionOrBehaviorFunction(
|
||||
std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode>
|
||||
ObjectFunctionOrBehaviorFunction(
|
||||
const gd::String &type,
|
||||
const gd::String &objectName,
|
||||
size_t functionStartPosition) {
|
||||
gd::String objectFunctionOrBehaviorName = ReadIdentifierName();
|
||||
const ExpressionParserLocation &objectNameLocation,
|
||||
const ExpressionParserLocation &objectNameDotLocation) {
|
||||
auto identifierAndLocation = ReadIdentifierName();
|
||||
const gd::String &objectFunctionOrBehaviorName = identifierAndLocation.name;
|
||||
const auto &objectFunctionOrBehaviorNameLocation =
|
||||
identifierAndLocation.location;
|
||||
|
||||
SkipWhitespace();
|
||||
SkipAllWhitespaces();
|
||||
|
||||
if (IsNamespaceSeparator()) {
|
||||
SkipNamespaceSeparator();
|
||||
ExpressionParserLocation namespaceSeparatorLocation =
|
||||
SkipNamespaceSeparator();
|
||||
SkipAllWhitespaces();
|
||||
return BehaviorFunction(type,
|
||||
objectName,
|
||||
objectFunctionOrBehaviorName,
|
||||
functionStartPosition);
|
||||
} else if (IsAnyChar("(")) {
|
||||
SkipChar();
|
||||
objectNameLocation,
|
||||
objectNameDotLocation,
|
||||
objectFunctionOrBehaviorNameLocation,
|
||||
namespaceSeparatorLocation);
|
||||
} else if (CheckIfChar(IsOpeningParenthesis)) {
|
||||
ExpressionParserLocation openingParenthesisLocation = SkipChar();
|
||||
|
||||
gd::String objectType =
|
||||
GetTypeOfObject(globalObjectsContainer, objectsContainer, objectName);
|
||||
@@ -354,40 +424,60 @@ class GD_CORE_API ExpressionParser2 {
|
||||
: 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);
|
||||
auto parametersNode = Parameters(metadata.parameters, objectName);
|
||||
auto function = gd::make_unique<FunctionCallNode>(
|
||||
type,
|
||||
objectName,
|
||||
std::move(parametersNode.parameters),
|
||||
metadata,
|
||||
objectFunctionOrBehaviorName);
|
||||
function->diagnostic = std::move(parametersNode.diagnostic);
|
||||
if (!function->diagnostic)
|
||||
function->diagnostic =
|
||||
ValidateFunction(*function, functionStartPosition);
|
||||
ValidateFunction(*function, objectNameLocation.GetStartPosition());
|
||||
|
||||
function->location = ExpressionParserLocation(
|
||||
objectNameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
function->objectNameLocation = objectNameLocation;
|
||||
function->objectNameDotLocation = objectNameDotLocation;
|
||||
function->functionNameLocation = objectFunctionOrBehaviorNameLocation;
|
||||
function->openingParenthesisLocation = openingParenthesisLocation;
|
||||
function->closingParenthesisLocation =
|
||||
parametersNode.closingParenthesisLocation;
|
||||
return std::move(function);
|
||||
}
|
||||
|
||||
auto node = gd::make_unique<EmptyNode>(type);
|
||||
auto node = gd::make_unique<ObjectFunctionNameNode>(
|
||||
type, objectName, objectFunctionOrBehaviorName);
|
||||
node->diagnostic = RaiseSyntaxError(
|
||||
_("An opening parenthesis (for an object expression), or double colon "
|
||||
"(::) was expected (for a behavior expression)."));
|
||||
|
||||
node->location = ExpressionParserLocation(
|
||||
objectNameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
node->objectNameLocation = objectNameLocation;
|
||||
node->objectNameDotLocation = objectNameDotLocation;
|
||||
node->objectFunctionOrBehaviorNameLocation =
|
||||
objectFunctionOrBehaviorNameLocation;
|
||||
return std::move(node);
|
||||
}
|
||||
|
||||
std::unique_ptr<FunctionOrEmptyNode> BehaviorFunction(
|
||||
std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode> BehaviorFunction(
|
||||
const gd::String &type,
|
||||
const gd::String &objectName,
|
||||
const gd::String &behaviorName,
|
||||
size_t functionStartPosition) {
|
||||
gd::String functionName = ReadIdentifierName();
|
||||
const ExpressionParserLocation &objectNameLocation,
|
||||
const ExpressionParserLocation &objectNameDotLocation,
|
||||
const ExpressionParserLocation &behaviorNameLocation,
|
||||
const ExpressionParserLocation &behaviorNameNamespaceSeparatorLocation) {
|
||||
auto identifierAndLocation = ReadIdentifierName();
|
||||
const gd::String &functionName = identifierAndLocation.name;
|
||||
const auto &functionNameLocation = identifierAndLocation.location;
|
||||
|
||||
SkipWhitespace();
|
||||
SkipAllWhitespaces();
|
||||
|
||||
if (IsAnyChar("(")) {
|
||||
SkipChar();
|
||||
if (CheckIfChar(IsOpeningParenthesis)) {
|
||||
ExpressionParserLocation openingParenthesisLocation = SkipChar();
|
||||
|
||||
gd::String behaviorType = GetTypeOfBehavior(
|
||||
globalObjectsContainer, objectsContainer, behaviorName);
|
||||
@@ -400,35 +490,61 @@ class GD_CORE_API ExpressionParser2 {
|
||||
: MetadataProvider::GetBehaviorStrExpressionMetadata(
|
||||
platform, behaviorType, functionName);
|
||||
|
||||
auto parametersAndError =
|
||||
auto parametersNode =
|
||||
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);
|
||||
auto function = gd::make_unique<FunctionCallNode>(
|
||||
type,
|
||||
objectName,
|
||||
behaviorName,
|
||||
std::move(parametersNode.parameters),
|
||||
metadata,
|
||||
functionName);
|
||||
function->diagnostic = std::move(parametersNode.diagnostic);
|
||||
if (!function->diagnostic)
|
||||
function->diagnostic =
|
||||
ValidateFunction(*function, functionStartPosition);
|
||||
ValidateFunction(*function, objectNameLocation.GetStartPosition());
|
||||
|
||||
function->location = ExpressionParserLocation(
|
||||
objectNameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
function->objectNameLocation = objectNameLocation;
|
||||
function->objectNameDotLocation = objectNameDotLocation;
|
||||
function->behaviorNameLocation = behaviorNameLocation;
|
||||
function->behaviorNameNamespaceSeparatorLocation =
|
||||
behaviorNameNamespaceSeparatorLocation;
|
||||
function->openingParenthesisLocation = openingParenthesisLocation;
|
||||
function->closingParenthesisLocation =
|
||||
parametersNode.closingParenthesisLocation;
|
||||
function->functionNameLocation = functionNameLocation;
|
||||
return std::move(function);
|
||||
} else {
|
||||
auto node = gd::make_unique<EmptyNode>(type);
|
||||
auto node = gd::make_unique<ObjectFunctionNameNode>(
|
||||
type, objectName, behaviorName, functionName);
|
||||
node->diagnostic = RaiseSyntaxError(
|
||||
_("An opening parenthesis was expected here to call a function."));
|
||||
|
||||
node->location = ExpressionParserLocation(
|
||||
objectNameLocation.GetStartPosition(), GetCurrentPosition());
|
||||
node->objectNameLocation = objectNameLocation;
|
||||
node->objectNameDotLocation = objectNameDotLocation;
|
||||
node->objectFunctionOrBehaviorNameLocation = behaviorNameLocation;
|
||||
node->behaviorNameNamespaceSeparatorLocation =
|
||||
behaviorNameNamespaceSeparatorLocation;
|
||||
node->behaviorFunctionNameLocation = functionNameLocation;
|
||||
return std::move(node);
|
||||
}
|
||||
}
|
||||
|
||||
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 = "") {
|
||||
// A temporary node that will be integrated into function nodes.
|
||||
struct ParametersNode {
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters;
|
||||
std::unique_ptr<gd::ExpressionParserError> diagnostic;
|
||||
ExpressionParserLocation closingParenthesisLocation;
|
||||
};
|
||||
|
||||
ParametersNode Parameters(
|
||||
std::vector<gd::ParameterMetadata> parameterMetadata,
|
||||
const gd::String &objectName = "",
|
||||
const gd::String &behaviorName = "") {
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters;
|
||||
|
||||
// By convention, object is always the first parameter, and behavior the
|
||||
@@ -437,11 +553,12 @@ class GD_CORE_API ExpressionParser2 {
|
||||
WrittenParametersFirstIndex(objectName, behaviorName);
|
||||
|
||||
while (!IsEndReached()) {
|
||||
SkipWhitespace();
|
||||
SkipAllWhitespaces();
|
||||
|
||||
if (IsAnyChar(")")) {
|
||||
SkipChar();
|
||||
return std::make_pair(std::move(parameters), nullptr);
|
||||
if (CheckIfChar(IsClosingParenthesis)) {
|
||||
auto closingParenthesisLocation = SkipChar();
|
||||
return ParametersNode{
|
||||
std::move(parameters), nullptr, closingParenthesisLocation};
|
||||
} else {
|
||||
if (parameterIndex < parameterMetadata.size()) {
|
||||
const gd::String &type = parameterMetadata[parameterIndex].GetType();
|
||||
@@ -479,16 +596,18 @@ class GD_CORE_API ExpressionParser2 {
|
||||
GetCurrentPosition());
|
||||
}
|
||||
|
||||
SkipWhitespace();
|
||||
SkipIfIsAnyChar(PARAMETERS_SEPARATOR);
|
||||
SkipAllWhitespaces();
|
||||
SkipIfChar(IsParameterSeparator);
|
||||
parameterIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(
|
||||
ExpressionParserLocation invalidClosingParenthesisLocation;
|
||||
return ParametersNode{
|
||||
std::move(parameters),
|
||||
RaiseSyntaxError(_("The list of parameters is not terminated. Add a "
|
||||
"closing parenthesis to end the parameters.")));
|
||||
"closing parenthesis to end the parameters.")),
|
||||
invalidClosingParenthesisLocation};
|
||||
}
|
||||
///@}
|
||||
|
||||
@@ -497,7 +616,7 @@ class GD_CORE_API ExpressionParser2 {
|
||||
*/
|
||||
///@{
|
||||
std::unique_ptr<ExpressionParserDiagnostic> ValidateFunction(
|
||||
const gd::FunctionNode &function, size_t functionStartPosition);
|
||||
const gd::FunctionCallNode &function, size_t functionStartPosition);
|
||||
|
||||
std::unique_ptr<ExpressionParserDiagnostic> ValidateOperator(
|
||||
const gd::String &type, gd::String::value_type operatorChar) {
|
||||
@@ -525,7 +644,8 @@ class GD_CORE_API ExpressionParser2 {
|
||||
} else if (gd::ParameterMetadata::IsObject(type)) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("Operators (+, -, /, *) can't be used with an object name. Remove the operator."),
|
||||
_("Operators (+, -, /, *) can't be used with an object name. Remove "
|
||||
"the operator."),
|
||||
GetCurrentPosition());
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
@@ -561,7 +681,8 @@ class GD_CORE_API ExpressionParser2 {
|
||||
} else if (gd::ParameterMetadata::IsObject(type)) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
_("Operators (+, -) can't be used with an object name. Remove the operator."),
|
||||
_("Operators (+, -) can't be used with an object name. Remove the "
|
||||
"operator."),
|
||||
GetCurrentPosition());
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
@@ -579,55 +700,133 @@ class GD_CORE_API ExpressionParser2 {
|
||||
* Read tokens or characters
|
||||
*/
|
||||
///@{
|
||||
void SkipChar() { currentPosition++; }
|
||||
ExpressionParserLocation SkipChar() {
|
||||
size_t startPosition = currentPosition;
|
||||
return ExpressionParserLocation(startPosition, ++currentPosition);
|
||||
}
|
||||
|
||||
void SkipWhitespace() {
|
||||
void SkipAllWhitespaces() {
|
||||
while (currentPosition < expression.size() &&
|
||||
WHITESPACES.find(expression[currentPosition]) != gd::String::npos) {
|
||||
IsWhitespace(expression[currentPosition])) {
|
||||
currentPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
void SkipIfIsAnyChar(const gd::String &allowedCharacters) {
|
||||
if (IsAnyChar(allowedCharacters)) {
|
||||
void SkipIfChar(
|
||||
const std::function<bool(gd::String::value_type)> &predicate) {
|
||||
if (CheckIfChar(predicate)) {
|
||||
currentPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
void SkipNamespaceSeparator() {
|
||||
ExpressionParserLocation SkipNamespaceSeparator() {
|
||||
size_t startPosition = currentPosition;
|
||||
// Namespace separator is a special kind of delimiter as it is 2 characters
|
||||
// long
|
||||
if (IsNamespaceSeparator()) {
|
||||
currentPosition += NAMESPACE_SEPARATOR.size();
|
||||
}
|
||||
|
||||
return ExpressionParserLocation(startPosition, currentPosition);
|
||||
}
|
||||
|
||||
bool IsAnyChar(const gd::String &allowedCharacters) {
|
||||
if (currentPosition < expression.size() &&
|
||||
allowedCharacters.find(expression[currentPosition]) !=
|
||||
gd::String::npos) {
|
||||
return true;
|
||||
}
|
||||
bool CheckIfChar(
|
||||
const std::function<bool(gd::String::value_type)> &predicate) {
|
||||
if (currentPosition >= expression.size()) return false;
|
||||
gd::String::value_type character = expression[currentPosition];
|
||||
|
||||
return false;
|
||||
return predicate(character);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (currentPosition >= expression.size()) return false;
|
||||
gd::String::value_type character = expression[currentPosition];
|
||||
|
||||
// Quickly compare if the character is a number or ASCII character.
|
||||
if ((character >= '0' && character <= '9') ||
|
||||
(character >= 'A' && character <= 'Z') ||
|
||||
(character >= 'a' && character <= 'z'))
|
||||
return true;
|
||||
|
||||
// Otherwise do the full check against separators forbidden in identifiers.
|
||||
if (!IsParameterSeparator(character) && !IsDot(character) &&
|
||||
!IsQuote(character) && !IsBracket(character) &&
|
||||
!IsExpressionOperator(character) && !IsTermOperator(character)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsWhitespace(gd::String::value_type character) {
|
||||
return character == ' ' || character == '\n' || character == '\r';
|
||||
}
|
||||
|
||||
static bool IsParameterSeparator(gd::String::value_type character) {
|
||||
return character == ',';
|
||||
}
|
||||
|
||||
static bool IsDot(gd::String::value_type character) {
|
||||
return character == '.';
|
||||
}
|
||||
|
||||
static bool IsQuote(gd::String::value_type character) {
|
||||
return character == '"';
|
||||
}
|
||||
|
||||
static bool IsBracket(gd::String::value_type character) {
|
||||
return character == '(' || character == ')' || character == '[' ||
|
||||
character == ']' || character == '{' || character == '}';
|
||||
}
|
||||
|
||||
static bool IsOpeningParenthesis(gd::String::value_type character) {
|
||||
return character == '(';
|
||||
}
|
||||
|
||||
static bool IsClosingParenthesis(gd::String::value_type character) {
|
||||
return character == ')';
|
||||
}
|
||||
|
||||
static bool IsOpeningSquareBracket(gd::String::value_type character) {
|
||||
return character == '[';
|
||||
}
|
||||
|
||||
static bool IsClosingSquareBracket(gd::String::value_type character) {
|
||||
return character == ']';
|
||||
}
|
||||
|
||||
static bool IsExpressionEndingChar(gd::String::value_type character) {
|
||||
return character == ',' || IsClosingParenthesis(character) ||
|
||||
IsClosingSquareBracket(character);
|
||||
}
|
||||
|
||||
static bool IsExpressionOperator(gd::String::value_type character) {
|
||||
return character == '+' || character == '-' || character == '<' ||
|
||||
character == '>' || character == '?' || character == '^' ||
|
||||
character == '=' || character == '\\' || character == ':' ||
|
||||
character == '!';
|
||||
}
|
||||
|
||||
static bool IsUnaryOperator(gd::String::value_type character) {
|
||||
return character == '+' || character == '-';
|
||||
}
|
||||
|
||||
static bool IsTermOperator(gd::String::value_type character) {
|
||||
return character == '/' || character == '*';
|
||||
}
|
||||
|
||||
static bool IsNumberFirstChar(gd::String::value_type character) {
|
||||
return character == '.' || (character >= '0' && character <= '9');
|
||||
}
|
||||
|
||||
static bool IsNonZeroDigit(gd::String::value_type character) {
|
||||
return (character >= '1' && character <= '9');
|
||||
}
|
||||
|
||||
static bool IsZeroDigit(gd::String::value_type character) {
|
||||
return character == '0';
|
||||
}
|
||||
|
||||
bool IsNamespaceSeparator() {
|
||||
// Namespace separator is a special kind of delimiter as it is 2 characters
|
||||
// long
|
||||
@@ -638,12 +837,20 @@ class GD_CORE_API ExpressionParser2 {
|
||||
|
||||
bool IsEndReached() { return currentPosition >= expression.size(); }
|
||||
|
||||
gd::String ReadIdentifierName() {
|
||||
// A temporary node used when reading an identifier
|
||||
struct IdentifierAndLocation {
|
||||
gd::String name;
|
||||
ExpressionParserLocation location;
|
||||
};
|
||||
|
||||
IdentifierAndLocation ReadIdentifierName() {
|
||||
gd::String name;
|
||||
size_t startPosition = currentPosition;
|
||||
while (currentPosition < expression.size() &&
|
||||
(IsIdentifierAllowedChar()
|
||||
// Allow whitespace in identifier name for compatibility
|
||||
|| expression[currentPosition] == ' ')) {
|
||||
||
|
||||
expression[currentPosition] == ' ')) {
|
||||
name += expression[currentPosition];
|
||||
currentPosition++;
|
||||
}
|
||||
@@ -651,12 +858,23 @@ class GD_CORE_API ExpressionParser2 {
|
||||
// Trim whitespace at the end (we allow them for compatibility inside
|
||||
// the name, but after the last character that is not whitespace, they
|
||||
// should be ignore again).
|
||||
size_t lastCharacterPos = name.find_last_not_of(WHITESPACES);
|
||||
if (!name.empty() && (lastCharacterPos + 1) < name.size()) {
|
||||
name.erase(lastCharacterPos + 1);
|
||||
if (!name.empty() && IsWhitespace(name[name.size() - 1])) {
|
||||
size_t lastCharacterPos = name.size() - 1;
|
||||
while (lastCharacterPos < name.size() &&
|
||||
IsWhitespace(name[lastCharacterPos])) {
|
||||
lastCharacterPos--;
|
||||
}
|
||||
if ((lastCharacterPos + 1) < name.size()) {
|
||||
name.erase(lastCharacterPos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
IdentifierAndLocation identifierAndLocation{
|
||||
name,
|
||||
// The location is ignoring the trailing whitespace (only whitespace
|
||||
// inside the identifier are allowed for compatibility).
|
||||
ExpressionParserLocation(startPosition, startPosition + name.size())};
|
||||
return identifierAndLocation;
|
||||
}
|
||||
|
||||
std::unique_ptr<TextNode> ReadText();
|
||||
@@ -664,24 +882,32 @@ class GD_CORE_API ExpressionParser2 {
|
||||
std::unique_ptr<NumberNode> ReadNumber();
|
||||
|
||||
std::unique_ptr<EmptyNode> ReadUntilWhitespace(gd::String type) {
|
||||
size_t startPosition = GetCurrentPosition();
|
||||
gd::String text;
|
||||
while (currentPosition < expression.size() &&
|
||||
WHITESPACES.find(expression[currentPosition]) == gd::String::npos) {
|
||||
!IsWhitespace(expression[currentPosition])) {
|
||||
text += expression[currentPosition];
|
||||
currentPosition++;
|
||||
}
|
||||
|
||||
return gd::make_unique<EmptyNode>(type, text);
|
||||
auto node = gd::make_unique<EmptyNode>(type, text);
|
||||
node->location =
|
||||
ExpressionParserLocation(startPosition, GetCurrentPosition());
|
||||
return node;
|
||||
}
|
||||
|
||||
std::unique_ptr<EmptyNode> ReadUntilEnd(gd::String type) {
|
||||
size_t startPosition = GetCurrentPosition();
|
||||
gd::String text;
|
||||
while (currentPosition < expression.size()) {
|
||||
text += expression[currentPosition];
|
||||
currentPosition++;
|
||||
}
|
||||
|
||||
return gd::make_unique<EmptyNode>(type, text);
|
||||
auto node = gd::make_unique<EmptyNode>(type, text);
|
||||
node->location =
|
||||
ExpressionParserLocation(startPosition, GetCurrentPosition());
|
||||
return node;
|
||||
}
|
||||
|
||||
size_t GetCurrentPosition() { return currentPosition; }
|
||||
@@ -746,15 +972,6 @@ class GD_CORE_API ExpressionParser2 {
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
|
||||
static gd::String NUMBER_FIRST_CHAR;
|
||||
static gd::String DOT;
|
||||
static gd::String PARAMETERS_SEPARATOR;
|
||||
static gd::String QUOTE;
|
||||
static gd::String BRACKETS;
|
||||
static gd::String EXPRESSION_OPERATORS;
|
||||
static gd::String TERM_OPERATORS;
|
||||
static gd::String UNARY_OPERATORS;
|
||||
static gd::String WHITESPACES;
|
||||
static gd::String NAMESPACE_SEPARATOR;
|
||||
};
|
||||
|
||||
|
@@ -20,6 +20,24 @@ class ExpressionMetadata;
|
||||
|
||||
namespace gd {
|
||||
|
||||
struct ExpressionParserLocation {
|
||||
ExpressionParserLocation() : isValid(false){};
|
||||
ExpressionParserLocation(size_t position)
|
||||
: isValid(true), startPosition(position), endPosition(position){};
|
||||
ExpressionParserLocation(size_t startPosition_, size_t endPosition_)
|
||||
: isValid(true),
|
||||
startPosition(startPosition_),
|
||||
endPosition(endPosition_){};
|
||||
size_t GetStartPosition() const { return startPosition; }
|
||||
size_t GetEndPosition() const { return endPosition; }
|
||||
bool IsValid() const { return isValid; }
|
||||
|
||||
private:
|
||||
bool isValid;
|
||||
size_t startPosition;
|
||||
size_t endPosition;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A diagnostic that can be attached to a gd::ExpressionNode.
|
||||
*/
|
||||
@@ -40,30 +58,25 @@ struct ExpressionParserError : public ExpressionParserDiagnostic {
|
||||
ExpressionParserError(const gd::String &type_,
|
||||
const gd::String &message_,
|
||||
size_t position_)
|
||||
: type(type_),
|
||||
message(message_),
|
||||
startPosition(position_),
|
||||
endPosition(position_){};
|
||||
: type(type_), message(message_), location(position_){};
|
||||
ExpressionParserError(const gd::String &type_,
|
||||
const gd::String &message_,
|
||||
size_t startPosition_,
|
||||
size_t endPosition_)
|
||||
: type(type_),
|
||||
message(message_),
|
||||
startPosition(startPosition_),
|
||||
endPosition(endPosition_){};
|
||||
location(startPosition_, 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; }
|
||||
size_t GetStartPosition() override { return location.GetStartPosition(); }
|
||||
size_t GetEndPosition() override { return location.GetEndPosition(); }
|
||||
|
||||
private:
|
||||
gd::String type;
|
||||
gd::String message;
|
||||
size_t startPosition;
|
||||
size_t endPosition;
|
||||
ExpressionParserLocation location;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -75,16 +88,26 @@ struct ExpressionNode {
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker){};
|
||||
|
||||
std::unique_ptr<ExpressionParserDiagnostic> diagnostic;
|
||||
ExpressionParserLocation location; ///< The location of the entire node. Some
|
||||
///nodes might have other locations stored
|
||||
///inside them. For example, a function
|
||||
///can store the position of the object
|
||||
///name, the dot, the function name,
|
||||
///etc...
|
||||
};
|
||||
|
||||
struct SubExpressionNode : public ExpressionNode {
|
||||
SubExpressionNode(std::unique_ptr<ExpressionNode> expression_)
|
||||
: expression(std::move(expression_)){};
|
||||
SubExpressionNode(const gd::String &type_,
|
||||
std::unique_ptr<ExpressionNode> expression_)
|
||||
: type(type_), expression(std::move(expression_)){};
|
||||
virtual ~SubExpressionNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitSubExpressionNode(*this);
|
||||
};
|
||||
|
||||
gd::String type; // "string", "number", type supported by
|
||||
// gd::ParameterMetadata::IsObject, types supported by
|
||||
// gd::ParameterMetadata::IsExpression or "unknown".
|
||||
std::unique_ptr<ExpressionNode> expression;
|
||||
};
|
||||
|
||||
@@ -92,6 +115,8 @@ struct SubExpressionNode : public ExpressionNode {
|
||||
* \brief An operator node. For example: "lhs + rhs".
|
||||
*/
|
||||
struct OperatorNode : public ExpressionNode {
|
||||
OperatorNode(const gd::String &type_, gd::String::value_type op_)
|
||||
: type(type_), op(op_){};
|
||||
virtual ~OperatorNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitOperatorNode(*this);
|
||||
@@ -99,6 +124,9 @@ struct OperatorNode : public ExpressionNode {
|
||||
|
||||
std::unique_ptr<ExpressionNode> leftHandSide;
|
||||
std::unique_ptr<ExpressionNode> rightHandSide;
|
||||
gd::String type; // "string", "number", type supported by
|
||||
// gd::ParameterMetadata::IsObject, types supported by
|
||||
// gd::ParameterMetadata::IsExpression or "unknown".
|
||||
gd::String::value_type op;
|
||||
};
|
||||
|
||||
@@ -106,13 +134,17 @@ struct OperatorNode : public ExpressionNode {
|
||||
* \brief A unary operator node. For example: "-2".
|
||||
*/
|
||||
struct UnaryOperatorNode : public ExpressionNode {
|
||||
UnaryOperatorNode(gd::String::value_type op_) : op(op_){};
|
||||
UnaryOperatorNode(const gd::String &type_, gd::String::value_type op_)
|
||||
: type(type_), op(op_){};
|
||||
virtual ~UnaryOperatorNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitUnaryOperatorNode(*this);
|
||||
};
|
||||
|
||||
std::unique_ptr<ExpressionNode> factor;
|
||||
gd::String type; // "string", "number", type supported by
|
||||
// gd::ParameterMetadata::IsObject, types supported by
|
||||
// gd::ParameterMetadata::IsExpression or "unknown".
|
||||
gd::String::value_type op;
|
||||
};
|
||||
|
||||
@@ -170,6 +202,8 @@ struct VariableNode : public ExpressionNode {
|
||||
|
||||
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
|
||||
child; // Can be nullptr if no accessor
|
||||
|
||||
ExpressionParserLocation nameLocation;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -185,6 +219,8 @@ struct VariableAccessorNode
|
||||
};
|
||||
|
||||
gd::String name;
|
||||
ExpressionParserLocation nameLocation;
|
||||
ExpressionParserLocation dotLocation;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -203,12 +239,14 @@ struct VariableBracketAccessorNode
|
||||
std::unique_ptr<ExpressionNode> expression;
|
||||
};
|
||||
|
||||
struct IdentifierOrFunctionOrEmptyNode : public ExpressionNode {};
|
||||
struct IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode
|
||||
: public ExpressionNode {};
|
||||
|
||||
/**
|
||||
* \brief An identifier node, usually representing an object.
|
||||
* \brief An identifier node, usually representing an object or a function name.
|
||||
*/
|
||||
struct IdentifierNode : public IdentifierOrFunctionOrEmptyNode {
|
||||
struct IdentifierNode
|
||||
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
IdentifierNode(const gd::String &identifierName_, const gd::String &type_)
|
||||
: identifierName(identifierName_), type(type_){};
|
||||
virtual ~IdentifierNode(){};
|
||||
@@ -220,64 +258,142 @@ struct IdentifierNode : public IdentifierOrFunctionOrEmptyNode {
|
||||
gd::String type;
|
||||
};
|
||||
|
||||
struct FunctionOrEmptyNode : public IdentifierOrFunctionOrEmptyNode {
|
||||
virtual ~FunctionOrEmptyNode(){};
|
||||
struct FunctionCallOrObjectFunctionNameOrEmptyNode
|
||||
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
virtual ~FunctionCallOrObjectFunctionNameOrEmptyNode(){};
|
||||
void Visit(ExpressionParser2NodeWorker &worker) override{};
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A function node. For example: "MyExtension::MyFunction(1, 2)".
|
||||
* \brief The name of a function to call on an object or the behavior
|
||||
* For example: "MyObject.Function" or "MyObject.Physics" or
|
||||
* "MyObject.Physics::LinearVelocity".
|
||||
*/
|
||||
struct FunctionNode : public FunctionOrEmptyNode {
|
||||
FunctionNode(const gd::String &type_,
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
|
||||
const ExpressionMetadata &expressionMetadata_,
|
||||
const gd::String &functionName_)
|
||||
struct ObjectFunctionNameNode
|
||||
: public FunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
ObjectFunctionNameNode(const gd::String &type_,
|
||||
const gd::String &objectName_,
|
||||
const gd::String &objectFunctionOrBehaviorName_)
|
||||
: type(type_),
|
||||
objectName(objectName_),
|
||||
objectFunctionOrBehaviorName(objectFunctionOrBehaviorName_) {}
|
||||
ObjectFunctionNameNode(const gd::String &type_,
|
||||
const gd::String &objectName_,
|
||||
const gd::String &behaviorName_,
|
||||
const gd::String &behaviorFunctionName_)
|
||||
: type(type_),
|
||||
objectName(objectName_),
|
||||
objectFunctionOrBehaviorName(behaviorName_),
|
||||
behaviorFunctionName(behaviorFunctionName_) {}
|
||||
virtual ~ObjectFunctionNameNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitObjectFunctionNameNode(*this);
|
||||
};
|
||||
|
||||
gd::String type; // This could be removed if the type ("string", "number",
|
||||
// type supported by gd::ParameterMetadata::IsObject, types
|
||||
// supported by gd::ParameterMetadata::IsExpression or
|
||||
// "unknown") was stored in ExpressionMetadata.
|
||||
gd::String objectName;
|
||||
gd::String objectFunctionOrBehaviorName; ///< Behavior name if
|
||||
///`behaviorFunctionName` is not
|
||||
///empty.
|
||||
gd::String behaviorFunctionName; ///< If empty, then
|
||||
///objectFunctionOrBehaviorName is filled
|
||||
///with the behavior name.
|
||||
|
||||
ExpressionParserLocation
|
||||
objectNameLocation; ///< Location of the object name.
|
||||
ExpressionParserLocation
|
||||
objectNameDotLocation; ///< Location of the "." after the object name.
|
||||
ExpressionParserLocation objectFunctionOrBehaviorNameLocation; ///< Location
|
||||
///of object
|
||||
///function
|
||||
///name or
|
||||
///behavior
|
||||
///name.
|
||||
ExpressionParserLocation
|
||||
behaviorNameNamespaceSeparatorLocation; ///< Location of the "::"
|
||||
///separator, if any.
|
||||
ExpressionParserLocation behaviorFunctionNameLocation; ///< Location of the
|
||||
///behavior function
|
||||
///name, if any.
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A function call node (either free function, object function or object
|
||||
* behavior function).
|
||||
* For example: "MyExtension::MyFunction(1, 2)", "MyObject.Function()" or
|
||||
* "MyObject.Physics::LinearVelocity()".
|
||||
*/
|
||||
struct FunctionCallNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
FunctionCallNode(const gd::String &type_,
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
|
||||
const ExpressionMetadata &expressionMetadata_,
|
||||
const gd::String &functionName_)
|
||||
: 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_)
|
||||
FunctionCallNode(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_)
|
||||
FunctionCallNode(const gd::String &type_,
|
||||
const gd::String &objectName_,
|
||||
const gd::String &behaviorName_,
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
|
||||
const ExpressionMetadata &expressionMetadata_,
|
||||
const gd::String &functionName_)
|
||||
: type(type_),
|
||||
objectName(objectName_),
|
||||
behaviorName(behaviorName_),
|
||||
parameters(std::move(parameters_)),
|
||||
expressionMetadata(expressionMetadata_),
|
||||
functionName(functionName_){};
|
||||
virtual ~FunctionNode(){};
|
||||
virtual ~FunctionCallNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker) {
|
||||
worker.OnVisitFunctionNode(*this);
|
||||
worker.OnVisitFunctionCallNode(*this);
|
||||
};
|
||||
|
||||
gd::String type; // This could be removed if the type ("string" or "number")
|
||||
// was stored in ExpressionMetadata.
|
||||
gd::String type; // This could be removed if the type ("string", "number",
|
||||
// type supported by gd::ParameterMetadata::IsObject, types
|
||||
// supported by gd::ParameterMetadata::IsExpression or
|
||||
// "unknown") was stored in ExpressionMetadata.
|
||||
gd::String objectName;
|
||||
gd::String behaviorName;
|
||||
std::vector<std::unique_ptr<ExpressionNode>> parameters;
|
||||
const ExpressionMetadata &expressionMetadata;
|
||||
gd::String functionName;
|
||||
|
||||
ExpressionParserLocation
|
||||
functionNameLocation; ///< Location of the function name.
|
||||
ExpressionParserLocation
|
||||
objectNameLocation; ///< Location of the object name, if any.
|
||||
ExpressionParserLocation
|
||||
objectNameDotLocation; ///< Location of the "." after the object name.
|
||||
ExpressionParserLocation
|
||||
behaviorNameLocation; ///< Location of the behavior name, if any.
|
||||
ExpressionParserLocation
|
||||
behaviorNameNamespaceSeparatorLocation; ///< Location of the "::"
|
||||
///separator, if any.
|
||||
ExpressionParserLocation
|
||||
openingParenthesisLocation; ///< Location of the "(".
|
||||
ExpressionParserLocation
|
||||
closingParenthesisLocation; ///< Location of the ")".
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An empty node, used when parsing failed/a syntax error was
|
||||
* encountered and any other node could not make sense.
|
||||
*/
|
||||
struct EmptyNode : public FunctionOrEmptyNode {
|
||||
struct EmptyNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
|
||||
EmptyNode(const gd::String &type_, const gd::String &text_ = "")
|
||||
: type(type_), text(text_){};
|
||||
virtual ~EmptyNode(){};
|
||||
@@ -285,10 +401,12 @@ struct EmptyNode : public FunctionOrEmptyNode {
|
||||
worker.OnVisitEmptyNode(*this);
|
||||
};
|
||||
|
||||
gd::String type;
|
||||
gd::String type; // "string", "number", type supported by
|
||||
// gd::ParameterMetadata::IsObject, types supported by
|
||||
// gd::ParameterMetadata::IsExpression or "unknown".
|
||||
gd::String text;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -92,7 +92,15 @@ class GD_CORE_API ExpressionParser2NodePrinter
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
output += node.identifierName;
|
||||
}
|
||||
void OnVisitFunctionNode(FunctionNode& node) override {
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
if (!node.behaviorFunctionName.empty()) {
|
||||
output +=
|
||||
node.objectName + "." + node.objectFunctionOrBehaviorName + "::" + node.behaviorFunctionName;
|
||||
} else {
|
||||
output += node.objectName + "." + node.objectFunctionOrBehaviorName;
|
||||
}
|
||||
};
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
if (!node.behaviorName.empty()) {
|
||||
output +=
|
||||
node.objectName + "." + node.behaviorName + "::" + node.functionName;
|
||||
|
@@ -16,10 +16,11 @@ class TextNode;
|
||||
class VariableNode;
|
||||
class VariableAccessorNode;
|
||||
class VariableBracketAccessorNode;
|
||||
class IdentifierOrFunctionOrEmptyNode;
|
||||
class IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
class IdentifierNode;
|
||||
class FunctionOrEmptyNode;
|
||||
class FunctionNode;
|
||||
class FunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
class ObjectFunctionNameNode;
|
||||
class FunctionCallNode;
|
||||
class EmptyNode;
|
||||
} // namespace gd
|
||||
|
||||
@@ -42,10 +43,11 @@ class GD_CORE_API ExpressionParser2NodeWorker {
|
||||
friend class VariableNode;
|
||||
friend class VariableAccessorNode;
|
||||
friend class VariableBracketAccessorNode;
|
||||
friend class IdentifierOrFunctionOrEmptyNode;
|
||||
friend class IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
friend class IdentifierNode;
|
||||
friend class FunctionOrEmptyNode;
|
||||
friend class FunctionNode;
|
||||
friend class FunctionCallOrObjectFunctionNameOrEmptyNode;
|
||||
friend class ObjectFunctionNameNode;
|
||||
friend class FunctionCallNode;
|
||||
friend class EmptyNode;
|
||||
|
||||
public:
|
||||
@@ -62,10 +64,11 @@ class GD_CORE_API ExpressionParser2NodeWorker {
|
||||
virtual void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) = 0;
|
||||
virtual void OnVisitIdentifierNode(IdentifierNode& node) = 0;
|
||||
virtual void OnVisitFunctionNode(FunctionNode& node) = 0;
|
||||
virtual void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) = 0;
|
||||
virtual void OnVisitFunctionCallNode(FunctionCallNode& node) = 0;
|
||||
virtual void OnVisitEmptyNode(EmptyNode& node) = 0;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Events/Parsers/VariableParser.h"
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class Layout;
|
||||
}
|
||||
namespace gd {
|
||||
class Project;
|
||||
}
|
||||
namespace gd {
|
||||
class Platform;
|
||||
}
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
VariableParser::~VariableParser() {}
|
||||
|
||||
bool VariableParser::Parse(VariableParserCallbacks& callbacks_) {
|
||||
callbacks = &callbacks_;
|
||||
rootVariableParsed = false;
|
||||
firstErrorStr.clear();
|
||||
firstErrorPos = 0;
|
||||
currentPositionIt = expression.begin();
|
||||
currentTokenType = TS_INVALID;
|
||||
currentToken.clear();
|
||||
S();
|
||||
|
||||
return firstErrorStr == "";
|
||||
}
|
||||
|
||||
void VariableParser::ReadToken() {
|
||||
currentTokenType = TS_INVALID;
|
||||
currentToken.clear();
|
||||
while (currentPositionIt != expression.end()) {
|
||||
char32_t currentChar = *currentPositionIt;
|
||||
if (currentChar == U'[' || currentChar == U']' || currentChar == U'.') {
|
||||
if (currentTokenType == TS_VARNAME)
|
||||
return; // We've parsed a variable name.
|
||||
}
|
||||
|
||||
if (currentChar == U'[') {
|
||||
currentTokenType = TS_OPENING_BRACKET;
|
||||
currentToken.clear();
|
||||
++currentPositionIt;
|
||||
return;
|
||||
} else if (currentChar == U']') {
|
||||
currentTokenType = TS_CLOSING_BRACKET;
|
||||
currentToken.clear();
|
||||
++currentPositionIt;
|
||||
return;
|
||||
} else if (currentChar == U'.') {
|
||||
currentTokenType = TS_PERIOD;
|
||||
currentToken.clear();
|
||||
++currentPositionIt;
|
||||
return;
|
||||
}
|
||||
|
||||
currentTokenType = TS_VARNAME; // We're parsing a variable name.
|
||||
currentToken.push_back(currentChar);
|
||||
++currentPositionIt;
|
||||
}
|
||||
|
||||
// Can be reached if we are at the end of the expression. In this case,
|
||||
// currentTokenType will be either TS_VARNAME or TS_INVALID.
|
||||
}
|
||||
|
||||
void VariableParser::S() {
|
||||
ReadToken();
|
||||
if (currentTokenType != TS_VARNAME) {
|
||||
firstErrorStr = _("Expecting a variable name.");
|
||||
firstErrorPos = std::distance<gd::String::const_iterator>(
|
||||
expression.begin(), currentPositionIt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rootVariableParsed) {
|
||||
rootVariableParsed = true;
|
||||
if (callbacks) callbacks->OnRootVariable(currentToken);
|
||||
} else if (callbacks)
|
||||
callbacks->OnChildVariable(currentToken);
|
||||
|
||||
X();
|
||||
}
|
||||
|
||||
void VariableParser::X() {
|
||||
ReadToken();
|
||||
if (currentTokenType == TS_INVALID)
|
||||
return; // Ended parsing.
|
||||
else if (currentTokenType == TS_PERIOD)
|
||||
S();
|
||||
else if (currentTokenType == TS_OPENING_BRACKET) {
|
||||
gd::String strExpr = SkipStringExpression();
|
||||
|
||||
ReadToken();
|
||||
if (currentTokenType != TS_CLOSING_BRACKET) {
|
||||
firstErrorStr = _("Expecting ]");
|
||||
firstErrorPos = std::distance<gd::String::const_iterator>(
|
||||
expression.begin(), currentPositionIt);
|
||||
return;
|
||||
}
|
||||
if (callbacks) callbacks->OnChildSubscript(strExpr);
|
||||
X();
|
||||
}
|
||||
}
|
||||
|
||||
gd::String VariableParser::SkipStringExpression() {
|
||||
gd::String stringExpression;
|
||||
bool insideStringLiteral = false;
|
||||
bool lastCharacterWasBackslash = false;
|
||||
unsigned int nestedBracket = 0;
|
||||
while (currentPositionIt != expression.end()) {
|
||||
char32_t currentChar = *currentPositionIt;
|
||||
if (currentChar == U'\"') {
|
||||
if (!insideStringLiteral)
|
||||
insideStringLiteral = true;
|
||||
else if (!lastCharacterWasBackslash)
|
||||
insideStringLiteral = false;
|
||||
} else if (currentChar == U'[' && !insideStringLiteral) {
|
||||
nestedBracket++;
|
||||
} else if (currentChar == U']' && !insideStringLiteral) {
|
||||
if (nestedBracket == 0)
|
||||
return stringExpression; // Found the end of the string litteral.
|
||||
nestedBracket--;
|
||||
}
|
||||
|
||||
lastCharacterWasBackslash = currentChar == U'\\';
|
||||
stringExpression.push_back(currentChar);
|
||||
++currentPositionIt;
|
||||
}
|
||||
|
||||
// End of the expression reached (so expression is invalid by the way)
|
||||
return stringExpression;
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_VARIABLEPARSER_H
|
||||
#define GDCORE_VARIABLEPARSER_H
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class Layout;
|
||||
}
|
||||
namespace gd {
|
||||
class Project;
|
||||
}
|
||||
namespace gd {
|
||||
class Platform;
|
||||
}
|
||||
namespace gd {
|
||||
class VariableParserCallbacks;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
/** \brief Parse a variable expression.
|
||||
*
|
||||
* Parse an variable expression ( like
|
||||
myVariable.child["subchild"+ToString(i)].subsubchild ),
|
||||
* calling callbacks when a token is reached.
|
||||
*
|
||||
* Usage example:
|
||||
\code
|
||||
//...
|
||||
|
||||
//VariableCodeGenerationCallbacks is a class inheriting from
|
||||
gd::VariableParserCallbacks VariableCodeGenerationCallbacks callbacks(output,
|
||||
*this, context, VariableCodeGenerationCallbacks::PROJECT_VARIABLE);
|
||||
|
||||
gd::VariableParser parser(parameter);
|
||||
if ( !parser.Parse(callbacks) )
|
||||
cout << "Error :" << parser.GetFirstError() << " in: "<< parameter <<
|
||||
endl;
|
||||
\endcode
|
||||
*
|
||||
* Here is the parsed grammar: <br>
|
||||
* S -> VarName X <br>
|
||||
* X -> e | . S | [StringExpression] X <br>
|
||||
*
|
||||
* where e = nothing (end of expression), StringExpression = A valid string
|
||||
expression and
|
||||
* S is the start.
|
||||
*
|
||||
* \see gd::VariableParserCallbacks
|
||||
*/
|
||||
class GD_CORE_API VariableParser {
|
||||
public:
|
||||
/**
|
||||
* \brief Default constructor
|
||||
* \param expressionPlainString The string representing the expression to be
|
||||
* parsed.
|
||||
*/
|
||||
VariableParser(const gd::String& expressionPlainString_)
|
||||
: currentPositionIt(), expression(expressionPlainString_){};
|
||||
virtual ~VariableParser();
|
||||
|
||||
/**
|
||||
* Parse the expression, calling each callback when necessary.
|
||||
* \param callbacks The callbacks to be called.
|
||||
* \return true if expression was correctly parsed.
|
||||
* \see gd::VariableParserCallbacks
|
||||
*/
|
||||
bool Parse(VariableParserCallbacks& callbacks);
|
||||
|
||||
/**
|
||||
* \brief Return the description of the error that was found
|
||||
*/
|
||||
const gd::String& GetFirstError() { return firstErrorStr; }
|
||||
|
||||
/**
|
||||
* \brief Return the position of the error that was found
|
||||
* \return The position, or gd::String::npos if no error is found
|
||||
*/
|
||||
size_t GetFirstErrorPosition() { return firstErrorPos; }
|
||||
|
||||
gd::String firstErrorStr;
|
||||
size_t firstErrorPos;
|
||||
|
||||
private:
|
||||
void S();
|
||||
void X();
|
||||
|
||||
/**
|
||||
* \brief Skip the string expression, starting from the current position.
|
||||
* \return The string expression skipped. currentPosition is now put on the
|
||||
* closing bracket.
|
||||
*/
|
||||
gd::String SkipStringExpression();
|
||||
|
||||
void ReadToken();
|
||||
|
||||
enum TokenType {
|
||||
TS_PERIOD,
|
||||
TS_OPENING_BRACKET,
|
||||
TS_CLOSING_BRACKET,
|
||||
TS_VARNAME,
|
||||
TS_INVALID
|
||||
};
|
||||
|
||||
TokenType currentTokenType;
|
||||
gd::String currentToken;
|
||||
gd::String::const_iterator currentPositionIt;
|
||||
gd::String expression;
|
||||
|
||||
VariableParserCallbacks* callbacks;
|
||||
bool rootVariableParsed;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Callbacks called by VariableParser when parsing a variable expression.
|
||||
*/
|
||||
class GD_CORE_API VariableParserCallbacks {
|
||||
public:
|
||||
/**
|
||||
* \brief Called when the first variable has been parsed. ( varName1 in
|
||||
* varName1.child for example. ) \param variableName The variable name.
|
||||
*/
|
||||
virtual void OnRootVariable(gd::String variableName) = 0;
|
||||
|
||||
/**
|
||||
* \brief Called when accessing the child of a structure variable. ( child in
|
||||
* varName1.child for example. ) \param variableName The child variable name.
|
||||
*/
|
||||
virtual void OnChildVariable(gd::String variableName) = 0;
|
||||
|
||||
/**
|
||||
* \brief Called when accessing the child of a structure variable using a
|
||||
* string expression in square brackets. ( "subscript" in
|
||||
* varName1["subscript"] for example. )
|
||||
*
|
||||
* \param variableName The expression used to access the child variable.
|
||||
*/
|
||||
virtual void OnChildSubscript(gd::String stringExpression) = 0;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDEXPRESSIONPARSER_H
|
@@ -8,10 +8,15 @@
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
EventsCodeNameMangler *EventsCodeNameMangler::_singleton = NULL;
|
||||
EventsCodeNameMangler *EventsCodeNameMangler::_singleton = nullptr;
|
||||
|
||||
gd::String EventsCodeNameMangler::GetMangledObjectsListName(
|
||||
const gd::String& EventsCodeNameMangler::GetMangledObjectsListName(
|
||||
const gd::String &originalObjectName) {
|
||||
auto it = mangledObjectNames.find(originalObjectName);
|
||||
if (it != mangledObjectNames.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
gd::String partiallyMangledName = originalObjectName;
|
||||
static const gd::String allowedCharacters =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
@@ -27,11 +32,17 @@ gd::String EventsCodeNameMangler::GetMangledObjectsListName(
|
||||
}
|
||||
}
|
||||
|
||||
return "GD" + partiallyMangledName + "Objects";
|
||||
mangledObjectNames[originalObjectName] = "GD" + partiallyMangledName + "Objects";
|
||||
return mangledObjectNames[originalObjectName];
|
||||
}
|
||||
|
||||
gd::String EventsCodeNameMangler::GetExternalEventsFunctionMangledName(
|
||||
const gd::String& EventsCodeNameMangler::GetExternalEventsFunctionMangledName(
|
||||
const gd::String &externalEventsName) {
|
||||
auto it = mangledExternalEventsNames.find(externalEventsName);
|
||||
if (it != mangledExternalEventsNames.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
gd::String partiallyMangledName = externalEventsName;
|
||||
static const gd::String allowedCharacters =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
@@ -47,23 +58,24 @@ gd::String EventsCodeNameMangler::GetExternalEventsFunctionMangledName(
|
||||
}
|
||||
}
|
||||
|
||||
return "GDExternalEvents" + partiallyMangledName;
|
||||
mangledExternalEventsNames[externalEventsName] = "GDExternalEvents" + partiallyMangledName;
|
||||
return mangledExternalEventsNames[externalEventsName];
|
||||
}
|
||||
|
||||
gd::String ManObjListName(const gd::String &objectName) {
|
||||
const gd::String& ManObjListName(const gd::String &objectName) {
|
||||
return EventsCodeNameMangler::Get()->GetMangledObjectsListName(objectName);
|
||||
}
|
||||
|
||||
EventsCodeNameMangler *EventsCodeNameMangler::Get() {
|
||||
if (NULL == _singleton) _singleton = new EventsCodeNameMangler;
|
||||
if (nullptr == _singleton) _singleton = new EventsCodeNameMangler;
|
||||
|
||||
return (static_cast<EventsCodeNameMangler *>(_singleton));
|
||||
}
|
||||
|
||||
void EventsCodeNameMangler::DestroySingleton() {
|
||||
if (NULL != _singleton) {
|
||||
if (nullptr != _singleton) {
|
||||
delete _singleton;
|
||||
_singleton = NULL;
|
||||
_singleton = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -6,26 +6,34 @@
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef EVENTSCODENAMEMANGLER_H
|
||||
#define EVENTSCODENAMEMANGLER_H
|
||||
#include <unordered_map>
|
||||
#include "GDCore/String.h"
|
||||
|
||||
/**
|
||||
* Manage name mangling, so as to ensure all names used in code are valid.
|
||||
* \brief Mangle object names, so as to ensure all names used in code are valid.
|
||||
*
|
||||
* \see ManObjListName
|
||||
*/
|
||||
class GD_CORE_API EventsCodeNameMangler {
|
||||
public:
|
||||
/**
|
||||
* Get the mangled name from a name : All characters that are not 0-9, a-z,
|
||||
* Get the mangled name from a name: All characters that are not 0-9, a-z,
|
||||
* A-Z or _ are replaced by "_"+AsciiCodeOfTheCharacter.
|
||||
*
|
||||
* The mangled name is memoized as this is intensively used during project
|
||||
* export and events code generation.
|
||||
*/
|
||||
gd::String GetMangledObjectsListName(const gd::String &originalObjectName);
|
||||
const gd::String &GetMangledObjectsListName(
|
||||
const gd::String &originalObjectName);
|
||||
|
||||
/**
|
||||
* Get the mangled function name to be used to call external events named \a
|
||||
* externalEventsName.
|
||||
*
|
||||
* The mangled name is memoized as this is intensively used during project
|
||||
* export and events code generation.
|
||||
*/
|
||||
gd::String GetExternalEventsFunctionMangledName(
|
||||
const gd::String &GetExternalEventsFunctionMangledName(
|
||||
const gd::String &externalEventsName);
|
||||
|
||||
static EventsCodeNameMangler *Get();
|
||||
@@ -35,14 +43,22 @@ class GD_CORE_API EventsCodeNameMangler {
|
||||
EventsCodeNameMangler(){};
|
||||
virtual ~EventsCodeNameMangler(){};
|
||||
static EventsCodeNameMangler *_singleton;
|
||||
|
||||
std::unordered_map<gd::String, gd::String>
|
||||
mangledObjectNames; ///< Memoized results of mangling for objects
|
||||
std::unordered_map<gd::String, gd::String>
|
||||
mangledExternalEventsNames; ///< Memoized results of mangling for
|
||||
/// external events
|
||||
};
|
||||
|
||||
/**
|
||||
* Shortcut to
|
||||
* EventsCodeNameMangler::Get()->GetMangledObjectsListName(objectName). \see
|
||||
* EventsCodeNameMangler \return Mangled object name
|
||||
* Shortcut for
|
||||
* `EventsCodeNameMangler::Get()->GetMangledObjectsListName(objectName)`.
|
||||
*
|
||||
* \see EventsCodeNameMangler
|
||||
* \return Mangled object name
|
||||
*/
|
||||
gd::String GD_CORE_API ManObjListName(const gd::String &objectName);
|
||||
const gd::String &GD_CORE_API ManObjListName(const gd::String &objectName);
|
||||
|
||||
#endif // EVENTSCODENAMEMANGLER_H
|
||||
#endif
|
||||
|
@@ -143,117 +143,97 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
|
||||
_("Volume of the sound on a channel"),
|
||||
_("This action modifies the volume of the sound on the "
|
||||
"specified channel. The volume is between 0 and 100."),
|
||||
_("Do _PARAM2__PARAM3_ to the volume of the sound on channel "
|
||||
"_PARAM1_"),
|
||||
_("the volume of the sound on channel _PARAM1_"),
|
||||
_("Audio/Sounds on channels"),
|
||||
"res/actions/sonVolume24.png",
|
||||
"res/actions/sonVolume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("ModVolumeMusicCanal",
|
||||
_("Volume of the music on a channel"),
|
||||
_("This action modifies the volume of the music on the "
|
||||
"specified channel. The volume is between 0 and 100."),
|
||||
_("Do _PARAM2__PARAM3_ to the volume of the music on channel "
|
||||
"_PARAM1_"),
|
||||
_("the volume of the music on channel _PARAM1_"),
|
||||
_("Audio/Music on channels"),
|
||||
"res/actions/musicVolume24.png",
|
||||
"res/actions/musicVolume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("ModGlobalVolume",
|
||||
_("Game global volume"),
|
||||
_("This action modifies the global volume of the game. The "
|
||||
"volume is between 0 and 100."),
|
||||
_("Do _PARAM1__PARAM2_ to global sound level"),
|
||||
_("the global sound level"),
|
||||
_("Audio"),
|
||||
"res/actions/volume24.png",
|
||||
"res/actions/volume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsSimple()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
.AddAction("ModPitchSoundChannel",
|
||||
_("Pitch of the sound of a channel"),
|
||||
_("This action modifies the pitch (speed) of the sound on a "
|
||||
"channel.\n1 is the default pitch."),
|
||||
_("Do _PARAM2__PARAM3_ to the pitch of the sound on channel "
|
||||
"_PARAM1_"),
|
||||
_("the pitch of the sound on channel _PARAM1_"),
|
||||
_("Audio/Sounds on channels"),
|
||||
"res/actions/son24.png",
|
||||
"res/actions/son.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("ModPitchMusicChannel",
|
||||
_("Pitch of the music on a channel"),
|
||||
_("This action modifies the pitch of the music on the "
|
||||
"specified channel. 1 is the default pitch"),
|
||||
_("Do _PARAM2__PARAM3_ to the pitch of the music on channel "
|
||||
"_PARAM1_"),
|
||||
_("the pitch of the music on channel _PARAM1_"),
|
||||
_("Audio/Music on channels"),
|
||||
"res/actions/music24.png",
|
||||
"res/actions/music.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("ModPlayingOffsetSoundChannel",
|
||||
_("Playing offset of the sound on a channel"),
|
||||
_("This action modifies the playing offset of the sound on a "
|
||||
"channel"),
|
||||
_("Do _PARAM2__PARAM3_ to the playing offset of the sound on "
|
||||
"channel _PARAM1_"),
|
||||
_("the playing offset of the sound on channel _PARAM1_"),
|
||||
_("Audio/Sounds on channels"),
|
||||
"res/actions/son24.png",
|
||||
"res/actions/son.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("ModPlayingOffsetMusicChannel",
|
||||
_("Playing offset of the music on a channel"),
|
||||
_("This action modifies the playing offset of the music on "
|
||||
"the specified channel"),
|
||||
_("Do _PARAM2__PARAM3_ to the playing offset of the music on "
|
||||
"channel _PARAM1_"),
|
||||
_("the playing offset of the music on channel _PARAM1_"),
|
||||
_("Audio/Music on channels"),
|
||||
"res/actions/music24.png",
|
||||
"res/actions/music.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("PlaySound",
|
||||
@@ -373,16 +353,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
|
||||
_("Volume of the sound on a channel"),
|
||||
_("Test the volume of the sound on the specified channel. The volume "
|
||||
"is between 0 and 100."),
|
||||
_("The volume of the sound on channel _PARAM1_ is _PARAM2__PARAM3_"),
|
||||
_("the volume of the sound on channel _PARAM1_"),
|
||||
_("Audio/Sounds on channels"),
|
||||
"res/conditions/sonVolume24.png",
|
||||
"res/conditions/sonVolume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Volume to test"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
@@ -390,30 +368,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
|
||||
_("Volume of the music on a channel"),
|
||||
_("Test the volume of the music on a specified channel. The volume "
|
||||
"is between 0 and 100."),
|
||||
_("The volume of the music on channel _PARAM1_ is _PARAM2__PARAM3_"),
|
||||
_("the volume of the music on channel _PARAM1_"),
|
||||
_("Audio/Music on channels"),
|
||||
"res/conditions/musicVolume24.png",
|
||||
"res/conditions/musicVolume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Volume to test"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"GlobalVolume",
|
||||
_("Global volume"),
|
||||
_("Test the global sound level. The volume is between 0 and 100."),
|
||||
_("The global game volume is _PARAM1__PARAM2_"),
|
||||
_("the global game volume"),
|
||||
_("Audio"),
|
||||
"res/conditions/volume24.png",
|
||||
"res/conditions/volume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Volume to test"))
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
@@ -421,16 +395,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
|
||||
_("Pitch of the sound of a channel"),
|
||||
_("Test the pitch of the sound on the specified channel. 1 is the "
|
||||
"default pitch."),
|
||||
_("The pitch of the sound on channel _PARAM1_ is _PARAM2__PARAM3_"),
|
||||
_("the pitch of the sound on channel _PARAM1_"),
|
||||
_("Audio/Sounds on channels"),
|
||||
"res/conditions/sonVolume24.png",
|
||||
"res/conditions/sonVolume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Pitch to test"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
@@ -438,50 +410,42 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
|
||||
_("Pitch of the music on a channel"),
|
||||
_("Test the pitch (speed) of the music on a specified channel. 1 is "
|
||||
"the default pitch."),
|
||||
_("The pitch of the music on channel _PARAM1_ is _PARAM2__PARAM3_"),
|
||||
_("the pitch of the music on channel _PARAM1_"),
|
||||
_("Audio/Music on channels"),
|
||||
"res/conditions/musicVolume24.png",
|
||||
"res/conditions/musicVolume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Pitch to test"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"SoundChannelPlayingOffset",
|
||||
_("Playing offset of the sound on a channel"),
|
||||
_("Test the playing offset of the sound on the specified channel."),
|
||||
_("The playing offset of the sound on channel _PARAM1_ is "
|
||||
"_PARAM2__PARAM3_"),
|
||||
_("the playing offset of the sound on channel _PARAM1_"),
|
||||
_("Audio/Sounds on channels"),
|
||||
"res/conditions/sonVolume24.png",
|
||||
"res/conditions/sonVolume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Playing position (in seconds)"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"MusicChannelPlayingOffset",
|
||||
_("Playing offset of the music on a channel"),
|
||||
_("Test the playing offset of the music on the specified channel."),
|
||||
_("The playing offset of the music on channel _PARAM1_ is "
|
||||
"_PARAM2__PARAM3_"),
|
||||
_("the playing offset of the music on channel _PARAM1_"),
|
||||
_("Audio/Music on channels"),
|
||||
"res/conditions/musicVolume24.png",
|
||||
"res/conditions/musicVolume.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Channel identifier"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Playing position (in seconds)"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddExpression("SoundChannelPlayingOffset",
|
||||
|
@@ -13,11 +13,12 @@ namespace gd {
|
||||
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
gd::PlatformExtension& extension) {
|
||||
extension
|
||||
.SetExtensionInformation("BuiltinObject",
|
||||
_("Base object"),
|
||||
_("Base object"),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionInformation(
|
||||
"BuiltinObject",
|
||||
_("Features for all objects"),
|
||||
_("Common features that can be used for all objects in GDevelop."),
|
||||
"Florian Rival",
|
||||
"Open source (MIT License)")
|
||||
.SetExtensionHelpPath("/objects/base_object/events");
|
||||
|
||||
gd::ObjectMetadata& obj = extension.AddObject<gd::Object>(
|
||||
@@ -27,67 +28,59 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddCondition("PosX",
|
||||
_("Compare X position of an object"),
|
||||
_("Compare the X position of the object."),
|
||||
_("The X position of _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the X position"),
|
||||
_("Position"),
|
||||
"res/conditions/position24.png",
|
||||
"res/conditions/position.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("X position"))
|
||||
.MarkAsSimple()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction("MettreX",
|
||||
_("X position of an object"),
|
||||
_("Change the X position of an object."),
|
||||
_("Do _PARAM1__PARAM2_ to the X position of _PARAM0_"),
|
||||
_("the X position"),
|
||||
_("Position"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsSimple()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddCondition("PosY",
|
||||
_("Compare Y position of an object"),
|
||||
_("Compare the Y position of an object."),
|
||||
_("The Y position of _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the Y position"),
|
||||
_("Position"),
|
||||
"res/conditions/position24.png",
|
||||
"res/conditions/position.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.MarkAsSimple()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction("MettreY",
|
||||
_("Y position of an object"),
|
||||
_("Change the Y position of an object."),
|
||||
_("Do _PARAM1__PARAM2_ to the Y position of _PARAM0_"),
|
||||
_("the Y position"),
|
||||
_("Position"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsSimple()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction(
|
||||
"MettreXY",
|
||||
_("Position of an object"),
|
||||
_("Change the position of an object."),
|
||||
_("Do _PARAM1__PARAM2_;_PARAM3__PARAM4_ to the position of _PARAM0_"),
|
||||
_("Position"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
obj.AddAction("MettreXY",
|
||||
_("Position of an object"),
|
||||
_("Change the position of an object."),
|
||||
_("Change the position of _PARAM0_: _PARAM1_ _PARAM2_ (x "
|
||||
"axis), _PARAM3_ _PARAM4_ (y axis)"),
|
||||
_("Position"),
|
||||
"res/actions/position24.png",
|
||||
"res/actions/position.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
@@ -117,15 +110,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddAction("SetAngle",
|
||||
_("Angle"),
|
||||
_("Change the angle of rotation of an object."),
|
||||
_("Do _PARAM1__PARAM2_ to angle of _PARAM0_"),
|
||||
_("the angle"),
|
||||
_("Angle"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number");
|
||||
|
||||
obj.AddAction("Rotate",
|
||||
_("Rotate"),
|
||||
@@ -271,15 +262,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddAction("ChangePlan",
|
||||
_("Z order"),
|
||||
_("Modify the Z-order of an object"),
|
||||
_("Do _PARAM1__PARAM2_ to Z-order of _PARAM0_"),
|
||||
_("the z-order"),
|
||||
_("Z order"),
|
||||
"res/actions/planicon24.png",
|
||||
"res/actions/planicon.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number");
|
||||
|
||||
obj.AddAction("ChangeLayer",
|
||||
_("Layer"),
|
||||
@@ -297,31 +286,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddAction("ModVarObjet",
|
||||
_("Modify a variable of an object"),
|
||||
_("Modify the value of a variable of an object"),
|
||||
_("Do _PARAM2__PARAM3_ to variable _PARAM1_ of _PARAM0_"),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number");
|
||||
|
||||
obj.AddAction(
|
||||
"ModVarObjetTxt",
|
||||
_("Modify the text of a variable of an object"),
|
||||
_("Modify the text of a variable of an object"),
|
||||
_("Do _PARAM2__PARAM3_ to the text of variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
obj.AddAction("ModVarObjetTxt",
|
||||
_("Modify the text of a variable of an object"),
|
||||
_("Modify the text of a variable of an object"),
|
||||
_("the text of variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("string", _("Text"))
|
||||
.SetManipulatedType("string");
|
||||
.UseStandardOperatorParameters("string");
|
||||
|
||||
obj.AddCondition(
|
||||
"ObjectVariableChildExists",
|
||||
@@ -385,30 +369,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddCondition("Angle",
|
||||
_("Angle"),
|
||||
_("Compare the angle of the specified object."),
|
||||
_("Angle of _PARAM0_ is _PARAM1__PARAM2_ deg."),
|
||||
_("the angle (in degrees)"),
|
||||
_("Angle"),
|
||||
"res/conditions/direction24.png",
|
||||
"res/conditions/direction.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare (in degrees)"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("Plan",
|
||||
_("Compare Z order"),
|
||||
_("Compare the Z-order of the specified object."),
|
||||
_("Z Order of _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the z Order"),
|
||||
_("Z order"),
|
||||
"res/conditions/planicon24.png",
|
||||
"res/conditions/planicon.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Z order"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("Layer",
|
||||
_("Compare layer"),
|
||||
@@ -458,16 +438,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddCondition("Vitesse",
|
||||
_("Speed"),
|
||||
_("Compare the overall speed of an object"),
|
||||
_("Overall speed of _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the overall speed"),
|
||||
_("Movement"),
|
||||
"res/conditions/vitesse24.png",
|
||||
"res/conditions/vitesse.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Speed"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("AngleOfDisplacement",
|
||||
_("Angle of movement"),
|
||||
@@ -486,31 +464,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
obj.AddCondition("VarObjet",
|
||||
_("Value of an object's variable"),
|
||||
_("Compare the value of a variable of an object."),
|
||||
_("Variable _PARAM1_ of _PARAM0_ is _PARAM2__PARAM3_"),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
obj.AddCondition(
|
||||
"VarObjetTxt",
|
||||
_("Text of an object's variable"),
|
||||
_("Compare the text of a variable of an object."),
|
||||
_("The text of variable _PARAM1_ of _PARAM0_ is _PARAM2__PARAM3_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
obj.AddCondition("VarObjetTxt",
|
||||
_("Text of an object's variable"),
|
||||
_("Compare the text of a variable of an object."),
|
||||
_("the text of variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("string", _("Text to test"))
|
||||
.SetManipulatedType("string");
|
||||
.UseStandardRelationalOperatorParameters("string");
|
||||
|
||||
obj.AddCondition("VarObjetDef",
|
||||
_("Variable defined"),
|
||||
@@ -660,6 +633,23 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("expression", _("Y position of the point"))
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
.AddCondition("SourisSurObjet",
|
||||
_("The cursor/touch is on an object"),
|
||||
_("Test if the cursor is over an object, or if the object "
|
||||
"is being touched."),
|
||||
_("The cursor/touch is on _PARAM0_"),
|
||||
_("Mouse and touch"),
|
||||
"res/conditions/surObjet24.png",
|
||||
"res/conditions/surObjet.png")
|
||||
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("yesorno", _("Accurate test (yes by default)"), "", true)
|
||||
.SetDefaultValue("yes")
|
||||
.AddCodeOnlyParameter("conditionInverted", "")
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddCondition(
|
||||
"ObjectTimer",
|
||||
_("Value of a timer"),
|
||||
@@ -1046,15 +1036,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"compare that number to a value. If previous conditions on the "
|
||||
"objects have not been used, this condition counts how many of "
|
||||
"these objects exist in the current scene."),
|
||||
_("The number of _PARAM0_ objects is _PARAM1__PARAM2_"),
|
||||
_("the number of _PARAM0_ objects"),
|
||||
_("Objects"),
|
||||
"res/conditions/nbObjet24.png",
|
||||
"res/conditions/nbObjet.png")
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.MarkAsSimple()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
|
@@ -24,86 +24,73 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddCondition("CameraX",
|
||||
_("Camera center X position"),
|
||||
_("Compare the X position of the center of a camera."),
|
||||
_("X position of camera _PARAM4_ is _PARAM1__PARAM2_ "
|
||||
"(layer: _PARAM3_)"),
|
||||
_("the X position of camera _PARAM4_ (layer: _PARAM3_)"),
|
||||
_("Layers and cameras"),
|
||||
"res/conditions/camera24.png",
|
||||
"res/conditions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("CameraY",
|
||||
_("Camera center Y position"),
|
||||
_("Compare the Y position of the center of a camera."),
|
||||
_("The Y position of camera _PARAM4_ is _PARAM1__PARAM2_ "
|
||||
"(layer: _PARAM3_)"),
|
||||
_("the Y position of camera _PARAM4_ (layer: _PARAM3_)"),
|
||||
_("Layers and cameras"),
|
||||
"res/conditions/camera24.png",
|
||||
"res/conditions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"))
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"))
|
||||
.SetDefaultValue("0")
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"CameraX",
|
||||
_("Camera center X position"),
|
||||
_("Change the X position of the center of the specified camera."),
|
||||
_("Do _PARAM1__PARAM2_ to X position of camera _PARAM4_ (layer: "
|
||||
"_PARAM3_)"),
|
||||
_("the X position of camera _PARAM4_ (layer: _PARAM3_)"),
|
||||
_("Layers and cameras"),
|
||||
"res/conditions/camera24.png",
|
||||
"res/conditions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.UseStandardOperatorParameters("number")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"CameraY",
|
||||
_("Camera center Y position"),
|
||||
_("Change the Y position of the center of the specified camera."),
|
||||
_("Do _PARAM1__PARAM2_ to Y position of camera _PARAM4_ (layer: "
|
||||
"_PARAM3_)"),
|
||||
_("the Y position of camera _PARAM4_ (layer: _PARAM3_)"),
|
||||
_("Layers and cameras"),
|
||||
"res/conditions/camera24.png",
|
||||
"res/conditions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.UseStandardOperatorParameters("number")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("CameraWidth",
|
||||
_("Width of a camera"),
|
||||
_("Test the width of a camera of a layer"),
|
||||
_("The width of camera _PARAM2_ of layer _PARAM1_ is "
|
||||
"_PARAM3__PARAM4_"),
|
||||
_("the width of camera _PARAM2_ of layer _PARAM1_"),
|
||||
_("Layers and cameras"),
|
||||
"res/conditions/camera24.png",
|
||||
"res/conditions/camera.png")
|
||||
@@ -111,17 +98,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddParameter("layer", _("Layer"))
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("CameraHeight",
|
||||
_("Height of a camera"),
|
||||
_("Test the height of a camera of a layer"),
|
||||
_("The height of camera _PARAM2_ of layer _PARAM1_ is "
|
||||
"_PARAM3__PARAM4_"),
|
||||
_("the height of camera _PARAM2_ of layer _PARAM1_"),
|
||||
_("Layers and cameras"),
|
||||
"res/conditions/camera24.png",
|
||||
"res/conditions/camera.png")
|
||||
@@ -129,48 +113,40 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"))
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("CameraAngle",
|
||||
_("Angle of a camera of a layer"),
|
||||
_("Test a camera angle."),
|
||||
_("Angle of camera is _PARAM1__PARAM2_ (layer: _PARAM3_, "
|
||||
"camera: _PARAM4_)"),
|
||||
_("the angle of camera (layer: _PARAM3_, camera: _PARAM4_)"),
|
||||
_("Layers and cameras"),
|
||||
"res/conditions/camera24.png",
|
||||
"res/conditions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("RotateCamera",
|
||||
_("Change camera angle"),
|
||||
_("This action modifies the angle of a camera in the "
|
||||
"specified layer."),
|
||||
_("Do _PARAM1__PARAM2_ to angle of camera (layer: _PARAM3_, "
|
||||
"camera: _PARAM4_)"),
|
||||
_("the angle of camera (layer: _PARAM3_, camera: _PARAM4_)"),
|
||||
_("Layers and cameras"),
|
||||
"res/actions/camera24.png",
|
||||
"res/actions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.UseStandardOperatorParameters("number")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.SetManipulatedType("number");
|
||||
.SetDefaultValue("0");
|
||||
|
||||
extension
|
||||
.AddAction("AddCamera",
|
||||
@@ -468,17 +444,15 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"LayerTimeScale",
|
||||
_("Layer time scale"),
|
||||
_("Compare the time scale applied to the objects of the layer."),
|
||||
_("The time scale of layer _PARAM1_ is _PARAM2__PARAM3_"),
|
||||
_("the time scale of layer _PARAM1_"),
|
||||
_("Layers and cameras/Time"),
|
||||
"res/conditions/time24.png",
|
||||
"res/conditions/time.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
|
@@ -37,17 +37,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsJoystickExtension(
|
||||
.AddCondition("JoystickAxis",
|
||||
_("Value of an axis of a joystick"),
|
||||
_("Test the value of an axis of a joystick."),
|
||||
_("The value of the axis _PARAM2_ of joystick _PARAM1_ is "
|
||||
"_PARAM3__PARAM4_"),
|
||||
_("the value of the axis _PARAM2_ of joystick _PARAM1_"),
|
||||
_("Joystick"),
|
||||
"res/conditions/joystick24.png",
|
||||
"res/conditions/joystick.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Joystick number (first joystick: 0)"))
|
||||
.AddParameter("joyaxis", _("Axis"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
|
@@ -21,23 +21,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.SetExtensionHelpPath("/all-features/mouse-touch");
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
extension
|
||||
.AddCondition("SourisSurObjet",
|
||||
_("The cursor/touch is on an object"),
|
||||
_("Test if the cursor is over an object, or if the object "
|
||||
"is being touched."),
|
||||
_("The cursor/touch is on _PARAM0_"),
|
||||
_("Mouse and touch"),
|
||||
"res/conditions/surObjet24.png",
|
||||
"res/conditions/surObjet.png")
|
||||
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("yesorno", _("Accurate test (yes by default)"), "", true)
|
||||
.SetDefaultValue("yes")
|
||||
.AddCodeOnlyParameter("conditionInverted", "")
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"IsMouseWheelScrollingUp",
|
||||
@@ -164,35 +147,31 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddCondition("SourisX",
|
||||
_("Cursor X position"),
|
||||
_("Compare the X position of the cursor or of a touch."),
|
||||
_("Cursor X position is _PARAM1__PARAM2_"),
|
||||
_("the cursor X position"),
|
||||
_("Mouse and touch"),
|
||||
"res/conditions/mouse24.png",
|
||||
"res/conditions/mouse.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("X position"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.SetManipulatedType("number");
|
||||
.SetDefaultValue("0");
|
||||
|
||||
extension
|
||||
.AddCondition("SourisY",
|
||||
_("Cursor Y position"),
|
||||
_("Compare the Y position of the cursor or of a touch."),
|
||||
_("Cursor Y position is _PARAM1__PARAM2_"),
|
||||
_("the cursor Y position"),
|
||||
_("Mouse and touch"),
|
||||
"res/conditions/mouse24.png",
|
||||
"res/conditions/mouse.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.SetManipulatedType("number");
|
||||
.SetDefaultValue("0");
|
||||
|
||||
extension
|
||||
.AddCondition("SourisBouton",
|
||||
@@ -224,37 +203,33 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddCondition("TouchX",
|
||||
_("Touch X position"),
|
||||
_("Compare the X position of a specific touch."),
|
||||
_("Touch #_PARAM1_ X position is _PARAM2__PARAM3_"),
|
||||
_("the touch #_PARAM1_ X position"),
|
||||
_("Mouse and touch/Multitouch"),
|
||||
"res/conditions/touch24.png",
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Touch identifier"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("X position"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.SetManipulatedType("number");
|
||||
.SetDefaultValue("0");
|
||||
|
||||
extension
|
||||
.AddCondition("TouchY",
|
||||
_("Touch Y position"),
|
||||
_("Compare the Y position of a specific touch."),
|
||||
_("Touch #_PARAM1_ Y position is _PARAM2__PARAM3_"),
|
||||
_("the touch #_PARAM1_ Y position"),
|
||||
_("Mouse and touch/Multitouch"),
|
||||
"res/conditions/touch24.png",
|
||||
"res/conditions/touch.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Touch identifier"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.SetManipulatedType("number");
|
||||
.SetDefaultValue("0");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
|
@@ -34,32 +34,27 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Change sprite opacity"),
|
||||
_("Change the opacity of a Sprite. 0 is fully transparent, 255 "
|
||||
"is opaque (default)."),
|
||||
_("Do _PARAM1__PARAM2_ to the opacity of _PARAM0_"),
|
||||
_("the opacity"),
|
||||
_("Visibility"),
|
||||
"res/actions/opacity24.png",
|
||||
"res/actions/opacity.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value (between 0 and 255)"))
|
||||
.MarkAsSimple()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction("ChangeAnimation",
|
||||
_("Change the animation"),
|
||||
_("Change the animation of the object, using the animation "
|
||||
"number in the animations list."),
|
||||
_("Do _PARAM1__PARAM2_ to the number of current animation of "
|
||||
"_PARAM0_"),
|
||||
_("the number of the animation"),
|
||||
_("Animations and images"),
|
||||
"res/actions/animation24.png",
|
||||
"res/actions/animation.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsSimple()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction("SetAnimationName",
|
||||
_("Change the animation (by name)"),
|
||||
@@ -80,35 +75,31 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Change the direction of the object.\nIf the object is set to "
|
||||
"automatically rotate, the direction is its angle.\nIf the object "
|
||||
"is in 8 directions mode, the valid directions are 0..7"),
|
||||
_("Do _PARAM1__PARAM2_ to the direction of _PARAM0_"),
|
||||
_("the direction"),
|
||||
_("Direction"),
|
||||
"res/actions/direction24.png",
|
||||
"res/actions/direction.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("ChangeSprite",
|
||||
_("Current frame"),
|
||||
_("Modify the current frame of the object"),
|
||||
_("Do _PARAM1__PARAM2_ to animation frame of _PARAM0_"),
|
||||
_("the animation frame"),
|
||||
_("Animations and images"),
|
||||
"res/actions/sprite24.png",
|
||||
"res/actions/sprite.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("PauseAnimation",
|
||||
_("Pause the animation"),
|
||||
_("Pause the current animation of the object"),
|
||||
_("Pause the current animation of _PARAM0_"),
|
||||
_("Pause the animation of the object"),
|
||||
_("Pause the animation of _PARAM0_"),
|
||||
_("Animations and images"),
|
||||
"res/actions/animation24.png",
|
||||
"res/actions/animation.png")
|
||||
@@ -118,8 +109,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
|
||||
obj.AddAction("PlayAnimation",
|
||||
_("Play the animation"),
|
||||
_("Play the current animation of the object"),
|
||||
_("Play the current animation of _PARAM0_"),
|
||||
_("Play the animation of the object"),
|
||||
_("Play the animation of _PARAM0_"),
|
||||
_("Animations and images"),
|
||||
"res/actions/animation24.png",
|
||||
"res/actions/animation.png")
|
||||
@@ -132,16 +123,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Animation speed scale"),
|
||||
_("Modify the animation speed scale (1 = the default speed, >1 = "
|
||||
"faster and <1 = slower)."),
|
||||
_("Do _PARAM1__PARAM2_ to the animation speed scale of _PARAM0_"),
|
||||
_("the animation speed scale"),
|
||||
_("Animations and images"),
|
||||
"res/actions/animation24.png",
|
||||
"res/actions/animation.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsSimple()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction("TourneVersPos",
|
||||
_("Rotate an object toward a position"),
|
||||
@@ -162,92 +151,79 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
obj.AddAction("ChangeScale",
|
||||
_("Scale"),
|
||||
_("Modify the scale of the specified object."),
|
||||
_("Do _PARAM1__PARAM2_ to the scale of _PARAM0_"),
|
||||
_("the scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("ChangeScaleWidth",
|
||||
_("Scale on X axis"),
|
||||
_("Modify the scale of the width of an object."),
|
||||
_("Do _PARAM1__PARAM2_ to the width's scale of _PARAM0_"),
|
||||
_("the width's scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("ChangeScaleHeight",
|
||||
_("Scale on Y axis"),
|
||||
_("Modify the scale of the height of an object."),
|
||||
_("Do _PARAM1__PARAM2_ to the height's scale of _PARAM0_"),
|
||||
_("the height's scale"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("ChangeWidth",
|
||||
_("Width"),
|
||||
_("Change the width of a Sprite object."),
|
||||
_("Do _PARAM1__PARAM2_ to the width of _PARAM0_"),
|
||||
_("the width"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("ChangeHeight",
|
||||
_("Height"),
|
||||
_("Change the height of a Sprite object."),
|
||||
_("Do _PARAM1__PARAM2_ to the height of _PARAM0_"),
|
||||
_("the height"),
|
||||
_("Size"),
|
||||
"res/actions/scale24.png",
|
||||
"res/actions/scale.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition(
|
||||
"Animation",
|
||||
_("Current animation"),
|
||||
_("Compare the number of the current animation of the object."),
|
||||
_("The number of the current animation of _PARAM0_ is "
|
||||
"_PARAM1__PARAM2_"),
|
||||
_("Compare the number of the animation played by the object."),
|
||||
_("the number of the animation"),
|
||||
_("Animations and images"),
|
||||
"res/conditions/animation24.png",
|
||||
"res/conditions/animation.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Number to test"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("AnimationName",
|
||||
_("Current animation name"),
|
||||
_("Check the current animation of the object."),
|
||||
_("Check the animation by played by the object."),
|
||||
_("The animation of _PARAM0_ is _PARAM1_"),
|
||||
_("Animations and images"),
|
||||
"res/conditions/animation24.png",
|
||||
@@ -263,33 +239,29 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
_("Compare the direction of the object. If 8 direction mode is "
|
||||
"activated for the sprite, the value taken for direction will be "
|
||||
"from 0 to 7. Otherwise, the direction is in degrees."),
|
||||
_("Direction of _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the direction"),
|
||||
_("Direction"),
|
||||
"res/conditions/direction24.png",
|
||||
"res/conditions/direction.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Direction to test"))
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
obj.AddCondition("Sprite",
|
||||
_("Current frame"),
|
||||
_("Test the number of the current animation frame."),
|
||||
_("The animation frame of _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("Compare the index of the current frame in the animation displayed by the specified object. The first frame in an animation starts at index 0."),
|
||||
_("the animation frame"),
|
||||
_("Animations and images"),
|
||||
"res/conditions/sprite24.png",
|
||||
"res/conditions/sprite.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Animation frame to test"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("AnimStopped",
|
||||
_("Animation paused"),
|
||||
_("Test if the animation of an object is paused"),
|
||||
_("Check if the animation of an object is paused."),
|
||||
_("The animation of _PARAM0_ is paused"),
|
||||
_("Animations and images"),
|
||||
"res/conditions/animation24.png",
|
||||
@@ -313,62 +285,52 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
obj.AddCondition("ScaleWidth",
|
||||
_("Scale on X axis"),
|
||||
_("Compare the scale of the width of an object."),
|
||||
_("The width's scale of _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the width's scale"),
|
||||
_("Size"),
|
||||
"res/conditions/scaleWidth24.png",
|
||||
"res/conditions/scaleWidth.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("ScaleHeight",
|
||||
_("Scale on Y axis"),
|
||||
_("Compare the scale of the height of an object."),
|
||||
_("The height's scale of _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the height's scale"),
|
||||
_("Size"),
|
||||
"res/conditions/scaleHeight24.png",
|
||||
"res/conditions/scaleHeight.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddCondition("Opacity",
|
||||
_("Opacity"),
|
||||
_("Compare the opacity of a Sprite, between 0 (fully "
|
||||
"transparent) to 255 (opaque)."),
|
||||
_("The opacity of _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the opacity"),
|
||||
_("Visibility"),
|
||||
"res/conditions/opacity24.png",
|
||||
"res/conditions/opacity.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.MarkAsSimple()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddCondition(
|
||||
"BlendMode",
|
||||
_("Blend mode"),
|
||||
_("Compare the number of the blend mode currently used by an object"),
|
||||
_("The number of the current blend mode of _PARAM0_ is "
|
||||
"_PARAM1__PARAM2_"),
|
||||
_("the number of the current blend mode"),
|
||||
_("Effects"),
|
||||
"res/conditions/opacity24.png",
|
||||
"res/conditions/opacity.png")
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression",
|
||||
_("Value to compare (0: Alpha, 1: Add, 2: Multiply, 3: None)"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("CopyImageOnImageOfSprite",
|
||||
_("Copy an image on the current one of an object"),
|
||||
@@ -418,7 +380,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
obj.AddAction("ChangeBlendMode",
|
||||
_("Blend mode"),
|
||||
_("Change the number of the blend mode of an object.\nThe "
|
||||
"default blend mode is 0 (Alpha)."),
|
||||
"default blend mode is 0 (Normal)."),
|
||||
_("Change Blend mode of _PARAM0_ to _PARAM1_"),
|
||||
_("Effects"),
|
||||
"res/actions/color24.png",
|
||||
@@ -426,7 +388,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("expression",
|
||||
_("Mode (0 : Alpha, 1 : Add, 2 : Multiply, 3 : None)"))
|
||||
_("Mode (0: Normal, 1: Add, 2: Multiply, 3: Screen)"))
|
||||
.MarkAsSimple();
|
||||
|
||||
obj.AddAction("FlipX",
|
||||
|
@@ -107,8 +107,7 @@ void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
|
||||
}
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties(
|
||||
gd::Project& project) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties[_("Animate even if hidden or far from the screen")]
|
||||
.SetValue(updateIfNotVisible ? "true" : "false")
|
||||
@@ -119,8 +118,7 @@ std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties(
|
||||
}
|
||||
|
||||
bool SpriteObject::UpdateProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) {
|
||||
const gd::String& value) {
|
||||
if (name == _("Animate even if hidden or far from the screen"))
|
||||
updateIfNotVisible = value == "1";
|
||||
|
||||
|
@@ -48,11 +48,9 @@ class GD_CORE_API SpriteObject : public gd::Object {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
gd::Project& project) const override;
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
bool UpdateProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) override;
|
||||
const gd::String& value) override;
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
|
||||
const gd::InitialInstance& position,
|
||||
|
@@ -119,6 +119,18 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Manipulation of text"),
|
||||
"res/conditions/toujours24.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"))
|
||||
.SetHidden(); // Deprecated, see StrFindLast instead.
|
||||
|
||||
extension
|
||||
.AddExpression("StrFindLast",
|
||||
_("Search the last occurence in a text"),
|
||||
_("Search the last occurence in a string (return the position of "
|
||||
"the result, from the beginning of the string, or -1 if not found)"),
|
||||
_("Manipulation of text"),
|
||||
"res/conditions/toujours24.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"));
|
||||
|
||||
@@ -145,6 +157,22 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Manipulation of text"),
|
||||
"res/conditions/toujours24.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"))
|
||||
.AddParameter("expression",
|
||||
_("Position of the last character in the string to be "
|
||||
"considered in the search"))
|
||||
.SetHidden(); // Deprecated, see StrFindLastFrom instead.
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"StrFindLastFrom",
|
||||
_("Search the last occurence in a text, starting from a position"),
|
||||
_("Search in a text the last occurence, starting from a position (return "
|
||||
" the position of the result, from the beginning of the string, or -1 if not found)"),
|
||||
_("Manipulation of text"),
|
||||
"res/conditions/toujours24.png")
|
||||
|
||||
.AddParameter("string", _("Text"))
|
||||
.AddParameter("string", _("Text to search for"))
|
||||
.AddParameter("expression",
|
||||
|
@@ -38,15 +38,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
.AddCondition("TimeScale",
|
||||
_("Time scale"),
|
||||
_("Test the time scale."),
|
||||
_("The time scale is _PARAM1__PARAM2_"),
|
||||
_("the time scale"),
|
||||
_("Timers and time"),
|
||||
"res/conditions/time24.png",
|
||||
"res/conditions/time.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("TimerPaused",
|
||||
@@ -123,16 +121,16 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
|
||||
extension
|
||||
.AddExpression("TimeDelta",
|
||||
_("Time elapsed since the last image"),
|
||||
_("Time elapsed since the last image"),
|
||||
_("Time elapsed since the last frame"),
|
||||
_("Time elapsed since the last frame rendered on screen"),
|
||||
_("Time"),
|
||||
"res/actions/time.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
extension
|
||||
.AddExpression("TempsFrame",
|
||||
_("Time elapsed since the last image"),
|
||||
_("Time elapsed since the last image"),
|
||||
_("Time elapsed since the last frame"),
|
||||
_("Time elapsed since the last frame rendered on screen"),
|
||||
_("Time"),
|
||||
"res/actions/time.png")
|
||||
.SetHidden()
|
||||
@@ -140,8 +138,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
|
||||
|
||||
extension
|
||||
.AddExpression("ElapsedTime",
|
||||
_("Time elapsed since the last image"),
|
||||
_("Time elapsed since the last image"),
|
||||
_("Time elapsed since the last frame"),
|
||||
_("Time elapsed since the last frame rendered on screen"),
|
||||
_("Time"),
|
||||
"res/actions/time.png")
|
||||
.SetHidden()
|
||||
|
@@ -25,27 +25,23 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.AddCondition("VarScene",
|
||||
_("Value of a scene variable"),
|
||||
_("Compare the value of a scene variable."),
|
||||
_("Scene variable _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the scene variable _PARAM0_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number");
|
||||
|
||||
extension
|
||||
.AddCondition("VarSceneTxt",
|
||||
_("Text of a scene variable"),
|
||||
_("Compare the text of a scene variable."),
|
||||
_("The text of scene variable _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the text of scene variable _PARAM0_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("string", _("Text to compare"))
|
||||
.SetManipulatedType("string");
|
||||
.UseStandardRelationalOperatorParameters("string");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
@@ -89,30 +85,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.AddCondition("VarGlobal",
|
||||
_("Value of a global variable"),
|
||||
_("Compare the value of a global variable."),
|
||||
_("Global variable _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the global variable _PARAM0_"),
|
||||
_("Variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("expression", _("Value to compare"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardRelationalOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"VarGlobalTxt",
|
||||
_("Text of a global variable"),
|
||||
_("Compare the text of a global variable."),
|
||||
_("The text of the global variable _PARAM0_ is _PARAM1__PARAM2_"),
|
||||
_("the text of the global variable _PARAM0_"),
|
||||
_("Variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("relationalOperator", _("Sign of the test"))
|
||||
.AddParameter("string", _("Text to compare"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("string");
|
||||
.UseStandardRelationalOperatorParameters("string")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("VarGlobalDef",
|
||||
@@ -131,56 +123,48 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.AddAction("ModVarScene",
|
||||
_("Value of a scene variable"),
|
||||
_("Modify the value of a scene variable."),
|
||||
_("Do _PARAM1__PARAM2_ to scene variable _PARAM0_"),
|
||||
_("the scene variable _PARAM0_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number");
|
||||
|
||||
extension
|
||||
.AddAction("ModVarSceneTxt",
|
||||
_("String of a scene variable"),
|
||||
_("Modify the text of a scene variable."),
|
||||
_("Do _PARAM1__PARAM2_ to the text of scene variable _PARAM0_"),
|
||||
_("the text of scene variable _PARAM0_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("string", _("Text"))
|
||||
.SetManipulatedType("string");
|
||||
.UseStandardOperatorParameters("string");
|
||||
|
||||
extension
|
||||
.AddAction("ModVarGlobal",
|
||||
_("Value of a global variable"),
|
||||
_("Modify the value of a global variable"),
|
||||
_("Do _PARAM1__PARAM2_ to global variable _PARAM0_"),
|
||||
_("the global variable _PARAM0_"),
|
||||
_("Variables/Global variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("expression", _("Value"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("number");
|
||||
.UseStandardOperatorParameters("number")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"ModVarGlobalTxt",
|
||||
_("String of a global variable"),
|
||||
_("Modify the text of a global variable."),
|
||||
_("Do _PARAM1__PARAM2_ to the text of global variable _PARAM0_"),
|
||||
_("the text of global variable _PARAM0_"),
|
||||
_("Variables/Global variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("operator", _("Modification's sign"))
|
||||
.AddParameter("string", _("Text"))
|
||||
.MarkAsAdvanced()
|
||||
.SetManipulatedType("string");
|
||||
.UseStandardOperatorParameters("string")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("VariableRemoveChild",
|
||||
|
@@ -27,7 +27,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
|
||||
_("De/activate fullscreen"),
|
||||
_("This action activates or deactivates fullscreen."),
|
||||
_("Activate fullscreen: _PARAM1_ (keep aspect ratio: _PARAM2_)"),
|
||||
_("Game's window"),
|
||||
_("Game's window and resolution"),
|
||||
"res/actions/fullscreen24.png",
|
||||
"res/actions/fullscreen.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -41,11 +41,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
|
||||
extension
|
||||
.AddAction("SetWindowMargins",
|
||||
_("Change the window's margins"),
|
||||
_("This action changes the margins, in pixels, of the game's "
|
||||
"window."),
|
||||
_("This action changes the margins, in pixels, between the "
|
||||
"game frame and the window borders."),
|
||||
_("Set margins of game window to "
|
||||
"_PARAM1_;_PARAM2_;_PARAM3_;_PARAM4_"),
|
||||
_("Game's window"),
|
||||
_("Game's window and resolution"),
|
||||
"res/actions/window24.png",
|
||||
"res/actions/window.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -55,28 +55,93 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
|
||||
.AddParameter("expression", _("Left"));
|
||||
|
||||
extension
|
||||
.AddAction("SetWindowSize",
|
||||
_("Change the size of the window"),
|
||||
_("This action changes the size of the game's window."),
|
||||
_("Change window size: _PARAM1_x_PARAM2_"),
|
||||
_("Game's window"),
|
||||
.AddAction("SetGameResolutionSize",
|
||||
_("Change the resolution of the game"),
|
||||
_("Changes the resolution of the game, effectively changing "
|
||||
"the game area size. This won't change the size of the "
|
||||
"window in which the game is running."),
|
||||
_("Set game resolution to _PARAM1_x_PARAM2_"),
|
||||
_("Game's window and resolution"),
|
||||
"res/actions/window24.png",
|
||||
"res/actions/window.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Width"))
|
||||
.AddParameter("expression", _("Height"));
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"SetWindowSize",
|
||||
_("Change the size of the game window"),
|
||||
_("This action changes the size of the game window. Note that this "
|
||||
"will only work on platform supporting this operation: games "
|
||||
"running in browsers or on mobile phones can not update their "
|
||||
"window size. Game resolution can still be updated."),
|
||||
_("Set game window size to _PARAM1_x_PARAM2_ (also update game "
|
||||
"resolution: _PARAM3_)"),
|
||||
_("Game's window and resolution"),
|
||||
"res/actions/window24.png",
|
||||
"res/actions/window.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Width"))
|
||||
.AddParameter("expression", _("Height"))
|
||||
.AddParameter(
|
||||
"yesorno",
|
||||
_("Do you want to use this size as the default size for new scene "
|
||||
"cameras\?\n(Yes to change the size of the game's viewable "
|
||||
"area,\nNo to stretch the game to the window's size)."));
|
||||
.AddParameter("yesorno",
|
||||
_("Also update the game resolution? If not, the game will "
|
||||
"be stretched or reduced to fit in the window."));
|
||||
|
||||
extension
|
||||
.AddAction("CenterWindow",
|
||||
_("Center the game window on the screen"),
|
||||
_("This action centers the game window on the screen. This "
|
||||
"only works on Windows, macOS and Linux (not when the game "
|
||||
"is executed in a web-browser or on iOS/Android)."),
|
||||
_("Center the game window"),
|
||||
_("Game's window and resolution"),
|
||||
"res/actions/window24.png",
|
||||
"res/actions/window.png")
|
||||
.AddCodeOnlyParameter("currentScene", "");
|
||||
|
||||
extension
|
||||
.AddAction("SetGameResolutionResizeMode",
|
||||
_("Change the game resolution resize mode"),
|
||||
_("Set if the width or the height of the game resolution "
|
||||
"should be changed to fit the game window - or if the game "
|
||||
"resolution should not be updated automatically."),
|
||||
_("Set game resolution resize mode to _PARAM1_"),
|
||||
_("Game's window and resolution"),
|
||||
"res/actions/window24.png",
|
||||
"res/actions/window.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("stringWithSelector",
|
||||
_("Resize mode"),
|
||||
"[\"adaptWidth\", \"adaptHeight\", \"\"]",
|
||||
false)
|
||||
.SetParameterLongDescription(
|
||||
_("Empty to disable resizing. \"adaptWidth\" will update the game "
|
||||
"width to fit in the window or screen. \"adaptHeight\" will do the "
|
||||
"same but with the game height."));
|
||||
|
||||
extension
|
||||
.AddAction("SetAdaptGameResolutionAtRuntime",
|
||||
_("Automatically adapt the game resolution"),
|
||||
_("Set if the game resolution should be automatically adapted "
|
||||
"when the game window or screen size change. This will only "
|
||||
"be the case if the game resolution resize mode is "
|
||||
"configured to adapt the width or the height of the game."),
|
||||
_("Automatically adapt the game resolution: _PARAM1_"),
|
||||
_("Game's window and resolution"),
|
||||
"res/actions/window24.png",
|
||||
"res/actions/window.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("yesorno",
|
||||
_("Update resolution during the game to fit the screen or "
|
||||
"window size?"));
|
||||
|
||||
extension
|
||||
.AddAction("SetWindowIcon",
|
||||
_("Change the window's icon"),
|
||||
_("This action changes the icon of the game's window."),
|
||||
_("Use _PARAM1_ as the icon for the game's window."),
|
||||
_("Game's window"),
|
||||
_("Game's window and resolution"),
|
||||
"res/actions/window24.png",
|
||||
"res/actions/window.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -87,7 +152,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
|
||||
_("Change the window's title"),
|
||||
_("This action changes the title of the game's window."),
|
||||
_("Change window title to _PARAM1_"),
|
||||
_("Game's window"),
|
||||
_("Game's window and resolution"),
|
||||
"res/actions/window24.png",
|
||||
"res/actions/window.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
|
@@ -59,7 +59,8 @@ gd::InstructionMetadata& BehaviorMetadata::AddCondition(
|
||||
group,
|
||||
icon,
|
||||
smallicon)
|
||||
.SetHelpPath(GetHelpPath());
|
||||
.SetHelpPath(GetHelpPath())
|
||||
.SetIsBehaviorInstruction();
|
||||
return conditionsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
@@ -83,7 +84,8 @@ gd::InstructionMetadata& BehaviorMetadata::AddAction(
|
||||
group,
|
||||
icon,
|
||||
smallicon)
|
||||
.SetHelpPath(GetHelpPath());
|
||||
.SetHelpPath(GetHelpPath())
|
||||
.SetIsBehaviorInstruction();
|
||||
return actionsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
@@ -107,7 +109,8 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedCondition(
|
||||
group,
|
||||
icon,
|
||||
smallicon)
|
||||
.SetHelpPath(GetHelpPath());
|
||||
.SetHelpPath(GetHelpPath())
|
||||
.SetIsBehaviorInstruction();
|
||||
return conditionsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
@@ -131,7 +134,8 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedAction(
|
||||
group,
|
||||
icon,
|
||||
smallicon)
|
||||
.SetHelpPath(GetHelpPath());
|
||||
.SetHelpPath(GetHelpPath())
|
||||
.SetIsBehaviorInstruction();
|
||||
return actionsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
|
@@ -3,23 +3,24 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "InstructionMetadata.h"
|
||||
#include <algorithm>
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "InstructionMetadata.h"
|
||||
|
||||
namespace gd {
|
||||
InstructionMetadata::InstructionMetadata()
|
||||
: sentence(
|
||||
"Unknown or unsupported instruction"), // Avoid translating this
|
||||
// string, so that it's safe
|
||||
// and *fast* to use a
|
||||
// InstructionMetadata.
|
||||
: sentence("Unknown or unsupported instruction"), // Avoid translating this
|
||||
// string, so that it's
|
||||
// safe and *fast* to use
|
||||
// a InstructionMetadata.
|
||||
canHaveSubInstructions(false),
|
||||
hidden(true),
|
||||
usageComplexity(5),
|
||||
isPrivate(false) {}
|
||||
isPrivate(false),
|
||||
isObjectInstruction(false),
|
||||
isBehaviorInstruction(false) {}
|
||||
|
||||
InstructionMetadata::InstructionMetadata(const gd::String& extensionNamespace_,
|
||||
const gd::String& name_,
|
||||
@@ -40,8 +41,9 @@ InstructionMetadata::InstructionMetadata(const gd::String& extensionNamespace_,
|
||||
extensionNamespace(extensionNamespace_),
|
||||
hidden(false),
|
||||
usageComplexity(5),
|
||||
isPrivate(false) {
|
||||
}
|
||||
isPrivate(false),
|
||||
isObjectInstruction(false),
|
||||
isBehaviorInstruction(false) {}
|
||||
|
||||
ParameterMetadata::ParameterMetadata() : optional(false), codeOnly(false) {}
|
||||
|
||||
@@ -86,6 +88,76 @@ InstructionMetadata& InstructionMetadata::AddCodeOnlyParameter(
|
||||
return *this;
|
||||
}
|
||||
|
||||
InstructionMetadata& InstructionMetadata::UseStandardOperatorParameters(
|
||||
const gd::String& type) {
|
||||
SetManipulatedType(type);
|
||||
|
||||
AddParameter("operator", _("Modification's sign"));
|
||||
AddParameter(type == "number" ? "expression" : type, _("Value"));
|
||||
size_t operatorParamIndex = parameters.size() - 2;
|
||||
size_t valueParamIndex = parameters.size() - 1;
|
||||
|
||||
if (isObjectInstruction || isBehaviorInstruction) {
|
||||
gd::String templateSentence =
|
||||
_("Change <subject> of _PARAM0_: <operator> <value>");
|
||||
|
||||
sentence =
|
||||
templateSentence.FindAndReplace("<subject>", sentence)
|
||||
.FindAndReplace(
|
||||
"<operator>",
|
||||
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
|
||||
.FindAndReplace("<value>",
|
||||
"_PARAM" + gd::String::From(valueParamIndex) + "_");
|
||||
} else {
|
||||
gd::String templateSentence = _("Change <subject>: <operator> <value>");
|
||||
|
||||
sentence =
|
||||
templateSentence.FindAndReplace("<subject>", sentence)
|
||||
.FindAndReplace(
|
||||
"<operator>",
|
||||
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
|
||||
.FindAndReplace("<value>",
|
||||
"_PARAM" + gd::String::From(valueParamIndex) + "_");
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
InstructionMetadata&
|
||||
InstructionMetadata::UseStandardRelationalOperatorParameters(
|
||||
const gd::String& type) {
|
||||
SetManipulatedType(type);
|
||||
|
||||
AddParameter("relationalOperator", _("Sign of the test"));
|
||||
AddParameter(type == "number" ? "expression" : type, _("Value to compare"));
|
||||
size_t operatorParamIndex = parameters.size() - 2;
|
||||
size_t valueParamIndex = parameters.size() - 1;
|
||||
|
||||
if (isObjectInstruction || isBehaviorInstruction) {
|
||||
gd::String templateSentence = _("<subject> of _PARAM0_ <operator> <value>");
|
||||
|
||||
sentence =
|
||||
templateSentence.FindAndReplace("<subject>", sentence)
|
||||
.FindAndReplace(
|
||||
"<operator>",
|
||||
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
|
||||
.FindAndReplace("<value>",
|
||||
"_PARAM" + gd::String::From(valueParamIndex) + "_");
|
||||
} else {
|
||||
gd::String templateSentence = _("<subject> <operator> <value>");
|
||||
|
||||
sentence =
|
||||
templateSentence.FindAndReplace("<subject>", sentence)
|
||||
.FindAndReplace(
|
||||
"<operator>",
|
||||
"_PARAM" + gd::String::From(operatorParamIndex) + "_")
|
||||
.FindAndReplace("<value>",
|
||||
"_PARAM" + gd::String::From(valueParamIndex) + "_");
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ParameterMetadata::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("type", type);
|
||||
element.SetAttribute("supplementaryInformation", supplementaryInformation);
|
||||
|
@@ -222,10 +222,10 @@ class GD_CORE_API ParameterMetadata {
|
||||
///< i.e. must not be shown in editor
|
||||
private:
|
||||
gd::String longDescription; ///< Long description shown in the editor.
|
||||
gd::String defaultValue; ///< Used as a default value in editor or if an
|
||||
///< optional parameter is empty.
|
||||
gd::String name; ///< The name of the parameter to be used in code
|
||||
///< generation. Optional.
|
||||
gd::String defaultValue; ///< Used as a default value in editor or if an
|
||||
///< optional parameter is empty.
|
||||
gd::String name; ///< The name of the parameter to be used in code
|
||||
///< generation. Optional.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -355,10 +355,10 @@ class GD_CORE_API InstructionMetadata {
|
||||
* \brief Add a parameter not displayed in editor.
|
||||
*
|
||||
* \param type One of the type handled by GDevelop. This will also determine
|
||||
* the type of the argument used when calling the function in the generated code.
|
||||
* \param supplementaryInformation Depends on `type`. For example, when `type ==
|
||||
* "inlineCode"`, the content of supplementaryInformation is inserted in the
|
||||
* generated code.
|
||||
* the type of the argument used when calling the function in the generated
|
||||
* code. \param supplementaryInformation Depends on `type`. For example, when
|
||||
* `type == "inlineCode"`, the content of supplementaryInformation is inserted
|
||||
* in the generated code.
|
||||
*
|
||||
* \see EventsCodeGenerator::GenerateParametersCodes
|
||||
*/
|
||||
@@ -371,21 +371,55 @@ class GD_CORE_API InstructionMetadata {
|
||||
*
|
||||
* \see AddParameter
|
||||
*/
|
||||
InstructionMetadata &SetDefaultValue(gd::String defaultValue_) {
|
||||
InstructionMetadata &SetDefaultValue(const gd::String &defaultValue_) {
|
||||
if (!parameters.empty()) parameters.back().SetDefaultValue(defaultValue_);
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Set the long description shown in the editor for the last added parameter.
|
||||
* \brief Set the long description shown in the editor for the last added
|
||||
* parameter.
|
||||
*
|
||||
* \see AddParameter
|
||||
*/
|
||||
InstructionMetadata &SetParameterLongDescription(gd::String longDescription) {
|
||||
if (!parameters.empty()) parameters.back().SetLongDescription(longDescription);
|
||||
InstructionMetadata &SetParameterLongDescription(
|
||||
const gd::String &longDescription) {
|
||||
if (!parameters.empty())
|
||||
parameters.back().SetLongDescription(longDescription);
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Add the default parameters for an instruction manipulating the
|
||||
* specified type ("string", "number") with the default operators.
|
||||
*/
|
||||
InstructionMetadata &UseStandardOperatorParameters(const gd::String &type);
|
||||
|
||||
/**
|
||||
* \brief Add the default parameters for an instruction comparing the
|
||||
* specified type ("string", "number") with the default relational operators.
|
||||
*/
|
||||
InstructionMetadata &UseStandardRelationalOperatorParameters(
|
||||
const gd::String &type);
|
||||
|
||||
/**
|
||||
* \brief Mark the instruction as an object instruction. Automatically called
|
||||
* when using `AddAction`/`AddCondition` on an `ObjectMetadata`.
|
||||
*/
|
||||
InstructionMetadata &SetIsObjectInstruction() {
|
||||
isObjectInstruction = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Mark the instruction as a behavior instruction. Automatically called
|
||||
* when using `AddAction`/`AddCondition` on a `BehaviorMetadata`.
|
||||
*/
|
||||
InstructionMetadata &SetIsBehaviorInstruction() {
|
||||
isBehaviorInstruction = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Consider that the instruction is easy for an user to understand.
|
||||
*/
|
||||
@@ -454,7 +488,7 @@ class GD_CORE_API InstructionMetadata {
|
||||
* obj.AddAction("String",
|
||||
* _("Change the string"),
|
||||
* _("Change the string of a text"),
|
||||
* _("Do _PARAM1__PARAM2_ to the string of _PARAM0_"),
|
||||
* _("the string"),
|
||||
* _("Text"),
|
||||
* "CppPlatform/Extensions/text24.png",
|
||||
* "CppPlatform/Extensions/text.png");
|
||||
@@ -587,6 +621,8 @@ class GD_CORE_API InstructionMetadata {
|
||||
int usageComplexity; ///< Evaluate the instruction from 0 (simple&easy to
|
||||
///< use) to 10 (complex to understand)
|
||||
bool isPrivate;
|
||||
bool isObjectInstruction;
|
||||
bool isBehaviorInstruction;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -77,7 +77,8 @@ gd::InstructionMetadata& ObjectMetadata::AddCondition(
|
||||
group,
|
||||
icon,
|
||||
smallicon)
|
||||
.SetHelpPath(GetHelpPath());
|
||||
.SetHelpPath(GetHelpPath())
|
||||
.SetIsObjectInstruction();
|
||||
return conditionsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
@@ -101,7 +102,8 @@ gd::InstructionMetadata& ObjectMetadata::AddAction(
|
||||
group,
|
||||
icon,
|
||||
smallicon)
|
||||
.SetHelpPath(GetHelpPath());
|
||||
.SetHelpPath(GetHelpPath())
|
||||
.SetIsObjectInstruction();
|
||||
return actionsInfos[nameWithNamespace];
|
||||
#endif
|
||||
}
|
||||
|
@@ -90,7 +90,7 @@ size_t ParameterMetadataTools::GetObjectParameterIndexFor(
|
||||
// the object in the list of parameters (if possible, just after).
|
||||
// Search "lastObjectName" in the codebase for other place where this
|
||||
// convention is enforced.
|
||||
for (std::size_t pNb = parameterIndex - 1; pNb < parametersMetadata.size();
|
||||
for (std::size_t pNb = parameterIndex; pNb < parametersMetadata.size();
|
||||
pNb--) {
|
||||
if (gd::ParameterMetadata::IsObject(parametersMetadata[pNb].GetType())) {
|
||||
return pNb;
|
||||
|
@@ -14,19 +14,19 @@ using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
Platform::Platform() {}
|
||||
Platform::Platform(): enableExtensionLoadingLogs(true) {}
|
||||
|
||||
Platform::~Platform() {}
|
||||
|
||||
bool Platform::AddExtension(std::shared_ptr<gd::PlatformExtension> extension) {
|
||||
if (!extension) return false;
|
||||
|
||||
std::cout << "Loading " << extension->GetName() << "...";
|
||||
if (enableExtensionLoadingLogs) std::cout << "Loading " << extension->GetName() << "...";
|
||||
if (IsExtensionLoaded(extension->GetName())) {
|
||||
std::cout << " (replacing existing extension)";
|
||||
if (enableExtensionLoadingLogs) std::cout << " (replacing existing extension)";
|
||||
RemoveExtension(extension->GetName());
|
||||
}
|
||||
std::cout << std::endl;
|
||||
if (enableExtensionLoadingLogs) std::cout << std::endl;
|
||||
|
||||
extensionsLoaded.push_back(extension);
|
||||
|
||||
|
@@ -156,6 +156,12 @@ class GD_CORE_API Platform {
|
||||
|
||||
///@}
|
||||
|
||||
/**
|
||||
* \brief Activate or disable the logs on the standard output when
|
||||
* loading an extension.
|
||||
*/
|
||||
void EnableExtensionLoadingLogs(bool enable) { enableExtensionLoadingLogs = enable; };
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE is about to shut down: Take this opportunity for
|
||||
* erasing for example any temporary file.
|
||||
@@ -174,6 +180,7 @@ class GD_CORE_API Platform {
|
||||
extensionsLoaded; ///< Extensions of the platform
|
||||
std::map<gd::String, CreateFunPtr>
|
||||
creationFunctionTable; ///< Creation functions for objects
|
||||
bool enableExtensionLoadingLogs;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -63,7 +63,16 @@ class GD_CORE_API ExpressionObjectsAnalyzer
|
||||
context.AddObjectName(node.identifierName);
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionNode(FunctionNode& node) override {
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
if (!node.objectName.empty()) {
|
||||
context.AddObjectName(node.objectName);
|
||||
|
||||
if (!node.behaviorFunctionName.empty()) {
|
||||
context.AddBehaviorName(node.objectName, node.objectFunctionOrBehaviorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
if (!node.objectName.empty()) {
|
||||
context.AddObjectName(node.objectName);
|
||||
|
||||
|
@@ -35,7 +35,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
virtual ~ExpressionObjectRenamer(){};
|
||||
|
||||
static bool Rename(gd::ExpressionNode & node, const gd::String& objectName, const gd::String& objectNewName) {
|
||||
if (ExpressionValidator::HasNoErrors(node)) {
|
||||
if (ExpressionValidator::HasNoErrors(node)) {
|
||||
ExpressionObjectRenamer renamer(objectName, objectNewName);
|
||||
node.Visit(renamer);
|
||||
|
||||
@@ -77,7 +77,13 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
|
||||
node.identifierName = objectNewName;
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionNode(FunctionNode& node) override {
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
if (node.objectName == objectName) {
|
||||
hasDoneRenaming = true;
|
||||
node.objectName = objectNewName;
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
if (node.objectName == objectName) {
|
||||
hasDoneRenaming = true;
|
||||
node.objectName = objectNewName;
|
||||
@@ -107,7 +113,7 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
|
||||
virtual ~ExpressionObjectFinder(){};
|
||||
|
||||
static bool CheckIfHasObject(gd::ExpressionNode & node, const gd::String & objectName) {
|
||||
if (ExpressionValidator::HasNoErrors(node)) {
|
||||
if (ExpressionValidator::HasNoErrors(node)) {
|
||||
ExpressionObjectFinder finder(objectName);
|
||||
node.Visit(finder);
|
||||
|
||||
@@ -148,7 +154,12 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
|
||||
hasObject = true;
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionNode(FunctionNode& node) override {
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
if (node.objectName == objectName) {
|
||||
hasObject = true;
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
if (node.objectName == objectName) {
|
||||
hasObject = true;
|
||||
}
|
||||
@@ -184,7 +195,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
actions[aId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
@@ -194,7 +205,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
actions[aId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
@@ -237,7 +248,7 @@ bool EventsRefactorer::RenameObjectInConditions(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
conditions[cId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
@@ -247,7 +258,7 @@ bool EventsRefactorer::RenameObjectInConditions(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
conditions[cId].SetParameter(pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
@@ -268,6 +279,43 @@ bool EventsRefactorer::RenameObjectInConditions(
|
||||
return somethingModified;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::RenameObjectInEventParameters(
|
||||
const gd::Platform& platform,
|
||||
gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::Expression& expression,
|
||||
gd::ParameterMetadata parameterMetadata,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
bool somethingModified = false;
|
||||
|
||||
if (gd::ParameterMetadata::IsObject(parameterMetadata.GetType()) &&
|
||||
expression.GetPlainString() == oldName)
|
||||
expression = gd::Expression(newName);
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", parameterMetadata.GetType())) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", expression.GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
}
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", parameterMetadata.GetType())) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", expression.GetPlainString());
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
|
||||
expression = ExpressionParser2NodePrinter::PrintNode(*node);
|
||||
}
|
||||
}
|
||||
|
||||
return somethingModified;
|
||||
}
|
||||
|
||||
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
|
||||
gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
@@ -289,6 +337,15 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
|
||||
platform, project, layout, *actionsVectors[j], oldName, newName);
|
||||
}
|
||||
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata>> expressionsWithMetadata =
|
||||
events[i].GetAllExpressionsWithMetadata();
|
||||
for (std::size_t j = 0; j < expressionsWithMetadata.size(); ++j) {
|
||||
gd::Expression* expression = expressionsWithMetadata[j].first;
|
||||
gd::ParameterMetadata parameterMetadata = expressionsWithMetadata[j].second;
|
||||
bool somethingModified = RenameObjectInEventParameters(
|
||||
platform, project, layout, *expression, parameterMetadata, oldName, newName);
|
||||
}
|
||||
|
||||
if (events[i].CanHaveSubEvents())
|
||||
RenameObjectInEvents(platform,
|
||||
project,
|
||||
@@ -323,7 +380,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
break;
|
||||
@@ -334,7 +391,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", actions[aId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
break;
|
||||
@@ -384,7 +441,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("number", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
break;
|
||||
@@ -395,7 +452,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
gd::ExpressionParser2 parser(platform, project, layout);
|
||||
auto node = parser.ParseExpression("string", conditions[cId].GetParameter(pNb).GetPlainString());
|
||||
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
|
||||
deleteMe = true;
|
||||
break;
|
||||
@@ -595,7 +652,8 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool inConditions,
|
||||
bool inActions) {
|
||||
bool inActions,
|
||||
bool inEventStrings) {
|
||||
vector<EventsSearchResult> results;
|
||||
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
@@ -631,6 +689,16 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
}
|
||||
}
|
||||
|
||||
if (inEventStrings) {
|
||||
if (!eventAddedInResults &&
|
||||
SearchStringInEvent(project, layout, events[i], search, matchCase)) {
|
||||
results.push_back(EventsSearchResult(
|
||||
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
|
||||
&events,
|
||||
i));
|
||||
}
|
||||
}
|
||||
|
||||
if (events[i].CanHaveSubEvents()) {
|
||||
vector<EventsSearchResult> subResults =
|
||||
SearchInEvents(project,
|
||||
@@ -639,7 +707,8 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
|
||||
search,
|
||||
matchCase,
|
||||
inConditions,
|
||||
inActions);
|
||||
inActions,
|
||||
inEventStrings);
|
||||
std::copy(
|
||||
subResults.begin(), subResults.end(), std::back_inserter(results));
|
||||
}
|
||||
@@ -711,6 +780,22 @@ bool EventsRefactorer::SearchStringInConditions(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsRefactorer::SearchStringInEvent(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::BaseEvent& event,
|
||||
gd::String search,
|
||||
bool matchCase) {
|
||||
for (gd::String str : event.GetAllSearchableStrings()) {
|
||||
if (matchCase) {
|
||||
if (str.find(search) != gd::String::npos) return true;
|
||||
} else {
|
||||
if (str.FindCaseInsensitive(search) != gd::String::npos) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EventsSearchResult::EventsSearchResult(std::weak_ptr<gd::BaseEvent> event_,
|
||||
gd::EventsList* eventsList_,
|
||||
std::size_t positionInList_)
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class EventsList;
|
||||
@@ -103,7 +104,8 @@ class GD_CORE_API EventsRefactorer {
|
||||
gd::String search,
|
||||
bool matchCase,
|
||||
bool inConditions,
|
||||
bool inAction);
|
||||
bool inActions,
|
||||
bool inEventStrings);
|
||||
|
||||
/**
|
||||
* Replace all occurrences of a gd::String in events
|
||||
@@ -145,6 +147,20 @@ class GD_CORE_API EventsRefactorer {
|
||||
gd::InstructionsList& instructions,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
/**
|
||||
* Replace all occurrences of an object name by another name in an expression
|
||||
* with the specified metadata
|
||||
* ( include : objects or objects in math/text expressions ).
|
||||
*
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RenameObjectInEventParameters(const gd::Platform& platform,
|
||||
gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::Expression& expression,
|
||||
gd::ParameterMetadata parameterMetadata,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
|
||||
/**
|
||||
* Remove all conditions of the list using an object
|
||||
@@ -202,6 +218,11 @@ class GD_CORE_API EventsRefactorer {
|
||||
gd::InstructionsList& conditions,
|
||||
gd::String search,
|
||||
bool matchCase);
|
||||
static bool SearchStringInEvent(gd::ObjectsContainer& project,
|
||||
gd::ObjectsContainer& layout,
|
||||
gd::BaseEvent& events,
|
||||
gd::String search,
|
||||
bool matchCase);
|
||||
|
||||
EventsRefactorer(){};
|
||||
};
|
||||
|
@@ -63,7 +63,8 @@ class GD_CORE_API ExpressionParameterSearcher
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {}
|
||||
void OnVisitFunctionNode(FunctionNode& node) override {
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
bool considerFunction = objectName.empty() || node.objectName == objectName;
|
||||
for (size_t i = 0; i < node.parameters.size() &&
|
||||
i < node.expressionMetadata.parameters.size();
|
||||
|
366
Core/GDCore/IDE/Events/ExpressionCompletionFinder.h
Normal file
366
Core/GDCore/IDE/Events/ExpressionCompletionFinder.h
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
#define GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
|
||||
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
class Platform;
|
||||
class ParameterMetadata;
|
||||
class ExpressionMetadata;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Describe completions to be shown to the user.
|
||||
*
|
||||
* The IDE is responsible for actually *searching* and showing the completions -
|
||||
* this is only describing what must be listed.
|
||||
*/
|
||||
struct ExpressionCompletionDescription {
|
||||
public:
|
||||
/**
|
||||
* The different kind of completions that can be described.
|
||||
*/
|
||||
enum CompletionKind {
|
||||
Object,
|
||||
Behavior,
|
||||
Expression,
|
||||
Variable,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Create a completion for an object with the given prefix
|
||||
*/
|
||||
static ExpressionCompletionDescription ForObject(const gd::String& type_,
|
||||
const gd::String& prefix_) {
|
||||
return ExpressionCompletionDescription(Object, type_, prefix_);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create a completion for a behavior with the given prefix of
|
||||
* the specified object
|
||||
*/
|
||||
static ExpressionCompletionDescription ForBehavior(
|
||||
const gd::String& prefix_, const gd::String& objectName_) {
|
||||
return ExpressionCompletionDescription(Behavior, "", prefix_, objectName_);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create a completion for a variable with the given prefix
|
||||
*/
|
||||
static ExpressionCompletionDescription ForVariable(
|
||||
const gd::String& type_, const gd::String& prefix_) {
|
||||
return ExpressionCompletionDescription(Variable, type_, prefix_);
|
||||
}
|
||||
/**
|
||||
* \brief Create a completion for an expression (free, object or behavior
|
||||
* expression) with the given prefix
|
||||
*/
|
||||
static ExpressionCompletionDescription ForExpression(
|
||||
const gd::String& type_,
|
||||
const gd::String& prefix_,
|
||||
const gd::String& objectName_ = "",
|
||||
const gd::String& behaviorName_ = "") {
|
||||
return ExpressionCompletionDescription(
|
||||
Expression, type_, prefix_, objectName_, behaviorName_);
|
||||
}
|
||||
|
||||
/** Check if two description of completions are equal */
|
||||
bool operator==(const ExpressionCompletionDescription& other) const {
|
||||
return completionKind == other.completionKind && type == other.type &&
|
||||
prefix == other.prefix && objectName == other.objectName &&
|
||||
behaviorName == other.behaviorName;
|
||||
};
|
||||
|
||||
/** \brief Return the kind of the completion */
|
||||
CompletionKind GetCompletionKind() const { return completionKind; }
|
||||
|
||||
/**
|
||||
* \brief Return the type of the completion (same type as types supported in
|
||||
* expressions)
|
||||
* (in other words, for expression this is the type of what must be returned).
|
||||
*/
|
||||
const gd::String& GetType() const { return type; }
|
||||
|
||||
/**
|
||||
* \brief Return the prefix currently entered and that must be completed.
|
||||
*/
|
||||
const gd::String& GetPrefix() const { return prefix; }
|
||||
|
||||
/**
|
||||
* \brief Return the object name, if completing an object expression or a
|
||||
* behavior.
|
||||
*/
|
||||
const gd::String& GetObjectName() const { return objectName; }
|
||||
|
||||
/**
|
||||
* \brief Return the behavior name, if completing an object behavior
|
||||
* expression.
|
||||
*
|
||||
* \warning If completing a behavior, the behavior (partial) name is returned
|
||||
* by `GetPrefix`.
|
||||
*/
|
||||
const gd::String& GetBehaviorName() const { return behaviorName; }
|
||||
|
||||
/**
|
||||
* \brief Set if the completion description is exact, i.e: it's not used
|
||||
* to complete anything. Rather, it should display information about what is
|
||||
* described by the completion.
|
||||
*/
|
||||
ExpressionCompletionDescription& SetIsExact(bool isExact_) {
|
||||
isExact = isExact_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the completion description is exact, i.e: it's not
|
||||
* used to complete anything. Rather, it should display information
|
||||
* about what is described by the completion.
|
||||
*/
|
||||
bool IsExact() const { return isExact; }
|
||||
|
||||
/** Default constructor, only to be used by Emscripten bindings. */
|
||||
ExpressionCompletionDescription() : completionKind(Object){};
|
||||
|
||||
private:
|
||||
ExpressionCompletionDescription(CompletionKind completionKind_,
|
||||
const gd::String& type_,
|
||||
const gd::String& prefix_,
|
||||
const gd::String& objectName_ = "",
|
||||
const gd::String& behaviorName_ = "")
|
||||
: completionKind(completionKind_),
|
||||
type(type_),
|
||||
prefix(prefix_),
|
||||
objectName(objectName_),
|
||||
behaviorName(behaviorName_),
|
||||
isExact(false) {}
|
||||
|
||||
CompletionKind completionKind;
|
||||
gd::String type;
|
||||
gd::String prefix;
|
||||
gd::String objectName;
|
||||
gd::String behaviorName;
|
||||
bool isExact;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Turn an ExpressionCompletionDescription to a string.
|
||||
*/
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
ExpressionCompletionDescription const& value) {
|
||||
os << "{ " << value.GetCompletionKind() << ", " << value.GetType() << ", "
|
||||
<< value.GetPrefix() << ", " << value.GetObjectName() << ", "
|
||||
<< value.GetBehaviorName() << ", "
|
||||
<< (value.IsExact() ? "exact" : "non-exact") << " }";
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the list of completion descriptions for an expression node.
|
||||
*
|
||||
* \see gd::ExpressionCompletionDescription
|
||||
*/
|
||||
class GD_CORE_API ExpressionCompletionFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
/**
|
||||
* \brief Given the expression, find the node at the specified location
|
||||
* and returns completions for it.
|
||||
*/
|
||||
static std::vector<ExpressionCompletionDescription>
|
||||
GetCompletionDescriptionsFor(gd::ExpressionNode& node,
|
||||
size_t searchedPosition) {
|
||||
gd::ExpressionNode* nodeAtLocation =
|
||||
gd::ExpressionNodeLocationFinder::GetNodeAtPosition(node,
|
||||
searchedPosition);
|
||||
|
||||
if (nodeAtLocation == nullptr) {
|
||||
std::vector<ExpressionCompletionDescription> emptyCompletions;
|
||||
return emptyCompletions;
|
||||
}
|
||||
|
||||
gd::ExpressionCompletionFinder autocompletionProvider(searchedPosition);
|
||||
nodeAtLocation->Visit(autocompletionProvider);
|
||||
return autocompletionProvider.GetCompletionDescriptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the completions found for the visited node.
|
||||
*/
|
||||
const std::vector<ExpressionCompletionDescription>&
|
||||
GetCompletionDescriptions() {
|
||||
return completions;
|
||||
};
|
||||
|
||||
virtual ~ExpressionCompletionFinder(){};
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForObject(node.type, ""));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpression(node.type, ""));
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForObject(node.type, ""));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpression(node.type, ""));
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForObject(node.type, ""));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpression(node.type, ""));
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {
|
||||
// No completions
|
||||
}
|
||||
void OnVisitTextNode(TextNode& node) override {
|
||||
// No completions
|
||||
}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForVariable(node.type, node.name));
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
// No completions
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
// No completions
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (gd::ParameterMetadata::IsObject(node.type)) {
|
||||
// Only show completions of objects if an object is required
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.identifierName));
|
||||
} else {
|
||||
// Show completions for expressions and objects otherwise.
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.identifierName));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, node.identifierName));
|
||||
}
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
if (!node.behaviorFunctionName.empty() ||
|
||||
node.behaviorNameNamespaceSeparatorLocation.IsValid()) {
|
||||
// Behavior function (or behavior function being written, with the
|
||||
// function name missing)
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.objectName));
|
||||
} else if (IsCaretOn(node.objectNameDotLocation) ||
|
||||
IsCaretOn(node.objectFunctionOrBehaviorNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForBehavior(
|
||||
node.objectFunctionOrBehaviorName, node.objectName));
|
||||
} else if (IsCaretOn(node.behaviorNameNamespaceSeparatorLocation) ||
|
||||
IsCaretOn(node.behaviorFunctionNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type,
|
||||
node.behaviorFunctionName,
|
||||
node.objectName,
|
||||
node.objectFunctionOrBehaviorName));
|
||||
}
|
||||
} else {
|
||||
// Object function or behavior name
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.objectName));
|
||||
} else if (IsCaretOn(node.objectNameDotLocation) ||
|
||||
IsCaretOn(node.objectFunctionOrBehaviorNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForBehavior(
|
||||
node.objectFunctionOrBehaviorName, node.objectName));
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, node.objectFunctionOrBehaviorName, node.objectName));
|
||||
}
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
bool isCaretOnParenthesis = IsCaretOn(node.openingParenthesisLocation) ||
|
||||
IsCaretOn(node.closingParenthesisLocation);
|
||||
|
||||
if (!node.behaviorName.empty()) {
|
||||
// Behavior function
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.objectName));
|
||||
} else if (IsCaretOn(node.objectNameDotLocation) ||
|
||||
IsCaretOn(node.behaviorNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForBehavior(
|
||||
node.behaviorName, node.objectName));
|
||||
} else {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpression(node.type,
|
||||
node.functionName,
|
||||
node.objectName,
|
||||
node.behaviorName)
|
||||
.SetIsExact(isCaretOnParenthesis));
|
||||
}
|
||||
} else if (!node.objectName.empty()) {
|
||||
// Object function
|
||||
if (IsCaretOn(node.objectNameLocation)) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForObject(
|
||||
node.type, node.objectName));
|
||||
} else {
|
||||
// Add completions for behaviors, because we could imagine that the user
|
||||
// wants to move from an object function to a behavior function, and so
|
||||
// need behavior completions. Do this unless we're on the parenthesis
|
||||
// (at which point we're only showing informative message about the
|
||||
// function).
|
||||
if (!isCaretOnParenthesis) {
|
||||
completions.push_back(ExpressionCompletionDescription::ForBehavior(
|
||||
node.functionName, node.objectName));
|
||||
}
|
||||
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, node.functionName, node.objectName)
|
||||
.SetIsExact(isCaretOnParenthesis));
|
||||
}
|
||||
} else {
|
||||
// Free function
|
||||
completions.push_back(ExpressionCompletionDescription::ForExpression(
|
||||
node.type, node.functionName)
|
||||
.SetIsExact(isCaretOnParenthesis));
|
||||
}
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForObject(node.type, node.text));
|
||||
completions.push_back(
|
||||
ExpressionCompletionDescription::ForExpression(node.type, node.text));
|
||||
}
|
||||
|
||||
private:
|
||||
bool IsCaretOn(const ExpressionParserLocation& location,
|
||||
bool inclusive = false) {
|
||||
if (!location.IsValid()) return false;
|
||||
|
||||
return (location.GetStartPosition() <= searchedPosition &&
|
||||
((!inclusive && searchedPosition < location.GetEndPosition()) ||
|
||||
(inclusive && searchedPosition <= location.GetEndPosition())));
|
||||
}
|
||||
|
||||
ExpressionCompletionFinder(size_t searchedPosition_)
|
||||
: searchedPosition(searchedPosition_){};
|
||||
|
||||
std::vector<ExpressionCompletionDescription> completions;
|
||||
size_t searchedPosition;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
126
Core/GDCore/IDE/Events/ExpressionNodeLocationFinder.h
Normal file
126
Core/GDCore/IDE/Events/ExpressionNodeLocationFinder.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONNODELOCATIONFINDER_H
|
||||
#define GDCORE_EXPRESSIONNODELOCATIONFINDER_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
class Platform;
|
||||
class ParameterMetadata;
|
||||
class ExpressionMetadata;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Find the deepest node at the specified location in an expression.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionNodeLocationFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
/**
|
||||
* \brief Initialize the finder to search at the specified position.
|
||||
*/
|
||||
ExpressionNodeLocationFinder(size_t searchedPosition_)
|
||||
: searchedPosition(searchedPosition_), foundNode(nullptr){};
|
||||
virtual ~ExpressionNodeLocationFinder(){};
|
||||
|
||||
/**
|
||||
* \brief Helper function to find the deepest node at the search position, if
|
||||
* any.
|
||||
*/
|
||||
static ExpressionNode* GetNodeAtPosition(gd::ExpressionNode& node,
|
||||
size_t searchedPosition) {
|
||||
gd::ExpressionNodeLocationFinder finder(searchedPosition);
|
||||
node.Visit(finder);
|
||||
return finder.GetNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the deepest node found at the search position, if any.
|
||||
*/
|
||||
ExpressionNode* GetNode() { return foundNode; };
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
CheckSearchPositionInNode(node);
|
||||
node.expression->Visit(*this);
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
if (CheckSearchPositionInNode(node)) {
|
||||
node.leftHandSide->Visit(*this);
|
||||
node.rightHandSide->Visit(*this);
|
||||
}
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
CheckSearchPositionInNode(node);
|
||||
node.factor->Visit(*this);
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {
|
||||
CheckSearchPositionInNode(node);
|
||||
}
|
||||
void OnVisitTextNode(TextNode& node) override {
|
||||
CheckSearchPositionInNode(node);
|
||||
}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (CheckSearchPositionInNode(node)) {
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (CheckSearchPositionInNode(node)) {
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
if (CheckSearchPositionInNode(node)) {
|
||||
node.expression->Visit(*this);
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
CheckSearchPositionInNode(node);
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
CheckSearchPositionInNode(node);
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
CheckSearchPositionInNode(node);
|
||||
for (auto& parameter : node.parameters) {
|
||||
parameter->Visit(*this);
|
||||
}
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {
|
||||
CheckSearchPositionInNode(node, /*inclusive=*/true);
|
||||
}
|
||||
|
||||
private:
|
||||
bool CheckSearchPositionInNode(ExpressionNode& node, bool inclusive = false) {
|
||||
if (node.location.GetStartPosition() <= searchedPosition &&
|
||||
((!inclusive && searchedPosition < node.location.GetEndPosition()) ||
|
||||
(inclusive && searchedPosition <= node.location.GetEndPosition()))) {
|
||||
foundNode = &node;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t searchedPosition;
|
||||
ExpressionNode* foundNode;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONNODELOCATIONFINDER_H
|
@@ -83,7 +83,10 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
ReportAnyError(node);
|
||||
}
|
||||
void OnVisitFunctionNode(FunctionNode& node) override {
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
ReportAnyError(node);
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
ReportAnyError(node);
|
||||
for (auto& parameter : node.parameters) {
|
||||
parameter->Visit(*this);
|
||||
|
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "GDCore/IDE/Events/ExpressionsCorrectnessTesting.h"
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Events/Expression.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
CallbacksForExpressionCorrectnessTesting::
|
||||
CallbacksForExpressionCorrectnessTesting(const gd::ObjectsContainer& project_,
|
||||
const gd::ObjectsContainer& layout_)
|
||||
: project(project_), layout(layout_) {}
|
||||
|
||||
bool CallbacksForExpressionCorrectnessTesting::OnSubMathExpression(
|
||||
const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::Expression& expression) {
|
||||
CallbacksForExpressionCorrectnessTesting callbacks(project, layout);
|
||||
|
||||
gd::ExpressionParser parser(expression.GetPlainString());
|
||||
if (!parser.ParseMathExpression(platform, project, layout, callbacks)) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
firstErrorStr = callbacks.GetFirstError();
|
||||
firstErrorPos = callbacks.GetFirstErrorPosition();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CallbacksForExpressionCorrectnessTesting::OnSubTextExpression(
|
||||
const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::Expression& expression) {
|
||||
CallbacksForExpressionCorrectnessTesting callbacks(project, layout);
|
||||
|
||||
gd::ExpressionParser parser(expression.GetPlainString());
|
||||
if (!parser.ParseStringExpression(platform, project, layout, callbacks)) {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
firstErrorStr = callbacks.GetFirstError();
|
||||
firstErrorPos = callbacks.GetFirstErrorPosition();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_EXPRESSIONSCORRECTNESSTESTING_H
|
||||
#define GDCORE_EXPRESSIONSCORRECTNESSTESTING_H
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Parsers/ExpressionParser.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class ExpressionMetadata;
|
||||
class Expression;
|
||||
class Project;
|
||||
class Layout;
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
|
||||
// TODO: Replace and remove (ExpressionValidator)
|
||||
|
||||
/**
|
||||
* \brief Parser callbacks used to check expressions correctness
|
||||
*
|
||||
* Usage example:
|
||||
* \code
|
||||
* gd::CallbacksForExpressionCorrectnessTesting callbacks(game, scene);
|
||||
* gd::ExpressionParser expressionParser(expression);
|
||||
* if ( !expressionParser.ParseMathExpression(game, scene, callbacks) )
|
||||
* //Expression is not valid
|
||||
* else
|
||||
* //Expression is correct
|
||||
* \endcode
|
||||
*
|
||||
* \see gd::ExpressionParser
|
||||
* \see gd::ParserCallbacks
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API CallbacksForExpressionCorrectnessTesting
|
||||
: public gd::ParserCallbacks {
|
||||
public:
|
||||
CallbacksForExpressionCorrectnessTesting(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout);
|
||||
virtual ~CallbacksForExpressionCorrectnessTesting(){};
|
||||
|
||||
void OnConstantToken(gd::String text){};
|
||||
void OnStaticFunction(gd::String functionName,
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const gd::ExpressionMetadata& expressionInfo){};
|
||||
void OnObjectFunction(gd::String functionName,
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const gd::ExpressionMetadata& expressionInfo){};
|
||||
void OnObjectBehaviorFunction(gd::String functionName,
|
||||
const std::vector<gd::Expression>& parameters,
|
||||
const gd::ExpressionMetadata& expressionInfo){};
|
||||
bool OnSubMathExpression(const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::Expression& expression);
|
||||
bool OnSubTextExpression(const gd::Platform& platform,
|
||||
const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::Expression& expression);
|
||||
|
||||
private:
|
||||
const gd::ObjectsContainer& project;
|
||||
const gd::ObjectsContainer& layout;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONSCORRECTNESSTESTING_H
|
179
Core/GDCore/IDE/Events/ExpressionsParameterMover.cpp
Normal file
179
Core/GDCore/IDE/Events/ExpressionsParameterMover.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Go through the nodes and change the position of a parameter of the
|
||||
* given function.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionParameterMover
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionParameterMover(const gd::ObjectsContainer& globalObjectsContainer_,
|
||||
const gd::ObjectsContainer& objectsContainer_,
|
||||
const gd::String& behaviorType_,
|
||||
const gd::String& objectType_,
|
||||
const gd::String& functionName_,
|
||||
std::size_t oldIndex_,
|
||||
std::size_t newIndex_)
|
||||
: hasDoneMoving(false),
|
||||
globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
behaviorType(behaviorType_),
|
||||
objectType(objectType_),
|
||||
functionName(functionName_),
|
||||
oldIndex(oldIndex_),
|
||||
newIndex(newIndex_){};
|
||||
virtual ~ExpressionParameterMover(){};
|
||||
|
||||
bool HasDoneMoving() const { return hasDoneMoving; }
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
|
||||
node.expression->Visit(*this);
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {
|
||||
node.leftHandSide->Visit(*this);
|
||||
node.rightHandSide->Visit(*this);
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
|
||||
node.factor->Visit(*this);
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
node.expression->Visit(*this);
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
auto moveParameter =
|
||||
[this](std::vector<std::unique_ptr<gd::ExpressionNode>>& parameters) {
|
||||
if (oldIndex >= parameters.size() || newIndex >= parameters.size())
|
||||
return;
|
||||
|
||||
auto movedParameterNode = std::move(parameters[oldIndex]);
|
||||
parameters.erase(parameters.begin() + oldIndex);
|
||||
parameters.insert(parameters.begin() + newIndex,
|
||||
std::move(movedParameterNode));
|
||||
};
|
||||
|
||||
if (node.functionName == functionName) {
|
||||
if (behaviorType.empty() && !objectType.empty() &&
|
||||
!node.objectName.empty()) {
|
||||
// Move parameter of an object function
|
||||
const gd::String& thisObjectType = gd::GetTypeOfObject(
|
||||
globalObjectsContainer, objectsContainer, node.objectName);
|
||||
if (thisObjectType == behaviorType) {
|
||||
moveParameter(node.parameters);
|
||||
hasDoneMoving = true;
|
||||
}
|
||||
} else if (!behaviorType.empty() && !node.behaviorName.empty()) {
|
||||
// Move parameter of a behavior function
|
||||
const gd::String& thisBehaviorType = gd::GetTypeOfBehavior(
|
||||
globalObjectsContainer, objectsContainer, node.behaviorName);
|
||||
if (thisBehaviorType == behaviorType) {
|
||||
moveParameter(node.parameters);
|
||||
hasDoneMoving = true;
|
||||
}
|
||||
} else if (behaviorType.empty() && objectType.empty()) {
|
||||
// Move parameter of a free function
|
||||
moveParameter(node.parameters);
|
||||
hasDoneMoving = true;
|
||||
}
|
||||
}
|
||||
for (auto& parameter : node.parameters) {
|
||||
parameter->Visit(*this);
|
||||
}
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
|
||||
private:
|
||||
bool hasDoneMoving;
|
||||
const gd::ObjectsContainer& globalObjectsContainer;
|
||||
const gd::ObjectsContainer& objectsContainer;
|
||||
const gd::String& behaviorType; // The behavior type of the function which
|
||||
// must have a parameter moved (optional).
|
||||
const gd::String& objectType; // The object type of the function which
|
||||
// must have a parameter moved (optional). If
|
||||
// `behaviorType` is not empty, it takes
|
||||
// precedence over `objectType`.
|
||||
const gd::String& functionName;
|
||||
std::size_t oldIndex;
|
||||
std::size_t newIndex;
|
||||
};
|
||||
|
||||
bool ExpressionsParameterMover::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
auto& metadata = isCondition ? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
|
||||
pNb < instruction.GetParametersCount();
|
||||
++pNb) {
|
||||
const gd::String& type = metadata.parameters[pNb].type;
|
||||
const gd::String& expression =
|
||||
instruction.GetParameter(pNb).GetPlainString();
|
||||
|
||||
gd::ExpressionParser2 parser(
|
||||
platform, GetGlobalObjectsContainer(), GetObjectsContainer());
|
||||
|
||||
auto node = gd::ParameterMetadata::IsExpression("number", type)
|
||||
? parser.ParseExpression("number", expression)
|
||||
: (gd::ParameterMetadata::IsExpression("string", type)
|
||||
? parser.ParseExpression("string", expression)
|
||||
: std::unique_ptr<gd::ExpressionNode>());
|
||||
if (node) {
|
||||
ExpressionParameterMover mover(GetGlobalObjectsContainer(),
|
||||
GetObjectsContainer(),
|
||||
behaviorType,
|
||||
objectType,
|
||||
functionName,
|
||||
oldIndex,
|
||||
newIndex);
|
||||
node->Visit(mover);
|
||||
|
||||
if (mover.HasDoneMoving()) {
|
||||
instruction.SetParameter(
|
||||
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ExpressionsParameterMover::~ExpressionsParameterMover() {}
|
||||
|
||||
} // namespace gd
|
85
Core/GDCore/IDE/Events/ExpressionsParameterMover.h
Normal file
85
Core/GDCore/IDE/Events/ExpressionsParameterMover.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef ExpressionsParameterMover_H
|
||||
#define ExpressionsParameterMover_H
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class Platform;
|
||||
class EventsList;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Move in expressions, in parameters of actions or conditions, a
|
||||
* parameter from one position to another.
|
||||
*
|
||||
* \see InstructionsParameterMover
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ExpressionsParameterMover
|
||||
: public ArbitraryEventsWorkerWithContext {
|
||||
public:
|
||||
ExpressionsParameterMover(const gd::Platform &platform_)
|
||||
: platform(platform_){};
|
||||
virtual ~ExpressionsParameterMover();
|
||||
|
||||
ExpressionsParameterMover &SetFreeExpressionMovedParameter(
|
||||
const gd::String &functionName_,
|
||||
std::size_t oldIndex_,
|
||||
std::size_t newIndex_) {
|
||||
objectType = "";
|
||||
behaviorType = "";
|
||||
functionName = functionName_;
|
||||
oldIndex = oldIndex_;
|
||||
newIndex = newIndex_;
|
||||
return *this;
|
||||
}
|
||||
ExpressionsParameterMover &SetObjectExpressionMovedParameter(
|
||||
const gd::String &objectType_,
|
||||
const gd::String &functionName_,
|
||||
std::size_t oldIndex_,
|
||||
std::size_t newIndex_) {
|
||||
objectType = objectType_;
|
||||
behaviorType = "";
|
||||
functionName = functionName_;
|
||||
oldIndex = oldIndex_;
|
||||
newIndex = newIndex_;
|
||||
return *this;
|
||||
};
|
||||
ExpressionsParameterMover &SetBehaviorExpressionMovedParameter(
|
||||
const gd::String &behaviorType_,
|
||||
const gd::String &functionName_,
|
||||
std::size_t oldIndex_,
|
||||
std::size_t newIndex_) {
|
||||
objectType = "";
|
||||
behaviorType = behaviorType_;
|
||||
functionName = functionName_;
|
||||
oldIndex = oldIndex_;
|
||||
newIndex = newIndex_;
|
||||
return *this;
|
||||
};
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override;
|
||||
|
||||
const gd::Platform &platform;
|
||||
gd::String functionName;
|
||||
std::size_t oldIndex;
|
||||
std::size_t newIndex;
|
||||
gd::String behaviorType;
|
||||
gd::String objectType;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // ExpressionsParameterMover_H
|
@@ -71,13 +71,41 @@ class GD_CORE_API ExpressionFunctionRenamer
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {}
|
||||
void OnVisitFunctionNode(FunctionNode& node) override {
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
|
||||
if (!node.behaviorFunctionName.empty()) {
|
||||
// Behavior function name
|
||||
if (!behaviorType.empty() &&
|
||||
node.behaviorFunctionName == oldFunctionName) {
|
||||
const gd::String& thisBehaviorType =
|
||||
gd::GetTypeOfBehavior(globalObjectsContainer,
|
||||
objectsContainer,
|
||||
node.objectFunctionOrBehaviorName);
|
||||
if (thisBehaviorType == behaviorType) {
|
||||
node.behaviorFunctionName = newFunctionName;
|
||||
hasDoneRenaming = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Object function name
|
||||
if (behaviorType.empty() && !objectType.empty() &&
|
||||
node.objectFunctionOrBehaviorName == oldFunctionName) {
|
||||
const gd::String& thisObjectType = gd::GetTypeOfObject(
|
||||
globalObjectsContainer, objectsContainer, node.objectName);
|
||||
if (thisObjectType == objectType) {
|
||||
node.objectFunctionOrBehaviorName = newFunctionName;
|
||||
hasDoneRenaming = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
|
||||
if (node.functionName == oldFunctionName) {
|
||||
if (!objectType.empty() && !node.objectName.empty()) {
|
||||
if (behaviorType.empty() && !objectType.empty() &&
|
||||
!node.objectName.empty()) {
|
||||
// Replace an object function
|
||||
const gd::String& thisObjectType = gd::GetTypeOfObject(
|
||||
globalObjectsContainer, objectsContainer, node.objectName);
|
||||
if (thisObjectType == behaviorType) {
|
||||
if (thisObjectType == objectType) {
|
||||
node.functionName = newFunctionName;
|
||||
hasDoneRenaming = true;
|
||||
}
|
||||
@@ -89,7 +117,7 @@ class GD_CORE_API ExpressionFunctionRenamer
|
||||
node.functionName = newFunctionName;
|
||||
hasDoneRenaming = true;
|
||||
}
|
||||
} else {
|
||||
} else if (behaviorType.empty() && objectType.empty()) {
|
||||
// Replace a free function
|
||||
node.functionName = newFunctionName;
|
||||
hasDoneRenaming = true;
|
||||
@@ -106,9 +134,11 @@ class GD_CORE_API ExpressionFunctionRenamer
|
||||
const gd::ObjectsContainer& globalObjectsContainer;
|
||||
const gd::ObjectsContainer& objectsContainer;
|
||||
const gd::String& behaviorType; // The behavior type for which the expression
|
||||
// must be replaced (optional)
|
||||
// must be replaced (optional).
|
||||
const gd::String& objectType; // The object type for which the expression
|
||||
// must be replaced (optional)
|
||||
// must be replaced (optional). If
|
||||
// `behaviorType` is not empty, it takes
|
||||
// precedence over `objectType`.
|
||||
const gd::String& oldFunctionName;
|
||||
const gd::String& newFunctionName;
|
||||
};
|
||||
|
@@ -49,9 +49,15 @@ InstructionSentenceFormatter::GetAsFormattedText(
|
||||
|
||||
gd::String sentence = metadata.GetSentence();
|
||||
std::replace(sentence.Raw().begin(), sentence.Raw().end(), '\n', ' ');
|
||||
bool parse = true;
|
||||
|
||||
size_t loopCount = 0;
|
||||
bool parse = true;
|
||||
while (parse) {
|
||||
if (loopCount > 40) {
|
||||
break;
|
||||
}
|
||||
loopCount++;
|
||||
|
||||
// Search first parameter
|
||||
parse = false;
|
||||
size_t firstParamPosition = gd::String::npos;
|
||||
|
37
Core/GDCore/IDE/Events/InstructionsParameterMover.cpp
Normal file
37
Core/GDCore/IDE/Events/InstructionsParameterMover.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/InstructionsParameterMover.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool InstructionsParameterMover::DoVisitInstruction(
|
||||
gd::Instruction& instruction, bool isCondition) {
|
||||
if (instruction.GetType() == instructionType) {
|
||||
std::vector<gd::Expression> updatedParameters = instruction.GetParameters();
|
||||
if (oldIndex < updatedParameters.size() ||
|
||||
newIndex < updatedParameters.size()) {
|
||||
gd::Expression movedParameter = updatedParameters[oldIndex];
|
||||
updatedParameters.erase(updatedParameters.begin() + oldIndex);
|
||||
updatedParameters.insert(updatedParameters.begin() + newIndex,
|
||||
movedParameter);
|
||||
instruction.SetParameters(updatedParameters);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
InstructionsParameterMover::~InstructionsParameterMover() {}
|
||||
|
||||
} // namespace gd
|
53
Core/GDCore/IDE/Events/InstructionsParameterMover.h
Normal file
53
Core/GDCore/IDE/Events/InstructionsParameterMover.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef InstructionsParameterMover_H
|
||||
#define InstructionsParameterMover_H
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class Project;
|
||||
class EventsList;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Reorder the parameters of the instruction with the specified
|
||||
* type in events, moving the parameter at the specified \a oldIndex to
|
||||
* \a newIndex.
|
||||
*
|
||||
* \see ExpressionsParameterMover
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API InstructionsParameterMover : public ArbitraryEventsWorker {
|
||||
public:
|
||||
InstructionsParameterMover(const gd::Project& project_,
|
||||
const gd::String& instructionType_,
|
||||
std::size_t oldIndex_,
|
||||
std::size_t newIndex_)
|
||||
: project(project_),
|
||||
instructionType(instructionType_),
|
||||
oldIndex(oldIndex_),
|
||||
newIndex(newIndex_){};
|
||||
virtual ~InstructionsParameterMover();
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) override;
|
||||
|
||||
const gd::Project& project;
|
||||
gd::String instructionType;
|
||||
std::size_t oldIndex;
|
||||
std::size_t newIndex;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // InstructionsParameterMover_H
|
@@ -4,6 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ProjectStripper.h"
|
||||
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/ExternalLayout.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
@@ -20,61 +21,8 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project& project) {
|
||||
project.GetLayout(i).GetObjectGroups().Clear();
|
||||
project.GetLayout(i).GetEvents().Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void GD_CORE_API ProjectStripper::StripProjectForLayoutEdition(
|
||||
gd::Project& project, const gd::String& layoutName) {
|
||||
while (project.GetExternalEventsCount() > 0)
|
||||
project.RemoveExternalEvents(project.GetExternalEvents(0).GetName());
|
||||
|
||||
for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
auto& layout = project.GetLayout(i);
|
||||
if (layoutName == layout.GetName()) continue;
|
||||
|
||||
project.GetLayout(i).GetEvents().Clear();
|
||||
project.GetLayout(i).GetInitialInstances().Clear();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < project.GetExternalEventsCount(); ++i) {
|
||||
project.GetExternalEvents(i).GetEvents().Clear();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < project.GetExternalLayoutsCount(); ++i) {
|
||||
project.GetExternalLayout(i).GetInitialInstances().Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void GD_CORE_API ProjectStripper::StripProjectForExternalLayoutEdition(
|
||||
gd::Project& project, const gd::String& externalLayoutName) {
|
||||
while (project.GetExternalEventsCount() > 0)
|
||||
project.RemoveExternalEvents(project.GetExternalEvents(0).GetName());
|
||||
|
||||
gd::String associatedLayoutName;
|
||||
if (project.HasExternalLayoutNamed(externalLayoutName)) {
|
||||
associatedLayoutName =
|
||||
project.GetExternalLayout(externalLayoutName).GetAssociatedLayout();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
auto& layout = project.GetLayout(i);
|
||||
if (!associatedLayoutName.empty() &&
|
||||
associatedLayoutName == layout.GetName())
|
||||
continue;
|
||||
|
||||
project.GetLayout(i).GetEvents().Clear();
|
||||
project.GetLayout(i).GetInitialInstances().Clear();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < project.GetExternalEventsCount(); ++i) {
|
||||
project.GetExternalEvents(i).GetEvents().Clear();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < project.GetExternalLayoutsCount(); ++i) {
|
||||
auto& externalLayout = project.GetExternalLayout(i);
|
||||
if (externalLayoutName == externalLayout.GetName()) continue;
|
||||
|
||||
externalLayout.GetInitialInstances().Clear();
|
||||
}
|
||||
project.ClearEventsFunctionsExtensions();
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -28,23 +28,6 @@ class GD_CORE_API ProjectStripper {
|
||||
*/
|
||||
static void StripProjectForExport(gd::Project& project);
|
||||
|
||||
/**
|
||||
* \brief Strip project to keep only the full content of the specified
|
||||
* layout. The content of other layouts, external events and external layouts
|
||||
* is removed.
|
||||
*/
|
||||
static void StripProjectForLayoutEdition(gd::Project& project,
|
||||
const gd::String& layoutName);
|
||||
|
||||
/**
|
||||
* \brief Strip project to keep only the full content of the specified
|
||||
* external layout and the associated layout.
|
||||
* The content of other layouts, external events and external layouts is
|
||||
* removed.
|
||||
*/
|
||||
static void StripProjectForExternalLayoutEdition(
|
||||
gd::Project& project, const gd::String& externalLayoutName);
|
||||
|
||||
private:
|
||||
ProjectStripper(){};
|
||||
virtual ~ProjectStripper(){};
|
||||
|
@@ -10,34 +10,49 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
gd::String SceneNameMangler::GetMangledSceneName(gd::String sceneName) {
|
||||
static const gd::String allowedCharacters =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
static const gd::String allowedExceptFirst = "0123456789";
|
||||
SceneNameMangler *SceneNameMangler::_singleton = nullptr;
|
||||
|
||||
std::size_t i = 0;
|
||||
for (auto it = sceneName.begin(); it != sceneName.end(); ++it) {
|
||||
char32_t character = *it;
|
||||
if (allowedCharacters.find(character) == gd::String::npos &&
|
||||
(allowedExceptFirst.find(character) == gd::String::npos ||
|
||||
i == 0)) // Also disallow some characters to be in first position
|
||||
{
|
||||
// Replace the character by an underscore and its unicode codepoint (in
|
||||
// base 10)
|
||||
auto it2 = it;
|
||||
++it2;
|
||||
sceneName.replace(it, it2, "_" + gd::String::From(character));
|
||||
|
||||
// The iterator it may have been invalidated:
|
||||
// re-assign it with a new iterator pointing to the same position.
|
||||
it = sceneName.begin();
|
||||
std::advance(it, i);
|
||||
}
|
||||
|
||||
++i;
|
||||
const gd::String &SceneNameMangler::GetMangledSceneName(
|
||||
const gd::String &sceneName) {
|
||||
auto it = mangledSceneNames.find(sceneName);
|
||||
if (it != mangledSceneNames.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return sceneName;
|
||||
gd::String partiallyMangledName = sceneName;
|
||||
static const gd::String alwaysAllowedCharacters =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
static const gd::String allowedExceptFirstCharacters = "0123456789";
|
||||
|
||||
for (size_t i = 0; i < partiallyMangledName.size();
|
||||
++i) // Replace all unallowed letter by an underscore and the unicode
|
||||
// code point of the letter
|
||||
{
|
||||
if (alwaysAllowedCharacters.find_first_of(
|
||||
std::u32string(1, partiallyMangledName[i])) == gd::String::npos &&
|
||||
(i == 0 ||
|
||||
allowedExceptFirstCharacters.find(
|
||||
std::u32string(1, partiallyMangledName[i])) == gd::String::npos)) {
|
||||
char32_t unallowedChar = partiallyMangledName[i];
|
||||
partiallyMangledName.replace(i, 1, "_" + gd::String::From(unallowedChar));
|
||||
}
|
||||
}
|
||||
|
||||
mangledSceneNames[sceneName] = partiallyMangledName;
|
||||
return mangledSceneNames[sceneName];
|
||||
}
|
||||
|
||||
SceneNameMangler *SceneNameMangler::Get() {
|
||||
if (nullptr == _singleton) _singleton = new SceneNameMangler;
|
||||
|
||||
return (static_cast<SceneNameMangler *>(_singleton));
|
||||
}
|
||||
|
||||
void SceneNameMangler::DestroySingleton() {
|
||||
if (nullptr != _singleton) {
|
||||
delete _singleton;
|
||||
_singleton = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -6,12 +6,14 @@
|
||||
|
||||
#ifndef SCENENAMEMANGLER_H
|
||||
#define SCENENAMEMANGLER_H
|
||||
#include <unordered_map>
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Used to mangle the name of a scene
|
||||
* \brief Mangle the name of a scene, so that it can be used in code or file
|
||||
* names.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
@@ -21,12 +23,22 @@ class GD_CORE_API SceneNameMangler {
|
||||
* \brief Mangle the name of a scene, replacing all characters that are not
|
||||
* 0-9, a-z or A-Z by "_"+UnicodeCodePointOfTheCharacter. The first character
|
||||
* must be a letter, otherwise it is also replaced in the same manner.
|
||||
*
|
||||
* The mangled name is memoized as this is intensively used during project
|
||||
* export and events code generation.
|
||||
*/
|
||||
static gd::String GetMangledSceneName(gd::String sceneName);
|
||||
const gd::String& GetMangledSceneName(const gd::String& sceneName);
|
||||
|
||||
static SceneNameMangler* Get();
|
||||
static void DestroySingleton();
|
||||
|
||||
private:
|
||||
SceneNameMangler(){};
|
||||
virtual ~SceneNameMangler(){};
|
||||
static SceneNameMangler* _singleton;
|
||||
|
||||
std::unordered_map<gd::String, gd::String>
|
||||
mangledSceneNames; ///< Memoized results of mangling
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -9,7 +9,9 @@
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/Events/EventsRefactorer.h"
|
||||
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
|
||||
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
|
||||
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/InstructionsParameterMover.h"
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
@@ -85,7 +87,8 @@ void WholeProjectRefactorer::ExposeProjectEvents(
|
||||
void WholeProjectRefactorer::ExposeProjectEvents(
|
||||
gd::Project& project, gd::ArbitraryEventsWorkerWithContext& worker) {
|
||||
// See also gd::Project::ExposeResources for a method that traverse the whole
|
||||
// project (this time for resources) and ExposeProjectEffects (this time for effects).
|
||||
// project (this time for resources) and ExposeProjectEffects (this time for
|
||||
// effects).
|
||||
|
||||
// Add layouts events
|
||||
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
|
||||
@@ -331,9 +334,6 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after an events function is renamed
|
||||
*/
|
||||
void WholeProjectRefactorer::RenameEventsFunction(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
@@ -391,6 +391,76 @@ void WholeProjectRefactorer::RenameBehaviorEventsFunction(
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::MoveEventsFunctionParameter(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::String& functionName,
|
||||
std::size_t oldIndex,
|
||||
std::size_t newIndex) {
|
||||
if (!eventsFunctionsExtension.HasEventsFunctionNamed(functionName)) return;
|
||||
|
||||
const gd::EventsFunction& eventsFunction =
|
||||
eventsFunctionsExtension.GetEventsFunction(functionName);
|
||||
|
||||
const gd::String& eventsFunctionType = GetEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), functionName);
|
||||
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
|
||||
project, eventsFunctionType, oldIndex, newIndex);
|
||||
ExposeProjectEvents(project, mover);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
gd::ExpressionsParameterMover mover =
|
||||
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
|
||||
mover.SetFreeExpressionMovedParameter(
|
||||
eventsFunctionType, oldIndex, newIndex);
|
||||
ExposeProjectEvents(project, mover);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& functionName,
|
||||
std::size_t oldIndex,
|
||||
std::size_t newIndex) {
|
||||
auto& eventsFunctions = eventsBasedBehavior.GetEventsFunctions();
|
||||
if (!eventsFunctions.HasEventsFunctionNamed(functionName)) return;
|
||||
|
||||
const gd::EventsFunction& eventsFunction =
|
||||
eventsFunctions.GetEventsFunction(functionName);
|
||||
|
||||
const gd::String& eventsFunctionType =
|
||||
GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName(),
|
||||
functionName);
|
||||
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
|
||||
project, eventsFunctionType, oldIndex, newIndex);
|
||||
ExposeProjectEvents(project, mover);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
gd::ExpressionsParameterMover mover =
|
||||
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
|
||||
mover.SetBehaviorExpressionMovedParameter(
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
functionName,
|
||||
oldIndex,
|
||||
newIndex);
|
||||
ExposeProjectEvents(project, mover);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameBehaviorProperty(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
@@ -400,7 +470,17 @@ void WholeProjectRefactorer::RenameBehaviorProperty(
|
||||
auto& properties = eventsBasedBehavior.GetPropertyDescriptors();
|
||||
if (!properties.Has(oldPropertyName)) return;
|
||||
|
||||
const auto& property = properties.Get(oldPropertyName);
|
||||
// Order is important: we first rename the expressions then the instructions,
|
||||
// to avoid being unable to fetch the metadata (the types of parameters) of
|
||||
// instructions after they are renamed.
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
|
||||
ExposeProjectEvents(project, expressionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -425,15 +505,6 @@ void WholeProjectRefactorer::RenameBehaviorProperty(
|
||||
eventsBasedBehavior.GetName(),
|
||||
EventsBasedBehavior::GetPropertyConditionName(newPropertyName)));
|
||||
ExposeProjectEvents(project, conditionRenamer);
|
||||
|
||||
gd::ExpressionsRenamer expressionRenamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
expressionRenamer.SetReplacedBehaviorExpression(
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName),
|
||||
EventsBasedBehavior::GetPropertyExpressionName(newPropertyName));
|
||||
ExposeProjectEvents(project, expressionRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
|
@@ -50,7 +50,10 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
gd::ArbitraryEventsWorkerWithContext& worker);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after an events function extension is renamed
|
||||
* \brief Refactor the project **before** an events function extension is renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified extension after calling this.
|
||||
* This is because the extension is expected to have its old name for the refactoring.
|
||||
*/
|
||||
static void RenameEventsFunctionsExtension(
|
||||
gd::Project& project,
|
||||
@@ -59,7 +62,10 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& newName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after an events function is renamed
|
||||
* \brief Refactor the project **before** an events function is renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified function after calling this.
|
||||
* This is because the function is expected to have its old name for the refactoring.
|
||||
*/
|
||||
static void RenameEventsFunction(
|
||||
gd::Project& project,
|
||||
@@ -68,8 +74,11 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& newFunctionName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after an events function of a behavior is
|
||||
* \brief Refactor the project **before** an events function of a behavior is
|
||||
* renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified function after calling this.
|
||||
* This is because the function is expected to have its old name for the refactoring.
|
||||
*/
|
||||
static void RenameBehaviorEventsFunction(
|
||||
gd::Project& project,
|
||||
@@ -79,8 +88,40 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& newFunctionName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after a property of a behavior is
|
||||
* \brief Refactor the project **before** an events function parameter
|
||||
* is moved.
|
||||
*
|
||||
* \warning Do the move of the specified function parameters after calling this.
|
||||
* This is because the function is expected to be in its old state for the refactoring.
|
||||
*/
|
||||
static void MoveEventsFunctionParameter(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::String& functionName,
|
||||
std::size_t oldIndex,
|
||||
std::size_t newIndex);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** the parameter of an events function of a
|
||||
* behavior is moved.
|
||||
*
|
||||
* \warning Do the move of the specified function parameters after calling this.
|
||||
* This is because the function is expected to be in its old state for the refactoring.
|
||||
*/
|
||||
static void MoveBehaviorEventsFunctionParameter(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& functionName,
|
||||
std::size_t oldIndex,
|
||||
std::size_t newIndex);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** a property of a behavior is
|
||||
* renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified property after calling this.
|
||||
* This is because the property is expected to have its old name for the refactoring.
|
||||
*/
|
||||
static void RenameBehaviorProperty(
|
||||
gd::Project& project,
|
||||
@@ -90,7 +131,10 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& newPropertyName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after a behavior is renamed.
|
||||
* \brief Refactor the project **before** a behavior is renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified behavior after calling this.
|
||||
* This is because the behavior is expected to have its old name for the refactoring.
|
||||
*/
|
||||
static void RenameEventsBasedBehavior(
|
||||
gd::Project& project,
|
||||
@@ -137,7 +181,7 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
bool isObjectGroup);
|
||||
|
||||
/**
|
||||
* \brief Refactor the events function after an object or group is renamed
|
||||
* \brief Refactor the events function after an object or group is removed
|
||||
*
|
||||
* This will update the events of the function and groups.
|
||||
*/
|
||||
|
@@ -15,7 +15,7 @@ Behavior::~Behavior(){};
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::map<gd::String, gd::PropertyDescriptor> Behavior::GetProperties(
|
||||
const gd::SerializerElement& behaviorContent, gd::Project& project) const {
|
||||
const gd::SerializerElement& behaviorContent) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
@@ -61,7 +61,7 @@ class GD_CORE_API Behavior {
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
const gd::SerializerElement& behaviorContent, gd::Project& project) const;
|
||||
const gd::SerializerElement& behaviorContent) const;
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a custom property of the
|
||||
@@ -72,8 +72,7 @@ class GD_CORE_API Behavior {
|
||||
*/
|
||||
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) {
|
||||
const gd::String& value) {
|
||||
return false;
|
||||
};
|
||||
#endif
|
||||
|
@@ -16,7 +16,7 @@ BehaviorsSharedData::~BehaviorsSharedData(){};
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::map<gd::String, gd::PropertyDescriptor> BehaviorsSharedData::GetProperties(
|
||||
const gd::SerializerElement& behaviorSharedDataContent, gd::Project& project) const {
|
||||
const gd::SerializerElement& behaviorSharedDataContent) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
@@ -64,8 +64,7 @@ class GD_CORE_API BehaviorsSharedData {
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
const gd::SerializerElement& behaviorSharedDataContent,
|
||||
gd::Project& project) const;
|
||||
const gd::SerializerElement& behaviorSharedDataContent) const;
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a property of the shared data
|
||||
@@ -75,8 +74,7 @@ class GD_CORE_API BehaviorsSharedData {
|
||||
*/
|
||||
virtual bool UpdateProperty(gd::SerializerElement& behaviorSharedDataContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) {
|
||||
const gd::String& value) {
|
||||
return false;
|
||||
};
|
||||
#endif
|
||||
|
@@ -70,6 +70,19 @@ void EventsFunctionsExtension::UnserializeFrom(
|
||||
"eventsBasedBehavior", project, element.GetChild("eventsBasedBehaviors"));
|
||||
}
|
||||
|
||||
bool EventsFunctionsExtension::IsExtensionLifecycleEventsFunction(
|
||||
const gd::String& eventsFunctionName) {
|
||||
// The list of all supported lifecycle events function names.
|
||||
// If adding a new one, code generator(s) must be updated.
|
||||
return eventsFunctionName == "onFirstSceneLoaded" ||
|
||||
eventsFunctionName == "onSceneLoaded" ||
|
||||
eventsFunctionName == "onScenePreEvents" ||
|
||||
eventsFunctionName == "onScenePostEvents" ||
|
||||
eventsFunctionName == "onScenePaused" ||
|
||||
eventsFunctionName == "onSceneResumed" ||
|
||||
eventsFunctionName == "onSceneUnloading";
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
|
@@ -8,8 +8,8 @@
|
||||
#define GDCORE_EVENTSFUNCTIONEXTENSION_H
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/Project/EventsFunctionsContainer.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsFunctionsContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/SerializableWithNameList.h"
|
||||
namespace gd {
|
||||
@@ -59,7 +59,8 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
}
|
||||
|
||||
const gd::String& GetShortDescription() const { return shortDescription; };
|
||||
EventsFunctionsExtension& SetShortDescription(const gd::String& shortDescription_) {
|
||||
EventsFunctionsExtension& SetShortDescription(
|
||||
const gd::String& shortDescription_) {
|
||||
shortDescription = shortDescription_;
|
||||
return *this;
|
||||
}
|
||||
@@ -97,15 +98,15 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
/**
|
||||
* \brief Return a reference to the list of the events based behaviors.
|
||||
*/
|
||||
SerializableWithNameList<EventsBasedBehavior>& GetEventsBasedBehaviors() {
|
||||
gd::SerializableWithNameList<EventsBasedBehavior>& GetEventsBasedBehaviors() {
|
||||
return eventsBasedBehaviors;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return a const reference to the list of the events based behaviors.
|
||||
*/
|
||||
const SerializableWithNameList<EventsBasedBehavior>& GetEventsBasedBehaviors()
|
||||
const {
|
||||
const gd::SerializableWithNameList<EventsBasedBehavior>&
|
||||
GetEventsBasedBehaviors() const {
|
||||
return eventsBasedBehaviors;
|
||||
}
|
||||
|
||||
@@ -124,6 +125,12 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
const gd::SerializerElement& element);
|
||||
///@}
|
||||
|
||||
/** \name Lifecycle event functions
|
||||
*/
|
||||
///@{
|
||||
static bool IsExtensionLifecycleEventsFunction(const gd::String& eventsFunctionName);
|
||||
///@}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize object using another object. Used by copy-ctor and assign-op.
|
||||
@@ -139,7 +146,7 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
gd::String fullName;
|
||||
gd::String tags;
|
||||
gd::String author;
|
||||
SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
|
||||
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -5,10 +5,12 @@
|
||||
*/
|
||||
|
||||
#include "GDCore/Project/InitialInstance.h"
|
||||
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/UUID/UUID.h"
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#endif
|
||||
@@ -27,7 +29,8 @@ InitialInstance::InitialInstance()
|
||||
personalizedSize(false),
|
||||
width(0),
|
||||
height(0),
|
||||
locked(false) {}
|
||||
locked(false),
|
||||
persistentUuid(UUID::MakeUuid4()) {}
|
||||
|
||||
void InitialInstance::UnserializeFrom(const SerializerElement& element) {
|
||||
SetObjectName(element.GetStringAttribute("name", "", "nom"));
|
||||
@@ -42,6 +45,9 @@ void InitialInstance::UnserializeFrom(const SerializerElement& element) {
|
||||
SetLayer(element.GetStringAttribute("layer"));
|
||||
SetLocked(element.GetBoolAttribute("locked", false));
|
||||
|
||||
persistentUuid = element.GetStringAttribute("persistentUuid");
|
||||
if (persistentUuid.empty()) ResetPersistentUuid();
|
||||
|
||||
floatInfos.clear();
|
||||
const SerializerElement& floatPropElement =
|
||||
element.GetChild("numberProperties", 0, "floatInfos");
|
||||
@@ -79,6 +85,9 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("height", GetCustomHeight());
|
||||
element.SetAttribute("locked", IsLocked());
|
||||
|
||||
if (persistentUuid.empty()) persistentUuid = UUID::MakeUuid4();
|
||||
element.SetStringAttribute("persistentUuid", persistentUuid);
|
||||
|
||||
SerializerElement& floatPropElement = element.AddChild("numberProperties");
|
||||
floatPropElement.ConsiderAsArrayOf("property");
|
||||
for (std::map<gd::String, float>::const_iterator floatInfo =
|
||||
@@ -104,6 +113,11 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
|
||||
GetVariables().SerializeTo(element.AddChild("initialVariables"));
|
||||
}
|
||||
|
||||
InitialInstance& InitialInstance::ResetPersistentUuid() {
|
||||
persistentUuid = UUID::MakeUuid4();
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
InitialInstance::GetCustomProperties(gd::Project& project, gd::Layout& layout) {
|
||||
@@ -146,13 +160,12 @@ const gd::String& InitialInstance::GetRawStringProperty(
|
||||
return it != stringInfos.end() ? it->second : *badStringProperyValue;
|
||||
}
|
||||
|
||||
void InitialInstance::SetRawFloatProperty(const gd::String& name, float value)
|
||||
{
|
||||
void InitialInstance::SetRawFloatProperty(const gd::String& name, float value) {
|
||||
floatInfos[name] = value;
|
||||
}
|
||||
|
||||
void InitialInstance::SetRawStringProperty(const gd::String& name, const gd::String& value)
|
||||
{
|
||||
void InitialInstance::SetRawStringProperty(const gd::String& name,
|
||||
const gd::String& value) {
|
||||
stringInfos[name] = value;
|
||||
}
|
||||
#endif
|
||||
|
@@ -200,7 +200,7 @@ class GD_CORE_API InitialInstance {
|
||||
/**
|
||||
* \brief Get the value of a float property stored in the instance.
|
||||
* \note Only use this when \a GetCustomProperties is too slow (when rendering
|
||||
* instances for example).
|
||||
* instances for example).
|
||||
* \return the value of the property, or 0 if it does
|
||||
* not exists.
|
||||
*/
|
||||
@@ -209,7 +209,7 @@ class GD_CORE_API InitialInstance {
|
||||
/**
|
||||
* \brief Get the value of a string property stored in the instance.
|
||||
* \note Only use this when \a GetCustomProperties is too slow (when rendering
|
||||
* instances for example).
|
||||
* instances for example).
|
||||
* \return the value of the propety, or an empty
|
||||
* string if it does not exists.
|
||||
*/
|
||||
@@ -240,6 +240,12 @@ class GD_CORE_API InitialInstance {
|
||||
* \brief Unserialize the instances container.
|
||||
*/
|
||||
virtual void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
/**
|
||||
* \brief Reset the persistent UUID used to recognize
|
||||
* the same initial instance between serialization.
|
||||
*/
|
||||
InitialInstance& ResetPersistentUuid();
|
||||
///@}
|
||||
|
||||
// More properties can be stored in floatInfos and stringInfos.
|
||||
@@ -260,6 +266,7 @@ class GD_CORE_API InitialInstance {
|
||||
float height; ///< Object custom height
|
||||
gd::VariablesContainer initialVariables; ///< Instance specific variables
|
||||
bool locked; ///< True if the instance is locked
|
||||
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID, useful for hot reloading.
|
||||
|
||||
static gd::String*
|
||||
badStringProperyValue; ///< Empty string returned by GetRawStringProperty
|
||||
|
@@ -63,7 +63,7 @@ Layout::Layout()
|
||||
|
||||
void Layout::SetName(const gd::String& name_) {
|
||||
name = name_;
|
||||
mangledName = gd::SceneNameMangler::GetMangledSceneName(name);
|
||||
mangledName = gd::SceneNameMangler::Get()->GetMangledSceneName(name);
|
||||
};
|
||||
|
||||
bool Layout::HasBehaviorSharedData(const gd::String& behaviorName) {
|
||||
|
@@ -77,8 +77,7 @@ gd::BehaviorContent& Object::AddBehavior(
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::map<gd::String, gd::PropertyDescriptor> Object::GetProperties(
|
||||
gd::Project& project) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> Object::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
@@ -139,8 +139,7 @@ class GD_CORE_API Object {
|
||||
* \return a std::map with properties names as key.
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
gd::Project& project) const;
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a custom property of the object
|
||||
@@ -148,8 +147,7 @@ class GD_CORE_API Object {
|
||||
* \return false if the new value cannot be set
|
||||
*/
|
||||
virtual bool UpdateProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) {
|
||||
const gd::String& value) {
|
||||
return false;
|
||||
};
|
||||
///@}
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include "Project.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cctype>
|
||||
#include <SFML/System/Utf.hpp>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
@@ -59,6 +60,7 @@ Project::Project()
|
||||
minFPS(20),
|
||||
verticalSync(false),
|
||||
scaleMode("linear"),
|
||||
adaptGameResolutionAtRuntime(true),
|
||||
sizeOnStartupMode("adaptWidth"),
|
||||
imageManager(std::make_shared<ImageManager>())
|
||||
#if defined(GD_IDE_ONLY)
|
||||
@@ -519,6 +521,9 @@ void Project::RemoveEventsFunctionsExtension(const gd::String& name) {
|
||||
|
||||
eventsFunctionsExtensions.erase(eventsFunctionExtension);
|
||||
}
|
||||
void Project::ClearEventsFunctionsExtensions() {
|
||||
eventsFunctionsExtensions.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
@@ -574,9 +579,8 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
element.GetChild("properties", 0, "Info");
|
||||
SetName(propElement.GetChild("name", 0, "Nom").GetValue().GetString());
|
||||
SetVersion(propElement.GetStringAttribute("version", "1.0.0"));
|
||||
SetDefaultWidth(
|
||||
propElement.GetChild("windowWidth", 0, "WindowW").GetValue().GetInt());
|
||||
SetDefaultHeight(
|
||||
SetGameResolutionSize(
|
||||
propElement.GetChild("windowWidth", 0, "WindowW").GetValue().GetInt(),
|
||||
propElement.GetChild("windowHeight", 0, "WindowH").GetValue().GetInt());
|
||||
SetMaximumFPS(
|
||||
propElement.GetChild("maxFPS", 0, "FPSmax").GetValue().GetInt());
|
||||
@@ -585,6 +589,8 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
SetVerticalSyncActivatedByDefault(
|
||||
propElement.GetChild("verticalSync").GetValue().GetBool());
|
||||
SetScaleMode(propElement.GetStringAttribute("scaleMode", "linear"));
|
||||
SetAdaptGameResolutionAtRuntime(
|
||||
propElement.GetBoolAttribute("adaptGameResolutionAtRuntime", false));
|
||||
SetSizeOnStartupMode(propElement.GetStringAttribute("sizeOnStartupMode", ""));
|
||||
#if defined(GD_IDE_ONLY)
|
||||
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
|
||||
@@ -851,8 +857,8 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
propElement.AddChild("name").SetValue(GetName());
|
||||
propElement.SetAttribute("version", GetVersion());
|
||||
propElement.AddChild("author").SetValue(GetAuthor());
|
||||
propElement.AddChild("windowWidth").SetValue(GetMainWindowDefaultWidth());
|
||||
propElement.AddChild("windowHeight").SetValue(GetMainWindowDefaultHeight());
|
||||
propElement.AddChild("windowWidth").SetValue(GetGameResolutionWidth());
|
||||
propElement.AddChild("windowHeight").SetValue(GetGameResolutionHeight());
|
||||
propElement.AddChild("latestCompilationDirectory")
|
||||
.SetValue(GetLastCompilationDirectory());
|
||||
propElement.AddChild("maxFPS").SetValue(GetMaximumFPS());
|
||||
@@ -860,6 +866,7 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
propElement.AddChild("verticalSync")
|
||||
.SetValue(IsVerticalSynchronizationEnabledByDefault());
|
||||
propElement.SetAttribute("scaleMode", scaleMode);
|
||||
propElement.SetAttribute("adaptGameResolutionAtRuntime", adaptGameResolutionAtRuntime);
|
||||
propElement.SetAttribute("sizeOnStartupMode", sizeOnStartupMode);
|
||||
propElement.SetAttribute("projectFile", gameFile);
|
||||
propElement.SetAttribute("folderProject", folderProject);
|
||||
@@ -942,18 +949,16 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Project::ValidateObjectName(const gd::String& name) {
|
||||
bool Project::ValidateName(const gd::String& name) {
|
||||
if (name.empty()) return false;
|
||||
|
||||
if (isdigit(name[0])) return false;
|
||||
|
||||
gd::String allowedCharacters =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
|
||||
return !(name.find_first_not_of(allowedCharacters) != gd::String::npos);
|
||||
}
|
||||
|
||||
gd::String Project::GetBadObjectNameWarning() {
|
||||
return _("Please use only letters, digits\nand underscores ( _ ).");
|
||||
}
|
||||
|
||||
void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
|
||||
// See also gd::WholeProjectRefactorer::ExposeProjectEvents for a method that
|
||||
// traverse the whole project (this time for events) and ExposeProjectEffects
|
||||
@@ -1059,6 +1064,7 @@ void Project::Init(const gd::Project& game) {
|
||||
minFPS = game.minFPS;
|
||||
verticalSync = game.verticalSync;
|
||||
scaleMode = game.scaleMode;
|
||||
adaptGameResolutionAtRuntime = game.adaptGameResolutionAtRuntime;
|
||||
sizeOnStartupMode = game.sizeOnStartupMode;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#define GDCORE_PROJECT_H
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/LoadingScreen.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
@@ -200,22 +201,36 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
* the first time. To change the width at runtime, use the functions related
|
||||
* to RuntimeScene.renderWindow
|
||||
*/
|
||||
void SetDefaultWidth(unsigned int width) { windowWidth = width; }
|
||||
void SetGameResolutionSize(unsigned int width, unsigned int height) {
|
||||
windowWidth = width;
|
||||
windowHeight = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default width of the project main window
|
||||
* \brief Returns the default game resolution width.
|
||||
*/
|
||||
unsigned int GetMainWindowDefaultWidth() const { return windowWidth; }
|
||||
unsigned int GetGameResolutionWidth() const { return windowWidth; }
|
||||
|
||||
/**
|
||||
* Change the default height of the project main window
|
||||
* \brief Returns the default game resolution height.
|
||||
*/
|
||||
void SetDefaultHeight(unsigned int height) { windowHeight = height; }
|
||||
unsigned int GetGameResolutionHeight() const { return windowHeight; }
|
||||
|
||||
/**
|
||||
* Return the default height of the project main window
|
||||
* \brief Returns true if the game resolution should be adapted to the window
|
||||
* size at runtime.
|
||||
*/
|
||||
unsigned int GetMainWindowDefaultHeight() const { return windowHeight; }
|
||||
bool GetAdaptGameResolutionAtRuntime() const {
|
||||
return adaptGameResolutionAtRuntime;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set if the game resolution should be adapted to the window size at
|
||||
* runtime. \see SetSizeOnStartupMode
|
||||
*/
|
||||
void SetAdaptGameResolutionAtRuntime(bool adaptGameResolutionAtRuntime_) {
|
||||
adaptGameResolutionAtRuntime = adaptGameResolutionAtRuntime_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get how the game size should be adapted to the screen.
|
||||
@@ -446,22 +461,27 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
std::size_t GetLayoutsCount() const;
|
||||
|
||||
/**
|
||||
* \brief \brief Adds a new empty layout called "name" at the specified
|
||||
* \brief Add a new empty layout called "name" at the specified
|
||||
* position in the layout list.
|
||||
*/
|
||||
gd::Layout& InsertNewLayout(const gd::String& name, std::size_t position);
|
||||
|
||||
/**
|
||||
* \brief \brief Adds a new layout constructed from the layout passed as
|
||||
* parameter. \note No pointer or reference must be kept on the layout passed
|
||||
* as parameter. \param layout The layout that must be copied and inserted
|
||||
* into the project \param position Insertion position. Even if the position
|
||||
* \brief Add a new layout constructed from the layout passed as
|
||||
* parameter.
|
||||
* \param layout The layout that must be copied and inserted
|
||||
* into the project
|
||||
* \param position Insertion position. Even if the position
|
||||
* is invalid, the layout must be inserted at the end of the layout list.
|
||||
*
|
||||
* \note No pointer or reference must be kept on the layout passed
|
||||
* as parameter.
|
||||
*
|
||||
*/
|
||||
gd::Layout& InsertLayout(const Layout& layout, std::size_t position);
|
||||
|
||||
/**
|
||||
* Must delete layout named "name".
|
||||
* \brief Delete layout named "name".
|
||||
*/
|
||||
void RemoveLayout(const gd::String& name);
|
||||
|
||||
@@ -578,7 +598,7 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
std::size_t position);
|
||||
|
||||
/**
|
||||
* Must delete external events named "name".
|
||||
* \brief Delete external events named "name".
|
||||
*/
|
||||
void RemoveExternalEvents(const gd::String& name);
|
||||
#endif
|
||||
@@ -659,7 +679,7 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
std::size_t position);
|
||||
|
||||
/**
|
||||
* Must delete external layout named "name".
|
||||
* \brief Delete external layout named "name".
|
||||
*/
|
||||
void RemoveExternalLayout(const gd::String& name);
|
||||
|
||||
@@ -680,37 +700,37 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
///@{
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* Return true if events functions extension called "name" exists.
|
||||
* \brief Check if events functions extension called "name" exists.
|
||||
*/
|
||||
bool HasEventsFunctionsExtensionNamed(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Return a reference to the events functions extension called "name".
|
||||
* \brief Return a reference to the events functions extension called "name".
|
||||
*/
|
||||
EventsFunctionsExtension& GetEventsFunctionsExtension(const gd::String& name);
|
||||
|
||||
/**
|
||||
* Return a reference to the events functions extension called "name".
|
||||
* \brief Return a reference to the events functions extension called "name".
|
||||
*/
|
||||
const EventsFunctionsExtension& GetEventsFunctionsExtension(
|
||||
const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Return a reference to the events functions extension at position "index" in
|
||||
* the list
|
||||
* \brief Return a reference to the events functions extension at position
|
||||
* "index" in the list
|
||||
*/
|
||||
EventsFunctionsExtension& GetEventsFunctionsExtension(std::size_t index);
|
||||
|
||||
/**
|
||||
* Return a reference to the events functions extension at position "index" in
|
||||
* the list
|
||||
* \brief Return a reference to the events functions extension at position
|
||||
* "index" in the list
|
||||
*/
|
||||
const EventsFunctionsExtension& GetEventsFunctionsExtension(
|
||||
std::size_t index) const;
|
||||
|
||||
/**
|
||||
* Return the position of the events functions extension called "name" in the
|
||||
* list
|
||||
* \brief Return the position of the events functions extension called "name"
|
||||
* in the list.
|
||||
*/
|
||||
std::size_t GetEventsFunctionsExtensionPosition(const gd::String& name) const;
|
||||
|
||||
@@ -722,7 +742,7 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
void SwapEventsFunctionsExtensions(std::size_t first, std::size_t second);
|
||||
|
||||
/**
|
||||
* Return the number of events functions extension.
|
||||
* \brief Returns the number of events functions extension.
|
||||
*/
|
||||
std::size_t GetEventsFunctionsExtensionsCount() const;
|
||||
|
||||
@@ -745,9 +765,14 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
std::size_t position);
|
||||
|
||||
/**
|
||||
* Must delete the events functions extension named "name".
|
||||
* \brief Delete the events functions extension named "name".
|
||||
*/
|
||||
void RemoveEventsFunctionsExtension(const gd::String& name);
|
||||
|
||||
/**
|
||||
* \brief Remove all the events functions extensions.
|
||||
*/
|
||||
void ClearEventsFunctionsExtensions();
|
||||
#endif
|
||||
///@}
|
||||
|
||||
@@ -829,21 +854,10 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Return true if \a objectName can be used as name for an object.
|
||||
*
|
||||
* Default implementation check if objectName is only composed of a-z,A-Z,0-9
|
||||
* or _ characters an if does not conflict with an expression.
|
||||
* Return true if \a name is valid (can be used safely for an object,
|
||||
* behavior, events function name, etc...).
|
||||
*/
|
||||
static bool ValidateObjectName(const gd::String& objectName);
|
||||
|
||||
/**
|
||||
* Return a message that will be displayed when an invalid object name has
|
||||
* been entered.
|
||||
*
|
||||
* \note This message will be displayed by the IDE into a tooltip.
|
||||
*/
|
||||
static gd::String GetBadObjectNameWarning();
|
||||
|
||||
static bool ValidateName(const gd::String& name);
|
||||
///@}
|
||||
|
||||
/** \name External source files
|
||||
@@ -924,6 +938,8 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
///< are below this number )
|
||||
bool verticalSync; ///< If true, must activate vertical synchronization.
|
||||
gd::String scaleMode;
|
||||
bool adaptGameResolutionAtRuntime; ///< Should the game resolution be adapted
|
||||
///< to the window size at runtime
|
||||
gd::String
|
||||
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
|
||||
///< "adaptWidth", "adaptHeight" or empty
|
||||
|
@@ -99,14 +99,12 @@ std::vector<gd::String> ResourcesManager::GetAllResourceNames() const {
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
std::map<gd::String, gd::PropertyDescriptor> Resource::GetProperties(
|
||||
gd::Project& project) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> Resource::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties(
|
||||
gd::Project& project) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties[_("Smooth the image")]
|
||||
.SetValue(smooth ? "true" : "false")
|
||||
@@ -119,8 +117,7 @@ std::map<gd::String, gd::PropertyDescriptor> ImageResource::GetProperties(
|
||||
}
|
||||
|
||||
bool ImageResource::UpdateProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) {
|
||||
const gd::String& value) {
|
||||
if (name == _("Smooth the image"))
|
||||
smooth = value == "1";
|
||||
else if (name == _("Always loaded in memory"))
|
||||
@@ -563,8 +560,7 @@ void JsonResource::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("disablePreload", IsPreloadDisabled());
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> JsonResource::GetProperties(
|
||||
gd::Project& project) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> JsonResource::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties["disablePreload"]
|
||||
.SetValue(disablePreload ? "true" : "false")
|
||||
@@ -575,8 +571,7 @@ std::map<gd::String, gd::PropertyDescriptor> JsonResource::GetProperties(
|
||||
}
|
||||
|
||||
bool JsonResource::UpdateProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) {
|
||||
const gd::String& value) {
|
||||
if (name == "disablePreload") disablePreload = value == "1";
|
||||
|
||||
return true;
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class Project;
|
||||
@@ -112,8 +113,7 @@ class GD_CORE_API Resource {
|
||||
* \return a std::map with properties names as key.
|
||||
* \see gd::PropertyDescriptor
|
||||
*/
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
gd::Project& project) const;
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a custom property of the
|
||||
@@ -122,8 +122,7 @@ class GD_CORE_API Resource {
|
||||
* \return false if the new value cannot be set
|
||||
*/
|
||||
virtual bool UpdateProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) {
|
||||
const gd::String& value) {
|
||||
return false;
|
||||
};
|
||||
///@}
|
||||
@@ -178,11 +177,9 @@ class GD_CORE_API ImageResource : public Resource {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
virtual bool UseFile() override { return true; }
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
gd::Project& project) const override;
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
bool UpdateProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) override;
|
||||
const gd::String& value) override;
|
||||
|
||||
/**
|
||||
* \brief Serialize the object
|
||||
@@ -315,11 +312,9 @@ class GD_CORE_API JsonResource : public Resource {
|
||||
#if defined(GD_IDE_ONLY)
|
||||
virtual bool UseFile() override { return true; }
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
gd::Project& project) const override;
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const override;
|
||||
bool UpdateProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project) override;
|
||||
const gd::String& value) override;
|
||||
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
#endif
|
||||
|
@@ -5,7 +5,9 @@
|
||||
*/
|
||||
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/TinyXml/tinyxml.h"
|
||||
@@ -19,9 +21,7 @@ namespace gd {
|
||||
*/
|
||||
double Variable::GetValue() const {
|
||||
if (!isNumber) {
|
||||
stringstream ss;
|
||||
ss << str;
|
||||
ss >> value;
|
||||
value = str.To<double>();
|
||||
isNumber = true;
|
||||
}
|
||||
|
||||
@@ -30,9 +30,7 @@ double Variable::GetValue() const {
|
||||
|
||||
const gd::String& Variable::GetString() const {
|
||||
if (isNumber) {
|
||||
stringstream s;
|
||||
s << (value);
|
||||
str = s.str();
|
||||
str = gd::String::From(value);
|
||||
isNumber = false;
|
||||
}
|
||||
|
||||
@@ -76,6 +74,7 @@ const Variable& Variable::GetChild(const gd::String& name) const {
|
||||
void Variable::RemoveChild(const gd::String& name) {
|
||||
if (!isStructure) return;
|
||||
children.erase(name);
|
||||
isStructure = !children.empty();
|
||||
}
|
||||
|
||||
bool Variable::RenameChild(const gd::String& oldName,
|
||||
@@ -190,6 +189,7 @@ void Variable::RemoveRecursively(const gd::Variable& variableToRemove) {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
isStructure = !children.empty();
|
||||
}
|
||||
|
||||
Variable::Variable(const Variable& other)
|
||||
|
@@ -95,6 +95,14 @@ void Serializer::FromXML(SerializerElement& element,
|
||||
}
|
||||
#endif
|
||||
|
||||
gd::String Serializer::ToEscapedXMLString(const gd::String& str) {
|
||||
return str.FindAndReplace("&", "&")
|
||||
.FindAndReplace("'", "'")
|
||||
.FindAndReplace("\"", """)
|
||||
.FindAndReplace("<", "<")
|
||||
.FindAndReplace(">", ">");
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
|
@@ -27,14 +27,26 @@ class GD_CORE_API Serializer {
|
||||
static void FromXML(SerializerElement& element,
|
||||
const TiXmlElement* xmlElement);
|
||||
#endif
|
||||
/**
|
||||
* \brief Escape a string for inclusion in a XML tag
|
||||
*/
|
||||
static gd::String ToEscapedXMLString(const gd::String& str);
|
||||
///@}
|
||||
|
||||
/** \name JSON serialization.
|
||||
* Serialize a SerializerElement from/to JSON.
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Serialize a gd::SerializerElement to a JSON string.
|
||||
*/
|
||||
static gd::String ToJSON(const SerializerElement& element);
|
||||
|
||||
static SerializerElement FromJSON(const std::string& json);
|
||||
|
||||
/**
|
||||
* \brief Parse a JSON string and returns a gd::SerializerElement for it.
|
||||
*/
|
||||
static SerializerElement FromJSON(const gd::String& json) {
|
||||
return FromJSON(json.ToUTF8());
|
||||
}
|
||||
|
@@ -25,11 +25,11 @@ gd::String GetTranslation(const char* str) { // TODO: Inline?
|
||||
// }
|
||||
ensureCache.prepare();
|
||||
|
||||
var translatedStr = getTranslation(Pointer_stringify($0));
|
||||
var translatedStr = getTranslation(UTF8ToString($0));
|
||||
return ensureString(translatedStr);
|
||||
},
|
||||
str);
|
||||
return gd::String(translatedStr); // TODO: Is copying necessary?
|
||||
}
|
||||
} // namespace gd
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -90,7 +90,7 @@ template <typename T>
|
||||
void SPtrList<T>::Init(const gd::SPtrList<T>& other) {
|
||||
elements.clear();
|
||||
for (size_t i = 0; i < other.elements.size(); ++i)
|
||||
elements.push_back(std::make_shared<T>(other[i]));
|
||||
elements.push_back(CloneRememberingOriginalElement(other.elements[i]));
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
24
Core/GDCore/Tools/UUID/UUID.h
Normal file
24
Core/GDCore/Tools/UUID/UUID.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_TOOLS_UUID_UUID_H
|
||||
#define GDCORE_TOOLS_UUID_UUID_H
|
||||
|
||||
#include "GDCore/String.h"
|
||||
#include "sole.h"
|
||||
|
||||
namespace gd {
|
||||
namespace UUID {
|
||||
|
||||
/**
|
||||
* Generate a random UUID v4
|
||||
*/
|
||||
inline gd::String MakeUuid4() { return gd::String::From(sole::uuid4()); }
|
||||
|
||||
} // namespace UUID
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user