Compare commits

..

2 Commits

Author SHA1 Message Date
Davy Hélard
e36d6018cb Typo 2022-04-15 21:19:36 +02:00
Davy Hélard
c0665dbba0 Hide advanced parameters and properties from beginners. 2022-04-15 20:54:09 +02:00
1394 changed files with 68232 additions and 117446 deletions

View File

@@ -2,17 +2,10 @@
# on the Electron runtime (newIDE/electron-app) for macOS and Linux.
# For Windows, see the appveyor.yml file.
# This also builds GDevelop.js and store it on a S3 so it can be used to run
# GDevelop without building it from scratch.
# Note that these CircleCI builds/tests are not launched on Pull Requests from forks,
# to avoid sharing secrets.
version: 2.1
orbs:
aws-cli: circleci/aws-cli@2.0.6
jobs:
# Build the **entire** app for macOS.
build-macos:
macos:
xcode: 12.5.1
@@ -68,7 +61,7 @@ jobs:
- run:
name: Clean dist folder to keep only installers/binaries.
command: rm -rf "newIDE/electron-app/dist/mac/GDevelop 5.app" && rm -rf "newIDE/electron-app/dist/mac-arm64/GDevelop 5.app"
command: rm -rf "newIDE/electron-app/dist/mac/GDevelop 5.app"
# Upload artifacts (CircleCI)
- store_artifacts:
@@ -82,7 +75,6 @@ jobs:
name: Deploy to S3 (latest)
command: export PATH=~/.local/bin:$PATH && aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
# Build the **entire** app for Linux.
build-linux:
# CircleCI docker workers are failing if they don't have enough memory (no swap)
resource_class: xlarge
@@ -143,11 +135,11 @@ jobs:
# Build GDevelop IDE (seems like we need to allow Node.js to use more space than usual)
- run:
name: Build GDevelop IDE
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && npm run build -- --linux --publish=never
command: export NODE_OPTIONS="--max-old-space-size=7168" && cd newIDE/electron-app && npm run build -- --linux AppImage zip deb --publish=never
- run:
name: Clean dist folder to keep only installers/binaries.
command: rm -rf newIDE/electron-app/dist/linux-unpacked && rm -rf newIDE/electron-app/dist/linux-arm64-unpacked
command: rm -rf newIDE/electron-app/dist/linux-unpacked
# Upload artifacts (CircleCI)
- store_artifacts:
@@ -161,67 +153,10 @@ jobs:
name: Deploy to S3 (latest)
command: aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
# Build the WebAssembly library only (so that it's cached on a S3 and easy to re-use).
build-gdevelop_js-wasm-only:
docker:
- image: cimg/node:16.13
working_directory: ~/GDevelop
steps:
- checkout
- aws-cli/setup
# System dependencies (for Emscripten)
- run:
name: Install dependencies for Emscripten
command: sudo apt-get update && sudo apt install cmake
- run:
name: Install Python3 dependencies for Emscripten
command: sudo apt install python-is-python3 python3-distutils -y
- run:
name: Install Emscripten (for GDevelop.js)
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
# GDevelop.js dependencies
- restore_cache:
keys:
- gdevelop.js-linux-nodejs-dependencies-{{ checksum "GDevelop.js/package-lock.json" }}
# fallback to using the latest cache if no exact match is found
- gdevelop.js-linux-nodejs-dependencies-
- run:
name: Install GDevelop.js dependencies and build it
command: cd GDevelop.js && npm install && cd ..
# Build GDevelop.js (and run tests to ensure it works)
- run:
name: Build GDevelop.js
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && npm test && cd ..
- save_cache:
paths:
- GDevelop.js/node_modules
key: gdevelop.js-linux-nodejs-dependencies-{{ checksum "GDevelop.js/package-lock.json" }}
# Upload artifacts (CircleCI)
- store_artifacts:
path: Binaries/embuild/GDevelop.js
# Upload artifacts (AWS)
- run:
name: Deploy to S3 (specific commit)
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/commit/$(git rev-parse HEAD)/
- run:
name: Deploy to S3 (latest)
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/latest/
workflows:
builds:
jobs:
- build-gdevelop_js-wasm-only
- build-macos:
filters:
branches:

View File

@@ -1,19 +0,0 @@
---
name: "📦 Asset Store submission"
about: Submit a free asset pack for the GDevelop Asset Store.
title: ''
labels: "📦 Asset Store submission"
assignees: ''
---
BEFORE opening a new submission, please make sure that you:
- You have packaged the asset pack according [these rules](https://wiki.gdevelop.io/gdevelop5/community/contribute-to-the-assets-store). Otherwise, your package may be rejected or we will ask you to do the changes.
## Description
- License:
- Author:
- Link to the original website:
- Zip file:

View File

@@ -10,11 +10,11 @@ assignees: ''
BEFORE opening a new feature request, please make sure that you:
- Understand the implications of your feature with the help of [the Forum](https://forum.gdevelop.io/c/gdevelop-general/feature-requests/35), OR
- Peer-reviewed it with other users on Discord,
- Consider commenting on the [Feature Request Forum](https://forum.gdevelop.io/c/gdevelop-general/feature-requests/35) if something is important for you
- Discussed it on the discord or the forum,
- There is not already a suggestion about it in the issues or in the roadmap: https://trello.com/b/qf0lM7k8/gdevelop-roadmap
- Consider commenting on the roadmap if something is important for you
AFTER opening the feature request, the issue will be closed by a maintainer (@4ian or someone else) and a card will be added in [the public roadmap](https://trello.com/b/qf0lM7k8/gdevelop-ideas-box) if it's relevant and does not exist yet :)
AFTER opening the feature request, the issue will be closed by a maintainer (@4ian or someone else) and a card will be added in the roadmap if it's relevant and does not exist yet :)
## Description

View File

@@ -4,14 +4,14 @@ contact_links:
url: https://discord.gg/rjdYHvj
about: Discuss on the forum or on the Discord to get help creating a game or identifying a bug.
- name: GDevelop Forums
url: https://forum.gdevelop.io
url: https://forum.gdevelop-app.com
about: You can also discuss game creation, new feature requests and bugs on the forum.
- name: GDevelop Roadmap
url: https://trello.com/b/qf0lM7k8/gdevelop-roadmap
about: Look at the roadmap and vote on features that you want to see in GDevelop.
- name: Submit a new game example that you created
url: https://github.com/GDevelopApp/GDevelop-examples/issues/new/choose
about: You can submit a game that you made to be added to examples in the "GDevelop-examples" repository
about: You can submit a game that you made to be added to examples in the "GDevelop-examples" repository
- name: Submit a new game extension that you created
url: https://github.com/4ian/GDevelop-extensions/issues/new/choose
about: You can submit an extension that you made in the "GDevelop-extensions" repository
about: You can submit an extension that you made in the "GDevelop-extensions" repository

View File

@@ -12,7 +12,7 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }}
type: "body"
regex: ".*Scroll down to '\\.\\.\\.\\.'.*"
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any steps to reproduce the bug.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop.io/), the Discord chat or [read the documentation](https://wiki.gdevelop.io/gdevelop5/start) to learn more about GDevelop. Thanks!"
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any steps to reproduce the bug.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop-app.com/), the Discord chat or [read the documentation](http://wiki.compilgames.net/doku.php/gdevelop5/start) to learn more about GDevelop. Thanks!"
- name: Autoclose known beta 105 web-app update bug
uses: arkon/issue-closer-action@v1.1
with:

1
.gitignore vendored
View File

@@ -8,7 +8,6 @@
/Binaries/.embuild*
/Binaries/build*
/Binaries/embuild*
/emsdk
*.dll
*.exe
*.a

View File

@@ -1,25 +0,0 @@
# This is a configuration file allowing to quickly set up a development environment
# on GitPod (https://www.gitpod.io/).
# Also check GitHub codespaces if you're interested in working
# on a remote development server.
# This works well for:
# - The editor web-app, including the C++ classes.
# This is not yet adapted for:
# - Working on the game engine or extensions, as they can't be easily tested on the web-app.
# - Working on the desktop app (Electron).
tasks:
- name: Install dependencies for Emscripten and build GDevelop.js
init: |
sudo apt-get update
sudo apt install cmake python-is-python3 python3-distutils -y
git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 1.39.6 && ./emsdk activate 1.39.6 && cd ..
cd GDevelop.js
npm install
source ../emsdk/emsdk_env.sh && npm run build -- --dev
cd ..
- name: Install GDevelop IDE dependencies
init: cd newIDE/app && npm install && cd ../electron-app && npm install

View File

@@ -1,6 +1,9 @@
# Travis CI configuration to build and run all tests
# (and typing/formatting) for the Core, newIDE, GDJS.
#
# This builds GDevelop.js and store it on a S3 so it can be used to run
# GDevelop without building it.
#
# See also Semaphore CI for quick tests (not building GDevelop.js, so
# faster but not always reliable).
@@ -14,7 +17,18 @@ cache:
directories:
- $HOME/.npm
services:
# Virtual Framebuffer 'fake' X server for SFML
- xvfb
addons:
artifacts:
s3_region: "us-east-1"
target_paths:
- /$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)/commit/$(git rev-parse HEAD)
- /$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)/latest
paths:
- Binaries/embuild/GDevelop.js
apt:
sources:
- ubuntu-toolchain-r-test
@@ -22,8 +36,20 @@ addons:
# Build dependencies:
- cmake
- p7zip-full
# SFML dependencies:
- libopenal-dev
- libjpeg-dev
- libglew-dev
- libudev-dev
- libxrandr-dev
- libsndfile1-dev
- libglu1-mesa-dev
- libfreetype6-dev
before_install:
#Activate X Virtual Framebuffer to allow tests to
#use SFML.
- "export DISPLAY=:99.0"
# This workaround is required to avoid libstdc++ errors (Emscripten requires a recent version of libstdc++)
- wget -q -O libstdc++6 http://security.ubuntu.com/ubuntu/pool/main/g/gcc-5/libstdc++6_5.4.0-6ubuntu1~16.04.12_amd64.deb
- sudo dpkg --force-all -i libstdc++6

View File

@@ -7,9 +7,11 @@
"${workspaceRoot}/GDJS",
"${workspaceRoot}/Extensions",
"${workspaceRoot}/Core",
"${workspaceRoot}/ExtLibs/SFML/include",
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
"/usr/local/include",
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
"/usr/include",
"${workspaceRoot}"
],
"defines": [
@@ -25,6 +27,7 @@
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
"/usr/local/include",
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",
"/usr/include",
"${workspaceRoot}"
],
"limitSymbolsToIncludedHeaders": true,
@@ -45,6 +48,7 @@
"${workspaceRoot}/GDJS",
"${workspaceRoot}/Extensions",
"${workspaceRoot}/Core",
"${workspaceRoot}/ExtLibs/SFML/include",
"/usr/include",
"/usr/local/include",
"${workspaceRoot}"
@@ -74,6 +78,7 @@
"${workspaceRoot}/GDJS",
"${workspaceRoot}/Extensions",
"${workspaceRoot}/Core",
"${workspaceRoot}/ExtLibs/SFML/include",
"${workspaceRoot}"
],
"defines": [
@@ -96,4 +101,4 @@
}
],
"version": 4
}
}

14
.vscode/launch.json vendored
View File

@@ -15,20 +15,6 @@
"disableOptimisticBPs": true,
"cwd": "${workspaceFolder}/GDevelop.js"
},
{
"type": "node",
"request": "launch",
"name": "newIDE/app Jest tests (current file)",
"program": "${workspaceFolder}/newIDE/app/node_modules/.bin/react-scripts",
"args": [
"test", "--env=node",
"${fileBasenameNoExtension}"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"cwd": "${workspaceFolder}/newIDE/app"
},
{
"type": "node",
"request": "launch",

View File

@@ -115,6 +115,7 @@
"files.exclude": {
"Binaries/*build*": true,
"Binaries/Output": true,
"ExtLibs/SFML": true,
"GDJS/Runtime-dist": true,
"docs": true,
"newIDE/electron-app/dist": true,

View File

@@ -17,7 +17,7 @@ endmacro()
gd_set_option(BUILD_CORE TRUE BOOL "TRUE to build GDevelop Core library")
gd_set_option(BUILD_GDJS TRUE BOOL "TRUE to build GDevelop JS Platform")
gd_set_option(BUILD_EXTENSIONS TRUE BOOL "TRUE to build the extensions")
gd_set_option(BUILD_TESTS TRUE BOOL "TRUE to build the tests")
gd_set_option(BUILD_TESTS FALSE BOOL "TRUE to build the tests")
# Disable deprecated code
set(NO_GUI TRUE CACHE BOOL "" FORCE) #Force disable old GUI related code.

View File

@@ -14,6 +14,7 @@ set(GDCORE_lib_dir ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SY
#Dependencies on external libraries:
###
include_directories(${sfml_include_dir})
#Defines
###
@@ -67,6 +68,14 @@ set(LIBRARY_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMA
set(ARCHIVE_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME})
set(RUNTIME_OUTPUT_PATH ${GD_base_dir}/Binaries/Output/${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME})
#Linker files
###
IF(EMSCRIPTEN)
#Nothing.
ELSE()
target_link_libraries(GDCore ${sfml_LIBRARIES})
ENDIF()
#Tests
###
if(BUILD_TESTS)
@@ -79,5 +88,5 @@ if(BUILD_TESTS)
add_executable(GDCore_tests ${test_source_files})
set_target_properties(GDCore_tests PROPERTIES BUILD_WITH_INSTALL_RPATH FALSE) #Allow finding dependencies directly from build path on Mac OS X.
target_link_libraries(GDCore_tests GDCore)
target_link_libraries(GDCore_tests ${CMAKE_DL_LIBS})
target_link_libraries(GDCore_tests ${sfml_LIBRARIES})
endif()

View File

@@ -13,6 +13,7 @@
#include <string>
#include <vector>
#include "Utf8/utf8.h"
#include <SFML/System/String.hpp>
#ifdef __GNUC__
#define GD_DEPRECATED __attribute__((deprecated))

View File

@@ -1,36 +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 "AsyncEvent.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/Serialization.h"
#include "GDCore/Serialization/SerializerElement.h"
using namespace std;
namespace gd {
AsyncEvent::AsyncEvent() : BaseEvent() {}
AsyncEvent::~AsyncEvent(){};
vector<const gd::InstructionsList *> AsyncEvent::GetAllActionsVectors() const {
vector<const gd::InstructionsList *> allActions;
allActions.push_back(&actions);
return allActions;
}
vector<gd::InstructionsList *> AsyncEvent::GetAllActionsVectors() {
vector<gd::InstructionsList *> allActions;
allActions.push_back(&actions);
return allActions;
}
} // namespace gd

View File

@@ -1,61 +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_ASYNCEVENT_H
#define GDCORE_ASYNCEVENT_H
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Events/InstructionsList.h"
namespace gd {
class Instruction;
class Project;
} // namespace gd
namespace gd {
/**
* \brief Internal event for asynchronous actions.
* This event gets added internally to the events tree when an
* asynchronous action is used.
*/
class GD_CORE_API AsyncEvent : public gd::BaseEvent {
public:
AsyncEvent();
AsyncEvent(const gd::Instruction &asyncAction_,
const gd::InstructionsList &actions_,
const gd::EventsList &subEvents_)
: asyncAction(asyncAction_), actions(actions_), subEvents(subEvents_) {
SetType("BuiltinAsync::Async");
};
virtual ~AsyncEvent();
virtual gd::AsyncEvent *Clone() const { return new AsyncEvent(*this); }
virtual bool IsExecutable() const { return true; }
virtual bool CanHaveSubEvents() const { return true; }
virtual const gd::EventsList &GetSubEvents() const { return subEvents; };
virtual gd::EventsList &GetSubEvents() { return subEvents; };
const gd::InstructionsList &GetActions() const { return actions; };
gd::InstructionsList &GetActions() { return actions; };
const gd::Instruction &GetInstruction() const { return asyncAction; };
gd::Instruction &GetInstruction() { return asyncAction; };
virtual std::vector<const gd::InstructionsList *>
GetAllActionsVectors() const;
virtual std::vector<gd::InstructionsList *> GetAllActionsVectors();
private:
gd::Instruction asyncAction;
gd::InstructionsList actions;
EventsList subEvents;
};
} // namespace gd
#endif // GDCORE_STANDARDEVENT_H

View File

@@ -23,9 +23,8 @@ vector<gd::String> CommentEvent::GetAllSearchableStrings() const {
bool CommentEvent::ReplaceAllSearchableStrings(
std::vector<gd::String> newSearchableString) {
if (newSearchableString[0] == com1) return false;
SetComment(newSearchableString[0]);
return true;
return newSearchableString[0] == com1;
}
void CommentEvent::SerializeTo(SerializerElement &element) const {

View File

@@ -53,10 +53,8 @@ void ForEachChildVariableEvent::SerializeTo(SerializerElement& element) const {
conditions, element.AddChild("conditions"));
gd::EventsListSerialization::SerializeInstructionsTo(
actions, element.AddChild("actions"));
if (!events.IsEmpty())
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
}
void ForEachChildVariableEvent::UnserializeFrom(gd::Project& project,
@@ -68,12 +66,8 @@ void ForEachChildVariableEvent::UnserializeFrom(gd::Project& project,
project, conditions, element.GetChild("conditions", 0, "Conditions"));
gd::EventsListSerialization::UnserializeInstructionsFrom(
project, actions, element.GetChild("actions", 0, "Actions"));
events.Clear();
if (element.HasChild("events", "Events")) {
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
} // namespace gd

View File

@@ -74,10 +74,8 @@ void ForEachEvent::SerializeTo(SerializerElement& element) const {
conditions, element.AddChild("conditions"));
gd::EventsListSerialization::SerializeInstructionsTo(
actions, element.AddChild("actions"));
if (!events.IsEmpty())
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
}
void ForEachEvent::UnserializeFrom(gd::Project& project,
@@ -88,12 +86,8 @@ void ForEachEvent::UnserializeFrom(gd::Project& project,
project, conditions, element.GetChild("conditions", 0, "Conditions"));
gd::EventsListSerialization::UnserializeInstructionsFrom(
project, actions, element.GetChild("actions", 0, "Actions"));
events.Clear();
if (element.HasChild("events", "Events")) {
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
} // namespace gd

View File

@@ -29,9 +29,8 @@ vector<gd::String> GroupEvent::GetAllSearchableStrings() const {
bool GroupEvent::ReplaceAllSearchableStrings(
std::vector<gd::String> newSearchableString) {
if (newSearchableString[0] == name) return false;
SetName(newSearchableString[0]);
return true;
return newSearchableString[0] == name;
}
void GroupEvent::SerializeTo(SerializerElement& element) const {

View File

@@ -75,10 +75,8 @@ void RepeatEvent::SerializeTo(SerializerElement& element) const {
conditions, element.AddChild("conditions"));
gd::EventsListSerialization::SerializeInstructionsTo(
actions, element.AddChild("actions"));
if (!events.IsEmpty())
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
}
void RepeatEvent::UnserializeFrom(gd::Project& project,
@@ -91,12 +89,8 @@ void RepeatEvent::UnserializeFrom(gd::Project& project,
project, conditions, element.GetChild("conditions", 0, "Conditions"));
gd::EventsListSerialization::UnserializeInstructionsFrom(
project, actions, element.GetChild("actions", 0, "Actions"));
events.Clear();
if (element.HasChild("events", "Events")) {
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
} // namespace gd

View File

@@ -53,10 +53,8 @@ void StandardEvent::SerializeTo(SerializerElement& element) const {
conditions, element.AddChild("conditions"));
gd::EventsListSerialization::SerializeInstructionsTo(
actions, element.AddChild("actions"));
if (!events.IsEmpty())
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
}
void StandardEvent::UnserializeFrom(gd::Project& project,
@@ -65,12 +63,8 @@ void StandardEvent::UnserializeFrom(gd::Project& project,
project, conditions, element.GetChild("conditions", 0, "Conditions"));
gd::EventsListSerialization::UnserializeInstructionsFrom(
project, actions, element.GetChild("actions", 0, "Actions"));
events.Clear();
if (element.HasChild("events", "Events")) {
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
} // namespace gd

View File

@@ -52,10 +52,8 @@ void WhileEvent::SerializeTo(SerializerElement& element) const {
conditions, element.AddChild("conditions"));
gd::EventsListSerialization::SerializeInstructionsTo(
actions, element.AddChild("actions"));
if (!events.IsEmpty())
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
gd::EventsListSerialization::SerializeEventsTo(events,
element.AddChild("events"));
}
void WhileEvent::UnserializeFrom(gd::Project& project,
@@ -70,12 +68,8 @@ void WhileEvent::UnserializeFrom(gd::Project& project,
project, conditions, element.GetChild("conditions", 0, "Conditions"));
gd::EventsListSerialization::UnserializeInstructionsFrom(
project, actions, element.GetChild("actions", 0, "Actions"));
events.Clear();
if (element.HasChild("events", "Events")) {
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
gd::EventsListSerialization::UnserializeEventsFrom(
project, events, element.GetChild("events", 0, "Events"));
}
} // namespace gd

View File

@@ -4,9 +4,7 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Events/CodeGeneration/EventsCodeGenerationContext.h"
#include <set>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
@@ -16,7 +14,7 @@ using namespace std;
namespace gd {
void EventsCodeGenerationContext::InheritsFrom(
EventsCodeGenerationContext& parent_) {
const EventsCodeGenerationContext& parent_) {
parent = &parent_;
// Objects lists declared by parent became "already declared" in the child
@@ -26,8 +24,8 @@ void EventsCodeGenerationContext::InheritsFrom(
parent_.objectsListsToBeDeclared.end(),
std::inserter(alreadyDeclaredObjectsLists,
alreadyDeclaredObjectsLists.begin()));
std::copy(parent_.objectsListsOrEmptyToBeDeclared.begin(),
parent_.objectsListsOrEmptyToBeDeclared.end(),
std::copy(parent_.objectsListsWithoutPickingToBeDeclared.begin(),
parent_.objectsListsWithoutPickingToBeDeclared.end(),
std::inserter(alreadyDeclaredObjectsLists,
alreadyDeclaredObjectsLists.begin()));
std::copy(parent_.emptyObjectsListsToBeDeclared.begin(),
@@ -35,8 +33,6 @@ void EventsCodeGenerationContext::InheritsFrom(
std::inserter(alreadyDeclaredObjectsLists,
alreadyDeclaredObjectsLists.begin()));
nearestAsyncParent = parent_.IsAsyncCallback() ? &parent_ : parent_.nearestAsyncParent;
asyncDepth = parent_.asyncDepth;
depthOfLastUse = parent_.depthOfLastUse;
customConditionDepth = parent_.customConditionDepth;
contextDepth = parent_.GetContextDepth() + 1;
@@ -46,59 +42,33 @@ void EventsCodeGenerationContext::InheritsFrom(
}
}
void EventsCodeGenerationContext::InheritsAsAsyncCallbackFrom(
EventsCodeGenerationContext& parent_) {
// Increasing the async depth is enough to mark the context as an async callback.
InheritsFrom(parent_);
asyncDepth = parent_.asyncDepth + 1;
}
void EventsCodeGenerationContext::Reuse(
EventsCodeGenerationContext& parent_) {
const EventsCodeGenerationContext& parent_) {
InheritsFrom(parent_);
if (parent_.CanReuse())
contextDepth = parent_.GetContextDepth(); // Keep same context depth
}
void EventsCodeGenerationContext::NotifyAsyncParentsAboutDeclaredObject(const gd::String& objectName) {
gd::EventsCodeGenerationContext* asyncContext = IsAsyncCallback() ? this : nearestAsyncParent;
for (;
asyncContext != nullptr;
asyncContext = asyncContext->parent->nearestAsyncParent)
asyncContext->allObjectsListToBeDeclaredAcrossChildren.insert(objectName);
}
void EventsCodeGenerationContext::ObjectsListNeeded(
const gd::String& objectName) {
if (!IsToBeDeclared(objectName)) {
if (!IsToBeDeclared(objectName))
objectsListsToBeDeclared.insert(objectName);
if (IsInsideAsync()) {
NotifyAsyncParentsAboutDeclaredObject(objectName);
}
}
depthOfLastUse[objectName] = GetContextDepth();
}
void EventsCodeGenerationContext::ObjectsListNeededOrEmptyIfJustDeclared(
void EventsCodeGenerationContext::ObjectsListWithoutPickingNeeded(
const gd::String& objectName) {
if (!IsToBeDeclared(objectName)) {
objectsListsOrEmptyToBeDeclared.insert(objectName);
if (IsInsideAsync()) {
NotifyAsyncParentsAboutDeclaredObject(objectName);
}
}
if (!IsToBeDeclared(objectName))
objectsListsWithoutPickingToBeDeclared.insert(objectName);
depthOfLastUse[objectName] = GetContextDepth();
}
void EventsCodeGenerationContext::EmptyObjectsListNeeded(
const gd::String& objectName) {
if (!IsToBeDeclared(objectName)) {
if (!IsToBeDeclared(objectName))
emptyObjectsListsToBeDeclared.insert(objectName);
}
depthOfLastUse[objectName] = GetContextDepth();
}
@@ -107,8 +77,8 @@ std::set<gd::String> EventsCodeGenerationContext::GetAllObjectsToBeDeclared()
const {
std::set<gd::String> allObjectListsToBeDeclared(
objectsListsToBeDeclared.begin(), objectsListsToBeDeclared.end());
allObjectListsToBeDeclared.insert(objectsListsOrEmptyToBeDeclared.begin(),
objectsListsOrEmptyToBeDeclared.end());
allObjectListsToBeDeclared.insert(objectsListsWithoutPickingToBeDeclared.begin(),
objectsListsWithoutPickingToBeDeclared.end());
allObjectListsToBeDeclared.insert(emptyObjectsListsToBeDeclared.begin(),
emptyObjectsListsToBeDeclared.end());
@@ -132,21 +102,4 @@ bool EventsCodeGenerationContext::IsSameObjectsList(
otherContext.GetLastDepthObjectListWasNeeded(objectName);
}
bool EventsCodeGenerationContext::ShouldUseAsyncObjectsList(
const gd::String& objectName) const {
if (!IsInsideAsync()) return false;
// Check if the objects list was used after (or in) the nearest async callback context.
const gd::EventsCodeGenerationContext* asyncContext = IsAsyncCallback() ? this : nearestAsyncParent;
if (parent->GetLastDepthObjectListWasNeeded(objectName) >= asyncContext->GetContextDepth()) {
// The object was used in a context after (or in) the nearest async parent context, so we're not getting it from the
// async object lists (it was already gotten from there in this previous context).
return false;
}
// If the objects list is declared in a parent of the nearest async context, it means
// the async context had to use an async objects list to access it.
return asyncContext->ObjectAlreadyDeclaredByParents(objectName);
};
} // namespace gd

View File

@@ -8,7 +8,6 @@
#include <map>
#include <memory>
#include <set>
#include "GDCore/String.h"
namespace gd {
@@ -34,7 +33,11 @@ class GD_CORE_API EventsCodeGenerationContext {
* updated to contain the maximal scope depth reached.
*/
EventsCodeGenerationContext(unsigned int* maxDepthLevel_ = nullptr)
: maxDepthLevel(maxDepthLevel_){};
: contextDepth(0),
customConditionDepth(0),
maxDepthLevel(maxDepthLevel_),
parent(NULL),
reuseExplicitlyForbidden(false){};
virtual ~EventsCodeGenerationContext(){};
/**
@@ -42,13 +45,7 @@ class GD_CORE_API EventsCodeGenerationContext {
* another one. The child will then for example not declare again objects
* already declared by its parent.
*/
void InheritsFrom(EventsCodeGenerationContext& parent);
/**
* Call this method to make an EventsCodeGenerationContext as a "child" of
* another one, but in the context of an async function.
*/
void InheritsAsAsyncCallbackFrom(EventsCodeGenerationContext& parent);
void InheritsFrom(const EventsCodeGenerationContext& parent);
/**
* \brief As InheritsFrom, mark the context as being the child of another one,
@@ -56,7 +53,7 @@ class GD_CORE_API EventsCodeGenerationContext {
*
* Used for example for optimizing the last event of a list.
*/
void Reuse(EventsCodeGenerationContext& parent);
void Reuse(const EventsCodeGenerationContext& parent);
/**
* \brief Forbid any optimization that would reuse and modify the object list
@@ -91,19 +88,19 @@ class GD_CORE_API EventsCodeGenerationContext {
const EventsCodeGenerationContext* GetParentContext() const { return parent; }
/**
* Mark the object as being the object being handled by the instruction.
* Mark the object has being the object being handled by the instruction
*/
void SetCurrentObject(const gd::String& objectName) {
currentObject = objectName;
};
/**
* Set that no particular object is being handled by an instruction.
* Set that no particular object is being handled by an instruction
*/
void SetNoCurrentObject() { currentObject = ""; };
/**
* Get the object being handled by the instruction.
* Get the object being handled by the instruction
*/
const gd::String& GetCurrentObject() const { return currentObject; };
@@ -112,7 +109,7 @@ class GD_CORE_API EventsCodeGenerationContext {
*
* The list will be filled with objects from the scene if it is the first time
* it is requested, unless there is already an object list with this name
* (i.e. `ObjectAlreadyDeclaredByParents(objectName)` returns true).
* (i.e. `ObjectAlreadyDeclared(objectName)` returns true).
*/
void ObjectsListNeeded(const gd::String& objectName);
@@ -124,7 +121,7 @@ class GD_CORE_API EventsCodeGenerationContext {
* from the scene. If there is already an objects list with this name, no new
* list will be declared again.
*/
void ObjectsListNeededOrEmptyIfJustDeclared(const gd::String& objectName);
void ObjectsListWithoutPickingNeeded(const gd::String& objectName);
/**
* Call this when an instruction in the event needs an empty object list,
@@ -137,21 +134,29 @@ class GD_CORE_API EventsCodeGenerationContext {
void EmptyObjectsListNeeded(const gd::String& objectName);
/**
* Return true if an object list has already been declared by the parent contexts.
* Return true if an object list has already been declared (or is going to be
* declared).
*/
bool ObjectAlreadyDeclaredByParents(const gd::String& objectName) const {
bool ObjectAlreadyDeclared(const gd::String& objectName) const {
return (alreadyDeclaredObjectsLists.find(objectName) !=
alreadyDeclaredObjectsLists.end());
};
/**
* \brief Consider that \a objectName is now declared in the context.
*/
void SetObjectDeclared(const gd::String& objectName) {
alreadyDeclaredObjectsLists.insert(objectName);
}
/**
* Return all the objects lists which will be declared by the current context
* (normal, potentially empty or empty).
* ( the non empty as well as the empty objects lists )
*/
std::set<gd::String> GetAllObjectsToBeDeclared() const;
/**
* Return the objects lists which will be declared by the current context.
* Return the objects lists which will be declared by the current context
*/
const std::set<gd::String>& GetObjectsListsToBeDeclared() const {
return objectsListsToBeDeclared;
@@ -161,9 +166,9 @@ class GD_CORE_API EventsCodeGenerationContext {
* Return the objects lists which will be will be declared, without filling
* them with objects from the scene.
*/
const std::set<gd::String>& GetObjectsListsToBeEmptyIfJustDeclared()
const std::set<gd::String>& GetObjectsListsToBeDeclaredWithoutPicking()
const {
return objectsListsOrEmptyToBeDeclared;
return objectsListsWithoutPickingToBeDeclared;
};
/**
@@ -179,7 +184,7 @@ class GD_CORE_API EventsCodeGenerationContext {
* Return the objects lists which are already declared and can be used in the
* current context without declaration.
*/
const std::set<gd::String>& GetObjectsListsAlreadyDeclaredByParents() const {
const std::set<gd::String>& GetObjectsListsAlreadyDeclared() const {
return alreadyDeclaredObjectsLists;
};
@@ -222,55 +227,22 @@ class GD_CORE_API EventsCodeGenerationContext {
*/
size_t GetCurrentConditionDepth() const { return customConditionDepth; }
/**
* \brief Returns the list of all objects declared in this context
* and subcontexts.
* \warning Only works on an async callback's context.
*
* It is to be used by the Async event code generator to know what objects
* lists to backup for the async callback and async callbacks after it.
*/
const std::set<gd::String>& GetAllDeclaredObjectsAcrossChildren() {
return allObjectsListToBeDeclaredAcrossChildren;
};
/**
* Returns true if an object list should be gotten from a backed up
* objects list instead of the parent context. This can happen inside an
* asynchronous callback or a child context of an asynchronous callback (i.e:
* the `asyncDepth` is not 0).
*/
bool ShouldUseAsyncObjectsList(const gd::String& objectName) const;
/**
* Returns true if the code currently being generated is inside an
* asynchronous context (either in an asynchronous callback, or in a children of
* an asynchronous callback).
*/
bool IsInsideAsync() const { return asyncDepth != 0; };
/**
* Returns true if the code currently being generated is an asynchronous
* callback (but not a child of an asynchronous callback).
*/
bool IsAsyncCallback() const { return parent != nullptr && parent->asyncDepth != asyncDepth; }
private:
/**
* \brief Returns true if the given object is already going to be declared
* in this context (either as a traditional objects list, or an empty one).
* (either as a traditional objects list, or one without picking, or one
* empty).
*
*/
bool IsToBeDeclared(const gd::String& objectName) {
return objectsListsToBeDeclared.find(objectName) !=
objectsListsToBeDeclared.end() ||
objectsListsOrEmptyToBeDeclared.find(objectName) !=
objectsListsOrEmptyToBeDeclared.end() ||
objectsListsWithoutPickingToBeDeclared.find(objectName) !=
objectsListsWithoutPickingToBeDeclared.end() ||
emptyObjectsListsToBeDeclared.find(objectName) !=
emptyObjectsListsToBeDeclared.end();
};
private:
void NotifyAsyncParentsAboutDeclaredObject(const gd::String& objectName);
std::set<gd::String>
alreadyDeclaredObjectsLists; ///< Objects lists already needed in a
///< parent context.
@@ -278,7 +250,7 @@ class GD_CORE_API EventsCodeGenerationContext {
objectsListsToBeDeclared; ///< Objects lists that will be declared in
///< this context.
std::set<gd::String>
objectsListsOrEmptyToBeDeclared; ///< Objects lists that will be
objectsListsWithoutPickingToBeDeclared; ///< Objects lists that will be
///< declared in this context,
///< but not filled with scene's
///< objects.
@@ -288,40 +260,21 @@ class GD_CORE_API EventsCodeGenerationContext {
///< but not filled with scene's
///< objects and not filled with any
///< previously existing objects list.
std::set<gd::String>
allObjectsListToBeDeclaredAcrossChildren; ///< This is only to be used by
///< the async callback
///< contexts to know all
///< objects declared across
///< all children, so that the
///< necessary objects can be
///< backed up.
std::map<gd::String, unsigned int>
depthOfLastUse; ///< The context depth when an object was last used.
gd::String
currentObject; ///< The object being used by an action or condition.
unsigned int contextDepth = 0; ///< The depth of the context: 0 for a newly
///< created context, n+1 for any context
///< inheriting from context with depth n.
unsigned int customConditionDepth =
0; ///< The depth of the conditions being generated.
unsigned int asyncDepth =
0; ///< If higher than 0, the current context is an asynchronous callback,
///< or a child context of an asynchronous callback:
///< - If the parent's async depth != the current context async depth,
///< then the current context is an asynchronous callback context.
///< - Otherwise, it's a child of an asynchronous callback.
unsigned int contextDepth; ///< The depth of the context : 0 for a newly
///< created context, n+1 for any context
///< inheriting from context with depth n.
unsigned int
customConditionDepth; ///< The depth of the conditions being generated.
unsigned int* maxDepthLevel; ///< A pointer to a unsigned int updated with
///< the maximum depth reached.
const EventsCodeGenerationContext* parent =
nullptr; ///< The parent of the current context. Can be NULL.
EventsCodeGenerationContext* nearestAsyncParent =
nullptr; ///< The nearest parent context that is an async callback
///< context.
bool reuseExplicitlyForbidden =
false; ///< If set to true, forbid children contexts
///< to reuse this one without inheriting.
const EventsCodeGenerationContext*
parent; ///< The parent of the current context. Can be NULL.
bool reuseExplicitlyForbidden; ///< If set to true, forbid children context
///< to reuse this one without inheriting.
};
} // namespace gd

View File

@@ -450,9 +450,7 @@ gd::String EventsCodeGenerator::GenerateConditionsListCode(
* Generate code for an action.
*/
gd::String EventsCodeGenerator::GenerateActionCode(
gd::Instruction& action,
EventsCodeGenerationContext& context,
const gd::String& optionalAsyncCallbackName) {
gd::Instruction& action, EventsCodeGenerationContext& context) {
gd::String actionCode;
const gd::InstructionMetadata& instrInfos =
@@ -468,14 +466,6 @@ gd::String EventsCodeGenerator::GenerateActionCode(
action, *this, context);
}
// Get the correct function name depending on whether it should be async or
// not.
const gd::String& functionCallName =
instrInfos.IsAsync() &&
(!instrInfos.IsOptionallyAsync() || action.IsAwaited())
? instrInfos.codeExtraInformation.asyncFunctionCallName
: instrInfos.codeExtraInformation.functionCallName;
// Be sure there is no lack of parameter.
while (action.GetParameters().size() < instrInfos.parameters.size()) {
vector<gd::Expression> parameters = action.GetParameters();
@@ -528,13 +518,8 @@ gd::String EventsCodeGenerator::GenerateActionCode(
// Prepare arguments and generate the whole action code
vector<gd::String> arguments = GenerateParametersCodes(
action.GetParameters(), instrInfos.parameters, context);
actionCode += GenerateObjectAction(realObjects[i],
objInfo,
functionCallName,
arguments,
instrInfos,
context,
optionalAsyncCallbackName);
actionCode += GenerateObjectAction(
realObjects[i], objInfo, arguments, instrInfos, context);
context.SetNoCurrentObject();
}
@@ -565,11 +550,9 @@ gd::String EventsCodeGenerator::GenerateActionCode(
GenerateBehaviorAction(realObjects[i],
action.GetParameter(1).GetPlainString(),
autoInfo,
functionCallName,
arguments,
instrInfos,
context,
optionalAsyncCallbackName);
context);
context.SetNoCurrentObject();
}
@@ -577,75 +560,12 @@ gd::String EventsCodeGenerator::GenerateActionCode(
} else {
vector<gd::String> arguments = GenerateParametersCodes(
action.GetParameters(), instrInfos.parameters, context);
actionCode += GenerateFreeAction(functionCallName,
arguments,
instrInfos,
context,
optionalAsyncCallbackName);
actionCode += GenerateFreeAction(arguments, instrInfos, context);
}
return actionCode;
}
const EventsCodeGenerator::CallbackDescriptor
EventsCodeGenerator::GenerateCallback(
const gd::String& callbackID,
gd::EventsCodeGenerationContext& parentContext,
gd::InstructionsList& actions,
gd::EventsList* subEvents) {
gd::EventsCodeGenerationContext callbackContext;
callbackContext.InheritsAsAsyncCallbackFrom(parentContext);
const gd::String callbackFunctionName =
GetCodeNamespaceAccessor() + "asyncCallback" + callbackID;
const gd::String callbackFunctionArguments =
GenerateEventsParameters(callbackContext);
// Generate actions
gd::String actionsCode = GenerateActionsListCode(actions, callbackContext);
// Generate subevents
if (subEvents != nullptr) // Sub events
{
actionsCode += "\n{ //Subevents\n";
actionsCode += GenerateEventsListCode(*subEvents, callbackContext);
actionsCode += "} //End of subevents\n";
}
// Compose the callback function and add outside main
const gd::String actionsDeclarationsCode =
GenerateObjectsDeclarationCode(callbackContext);
const gd::String callbackCode = callbackFunctionName + " = function (" +
GenerateEventsParameters(callbackContext) +
") {\n" + actionsDeclarationsCode +
actionsCode + "}\n";
AddCustomCodeOutsideMain(callbackCode);
std::set<gd::String> requiredObjects;
// Build the list of all objects required by the callback. Any object that has
// already been declared could have gone through previous object picking, so
// if such an object is used by the actions or subevents of this callback, we
// must ask the caller to pass the already existing objects lists through a
// `LongLivedObjectsList` to the callback function.
for (const auto& objectUsedInSubTree :
callbackContext.GetAllDeclaredObjectsAcrossChildren()) {
if (callbackContext.ObjectAlreadyDeclaredByParents(objectUsedInSubTree))
requiredObjects.insert(objectUsedInSubTree);
};
return CallbackDescriptor(
callbackFunctionName, callbackFunctionArguments, requiredObjects);
};
const gd::String EventsCodeGenerator::GenerateEventsParameters(
const gd::EventsCodeGenerationContext& context) {
gd::String parameters = "runtimeScene";
if (!HasProjectAndLayout()) parameters += ", eventsFunctionContext";
if (context.IsInsideAsync()) parameters += ", asyncObjectsList";
return parameters;
};
/**
* Generate actions code.
*/
@@ -671,7 +591,7 @@ gd::String EventsCodeGenerator::GenerateActionsListCode(
}
gd::String EventsCodeGenerator::GenerateParameterCodes(
const gd::Expression& parameter,
const gd::String& parameter,
const gd::ParameterMetadata& metadata,
gd::EventsCodeGenerationContext& context,
const gd::String& lastObjectName,
@@ -681,21 +601,19 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
if (ParameterMetadata::IsExpression("number", metadata.type)) {
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, "number", parameter, lastObjectName);
*this, context, "number", parameter);
} else if (ParameterMetadata::IsExpression("string", metadata.type)) {
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, "string", parameter, lastObjectName);
*this, context, "string", parameter);
} else if (ParameterMetadata::IsExpression("variable", metadata.type)) {
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
*this, context, metadata.type, parameter, lastObjectName);
} else if (ParameterMetadata::IsObject(metadata.type)) {
// It would be possible to run a gd::ExpressionCodeGenerator if later
// objects can have nested objects, or function returning objects.
argOutput =
GenerateObject(parameter.GetPlainString(), metadata.type, context);
argOutput = GenerateObject(parameter, metadata.type, context);
} else if (metadata.type == "relationalOperator") {
auto parameterString = parameter.GetPlainString();
argOutput += parameterString == "=" ? "==" : parameterString;
argOutput += parameter == "=" ? "==" : parameter;
if (argOutput != "==" && argOutput != "<" && argOutput != ">" &&
argOutput != "<=" && argOutput != ">=" && argOutput != "!=") {
cout << "Warning: Bad relational operator: Set to == by default." << endl;
@@ -704,7 +622,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
argOutput = "\"" + argOutput + "\"";
} else if (metadata.type == "operator") {
argOutput += parameter.GetPlainString();
argOutput += parameter;
if (argOutput != "=" && argOutput != "+" && argOutput != "-" &&
argOutput != "/" && argOutput != "*") {
cout << "Warning: Bad operator: Set to = by default." << endl;
@@ -713,9 +631,9 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
argOutput = "\"" + argOutput + "\"";
} else if (ParameterMetadata::IsBehavior(metadata.type)) {
argOutput = GenerateGetBehaviorNameCode(parameter.GetPlainString());
argOutput = GenerateGetBehaviorNameCode(parameter);
} else if (metadata.type == "key") {
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
argOutput = "\"" + ConvertToString(parameter) + "\"";
} else if (metadata.type == "audioResource" ||
metadata.type == "bitmapFontResource" ||
metadata.type == "fontResource" ||
@@ -725,20 +643,16 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
// Deprecated, old parameter names:
metadata.type == "password" || metadata.type == "musicfile" ||
metadata.type == "soundfile" || metadata.type == "police") {
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
argOutput = "\"" + ConvertToString(parameter) + "\"";
} else if (metadata.type == "mouse") {
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
argOutput = "\"" + ConvertToString(parameter) + "\"";
} else if (metadata.type == "yesorno") {
auto parameterString = parameter.GetPlainString();
argOutput += (parameterString == "yes" || parameterString == "oui")
? GenerateTrue()
: GenerateFalse();
argOutput += (parameter == "yes" || parameter == "oui") ? GenerateTrue()
: GenerateFalse();
} else if (metadata.type == "trueorfalse") {
auto parameterString = parameter.GetPlainString();
// This is duplicated in AdvancedExtension.cpp for GDJS
argOutput += (parameterString == "True" || parameterString == "Vrai")
? GenerateTrue()
: GenerateFalse();
argOutput += (parameter == "True" || parameter == "Vrai") ? GenerateTrue()
: GenerateFalse();
}
// Code only parameter type
else if (metadata.type == "inlineCode") {
@@ -757,7 +671,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
if (!metadata.type.empty())
cout << "Warning: Unknown type of parameter \"" << metadata.type
<< "\"." << std::endl;
argOutput += "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
argOutput += "\"" + ConvertToString(parameter) + "\"";
}
}
@@ -777,7 +691,7 @@ vector<gd::String> EventsCodeGenerator::GenerateParametersCodes(
parametersInfo,
[this, &context, &supplementaryParametersTypes, &arguments](
const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& parameterValue,
const gd::String& lastObjectName) {
gd::String argOutput =
GenerateParameterCodes(parameterValue,
@@ -829,21 +743,23 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
gd::String declarationsCode;
for (auto object : context.GetObjectsListsToBeDeclared()) {
gd::String objectListDeclaration = "";
if (!context.ObjectAlreadyDeclaredByParents(object)) {
if (!context.ObjectAlreadyDeclared(object)) {
objectListDeclaration = "std::vector<RuntimeObject*> " +
GetObjectListName(object, context) +
" = runtimeContext->GetObjectsRawPointers(\"" +
ConvertToString(object) + "\");\n";
context.SetObjectDeclared(object);
} else
objectListDeclaration = declareObjectList(object, context);
declarationsCode += objectListDeclaration + "\n";
}
for (auto object : context.GetObjectsListsToBeEmptyIfJustDeclared()) {
for (auto object : context.GetObjectsListsToBeDeclaredWithoutPicking()) {
gd::String objectListDeclaration = "";
if (!context.ObjectAlreadyDeclaredByParents(object)) {
if (!context.ObjectAlreadyDeclared(object)) {
objectListDeclaration = "std::vector<RuntimeObject*> " +
GetObjectListName(object, context) + ";\n";
context.SetObjectDeclared(object);
} else
objectListDeclaration = declareObjectList(object, context);
@@ -851,9 +767,10 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
}
for (auto object : context.GetObjectsListsToBeDeclaredEmpty()) {
gd::String objectListDeclaration = "";
if (!context.ObjectAlreadyDeclaredByParents(object)) {
if (!context.ObjectAlreadyDeclared(object)) {
objectListDeclaration = "std::vector<RuntimeObject*> " +
GetObjectListName(object, context) + ";\n";
context.SetObjectDeclared(object);
} else
objectListDeclaration = "std::vector<RuntimeObject*> " +
GetObjectListName(object, context) + ";\n";
@@ -868,7 +785,7 @@ gd::String EventsCodeGenerator::GenerateObjectsDeclarationCode(
* Generate events list code.
*/
gd::String EventsCodeGenerator::GenerateEventsListCode(
gd::EventsList& events, EventsCodeGenerationContext& parentContext) {
gd::EventsList& events, const EventsCodeGenerationContext& parentContext) {
gd::String output;
for (std::size_t eId = 0; eId < events.size(); ++eId) {
// Each event has its own context : Objects picked in an event are totally
@@ -884,8 +801,6 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
// operation.
bool reuseParentContext =
parentContext.CanReuse() && eId == events.size() - 1;
// TODO: avoid creating if useless.
gd::EventsCodeGenerationContext reusedContext;
reusedContext.Reuse(parentContext);
@@ -1098,11 +1013,9 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
}
gd::String EventsCodeGenerator::GenerateFreeAction(
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
const gd::String& optionalAsyncCallbackName) {
gd::EventsCodeGenerationContext& context) {
// Generate call
gd::String call;
if (instrInfos.codeExtraInformation.type == "number" ||
@@ -1112,39 +1025,32 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
call = GenerateOperatorCall(
instrInfos,
arguments,
functionCallName,
instrInfos.codeExtraInformation.functionCallName,
instrInfos.codeExtraInformation.optionalAssociatedInstruction);
else if (instrInfos.codeExtraInformation.accessType ==
gd::InstructionMetadata::ExtraInformation::Mutators)
call =
GenerateMutatorCall(instrInfos,
arguments,
functionCallName);
instrInfos.codeExtraInformation.functionCallName);
else
call = GenerateCompoundOperatorCall(
instrInfos,
arguments,
functionCallName);
instrInfos.codeExtraInformation.functionCallName);
} else {
call = functionCallName + "(" +
call = instrInfos.codeExtraInformation.functionCallName + "(" +
GenerateArgumentsList(arguments) + ")";
}
if (!optionalAsyncCallbackName.empty())
call = "runtimeScene.getAsyncTasksManager().addTask(" + call + ", " +
optionalAsyncCallbackName + ")";
return call + ";\n";
}
gd::String EventsCodeGenerator::GenerateObjectAction(
const gd::String& objectName,
const gd::ObjectMetadata& objInfo,
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
const gd::String& optionalAsyncCallbackName) {
gd::EventsCodeGenerationContext& context) {
// Create call
gd::String call;
if ((instrInfos.codeExtraInformation.type == "number" ||
@@ -1154,26 +1060,25 @@ gd::String EventsCodeGenerator::GenerateObjectAction(
call = GenerateOperatorCall(
instrInfos,
arguments,
functionCallName,
instrInfos.codeExtraInformation.functionCallName,
instrInfos.codeExtraInformation.optionalAssociatedInstruction,
2);
else
call = GenerateCompoundOperatorCall(
instrInfos, arguments, functionCallName, 2);
instrInfos,
arguments,
instrInfos.codeExtraInformation.functionCallName,
2);
return "For each picked object \"" + objectName + "\", call " + call +
".\n";
} else {
gd::String argumentsStr = GenerateArgumentsList(arguments, 1);
call = functionCallName + "(" + argumentsStr + ")";
call = instrInfos.codeExtraInformation.functionCallName + "(" +
argumentsStr + ")";
return "For each picked object \"" + objectName + "\", call " + call + "(" +
argumentsStr + ")" +
(optionalAsyncCallbackName.empty()
? ""
: (", then call" + optionalAsyncCallbackName)) +
".\n";
argumentsStr + ").\n";
}
}
@@ -1181,11 +1086,9 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
const gd::String& objectName,
const gd::String& behaviorName,
const gd::BehaviorMetadata& autoInfo,
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
const gd::String& optionalAsyncCallbackName) {
gd::EventsCodeGenerationContext& context) {
// Create call
gd::String call;
if ((instrInfos.codeExtraInformation.type == "number" ||
@@ -1195,29 +1098,24 @@ gd::String EventsCodeGenerator::GenerateBehaviorAction(
call = GenerateOperatorCall(
instrInfos,
arguments,
functionCallName,
instrInfos.codeExtraInformation.functionCallName,
instrInfos.codeExtraInformation.optionalAssociatedInstruction,
2);
else
call = GenerateCompoundOperatorCall(
instrInfos,
arguments,
functionCallName,
instrInfos.codeExtraInformation.functionCallName,
2);
return "For each picked object \"" + objectName + "\", call " + call +
" for behavior \"" + behaviorName + "\".\n";
} else {
gd::String argumentsStr = GenerateArgumentsList(arguments, 2);
call = functionCallName + "(" +
call = instrInfos.codeExtraInformation.functionCallName + "(" +
argumentsStr + ")";
return "For each picked object \"" + objectName + "\", call " + call + "(" +
argumentsStr + ")" + " for behavior \"" + behaviorName + "\"" +
(optionalAsyncCallbackName.empty()
? ""
: (", then call" + optionalAsyncCallbackName)) +
".\n";
argumentsStr + ")" + " for behavior \"" + behaviorName + "\".\n";
}
}
@@ -1265,7 +1163,7 @@ gd::String EventsCodeGenerator::GenerateArgumentsList(
return argumentsStr;
}
EventsCodeGenerator::EventsCodeGenerator(const gd::Project& project_,
EventsCodeGenerator::EventsCodeGenerator(gd::Project& project_,
const gd::Layout& layout,
const gd::Platform& platform_)
: platform(platform_),
@@ -1282,7 +1180,7 @@ EventsCodeGenerator::EventsCodeGenerator(const gd::Project& project_,
EventsCodeGenerator::EventsCodeGenerator(
const gd::Platform& platform_,
const gd::ObjectsContainer& globalObjectsAndGroups_,
gd::ObjectsContainer& globalObjectsAndGroups_,
const gd::ObjectsContainer& objectsAndGroups_)
: platform(platform_),
globalObjectsAndGroups(globalObjectsAndGroups_),

View File

@@ -48,7 +48,7 @@ class GD_CORE_API EventsCodeGenerator {
* \brief Construct a code generator for the specified
* platform/project/layout.
*/
EventsCodeGenerator(const gd::Project& project_,
EventsCodeGenerator(gd::Project& project_,
const gd::Layout& layout,
const gd::Platform& platform_);
@@ -57,7 +57,7 @@ class GD_CORE_API EventsCodeGenerator {
* objects/groups and platform
*/
EventsCodeGenerator(const gd::Platform& platform,
const gd::ObjectsContainer& globalObjectsAndGroups_,
gd::ObjectsContainer& globalObjectsAndGroups_,
const gd::ObjectsContainer& objectsAndGroups_);
virtual ~EventsCodeGenerator(){};
@@ -77,7 +77,7 @@ class GD_CORE_API EventsCodeGenerator {
* \return Code
*/
virtual gd::String GenerateEventsListCode(
gd::EventsList& events, EventsCodeGenerationContext& context);
gd::EventsList& events, const EventsCodeGenerationContext& context);
/**
* \brief Generate code for executing a condition list
@@ -154,54 +154,8 @@ class GD_CORE_API EventsCodeGenerator {
* \param context Context used for generation
* \return Code
*/
gd::String GenerateActionCode(
gd::Instruction& action,
EventsCodeGenerationContext& context,
const gd::String& optionalAsyncCallbackName = "");
struct CallbackDescriptor {
CallbackDescriptor(const gd::String functionName_,
const gd::String argumentsList_,
const std::set<gd::String> requiredObjects_)
: functionName(functionName_),
argumentsList(argumentsList_),
requiredObjects(requiredObjects_){};
/**
* The name by which the function can be invoked.
*/
const gd::String functionName;
/**
* The comma separated list of arguments that the function takes.
*/
const gd::String argumentsList;
/**
* A set of all objects that need to be backed up to be passed to the
* callback code.
*/
const std::set<gd::String> requiredObjects;
};
/**
* \brief Generates actions and events as a callback.
*
* This is used by asynchronous functions to run the code out of the normal
* events flow.
*
* \returns A set with all objects required by the callback code.
* The caller must take care of backing them up in a LongLivedObjectsList,
* and to pass it to the callback function as the last argument.
*/
virtual const CallbackDescriptor GenerateCallback(
const gd::String& callbackFunctionName,
gd::EventsCodeGenerationContext& parentContext,
gd::InstructionsList& actions,
gd::EventsList* subEvents = nullptr);
/**
* \brief Generates the parameters list of an event's generated function.
*/
const gd::String GenerateEventsParameters(
const gd::EventsCodeGenerationContext& context);
gd::String GenerateActionCode(gd::Instruction& action,
EventsCodeGenerationContext& context);
/**
* \brief Generate code for declaring objects lists.
@@ -329,7 +283,7 @@ class GD_CORE_API EventsCodeGenerator {
/**
* \brief Get the global objects/groups used for code generation.
*/
const gd::ObjectsContainer& GetGlobalObjectsAndGroups() const {
gd::ObjectsContainer& GetGlobalObjectsAndGroups() const {
return globalObjectsAndGroups;
}
@@ -350,7 +304,7 @@ class GD_CORE_API EventsCodeGenerator {
* \brief Get the project the code is being generated for.
* \warning This is only valid if HasProjectAndLayout() is true.
*/
const gd::Project& GetProject() const { return *project; }
gd::Project& GetProject() const { return *project; }
/**
* \brief Get the layout the code is being generated for.
@@ -508,18 +462,25 @@ class GD_CORE_API EventsCodeGenerator {
* Other standard parameters type that should be implemented by platforms:
* - currentScene: Reference to the current runtime scene.
* - objectList : a map containing lists of objects which are specified by the
object name in another parameter.
* - objectListOrEmptyIfJustDeclared : Same as `objectList` but do not pick
object if they are not already picked.
* - objectPtr: Return a reference to the object specified by the object name
in another parameter. Example:
object name in another parameter. Example:
* \code
AddExpression("Count", _("Object count"), _("Count the number of picked
objects"), _("Objects"), "res/conditions/nbObjet.png")
.AddParameter("objectList", _("Object"))
.SetFunctionName("getPickedObjectsCount");
* \endcode
* - objectListWithoutPicking : Same as objectList but do not pick object if
they are not already picked.
* - objectPtr : Return a reference to the object specified by the object name in
another parameter. Example:
* \code
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Target object"))
* \endcode
*/
virtual gd::String GenerateParameterCodes(
const gd::Expression& parameter,
const gd::String& parameter,
const gd::ParameterMetadata& metadata,
gd::EventsCodeGenerationContext& context,
const gd::String& lastObjectName,
@@ -702,30 +663,24 @@ class GD_CORE_API EventsCodeGenerator {
gd::EventsCodeGenerationContext& context);
virtual gd::String GenerateFreeAction(
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
const gd::String& optionalAsyncCallbackName = "");
gd::EventsCodeGenerationContext& context);
virtual gd::String GenerateObjectAction(
const gd::String& objectName,
const gd::ObjectMetadata& objInfo,
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
const gd::String& optionalAsyncCallbackName = "");
gd::EventsCodeGenerationContext& context);
virtual gd::String GenerateBehaviorAction(
const gd::String& objectName,
const gd::String& behaviorName,
const gd::BehaviorMetadata& autoInfo,
const gd::String& functionCallName,
const std::vector<gd::String>& arguments,
const gd::InstructionMetadata& instrInfos,
gd::EventsCodeGenerationContext& context,
const gd::String& optionalAsyncCallbackName = "");
gd::EventsCodeGenerationContext& context);
gd::String GenerateRelationalOperatorCall(
const gd::InstructionMetadata& instrInfos,
@@ -775,13 +730,13 @@ class GD_CORE_API EventsCodeGenerator {
const gd::Platform& platform; ///< The platform being used.
const gd::ObjectsContainer& globalObjectsAndGroups;
gd::ObjectsContainer& globalObjectsAndGroups;
const gd::ObjectsContainer& objectsAndGroups;
bool hasProjectAndLayout; ///< true only if project and layout are valid
///< references. If false, they should not be used.
const gd::Project* project; ///< The project being used.
const gd::Layout* scene; ///< The scene being generated.
gd::Project* project; ///< The project being used.
const gd::Layout* scene; ///< The scene being generated.
bool errorOccurred; ///< Must be set to true if an error occured.
bool compilationForRuntime; ///< Is set to true if the code generation is

View File

@@ -25,38 +25,36 @@
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
namespace gd {
gd::String ExpressionCodeGenerator::GenerateExpressionCode(
EventsCodeGenerator& codeGenerator,
EventsCodeGenerationContext& context,
const gd::String& rootType,
const gd::Expression& expression,
const gd::String& rootObjectName) {
ExpressionCodeGenerator generator(rootType, rootObjectName, codeGenerator, context);
const gd::String& type,
const gd::String& expression,
const gd::String& objectName) {
gd::ExpressionParser2 parser(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups());
ExpressionCodeGenerator generator(codeGenerator, context);
auto node = expression.GetRootNode();
auto node = parser.ParseExpression(type, expression, objectName);
if (!node) {
std::cout << "Error: error while parsing: \"" << expression.GetPlainString()
<< "\" (" << rootType << ")" << std::endl;
std::cout << "Error: error while parsing: \"" << expression << "\" ("
<< type << ")" << std::endl;
return generator.GenerateDefaultValue(rootType);
return generator.GenerateDefaultValue(type);
}
gd::ExpressionValidator validator(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType);
gd::ExpressionValidator validator;
node->Visit(validator);
if (!validator.GetErrors().empty()) {
std::cout << "Error: \"" << validator.GetErrors()[0]->GetMessage()
<< "\" in: \"" << expression.GetPlainString() << "\" ("
<< rootType << ")" << std::endl;
<< "\" in: \"" << expression << "\" (" << type << ")"
<< std::endl;
return generator.GenerateDefaultValue(rootType);
return generator.GenerateDefaultValue(type);
}
node->Visit(generator);
@@ -99,24 +97,15 @@ void ExpressionCodeGenerator::OnVisitTextNode(TextNode& node) {
void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
// This "translation" from the type to an enum could be avoided
// if all types were moved to an enum.
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType,
node);
EventsCodeGenerator::VariableScope scope =
type == "globalvar"
node.type == "globalvar"
? gd::EventsCodeGenerator::PROJECT_VARIABLE
: ((type == "scenevar")
: ((node.type == "scenevar")
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootObjectName,
node);
output += codeGenerator.GenerateGetVariable(
node.name, scope, context, objectName);
node.name, scope, context, node.objectName);
if (node.child) node.child->Visit(*this);
}
@@ -128,7 +117,7 @@ void ExpressionCodeGenerator::OnVisitVariableAccessorNode(
void ExpressionCodeGenerator::OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) {
ExpressionCodeGenerator generator("string", "", codeGenerator, context);
ExpressionCodeGenerator generator(codeGenerator, context);
node.expression->Visit(generator);
output +=
codeGenerator.GenerateVariableBracketAccessor(generator.GetOutput());
@@ -136,79 +125,39 @@ void ExpressionCodeGenerator::OnVisitVariableBracketAccessorNode(
}
void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType,
node);
if (gd::ParameterMetadata::IsObject(type)) {
if (gd::ParameterMetadata::IsObject(node.type)) {
output +=
codeGenerator.GenerateObject(node.identifierName, type, context);
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
EventsCodeGenerator::VariableScope scope =
type == "globalvar"
? gd::EventsCodeGenerator::PROJECT_VARIABLE
: ((type == "scenevar")
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootObjectName,
node);
output += codeGenerator.GenerateGetVariable(
node.identifierName, scope, context, objectName);
if (!node.childIdentifierName.empty()) {
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
}
} else if (node.childIdentifierName.empty()) {
codeGenerator.GenerateObject(node.identifierName, node.type, context);
} else {
output += "/* Error during generation, unrecognized identifier type: " +
codeGenerator.ConvertToString(type) + " with value " +
codeGenerator.ConvertToString(node.type) + " with value " +
codeGenerator.ConvertToString(node.identifierName) + " */ " +
codeGenerator.ConvertToStringExplicit(node.identifierName);
}
else {
// This is for function names that are put in IdentifierNode
// because the type is needed to tell them appart from variables.
output += GenerateDefaultValue(type);
}
}
void ExpressionCodeGenerator::OnVisitFunctionCallNode(FunctionCallNode& node) {
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType,
node);
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
node);
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
if (gd::MetadataProvider::IsBadExpressionMetadata(node.expressionMetadata)) {
output += "/* Error during generation, function not found: " +
codeGenerator.ConvertToString(node.functionName) + " */ " +
GenerateDefaultValue(type);
GenerateDefaultValue(node.type);
return;
}
if (!node.objectName.empty()) {
if (!node.behaviorName.empty()) {
output += GenerateBehaviorFunctionCode(type,
output += GenerateBehaviorFunctionCode(node.type,
node.objectName,
node.behaviorName,
node.parameters,
metadata);
node.expressionMetadata);
} else {
output += GenerateObjectFunctionCode(
type, node.objectName, node.parameters, metadata);
node.type, node.objectName, node.parameters, node.expressionMetadata);
}
} else {
output +=
GenerateFreeFunctionCode(node.parameters, metadata);
GenerateFreeFunctionCode(node.parameters, node.expressionMetadata);
}
}
@@ -356,21 +305,18 @@ gd::String ExpressionCodeGenerator::GenerateParametersCodes(
auto& parameterMetadata = expressionMetadata.parameters[i];
if (!parameterMetadata.IsCodeOnly()) {
ExpressionCodeGenerator generator(codeGenerator, context);
if (nonCodeOnlyParameterIndex < parameters.size()) {
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootObjectName,
*parameters[nonCodeOnlyParameterIndex].get());
ExpressionCodeGenerator generator(parameterMetadata.GetType(), objectName, codeGenerator, context);
parameters[nonCodeOnlyParameterIndex]->Visit(generator);
parametersCode += generator.GetOutput();
} else if (parameterMetadata.IsOptional()) {
ExpressionCodeGenerator generator(parameterMetadata.GetType(), "", codeGenerator, context);
// Optional parameters default value were not parsed at the time of the
// expression parsing. Parse them now.
ExpressionParser2 parser;
auto node = parser.ParseExpression(parameterMetadata.GetDefaultValue());
ExpressionParser2 parser(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups());
auto node = parser.ParseExpression(parameterMetadata.GetType(),
parameterMetadata.GetDefaultValue());
node->Visit(generator);
parametersCode += generator.GetOutput();
@@ -428,22 +374,12 @@ gd::String ExpressionCodeGenerator::GenerateDefaultValue(
}
void ExpressionCodeGenerator::OnVisitEmptyNode(EmptyNode& node) {
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType,
node);
output += GenerateDefaultValue(type);
output += GenerateDefaultValue(node.type);
}
void ExpressionCodeGenerator::OnVisitObjectFunctionNameNode(
ObjectFunctionNameNode& node) {
auto type = gd::ExpressionTypeFinder::GetType(codeGenerator.GetPlatform(),
codeGenerator.GetGlobalObjectsAndGroups(),
codeGenerator.GetObjectsAndGroups(),
rootType,
node);
output += GenerateDefaultValue(type);
output += GenerateDefaultValue(node.type);
}
} // namespace gd

View File

@@ -9,6 +9,7 @@
#include <memory>
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/String.h"
@@ -34,11 +35,9 @@ namespace gd {
*/
class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
public:
ExpressionCodeGenerator(const gd::String &rootType_,
const gd::String &rootObjectName_,
EventsCodeGenerator& codeGenerator_,
ExpressionCodeGenerator(EventsCodeGenerator& codeGenerator_,
EventsCodeGenerationContext& context_)
: rootType(rootType_), rootObjectName(rootObjectName_), codeGenerator(codeGenerator_), context(context_){};
: codeGenerator(codeGenerator_), context(context_){};
virtual ~ExpressionCodeGenerator(){};
/**
@@ -58,7 +57,7 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
static gd::String GenerateExpressionCode(EventsCodeGenerator& codeGenerator,
EventsCodeGenerationContext& context,
const gd::String& type,
const gd::Expression& expression,
const gd::String& expression,
const gd::String& objectName = "");
const gd::String& GetOutput() { return output; };
@@ -104,8 +103,6 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
gd::String output;
EventsCodeGenerator& codeGenerator;
EventsCodeGenerationContext& context;
const gd::String rootType;
const gd::String rootObjectName;
};
} // namespace gd

View File

@@ -5,11 +5,8 @@
*/
#include "GDCore/Events/Event.h"
#include "GDCore/Events/Builtin/AsyncEvent.h"
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
@@ -68,41 +65,10 @@ gd::String BaseEvent::GenerateEventCode(
return "";
}
void BaseEvent::PreprocessAsyncActions(const gd::Platform& platform) {
if (!CanHaveSubEvents()) return;
for (const auto& actionsList : GetAllActionsVectors())
for (std::size_t aId = 0; aId < actionsList->size(); ++aId) {
const auto& action = actionsList->at(aId);
const gd::InstructionMetadata& actionMetadata =
gd::MetadataProvider::GetActionMetadata(platform, action.GetType());
if (actionMetadata.IsAsync() &&
(!actionMetadata.IsOptionallyAsync() || action.IsAwaited())) {
gd::InstructionsList remainingActions;
remainingActions.InsertInstructions(
*actionsList, aId + 1, actionsList->size() - 1);
gd::AsyncEvent asyncEvent(action, remainingActions, GetSubEvents());
// Ensure that the local event no longer has any of the actions/subevent
// after the async function
actionsList->RemoveAfter(aId);
GetSubEvents().Clear();
GetSubEvents().InsertEvent(asyncEvent);
// We just moved all the rest, there's nothing left to do in this event.
return;
}
}
};
void BaseEvent::Preprocess(gd::EventsCodeGenerator& codeGenerator,
gd::EventsList& eventList,
std::size_t indexOfTheEventInThisList) {
if (IsDisabled()) return;
PreprocessAsyncActions(codeGenerator.GetPlatform());
if (!MustBePreprocessed()) return;
if (IsDisabled() || !MustBePreprocessed()) return;
try {
if (type.empty()) return;

View File

@@ -10,7 +10,6 @@
#include <iostream>
#include <memory>
#include <vector>
#include "GDCore/Events/Instruction.h"
#include "GDCore/Events/InstructionsList.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
@@ -24,7 +23,7 @@ class EventsCodeGenerationContext;
class Platform;
class SerializerElement;
class Instruction;
} // namespace gd
}
namespace gd {
@@ -137,15 +136,13 @@ class GD_CORE_API BaseEvent {
* \note Used to preprocess or search in the expressions of the event.
*/
virtual std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() {
GetAllExpressionsWithMetadata() {
std::vector<std::pair<gd::Expression*, gd::ParameterMetadata> > noExpr;
return noExpr;
};
virtual std::vector<
std::pair<const gd::Expression*, const gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() const {
std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
noExpr;
virtual std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> >
GetAllExpressionsWithMetadata() const {
std::vector<std::pair<const gd::Expression*, const gd::ParameterMetadata> > noExpr;
return noExpr;
};
@@ -209,11 +206,6 @@ class GD_CORE_API BaseEvent {
gd::EventsList& eventList,
std::size_t indexOfTheEventInThisList);
/**
* A function that turns all async member actions into an Async subevent for code generation.
*/
void PreprocessAsyncActions(const gd::Platform& platform);
/**
* \brief If MustBePreprocessed is redefined to return true, the
* gd::EventMetadata::preprocessing associated to the event will be called to

View File

@@ -1,41 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Events/Expression.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/String.h"
namespace gd {
Expression::Expression() : node(nullptr) {};
Expression::Expression(gd::String plainString_)
: node(nullptr), plainString(plainString_) {};
Expression::Expression(const char* plainString_)
: node(nullptr), plainString(plainString_) {};
Expression::Expression(const Expression& copy)
: node(nullptr), plainString{copy.plainString} {};
Expression& Expression::operator=(const Expression& expression) {
plainString = expression.plainString;
node = nullptr;
return *this;
};
Expression::~Expression(){};
ExpressionNode* Expression::GetRootNode() const {
if (!node) {
gd::ExpressionParser2 parser = ExpressionParser2();
node = std::move(parser.ParseExpression(plainString));
}
return node.get();
}
} // namespace gd

View File

@@ -6,15 +6,7 @@
#ifndef GDCORE_EXPRESSION_H
#define GDCORE_EXPRESSION_H
#include "GDCore/String.h"
#include <memory>
namespace gd {
class ExpressionParser2;
class ObjectsContainer;
struct ExpressionNode;
} // namespace gd
namespace gd {
@@ -32,49 +24,32 @@ class GD_CORE_API Expression {
/**
* \brief Construct an empty expression
*/
Expression();
Expression(){};
/**
* \brief Construct an expression from a string
*/
Expression(gd::String plainString_);
Expression(gd::String plainString_) : plainString(plainString_){};
/**
* \brief Construct an expression from a const char *
*/
Expression(const char* plainString_);
/**
* \brief Copy construct an expression.
*/
Expression(const Expression& copy);
/**
* \brief Expression affectation overriding.
*/
Expression& operator=(const Expression& expression);
Expression(const char* plainString_) : plainString(plainString_){};
/**
* \brief Get the plain string representing the expression
*/
inline const gd::String& GetPlainString() const { return plainString; };
/**
* @brief Get the expression node.
* @return std::unique_ptr<gd::ExpressionNode>
*/
gd::ExpressionNode* GetRootNode() const;
/**
* \brief Mimics std::string::c_str
*/
inline const char* c_str() const { return plainString.c_str(); };
virtual ~Expression();
virtual ~Expression(){};
private:
gd::String plainString; ///< The expression string
mutable std::unique_ptr<gd::ExpressionNode> node;
};
} // namespace gd

View File

@@ -72,22 +72,6 @@ class GD_CORE_API Instruction {
*/
void SetInverted(bool inverted_) { inverted = inverted_; }
/**
* \brief Return true if the async instruction should be awaited.
* This is not relevant if the instruction is not optionally asynchronous.
*
* \return true if the instruction is to be awaited
*/
bool IsAwaited() const { return awaitAsync; }
/**
* \brief Set if the async instruction is to be awaited or not.
* This is not relevant if the instruction is not optionally asynchronous.
*
* \param inverted true if the instruction must be awaited
*/
void SetAwaited(bool awaited) { awaitAsync = awaited; }
/**
* \brief Return the number of parameters of the instruction.
*/
@@ -155,9 +139,7 @@ class GD_CORE_API Instruction {
* Useful to get reference to the original instruction in memory during code
* generation, to ensure stable unique identifiers.
*/
std::weak_ptr<Instruction> GetOriginalInstruction() {
return originalInstruction;
};
std::weak_ptr<Instruction> GetOriginalInstruction() { return originalInstruction; };
friend std::shared_ptr<Instruction> CloneRememberingOriginalElement(
std::shared_ptr<Instruction> instruction);
@@ -166,9 +148,6 @@ class GD_CORE_API Instruction {
gd::String type; ///< Instruction type
bool inverted; ///< True if the instruction if inverted. Only applicable for
///< instruction used as conditions by events
bool awaitAsync =
false; ///< Tells the code generator whether the optionally asynchronous
///< instruction should be generated as asynchronous (awaited) or not.
mutable std::vector<gd::Expression>
parameters; ///< Vector containing the parameters
gd::InstructionsList subInstructions; ///< Sub instructions, if applicable.

View File

@@ -5,7 +5,6 @@
*/
#include "InstructionsList.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Project/Project.h"
#include "Serialization.h"
@@ -32,10 +31,6 @@ void InstructionsList::InsertInstructions(const InstructionsList& list,
}
}
void InstructionsList::RemoveAfter(const size_t position) {
elements.resize(position);
}
void InstructionsList::SerializeTo(SerializerElement& element) const {
EventsListSerialization::SerializeInstructionsTo(*this, element);
}

View File

@@ -6,10 +6,9 @@
#ifndef GDCORE_INSTRUCTIONSLIST_H
#define GDCORE_INSTRUCTIONSLIST_H
#include "GDCore/Tools/SPtrList.h"
#include <memory>
#include <vector>
#include "GDCore/Tools/SPtrList.h"
namespace gd {
class Instruction;
}
@@ -23,11 +22,11 @@ class SerializerElement;
namespace gd {
class InstructionsList : public SPtrList<gd::Instruction> {
public:
void InsertInstructions(const InstructionsList &list, size_t begin,
size_t end, size_t position = (size_t)-1);
void RemoveAfter(size_t position);
public:
void InsertInstructions(const InstructionsList& list,
size_t begin,
size_t end,
size_t position = (size_t)-1);
/** \name Serialization
*/
@@ -36,17 +35,17 @@ public:
* \brief Serialize the instructions to the specified element
* \see EventsListSerialization
*/
void SerializeTo(gd::SerializerElement &element) const;
void SerializeTo(gd::SerializerElement& element) const;
/**
* \brief Load the instructions from the specified element
* \see EventsListSerialization
*/
void UnserializeFrom(gd::Project &project,
const gd::SerializerElement &element);
void UnserializeFrom(gd::Project& project,
const gd::SerializerElement& element);
///@}
};
} // namespace gd
} // namespace gd
#endif

View File

@@ -26,16 +26,132 @@ namespace gd {
gd::String ExpressionParser2::NAMESPACE_SEPARATOR = "::";
ExpressionParser2::ExpressionParser2()
ExpressionParser2::ExpressionParser2(
const gd::Platform& platform_,
const gd::ObjectsContainer& globalObjectsContainer_,
const gd::ObjectsContainer& objectsContainer_)
: expression(""),
currentPosition(0) {}
currentPosition(0),
platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_) {}
namespace {
/**
* Return the minimum number of parameters, starting from a given parameter
* (by convention, 1 for object functions and 2 for behavior functions).
*/
size_t GetMinimumParametersNumber(
const std::vector<gd::ParameterMetadata>& parameters,
size_t initialParameterIndex) {
size_t nb = 0;
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
if (!parameters[i].optional && !parameters[i].codeOnly) nb++;
}
return nb;
}
/**
* Return the maximum number of parameters, starting from a given parameter
* (by convention, 1 for object functions and 2 for behavior functions).
*/
size_t GetMaximumParametersNumber(
const std::vector<gd::ParameterMetadata>& parameters,
size_t initialParameterIndex) {
size_t nb = 0;
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
if (!parameters[i].codeOnly) nb++;
}
return nb;
}
} // namespace
std::unique_ptr<ExpressionParserDiagnostic> ExpressionParser2::ValidateFunction(
const gd::String& type,
const gd::FunctionCallNode& function,
size_t functionStartPosition) {
if (gd::MetadataProvider::IsBadExpressionMetadata(
function.expressionMetadata)) {
return gd::make_unique<ExpressionParserError>(
"invalid_function_name",
_("Cannot find an expression with this name: ") +
function.functionName + "\n" +
_("Double check that you've not made any typo in the name."),
functionStartPosition,
GetCurrentPosition());
}
// Validate the type of the function
const gd::String& returnType = function.expressionMetadata.GetReturnType();
if (returnType == "number") {
if (type == "string")
return RaiseTypeError(
_("You tried to use an expression that returns a number, but a "
"string is expected. Use `ToString` if you need to convert a "
"number to a string."),
functionStartPosition);
else if (type != "number" && type != "number|string")
return RaiseTypeError(_("You tried to use an expression that returns a "
"number, but another type is expected:") +
" " + type,
functionStartPosition);
} else if (returnType == "string") {
if (type == "number")
return RaiseTypeError(
_("You tried to use an expression that returns a string, but a "
"number is expected. Use `ToNumber` if you need to convert a "
"string to a number."),
functionStartPosition);
else if (type != "string" && type != "number|string")
return RaiseTypeError(_("You tried to use an expression that returns a "
"string, but another type is expected:") +
" " + type,
functionStartPosition);
} else {
if (type != returnType)
return RaiseTypeError(
_("You tried to use an expression with the wrong return type:") + " " +
returnType,
functionStartPosition);
}
// Validate parameters count
size_t minParametersCount = GetMinimumParametersNumber(
function.expressionMetadata.parameters,
WrittenParametersFirstIndex(function.objectName, function.behaviorName));
size_t maxParametersCount = GetMaximumParametersNumber(
function.expressionMetadata.parameters,
WrittenParametersFirstIndex(function.objectName, function.behaviorName));
if (function.parameters.size() < minParametersCount ||
function.parameters.size() > maxParametersCount) {
gd::String expectedCountMessage =
minParametersCount == maxParametersCount
? _("The number of parameters must be exactly ") +
gd::String::From(minParametersCount)
: _("The number of parameters must be: ") +
gd::String::From(minParametersCount) + "-" +
gd::String::From(maxParametersCount);
if (function.parameters.size() < minParametersCount) {
return gd::make_unique<ExpressionParserError>(
"too_few_parameters",
"You have not entered enough parameters for the expression. " +
expectedCountMessage,
functionStartPosition,
GetCurrentPosition());
}
}
return gd::make_unique<ExpressionParserDiagnostic>();
}
std::unique_ptr<TextNode> ExpressionParser2::ReadText() {
size_t textStartPosition = GetCurrentPosition();
SkipAllWhitespaces();
if (!CheckIfChar(IsQuote)) {
auto text = gd::make_unique<TextNode>("");
// It can't happen.
text->diagnostic =
RaiseSyntaxError(_("A text must start with a double quote (\")."));
text->location =

View File

@@ -40,7 +40,9 @@ namespace gd {
*/
class GD_CORE_API ExpressionParser2 {
public:
ExpressionParser2();
ExpressionParser2(const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_);
virtual ~ExpressionParser2(){};
/**
@@ -56,11 +58,13 @@ class GD_CORE_API ExpressionParser2 {
* \return The node representing the expression as a parsed tree.
*/
std::unique_ptr<ExpressionNode> ParseExpression(
const gd::String &expression_) {
const gd::String &type,
const gd::String &expression_,
const gd::String &objectName = "") {
expression = expression_;
currentPosition = 0;
return Start();
return Start(type, objectName);
}
/**
@@ -84,16 +88,18 @@ class GD_CORE_API ExpressionParser2 {
* Each method is a part of the grammar.
*/
///@{
std::unique_ptr<ExpressionNode> Start() {
std::unique_ptr<ExpressionNode> Start(const gd::String &type,
const gd::String &objectName = "") {
size_t expressionStartPosition = GetCurrentPosition();
auto expression = Expression();
auto expression = Expression(type, objectName);
const gd::String &inferredType = expression->type;
// Check for extra characters at the end of the expression
if (!IsEndReached()) {
auto op = gd::make_unique<OperatorNode>(' ');
auto op = gd::make_unique<OperatorNode>(inferredType, ' ');
op->leftHandSide = std::move(expression);
op->rightHandSide = ReadUntilEnd();
op->rightHandSide->parent = op.get();
op->rightHandSide = ReadUntilEnd("unknown");
op->rightHandSide->diagnostic = RaiseSyntaxError(
_("The expression has extra character at the end that should be "
@@ -107,49 +113,61 @@ class GD_CORE_API ExpressionParser2 {
return expression;
}
std::unique_ptr<ExpressionNode> Expression() {
std::unique_ptr<ExpressionNode> Expression(
const gd::String &type, const gd::String &objectName = "") {
SkipAllWhitespaces();
size_t expressionStartPosition = GetCurrentPosition();
std::unique_ptr<ExpressionNode> leftHandSide = Term();
std::unique_ptr<ExpressionNode> leftHandSide = Term(type, objectName);
const gd::String &inferredType = leftHandSide->type;
SkipAllWhitespaces();
if (IsEndReached()) return leftHandSide;
if (CheckIfChar(IsExpressionEndingChar)) return leftHandSide;
if (CheckIfChar(IsExpressionOperator)) {
auto op = gd::make_unique<OperatorNode>(GetCurrentChar());
auto op = gd::make_unique<OperatorNode>(inferredType, GetCurrentChar());
op->leftHandSide = std::move(leftHandSide);
op->leftHandSide->parent = op.get();
op->diagnostic = ValidateOperator(GetCurrentChar());
op->diagnostic = ValidateOperator(inferredType, GetCurrentChar());
SkipChar();
op->rightHandSide = Expression();
op->rightHandSide->parent = op.get();
op->rightHandSide = Expression(inferredType, objectName);
op->location = ExpressionParserLocation(expressionStartPosition,
GetCurrentPosition());
return std::move(op);
}
leftHandSide->diagnostic = RaiseSyntaxError(
"More than one term was found. Verify that your expression is "
"properly written.");
if (inferredType == "string") {
leftHandSide->diagnostic = RaiseSyntaxError(
"You must add the operator + between texts or expressions. For "
"example: \"Your name: \" + VariableString(PlayerName).");
} else if (inferredType == "number") {
leftHandSide->diagnostic = RaiseSyntaxError(
"No operator found. Did you forget to enter an operator (like +, -, "
"* or /) between numbers or expressions?");
} else {
leftHandSide->diagnostic = RaiseSyntaxError(
"More than one term was found. Verify that your expression is "
"properly written.");
}
auto op = gd::make_unique<OperatorNode>(' ');
auto op = gd::make_unique<OperatorNode>(inferredType, ' ');
op->leftHandSide = std::move(leftHandSide);
op->leftHandSide->parent = op.get();
op->rightHandSide = Expression();
op->rightHandSide->parent = op.get();
op->rightHandSide = Expression(inferredType, objectName);
op->location =
ExpressionParserLocation(expressionStartPosition, GetCurrentPosition());
return std::move(op);
}
std::unique_ptr<ExpressionNode> Term() {
std::unique_ptr<ExpressionNode> Term(const gd::String &type,
const gd::String &objectName) {
SkipAllWhitespaces();
size_t expressionStartPosition = GetCurrentPosition();
std::unique_ptr<ExpressionNode> factor = Factor();
std::unique_ptr<ExpressionNode> factor = Factor(type, objectName);
const gd::String &inferredType = factor->type;
SkipAllWhitespaces();
@@ -157,13 +175,11 @@ class GD_CORE_API ExpressionParser2 {
// to guarantee the proper operator precedence. (Expression could also
// be reworked to use a while loop).
while (CheckIfChar(IsTermOperator)) {
auto op = gd::make_unique<OperatorNode>(GetCurrentChar());
auto op = gd::make_unique<OperatorNode>(inferredType, GetCurrentChar());
op->leftHandSide = std::move(factor);
op->leftHandSide->parent = op.get();
op->diagnostic = ValidateOperator(GetCurrentChar());
op->diagnostic = ValidateOperator(inferredType, GetCurrentChar());
SkipChar();
op->rightHandSide = Factor();
op->rightHandSide->parent = op.get();
op->rightHandSide = Factor(inferredType, objectName);
op->location = ExpressionParserLocation(expressionStartPosition,
GetCurrentPosition());
SkipAllWhitespaces();
@@ -174,35 +190,54 @@ class GD_CORE_API ExpressionParser2 {
return factor;
};
std::unique_ptr<ExpressionNode> Factor() {
std::unique_ptr<ExpressionNode> Factor(const gd::String &type,
const gd::String &objectName) {
SkipAllWhitespaces();
size_t expressionStartPosition = GetCurrentPosition();
if (CheckIfChar(IsQuote)) {
std::unique_ptr<ExpressionNode> factor = ReadText();
if (type == "number")
factor->diagnostic =
RaiseTypeError(_("You entered a text, but a number was expected."),
expressionStartPosition);
else if (type != "string" && type != "number|string")
factor->diagnostic = RaiseTypeError(
_("You entered a text, but this type was expected:") + type,
expressionStartPosition);
return factor;
} else if (CheckIfChar(IsUnaryOperator)) {
auto unaryOperatorCharacter = GetCurrentChar();
SkipChar();
auto operatorOperand = Factor();
auto operatorOperand = Factor(type, objectName);
const gd::String &inferredType = operatorOperand->type;
auto unaryOperator = gd::make_unique<UnaryOperatorNode>(
unaryOperatorCharacter);
inferredType, unaryOperatorCharacter);
unaryOperator->diagnostic = ValidateUnaryOperator(
unaryOperatorCharacter, expressionStartPosition);
inferredType, unaryOperatorCharacter, expressionStartPosition);
unaryOperator->factor = std::move(operatorOperand);
unaryOperator->factor->parent = unaryOperator.get();
unaryOperator->location = ExpressionParserLocation(
expressionStartPosition, GetCurrentPosition());
return std::move(unaryOperator);
} else if (CheckIfChar(IsNumberFirstChar)) {
std::unique_ptr<ExpressionNode> factor = ReadNumber();
if (type == "string")
factor->diagnostic = RaiseTypeError(
_("You entered a number, but a text was expected (in quotes)."),
expressionStartPosition);
else if (type != "number" && type != "number|string")
factor->diagnostic = RaiseTypeError(
_("You entered a number, but this type was expected:") + type,
expressionStartPosition);
return factor;
} else if (CheckIfChar(IsOpeningParenthesis)) {
SkipChar();
std::unique_ptr<ExpressionNode> factor = SubExpression();
std::unique_ptr<ExpressionNode> factor = SubExpression(type, objectName);
if (!CheckIfChar(IsClosingParenthesis)) {
factor->diagnostic =
@@ -212,20 +247,29 @@ class GD_CORE_API ExpressionParser2 {
SkipIfChar(IsClosingParenthesis);
return factor;
} else if (IsIdentifierAllowedChar()) {
return Identifier();
// This is a place where the grammar differs according to the
// type being expected.
if (gd::ParameterMetadata::IsExpression("variable", type)) {
return Variable(type, objectName);
} else {
return Identifier(type);
}
}
std::unique_ptr<ExpressionNode> factor = ReadUntilWhitespace();
std::unique_ptr<ExpressionNode> factor = ReadUntilWhitespace(type);
factor->diagnostic = RaiseEmptyError(type, expressionStartPosition);
return factor;
}
std::unique_ptr<SubExpressionNode> SubExpression() {
std::unique_ptr<SubExpressionNode> SubExpression(
const gd::String &type, const gd::String &objectName) {
size_t expressionStartPosition = GetCurrentPosition();
auto expression = Expression();
auto expression = Expression(type, objectName);
const gd::String &inferredType = expression->type;
auto subExpression =
gd::make_unique<SubExpressionNode>(std::move(expression));
gd::make_unique<SubExpressionNode>(inferredType, std::move(expression));
subExpression->location =
ExpressionParserLocation(expressionStartPosition, GetCurrentPosition());
@@ -233,7 +277,7 @@ class GD_CORE_API ExpressionParser2 {
};
std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
Identifier() {
Identifier(const gd::String &type) {
auto identifierAndLocation = ReadIdentifierName();
gd::String name = identifierAndLocation.name;
auto nameLocation = identifierAndLocation.location;
@@ -260,28 +304,47 @@ class GD_CORE_API ExpressionParser2 {
if (CheckIfChar(IsOpeningParenthesis)) {
ExpressionParserLocation openingParenthesisLocation = SkipChar();
return FreeFunction(name, nameLocation, openingParenthesisLocation);
return FreeFunction(type, name, nameLocation, openingParenthesisLocation);
} else if (CheckIfChar(IsDot)) {
ExpressionParserLocation dotLocation = SkipChar();
SkipAllWhitespaces();
return ObjectFunctionOrBehaviorFunction(
name, nameLocation, dotLocation);
} else if (CheckIfChar(IsOpeningSquareBracket)) {
return Variable(name, nameLocation);
}
else {
auto identifier = gd::make_unique<IdentifierNode>(name);
type, name, nameLocation, dotLocation);
} else {
auto identifier = gd::make_unique<IdentifierNode>(name, type);
if (type == "string") {
identifier->diagnostic =
RaiseTypeError(_("You must wrap your text inside double quotes "
"(example: \"Hello world\")."),
nameLocation.GetStartPosition());
} else if (type == "number") {
identifier->diagnostic = RaiseTypeError(
_("You must enter a number."), nameLocation.GetStartPosition());
} else if (type == "number|string") {
identifier->diagnostic = RaiseTypeError(
_("You must enter a number or a text, wrapped inside double quotes "
"(example: \"Hello world\")."),
nameLocation.GetStartPosition());
} else if (!gd::ParameterMetadata::IsObject(type)) {
identifier->diagnostic = RaiseTypeError(
_("You've entered a name, but this type was expected:") + type,
nameLocation.GetStartPosition());
}
identifier->location = ExpressionParserLocation(
nameLocation.GetStartPosition(), GetCurrentPosition());
identifier->identifierNameLocation = identifier->location;
return std::move(identifier);
}
}
std::unique_ptr<VariableNode> Variable(const gd::String &name, gd::ExpressionParserLocation nameLocation) {
auto variable = gd::make_unique<VariableNode>(name);
std::unique_ptr<VariableNode> Variable(const gd::String &type,
const gd::String &objectName) {
auto identifierAndLocation = ReadIdentifierName();
const gd::String &name = identifierAndLocation.name;
const auto &nameLocation = identifierAndLocation.location;
auto variable = gd::make_unique<VariableNode>(type, name, objectName);
variable->child = VariableAccessorOrVariableBracketAccessor();
variable->child->parent = variable.get();
variable->location = ExpressionParserLocation(
nameLocation.GetStartPosition(), GetCurrentPosition());
@@ -296,8 +359,8 @@ class GD_CORE_API ExpressionParser2 {
SkipAllWhitespaces();
if (CheckIfChar(IsOpeningSquareBracket)) {
SkipChar();
auto child = gd::make_unique<VariableBracketAccessorNode>(Expression());
child->expression->parent = child.get();
auto child = gd::make_unique<VariableBracketAccessorNode>(
Expression("number|string"));
if (!CheckIfChar(IsClosingSquareBracket)) {
child->diagnostic =
@@ -306,7 +369,6 @@ class GD_CORE_API ExpressionParser2 {
}
SkipIfChar(IsClosingSquareBracket);
child->child = VariableAccessorOrVariableBracketAccessor();
child->child->parent = child.get();
child->location =
ExpressionParserLocation(childStartPosition, GetCurrentPosition());
@@ -319,7 +381,6 @@ class GD_CORE_API ExpressionParser2 {
auto child =
gd::make_unique<VariableAccessorNode>(identifierAndLocation.name);
child->child = VariableAccessorOrVariableBracketAccessor();
child->child->parent = child.get();
child->nameLocation = identifierAndLocation.location;
child->dotLocation = dotLocation;
child->location =
@@ -328,21 +389,40 @@ class GD_CORE_API ExpressionParser2 {
return std::move(child);
}
return std::move(gd::make_unique<VariableAccessorOrVariableBracketAccessorNode>());
return std::move(
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>());
}
std::unique_ptr<FunctionCallNode> FreeFunction(
const gd::String &type,
const gd::String &functionFullName,
const ExpressionParserLocation &identifierLocation,
const ExpressionParserLocation &openingParenthesisLocation) {
// TODO: error if trying to use function for type != "number" && != "string"
// + Test for it
const gd::ExpressionMetadata &metadata =
MetadataProvider::GetAnyExpressionMetadata(platform, functionFullName);
// In case we can't find a valid expression, ensure the node has the type
// that is requested by the parent, so we avoid putting "unknown" (which
// would be also correct, but less precise and would prevent completions to
// be shown to the user)
const gd::String returnType =
gd::MetadataProvider::IsBadExpressionMetadata(metadata) == true
? type
: metadata.GetReturnType();
auto parametersNode = Parameters(metadata.parameters);
auto function =
gd::make_unique<FunctionCallNode>(functionFullName);
auto parametersNode = Parameters(function.get());
function->parameters = std::move(parametersNode.parameters);
gd::make_unique<FunctionCallNode>(returnType,
std::move(parametersNode.parameters),
metadata,
functionFullName);
function->diagnostic = std::move(parametersNode.diagnostic);
if (!function->diagnostic) // TODO: reverse the order of diagnostic?
function->diagnostic = ValidateFunction(
type, *function, identifierLocation.GetStartPosition());
function->location = ExpressionParserLocation(
identifierLocation.GetStartPosition(), GetCurrentPosition());
@@ -354,15 +434,16 @@ class GD_CORE_API ExpressionParser2 {
return std::move(function);
}
std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode>
ObjectFunctionOrBehaviorFunction(
const gd::String &parentIdentifier,
const ExpressionParserLocation &parentIdentifierLocation,
const ExpressionParserLocation &parentIdentifierDotLocation) {
auto childIdentifierAndLocation = ReadIdentifierName();
const gd::String &childIdentifierName = childIdentifierAndLocation.name;
const auto &childIdentifierNameLocation =
childIdentifierAndLocation.location;
const gd::String &type,
const gd::String &objectName,
const ExpressionParserLocation &objectNameLocation,
const ExpressionParserLocation &objectNameDotLocation) {
auto identifierAndLocation = ReadIdentifierName();
const gd::String &objectFunctionOrBehaviorName = identifierAndLocation.name;
const auto &objectFunctionOrBehaviorNameLocation =
identifierAndLocation.location;
SkipAllWhitespaces();
@@ -370,68 +451,87 @@ class GD_CORE_API ExpressionParser2 {
ExpressionParserLocation namespaceSeparatorLocation =
SkipNamespaceSeparator();
SkipAllWhitespaces();
return BehaviorFunction(parentIdentifier,
childIdentifierName,
parentIdentifierLocation,
parentIdentifierDotLocation,
childIdentifierNameLocation,
return BehaviorFunction(type,
objectName,
objectFunctionOrBehaviorName,
objectNameLocation,
objectNameDotLocation,
objectFunctionOrBehaviorNameLocation,
namespaceSeparatorLocation);
} else if (CheckIfChar(IsOpeningParenthesis)) {
ExpressionParserLocation openingParenthesisLocation = SkipChar();
gd::String objectType =
GetTypeOfObject(globalObjectsContainer, objectsContainer, objectName);
const gd::ExpressionMetadata &metadata =
MetadataProvider::GetObjectAnyExpressionMetadata(
platform, objectType, objectFunctionOrBehaviorName);
// In case we can't find a valid expression, ensure the node has the type
// that is requested by the parent, so we avoid putting "unknown" (which
// would be also correct, but less precise and would prevent completions
// to be shown to the user)
const gd::String returnType =
gd::MetadataProvider::IsBadExpressionMetadata(metadata) == true
? type
: metadata.GetReturnType();
auto parametersNode = Parameters(metadata.parameters, objectName);
auto function = gd::make_unique<FunctionCallNode>(
parentIdentifier,
childIdentifierName);
auto parametersNode = Parameters(function.get(), parentIdentifier);
function->parameters = std::move(parametersNode.parameters),
returnType,
objectName,
std::move(parametersNode.parameters),
metadata,
objectFunctionOrBehaviorName);
function->diagnostic = std::move(parametersNode.diagnostic);
if (!function->diagnostic) // TODO: reverse the order of diagnostic?
function->diagnostic = ValidateFunction(
type, *function, objectNameLocation.GetStartPosition());
// If the function needs a capability on the object that may not be covered
// by all objects, check it now.
if (!metadata.GetRequiredBaseObjectCapability().empty()) {
const gd::ObjectMetadata &objectMetadata =
MetadataProvider::GetObjectMetadata(platform, objectType);
if (objectMetadata.IsUnsupportedBaseObjectCapability(
metadata.GetRequiredBaseObjectCapability())) {
function->diagnostic = RaiseTypeError(
_("This expression exists, but it can't be used on this object."),
objectNameLocation.GetStartPosition());
}
}
function->location = ExpressionParserLocation(
parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
function->objectNameLocation = parentIdentifierLocation;
function->objectNameDotLocation = parentIdentifierDotLocation;
function->functionNameLocation = childIdentifierNameLocation;
objectNameLocation.GetStartPosition(), GetCurrentPosition());
function->objectNameLocation = objectNameLocation;
function->objectNameDotLocation = objectNameDotLocation;
function->functionNameLocation = objectFunctionOrBehaviorNameLocation;
function->openingParenthesisLocation = openingParenthesisLocation;
function->closingParenthesisLocation =
parametersNode.closingParenthesisLocation;
return std::move(function);
} else if (CheckIfChar(IsDot) || CheckIfChar(IsOpeningSquareBracket)) {
auto variable = gd::make_unique<VariableNode>(parentIdentifier);
auto child =
gd::make_unique<VariableAccessorNode>(childIdentifierName);
child->child = VariableAccessorOrVariableBracketAccessor();
child->child->parent = child.get();
child->nameLocation = childIdentifierNameLocation;
child->dotLocation = parentIdentifierDotLocation;
child->location = ExpressionParserLocation(
parentIdentifierDotLocation.GetStartPosition(), GetCurrentPosition());
variable->child = std::move(child);
variable->child->parent = variable.get();
variable->location = ExpressionParserLocation(
parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
variable->nameLocation = parentIdentifierLocation;
return std::move(variable);
}
auto node = gd::make_unique<IdentifierNode>(
parentIdentifier, childIdentifierName);
if (!CheckIfChar(IsParameterSeparator) && !CheckIfChar(IsClosingParenthesis) && !IsEndReached()) {
node->diagnostic = RaiseSyntaxError(
_("An opening parenthesis (for an object expression), a double colon "
"(:: for a behavior expression), a dot or an opening bracket (for "
"a child variable) where expected."));
}
auto node = gd::make_unique<ObjectFunctionNameNode>(
type, objectName, objectFunctionOrBehaviorName);
node->diagnostic = RaiseSyntaxError(
_("An opening parenthesis (for an object expression), or double colon "
"(::) was expected (for a behavior expression)."));
node->location = ExpressionParserLocation(
parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
node->identifierNameLocation = parentIdentifierLocation;
node->identifierNameDotLocation = parentIdentifierDotLocation;
node->childIdentifierNameLocation = childIdentifierNameLocation;
objectNameLocation.GetStartPosition(), GetCurrentPosition());
node->objectNameLocation = objectNameLocation;
node->objectNameDotLocation = objectNameDotLocation;
node->objectFunctionOrBehaviorNameLocation =
objectFunctionOrBehaviorNameLocation;
return std::move(node);
}
std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode> BehaviorFunction(
const gd::String &type,
const gd::String &objectName,
const gd::String &behaviorName,
const ExpressionParserLocation &objectNameLocation,
@@ -447,14 +547,35 @@ class GD_CORE_API ExpressionParser2 {
if (CheckIfChar(IsOpeningParenthesis)) {
ExpressionParserLocation openingParenthesisLocation = SkipChar();
gd::String behaviorType = GetTypeOfBehavior(
globalObjectsContainer, objectsContainer, behaviorName);
const gd::ExpressionMetadata &metadata =
MetadataProvider::GetBehaviorAnyExpressionMetadata(
platform, behaviorType, functionName);
// In case we can't find a valid expression, ensure the node has the type
// that is requested by the parent, so we avoid putting "unknown" (which
// would be also correct, but less precise and would prevent completions
// to be shown to the user)
const gd::String returnType =
gd::MetadataProvider::IsBadExpressionMetadata(metadata) == true
? type
: metadata.GetReturnType();
auto parametersNode =
Parameters(metadata.parameters, objectName, behaviorName);
auto function = gd::make_unique<FunctionCallNode>(
returnType,
objectName,
behaviorName,
std::move(parametersNode.parameters),
metadata,
functionName);
auto parametersNode =
Parameters(function.get(), objectName, behaviorName);
function->parameters = std::move(parametersNode.parameters);
function->diagnostic = std::move(parametersNode.diagnostic);
if (!function->diagnostic) // TODO: reverse the order of diagnostic?
function->diagnostic = ValidateFunction(
type, *function, objectNameLocation.GetStartPosition());
function->location = ExpressionParserLocation(
objectNameLocation.GetStartPosition(), GetCurrentPosition());
@@ -470,7 +591,7 @@ class GD_CORE_API ExpressionParser2 {
return std::move(function);
} else {
auto node = gd::make_unique<ObjectFunctionNameNode>(
objectName, behaviorName, functionName);
type, objectName, behaviorName, functionName);
node->diagnostic = RaiseSyntaxError(
_("An opening parenthesis was expected here to call a function."));
@@ -494,7 +615,7 @@ class GD_CORE_API ExpressionParser2 {
};
ParametersNode Parameters(
FunctionCallNode *functionCallNode,
std::vector<gd::ParameterMetadata> parameterMetadata,
const gd::String &objectName = "",
const gd::String &behaviorName = "") {
std::vector<std::unique_ptr<ExpressionNode>> parameters;
@@ -505,25 +626,77 @@ class GD_CORE_API ExpressionParser2 {
size_t parameterIndex =
WrittenParametersFirstIndex(objectName, behaviorName);
bool previousCharacterIsParameterSeparator = false;
while (!IsEndReached()) {
SkipAllWhitespaces();
if (CheckIfChar(IsClosingParenthesis) && !previousCharacterIsParameterSeparator) {
if (CheckIfChar(IsClosingParenthesis)) {
auto closingParenthesisLocation = SkipChar();
return ParametersNode{
std::move(parameters), nullptr, closingParenthesisLocation};
}
bool isEmptyParameter = CheckIfChar(IsParameterSeparator)
|| (CheckIfChar(IsClosingParenthesis) && previousCharacterIsParameterSeparator);
auto parameter = isEmptyParameter ? gd::make_unique<EmptyNode>() : Expression();
parameter->parent = functionCallNode;
parameters.push_back(std::move(parameter));
} else {
if (parameterIndex < parameterMetadata.size()) {
const gd::String &type = parameterMetadata[parameterIndex].GetType();
if (parameterMetadata[parameterIndex].IsCodeOnly()) {
// Do nothing, code only parameters are not written in expressions.
} else if (gd::ParameterMetadata::IsExpression("number", type)) {
parameters.push_back(Expression("number"));
} else if (gd::ParameterMetadata::IsExpression("string", type)) {
parameters.push_back(Expression("string"));
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
parameters.push_back(Expression(
type, lastObjectName.empty() ? objectName : lastObjectName));
} else if (gd::ParameterMetadata::IsObject(type)) {
size_t parameterStartPosition = GetCurrentPosition();
std::unique_ptr<ExpressionNode> objectExpression = Expression(type);
SkipAllWhitespaces();
previousCharacterIsParameterSeparator = CheckIfChar(IsParameterSeparator);
SkipIfChar(IsParameterSeparator);
parameterIndex++;
// Memorize the last object name. By convention, parameters that
// require an object (mainly, "objectvar" and "behavior") should be
// placed after the object in the list of parameters (if possible,
// just after). Search "lastObjectName" in the codebase for other
// place where this convention is enforced.
if (auto identifierNode =
dynamic_cast<IdentifierNode *>(objectExpression.get())) {
lastObjectName = identifierNode->identifierName;
} else {
objectExpression->diagnostic =
gd::make_unique<ExpressionParserError>(
"malformed_object_parameter",
_("An object name was expected but something else was "
"written. Enter just the name of the object for this "
"parameter."),
parameterStartPosition,
GetCurrentPosition());
}
parameters.push_back(std::move(objectExpression));
} else {
size_t parameterStartPosition = GetCurrentPosition();
parameters.push_back(Expression("unknown"));
parameters.back()->diagnostic =
gd::make_unique<ExpressionParserError>(
"unknown_parameter_type",
_("This function is improperly set up. Reach out to the "
"extension developer or a GDevelop maintainer to fix "
"this issue"),
parameterStartPosition,
GetCurrentPosition());
}
} else {
size_t parameterStartPosition = GetCurrentPosition();
parameters.push_back(Expression("unknown"));
parameters.back()
->diagnostic = gd::make_unique<ExpressionParserError>(
"extra_parameter",
_("This parameter was not expected by this expression. Remove it "
"or verify that you've entered the proper expression name."),
parameterStartPosition,
GetCurrentPosition());
}
SkipAllWhitespaces();
SkipIfChar(IsParameterSeparator);
parameterIndex++;
}
}
ExpressionParserLocation invalidClosingParenthesisLocation;
@@ -535,32 +708,92 @@ class GD_CORE_API ExpressionParser2 {
}
///@}
/** \name Validators
* Return a diagnostic if any error is found
*/
///@{
std::unique_ptr<ExpressionParserDiagnostic> ValidateFunction(
const gd::String &type,
const gd::FunctionCallNode &function,
size_t functionStartPosition);
std::unique_ptr<ExpressionParserDiagnostic> ValidateOperator(
gd::String::value_type operatorChar) {
if (operatorChar == '+' || operatorChar == '-' || operatorChar == '/' ||
operatorChar == '*') {
return gd::make_unique<ExpressionParserDiagnostic>();
const gd::String &type, gd::String::value_type operatorChar) {
if (type == "number") {
if (operatorChar == '+' || operatorChar == '-' || operatorChar == '/' ||
operatorChar == '*') {
return gd::make_unique<ExpressionParserDiagnostic>();
}
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("You've used an operator that is not supported. Operator should be "
"either +, -, / or *."),
GetCurrentPosition());
} else if (type == "string") {
if (operatorChar == '+') {
return gd::make_unique<ExpressionParserDiagnostic>();
}
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("You've used an operator that is not supported. Only + can be used "
"to concatenate texts."),
GetCurrentPosition());
} else if (gd::ParameterMetadata::IsObject(type)) {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("Operators (+, -, /, *) can't be used with an object name. Remove "
"the operator."),
GetCurrentPosition());
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("Operators (+, -, /, *) can't be used in variable names. Remove "
"the operator from the variable name."),
GetCurrentPosition());
}
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("You've used an operator that is not supported. Operator should be "
"either +, -, / or *."),
GetCurrentPosition());
return gd::make_unique<ExpressionParserDiagnostic>();
}
std::unique_ptr<ExpressionParserDiagnostic> ValidateUnaryOperator(
const gd::String &type,
gd::String::value_type operatorChar,
size_t position) {
if (operatorChar == '+' || operatorChar == '-') {
return gd::make_unique<ExpressionParserDiagnostic>();
if (type == "number") {
if (operatorChar == '+' || operatorChar == '-') {
return gd::make_unique<ExpressionParserDiagnostic>();
}
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("You've used an \"unary\" operator that is not supported. Operator "
"should be "
"either + or -."),
position);
} else if (type == "string") {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("You've used an operator that is not supported. Only + can be used "
"to concatenate texts, and must be placed between two texts (or "
"expressions)."),
position);
} else if (gd::ParameterMetadata::IsObject(type)) {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("Operators (+, -) can't be used with an object name. Remove the "
"operator."),
position);
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("Operators (+, -) can't be used in variable names. Remove "
"the operator from the variable name."),
position);
}
return gd::make_unique<ExpressionParserError>(
"invalid_operator",
_("You've used an \"unary\" operator that is not supported. Operator "
"should be "
"either + or -."),
position);
return gd::make_unique<ExpressionParserDiagnostic>();
}
///@}
@@ -748,7 +981,7 @@ class GD_CORE_API ExpressionParser2 {
std::unique_ptr<NumberNode> ReadNumber();
std::unique_ptr<EmptyNode> ReadUntilWhitespace() {
std::unique_ptr<EmptyNode> ReadUntilWhitespace(gd::String type) {
size_t startPosition = GetCurrentPosition();
gd::String text;
while (currentPosition < expression.size() &&
@@ -757,13 +990,13 @@ class GD_CORE_API ExpressionParser2 {
currentPosition++;
}
auto node = gd::make_unique<EmptyNode>(text);
auto node = gd::make_unique<EmptyNode>(type, text);
node->location =
ExpressionParserLocation(startPosition, GetCurrentPosition());
return node;
}
std::unique_ptr<EmptyNode> ReadUntilEnd() {
std::unique_ptr<EmptyNode> ReadUntilEnd(gd::String type) {
size_t startPosition = GetCurrentPosition();
gd::String text;
while (currentPosition < expression.size()) {
@@ -771,7 +1004,7 @@ class GD_CORE_API ExpressionParser2 {
currentPosition++;
}
auto node = gd::make_unique<EmptyNode>(text);
auto node = gd::make_unique<EmptyNode>(type, text);
node->location =
ExpressionParserLocation(startPosition, GetCurrentPosition());
return node;
@@ -804,11 +1037,34 @@ class GD_CORE_API ExpressionParser2 {
return std::move(gd::make_unique<ExpressionParserError>(
"type_error", message, beginningPosition, GetCurrentPosition()));
}
std::unique_ptr<ExpressionParserError> RaiseEmptyError(
const gd::String &type, size_t beginningPosition) {
gd::String message;
if (type == "number") {
message = _("You must enter a number or a valid expression call.");
} else if (type == "string") {
message = _(
"You must enter a text (between quotes) or a valid expression call.");
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
message = _("You must enter a variable name.");
} else if (gd::ParameterMetadata::IsObject(type)) {
message = _("You must enter a valid object name.");
} else {
message = _("You must enter a valid expression.");
}
return std::move(RaiseTypeError(message, beginningPosition));
}
///@}
gd::String expression;
std::size_t currentPosition;
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
static gd::String NAMESPACE_SEPARATOR;
};

View File

@@ -17,7 +17,6 @@ class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
struct FunctionCallNode;
} // namespace gd
namespace gd {
@@ -58,10 +57,6 @@ struct GD_CORE_API ExpressionParserDiagnostic {
* \brief An error that can be attached to a gd::ExpressionNode.
*/
struct GD_CORE_API ExpressionParserError : public ExpressionParserDiagnostic {
ExpressionParserError(const gd::String &type_,
const gd::String &message_,
const ExpressionParserLocation &location_)
: type(type_), message(message_), location(location_){};
ExpressionParserError(const gd::String &type_,
const gd::String &message_,
size_t position_)
@@ -91,7 +86,7 @@ struct GD_CORE_API ExpressionParserError : public ExpressionParserDiagnostic {
* an expression inherits from.
*/
struct GD_CORE_API ExpressionNode {
ExpressionNode() : parent(nullptr) {};
ExpressionNode(const gd::String &type_) : type(type_){};
virtual ~ExpressionNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker){};
@@ -102,12 +97,17 @@ struct GD_CORE_API ExpressionNode {
/// function can store the position of the
/// object name, the dot, the function
/// name, etc...
ExpressionNode *parent;
gd::String type; // Actual type of the node.
// "string", "number", type supported by
// gd::ParameterMetadata::IsObject, types supported by
// gd::ParameterMetadata::IsExpression or "unknown".
};
struct GD_CORE_API SubExpressionNode : public ExpressionNode {
SubExpressionNode(std::unique_ptr<ExpressionNode> expression_)
: ExpressionNode(), expression(std::move(expression_)){};
SubExpressionNode(const gd::String &type_,
std::unique_ptr<ExpressionNode> expression_)
: ExpressionNode(type_), expression(std::move(expression_)){};
virtual ~SubExpressionNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitSubExpressionNode(*this);
@@ -120,8 +120,8 @@ struct GD_CORE_API SubExpressionNode : public ExpressionNode {
* \brief An operator node. For example: "lhs + rhs".
*/
struct GD_CORE_API OperatorNode : public ExpressionNode {
OperatorNode(gd::String::value_type op_)
: ExpressionNode(), op(op_){};
OperatorNode(const gd::String &type_, gd::String::value_type op_)
: ExpressionNode(type_), op(op_){};
virtual ~OperatorNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitOperatorNode(*this);
@@ -136,8 +136,8 @@ struct GD_CORE_API OperatorNode : public ExpressionNode {
* \brief A unary operator node. For example: "-2".
*/
struct GD_CORE_API UnaryOperatorNode : public ExpressionNode {
UnaryOperatorNode(gd::String::value_type op_)
: ExpressionNode(), op(op_){};
UnaryOperatorNode(const gd::String &type_, gd::String::value_type op_)
: ExpressionNode(type_), op(op_){};
virtual ~UnaryOperatorNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitUnaryOperatorNode(*this);
@@ -153,7 +153,7 @@ struct GD_CORE_API UnaryOperatorNode : public ExpressionNode {
*/
struct GD_CORE_API NumberNode : public ExpressionNode {
NumberNode(const gd::String &number_)
: ExpressionNode(), number(number_){};
: ExpressionNode("number"), number(number_){};
virtual ~NumberNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitNumberNode(*this);
@@ -168,7 +168,7 @@ struct GD_CORE_API NumberNode : public ExpressionNode {
* Its `type` is always "string".
*/
struct GD_CORE_API TextNode : public ExpressionNode {
TextNode(const gd::String &text_) : ExpressionNode(), text(text_){};
TextNode(const gd::String &text_) : ExpressionNode("string"), text(text_){};
virtual ~TextNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitTextNode(*this);
@@ -177,88 +177,32 @@ struct GD_CORE_API TextNode : public ExpressionNode {
gd::String text;
};
struct GD_CORE_API IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode
: public ExpressionNode {
IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode()
: ExpressionNode(){};
};
/**
* \brief An identifier node, usually representing an object or a variable
* with an optional function name or child variable name respectively.
*
* The name of a function to call on an object or the behavior,
* for example: "MyObject.Function" or "MyObject.Physics".
*
* A variable, potentially with accessor to its child,
* for example: MyVariable or MyVariable.MyChild
*/
struct GD_CORE_API IdentifierNode
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
IdentifierNode(
const gd::String &identifierName_)
: IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(),
identifierName(identifierName_),
childIdentifierName(""){};
IdentifierNode(
const gd::String &identifierName_,
const gd::String &childIdentifierName_)
: IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(),
identifierName(identifierName_),
childIdentifierName(childIdentifierName_){};
virtual ~IdentifierNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitIdentifierNode(*this);
};
gd::String identifierName; ///< The object or variable name.
gd::String childIdentifierName; ///< The object function or variable child name.
ExpressionParserLocation
identifierNameLocation; ///< Location of the object or variable name.
ExpressionParserLocation
identifierNameDotLocation; ///< Location of the "." after the object or variable name.
ExpressionParserLocation childIdentifierNameLocation; ///< Location of object
/// function, behavior or
/// child variable name.
};
struct GD_CORE_API FunctionCallOrObjectFunctionNameOrEmptyNode
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
FunctionCallOrObjectFunctionNameOrEmptyNode()
: IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(){};
virtual ~FunctionCallOrObjectFunctionNameOrEmptyNode(){};
void Visit(ExpressionParser2NodeWorker &worker) override{};
};
struct GD_CORE_API VariableAccessorOrVariableBracketAccessorNode : public ExpressionNode {
VariableAccessorOrVariableBracketAccessorNode() : ExpressionNode(){};
VariableAccessorOrVariableBracketAccessorNode() : ExpressionNode(""){};
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode> child;
};
/**
* \brief A variable with bracket accessor or at least 2 "dot" accessors.
* \brief A variable, potentially with accessor to its children.
*
* Example: MyVariable or MyVariable.MyChildren
*
* Example: MyVariable[MyChildren] or MyVariable.MyChildren.MyGranChildren.
*
* Other cases like "MyVariable" or "MyVariable.MyChildren" are IdentifierNode
* to allow handling ambiguities.
*
* \see gd::IdentifierNode
* \see gd::VariableAccessorNode
* \see gd::VariableBracketAccessorNode
*/
struct GD_CORE_API VariableNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
VariableNode(const gd::String &name_)
: FunctionCallOrObjectFunctionNameOrEmptyNode(), name(name_){};
struct GD_CORE_API VariableNode : public ExpressionNode {
VariableNode(const gd::String &type_,
const gd::String &name_,
const gd::String &objectName_)
: ExpressionNode(type_), name(name_), objectName(objectName_){};
virtual ~VariableNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitVariableNode(*this);
};
gd::String name;
gd::String objectName;
std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
child; // Can be nullptr if no accessor
@@ -272,8 +216,7 @@ struct GD_CORE_API VariableNode : public FunctionCallOrObjectFunctionNameOrEmpty
*/
struct GD_CORE_API VariableAccessorNode
: public VariableAccessorOrVariableBracketAccessorNode {
VariableAccessorNode(const gd::String &name_)
: VariableAccessorOrVariableBracketAccessorNode(), name(name_){};
VariableAccessorNode(const gd::String &name_) : name(name_){};
virtual ~VariableAccessorNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitVariableAccessorNode(*this);
@@ -291,7 +234,7 @@ struct GD_CORE_API VariableAccessorNode
struct GD_CORE_API VariableBracketAccessorNode
: public VariableAccessorOrVariableBracketAccessorNode {
VariableBracketAccessorNode(std::unique_ptr<ExpressionNode> expression_)
: VariableAccessorOrVariableBracketAccessorNode(), expression(std::move(expression_)){};
: expression(std::move(expression_)){};
virtual ~VariableBracketAccessorNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitVariableBracketAccessorNode(*this);
@@ -300,26 +243,55 @@ struct GD_CORE_API VariableBracketAccessorNode
std::unique_ptr<ExpressionNode> expression;
};
struct GD_CORE_API IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode
: public ExpressionNode {
IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(
const gd::String &type)
: ExpressionNode(type){};
};
/**
* \brief An identifier node, usually representing an object or a function name.
*/
struct GD_CORE_API IdentifierNode
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
IdentifierNode(const gd::String &identifierName_, const gd::String &type_)
: IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(type_),
identifierName(identifierName_){};
virtual ~IdentifierNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitIdentifierNode(*this);
};
gd::String identifierName;
};
struct GD_CORE_API FunctionCallOrObjectFunctionNameOrEmptyNode
: public IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode {
FunctionCallOrObjectFunctionNameOrEmptyNode(const gd::String &type)
: IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode(type){};
virtual ~FunctionCallOrObjectFunctionNameOrEmptyNode(){};
void Visit(ExpressionParser2NodeWorker &worker) override{};
};
/**
* \brief The name of a function to call on an object or the behavior
* For example: "MyObject.Physics::LinearVelocity".
*
* Other cases like "MyObject.Function" or "MyObject.Physics" are IdentifierNode
* to allow handling ambiguities.
*
* \see gd::IdentifierNode
* For example: "MyObject.Function" or "MyObject.Physics" or
* "MyObject.Physics::LinearVelocity".
*/
struct GD_CORE_API ObjectFunctionNameNode
: public FunctionCallOrObjectFunctionNameOrEmptyNode {
ObjectFunctionNameNode(const gd::String &objectName_,
ObjectFunctionNameNode(const gd::String &type_,
const gd::String &objectName_,
const gd::String &objectFunctionOrBehaviorName_)
: FunctionCallOrObjectFunctionNameOrEmptyNode(),
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_),
objectName(objectName_),
objectFunctionOrBehaviorName(objectFunctionOrBehaviorName_) {}
ObjectFunctionNameNode(const gd::String &objectName_,
ObjectFunctionNameNode(const gd::String &type_,
const gd::String &objectName_,
const gd::String &behaviorName_,
const gd::String &behaviorFunctionName_)
: FunctionCallOrObjectFunctionNameOrEmptyNode(),
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_),
objectName(objectName_),
objectFunctionOrBehaviorName(behaviorName_),
behaviorFunctionName(behaviorFunctionName_) {}
@@ -362,24 +334,39 @@ struct GD_CORE_API ObjectFunctionNameNode
*/
struct GD_CORE_API FunctionCallNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
/** \brief Construct a free function call node. */
FunctionCallNode(const gd::String &functionName_)
: FunctionCallOrObjectFunctionNameOrEmptyNode(),
FunctionCallNode(const gd::String &type_,
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
const ExpressionMetadata &expressionMetadata_,
const gd::String &functionName_)
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_),
parameters(std::move(parameters_)),
expressionMetadata(expressionMetadata_),
functionName(functionName_){};
/** \brief Construct an object function call node. */
FunctionCallNode(const gd::String &objectName_,
FunctionCallNode(const gd::String &type_,
const gd::String &objectName_,
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
const ExpressionMetadata &expressionMetadata_,
const gd::String &functionName_)
: FunctionCallOrObjectFunctionNameOrEmptyNode(),
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_),
objectName(objectName_),
parameters(std::move(parameters_)),
expressionMetadata(expressionMetadata_),
functionName(functionName_){};
/** \brief Construct a behavior function call node. */
FunctionCallNode(const gd::String &objectName_,
FunctionCallNode(const gd::String &type_,
const gd::String &objectName_,
const gd::String &behaviorName_,
std::vector<std::unique_ptr<ExpressionNode>> parameters_,
const ExpressionMetadata &expressionMetadata_,
const gd::String &functionName_)
: FunctionCallOrObjectFunctionNameOrEmptyNode(),
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_),
objectName(objectName_),
behaviorName(behaviorName_),
parameters(std::move(parameters_)),
expressionMetadata(expressionMetadata_),
functionName(functionName_){};
virtual ~FunctionCallNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
@@ -389,6 +376,7 @@ struct GD_CORE_API FunctionCallNode : public FunctionCallOrObjectFunctionNameOrE
gd::String objectName;
gd::String behaviorName;
std::vector<std::unique_ptr<ExpressionNode>> parameters;
const ExpressionMetadata &expressionMetadata;
gd::String functionName;
ExpressionParserLocation
@@ -413,8 +401,8 @@ struct GD_CORE_API FunctionCallNode : public FunctionCallOrObjectFunctionNameOrE
* encountered and any other node could not make sense.
*/
struct GD_CORE_API EmptyNode : public FunctionCallOrObjectFunctionNameOrEmptyNode {
EmptyNode(const gd::String &text_ = "")
: FunctionCallOrObjectFunctionNameOrEmptyNode(), text(text_){};
EmptyNode(const gd::String &type_, const gd::String &text_ = "")
: FunctionCallOrObjectFunctionNameOrEmptyNode(type_), text(text_){};
virtual ~EmptyNode(){};
virtual void Visit(ExpressionParser2NodeWorker &worker) {
worker.OnVisitEmptyNode(*this);

View File

@@ -91,9 +91,6 @@ class GD_CORE_API ExpressionParser2NodePrinter
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
output += node.identifierName;
if (!node.childIdentifierName.empty()) {
output += "." + node.childIdentifierName;
}
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
if (!node.behaviorFunctionName.empty()) {

View File

@@ -4,7 +4,6 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Events/Serialization.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
@@ -219,8 +218,8 @@ void EventsListSerialization::UnserializeEventsFrom(
event = std::make_shared<EmptyEvent>();
}
event->SetDisabled(eventElem.GetBoolAttribute("disabled", false));
event->SetFolded(eventElem.GetBoolAttribute("folded", false));
event->SetDisabled(eventElem.GetBoolAttribute("disabled"));
event->SetFolded(eventElem.GetBoolAttribute("folded"));
list.InsertEvent(event, list.GetEventsCount());
}
@@ -233,9 +232,8 @@ void EventsListSerialization::SerializeEventsTo(const EventsList& list,
const gd::BaseEvent& event = list.GetEvent(j);
SerializerElement& eventElem = events.AddChild("event");
if (event.IsDisabled())
eventElem.SetAttribute("disabled", event.IsDisabled());
if (event.IsFolded()) eventElem.SetAttribute("folded", event.IsFolded());
eventElem.SetAttribute("disabled", event.IsDisabled());
eventElem.SetAttribute("folded", event.IsFolded());
eventElem.AddChild("type").SetValue(event.GetType());
event.SerializeTo(eventElem);
@@ -269,9 +267,6 @@ void gd::EventsListSerialization::UnserializeInstructionsFrom(
instrElement.GetChild("type", 0, "Type")
.GetBoolAttribute("inverted", false, "Contraire"));
instruction.SetAwaited(
instrElement.GetChild("type", 0, "Type").GetBoolAttribute("await"));
// Read parameters
vector<gd::Expression> parameters;
@@ -345,12 +340,9 @@ void gd::EventsListSerialization::SerializeInstructionsTo(
instructions.ConsiderAsArrayOf("instruction");
for (std::size_t k = 0; k < list.size(); k++) {
SerializerElement& instruction = instructions.AddChild("instruction");
instruction.AddChild("type").SetAttribute("value", list[k].GetType());
if (list[k].IsInverted())
instruction.GetChild("type").SetAttribute("inverted", true);
if (list[k].IsAwaited())
instruction.GetChild("type").SetAttribute("await", true);
instruction.AddChild("type")
.SetAttribute("value", list[k].GetType())
.SetAttribute("inverted", list[k].IsInverted());
// Parameters
SerializerElement& parameters = instruction.AddChild("parameters");
@@ -360,10 +352,9 @@ void gd::EventsListSerialization::SerializeInstructionsTo(
.SetValue(list[k].GetParameter(l).GetPlainString());
// Sub instructions
if (!list[k].GetSubInstructions().empty()) {
SerializeInstructionsTo(list[k].GetSubInstructions(),
instruction.AddChild("subInstructions"));
}
SerializerElement& subInstructions =
instruction.AddChild("subInstructions");
SerializeInstructionsTo(list[k].GetSubInstructions(), subInstructions);
}
}

View File

@@ -42,7 +42,6 @@ class GD_CORE_API BuiltinExtensionsImplementer {
static void ImplementsTimeExtension(gd::PlatformExtension& extension);
static void ImplementsVariablesExtension(gd::PlatformExtension& extension);
static void ImplementsWindowExtension(gd::PlatformExtension& extension);
static void ImplementsAsyncExtension(gd::PlatformExtension& extension);
};
} // namespace gd

View File

@@ -1,32 +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 "AllBuiltinExtensions.h"
#include "GDCore/Events/Builtin/AsyncEvent.h"
#include "GDCore/Tools/Localization.h"
using namespace std;
namespace gd {
void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAsyncExtension(
gd::PlatformExtension &extension) {
extension
.SetExtensionInformation(
"BuiltinAsync",
_("Async functions"),
_("Functions that defer the execution of the events after it."),
"Arthur Pacaud (arthuro555)",
"Open source (MIT License)")
.SetCategory("Advanced");
extension.AddEvent("Async",
_("Async event"),
_("Internal event for asynchronous actions"),
"",
"res/eventaddicon.png",
std::make_shared<gd::AsyncEvent>());
}
} // namespace gd

View File

@@ -14,14 +14,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
extension
.SetExtensionInformation(
"BuiltinAudio",
_("Sounds and music"),
_("Sounds and musics"),
_("GDevelop provides several conditions and actions to play audio "
"files. They can be either long music or short sound effects."),
"files. They can be either long musics or short sound effects."),
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/all-features/audio")
.SetCategory("Audio");
extension.AddInstructionOrExpressionGroupMetadata(_("Sounds and music"))
extension.AddInstructionOrExpressionGroupMetadata(_("Sounds and musics"))
.SetIcon("res/actions/music24.png");
extension
@@ -73,9 +73,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
extension
.AddAction("RePlaySoundCanal",
_("Resume playing a sound on a channel"),
_("Resume playing a sound on a channel that was paused."),
_("Resume the sound of channel _PARAM1_"),
_("Play the sound of a channel"),
_("Play the sound of the channel."),
_("Play the sound of channel _PARAM1_"),
_("Sounds on channels"),
"res/actions/son24.png",
"res/actions/son.png")
@@ -132,9 +132,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
extension
.AddAction("RePlayMusicCanal",
_("Resume playing a music on a channel"),
_("Resume playing a music on a channel that was paused."),
_("Resume the music of channel _PARAM1_"),
_("Play the music of a channel"),
_("Play the music of the channel."),
_("Play the music of channel _PARAM1_"),
_("Music on channels"),
"res/actions/music24.png",
"res/actions/music.png")
@@ -343,34 +343,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAudioExtension(
"res/actions/music.png")
.AddCodeOnlyParameter("currentScene", "")
.MarkAsComplex();
extension
.AddAction(
"FadeSoundVolume",
_("Fade the volume of a sound played on a channel."),
_("Fade the volume of a sound played on a channel to the specified volume within the specified duration."),
_("Fade the sound on channel _PARAM1_ to volume _PARAM2_ within _PARAM3_ seconds"),
_("Sounds on channels"),
"res/actions/son24.png",
"res/actions/son.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.AddParameter("expression", _("Final volume (0-100)"))
.AddParameter("expression", _("Fading time in seconds"))
.MarkAsAdvanced();
extension
.AddAction(
"FadeMusicVolume",
_("Fade the volume of a music played on a channel."),
_("Fade the volume of a music played on a channel to the specified volume within the specified duration."),
_("Fade the music on channel _PARAM1_ to volume _PARAM2_ within _PARAM3_ seconds"),
_("Music on channels"),
"res/actions/music24.png",
"res/actions/music.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("expression", _("Channel identifier"))
.AddParameter("expression", _("Final volume (0-100)"))
.AddParameter("expression", _("Fading time in seconds"))
.MarkAsAdvanced();
extension
.AddCondition("MusicPlaying",

View File

@@ -28,7 +28,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
extension.AddInstructionOrExpressionGroupMetadata(_("Movement using forces"))
.SetIcon("res/actions/force24.png");
gd::ObjectMetadata& obj = extension.AddObject<gd::ObjectConfiguration>(
gd::ObjectMetadata& obj = extension.AddObject<gd::Object>(
"", _("Base object"), _("Base object"), "res/objeticon24.png");
obj.AddCondition("PosX",
@@ -36,8 +36,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Compare the X position of the object."),
_("the X position"),
_("Position"),
"res/conditions/position24_black.png",
"res/conditions/position_black.png")
"res/conditions/position24.png",
"res/conditions/position.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
@@ -48,8 +48,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Change the X position of an object."),
_("the X position"),
_("Position"),
"res/actions/position24_black.png",
"res/actions/position_black.png")
"res/actions/position24.png",
"res/actions/position.png")
.AddParameter("object", _("Object"))
.UseStandardOperatorParameters("number")
@@ -60,8 +60,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Compare the Y position of an object."),
_("the Y position"),
_("Position"),
"res/conditions/position24_black.png",
"res/conditions/position_black.png")
"res/conditions/position24.png",
"res/conditions/position.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
@@ -72,8 +72,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Change the Y position of an object."),
_("the Y position"),
_("Position"),
"res/actions/position24_black.png",
"res/actions/position_black.png")
"res/actions/position24.png",
"res/actions/position.png")
.AddParameter("object", _("Object"))
.UseStandardOperatorParameters("number")
@@ -85,8 +85,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Change the position of _PARAM0_: _PARAM1_ _PARAM2_ (x "
"axis), _PARAM3_ _PARAM4_ (y axis)"),
_("Position"),
"res/actions/position24_black.png",
"res/actions/position_black.png")
"res/actions/position24.png",
"res/actions/position.png")
.AddParameter("object", _("Object"))
.AddParameter("operator", _("Modification's sign"), "number")
@@ -102,8 +102,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"_PARAM2_ (x "
"axis), _PARAM3_ _PARAM4_ (y axis)"),
_("Position/Center"),
"res/actions/position24_black.png",
"res/actions/position_black.png")
"res/actions/position24.png",
"res/actions/position.png")
.AddParameter("object", _("Object"))
.AddParameter("operator", _("Modification's sign"), "number")
.AddParameter("expression", _("X position"))
@@ -118,7 +118,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the X position of the center of rotation"),
_("the X position of the center"),
_("Position/Center"),
"res/actions/position24_black.png")
"res/actions/position24.png")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -129,7 +129,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the Y position of the center of rotation"),
_("the Y position of the center"),
_("Position/Center"),
"res/actions/position24_black.png")
"res/actions/position24.png")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -140,7 +140,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the object) left position"),
_("the bounding box left position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-left_black.svg")
"res/conditions/bounding-box-left.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -151,7 +151,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("the bounding box (the area encapsulating the object) top position"),
_("the bounding box top position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-top_black.svg")
"res/conditions/bounding-box-top.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -162,7 +162,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the object) right position"),
_("the bounding box right position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-right_black.svg")
"res/conditions/bounding-box-right.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -173,7 +173,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the object) bottom position"),
_("the bounding box bottom position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-bottom_black.svg")
"res/conditions/bounding-box-bottom.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -184,7 +184,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the object) center X position"),
_("the bounding box center X position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-center_black.svg")
"res/conditions/bounding-box-center.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -195,7 +195,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"the object) center Y position"),
_("the bounding box center Y position"),
_("Position/Bounding Box"),
"res/conditions/bounding-box-center_black.svg")
"res/conditions/bounding-box-center.svg")
.AddParameter("object", _("Object"))
.UseStandardParameters("number");
@@ -219,11 +219,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddAction("SetAngle",
_("Angle"),
_("Change the angle of rotation of an object (in degrees)."),
_("Change the angle of rotation of an object."),
_("the angle"),
_("Angle"),
"res/actions/direction24_black.png",
"res/actions/direction_black.png")
"res/actions/direction24.png",
"res/actions/direction.png")
.AddParameter("object", _("Object"))
.UseStandardOperatorParameters("number");
@@ -234,8 +234,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"counterclockwise otherwise."),
_("Rotate _PARAM0_ at speed _PARAM1_ deg/second"),
_("Angle"),
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
"res/actions/direction24.png",
"res/actions/direction.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angular speed (in degrees per second)"))
@@ -248,8 +248,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Rotate an object towards an angle with the specified speed."),
_("Rotate _PARAM0_ towards _PARAM1_ at speed _PARAM2_ deg/second"),
_("Angle"),
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
"res/actions/direction24.png",
"res/actions/direction.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle to rotate towards (in degrees)"))
@@ -264,8 +264,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Rotate _PARAM0_ towards _PARAM1_;_PARAM2_ at speed "
"_PARAM3_ deg/second"),
_("Angle"),
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
"res/actions/direction24.png",
"res/actions/direction.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("X position"))
@@ -289,8 +289,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Speed on X axis (in pixels per second)"))
.AddParameter("expression", _("Speed on Y axis (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0");
.AddParameter("forceMultiplier", _("Force multiplier"));
obj.AddAction("AddForceAL",
_("Add a force (angle)"),
@@ -306,8 +305,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.AddParameter("forceMultiplier", _("Force multiplier"))
.MarkAsAdvanced();
obj.AddAction(
@@ -325,8 +323,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("X position"))
.AddParameter("expression", _("Y position"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.AddParameter("forceMultiplier", _("Force multiplier"))
.MarkAsAdvanced();
obj.AddAction(
@@ -393,7 +390,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/layer.png")
.AddParameter("object", _("Object"))
.AddParameter("layer", _("Move it to this layer"))
.AddParameter("layer", _("Move it to this layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.MarkAsAdvanced();
@@ -512,8 +509,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Compare the angle of the specified object."),
_("the angle (in degrees)"),
_("Angle"),
"res/conditions/direction24_black.png",
"res/conditions/direction_black.png")
"res/conditions/direction24.png",
"res/conditions/direction.png")
.AddParameter("object", _("Object"))
.UseStandardRelationalOperatorParameters("number")
@@ -759,8 +756,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Target Object"))
.AddParameter("expression", _("Speed (in pixels per second)"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.AddParameter("forceMultiplier", _("Force multiplier"))
.MarkAsAdvanced();
obj.AddAction(
@@ -780,8 +776,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectPtr", _("Rotate around this object"))
.AddParameter("expression", _("Speed (in degrees per second)"))
.AddParameter("expression", _("Distance (in pixels)"))
.AddParameter("forceMultiplier", _("Force multiplier"), "", true)
.SetDefaultValue("0")
.AddParameter("forceMultiplier", _("Force multiplier"))
.MarkAsAdvanced();
obj.AddAction("MettreAutour",
@@ -844,6 +839,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"edges, but are not overlapping (default: no)"),
"",
true)
.MarkParameterAsAdvanced()
.SetDefaultValue("no")
.MarkAsSimple();
@@ -965,21 +961,21 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("X position"),
_("X position of the object"),
_("Position"),
"res/actions/position_black.png")
"res/actions/position.png")
.AddParameter("object", _("Object"));
obj.AddExpression("Y",
_("Y position"),
_("Y position of the object"),
_("Position"),
"res/actions/position_black.png")
"res/actions/position.png")
.AddParameter("object", _("Object"));
obj.AddExpression("Angle",
_("Angle"),
_("Current angle, in degrees, of the object"),
_("Angle"),
"res/actions/direction_black.png")
"res/actions/direction.png")
.AddParameter("object", _("Object"));
obj.AddExpression("ForceX",
@@ -998,7 +994,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddExpression("ForceAngle",
_("Angle of the sum of forces"),
_("Angle of the sum of forces (in degrees)"),
_("Angle of the sum of forces"),
_("Movement using forces"),
"res/actions/force.png")
.AddParameter("object", _("Object"));
@@ -1022,14 +1018,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Width"),
_("Width of the object"),
_("Size"),
"res/actions/scaleWidth_black.png")
"res/actions/scaleWidth.png")
.AddParameter("object", _("Object"));
obj.AddExpression("Largeur",
_("Width"),
_("Width of the object"),
_("Size"),
"res/actions/scaleWidth_black.png")
"res/actions/scaleWidth.png")
.AddParameter("object", _("Object"))
.SetHidden();
@@ -1037,14 +1033,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
_("Height"),
_("Height of the object"),
_("Size"),
"res/actions/scaleHeight_black.png")
"res/actions/scaleHeight.png")
.AddParameter("object", _("Object"));
obj.AddExpression("Hauteur",
_("Height"),
_("Height of the object"),
_("Size"),
"res/actions/scaleHeight_black.png")
"res/actions/scaleHeight.png")
.AddParameter("object", _("Object"))
.SetHidden();
@@ -1098,7 +1094,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Target Y position"));
obj.AddExpression("Variable",
_("Value of an object variable"),
_("Object variable"),
_("Value of an object variable"),
_("Variables"),
"res/actions/var.png")
@@ -1114,7 +1110,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("objectvar", _("Variable"));
obj.AddStrExpression("VariableString",
_("Text of an object variable"),
_("Object variable"),
_("Text of an object variable"),
_("Variables"),
"res/actions/var.png")
@@ -1131,11 +1127,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddExpression("AngleToObject",
_("Angle between two objects"),
_("Compute the angle between two objects (in degrees). "
"If you need the angle to an arbitrary position, "
"use AngleToPosition."),
_("Compute the angle between two objects. If you need the "
"angle to an arbitrary position, use AngleToPosition."),
_("Angle"),
"res/actions/position_black.png")
"res/actions/position.png")
.AddParameter("object", _("Object"))
.AddParameter("objectPtr", _("Object"));
@@ -1146,7 +1141,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"getting the cartesian coordinates of a 2D vector, using "
"its polar coordinates."),
_("Position"),
"res/actions/position_black.png")
"res/actions/position.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Distance"));
@@ -1158,7 +1153,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"getting the cartesian coordinates of a 2D vector, using "
"its polar coordinates."),
_("Position"),
"res/actions/position_black.png")
"res/actions/position.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Distance"));
@@ -1166,10 +1161,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
obj.AddExpression("AngleToPosition",
_("Angle between an object and a position"),
_("Compute the angle between the object center and a "
"\"target\" position (in degrees). If you need the angle "
"between two objects, use AngleToObject."),
"\"target\" position. If you need the angle between two "
"objects, use AngleToObject."),
_("Angle"),
"res/actions/position_black.png")
"res/actions/position.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Target X position"))
.AddParameter("expression", _("Target Y position"));
@@ -1258,7 +1253,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/create24.png",
"res/actions/create24.png")
.AddCodeOnlyParameter("objectsContext", "")
.AddParameter("objectListOrEmptyIfJustDeclared", _("Object to create"))
.AddParameter("objectListWithoutPicking", _("Object to create"))
.AddParameter("expression", _("X position"))
.AddParameter("expression", _("Y position"))
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
@@ -1276,7 +1271,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/actions/create24.png",
"res/actions/create24.png")
.AddCodeOnlyParameter("objectsContext", "")
.AddParameter("objectListOrEmptyIfJustDeclared", _("Group of potential objects"))
.AddParameter("objectListWithoutPicking", _("Group of potential objects"))
.SetParameterLongDescription(
_("Group containing objects that can be created by the action."))
.AddParameter("string", _("Name of the object to create"))
@@ -1424,33 +1419,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"res/conditions/nbObjet.png")
.AddParameter("objectList", _("Object"))
.UseStandardRelationalOperatorParameters("number")
.MarkAsSimple()
.SetHidden();
extension.AddExpressionAndCondition(
"number",
"SceneInstancesCount",
_("Number of object instances on the scene"),
_("the number of instances of the specified objects living on the scene"),
_("the number of _PARAM1_ living on the scene"),
_("Objects"),
"res/conditions/nbObjet24.png")
.AddCodeOnlyParameter("objectsContext", "")
.AddParameter("objectListOrEmptyWithoutPicking", _("Object"))
.UseStandardParameters("number")
.MarkAsSimple();
extension.AddExpressionAndCondition(
"number",
"PickedInstancesCount",
_("Number of object instances currently picked"),
_("the number of instances picked by the previous conditions (or actions)"),
_("the number of _PARAM0_ currently picked"),
_("Objects"),
"res/conditions/nbObjet24.png")
.AddParameter("objectListOrEmptyWithoutPicking", _("Object"))
.UseStandardParameters("number")
.MarkAsSimple();
.MarkAsSimple();
extension
.AddCondition(
@@ -1529,7 +1498,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"object will become the only one taken into account.\nIf "
"the condition is inverted, the object to be intersected "
"will be the farthest one within the ray radius."),
_("Cast a ray from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ "
_("Cast a ray from from _PARAM1_;_PARAM2_ to _PARAM3_;_PARAM4_ "
"against _PARAM0_, and save the "
"result in _PARAM5_, _PARAM6_"),
"",
@@ -1558,14 +1527,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
"currently picked in the event"),
"",
"res/conditions/nbObjet.png")
.AddParameter("objectList", _("Object"))
.SetHidden(); // Deprecated
.AddParameter("objectList", _("Object"));
obj.AddStrExpression("ObjectName",
_("Object name"),
_("Return the name of the object"),
"",
"res/conditions/text_black.png")
"res/conditions/text.png")
.AddParameter("object", _("Object"));
obj.AddStrExpression("Layer",

View File

@@ -29,7 +29,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
extension
.AddExpressionAndConditionAndAction(
"number",
"CameraCenterX",
"CameraX",
_("Camera center X position"),
_("the X position of the center of a camera"),
_("the X position of camera _PARAM4_ (layer: _PARAM3_)"),
@@ -40,28 +40,19 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.MarkParameterAsAdvanced()
.SetDefaultValue("0")
.MarkAsAdvanced();
// Compatibility with GD <= 5.0.135
extension.AddDuplicatedCondition("CameraX", "CameraCenterX")
.SetHidden(); // Deprecated
extension.AddDuplicatedExpression("CameraX", "CameraCenterX")
.SetHidden(); // Deprecated
extension.AddDuplicatedAction("SetCameraX", "SetCameraCenterX")
.SetHidden(); // Deprecated
extension.AddDuplicatedAction("CameraX", "SetCameraX")
.SetHidden(); // Deprecated
extension.AddDuplicatedExpression("VueX", "CameraX")
.SetHidden(); // Deprecated
// end of compatibility code
extension
.AddExpressionAndConditionAndAction(
"number",
"CameraCenterY",
"CameraY",
_("Camera center Y position"),
_("the Y position of the center of a camera"),
_("the Y position of camera _PARAM4_ (layer: _PARAM3_)"),
@@ -72,23 +63,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.MarkParameterAsAdvanced()
.SetDefaultValue("0")
.MarkAsAdvanced();
// Compatibility with GD <= 5.0.135
extension.AddDuplicatedCondition("CameraY", "CameraCenterY")
.SetHidden(); // Deprecated
extension.AddDuplicatedExpression("CameraY", "CameraCenterY")
.SetHidden(); // Deprecated
extension.AddDuplicatedAction("SetCameraY", "SetCameraCenterY")
.SetHidden(); // Deprecated
extension.AddDuplicatedAction("CameraY", "SetCameraY")
.SetHidden(); // Deprecated
extension.AddDuplicatedExpression("VueY", "CameraY")
.SetHidden(); // Deprecated
// end of compatibility code
extension
.AddExpressionAndCondition(
@@ -100,9 +82,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"",
"res/conditions/camera24.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"), "", true)
.AddParameter("expression", _("Camera number"))
.UseStandardParameters("number")
.MarkAsAdvanced();
@@ -116,77 +98,9 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"",
"res/conditions/camera24.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"), "", true)
.UseStandardParameters("number")
.MarkAsAdvanced();
extension
.AddExpressionAndCondition(
"number",
"CameraBorderLeft",
_("Camera left border position"),
_("the position of the left border of a camera"),
_("the position of the left border of camera _PARAM2_ of layer "
"_PARAM1_"),
"",
"res/conditions/camera24.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"), "", true)
.UseStandardParameters("number")
.MarkAsAdvanced();
extension
.AddExpressionAndCondition(
"number",
"CameraBorderRight",
_("Camera right border position"),
_("the position of the right border of a camera"),
_("the position of the right border of camera _PARAM2_ of layer "
"_PARAM1_"),
"",
"res/conditions/camera24.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"), "", true)
.UseStandardParameters("number")
.MarkAsAdvanced();
extension
.AddExpressionAndCondition(
"number",
"CameraBorderTop",
_("Camera top border position"),
_("the position of the top border of a camera"),
_("the position of the top border of camera _PARAM2_ of layer "
"_PARAM1_"),
"",
"res/conditions/camera24.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"), "", true)
.UseStandardParameters("number")
.MarkAsAdvanced();
extension
.AddExpressionAndCondition(
"number",
"CameraBorderBottom",
_("Camera bottom border position"),
_("the position of the bottom border of a camera"),
_("the position of the bottom border of camera _PARAM2_ of layer "
"_PARAM1_"),
"",
"res/conditions/camera24.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"), "", true)
.AddParameter("expression", _("Camera number"))
.UseStandardParameters("number")
.MarkAsAdvanced();
@@ -195,7 +109,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"number",
"CameraAngle",
_("Angle of a camera of a layer"),
_("the angle of rotation of a camera (in degrees)"),
_("the angle of rotation of a camera"),
_("the angle of camera (layer: _PARAM3_, camera: _PARAM4_)"),
"",
"res/conditions/camera24.png")
@@ -204,6 +118,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.MarkParameterAsAdvanced()
.SetDefaultValue("0")
.MarkAsAdvanced();
@@ -221,7 +136,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/camera24.png",
"res/actions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"))
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Width"), "", true)
.AddParameter("expression", _("Height"), "", true)
@@ -256,7 +171,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/camera24.png",
"res/actions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"))
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"))
.MarkAsComplex();
@@ -272,7 +187,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/camera24.png",
"res/actions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"))
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"))
.AddParameter("expression", _("Width"))
@@ -290,7 +205,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/camera24.png",
"res/actions/camera.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"))
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number"))
.AddParameter(
@@ -309,7 +224,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
extension
.AddAction("ZoomCamera",
_("Camera zoom"),
_("Change camera zoom"),
_("Change camera zoom."),
_("Change camera zoom to _PARAM1_ (layer: _PARAM2_, camera: "
"_PARAM3_)"),
@@ -322,6 +237,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.MarkParameterAsAdvanced()
.SetDefaultValue("0");
// TODO Deprecated: hide this action in a future release.
@@ -350,10 +266,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
_("Anticipate the movement of the object (yes by default)"),
"",
true)
.MarkParameterAsAdvanced()
.SetDefaultValue("yes")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.MarkParameterAsAdvanced()
.SetDefaultValue("0")
.MarkAsAdvanced();
@@ -379,6 +297,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.MarkParameterAsAdvanced()
.SetDefaultValue("0")
.MarkAsAdvanced();
@@ -397,10 +316,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
_("Anticipate the movement of the object (yes by default)"),
"",
true)
.MarkParameterAsAdvanced()
.SetDefaultValue("yes")
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
.SetDefaultValue("\"\"")
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
.MarkParameterAsAdvanced()
.SetDefaultValue("0")
.MarkAsSimple();
@@ -413,7 +334,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/layer24.png",
"res/actions/layer.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"))
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.MarkAsAdvanced();
@@ -426,7 +347,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/actions/layer24.png",
"res/actions/layer.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"))
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.MarkAsAdvanced();
@@ -439,7 +360,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
"res/conditions/layer24.png",
"res/conditions/layer.png")
.AddCodeOnlyParameter("currentScene", "")
.AddParameter("layer", _("Layer"))
.AddParameter("layer", _("Layer (base layer if empty)"))
.SetDefaultValue("\"\"")
.MarkAsAdvanced();
@@ -576,7 +497,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
extension
.AddAction("SetLayerDefaultZOrder",
_("Layer default Z order"),
_("Change layer default Z order"),
_("Change the default Z order set to objects when they are "
"created on a layer."),
_("Set the default Z order of objects created on _PARAM1_ to "

View File

@@ -21,14 +21,14 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
"Open source (MIT License)")
.SetExtensionHelpPath("/all-features/common-conversions");
extension.AddInstructionOrExpressionGroupMetadata(_("Conversion"))
.SetIcon("res/conditions/toujours24_black.png");
.SetIcon("res/conditions/toujours24.png");
extension
.AddExpression("ToNumber",
_("Text > Number"),
_("Convert the text to a number"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text to convert to a number"));
extension
@@ -36,7 +36,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Number > Text"),
_("Convert the result of the expression to text"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("expression", _("Expression to be converted to text"));
extension
@@ -45,7 +45,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Convert the result of the expression to text, "
"without using the scientific notation"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("expression", _("Expression to be converted to text"));
extension
@@ -54,7 +54,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Degrees > Radians"),
_("Converts the angle, expressed in degrees, into radians"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("expression", _("Angle, in degrees"));
extension
@@ -63,7 +63,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Radians > Degrees"),
_("Converts the angle, expressed in radians, into degrees"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("expression", _("Angle, in radians"));
extension
@@ -71,7 +71,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Convert scene variable to JSON"),
_("Convert a scene variable to JSON"),
_("JSON"),
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("scenevar", _("Scene variable to be stringified"));
extension
@@ -79,7 +79,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Convert global variable to JSON"),
_("Convert a global variable to JSON"),
_("JSON"),
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("globalvar", _("The global variable to be stringified"));
extension
@@ -87,7 +87,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
_("Convert object variable to JSON"),
_("Convert an object variable to JSON"),
_("JSON"),
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("objectPtr", _("The object with the variable"))
.AddParameter("objectvar", _("The object variable to be stringified"));

View File

@@ -33,7 +33,7 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
.SetExtensionHelpPath("/all-features/advanced-conditions");
extension
.AddInstructionOrExpressionGroupMetadata(_("Events and control flow"))
.SetIcon("res/conditions/toujours24_black.png");
.SetIcon("res/conditions/toujours24.png");
extension
.AddCondition("Always",
@@ -42,8 +42,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
"the condition is inverted)."),
_("Always"),
"",
"res/conditions/toujours24_black.png",
"res/conditions/toujours_black.png")
"res/conditions/toujours24.png",
"res/conditions/toujours.png")
.SetHelpPath("/all-features/advanced-conditions")
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsAdvanced();
@@ -61,8 +61,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
_("Check if one of the sub conditions is true"),
_("If one of these conditions is true:"),
"",
"res/conditions/or24_black.png",
"res/conditions/or_black.png")
"res/conditions/or24.png",
"res/conditions/or.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
@@ -72,8 +72,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
_("Check if all sub conditions are true"),
_("If all of these conditions are true:"),
"",
"res/conditions/and24_black.png",
"res/conditions/and_black.png")
"res/conditions/and24.png",
"res/conditions/and.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
@@ -84,8 +84,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
_("Return the contrary of the result of the sub conditions"),
_("Invert the logical result of these conditions:"),
"",
"res/conditions/not24_black.png",
"res/conditions/not_black.png")
"res/conditions/not24.png",
"res/conditions/not.png")
.SetCanHaveSubInstructions()
.MarkAsAdvanced();
@@ -104,8 +104,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
_("Compare the two numbers."),
_("_PARAM0_ _PARAM1_ _PARAM2_"),
"",
"res/conditions/egal24_black.png",
"res/conditions/egal_black.png")
"res/conditions/egal24.png",
"res/conditions/egal.png")
.SetHelpPath("/all-features/advanced-conditions")
.AddParameter("expression", _("First expression"))
.AddParameter("relationalOperator", _("Sign of the test"), "number")
@@ -125,8 +125,8 @@ BuiltinExtensionsImplementer::ImplementsCommonInstructionsExtension(
_("Compare the two strings."),
_("_PARAM0_ _PARAM1_ _PARAM2_"),
"",
"res/conditions/egal24_black.png",
"res/conditions/egal_black.png")
"res/conditions/egal24.png",
"res/conditions/egal.png")
.SetHelpPath("/all-features/advanced-conditions")
.AddParameter("string", _("First string expression"))
.AddParameter("relationalOperator", _("Sign of the test"), "string")

View File

@@ -96,13 +96,13 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
_("Difference between two angles"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("First angle, in degrees"))
.AddParameter("expression", _("Second angle, in degrees"));
.AddParameter("expression", _("First angle"))
.AddParameter("expression", _("Second angle"));
extension
.AddExpression("AngleBetweenPositions",
_("Angle between two positions"),
_("Compute the angle between two positions (in degrees)."),
_("Compute the angle between two positions."),
"",
"res/mathfunction.png")
.AddParameter("expression", _("First point X position"))
@@ -159,8 +159,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("acos",
_("Arccosine"),
_("Arccosine, return an angle (in radian). "
"`ToDeg` allows to convert it to degrees."),
_("Arccosine"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -176,8 +175,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("asin",
_("Arcsine"),
_("Arcsine, return an angle (in radian). "
"`ToDeg` allows to convert it to degrees."),
_("Arcsine"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -193,8 +191,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("atan",
_("Arctangent"),
_("Arctangent, return an angle (in radian). "
"`ToDeg` allows to convert it to degrees."),
_("Arctangent"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -232,15 +229,6 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
.AddExpression("ceilTo",
_("Ceil (round up) to a decimal point"),
_("Round number up to the Nth decimal place"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"))
.AddParameter("expression", _("Expression"), "", true);
extension
.AddExpression("floor",
_("Floor (round down)"),
@@ -249,20 +237,10 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
.AddExpression("floorTo",
_("Floor (round down) to a decimal point"),
_("Round number down to the Nth decimal place"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"))
.AddParameter("expression", _("Expression"), "", true);
extension
.AddExpression("cos",
_("Cosine"),
_("Cosine of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
_("Cosine of a number"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -317,15 +295,6 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
extension
.AddExpression("roundTo",
_("Round to a decimal point"),
_("Round a number to the Nth decimal place"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"))
.AddParameter("expression", _("Expression"), "", true);
extension
.AddExpression("exp",
_("Exponential"),
@@ -404,8 +373,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("sin",
_("Sine"),
_("Sine of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `sin(ToRad(45))`."),
_("Sine of a number"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -429,8 +397,7 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
extension
.AddExpression("tan",
_("Tangent"),
_("Tangent of an angle (in radian). "
"If you want to use degrees, use`ToRad`: `tan(ToRad(45))`."),
_("Tangent of a number"),
"",
"res/mathfunction.png")
.AddParameter("expression", _("Expression"));
@@ -485,13 +452,6 @@ BuiltinExtensionsImplementer::ImplementsMathematicalToolsExtension(
.AddParameter("expression", _("Angle, in degrees"))
.AddParameter("expression", _("Distance"));
extension
.AddExpression("Pi",
_("Number Pi (3.1415...)"),
_("The number Pi (3.1415...)"),
"",
"res/mathfunction.png")
.SetHelpPath("/all-features/expressions");
}
} // namespace gd

View File

@@ -112,7 +112,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
extension
.AddAction("SceneBackground",
_("Background color"),
_("Change background color"),
_("Change the background color of the scene."),
_("Set background color to _PARAM1_"),
"",

View File

@@ -4,10 +4,8 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Extensions/Builtin/SpriteExtension/Direction.h"
#include <iostream>
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
#include "GDCore/Serialization/SerializerElement.h"
@@ -31,15 +29,6 @@ const Sprite& Direction::GetSprite(std::size_t nb) const { return sprites[nb]; }
Sprite& Direction::GetSprite(std::size_t nb) { return sprites[nb]; }
const std::vector<gd::String>& Direction::GetSpriteNames() const {
static std::vector<gd::String> spriteNames;
spriteNames.clear();
for (std::size_t i = 0; i < sprites.size(); ++i) {
spriteNames.push_back(sprites[i].GetImageName());
}
return spriteNames;
}
void Direction::RemoveSprite(std::size_t index) {
if (index < sprites.size()) sprites.erase(sprites.begin() + index);
}
@@ -132,7 +121,7 @@ void Direction::UnserializeFrom(const gd::SerializerElement& element) {
polygonElement.GetChild(k);
polygon.vertices.push_back(
gd::Vector2f(verticeElement.GetDoubleAttribute("x"),
sf::Vector2f(verticeElement.GetDoubleAttribute("x"),
verticeElement.GetDoubleAttribute("y")));
}

View File

@@ -72,13 +72,6 @@ class GD_CORE_API Direction {
*/
Sprite& GetSprite(std::size_t nb);
/**
* \brief Return a vector of references to sprite names.
*
* \return A vector of all sprite names references.
*/
const std::vector<gd::String>& GetSpriteNames() const;
/**
* \brief Check if the direction contains sprites.
*

View File

@@ -4,7 +4,7 @@
* reserved. This project is released under the MIT License.
*/
#include "Polygon2d.h"
#include "GDCore/Vector2.h"
#include <SFML/System/Vector2.hpp>
#include <cmath>
#include <iostream>
@@ -28,7 +28,7 @@ void Polygon2d::Move(float x, float y) {
}
void Polygon2d::ComputeEdges() const {
gd::Vector2f v1, v2;
sf::Vector2f v1, v2;
edges.clear();
for (std::size_t i = 0; i < vertices.size(); i++) {
@@ -62,8 +62,8 @@ bool Polygon2d::IsConvex() const {
return true;
}
gd::Vector2f Polygon2d::ComputeCenter() const {
gd::Vector2f center;
sf::Vector2f Polygon2d::ComputeCenter() const {
sf::Vector2f center;
for (std::size_t i = 0; i < vertices.size(); i++) {
center.x += vertices[i].x;
@@ -77,10 +77,10 @@ gd::Vector2f Polygon2d::ComputeCenter() const {
Polygon2d Polygon2d::CreateRectangle(float width, float height) {
Polygon2d rect;
rect.vertices.push_back(gd::Vector2f(-width / 2.0f, -height / 2.0f));
rect.vertices.push_back(gd::Vector2f(+width / 2.0f, -height / 2.0f));
rect.vertices.push_back(gd::Vector2f(+width / 2.0f, +height / 2.0f));
rect.vertices.push_back(gd::Vector2f(-width / 2.0f, +height / 2.0f));
rect.vertices.push_back(sf::Vector2f(-width / 2.0f, -height / 2.0f));
rect.vertices.push_back(sf::Vector2f(+width / 2.0f, -height / 2.0f));
rect.vertices.push_back(sf::Vector2f(+width / 2.0f, +height / 2.0f));
rect.vertices.push_back(sf::Vector2f(-width / 2.0f, +height / 2.0f));
return rect;
}

View File

@@ -5,7 +5,7 @@
*/
#ifndef GDCORE_POLYGON_H
#define GDCORE_POLYGON_H
#include "GDCore/Vector2.h"
#include <SFML/System/Vector2.hpp>
#include <vector>
/**
@@ -22,19 +22,19 @@ class GD_CORE_API Polygon2d {
Polygon2d(){};
virtual ~Polygon2d(){};
std::vector<gd::Vector2f> vertices; ///< The vertices composing the polygon
mutable std::vector<gd::Vector2f>
std::vector<sf::Vector2f> vertices; ///< The vertices composing the polygon
mutable std::vector<sf::Vector2f>
edges; ///< Edges. Can be computed from vertices using ComputeEdges()
/**
* \brief Get the vertices composing the polygon.
*/
std::vector<gd::Vector2f>& GetVertices() { return vertices; }
std::vector<sf::Vector2f>& GetVertices() { return vertices; }
/**
* \brief Get the vertices composing the polygon.
*/
const std::vector<gd::Vector2f>& GetVertices() const { return vertices; }
const std::vector<sf::Vector2f>& GetVertices() const { return vertices; }
/**
* \brief Moves each vertices from the given amount.
@@ -68,7 +68,7 @@ class GD_CORE_API Polygon2d {
/**
* \brief Return the position of the center of the polygon
*/
gd::Vector2f ComputeCenter() const;
sf::Vector2f ComputeCenter() const;
/** \name Tools
* Tool functions

View File

@@ -4,6 +4,7 @@
* reserved. This project is released under the MIT License.
*/
#include "GDCore/Extensions/Builtin/SpriteExtension/Sprite.h"
#include <SFML/Graphics/Sprite.hpp>
#include <iostream>
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"

View File

@@ -6,6 +6,7 @@
#ifndef SPRITE_H
#define SPRITE_H
#include <SFML/Graphics/Sprite.hpp>
#include <memory>
#include "GDCore/Extensions/Builtin/SpriteExtension/Point.h"
#include "GDCore/Extensions/Builtin/SpriteExtension/Polygon2d.h"

View File

@@ -33,7 +33,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
.SetCategoryFullName(_("General"));
obj.AddAction("Opacity",
_("Sprite opacity"),
_("Change sprite opacity"),
_("Change the opacity of a Sprite. 0 is fully transparent, 255 "
"is opaque (default)."),
_("the opacity"),
@@ -79,8 +79,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"is in 8 directions mode, the valid directions are 0..7"),
_("the direction"),
_("Direction"),
"res/actions/direction24_black.png",
"res/actions/direction_black.png")
"res/actions/direction24.png",
"res/actions/direction.png")
.SetHidden() // Hide as 8 direction is not supported officially in the
// interface.
.AddParameter("object", _("Object"), "Sprite")
@@ -140,8 +140,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"Rotate an object towards a position.",
"Rotate _PARAM0_ towards _PARAM1_;_PARAM2_",
_("Direction"),
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
"res/actions/direction24.png",
"res/actions/direction.png")
.AddParameter("object", _("Object to be rotated"), "Sprite")
.AddParameter("expression", _("X position"))
@@ -156,8 +156,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Modify the scale of the specified object."),
_("the scale"),
_("Size"),
"res/actions/scale24_black.png",
"res/actions/scale_black.png")
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
@@ -168,8 +168,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Modify the scale of the width of an object."),
_("the width's scale"),
_("Size"),
"res/actions/scaleWidth24_black.png",
"res/actions/scaleWidth_black.png")
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
@@ -180,8 +180,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Modify the scale of the height of an object."),
_("the height's scale"),
_("Size"),
"res/actions/scaleHeight24_black.png",
"res/actions/scaleHeight_black.png")
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
@@ -192,8 +192,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Change the width of a Sprite object."),
_("the width"),
_("Size"),
"res/actions/scaleWidth24_black.png",
"res/actions/scaleWidth_black.png")
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
@@ -204,8 +204,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Compare the width of a Sprite object."),
_("the width"),
_("Size"),
"res/conditions/scaleWidth24_black.png",
"res/conditions/scaleWidth_black.png")
"res/conditions/scaleWidth24.png",
"res/conditions/scaleWidth.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
@@ -216,8 +216,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Change the height of a Sprite object."),
_("the height"),
_("Size"),
"res/actions/scaleHeight24_black.png",
"res/actions/scaleHeight_black.png")
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardOperatorParameters("number")
@@ -228,8 +228,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Compare the height of a Sprite object."),
_("the height"),
_("Size"),
"res/conditions/scaleHeight24_black.png",
"res/conditions/scaleHeight_black.png")
"res/conditions/scaleHeight24.png",
"res/conditions/scaleHeight.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
@@ -240,8 +240,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Change the size of an object."),
_("Change the size of _PARAM0_: set to _PARAM1_x_PARAM2_"),
_("Size"),
"res/actions/scale24_black.png",
"res/actions/scale_black.png")
"res/actions/scale24.png",
"res/actions/scale.png")
.AddParameter("object", _("Object"))
.AddParameter("expression", _("Width"))
@@ -281,8 +281,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"from 0 to 7. Otherwise, the direction is in degrees."),
_("the direction"),
_("Direction"),
"res/conditions/direction24_black.png",
"res/conditions/direction_black.png")
"res/conditions/direction24.png",
"res/conditions/direction.png")
.SetHidden() // Hide as 8 direction is not supported officially in the
// interface.
.AddParameter("object", _("Object"), "Sprite")
@@ -330,8 +330,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Compare the scale of the width of an object."),
_("the width's scale"),
_("Size"),
"res/conditions/scaleWidth24_black.png",
"res/conditions/scaleWidth_black.png")
"res/conditions/scaleWidth24.png",
"res/conditions/scaleWidth.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
@@ -342,8 +342,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Compare the scale of the height of an object."),
_("the height's scale"),
_("Size"),
"res/conditions/scaleHeight24_black.png",
"res/conditions/scaleHeight_black.png")
"res/conditions/scaleHeight24.png",
"res/conditions/scaleHeight.png")
.AddParameter("object", _("Object"), "Sprite")
.UseStandardRelationalOperatorParameters("number")
@@ -449,8 +449,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
"Rotate an object towards another.",
"Rotate _PARAM0_ towards _PARAM1_",
_("Direction"),
"res/actions/rotate24_black.png",
"res/actions/rotate_black.png")
"res/actions/direction24.png",
"res/actions/direction.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPtr", "Rotate toward this object")
@@ -461,7 +461,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("X position of a point"),
_("X position of a point"),
_("Position"),
"res/actions/position_black.png")
"res/actions/position.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPointName", _("Name of the point"), "", true);
@@ -470,7 +470,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Y position of a point"),
_("Y position of a point"),
_("Position"),
"res/actions/position_black.png")
"res/actions/position.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPointName", _("Name of the point"), "", true);
@@ -479,7 +479,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("X position of a point"),
_("X position of a point"),
_("Position"),
"res/actions/position_black.png")
"res/actions/position.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPointName", _("Name of the point"));
@@ -488,7 +488,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Y position of a point"),
_("Y position of a point"),
_("Position"),
"res/actions/position_black.png")
"res/actions/position.png")
.AddParameter("object", _("Object"), "Sprite")
.AddParameter("objectPointName", _("Name of the point"));
@@ -497,7 +497,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Direction"),
_("Direction of the object"),
_("Direction"),
"res/actions/direction_black.png")
"res/actions/direction.png")
.SetHidden()
.AddParameter("object", _("Object"), "Sprite");
@@ -505,7 +505,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Direction"),
_("Direction of the object"),
_("Direction"),
"res/actions/direction_black.png")
"res/actions/direction.png")
.SetHidden() // Hide as 8 direction is not supported officially in the
// interface.
.AddParameter("object", _("Object"), "Sprite");
@@ -550,14 +550,14 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
_("Scale of the width of an object"),
_("Scale of the width of an object"),
_("Size"),
"res/actions/scaleWidth_black.png")
"res/actions/scaleWidth.png")
.AddParameter("object", _("Object"), "Sprite");
obj.AddExpression("ScaleY",
_("Scale of the height of an object"),
_("Scale of the height of an object"),
_("Size"),
"res/actions/scaleHeight_black.png")
"res/actions/scaleHeight.png")
.AddParameter("object", _("Object"), "Sprite");
obj.AddExpression("Opacity",

View File

@@ -6,6 +6,7 @@
#include "GDCore/Extensions/Builtin/SpriteExtension/SpriteObject.h"
#include <SFML/Graphics.hpp>
#include <algorithm>
#include "GDCore/CommonTools.h"
@@ -25,7 +26,8 @@ namespace gd {
Animation SpriteObject::badAnimation;
SpriteObject::SpriteObject() : updateIfNotVisible(false) {}
SpriteObject::SpriteObject(gd::String name_)
: Object(name_), updateIfNotVisible(false) {}
SpriteObject::~SpriteObject(){};

View File

@@ -36,11 +36,11 @@ namespace gd {
* \see gd::BuiltinExtensionsImplementer::ImplementsSpriteExtension
* \ingroup SpriteObjectExtension
*/
class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
class GD_CORE_API SpriteObject : public gd::Object {
public:
SpriteObject();
SpriteObject(gd::String name_);
virtual ~SpriteObject();
std::unique_ptr<gd::ObjectConfiguration> Clone() const override {
std::unique_ptr<gd::Object> Clone() const override {
return gd::make_unique<SpriteObject>(*this);
}

View File

@@ -21,20 +21,20 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
"Open source (MIT License)")
.SetExtensionHelpPath("" /*TODO: Add a documentation page for this */);
extension.AddInstructionOrExpressionGroupMetadata(_("Text manipulation"))
.SetIcon("res/actions/text24_black.png");
.SetIcon("res/actions/text24.png");
extension.AddStrExpression("NewLine",
_("Insert a new line"),
_("Insert a new line"),
"",
"res/conditions/toujours24_black.png");
"res/conditions/toujours24.png");
extension
.AddStrExpression("FromCodePoint",
_("Get character from code point"),
_("Get character from code point"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("expression", _("Code point"));
@@ -43,7 +43,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Uppercase a text"),
_("Uppercase a text"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"));
@@ -52,7 +52,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Lowercase a text"),
_("Lowercase a text"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"));
@@ -61,7 +61,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Get a portion of a text"),
_("Get a portion of a text"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("expression",
@@ -74,7 +74,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Get a character from a text"),
_("Get a character from a text"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter(
@@ -86,7 +86,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Repeat a text"),
_("Repeat a text"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text to repeat"))
.AddParameter("expression", _("Repetition count"));
@@ -96,7 +96,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Length of a text"),
_("Length of a text"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"));
@@ -106,7 +106,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Search in a text (return the position of the result or "
"-1 if not found)"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"));
@@ -117,7 +117,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
"Search in a text from the end (return the position of "
"the result or -1 if not found)",
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))
@@ -131,7 +131,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
"the result, from the beginning of the string, or -1 if not "
"found)"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"));
@@ -142,7 +142,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
_("Search in a text, starting from a position (return the "
"position of the result or -1 if not found)"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))
@@ -157,7 +157,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
"Search in a text from the end, starting from a position (return "
"the position of the result or -1 if not found)",
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))
@@ -175,7 +175,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
" the position of the result, from the beginning of the string, or "
"-1 if not found)"),
"",
"res/conditions/toujours24_black.png")
"res/conditions/toujours24.png")
.AddParameter("string", _("Text"))
.AddParameter("string", _("Text to search for"))

View File

@@ -20,8 +20,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
"for slow motion effects).",
"Florian Rival",
"Open source (MIT License)")
.SetExtensionHelpPath("/all-features/timers-and-time");
extension.AddInstructionOrExpressionGroupMetadata(_("Timers and time"))
.SetExtensionHelpPath("/all-features/timers");
extension.AddInstructionOrExpressionGroupMetadata(
_("Timers and time")
)
.SetIcon("res/conditions/timer24.png");
// Deprecated and replaced by CompareTimer
@@ -136,9 +138,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
extension
.AddAction("ChangeTimeScale",
_("Time scale"),
_("Change time scale"),
_("Change the time scale of the scene."),
_("Set the time scale of the scene to _PARAM1_"),
"",
"res/actions/time24.png",
"res/actions/time.png")
@@ -146,18 +149,6 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsTimeExtension(
.AddParameter("expression",
_("Scale (1: Default, 2: 2x faster, 0.5: 2x slower...)"));
extension
.AddAction("Wait",
_("Wait X seconds (experimental)"),
_("Waits a number of seconds before running "
"the next actions (and sub-events)."),
_("Wait _PARAM0_ seconds"),
"",
"res/timer_black.svg",
"res/timer_black.svg")
.AddParameter("expression", "Time to wait in seconds")
.SetHelpPath("/all-features/timers-and-time/wait-action");
extension
.AddExpression("TimeDelta",
_("Time elapsed since the last frame"),

View File

@@ -55,7 +55,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetWindowMargins",
_("Window's margins"),
_("Change the window's margins"),
_("This action changes the margins, in pixels, between the "
"game frame and the window borders."),
_("Set margins of game window to "
@@ -71,7 +71,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetGameResolutionSize",
_("Game resolution"),
_("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."),
@@ -117,7 +117,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetGameResolutionResizeMode",
_("Game resolution resize mode"),
_("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."),
@@ -153,7 +153,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetWindowIcon",
_("Window's icon"),
_("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."),
"",
@@ -164,7 +164,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsWindowExtension(
extension
.AddAction("SetWindowTitle",
_("Window's title"),
_("Change the window's title"),
_("This action changes the title of the game's window."),
_("Change window title to _PARAM1_"),
"",

View File

@@ -14,14 +14,12 @@
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Tools/Log.h"
namespace gd {
BehaviorMetadata::BehaviorMetadata(
const gd::String& extensionNamespace_,
const gd::String& nameWithNamespace,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& defaultName_,
const gd::String& description_,
@@ -31,50 +29,21 @@ BehaviorMetadata::BehaviorMetadata(
std::shared_ptr<gd::Behavior> instance_,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance_)
: extensionNamespace(extensionNamespace_),
className(className_),
iconFilename(icon24x24),
instance(instance_),
sharedDatasInstance(sharedDatasInstance_),
isEventBased(false) {
sharedDatasInstance(sharedDatasInstance_) {
#if defined(GD_IDE_ONLY)
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
SetDefaultName(gd::String(defaultName_));
SetGroup(group_);
className = className_;
iconFilename = icon24x24;
#endif
if (!instance) {
gd::LogFatalError(
"Trying to create a BehaviorMetadata that has no "
"behavior. This will crash - please double check that the "
"BehaviorMetadata is valid for: " + nameWithNamespace);
}
if (instance) instance->SetTypeName(nameWithNamespace);
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(nameWithNamespace);
if (instance) instance->SetTypeName(name_);
if (sharedDatasInstance) sharedDatasInstance->SetTypeName(name_);
}
BehaviorMetadata::BehaviorMetadata(
const gd::String& extensionNamespace,
const gd::String& nameWithNamespace,
const gd::String& fullname_,
const gd::String& defaultName_,
const gd::String& description_,
const gd::String& group_,
const gd::String& icon24x24_): BehaviorMetadata(
extensionNamespace,
nameWithNamespace,
fullname_,
defaultName_,
description_,
group_,
icon24x24_,
// Class name is the name, actually unused
defaultName_,
// It is only used to get the name for GetName.
gd::make_unique<gd::Behavior>("", nameWithNamespace),
nullptr){
isEventBased = true;
};
gd::InstructionMetadata& BehaviorMetadata::AddCondition(
const gd::String& name,
const gd::String& fullname,
@@ -83,6 +52,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddCondition(
const gd::String& group,
const gd::String& icon,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
gd::String nameWithNamespace =
extensionNamespace.empty() ? name : extensionNamespace + name;
conditionsInfos[nameWithNamespace] = InstructionMetadata(extensionNamespace,
@@ -96,6 +66,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddCondition(
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
return conditionsInfos[nameWithNamespace];
#endif
}
gd::InstructionMetadata& BehaviorMetadata::AddAction(
@@ -106,6 +77,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddAction(
const gd::String& group,
const gd::String& icon,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
gd::String nameWithNamespace =
extensionNamespace.empty() ? name : extensionNamespace + name;
actionsInfos[nameWithNamespace] = InstructionMetadata(extensionNamespace,
@@ -119,6 +91,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddAction(
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
return actionsInfos[nameWithNamespace];
#endif
}
gd::InstructionMetadata& BehaviorMetadata::AddScopedCondition(
@@ -129,6 +102,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedCondition(
const gd::String& group,
const gd::String& icon,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
gd::String nameWithNamespace =
GetName() + gd::PlatformExtension::GetNamespaceSeparator() + name;
conditionsInfos[nameWithNamespace] = InstructionMetadata(extensionNamespace,
@@ -142,6 +116,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedCondition(
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
return conditionsInfos[nameWithNamespace];
#endif
}
gd::InstructionMetadata& BehaviorMetadata::AddScopedAction(
@@ -152,6 +127,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedAction(
const gd::String& group,
const gd::String& icon,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
gd::String nameWithNamespace =
GetName() + gd::PlatformExtension::GetNamespaceSeparator() + name;
actionsInfos[nameWithNamespace] = InstructionMetadata(extensionNamespace,
@@ -165,6 +141,7 @@ gd::InstructionMetadata& BehaviorMetadata::AddScopedAction(
.SetHelpPath(GetHelpPath())
.SetIsBehaviorInstruction();
return actionsInfos[nameWithNamespace];
#endif
}
gd::ExpressionMetadata& BehaviorMetadata::AddExpression(
@@ -173,6 +150,7 @@ gd::ExpressionMetadata& BehaviorMetadata::AddExpression(
const gd::String& description,
const gd::String& group,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
// Be careful, behaviors expression do not have namespace (not necessary as
// we refer to the behavior name in the expression).
expressionsInfos[name] = ExpressionMetadata("number",
@@ -184,6 +162,7 @@ gd::ExpressionMetadata& BehaviorMetadata::AddExpression(
smallicon)
.SetHelpPath(GetHelpPath());
return expressionsInfos[name];
#endif
}
gd::ExpressionMetadata& BehaviorMetadata::AddStrExpression(
@@ -192,6 +171,7 @@ gd::ExpressionMetadata& BehaviorMetadata::AddStrExpression(
const gd::String& description,
const gd::String& group,
const gd::String& smallicon) {
#if defined(GD_IDE_ONLY)
// Be careful, behaviors expression do not have namespace (not necessary as
// we refer to the behavior name in the expression).
strExpressionsInfos[name] = ExpressionMetadata("string",
@@ -203,6 +183,7 @@ gd::ExpressionMetadata& BehaviorMetadata::AddStrExpression(
smallicon)
.SetHelpPath(GetHelpPath());
return strExpressionsInfos[name];
#endif
}
gd::MultipleInstructionMetadata BehaviorMetadata::AddExpressionAndCondition(
@@ -307,6 +288,7 @@ BehaviorMetadata::AddExpressionAndConditionAndAction(
expression, condition, action);
}
#if defined(GD_IDE_ONLY)
gd::InstructionMetadata& BehaviorMetadata::AddDuplicatedAction(
const gd::String& newActionName, const gd::String& copiedActionName) {
gd::String newNameWithNamespace = extensionNamespace + newActionName;
@@ -374,44 +356,49 @@ gd::ExpressionMetadata& BehaviorMetadata::AddDuplicatedStrExpression(
return strExpressionsInfos[newNameWithNamespace];
}
#endif
BehaviorMetadata& BehaviorMetadata::SetFullName(const gd::String& fullname_) {
#if defined(GD_IDE_ONLY)
fullname = fullname_;
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::SetDefaultName(
const gd::String& defaultName_) {
#if defined(GD_IDE_ONLY)
defaultName = defaultName_;
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::SetDescription(
const gd::String& description_) {
#if defined(GD_IDE_ONLY)
description = description_;
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::SetGroup(const gd::String& group_) {
#if defined(GD_IDE_ONLY)
group = group_;
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::SetIncludeFile(
const gd::String& includeFile) {
#if defined(GD_IDE_ONLY)
includeFiles.clear();
includeFiles.push_back(includeFile);
#endif
return *this;
}
BehaviorMetadata& BehaviorMetadata::AddIncludeFile(
const gd::String& includeFile) {
#if defined(GD_IDE_ONLY)
if (std::find(includeFiles.begin(), includeFiles.end(), includeFile) ==
includeFiles.end())
includeFiles.push_back(includeFile);
return *this;
}
BehaviorMetadata& BehaviorMetadata::AddRequiredFile(
const gd::String& requiredFile) {
if (std::find(requiredFiles.begin(), requiredFiles.end(), requiredFile) ==
requiredFiles.end())
requiredFiles.push_back(requiredFile);
#endif
return *this;
}
@@ -420,25 +407,13 @@ const gd::String& BehaviorMetadata::GetName() const {
}
gd::Behavior& BehaviorMetadata::Get() const {
if (isEventBased) {
gd::LogFatalError("Error: Event-based behaviors don't have blueprint. "
"This method should not never be called.");
}
if (!instance) {
if (!instance)
gd::LogFatalError(
"Trying to get a behavior from a BehaviorMetadata that has no "
"behavior. This will crash - please double check that the "
"BehaviorMetadata is valid for: " + className);
}
"BehaviorMetadata is valid.");
return *instance;
}
gd::BehaviorsSharedData* BehaviorMetadata::GetSharedDataInstance() const {
if (isEventBased) {
gd::LogFatalError("Error: Event-based behaviors don't have blueprint. "
"This method should not never be called.");
}
return sharedDatasInstance.get();
}
} // namespace gd

View File

@@ -29,7 +29,7 @@ class GD_CORE_API BehaviorMetadata {
public:
BehaviorMetadata(
const gd::String& extensionNamespace,
const gd::String& nameWithNamespace,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& defaultName_,
const gd::String& description_,
@@ -38,21 +38,6 @@ class GD_CORE_API BehaviorMetadata {
const gd::String& className_,
std::shared_ptr<gd::Behavior> instance,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
/**
* \brief Construct a behavior metadata, without "blueprint" behavior.
*
* \note This is used by events based behaviors.
*/
BehaviorMetadata(
const gd::String& extensionNamespace,
const gd::String& nameWithNamespace,
const gd::String& fullname_,
const gd::String& defaultName_,
const gd::String& description_,
const gd::String& group_,
const gd::String& icon24x24_);
BehaviorMetadata(){};
virtual ~BehaviorMetadata(){};
@@ -210,13 +195,6 @@ class GD_CORE_API BehaviorMetadata {
*/
BehaviorMetadata& AddIncludeFile(const gd::String& includeFile);
/**
* \brief Add a file to the already existing required files.
* \note These files are required for the behavior to work,
* but they are not executable.
*/
BehaviorMetadata& AddRequiredFile(const gd::String& requiredFile);
/**
* Get the help path of the behavior, relative to the GDevelop documentation
* root.
@@ -261,20 +239,16 @@ class GD_CORE_API BehaviorMetadata {
/**
* \brief Return the associated gd::Behavior, handling behavior contents.
*
* \note Returns a dumb Behavior for events based behaviors as CustomBehavior
* are using EventBasedBehavior.
*/
gd::Behavior& Get() const;
/**
* \brief Return the associated gd::BehaviorsSharedData, handling behavior
* shared data, if any (nullptr if none).
*
* \note Returns nullptr for events based behaviors as they don't declare
* shared data yet.
*/
gd::BehaviorsSharedData* GetSharedDataInstance() const;
gd::BehaviorsSharedData* GetSharedDataInstance() const {
return sharedDatasInstance.get();
}
/**
* \brief Return a reference to a map containing the names of the actions
@@ -297,29 +271,30 @@ class GD_CORE_API BehaviorMetadata {
*/
std::map<gd::String, gd::ExpressionMetadata>& GetAllStrExpressions() { return strExpressionsInfos; };
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
std::map<gd::String, gd::ExpressionMetadata> strExpressionsInfos;
std::vector<gd::String> includeFiles;
std::vector<gd::String> requiredFiles;
gd::String className;
#endif
private:
gd::String extensionNamespace;
gd::String helpPath;
#if defined(GD_IDE_ONLY)
gd::String fullname;
gd::String defaultName;
gd::String description;
gd::String group;
gd::String iconFilename;
gd::String objectType;
#endif
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
std::shared_ptr<gd::Behavior> instance;
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance;
bool isEventBased;
};
} // namespace gd

View File

@@ -8,7 +8,6 @@
#include <functional>
#include <map>
#include <memory>
#include <algorithm>
#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"

View File

@@ -6,7 +6,6 @@
#ifndef INSTRUCTIONMETADATA_H
#define INSTRUCTIONMETADATA_H
#include <algorithm>
#include <functional>
#include <map>
#include <memory>
@@ -99,23 +98,6 @@ class GD_CORE_API InstructionMetadata {
return *this;
}
/**
* Check if the instruction is asynchronous - it will be running in the
* background, executing the instructions following it before the frame after
* it resolved.
*/
bool IsAsync() const {
return !codeExtraInformation.asyncFunctionCallName.empty();
}
/**
* Check if the instruction asynchronicity is optional. If it is, it can either
* be used synchronously or asynchronously, with one function for each.
*/
bool IsOptionallyAsync() const {
return IsAsync() && !codeExtraInformation.functionCallName.empty();
}
/**
* Notify that the instruction can have sub instructions.
*/
@@ -220,6 +202,18 @@ class GD_CORE_API InstructionMetadata {
return *this;
};
/**
* \brief Consider that the parameter is harder for a user to understand
* and not necessary for common usages.
*
* \see AddParameter
*/
InstructionMetadata &MarkParameterAsAdvanced() {
if (!parameters.empty())
parameters.back().MarkAsAdvanced();
return *this;
};
/**
* \brief Add the default parameters for an instruction manipulating the
* specified type ("string", "number") with the default operators.
@@ -319,26 +313,14 @@ class GD_CORE_API InstructionMetadata {
virtual ~ExtraInformation(){};
/**
* Set the name of the function which will be called in the generated code.
* \param functionName the name of the function to call.
* Set the function name which will be used when generating the code.
* \param functionName the name of the function to call
*/
ExtraInformation &SetFunctionName(const gd::String &functionName_) {
functionCallName = functionName_;
return *this;
}
/**
* Set the name of the function, doing asynchronous work, which will be called in
* the generated code. This function should return an asynchronous task
* (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
*
* \param functionName the name of the function doing asynchronous work to call.
*/
ExtraInformation &SetAsyncFunctionName(const gd::String &functionName_) {
asyncFunctionCallName = functionName_;
return *this;
}
/**
* Declare if the instruction being declared is somewhat manipulating in a
* standard way.
@@ -361,12 +343,12 @@ class GD_CORE_API InstructionMetadata {
* _("the string"),
* _("Text"),
* "CppPlatform/Extensions/text24.png",
* "CppPlatform/Extensions/text_black.png");
* "CppPlatform/Extensions/text.png");
*
* .AddParameter("object", _("Object"), "Text", false)
* .AddParameter("operator", _("Modification operator"), "string")
* .AddParameter("string", _("String"))
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString");
* .SetFunctionName("SetString").SetManipulatedType("string").SetGetter("GetString").SetIncludeFile("MyExtension/TextObject.h");
*
* DECLARE_END_OBJECT_ACTION()
* \endcode
@@ -434,7 +416,6 @@ class GD_CORE_API InstructionMetadata {
bool HasCustomCodeGenerator() const { return hasCustomCodeGenerator; }
gd::String functionCallName;
gd::String asyncFunctionCallName;
gd::String type;
AccessType accessType;
gd::String optionalAssociatedInstruction;
@@ -467,26 +448,15 @@ class GD_CORE_API InstructionMetadata {
}
/**
* Set the name of the function which will be called in the generated code.
* \param functionName the name of the function to call.
* \brief Set the function that should be called when generating the source
* code from events.
* \param functionName the name of the function to call
* \note Shortcut for `codeExtraInformation.SetFunctionName`.
*/
ExtraInformation &SetFunctionName(const gd::String &functionName) {
return codeExtraInformation.SetFunctionName(functionName);
}
/**
* Set the name of the function, doing asynchronous work, which will be called in
* the generated code. This function should return an asynchronous task
* (i.e: `gdjs.AsyncTask` in the JavaScript runtime).
*
* \param functionName the name of the function doing asynchronous work to call.
* \note Shortcut for `codeExtraInformation.SetAsyncFunctionName`.
*/
ExtraInformation &SetAsyncFunctionName(const gd::String &functionName) {
return codeExtraInformation.SetAsyncFunctionName(functionName);
}
std::vector<ParameterMetadata> parameters;
private:

View File

@@ -13,9 +13,7 @@
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
#include "GDCore/String.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
using namespace std;
@@ -32,9 +30,12 @@ ExtensionAndMetadata<BehaviorMetadata>
MetadataProvider::GetExtensionAndBehaviorMetadata(const gd::Platform& platform,
gd::String behaviorType) {
for (auto& extension : platform.GetAllPlatformExtensions()) {
if (extension->HasBehavior(behaviorType))
return ExtensionAndMetadata<BehaviorMetadata>(
*extension, extension->GetBehaviorMetadata(behaviorType));
auto behaviorTypes = extension->GetBehaviorsTypes();
for (std::size_t j = 0; j < behaviorTypes.size(); ++j) {
if (behaviorTypes[j] == behaviorType)
return ExtensionAndMetadata<BehaviorMetadata>(
*extension, extension->GetBehaviorMetadata(behaviorType));
}
}
return ExtensionAndMetadata<BehaviorMetadata>(badExtension, badBehaviorMetadata);
@@ -201,7 +202,8 @@ MetadataProvider::GetExtensionAndBehaviorExpressionMetadata(
const gd::Platform& platform, gd::String autoType, gd::String exprType) {
auto& extensions = platform.GetAllPlatformExtensions();
for (auto& extension : extensions) {
if (extension->HasBehavior(autoType)) {
const auto& autos = extension->GetBehaviorsTypes();
if (find(autos.begin(), autos.end(), autoType) != autos.end()) {
const auto& allAutoExpressions =
extension->GetAllExpressionsForBehavior(autoType);
if (allAutoExpressions.find(exprType) != allAutoExpressions.end())
@@ -290,7 +292,8 @@ MetadataProvider::GetExtensionAndBehaviorStrExpressionMetadata(
const gd::Platform& platform, gd::String autoType, gd::String exprType) {
auto& extensions = platform.GetAllPlatformExtensions();
for (auto& extension : extensions) {
if (extension->HasBehavior(autoType)) {
const auto& autos = extension->GetBehaviorsTypes();
if (find(autos.begin(), autos.end(), autoType) != autos.end()) {
const auto& allBehaviorStrExpressions =
extension->GetAllStrExpressionsForBehavior(autoType);
if (allBehaviorStrExpressions.find(exprType) !=
@@ -347,30 +350,28 @@ const gd::ExpressionMetadata& MetadataProvider::GetAnyExpressionMetadata(
const gd::Platform& platform, gd::String exprType) {
const auto& numberExpressionMetadata =
GetExpressionMetadata(platform, exprType);
if (&numberExpressionMetadata != &badExpressionMetadata) {
return numberExpressionMetadata;
}
const auto& stringExpressionMetadata =
GetStrExpressionMetadata(platform, exprType);
if (&stringExpressionMetadata != &badExpressionMetadata) {
return stringExpressionMetadata;
}
return badExpressionMetadata;
return &numberExpressionMetadata != &badExpressionMetadata
? numberExpressionMetadata
: &stringExpressionMetadata != &badExpressionMetadata
? stringExpressionMetadata
: badExpressionMetadata;
}
const gd::ExpressionMetadata& MetadataProvider::GetObjectAnyExpressionMetadata(
const gd::Platform& platform, gd::String objectType, gd::String exprType) {
const auto& numberExpressionMetadata =
GetObjectExpressionMetadata(platform, objectType, exprType);
if (&numberExpressionMetadata != &badExpressionMetadata) {
return numberExpressionMetadata;
}
const auto& stringExpressionMetadata =
GetObjectStrExpressionMetadata(platform, objectType, exprType);
if (&stringExpressionMetadata != &badExpressionMetadata) {
return stringExpressionMetadata;
}
return badExpressionMetadata;
return &numberExpressionMetadata != &badExpressionMetadata
? numberExpressionMetadata
: &stringExpressionMetadata != &badExpressionMetadata
? stringExpressionMetadata
: badExpressionMetadata;
}
const gd::ExpressionMetadata&
@@ -379,98 +380,14 @@ MetadataProvider::GetBehaviorAnyExpressionMetadata(const gd::Platform& platform,
gd::String exprType) {
const auto& numberExpressionMetadata =
GetBehaviorExpressionMetadata(platform, autoType, exprType);
if (&numberExpressionMetadata != &badExpressionMetadata) {
return numberExpressionMetadata;
}
const auto& stringExpressionMetadata =
GetBehaviorStrExpressionMetadata(platform, autoType, exprType);
if (&stringExpressionMetadata != &badExpressionMetadata) {
return stringExpressionMetadata;
}
return badExpressionMetadata;
}
const gd::ExpressionMetadata& MetadataProvider::GetFunctionCallMetadata(
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& node) {
if (!node.behaviorName.empty()) {
gd::String behaviorType =
GetTypeOfBehavior(globalObjectsContainer, objectsContainer, node.behaviorName);
return MetadataProvider::GetBehaviorAnyExpressionMetadata(
platform, behaviorType, node.functionName);
}
else if (!node.objectName.empty()) {
gd::String objectType =
GetTypeOfObject(globalObjectsContainer, objectsContainer, node.objectName);
return MetadataProvider::GetObjectAnyExpressionMetadata(
platform, objectType, node.functionName);
}
return MetadataProvider::GetAnyExpressionMetadata(platform, node.functionName);
}
const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& functionCall,
ExpressionNode& parameter) {
int parameterIndex = -1;
for (int i = 0; i < functionCall.parameters.size(); i++) {
if (functionCall.parameters.at(i).get() == &parameter) {
parameterIndex = i;
break;
}
}
if (parameterIndex < 0) {
return nullptr;
}
return MetadataProvider::GetFunctionCallParameterMetadata(
platform,
globalObjectsContainer,
objectsContainer,
functionCall,
parameterIndex);
}
const gd::ParameterMetadata* MetadataProvider::GetFunctionCallParameterMetadata(
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& functionCall,
int parameterIndex) {
// Search the parameter metadata index skipping invisible ones.
size_t visibleParameterIndex = 0;
size_t metadataParameterIndex =
ExpressionParser2::WrittenParametersFirstIndex(
functionCall.objectName, functionCall.behaviorName);
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
platform, globalObjectsContainer, objectsContainer, functionCall);
if (IsBadExpressionMetadata(metadata)) {
return nullptr;
}
// TODO use a badMetadata instead of a nullptr?
const gd::ParameterMetadata* parameterMetadata = nullptr;
while (metadataParameterIndex <
metadata.parameters.size()) {
if (!metadata.parameters[metadataParameterIndex]
.IsCodeOnly()) {
if (visibleParameterIndex == parameterIndex) {
parameterMetadata = &metadata.parameters[metadataParameterIndex];
}
visibleParameterIndex++;
}
metadataParameterIndex++;
}
const int visibleParameterCount = visibleParameterIndex;
// It can be null if there are too many parameters in the expression, this text node is
// not actually linked to a parameter expected by the function call.
return parameterMetadata;
return &numberExpressionMetadata != &badExpressionMetadata
? numberExpressionMetadata
: &stringExpressionMetadata != &badExpressionMetadata
? stringExpressionMetadata
: badExpressionMetadata;
}
MetadataProvider::~MetadataProvider() {}

View File

@@ -15,8 +15,6 @@ class ExpressionMetadata;
class ExpressionMetadata;
class Platform;
class PlatformExtension;
struct FunctionCallNode;
struct ExpressionNode;
} // namespace gd
namespace gd {
@@ -236,26 +234,6 @@ class GD_CORE_API MetadataProvider {
static const gd::ExpressionMetadata& GetObjectAnyExpressionMetadata(
const gd::Platform& platform, gd::String objectType, gd::String exprType);
static const gd::ExpressionMetadata& GetFunctionCallMetadata(
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& node);
static const gd::ParameterMetadata* GetFunctionCallParameterMetadata(
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& functionCall,
ExpressionNode& parameter);
static const gd::ParameterMetadata* GetFunctionCallParameterMetadata(
const gd::Platform& platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
FunctionCallNode& functionCall,
int parameterIndex);
/**
* Get information about an expression from its type.
* Works for behavior expressions.

View File

@@ -91,6 +91,18 @@ class GD_CORE_API MultipleInstructionMetadata {
return *this;
};
/**
* \brief Consider that the parameter is harder for a user to understand
* and not necessary for common usages.
*
* \see AddParameter
*/
MultipleInstructionMetadata &MarkParameterAsAdvanced() {
if (condition) condition->MarkParameterAsAdvanced();
if (action) action->MarkParameterAsAdvanced();
return *this;
};
/**
* \see gd::InstructionMetadata::SetHidden
*/

View File

@@ -14,7 +14,6 @@
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Log.h"
namespace gd {
@@ -23,40 +22,30 @@ ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24,
std::shared_ptr<gd::ObjectConfiguration> blueprintObject_)
: ObjectMetadata(extensionNamespace_,
name_,
fullname_,
description_,
icon24x24,
[blueprintObject_]() -> std::unique_ptr<gd::ObjectConfiguration> {
if (blueprintObject_ == std::shared_ptr<gd::ObjectConfiguration>()) {
gd::LogFatalError(
"Error: Unable to create object. Have you declared an extension "
"(or ObjectMetadata) without specifying an object as blueprint?");
std::shared_ptr<gd::Object> blueprintObject_)
: extensionNamespace(extensionNamespace_),
blueprintObject(blueprintObject_) {
name = name_;
#if defined(GD_IDE_ONLY)
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
iconFilename = icon24x24;
#endif
createFunPtr =
[blueprintObject_](gd::String name) -> std::unique_ptr<gd::Object> {
if (blueprintObject_ == std::shared_ptr<gd::Object>()) {
std::cout
<< "Error: Unable to create object. Have you declared an extension "
"(or ObjectMetadata) without specifying an object as blueprint?"
<< std::endl;
return nullptr;
}
return blueprintObject_->Clone();
}) {
blueprintObject = blueprintObject_;
}
ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24)
: ObjectMetadata(extensionNamespace_,
name_,
fullname_,
description_,
icon24x24,
[]() -> std::unique_ptr<gd::ObjectConfiguration> {
gd::LogFatalError(
"Error: Event-based objects don't have blueprint. "
"This method should not never be called.");
return nullptr;
}) {}
std::unique_ptr<gd::Object> newObject = blueprintObject_->Clone();
newObject->SetName(name);
return newObject;
};
}
ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
@@ -64,12 +53,14 @@ ObjectMetadata::ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& description_,
const gd::String& icon24x24,
CreateFunPtr createFunPtrP)
: name(name_),
iconFilename(icon24x24),
createFunPtr(createFunPtrP),
extensionNamespace(extensionNamespace_) {
: extensionNamespace(extensionNamespace_) {
name = name_;
#if defined(GD_IDE_ONLY)
SetFullName(gd::String(fullname_));
SetDescription(gd::String(description_));
iconFilename = icon24x24;
#endif
createFunPtr = createFunPtrP;
}
gd::InstructionMetadata& ObjectMetadata::AddCondition(

View File

@@ -13,7 +13,6 @@
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/String.h"
namespace gd {
class InstructionMetadata;
@@ -21,7 +20,7 @@ class MultipleInstructionMetadata;
class ExpressionMetadata;
} // namespace gd
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)>
CreateFunPtr;
namespace gd {
@@ -43,17 +42,7 @@ class GD_CORE_API ObjectMetadata {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24_,
std::shared_ptr<gd::ObjectConfiguration> blueprintObject_);
/**
* \brief Construct an object metadata, without "blueprint" object
*
* \note This is used by events based objects.
*/
ObjectMetadata(const gd::String& extensionNamespace_,
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon24x24_);
std::shared_ptr<gd::Object> blueprintObject_);
/**
* \brief Construct an object metadata, with a function that will be called
@@ -315,12 +304,10 @@ class GD_CORE_API ObjectMetadata {
gd::String categoryFullName;
std::set<gd::String> unsupportedBaseObjectCapabilities;
std::shared_ptr<gd::ObjectConfiguration>
std::shared_ptr<gd::Object>
blueprintObject; ///< The "blueprint" object to be copied when a new
///< object is asked. Can be null in case a creation
///< function is passed or for events based objects
///< (CustomObject are using EventBasedObject, they
///< don't need blueprints).
///< function is passed.
};
} // namespace gd

View File

@@ -10,7 +10,7 @@
namespace gd {
ParameterMetadata::ParameterMetadata() : optional(false), codeOnly(false) {}
ParameterMetadata::ParameterMetadata() : optional(false), codeOnly(false), usageComplexity(5) {}
void ParameterMetadata::SerializeTo(SerializerElement& element) const {
element.SetAttribute("type", type);
@@ -21,6 +21,7 @@ void ParameterMetadata::SerializeTo(SerializerElement& element) const {
element.SetAttribute("codeOnly", codeOnly);
element.SetAttribute("defaultValue", defaultValue);
element.SetAttribute("name", name);
element.SetAttribute("usageComplexity", usageComplexity);
}
void ParameterMetadata::UnserializeFrom(const SerializerElement& element) {
@@ -33,20 +34,7 @@ void ParameterMetadata::UnserializeFrom(const SerializerElement& element) {
codeOnly = element.GetBoolAttribute("codeOnly");
defaultValue = element.GetStringAttribute("defaultValue");
name = element.GetStringAttribute("name");
usageComplexity = element.GetIntAttribute("usageComplexity");
}
// TODO factorize in a file with an enum and helpers?
const gd::String ParameterMetadata::numberType = "number";
const gd::String ParameterMetadata::stringType = "string";
const gd::String &ParameterMetadata::GetExpressionValueType(const gd::String &parameterType) {
if (parameterType == "number" || gd::ParameterMetadata::IsExpression("number", parameterType)) {
return ParameterMetadata::numberType;
}
if (parameterType == "string" || gd::ParameterMetadata::IsExpression("string", parameterType)) {
return ParameterMetadata::stringType;
}
return parameterType;
}
} // namespace gd

View File

@@ -152,16 +152,46 @@ class GD_CORE_API ParameterMetadata {
}
/**
* \brief Return true if the type of the parameter is representing one object
* (or more, i.e: an object group).
* \brief Consider that the parameter is easy for a user to understand.
*/
ParameterMetadata &MarkAsSimple() {
usageComplexity = 2;
return *this;
}
/**
* \brief Consider that the parameter is harder for a user to understand
* than a normal parameter.
*/
ParameterMetadata &MarkAsAdvanced() {
usageComplexity = 7;
return *this;
}
/**
* \brief Consider that the parameter is complex for a user to understand.
*/
ParameterMetadata &MarkAsComplex() {
usageComplexity = 9;
return *this;
}
/**
* \brief Return the usage complexity of this parameter for the user,
* from 0 (simple&easy to use) to 10 (complex to understand).
*/
int GetUsageComplexity() const { return usageComplexity; }
/**
* \brief Return true if the type of the parameter is "object", "objectPtr" or
* "objectList".
*
* \see gd::ParameterMetadata::GetType
*/
static bool IsObject(const gd::String &parameterType) {
return parameterType == "object" || parameterType == "objectPtr" ||
parameterType == "objectList" ||
parameterType == "objectListOrEmptyIfJustDeclared" ||
parameterType == "objectListOrEmptyWithoutPicking";
parameterType == "objectListWithoutPicking";
}
/**
@@ -207,15 +237,6 @@ class GD_CORE_API ParameterMetadata {
return false;
}
/**
* \brief Return the expression type from the parameter type.
* Declinations of "number" and "string" types (like "forceMultiplier" or
* "sceneName") are replaced by "number" and "string".
*/
static const gd::String &GetExpressionValueType(const gd::String &parameterType);
static const gd::String numberType;
static const gd::String stringType;
/** \name Serialization
*/
///@{
@@ -245,6 +266,8 @@ class GD_CORE_API ParameterMetadata {
///< optional parameter is empty.
gd::String name; ///< The name of the parameter to be used in code
///< generation. Optional.
int usageComplexity; ///< Evaluate the parameter from 0 (simple&easy to
///< use) to 10 (complex to understand)
};
} // namespace gd

View File

@@ -14,7 +14,7 @@
namespace gd {
void ParameterMetadataTools::ParametersToObjectsContainer(
const gd::Project& project,
gd::Project& project,
const std::vector<gd::ParameterMetadata>& parameters,
gd::ObjectsContainer& outputObjectsContainer) {
outputObjectsContainer.GetObjects().clear();
@@ -59,13 +59,13 @@ void ParameterMetadataTools::IterateOverParameters(
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& parameterValue,
const gd::String& lastObjectName)> fn) {
IterateOverParametersWithIndex(
parameters,
parametersMetadata,
[&fn](const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName) {
fn(parameterMetadata, parameterValue, lastObjectName);
@@ -76,17 +76,17 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName)> fn) {
gd::String lastObjectName = "";
for (std::size_t pNb = 0; pNb < parametersMetadata.size(); ++pNb) {
const gd::ParameterMetadata& parameterMetadata = parametersMetadata[pNb];
const gd::Expression& parameterValue =
const gd::String& parameterValue =
pNb < parameters.size() ? parameters[pNb].GetPlainString() : "";
const gd::Expression& parameterValueOrDefault =
parameterValue.GetPlainString().empty() && parameterMetadata.optional
? Expression(parameterMetadata.GetDefaultValue())
const gd::String& parameterValueOrDefault =
parameterValue.empty() && parameterMetadata.optional
? parameterMetadata.GetDefaultValue()
: parameterValue;
fn(parameterMetadata, parameterValueOrDefault, pNb, lastObjectName);
@@ -97,7 +97,7 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
// Search "lastObjectName" in the codebase for other place where this
// convention is enforced.
if (gd::ParameterMetadata::IsObject(parameterMetadata.GetType()))
lastObjectName = parameterValueOrDefault.GetPlainString();
lastObjectName = parameterValueOrDefault;
}
}

View File

@@ -19,7 +19,7 @@ namespace gd {
class GD_CORE_API ParameterMetadataTools {
public:
static void ParametersToObjectsContainer(
const gd::Project& project,
gd::Project& project,
const std::vector<gd::ParameterMetadata>& parameters,
gd::ObjectsContainer& outputObjectsContainer);
@@ -32,7 +32,7 @@ class GD_CORE_API ParameterMetadataTools {
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& parameterValue,
const gd::String& lastObjectName)> fn);
/**
@@ -44,7 +44,7 @@ class GD_CORE_API ParameterMetadataTools {
const std::vector<gd::Expression>& parameters,
const std::vector<gd::ParameterMetadata>& parametersMetadata,
std::function<void(const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName)> fn);

View File

@@ -7,9 +7,7 @@
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/String.h"
#include "GDCore/Tools/Log.h"
using namespace std;
@@ -93,22 +91,24 @@ std::shared_ptr<gd::PlatformExtension> Platform::GetExtension(
return std::shared_ptr<gd::PlatformExtension>();
}
std::unique_ptr<gd::ObjectConfiguration> Platform::CreateObjectConfiguration(
gd::String type) const {
std::unique_ptr<gd::Object> Platform::CreateObject(
gd::String type, const gd::String& name) const {
if (creationFunctionTable.find(type) == creationFunctionTable.end()) {
gd::LogWarning("Tried to create an object with an unknown type: " + type
+ " for platform " + GetName() + "!");
std::cout << "Tried to create an object with an unknown type: " << type
<< " for platform " << GetName() << "!" << std::endl;
type = "";
if (creationFunctionTable.find("") == creationFunctionTable.end()) {
gd::LogError("Unable to create a Base object!");
std::cout << "Unable to create a Base object!" << std::endl;
return nullptr;
}
}
// Create a new object with the type we want.
auto objectConfiguration = (creationFunctionTable.find(type)->second)();
objectConfiguration->SetType(type);
return objectConfiguration;
std::unique_ptr<gd::Object> object =
(creationFunctionTable.find(type)->second)(name);
object->SetType(type);
return std::unique_ptr<gd::Object>(std::move(object));
}
#if defined(GD_IDE_ONLY)

View File

@@ -16,7 +16,6 @@ namespace gd {
class InstructionsMetadataHolder;
class Project;
class Object;
class ObjectConfiguration;
class Behavior;
class BehaviorMetadata;
class ObjectMetadata;
@@ -27,7 +26,7 @@ class LayoutEditorCanvas;
class ProjectExporter;
} // namespace gd
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)>
CreateFunPtr;
#undef CreateEvent
@@ -147,8 +146,8 @@ class GD_CORE_API Platform {
/**
* \brief Create an object of given type with the specified name.
*/
std::unique_ptr<gd::ObjectConfiguration> CreateObjectConfiguration(
gd::String type) const;
std::unique_ptr<gd::Object> CreateObject(gd::String type,
const gd::String& name) const;
/**
* \brief Create an event of given type

View File

@@ -18,7 +18,6 @@
#include "GDCore/Extensions/Platform.h"
#include "GDCore/IDE/PlatformManager.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/Project/BehaviorsSharedData.h"
#include "GDCore/Tools/Localization.h"
@@ -232,7 +231,7 @@ gd::ObjectMetadata& PlatformExtension::AddObject(
const gd::String& fullname,
const gd::String& description,
const gd::String& icon24x24,
std::shared_ptr<gd::ObjectConfiguration> instance) {
std::shared_ptr<gd::Object> instance) {
gd::String nameWithNamespace = GetNameSpace() + name;
objectsInfos[nameWithNamespace] = ObjectMetadata(GetNameSpace(),
nameWithNamespace,
@@ -245,21 +244,6 @@ gd::ObjectMetadata& PlatformExtension::AddObject(
return objectsInfos[nameWithNamespace];
}
gd::ObjectMetadata& PlatformExtension::AddEventsBasedObject(
const gd::String& name,
const gd::String& fullname,
const gd::String& description,
const gd::String& icon24x24) {
gd::String nameWithNamespace = GetNameSpace() + name;
objectsInfos[nameWithNamespace] = ObjectMetadata(GetNameSpace(),
nameWithNamespace,
fullname,
description,
icon24x24)
.SetHelpPath(GetHelpPath());
return objectsInfos[nameWithNamespace];
}
gd::BehaviorMetadata& PlatformExtension::AddBehavior(
const gd::String& name,
const gd::String& fullname,
@@ -285,25 +269,6 @@ gd::BehaviorMetadata& PlatformExtension::AddBehavior(
return behaviorsInfo[nameWithNamespace];
}
gd::BehaviorMetadata& PlatformExtension::AddEventsBasedBehavior(
const gd::String& name,
const gd::String& fullname,
const gd::String& description,
const gd::String& group,
const gd::String& icon24x24) {
gd::String nameWithNamespace = GetNameSpace() + name;
behaviorsInfo[nameWithNamespace] = BehaviorMetadata(GetNameSpace(),
nameWithNamespace,
fullname,
// Default name is the name
name,
description,
group,
icon24x24)
.SetHelpPath(GetHelpPath());
return behaviorsInfo[nameWithNamespace];
}
gd::EffectMetadata& PlatformExtension::AddEffect(const gd::String& name) {
gd::String nameWithNamespace = GetNameSpace() + name;
effectsMetadata[nameWithNamespace] = EffectMetadata(nameWithNamespace);
@@ -381,11 +346,6 @@ gd::BehaviorMetadata& PlatformExtension::GetBehaviorMetadata(
return badBehaviorMetadata;
}
bool PlatformExtension::HasBehavior(
const gd::String& behaviorType) const {
return behaviorsInfo.find(behaviorType) != behaviorsInfo.end();
}
gd::EffectMetadata& PlatformExtension::GetEffectMetadata(
const gd::String& effectName) {
if (effectsMetadata.find(effectName) != effectsMetadata.end())
@@ -415,7 +375,7 @@ gd::InstructionMetadata& PlatformExtension::AddDuplicatedAction(
auto copiedAction = actionsInfos.find(copiedNameWithNamespace);
if (copiedAction == actionsInfos.end()) {
gd::LogError("Could not find an action with name " +
gd::LogWarning("Could not find an action with name " +
copiedNameWithNamespace + " to copy.");
} else {
actionsInfos[newNameWithNamespace] = copiedAction->second;
@@ -435,7 +395,7 @@ gd::InstructionMetadata& PlatformExtension::AddDuplicatedCondition(
auto copiedCondition = conditionsInfos.find(copiedNameWithNamespace);
if (copiedCondition == conditionsInfos.end()) {
gd::LogError("Could not find a condition with name " +
gd::LogWarning("Could not find a condition with name " +
copiedNameWithNamespace + " to copy.");
} else {
conditionsInfos[newNameWithNamespace] = copiedCondition->second;
@@ -452,7 +412,7 @@ gd::ExpressionMetadata& PlatformExtension::AddDuplicatedExpression(
auto copiedExpression = expressionsInfos.find(copiedNameWithNamespace);
if (copiedExpression == expressionsInfos.end()) {
gd::LogError("Could not find an expression with name " +
gd::LogWarning("Could not find an expression with name " +
copiedNameWithNamespace + " to copy.");
} else {
expressionsInfos[newNameWithNamespace] = copiedExpression->second;
@@ -469,7 +429,7 @@ gd::ExpressionMetadata& PlatformExtension::AddDuplicatedStrExpression(
auto copiedExpression = strExpressionsInfos.find(copiedNameWithNamespace);
if (copiedExpression == strExpressionsInfos.end()) {
gd::LogError("Could not find a string expression with name " +
gd::LogWarning("Could not find a string expression with name " +
copiedNameWithNamespace + " to copy.");
} else {
strExpressionsInfos[newNameWithNamespace] = copiedExpression->second;

View File

@@ -37,10 +37,9 @@ class ArbitraryResourceWorker;
class BehaviorsSharedData;
class Behavior;
class Object;
class ObjectConfiguration;
} // namespace gd
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
typedef std::function<std::unique_ptr<gd::Object>(gd::String name)>
CreateFunPtr;
namespace gd {
@@ -243,21 +242,7 @@ class GD_CORE_API PlatformExtension {
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon_,
std::shared_ptr<gd::ObjectConfiguration> instance);
/**
* \brief Declare a new events based object as being part of the extension.
*
* \param name The name of the object
* \param fullname The user friendly name of the object
* \param description The user friendly description of the object
* \param icon The icon of the object.
*/
gd::ObjectMetadata& AddEventsBasedObject(
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& icon_);
std::shared_ptr<gd::Object> instance);
/**
* \brief Declare a new behavior as being part of the extension.
@@ -282,21 +267,6 @@ class GD_CORE_API PlatformExtension {
std::shared_ptr<gd::Behavior> instance,
std::shared_ptr<gd::BehaviorsSharedData> sharedDatasInstance);
/**
* \brief Declare a new events based behavior as being part of the extension.
*
* \param name The name of the behavior
* \param fullname The user friendly name of the behavior
* \param description The user friendly description of the behavior
* \param icon The icon of the behavior.
*/
gd::BehaviorMetadata& AddEventsBasedBehavior(
const gd::String& name_,
const gd::String& fullname_,
const gd::String& description_,
const gd::String& group_,
const gd::String& icon_);
/**
* \brief Declare a new effect as being part of the extension.
* \param name The internal name of the effect (also called effect type).
@@ -497,12 +467,6 @@ class GD_CORE_API PlatformExtension {
*/
BehaviorMetadata& GetBehaviorMetadata(const gd::String& behaviorType);
/**
* \brief Return true if the extension contains a behavior associated to \a
* behaviorType
*/
bool HasBehavior(const gd::String& behaviorType) const;
/**
* \brief Return the metadata for the effect with the given name.
*/

View File

@@ -25,8 +25,8 @@ gd::ObjectMetadata& PlatformExtension::AddObject(const gd::String& name,
fullname,
description,
icon24x24,
[]() -> std::unique_ptr<gd::ObjectConfiguration> {
return gd::make_unique<T>();
[](gd::String name) -> std::unique_ptr<gd::Object> {
return gd::make_unique<T>(name);
})
.SetHelpPath(GetHelpPath());

View File

@@ -1,25 +0,0 @@
#include "BehaviorTypeRenamer.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
namespace gd {
void BehaviorTypeRenamer::DoVisitObject(gd::Object& object) {
};
void BehaviorTypeRenamer::DoVisitBehavior(gd::Behavior& behavior) {
if (behavior.GetTypeName() == oldType) {
behavior.SetTypeName(newType);
}
};
BehaviorTypeRenamer::~BehaviorTypeRenamer() {}
} // namespace gd

View File

@@ -1,43 +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_BEHAVIORTYPERENAMER_H
#define GDCORE_BEHAVIORTYPERENAMER_H
#include <set>
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/String.h"
namespace gd {
class Project;
class Object;
class Behavior;
} // namespace gd
namespace gd {
class GD_CORE_API BehaviorTypeRenamer : public ArbitraryObjectsWorker {
public:
BehaviorTypeRenamer(const gd::Project& project_,
const gd::String& oldType_,
const gd::String& newType_)
: project(project_), oldType(oldType_), newType(newType_){};
virtual ~BehaviorTypeRenamer();
private:
void DoVisitObject(gd::Object& object) override;
void DoVisitBehavior(gd::Behavior& behavior) override;
const gd::Project& project;
gd::String oldType;
gd::String newType;
};
}; // namespace gd
#endif // GDCORE_BEHAVIORTYPERENAMER_H

View File

@@ -1,24 +0,0 @@
#include "CustomObjectTypeRenamer.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/IDE/WholeProjectRefactorer.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
namespace gd {
void CustomObjectTypeRenamer::DoVisitObject(gd::Object& object) {
if (object.GetType() == oldType) {
object.SetType(newType);
}
};
void CustomObjectTypeRenamer::DoVisitBehavior(gd::Behavior& behavior) {};
CustomObjectTypeRenamer::~CustomObjectTypeRenamer() {}
} // namespace gd

View File

@@ -1,43 +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_CUSTOMOBJECTTYPERENAMER_H
#define GDCORE_CUSTOMOBJECTTYPERENAMER_H
#include <set>
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/String.h"
namespace gd {
class Project;
class Object;
class Behavior;
} // namespace gd
namespace gd {
class GD_CORE_API CustomObjectTypeRenamer : public ArbitraryObjectsWorker {
public:
CustomObjectTypeRenamer(const gd::Project& project_,
const gd::String& oldType_,
const gd::String& newType_)
: project(project_), oldType(oldType_), newType(newType_){};
virtual ~CustomObjectTypeRenamer();
private:
void DoVisitObject(gd::Object& object) override;
void DoVisitBehavior(gd::Behavior& behavior) override;
const gd::Project& project;
gd::String oldType;
gd::String newType;
};
}; // namespace gd
#endif // GDCORE_CUSTOMOBJECTTYPERENAMER_H

View File

@@ -11,6 +11,7 @@
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
@@ -117,20 +118,27 @@ bool EventsBehaviorRenamer::DoVisitInstruction(gd::Instruction& instruction,
instruction.GetParameters(),
metadata.GetParameters(),
[&](const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& parameterValue,
size_t parameterIndex,
const gd::String& lastObjectName) {
const gd::String& type = parameterMetadata.type;
if (gd::ParameterMetadata::IsBehavior(type)) {
if (lastObjectName == objectName) {
if (parameterValue.GetPlainString() == oldBehaviorName) {
if (parameterValue == oldBehaviorName) {
instruction.SetParameter(parameterIndex,
gd::Expression(newBehaviorName));
}
}
} else {
auto node = parameterValue.GetRootNode();
gd::ExpressionParser2 parser(
platform, GetGlobalObjectsContainer(), GetObjectsContainer());
auto node =
gd::ParameterMetadata::IsExpression("number", type)
? parser.ParseExpression("number", parameterValue)
: (gd::ParameterMetadata::IsExpression("string", type)
? parser.ParseExpression("string", parameterValue)
: std::unique_ptr<gd::ExpressionNode>());
if (node) {
ExpressionBehaviorRenamer renamer(GetGlobalObjectsContainer(),
GetObjectsContainer(),

View File

@@ -9,6 +9,7 @@
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
@@ -16,7 +17,6 @@
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
@@ -31,17 +31,7 @@ namespace gd {
class GD_CORE_API ExpressionObjectsAnalyzer
: public ExpressionParser2NodeWorker {
public:
ExpressionObjectsAnalyzer(
const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_,
EventsContext& context_) :
platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootType(rootType_),
context(context_){};
ExpressionObjectsAnalyzer(EventsContext& context_) : context(context_){};
virtual ~ExpressionObjectsAnalyzer(){};
protected:
@@ -69,8 +59,7 @@ class GD_CORE_API ExpressionObjectsAnalyzer
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
if (gd::ParameterMetadata::IsObject(type)) {
if (gd::ParameterMetadata::IsObject(node.type)) {
context.AddObjectName(node.identifierName);
}
}
@@ -98,11 +87,6 @@ class GD_CORE_API ExpressionObjectsAnalyzer
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
EventsContext& context;
};
@@ -118,7 +102,7 @@ bool EventsContextAnalyzer::DoVisitInstruction(gd::Instruction& instruction,
instruction.GetParameters(),
instrInfo.parameters,
[this](const gd::ParameterMetadata& parameterMetadata,
const gd::Expression& parameterValue,
const gd::String& parameterValue,
const gd::String& lastObjectName) {
AnalyzeParameter(platform,
project,
@@ -145,14 +129,16 @@ void EventsContextAnalyzer::AnalyzeParameter(
if (ParameterMetadata::IsObject(type)) {
context.AddObjectName(value);
} else if (ParameterMetadata::IsExpression("number", type)) {
auto node = parameter.GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", value);
ExpressionObjectsAnalyzer analyzer(platform, project, layout, "number", context);
ExpressionObjectsAnalyzer analyzer(context);
node->Visit(analyzer);
} else if (ParameterMetadata::IsExpression("string", type)) {
auto node = parameter.GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", value);
ExpressionObjectsAnalyzer analyzer(platform, project, layout, "string", context);
ExpressionObjectsAnalyzer analyzer(context);
node->Visit(analyzer);
} else if (ParameterMetadata::IsBehavior(type)) {
context.AddBehaviorName(lastObjectName, value);

View File

@@ -1,41 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/EventsLeaderboardsLister.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
bool EventsLeaderboardsLister::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const gd::InstructionMetadata& instrInfo =
isCondition ? MetadataProvider::GetConditionMetadata(
project.GetCurrentPlatform(), instruction.GetType())
: MetadataProvider::GetActionMetadata(
project.GetCurrentPlatform(), instruction.GetType());
for (int i = 0; i < instruction.GetParametersCount() &&
i < instrInfo.GetParametersCount();
++i)
if (instrInfo.GetParameter(i).type == "leaderboardId") {
leaderboardIds.insert(instruction.GetParameter(i).GetPlainString());
}
return false;
}
EventsLeaderboardsLister::~EventsLeaderboardsLister() {}
} // namespace gd

View File

@@ -1,48 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef EventsLeaderboardsLister_H
#define EventsLeaderboardsLister_H
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class Project;
class EventsList;
}
namespace gd {
/**
* \brief List the leaderboard ids in the instructions.
*
* \ingroup IDE
*/
class GD_CORE_API EventsLeaderboardsLister : public ArbitraryEventsWorker {
public:
EventsLeaderboardsLister(gd::Project& project_) : project(project_){};
virtual ~EventsLeaderboardsLister();
/**
* Return the values of all leaderboardIds found in the events.
*/
const std::set<gd::String>& GetLeaderboardIds() { return leaderboardIds; }
private:
virtual bool DoVisitInstruction(gd::Instruction& instruction,
bool isCondition);
std::set<gd::String> leaderboardIds;
gd::Project& project;
};
} // namespace gd
#endif // EventsLeaderboardsLister_H

View File

@@ -1,49 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/EventsLeaderboardsRenamer.h"
#include <map>
#include <memory>
#include <vector>
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/String.h"
namespace gd {
bool EventsLeaderboardsRenamer::DoVisitInstruction(gd::Instruction& instruction,
bool isCondition) {
const gd::InstructionMetadata& instrInfo =
isCondition ? MetadataProvider::GetConditionMetadata(
project.GetCurrentPlatform(), instruction.GetType())
: MetadataProvider::GetActionMetadata(
project.GetCurrentPlatform(), instruction.GetType());
for (int i = 0; i < instruction.GetParametersCount() &&
i < instrInfo.GetParametersCount();
++i) {
const gd::ParameterMetadata parameter = instrInfo.GetParameter(i);
if (parameter.type == "leaderboardId") {
const gd::String leaderboardId =
instruction.GetParameter(i).GetPlainString();
if (leaderboardIdMap.find(leaderboardId) != leaderboardIdMap.end()) {
instruction.SetParameter(i, leaderboardIdMap[leaderboardId]);
}
}
}
return false;
}
EventsLeaderboardsRenamer::~EventsLeaderboardsRenamer() {}
} // namespace gd

View File

@@ -1,46 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef EventsLeaderboardsRenamer_H
#define EventsLeaderboardsRenamer_H
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
#include "GDCore/String.h"
namespace gd {
class BaseEvent;
class Project;
class EventsList;
}
namespace gd {
/**
* \brief Replace the leaderboard ids in the instructions.
*
* \ingroup IDE
*/
class GD_CORE_API EventsLeaderboardsRenamer : public ArbitraryEventsWorker {
public:
EventsLeaderboardsRenamer(
gd::Project& project_,
const std::map<gd::String, gd::String>& leaderboardIdMap_)
: project(project_), leaderboardIdMap(leaderboardIdMap_){};
virtual ~EventsLeaderboardsRenamer();
private:
virtual bool DoVisitInstruction(gd::Instruction& instruction,
bool isCondition);
std::map<gd::String, gd::String> leaderboardIdMap;
gd::Project& project;
};
} // namespace gd
#endif // EventsLeaderboardsRenamer_H

View File

@@ -11,16 +11,15 @@
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Events/EventsList.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include "GDCore/IDE/Events/InstructionSentenceFormatter.h"
#include "GDCore/Project/ObjectsContainer.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/IDE/Events/InstructionSentenceFormatter.h"
using namespace std;
@@ -35,30 +34,18 @@ const gd::String EventsRefactorer::searchIgnoredCharacters = ";:,#()";
*/
class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
public:
ExpressionObjectRenamer(const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_,
const gd::String& objectName_,
ExpressionObjectRenamer(const gd::String& objectName_,
const gd::String& objectNewName_)
: platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootType(rootType_),
hasDoneRenaming(false),
: hasDoneRenaming(false),
objectName(objectName_),
objectNewName(objectNewName_){};
virtual ~ExpressionObjectRenamer(){};
static bool Rename(const gd::Platform &platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String &rootType,
gd::ExpressionNode& node,
static bool Rename(gd::ExpressionNode& node,
const gd::String& objectName,
const gd::String& objectNewName) {
if (gd::ExpressionValidator::HasNoErrors(platform, globalObjectsContainer, objectsContainer, rootType, node)) {
ExpressionObjectRenamer renamer(platform, globalObjectsContainer, objectsContainer, rootType, objectName, objectNewName);
if (ExpressionValidator::HasNoErrors(node)) {
ExpressionObjectRenamer renamer(objectName, objectNewName);
node.Visit(renamer);
return renamer.HasDoneRenaming();
@@ -94,8 +81,7 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
if (gd::ParameterMetadata::IsObject(type) &&
if (gd::ParameterMetadata::IsObject(node.type) &&
node.identifierName == objectName) {
hasDoneRenaming = true;
node.identifierName = objectNewName;
@@ -122,11 +108,6 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
bool hasDoneRenaming;
const gd::String& objectName;
const gd::String& objectNewName;
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
};
/**
@@ -137,27 +118,14 @@ class GD_CORE_API ExpressionObjectRenamer : public ExpressionParser2NodeWorker {
*/
class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
public:
ExpressionObjectFinder(const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_,
const gd::String& objectName_)
: platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootType(rootType_),
hasObject(false),
objectName(objectName_){};
ExpressionObjectFinder(const gd::String& objectName_)
: hasObject(false), objectName(objectName_){};
virtual ~ExpressionObjectFinder(){};
static bool CheckIfHasObject(const gd::Platform &platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String &rootType,
gd::ExpressionNode& node,
static bool CheckIfHasObject(gd::ExpressionNode& node,
const gd::String& objectName) {
if (gd::ExpressionValidator::HasNoErrors(platform, globalObjectsContainer, objectsContainer, rootType, node)) {
ExpressionObjectFinder finder(platform, globalObjectsContainer, objectsContainer, rootType, objectName);
if (ExpressionValidator::HasNoErrors(node)) {
ExpressionObjectFinder finder(objectName);
node.Visit(finder);
return finder.HasFoundObject();
@@ -193,8 +161,7 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
if (gd::ParameterMetadata::IsObject(type) &&
if (gd::ParameterMetadata::IsObject(node.type) &&
node.identifierName == objectName) {
hasObject = true;
}
@@ -217,11 +184,6 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
private:
bool hasObject;
const gd::String& objectName;
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
};
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
@@ -243,9 +205,11 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].type)) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"number", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
actions[aId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -253,9 +217,11 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"string", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
actions[aId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -297,9 +263,11 @@ bool EventsRefactorer::RenameObjectInConditions(
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].type)) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"number", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
conditions[cId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -307,9 +275,11 @@ bool EventsRefactorer::RenameObjectInConditions(
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"string", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
conditions[cId].SetParameter(
pNb, ExpressionParser2NodePrinter::PrintNode(*node));
}
@@ -346,18 +316,20 @@ bool EventsRefactorer::RenameObjectInEventParameters(
// Replace object's name in expressions
else if (ParameterMetadata::IsExpression("number",
parameterMetadata.GetType())) {
auto node = expression.GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("number", expression.GetPlainString());
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
// Replace object's name in text expressions
else if (ParameterMetadata::IsExpression("string",
parameterMetadata.GetType())) {
auto node = expression.GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression("string", expression.GetPlainString());
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
if (ExpressionObjectRenamer::Rename(*node, oldName, newName)) {
expression = ExpressionParser2NodePrinter::PrintNode(*node);
}
}
@@ -412,8 +384,8 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
}
bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& actions,
gd::String name) {
bool somethingModified = false;
@@ -433,9 +405,11 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
// Find object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].type)) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"number", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "number", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
break;
}
@@ -443,9 +417,11 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
// Find object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
auto node = actions[aId].GetParameter(pNb).GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"string", actions[aId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "string", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
break;
}
@@ -459,8 +435,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
} else if (!actions[aId].GetSubInstructions().empty())
somethingModified =
RemoveObjectInActions(platform,
globalObjectsContainer,
objectsContainer,
project,
layout,
actions[aId].GetSubInstructions(),
name) ||
somethingModified;
@@ -471,8 +447,8 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
bool EventsRefactorer::RemoveObjectInConditions(
const gd::Platform& platform,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::InstructionsList& conditions,
gd::String name) {
bool somethingModified = false;
@@ -493,9 +469,11 @@ bool EventsRefactorer::RemoveObjectInConditions(
// Find object's name in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].type)) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"number", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "number", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
break;
}
@@ -503,9 +481,11 @@ bool EventsRefactorer::RemoveObjectInConditions(
// Find object's name in text expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"string", conditions[cId].GetParameter(pNb).GetPlainString());
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "string", *node, name)) {
if (ExpressionObjectFinder::CheckIfHasObject(*node, name)) {
deleteMe = true;
break;
}
@@ -519,8 +499,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
} else if (!conditions[cId].GetSubInstructions().empty())
somethingModified =
RemoveObjectInConditions(platform,
globalObjectsContainer,
objectsContainer,
project,
layout,
conditions[cId].GetSubInstructions(),
name) ||
somethingModified;
@@ -530,8 +510,8 @@ bool EventsRefactorer::RemoveObjectInConditions(
}
void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
gd::ObjectsContainer& globalObjectsContainer,
gd::ObjectsContainer& objectsContainer,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String name) {
for (std::size_t i = 0; i < events.size(); ++i) {
@@ -539,37 +519,32 @@ void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
events[i].GetAllConditionsVectors();
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
bool conditionsModified = RemoveObjectInConditions(
platform, globalObjectsContainer, objectsContainer, *conditionsVectors[j], name);
platform, project, layout, *conditionsVectors[j], name);
}
vector<gd::InstructionsList*> actionsVectors =
events[i].GetAllActionsVectors();
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
bool actionsModified = RemoveObjectInActions(
platform, globalObjectsContainer, objectsContainer, *actionsVectors[j], name);
platform, project, layout, *actionsVectors[j], name);
}
if (events[i].CanHaveSubEvents())
RemoveObjectInEvents(
platform, globalObjectsContainer, objectsContainer, events[i].GetSubEvents(), name);
platform, project, layout, events[i].GetSubEvents(), name);
}
}
std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String toReplace,
gd::String newString,
bool matchCase,
bool inConditions,
bool inActions,
bool inEventStrings) {
vector<EventsSearchResult> modifiedEvents;
if (toReplace.empty()) return modifiedEvents;
void EventsRefactorer::ReplaceStringInEvents(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String toReplace,
gd::String newString,
bool matchCase,
bool inConditions,
bool inActions,
bool inEventStrings) {
for (std::size_t i = 0; i < events.size(); ++i) {
bool eventModified = false;
if (inConditions) {
vector<gd::InstructionsList*> conditionsVectors =
events[i].GetAllConditionsVectors();
@@ -581,13 +556,6 @@ std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
toReplace,
newString,
matchCase);
if (conditionsModified && !eventModified) {
modifiedEvents.push_back(EventsSearchResult(
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
&events,
i));
eventModified = true;
}
}
}
@@ -601,45 +569,25 @@ std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
toReplace,
newString,
matchCase);
if (actionsModified && !eventModified) {
modifiedEvents.push_back(EventsSearchResult(
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
&events,
i));
eventModified = true;
}
}
}
if (inEventStrings) {
bool eventStringModified = ReplaceStringInEventSearchableStrings(
project, layout, events[i], toReplace, newString, matchCase);
if (eventStringModified && !eventModified) {
modifiedEvents.push_back(EventsSearchResult(
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
&events,
i));
eventModified = true;
}
}
if (events[i].CanHaveSubEvents()) {
std::vector<EventsSearchResult> modifiedSubEvent =
ReplaceStringInEvents(project,
layout,
events[i].GetSubEvents(),
toReplace,
newString,
matchCase,
inConditions,
inActions,
inEventStrings);
std::copy(modifiedSubEvent.begin(),
modifiedSubEvent.end(),
std::back_inserter(modifiedEvents));
}
if (events[i].CanHaveSubEvents())
ReplaceStringInEvents(project,
layout,
events[i].GetSubEvents(),
toReplace,
newString,
matchCase,
inConditions,
inActions,
inEventStrings);
}
return modifiedEvents;
}
gd::String ReplaceAllOccurencesCaseUnsensitive(gd::String context,
@@ -770,16 +718,14 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
bool inEventSentences) {
vector<EventsSearchResult> results;
const gd::String& ignored_characters =
EventsRefactorer::searchIgnoredCharacters;
const gd::String& ignored_characters = EventsRefactorer::searchIgnoredCharacters;
search.replace_if(
search.begin(),
search.end(),
[ignored_characters](const char& c) {
return ignored_characters.find(c) != gd::String::npos;
},
"");
search.replace_if(search.begin(),
search.end(),
[ignored_characters](const char &c) {
return ignored_characters.find(c) != gd::String::npos;
},
"");
search = search.LeftTrim().RightTrim();
search.RemoveConsecutiveOccurrences(search.begin(), search.end(), ' ');
@@ -791,11 +737,8 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
events[i].GetAllConditionsVectors();
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
if (!eventAddedInResults &&
SearchStringInConditions(platform,
*conditionsVectors[j],
search,
matchCase,
inEventSentences)) {
SearchStringInConditions(
platform, *conditionsVectors[j], search, matchCase, inEventSentences)) {
results.push_back(EventsSearchResult(
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
&events,
@@ -808,11 +751,9 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
vector<gd::InstructionsList*> actionsVectors =
events[i].GetAllActionsVectors();
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
if (!eventAddedInResults && SearchStringInActions(platform,
*actionsVectors[j],
search,
matchCase,
inEventSentences)) {
if (!eventAddedInResults &&
SearchStringInActions(
platform, *actionsVectors[j], search, matchCase, inEventSentences)) {
results.push_back(EventsSearchResult(
std::weak_ptr<gd::BaseEvent>(events.GetEventSmartPtr(i)),
&events,
@@ -849,11 +790,12 @@ vector<EventsSearchResult> EventsRefactorer::SearchInEvents(
return results;
}
bool EventsRefactorer::SearchStringInActions(const gd::Platform& platform,
gd::InstructionsList& actions,
gd::String search,
bool matchCase,
bool inSentences) {
bool EventsRefactorer::SearchStringInActions(
const gd::Platform& platform,
gd::InstructionsList& actions,
gd::String search,
bool matchCase,
bool inSentences) {
for (std::size_t aId = 0; aId < actions.size(); ++aId) {
for (std::size_t pNb = 0; pNb < actions[aId].GetParameters().size();
++pNb) {
@@ -884,30 +826,27 @@ bool EventsRefactorer::SearchStringInActions(const gd::Platform& platform,
return false;
}
bool EventsRefactorer::SearchStringInFormattedText(const gd::Platform& platform,
gd::Instruction& instruction,
gd::String search,
bool matchCase,
bool isCondition) {
bool EventsRefactorer::SearchStringInFormattedText(
const gd::Platform& platform,
gd::Instruction& instruction,
gd::String search,
bool matchCase,
bool isCondition) {
const auto& metadata = isCondition
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
gd::String completeSentence =
gd::InstructionSentenceFormatter::Get()->GetFullText(instruction,
metadata);
? gd::MetadataProvider::GetConditionMetadata(
platform, instruction.GetType())
: gd::MetadataProvider::GetActionMetadata(
platform, instruction.GetType());
gd::String completeSentence = gd::InstructionSentenceFormatter::Get()->GetFullText(instruction, metadata);
const gd::String& ignored_characters =
EventsRefactorer::searchIgnoredCharacters;
const gd::String& ignored_characters = EventsRefactorer::searchIgnoredCharacters;
completeSentence.replace_if(
completeSentence.begin(),
completeSentence.end(),
[ignored_characters](const char& c) {
return ignored_characters.find(c) != gd::String::npos;
},
"");
completeSentence.replace_if(completeSentence.begin(),
completeSentence.end(),
[ignored_characters](const char &c) {
return ignored_characters.find(c) != gd::String::npos;
},
"");
completeSentence.RemoveConsecutiveOccurrences(
completeSentence.begin(), completeSentence.end(), ' ');

View File

@@ -7,7 +7,6 @@
#define GDCORE_EVENTSREFACTORER_H
#include <memory>
#include <vector>
#include "GDCore/Events/Instruction.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/String.h"
@@ -19,7 +18,7 @@ class ExternalEvents;
class BaseEvent;
class Instruction;
typedef std::shared_ptr<gd::BaseEvent> BaseEventSPtr;
} // namespace gd
}
namespace gd {
@@ -44,11 +43,10 @@ class GD_CORE_API EventsSearchResult {
bool IsEventsListValid() const { return eventsList != nullptr; }
/**
* \brief Get the events list containing the event pointed by the
* EventsSearchResult. \warning Only call this when IsEventsListValid returns
* true.
* \brief Get the events list containing the event pointed by the EventsSearchResult.
* \warning Only call this when IsEventsListValid returns true.
*/
const gd::EventsList& GetEventsList() const { return *eventsList; }
const gd::EventsList & GetEventsList() const { return *eventsList; }
std::size_t GetPositionInList() const { return positionInList; }
@@ -58,7 +56,7 @@ class GD_CORE_API EventsSearchResult {
* \brief Get the event pointed by the EventsSearchResult.
* \warning Only call this when IsEventValid returns true.
*/
const gd::BaseEvent& GetEvent() const { return *event.lock(); }
const gd::BaseEvent & GetEvent() const { return *event.lock(); }
};
/**
@@ -100,31 +98,27 @@ class GD_CORE_API EventsRefactorer {
* \return A vector containing EventsSearchResult objects filled with events
* containing the string
*/
static std::vector<EventsSearchResult> SearchInEvents(
const gd::Platform& platform,
gd::EventsList& events,
gd::String search,
bool matchCase,
bool inConditions,
bool inActions,
bool inEventStrings,
bool inEventSentences);
static std::vector<EventsSearchResult> SearchInEvents(const gd::Platform& platform,
gd::EventsList& events,
gd::String search,
bool matchCase,
bool inConditions,
bool inActions,
bool inEventStrings,
bool inEventSentences);
/**
* Replace all occurrences of a gd::String in events
*
* \return A vector of all modified events.
*/
static std::vector<EventsSearchResult> ReplaceStringInEvents(
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String toReplace,
gd::String newString,
bool matchCase,
bool inConditions,
bool inActions,
bool inEventString);
static void ReplaceStringInEvents(gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::EventsList& events,
gd::String toReplace,
gd::String newString,
bool matchCase,
bool inConditions,
bool inActions,
bool inEventString);
virtual ~EventsRefactorer(){};
@@ -154,21 +148,20 @@ class GD_CORE_API EventsRefactorer {
gd::InstructionsList& instructions,
gd::String oldName,
gd::String newName);
/**
/**
* Replace all occurrences of an object name by another name in an expression
* with the specified metadata
* ( include : objects or objects in math/text expressions ).
*
* \return true if something was modified.
*/
static bool RenameObjectInEventParameters(
const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
gd::String newName);
static bool RenameObjectInEventParameters(const gd::Platform& platform,
gd::ObjectsContainer& project,
gd::ObjectsContainer& layout,
gd::Expression& expression,
gd::ParameterMetadata parameterMetadata,
gd::String oldName,
gd::String newName);
/**
* Remove all conditions of the list using an object

View File

@@ -7,6 +7,7 @@
#include "EventsVariablesFinder.h"
#include "GDCore/Events/Event.h"
#include "GDCore/Events/Instruction.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
@@ -31,16 +32,10 @@ namespace gd {
class GD_CORE_API ExpressionParameterSearcher
: public ExpressionParser2NodeWorker {
public:
ExpressionParameterSearcher(const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
std::set<gd::String>& results_,
ExpressionParameterSearcher(std::set<gd::String>& results_,
const gd::String& parameterType_,
const gd::String& objectName_ = "")
: platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
results(results_),
: results(results_),
parameterType(parameterType_),
objectName(objectName_){};
virtual ~ExpressionParameterSearcher(){};
@@ -73,22 +68,10 @@ class GD_CORE_API ExpressionParameterSearcher
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
bool considerFunction = objectName.empty() || node.objectName == objectName;
const gd::ExpressionMetadata &metadata = node.objectName.empty() ?
MetadataProvider::GetAnyExpressionMetadata(platform, node.functionName) :
MetadataProvider::GetObjectAnyExpressionMetadata(
platform,
GetTypeOfObject(globalObjectsContainer, objectsContainer, objectName),
node.functionName);
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
return;
}
for (size_t i = 0; i < node.parameters.size() &&
i < metadata.parameters.size();
i < node.expressionMetadata.parameters.size();
++i) {
auto& parameterMetadata = metadata.parameters[i];
auto& parameterMetadata = node.expressionMetadata.parameters[i];
if (considerFunction && parameterMetadata.GetType() == parameterType) {
// Store the value of the parameter
results.insert(
@@ -101,10 +84,6 @@ class GD_CORE_API ExpressionParameterSearcher
void OnVisitEmptyNode(EmptyNode& node) override {}
private:
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
std::set<gd::String>& results; ///< Reference to the std::set where argument
///< values must be stored.
gd::String parameterType; ///< The type of the parameters to be searched for.
@@ -186,18 +165,24 @@ std::set<gd::String> EventsVariablesFinder::FindArgumentsInInstructions(
}
// Search in expressions
else if (ParameterMetadata::IsExpression(
"number", instrInfos.parameters[pNb].type) ||
ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
auto node = instructions[aId].GetParameter(pNb).GetRootNode();
"number", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"number", instructions[aId].GetParameter(pNb).GetPlainString());
ExpressionParameterSearcher searcher(
platform,
project,
layout,
results,
parameterType,
objectName);
results, parameterType, objectName);
node->Visit(searcher);
}
// Search in gd::String expressions
else if (ParameterMetadata::IsExpression(
"string", instrInfos.parameters[pNb].type)) {
gd::ExpressionParser2 parser(platform, project, layout);
auto node = parser.ParseExpression(
"number", instructions[aId].GetParameter(pNb).GetPlainString());
ExpressionParameterSearcher searcher(
results, parameterType, objectName);
node->Visit(searcher);
}
// Remember the value of the last "object" parameter.

View File

@@ -15,8 +15,6 @@
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
namespace gd {
class Expression;
@@ -292,11 +290,7 @@ class GD_CORE_API ExpressionCompletionFinder
* and returns completions for it.
*/
static std::vector<ExpressionCompletionDescription>
GetCompletionDescriptionsFor(const gd::Platform &platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String &rootType,
gd::ExpressionNode& node,
GetCompletionDescriptionsFor(gd::ExpressionNode& node,
size_t searchedPosition) {
gd::ExpressionNodeLocationFinder finder(searchedPosition);
node.Visit(finder);
@@ -309,7 +303,6 @@ class GD_CORE_API ExpressionCompletionFinder
gd::ExpressionNode* maybeParentNodeAtLocation = finder.GetParentNode();
gd::ExpressionCompletionFinder autocompletionProvider(
platform, globalObjectsContainer, objectsContainer, rootType,
searchedPosition, maybeParentNodeAtLocation);
nodeAtLocation->Visit(autocompletionProvider);
return autocompletionProvider.GetCompletionDescriptions();
@@ -327,21 +320,19 @@ class GD_CORE_API ExpressionCompletionFinder
protected:
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
completions.push_back(ExpressionCompletionDescription::ForObject(
type, "", searchedPosition + 1, searchedPosition + 1));
node.type, "", searchedPosition + 1, searchedPosition + 1));
completions.push_back(ExpressionCompletionDescription::ForExpression(
type, "", searchedPosition + 1, searchedPosition + 1));
node.type, "", searchedPosition + 1, searchedPosition + 1));
}
void OnVisitOperatorNode(OperatorNode& node) override {
// No completions.
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
completions.push_back(ExpressionCompletionDescription::ForObject(
type, "", searchedPosition + 1, searchedPosition + 1));
node.type, "", searchedPosition + 1, searchedPosition + 1));
completions.push_back(ExpressionCompletionDescription::ForExpression(
type, "", searchedPosition + 1, searchedPosition + 1));
node.type, "", searchedPosition + 1, searchedPosition + 1));
}
void OnVisitNumberNode(NumberNode& node) override {
// No completions
@@ -353,7 +344,6 @@ class GD_CORE_API ExpressionCompletionFinder
FunctionCallNode* functionCall =
dynamic_cast<FunctionCallNode*>(maybeParentNodeAtLocation);
if (functionCall != nullptr) {
int parameterIndex = -1;
for (int i = 0; i < functionCall->parameters.size(); i++) {
if (functionCall->parameters.at(i).get() == &node) {
@@ -369,16 +359,15 @@ class GD_CORE_API ExpressionCompletionFinder
size_t metadataParameterIndex =
ExpressionParser2::WrittenParametersFirstIndex(
functionCall->objectName, functionCall->behaviorName);
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
platform, globalObjectsContainer, objectsContainer, *functionCall);
const gd::ParameterMetadata* parameterMetadata = nullptr;
while (metadataParameterIndex <
metadata.parameters.size()) {
if (!metadata.parameters[metadataParameterIndex]
functionCall->expressionMetadata.parameters.size()) {
if (!functionCall->expressionMetadata.parameters[metadataParameterIndex]
.IsCodeOnly()) {
if (visibleParameterIndex == parameterIndex) {
parameterMetadata = &metadata.parameters[metadataParameterIndex];
parameterMetadata = &functionCall->expressionMetadata
.parameters[metadataParameterIndex];
}
visibleParameterIndex++;
}
@@ -409,21 +398,12 @@ class GD_CORE_API ExpressionCompletionFinder
}
}
void OnVisitVariableNode(VariableNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform,
globalObjectsContainer,
objectsContainer,
// Variable fields doesn't use expression completion,
// so the object will be found inside the expression itself.
"",
node);
completions.push_back(ExpressionCompletionDescription::ForVariable(
type,
node.type,
node.name,
node.location.GetStartPosition(),
node.location.GetEndPosition(),
objectName));
node.objectName));
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
// No completions
@@ -433,69 +413,35 @@ class GD_CORE_API ExpressionCompletionFinder
// No completions
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
if (gd::ParameterMetadata::IsObject(type)) {
if (gd::ParameterMetadata::IsObject(node.type)) {
// Only show completions of objects if an object is required
completions.push_back(ExpressionCompletionDescription::ForObject(
type,
node.type,
node.identifierName,
node.location.GetStartPosition(),
node.location.GetEndPosition()));
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(
platform,
globalObjectsContainer,
objectsContainer,
// Variable fields doesn't use expression completion,
// so the object will be found inside the expression itself.
"",
node);
completions.push_back(ExpressionCompletionDescription::ForVariable(
type,
} else {
// Show completions for expressions and objects otherwise.
completions.push_back(ExpressionCompletionDescription::ForObject(
node.type,
node.identifierName,
node.location.GetStartPosition(),
node.location.GetEndPosition(),
objectName));
} else {
// Object function or behavior name
if (IsCaretOn(node.identifierNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
type,
node.identifierName,
node.identifierNameLocation.GetStartPosition(),
node.identifierNameLocation.GetEndPosition()));
if (!node.identifierNameDotLocation.IsValid()) {
completions.push_back(ExpressionCompletionDescription::ForExpression(
type,
node.identifierName,
node.identifierNameLocation.GetStartPosition(),
node.identifierNameLocation.GetEndPosition()));
}
} else if (IsCaretOn(node.identifierNameDotLocation) ||
IsCaretOn(node.childIdentifierNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForBehavior(
node.childIdentifierName,
node.childIdentifierNameLocation.GetStartPosition(),
node.childIdentifierNameLocation.GetEndPosition(),
node.identifierName));
completions.push_back(ExpressionCompletionDescription::ForExpression(
type,
node.childIdentifierName,
node.childIdentifierNameLocation.GetStartPosition(),
node.childIdentifierNameLocation.GetEndPosition(),
node.identifierName));
}
node.location.GetEndPosition()));
completions.push_back(ExpressionCompletionDescription::ForExpression(
node.type,
node.identifierName,
node.location.GetStartPosition(),
node.location.GetEndPosition()));
}
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
if (!node.behaviorFunctionName.empty() ||
node.behaviorNameNamespaceSeparatorLocation.IsValid()) {
// Behavior function (or behavior function being written, with the
// function name missing)
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
type,
node.type,
node.objectName,
node.objectNameLocation.GetStartPosition(),
node.objectNameLocation.GetEndPosition()));
@@ -509,7 +455,7 @@ class GD_CORE_API ExpressionCompletionFinder
} else if (IsCaretOn(node.behaviorNameNamespaceSeparatorLocation) ||
IsCaretOn(node.behaviorFunctionNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForExpression(
type,
node.type,
node.behaviorFunctionName,
node.behaviorFunctionNameLocation.GetStartPosition(),
node.behaviorFunctionNameLocation.GetEndPosition(),
@@ -520,7 +466,7 @@ class GD_CORE_API ExpressionCompletionFinder
// Object function or behavior name
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
type,
node.type,
node.objectName,
node.objectNameLocation.GetStartPosition(),
node.objectNameLocation.GetEndPosition()));
@@ -532,7 +478,7 @@ class GD_CORE_API ExpressionCompletionFinder
node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
node.objectName));
completions.push_back(ExpressionCompletionDescription::ForExpression(
type,
node.type,
node.objectFunctionOrBehaviorName,
node.objectFunctionOrBehaviorNameLocation.GetStartPosition(),
node.objectFunctionOrBehaviorNameLocation.GetEndPosition(),
@@ -541,7 +487,6 @@ class GD_CORE_API ExpressionCompletionFinder
}
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
bool isCaretOnParenthesis = IsCaretOn(node.openingParenthesisLocation) ||
IsCaretOn(node.closingParenthesisLocation);
@@ -549,7 +494,7 @@ class GD_CORE_API ExpressionCompletionFinder
// Behavior function
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
type,
node.type,
node.objectName,
node.objectNameLocation.GetStartPosition(),
node.objectNameLocation.GetEndPosition()));
@@ -562,7 +507,7 @@ class GD_CORE_API ExpressionCompletionFinder
node.objectName));
} else {
completions.push_back(ExpressionCompletionDescription::ForExpression(
type,
node.type,
node.functionName,
node.functionNameLocation.GetStartPosition(),
node.functionNameLocation.GetEndPosition(),
@@ -574,7 +519,7 @@ class GD_CORE_API ExpressionCompletionFinder
// Object function
if (IsCaretOn(node.objectNameLocation)) {
completions.push_back(ExpressionCompletionDescription::ForObject(
type,
node.type,
node.objectName,
node.objectNameLocation.GetStartPosition(),
node.objectNameLocation.GetEndPosition()));
@@ -593,7 +538,7 @@ class GD_CORE_API ExpressionCompletionFinder
}
completions.push_back(ExpressionCompletionDescription::ForExpression(
type,
node.type,
node.functionName,
node.functionNameLocation.GetStartPosition(),
node.functionNameLocation.GetEndPosition(),
@@ -603,7 +548,7 @@ class GD_CORE_API ExpressionCompletionFinder
} else {
// Free function
completions.push_back(ExpressionCompletionDescription::ForExpression(
type,
node.type,
node.functionName,
node.functionNameLocation.GetStartPosition(),
node.functionNameLocation.GetEndPosition())
@@ -611,14 +556,13 @@ class GD_CORE_API ExpressionCompletionFinder
}
}
void OnVisitEmptyNode(EmptyNode& node) override {
auto type = gd::ExpressionTypeFinder::GetType(platform, globalObjectsContainer, objectsContainer, rootType, node);
completions.push_back(ExpressionCompletionDescription::ForObject(
type,
node.type,
node.text,
node.location.GetStartPosition(),
node.location.GetEndPosition()));
completions.push_back(ExpressionCompletionDescription::ForExpression(
type,
node.type,
node.text,
node.location.GetStartPosition(),
node.location.GetEndPosition()));
@@ -634,27 +578,14 @@ class GD_CORE_API ExpressionCompletionFinder
(inclusive && searchedPosition <= location.GetEndPosition())));
}
ExpressionCompletionFinder(const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_,
size_t searchedPosition_,
ExpressionCompletionFinder(size_t searchedPosition_,
gd::ExpressionNode* maybeParentNodeAtLocation_)
: platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootType(rootType_),
searchedPosition(searchedPosition_),
: searchedPosition(searchedPosition_),
maybeParentNodeAtLocation(maybeParentNodeAtLocation_){};
std::vector<ExpressionCompletionDescription> completions;
size_t searchedPosition;
gd::ExpressionNode* maybeParentNodeAtLocation;
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
};
} // namespace gd

View File

@@ -1,123 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONLEFTSIDETYPEFINDER_H
#define GDCORE_EXPRESSIONLEFTSIDETYPEFINDER_H
#include <memory>
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
#include "GDCore/Tools/Localization.h"
namespace gd {
class Expression;
class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
} // namespace gd
namespace gd {
/**
* \brief Find the type of the node at the left side of operations.
*
* \see gd::ExpressionTypeFinder
*/
class GD_CORE_API ExpressionLeftSideTypeFinder : public ExpressionParser2NodeWorker {
public:
/**
* \brief Helper function to find the type of the node at the left side of
* operations.
*/
static const gd::String GetType(const gd::Platform &platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
gd::ExpressionNode& node) {
gd::ExpressionLeftSideTypeFinder typeFinder(
platform, globalObjectsContainer, objectsContainer);
node.Visit(typeFinder);
return typeFinder.GetType();
}
virtual ~ExpressionLeftSideTypeFinder(){};
protected:
ExpressionLeftSideTypeFinder(const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_)
: platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
type("unknown") {};
const gd::String &GetType() {
return type;
};
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
node.expression->Visit(*this);
}
void OnVisitOperatorNode(OperatorNode& node) override {
node.leftHandSide->Visit(*this);
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
node.factor->Visit(*this);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
node.expression->Visit(*this);
}
void OnVisitNumberNode(NumberNode& node) override {
type = "number";
}
void OnVisitTextNode(TextNode& node) override {
type = "string";
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
platform, globalObjectsContainer, objectsContainer, node);
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
type = "unknown";
}
else {
type = metadata.GetReturnType();
}
}
void OnVisitVariableNode(VariableNode& node) override {
type = "unknown";
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
type = "unknown";
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
type = "unknown";
}
void OnVisitEmptyNode(EmptyNode& node) override {
type = "unknown";
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
type = "unknown";
}
private:
gd::String type;
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
};
} // namespace gd
#endif // GDCORE_EXPRESSIONLEFTSIDETYPEFINDER_H

View File

@@ -1,35 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
#include <algorithm>
#include <memory>
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Expression.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
using namespace std;
namespace gd {
// TODO factorize in a file with an enum and helpers?
const gd::String ExpressionTypeFinder::unknownType = "unknown";
const gd::String ExpressionTypeFinder::numberType = "number";
const gd::String ExpressionTypeFinder::stringType = "string";
const gd::String ExpressionTypeFinder::numberOrStringType = "number|string";
} // namespace gd

View File

@@ -1,198 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONTYPEFINDER_H
#define GDCORE_EXPRESSIONTYPEFINDER_H
#include <memory>
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/IDE/Events/ExpressionLeftSideTypeFinder.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
#include "GDCore/Tools/Localization.h"
namespace gd {
class Expression;
class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
} // namespace gd
namespace gd {
/**
* \brief Find the type of the expression or sub-expression that a given node
* represents.
*
* The type returned by this worker is a mix of:
* - an expected type looking up like a parameter declaration
* - an actual type looking down, but only looking at the most left branch
* (using ExpressionLeftSideTypeFinder)
*
* This logic was built with the constraint of following a parser that can't
* know the right side. Now that it is extracted, it could be enhanced if needed.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionTypeFinder : public ExpressionParser2NodeWorker {
public:
/**
* \brief Helper function to find the type of the expression or
* sub-expression that a given node represents.
*/
static const gd::String GetType(const gd::Platform &platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String &rootType,
gd::ExpressionNode& node) {
gd::ExpressionTypeFinder typeFinder(
platform, globalObjectsContainer, objectsContainer, rootType);
node.Visit(typeFinder);
return typeFinder.GetType();
}
virtual ~ExpressionTypeFinder(){};
protected:
ExpressionTypeFinder(const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_)
: platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootType(rootType_),
type(ExpressionTypeFinder::unknownType),
child(nullptr) {};
const gd::String &GetType() {
return gd::ParameterMetadata::GetExpressionValueType(type);
};
void OnVisitSubExpressionNode(SubExpressionNode& node) override {
VisitParent(node);
}
void OnVisitOperatorNode(OperatorNode& node) override {
VisitParent(node);
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
VisitParent(node);
}
void OnVisitNumberNode(NumberNode& node) override {
type = ExpressionTypeFinder::numberType;
}
void OnVisitTextNode(TextNode& node) override {
type = ExpressionTypeFinder::stringType;
}
void OnVisitVariableNode(VariableNode& node) override {
VisitParent(node);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
VisitParent(node);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
VisitParent(node);
}
void OnVisitEmptyNode(EmptyNode& node) override {
VisitParent(node);
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
VisitParent(node);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
if (child == nullptr) {
type = ExpressionTypeFinder::unknownType;
}
auto leftSideType = gd::ExpressionLeftSideTypeFinder::GetType(
platform,
globalObjectsContainer,
objectsContainer,
node);
if (leftSideType == ExpressionTypeFinder::numberType
|| leftSideType == ExpressionTypeFinder::stringType) {
type = leftSideType;
}
else {
type = ExpressionTypeFinder::numberOrStringType;
}
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
if (child == nullptr) {
const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
platform, globalObjectsContainer, objectsContainer, node);
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
VisitParent(node);
}
else {
type = metadata.GetReturnType();
}
}
else {
const gd::ParameterMetadata* parameterMetadata =
gd::MetadataProvider::GetFunctionCallParameterMetadata(
platform,
globalObjectsContainer,
objectsContainer,
node,
*child);
if (parameterMetadata == nullptr || parameterMetadata->GetType().empty()) {
type = ExpressionTypeFinder::unknownType;
}
else {
type = parameterMetadata->GetType();
}
}
}
private:
inline void VisitParent(ExpressionNode& node) {
child = &node;
if (node.parent != nullptr) {
node.parent->Visit(*this);
}
else if (rootType == ExpressionTypeFinder::numberOrStringType) {
auto leftSideType = gd::ExpressionLeftSideTypeFinder::GetType(
platform,
globalObjectsContainer,
objectsContainer,
node);
if (leftSideType == ExpressionTypeFinder::numberType
|| leftSideType == ExpressionTypeFinder::stringType) {
type = leftSideType;
}
else {
type = rootType;
}
}
else {
type = rootType;
}
}
static const gd::String unknownType;
static const gd::String numberType;
static const gd::String stringType;
static const gd::String numberOrStringType;
gd::String type;
ExpressionNode *child;
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String rootType;
};
} // namespace gd
#endif // GDCORE_EXPRESSIONTYPEFINDER_H

View File

@@ -1,300 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#include "GDCore/IDE/Events/ExpressionValidator.h"
#include <algorithm>
#include <memory>
#include <vector>
#include "GDCore/CommonTools.h"
#include "GDCore/Events/Expression.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/InstructionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Platform.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Events/Parsers/ExpressionParser2.h"
using namespace std;
namespace gd {
namespace {
/**
* Return the minimum number of parameters, starting from a given parameter
* (by convention, 1 for object functions and 2 for behavior functions).
*/
size_t GetMinimumParametersNumber(
const std::vector<gd::ParameterMetadata>& parameters,
size_t initialParameterIndex) {
size_t nb = 0;
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
if (!parameters[i].optional && !parameters[i].codeOnly) nb++;
}
return nb;
}
/**
* Return the maximum number of parameters, starting from a given parameter
* (by convention, 1 for object functions and 2 for behavior functions).
*/
size_t GetMaximumParametersNumber(
const std::vector<gd::ParameterMetadata>& parameters,
size_t initialParameterIndex) {
size_t nb = 0;
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
if (!parameters[i].codeOnly) nb++;
}
return nb;
}
} // namespace
ExpressionValidator::Type ExpressionValidator::ValidateFunction(const gd::FunctionCallNode& function) {
ReportAnyError(function);
gd::String objectType = function.objectName.empty() ? "" :
GetTypeOfObject(globalObjectsContainer, objectsContainer, function.objectName);
gd::String behaviorType = function.behaviorName.empty() ? "" :
GetTypeOfBehavior(globalObjectsContainer, objectsContainer, function.behaviorName);
const gd::ExpressionMetadata &metadata = function.behaviorName.empty() ?
function.objectName.empty() ?
MetadataProvider::GetAnyExpressionMetadata(platform, function.functionName) :
MetadataProvider::GetObjectAnyExpressionMetadata(
platform, objectType, function.functionName) :
MetadataProvider::GetBehaviorAnyExpressionMetadata(
platform, behaviorType, function.functionName);
if (!function.objectName.empty()) {
// If the function needs a capability on the object that may not be covered
// by all objects, check it now.
if (!metadata.GetRequiredBaseObjectCapability().empty()) {
const gd::ObjectMetadata &objectMetadata =
MetadataProvider::GetObjectMetadata(platform, objectType);
if (objectMetadata.IsUnsupportedBaseObjectCapability(
metadata.GetRequiredBaseObjectCapability())) {
RaiseTypeError(
_("This expression exists, but it can't be used on this object."),
function.objectNameLocation);
return StringToType(metadata.GetReturnType());
}
}
}
Type returnType = StringToType(metadata.GetReturnType());
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
RaiseError(
"invalid_function_name",
_("Cannot find an expression with this name: ") +
function.functionName + "\n" +
_("Double check that you've not made any typo in the name."),
function.location);
return returnType;
}
// Validate the type of the function
if (returnType == Type::Number) {
if (parentType == Type::String) {
RaiseTypeError(
_("You tried to use an expression that returns a number, but a "
"string is expected. Use `ToString` if you need to convert a "
"number to a string."),
function.location);
return returnType;
}
else if (parentType != Type::Number && parentType != Type::NumberOrString) {
RaiseTypeError(_("You tried to use an expression that returns a "
"number, but another type is expected:") +
" " + TypeToString(parentType),
function.location);
return returnType;
}
} else if (returnType == Type::String) {
if (parentType == Type::Number) {
RaiseTypeError(
_("You tried to use an expression that returns a string, but a "
"number is expected. Use `ToNumber` if you need to convert a "
"string to a number."),
function.location);
return returnType;
}
else if (parentType != Type::String && parentType != Type::NumberOrString) {
RaiseTypeError(_("You tried to use an expression that returns a "
"string, but another type is expected:") +
" " + TypeToString(parentType),
function.location);
return returnType;
}
} else {
if (parentType != returnType) {
RaiseTypeError(
_("You tried to use an expression with the wrong return type:") + " " +
TypeToString(returnType),
function.location);
return returnType;
}
}
// Validate parameters count
size_t minParametersCount = GetMinimumParametersNumber(
metadata.parameters,
ExpressionParser2::WrittenParametersFirstIndex(function.objectName, function.behaviorName));
size_t maxParametersCount = GetMaximumParametersNumber(
metadata.parameters,
ExpressionParser2::WrittenParametersFirstIndex(function.objectName, function.behaviorName));
if (function.parameters.size() < minParametersCount ||
function.parameters.size() > maxParametersCount) {
gd::String expectedCountMessage =
minParametersCount == maxParametersCount
? _("The number of parameters must be exactly ") +
gd::String::From(minParametersCount)
: _("The number of parameters must be: ") +
gd::String::From(minParametersCount) + "-" +
gd::String::From(maxParametersCount);
if (function.parameters.size() < minParametersCount) {
RaiseError(
"too_few_parameters",
_("You have not entered enough parameters for the expression.") + " " +
expectedCountMessage,
function.location);
}
else {
RaiseError(
"extra_parameter",
_("This parameter was not expected by this expression. Remove it "
"or verify that you've entered the proper expression name.") + " " +
expectedCountMessage,
ExpressionParserLocation(
function.parameters[maxParametersCount]->location.GetStartPosition(),
function.location.GetEndPosition() - 1));
}
return returnType;
}
// TODO: reverse the order of diagnostic?
size_t writtenParametersFirstIndex =
ExpressionParser2::WrittenParametersFirstIndex(
function.objectName, function.behaviorName);
int metadataIndex = writtenParametersFirstIndex;
for (int parameterIndex = 0; parameterIndex < function.parameters.size(); parameterIndex++) {
auto& parameter = function.parameters[parameterIndex];
while (metadata.GetParameters()[metadataIndex].IsCodeOnly()) {
// The sizes are already checked above.
metadataIndex++;
}
auto& parameterMetadata = metadata.GetParameters()[metadataIndex];
if (!parameterMetadata.IsOptional() || dynamic_cast<EmptyNode*>(parameter.get()) == nullptr) {
auto currentParentType = parentType;
parentType = StringToType(parameterMetadata.GetType());
parameter->Visit(*this);
parentType = currentParentType;
const gd::String &expectedParameterType = parameterMetadata.GetType();
if (gd::ParameterMetadata::IsExpression(
ExpressionValidator::variableTypeString, expectedParameterType)) {
if (dynamic_cast<IdentifierNode *>(parameter.get()) == nullptr
&& dynamic_cast<VariableNode *>(parameter.get()) == nullptr) {
RaiseError(
"malformed_variable_parameter",
_("A variable name was expected but something else was "
"written. Enter just the name of the variable for this "
"parameter."),
parameter->location);
}
}
else if (gd::ParameterMetadata::IsObject(expectedParameterType)) {
if (dynamic_cast<IdentifierNode *>(parameter.get()) == nullptr) {
RaiseError(
"malformed_object_parameter",
_("An object name was expected but something else was "
"written. Enter just the name of the object for this "
"parameter."),
parameter->location);
}
}
// String and number are already checked in children.
else if (!gd::ParameterMetadata::IsExpression(
ExpressionValidator::numberTypeString, expectedParameterType)
&& !gd::ParameterMetadata::IsExpression(
ExpressionValidator::stringTypeString, expectedParameterType)) {
RaiseError(
"unknown_parameter_type",
_("This function is improperly set up. Reach out to the "
"extension developer or a GDevelop maintainer to fix "
"this issue"),
parameter->location);
}
}
metadataIndex++;
}
return returnType;
}
// TODO factorize in a file with an enum and helpers?
const gd::String ExpressionValidator::unknownTypeString = "unknown";
const gd::String ExpressionValidator::numberTypeString = "number";
const gd::String ExpressionValidator::stringTypeString = "string";
const gd::String ExpressionValidator::numberOrStringTypeString = "number|string";
const gd::String ExpressionValidator::variableTypeString = "variable";
const gd::String ExpressionValidator::objectTypeString = "object";
const gd::String ExpressionValidator::emptyTypeString = "empty";
const gd::String &ExpressionValidator::TypeToString(Type type) {
switch (type) {
case Type::Unknown:
return unknownTypeString;
case Type::Number:
return numberTypeString;
case Type::String:
return stringTypeString;
case Type::NumberOrString:
return numberOrStringTypeString;
case Type::Variable:
return variableTypeString;
case Type::Object:
return objectTypeString;
case Type::Empty:
return emptyTypeString;
}
return unknownTypeString;
}
ExpressionValidator::Type ExpressionValidator::StringToType(const gd::String &type) {
if (type == ExpressionValidator::numberTypeString
|| gd::ParameterMetadata::IsExpression(ExpressionValidator::numberTypeString, type)) {
return Type::Number;
}
if (type == ExpressionValidator::stringTypeString
|| gd::ParameterMetadata::IsExpression(ExpressionValidator::stringTypeString, type)) {
return Type::String;
}
if (type == ExpressionValidator::numberOrStringTypeString) {
return Type::NumberOrString;
}
if (type == ExpressionValidator::variableTypeString
|| gd::ParameterMetadata::IsExpression(ExpressionValidator::variableTypeString, type)) {
return Type::Variable;
}
if (type == ExpressionValidator::objectTypeString
|| gd::ParameterMetadata::IsObject(type)) {
return Type::Object;
}
return Type::Unknown;
}
} // namespace gd

View File

@@ -10,10 +10,6 @@
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Tools/MakeUnique.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
namespace gd {
class Expression;
class ObjectsContainer;
@@ -32,27 +28,15 @@ namespace gd {
*/
class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
public:
ExpressionValidator(const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String &rootType_)
: platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
parentType(StringToType(gd::ParameterMetadata::GetExpressionValueType(rootType_))),
childType(Type::Unknown) {};
ExpressionValidator(){};
virtual ~ExpressionValidator(){};
/**
* \brief Helper function to check if a given node does not contain
* any error.
*/
static bool HasNoErrors(const gd::Platform &platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String &rootType,
gd::ExpressionNode& node) {
gd::ExpressionValidator validator(platform, globalObjectsContainer, objectsContainer, rootType);
static bool HasNoErrors(gd::ExpressionNode& node) {
gd::ExpressionValidator validator;
node.Visit(validator);
return validator.GetErrors().empty();
}
@@ -72,247 +56,52 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
node.expression->Visit(*this);
}
void OnVisitOperatorNode(OperatorNode& node) override {
ReportAnyError(node);
node.leftHandSide->Visit(*this);
const Type leftType = childType;
if (leftType == Type::Number) {
if (node.op == ' ') {
RaiseError("syntax_error",
"No operator found. Did you forget to enter an operator (like +, -, "
"* or /) between numbers or expressions?", node.rightHandSide->location);
}
}
else if (leftType == Type::String) {
if (node.op == ' ') {
RaiseError("syntax_error",
"You must add the operator + between texts or expressions. For "
"example: \"Your name: \" + VariableString(PlayerName).", node.rightHandSide->location);
}
else if (node.op != '+') {
RaiseOperatorError(
_("You've used an operator that is not supported. Only + can be used "
"to concatenate texts."),
ExpressionParserLocation(node.leftHandSide->location.GetEndPosition() + 1, node.location.GetEndPosition()));
}
} else if (leftType == Type::Object) {
RaiseOperatorError(
_("Operators (+, -, /, *) can't be used with an object name. Remove "
"the operator."),
node.rightHandSide->location);
} else if (leftType == Type::Variable) {
RaiseOperatorError(
_("Operators (+, -, /, *) can't be used in variable names. Remove "
"the operator from the variable name."),
node.rightHandSide->location);
}
parentType = leftType;
ReportAnyError(node);
node.rightHandSide->Visit(*this);
const Type rightType = childType;
childType = leftType;
}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
ReportAnyError(node);
node.factor->Visit(*this);
const Type rightType = childType;
if (rightType == Type::Number) {
if (node.op != '+' && node.op != '-') {
// This is actually a dead code because the parser takes them as
// binary operations with an empty left side which makes as much sense.
RaiseTypeError(
_("You've used an \"unary\" operator that is not supported. Operator "
"should be "
"either + or -."),
node.location);
}
} else if (rightType == Type::String) {
RaiseTypeError(
_("You've used an operator that is not supported. Only + can be used "
"to concatenate texts, and must be placed between two texts (or "
"expressions)."),
node.location);
} else if (rightType == Type::Object) {
RaiseTypeError(
_("Operators (+, -) can't be used with an object name. Remove the "
"operator."),
node.location);
} else if (rightType == Type::Variable) {
RaiseTypeError(
_("Operators (+, -) can't be used in variable names. Remove "
"the operator from the variable name."),
node.location);
}
}
void OnVisitNumberNode(NumberNode& node) override {
ReportAnyError(node);
childType = Type::Number;
CheckType(parentType, childType, node.location);
}
void OnVisitTextNode(TextNode& node) override {
ReportAnyError(node);
childType = Type::String;
CheckType(parentType, childType, node.location);
}
void OnVisitNumberNode(NumberNode& node) override { ReportAnyError(node); }
void OnVisitTextNode(TextNode& node) override { ReportAnyError(node); }
void OnVisitVariableNode(VariableNode& node) override {
ReportAnyError(node);
if (node.child) {
node.child->Visit(*this);
}
childType = Type::Variable;
CheckType(parentType, childType, node.location);
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
ReportAnyError(node);
if (node.child) {
node.child->Visit(*this);
}
if (node.child) node.child->Visit(*this);
}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {
ReportAnyError(node);
Type currentParentType = parentType;
parentType = Type::NumberOrString;
node.expression->Visit(*this);
parentType = currentParentType;
if (node.child) {
node.child->Visit(*this);
}
if (node.child) node.child->Visit(*this);
}
void OnVisitIdentifierNode(IdentifierNode& node) override {
ReportAnyError(node);
if (parentType == Type::String) {
RaiseTypeError(_("You must wrap your text inside double quotes "
"(example: \"Hello world\")."),
node.location);
}
else if (parentType == Type::Number) {
RaiseTypeError(
_("You must enter a number."), node.location);
}
else if (parentType == Type::NumberOrString) {
RaiseTypeError(
_("You must enter a number or a text, wrapped inside double quotes "
"(example: \"Hello world\")."),
node.location);
}
else if (parentType != Type::Object && parentType != Type::Variable) {
// It can't happen.
RaiseTypeError(
_("You've entered a name, but this type was expected:") + " " + TypeToString(parentType),
node.location);
}
childType = parentType;
}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
ReportAnyError(node);
}
void OnVisitFunctionCallNode(FunctionCallNode& node) override {
childType = ValidateFunction(node);
}
void OnVisitEmptyNode(EmptyNode& node) override {
ReportAnyError(node);
gd::String message;
if (parentType == Type::Number) {
message = _("You must enter a number or a valid expression call.");
} else if (parentType == Type::String) {
message = _(
"You must enter a text (between quotes) or a valid expression call.");
} else if (parentType == Type::Variable) {
message = _("You must enter a variable name.");
} else if (parentType == Type::Object) {
message = _("You must enter a valid object name.");
} else {
// It can't happen.
message = _("You must enter a valid expression.");
for (auto& parameter : node.parameters) {
parameter->Visit(*this);
}
RaiseTypeError(message, node.location);
childType = Type::Empty;
}
void OnVisitEmptyNode(EmptyNode& node) override { ReportAnyError(node); }
private:
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, Object, Empty};
Type ValidateFunction(const gd::FunctionCallNode& function);
void ReportAnyError(const ExpressionNode& node) {
void ReportAnyError(ExpressionNode& node) {
if (node.diagnostic && node.diagnostic->IsError()) {
// Syntax errors are holden by the AST nodes.
// It's fine to give pointers on them as the AST live longer than errors
// handling.
errors.push_back(node.diagnostic.get());
}
}
void RaiseError(const gd::String &type,
const gd::String &message, const ExpressionParserLocation &location) {
auto diagnostic = gd::make_unique<ExpressionParserError>(
type, message, location);
errors.push_back(diagnostic.get());
// Errors found by the validator are not holden by the AST nodes.
// They must be owned by the validator to keep living while errors are
// handled by the caller.
supplementalErrors.push_back(std::move(diagnostic));
}
void RaiseTypeError(
const gd::String &message, const ExpressionParserLocation &location) {
RaiseError("type_error", message, location);
}
void RaiseOperatorError(
const gd::String &message, const ExpressionParserLocation &location) {
RaiseError("invalid_operator", message, location);
}
void CheckType(Type expect, Type actual, const ExpressionParserLocation &location) {
if (actual == Type::String) {
if (expect == Type::Number) {
RaiseTypeError(_("You entered a text, but a number was expected."),
location);
}
else if (expect != Type::String && expect != Type::NumberOrString) {
RaiseTypeError(
_("You entered a text, but this type was expected:") + " " + TypeToString(expect),
location);
}
}
else if (actual == Type::Number) {
if (expect == Type::String) {
RaiseTypeError(
_("You entered a number, but a text was expected (in quotes)."),
location);
}
else if (expect != Type::Number && expect != Type::NumberOrString) {
RaiseTypeError(
_("You entered a number, but this type was expected:") + " " + TypeToString(expect),
location);
}
}
}
static Type StringToType(const gd::String &type);
static const gd::String &TypeToString(Type type);
static const gd::String unknownTypeString;
static const gd::String numberTypeString;
static const gd::String stringTypeString;
static const gd::String numberOrStringTypeString;
static const gd::String variableTypeString;
static const gd::String objectTypeString;
static const gd::String identifierTypeString;
static const gd::String emptyTypeString;
std::vector<ExpressionParserDiagnostic*> errors;
std::vector<std::unique_ptr<ExpressionParserDiagnostic>> supplementalErrors;
Type childType;
Type parentType;
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
};
} // namespace gd

View File

@@ -1,172 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef GDCORE_EXPRESSIONVARIABLEOWNERFINDER_H
#define GDCORE_EXPRESSIONVARIABLEOWNERFINDER_H
#include <memory>
#include <vector>
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
#include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
#include "GDCore/Tools/Localization.h"
namespace gd {
class Expression;
class ObjectsContainer;
class Platform;
class ParameterMetadata;
class ExpressionMetadata;
} // namespace gd
namespace gd {
/**
* \brief Find the object name that should be used as a context of the
* expression or sub-expression that a given node represents.
*
* \see gd::ExpressionParser2
*/
class GD_CORE_API ExpressionVariableOwnerFinder : public ExpressionParser2NodeWorker {
public:
/**
* \brief Helper function to find the object name that should be used as a
* context of the expression or sub-expression that a given node represents.
*/
static const gd::String GetObjectName(const gd::Platform &platform,
const gd::ObjectsContainer &globalObjectsContainer,
const gd::ObjectsContainer &objectsContainer,
const gd::String& rootObjectName,
gd::ExpressionNode& node) {
gd::ExpressionVariableOwnerFinder typeFinder(
platform, globalObjectsContainer, objectsContainer, rootObjectName);
node.Visit(typeFinder);
return typeFinder.GetObjectName();
}
virtual ~ExpressionVariableOwnerFinder(){};
protected:
ExpressionVariableOwnerFinder(const gd::Platform &platform_,
const gd::ObjectsContainer &globalObjectsContainer_,
const gd::ObjectsContainer &objectsContainer_,
const gd::String& rootObjectName_)
: platform(platform_),
globalObjectsContainer(globalObjectsContainer_),
objectsContainer(objectsContainer_),
rootObjectName(rootObjectName_),
objectName(""),
variableNode(nullptr) {};
/**
* \brief Get all the errors
*
* No errors means that the expression is valid.
*/
const gd::String &GetObjectName() {
return objectName;
};
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
void OnVisitOperatorNode(OperatorNode& node) override {}
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
void OnVisitNumberNode(NumberNode& node) override {}
void OnVisitTextNode(TextNode& node) override {}
void OnVisitVariableNode(VariableNode& node) override {
if (variableNode != nullptr) {
// This is not possible
return;
}
if (node.parent == nullptr) {
objectName = rootObjectName;
return;
}
variableNode = &node;
node.parent->Visit(*this);
}
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {}
void OnVisitIdentifierNode(IdentifierNode& node) override {
if (variableNode != nullptr) {
// This is not possible
return;
}
if (node.parent == nullptr) {
objectName = rootObjectName;
return;
}
// This node is not necessarily a variable node.
// It will be checked when visiting the FunctionCallNode.
variableNode = &node;
node.parent->Visit(*this);
}
void OnVisitEmptyNode(EmptyNode& node) override {}
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
void OnVisitVariableBracketAccessorNode(
VariableBracketAccessorNode& node) override {}
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {
if (variableNode == nullptr) {
return;
}
int parameterIndex = -1;
for (int i = 0; i < functionCall.parameters.size(); i++) {
if (functionCall.parameters.at(i).get() == variableNode) {
parameterIndex = i;
break;
}
}
if (parameterIndex < 0) {
return;
}
const gd::ParameterMetadata* parameterMetadata =
MetadataProvider::GetFunctionCallParameterMetadata(
platform,
globalObjectsContainer,
objectsContainer,
functionCall,
parameterIndex);
if (parameterMetadata == nullptr
|| parameterMetadata->GetType() != "objectvar") {
return;
}
// The object on which the function is called is returned if no previous
// parameters are objects.
objectName = functionCall.objectName;
for (int previousIndex = parameterIndex - 1; previousIndex >= 0; previousIndex--) {
const gd::ParameterMetadata* previousParameterMetadata =
MetadataProvider::GetFunctionCallParameterMetadata(
platform,
globalObjectsContainer,
objectsContainer,
functionCall,
previousIndex);
if (previousParameterMetadata != nullptr
&& gd::ParameterMetadata::IsObject(previousParameterMetadata->GetType())) {
auto previousParameterNode = functionCall.parameters[previousIndex].get();
IdentifierNode* objectNode = dynamic_cast<IdentifierNode*>(previousParameterNode);
objectName = objectNode->identifierName;
return;
}
}
}
private:
gd::String objectName;
gd::ExpressionNode *variableNode;
const gd::Platform &platform;
const gd::ObjectsContainer &globalObjectsContainer;
const gd::ObjectsContainer &objectsContainer;
const gd::String &rootObjectName;
};
} // namespace gd
#endif // GDCORE_EXPRESSIONVARIABLEOWNERFINDER_H

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