summaryrefslogtreecommitdiff
path: root/modules/gdscript/gdscript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript.cpp')
-rw-r--r--modules/gdscript/gdscript.cpp876
1 files changed, 326 insertions, 550 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 9a4fa5cc86..9170255c02 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -39,17 +39,19 @@
#include "core/os/file_access.h"
#include "core/os/os.h"
#include "core/project_settings.h"
+#include "gdscript_analyzer.h"
+#include "gdscript_cache.h"
#include "gdscript_compiler.h"
+#include "gdscript_parser.h"
+#include "gdscript_warning.h"
///////////////////////////
GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) {
-
name = p_name;
}
bool GDScriptNativeClass::_get(const StringName &p_name, Variant &r_ret) const {
-
bool ok;
int v = ClassDB::get_integer_constant(name, p_name, &ok);
@@ -62,12 +64,10 @@ bool GDScriptNativeClass::_get(const StringName &p_name, Variant &r_ret) const {
}
void GDScriptNativeClass::_bind_methods() {
-
ClassDB::bind_method(D_METHOD("new"), &GDScriptNativeClass::_new);
}
Variant GDScriptNativeClass::_new() {
-
Object *o = instance();
ERR_FAIL_COND_V_MSG(!o, Variant(), "Class type: '" + String(name) + "' is not instantiable.");
@@ -80,12 +80,21 @@ Variant GDScriptNativeClass::_new() {
}
Object *GDScriptNativeClass::instance() {
-
return ClassDB::instance(name);
}
-GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error) {
+void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error) {
+ GDScript *base = p_script->_base;
+ if (base != nullptr) {
+ _super_implicit_constructor(base, p_instance, r_error);
+ if (r_error.error != Callable::CallError::CALL_OK) {
+ return;
+ }
+ }
+ p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error);
+}
+GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error) {
/* STEP 1, CREATE */
GDScriptInstance *instance = memnew(GDScriptInstance);
@@ -103,15 +112,12 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
instance->owner->set_script_instance(instance);
/* STEP 2, INITIALIZE AND CONSTRUCT */
-
{
MutexLock lock(GDScriptLanguage::singleton->lock);
-
instances.insert(instance->owner);
}
- initializer->call(instance, p_args, p_argcount, r_error);
-
+ _super_implicit_constructor(this, instance, r_error);
if (r_error.error != Callable::CallError::CALL_OK) {
instance->script = Ref<GDScript>();
instance->owner->set_script_instance(nullptr);
@@ -119,16 +125,29 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
MutexLock lock(GDScriptLanguage::singleton->lock);
instances.erase(p_owner);
}
-
- ERR_FAIL_COND_V(r_error.error != Callable::CallError::CALL_OK, nullptr); //error constructing
+ ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance.");
}
+ if (p_argcount < 0) {
+ return instance;
+ }
+ if (initializer != nullptr) {
+ initializer->call(instance, p_args, p_argcount, r_error);
+ if (r_error.error != Callable::CallError::CALL_OK) {
+ instance->script = Ref<GDScript>();
+ instance->owner->set_script_instance(nullptr);
+ {
+ MutexLock lock(GDScriptLanguage::singleton->lock);
+ instances.erase(p_owner);
+ }
+ ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance.");
+ }
+ }
//@TODO make thread safe
return instance;
}
Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
-
/* STEP 1, CREATE */
if (!valid) {
@@ -174,7 +193,6 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
}
bool GDScript::can_instance() const {
-
#ifdef TOOLS_ENABLED
return valid && (tool || ScriptServer::is_scripting_enabled());
#else
@@ -183,7 +201,6 @@ bool GDScript::can_instance() const {
}
Ref<Script> GDScript::get_base_script() const {
-
if (_base) {
return Ref<GDScript>(_base);
} else {
@@ -192,16 +209,16 @@ Ref<Script> GDScript::get_base_script() const {
}
StringName GDScript::get_instance_base_type() const {
-
- if (native.is_valid())
+ if (native.is_valid()) {
return native->get_name();
- if (base.is_valid() && base->is_valid())
+ }
+ if (base.is_valid() && base->is_valid()) {
return base->get_instance_base_type();
+ }
return StringName();
}
struct _GDScriptMemberSort {
-
int index;
StringName name;
_FORCE_INLINE_ bool operator<(const _GDScriptMemberSort &p_member) const { return index < p_member.index; }
@@ -210,13 +227,11 @@ struct _GDScriptMemberSort {
#ifdef TOOLS_ENABLED
void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
-
placeholders.erase(p_placeholder);
}
#endif
void GDScript::get_script_method_list(List<MethodInfo> *p_list) const {
-
const GDScript *current = this;
while (current) {
for (const Map<StringName, GDScriptFunction *>::Element *E = current->member_functions.front(); E; E = E->next()) {
@@ -236,15 +251,12 @@ void GDScript::get_script_method_list(List<MethodInfo> *p_list) const {
}
void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const {
-
const GDScript *sptr = this;
List<PropertyInfo> props;
while (sptr) {
-
Vector<_GDScriptMemberSort> msort;
for (Map<StringName, PropertyInfo>::Element *E = sptr->member_info.front(); E; E = E->next()) {
-
_GDScriptMemberSort ms;
ERR_CONTINUE(!sptr->member_indices.has(E->key()));
ms.index = sptr->member_indices[E->key()].index;
@@ -255,7 +267,6 @@ void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const {
msort.sort();
msort.invert();
for (int i = 0; i < msort.size(); i++) {
-
props.push_front(sptr->member_info[msort[i].name]);
}
@@ -268,15 +279,14 @@ void GDScript::get_script_property_list(List<PropertyInfo> *p_list) const {
}
bool GDScript::has_method(const StringName &p_method) const {
-
return member_functions.has(p_method);
}
MethodInfo GDScript::get_method_info(const StringName &p_method) const {
-
const Map<StringName, GDScriptFunction *>::Element *E = member_functions.find(p_method);
- if (!E)
+ if (!E) {
return MethodInfo();
+ }
GDScriptFunction *func = E->get();
MethodInfo mi;
@@ -290,7 +300,6 @@ MethodInfo GDScript::get_method_info(const StringName &p_method) const {
}
bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
-
#ifdef TOOLS_ENABLED
const Map<StringName, Variant>::Element *E = member_default_values_cache.find(p_property);
@@ -307,14 +316,13 @@ bool GDScript::get_property_default_value(const StringName &p_property, Variant
}
ScriptInstance *GDScript::instance_create(Object *p_this) {
-
GDScript *top = this;
- while (top->_base)
+ while (top->_base) {
top = top->_base;
+ }
if (top->native.is_valid()) {
if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) {
-
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'");
}
@@ -338,24 +346,23 @@ PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this)
}
bool GDScript::instance_has(const Object *p_this) const {
-
MutexLock lock(GDScriptLanguage::singleton->lock);
return instances.has((Object *)p_this);
}
bool GDScript::has_source_code() const {
-
return source != "";
}
-String GDScript::get_source_code() const {
+String GDScript::get_source_code() const {
return source;
}
-void GDScript::set_source_code(const String &p_code) {
- if (source == p_code)
+void GDScript::set_source_code(const String &p_code) {
+ if (source == p_code) {
return;
+ }
source = p_code;
#ifdef TOOLS_ENABLED
source_changed_cache = true;
@@ -364,7 +371,6 @@ void GDScript::set_source_code(const String &p_code) {
#ifdef TOOLS_ENABLED
void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) {
-
if (base_cache.is_valid()) {
base_cache->_update_exports_values(values, propnames);
}
@@ -379,10 +385,15 @@ void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<Pro
}
#endif
-bool GDScript::_update_exports() {
-
+bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) {
#ifdef TOOLS_ENABLED
+ static Vector<GDScript *> base_caches;
+ if (!p_recursive_call) {
+ base_caches.clear();
+ }
+ base_caches.append(this);
+
bool changed = false;
if (source_changed_cache) {
@@ -391,21 +402,20 @@ bool GDScript::_update_exports() {
String basedir = path;
- if (basedir == "")
+ if (basedir == "") {
basedir = get_path();
+ }
- if (basedir != "")
+ if (basedir != "") {
basedir = basedir.get_base_dir();
+ }
GDScriptParser parser;
- Error err = parser.parse(source, basedir, true, path);
+ GDScriptAnalyzer analyzer(&parser);
+ Error err = parser.parse(source, path, false);
- if (err == OK) {
-
- const GDScriptParser::Node *root = parser.get_parse_tree();
- ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, false);
-
- const GDScriptParser::ClassNode *c = static_cast<const GDScriptParser::ClassNode *>(root);
+ if (err == OK && analyzer.analyze() == OK) {
+ const GDScriptParser::ClassNode *c = parser.get_tree();
if (base_cache.is_valid()) {
base_cache->inheriters_cache.erase(get_instance_id());
@@ -414,32 +424,29 @@ bool GDScript::_update_exports() {
if (c->extends_used) {
String path = "";
- if (String(c->extends_file) != "" && String(c->extends_file) != get_path()) {
- path = c->extends_file;
+ if (String(c->extends_path) != "" && String(c->extends_path) != get_path()) {
+ path = c->extends_path;
if (path.is_rel_path()) {
-
String base = get_path();
if (base == "" || base.is_rel_path()) {
-
ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());
} else {
path = base.get_base_dir().plus_file(path);
}
}
- } else if (c->extends_class.size() != 0) {
- String base = c->extends_class[0];
+ } else if (c->extends.size() != 0) {
+ const StringName &base = c->extends[0];
- if (ScriptServer::is_global_class(base))
+ if (ScriptServer::is_global_class(base)) {
path = ScriptServer::get_global_class_path(base);
+ }
}
if (path != "") {
if (path != get_path()) {
-
Ref<GDScript> bf = ResourceLoader::load(path);
if (bf.is_valid()) {
-
base_cache = bf;
bf->inheriters_cache.insert(get_instance_id());
}
@@ -451,19 +458,36 @@ bool GDScript::_update_exports() {
members_cache.clear();
member_default_values_cache.clear();
+ _signals.clear();
- for (int i = 0; i < c->variables.size(); i++) {
- if (c->variables[i]._export.type == Variant::NIL)
- continue;
-
- members_cache.push_back(c->variables[i]._export);
- member_default_values_cache[c->variables[i].identifier] = c->variables[i].default_value;
- }
+ for (int i = 0; i < c->members.size(); i++) {
+ const GDScriptParser::ClassNode::Member &member = c->members[i];
- _signals.clear();
+ switch (member.type) {
+ case GDScriptParser::ClassNode::Member::VARIABLE: {
+ if (!member.variable->exported) {
+ continue;
+ }
- for (int i = 0; i < c->_signals.size(); i++) {
- _signals[c->_signals[i].name] = c->_signals[i].arguments;
+ members_cache.push_back(member.variable->export_info);
+ Variant default_value;
+ if (member.variable->initializer && member.variable->initializer->is_constant) {
+ default_value = member.variable->initializer->reduced_value;
+ }
+ member_default_values_cache[member.variable->identifier->name] = default_value;
+ } break;
+ case GDScriptParser::ClassNode::Member::SIGNAL: {
+ // TODO: Cache this in parser to avoid loops like this.
+ Vector<StringName> parameters_names;
+ parameters_names.resize(member.signal->parameters.size());
+ for (int j = 0; j < member.signal->parameters.size(); j++) {
+ parameters_names.write[j] = member.signal->parameters[j]->identifier->name;
+ }
+ _signals[member.signal->identifier->name] = parameters_names;
+ } break;
+ default:
+ break; // Nothing.
+ }
}
} else {
placeholder_fallback_enabled = true;
@@ -476,7 +500,24 @@ bool GDScript::_update_exports() {
placeholder_fallback_enabled = false;
if (base_cache.is_valid() && base_cache->is_valid()) {
- if (base_cache->_update_exports()) {
+ for (int i = 0; i < base_caches.size(); i++) {
+ if (base_caches[i] == base_cache.ptr()) {
+ if (r_err) {
+ *r_err = true;
+ }
+ valid = false; // to show error in the editor
+ base_cache->valid = false;
+ base_cache->inheriters_cache.clear(); // to prevent future stackoverflows
+ base_cache.unref();
+ base.unref();
+ _base = nullptr;
+ ERR_FAIL_V_MSG(false, "Cyclic inheritance in script class.");
+ }
+ }
+ if (base_cache->_update_exports(r_err, true)) {
+ if (r_err && *r_err) {
+ return false;
+ }
changed = true;
}
}
@@ -501,18 +542,22 @@ bool GDScript::_update_exports() {
}
void GDScript::update_exports() {
-
#ifdef TOOLS_ENABLED
- _update_exports();
+ bool cyclic_error = false;
+ _update_exports(&cyclic_error);
+ if (cyclic_error) {
+ return;
+ }
Set<ObjectID> copy = inheriters_cache; //might get modified
for (Set<ObjectID>::Element *E = copy.front(); E; E = E->next()) {
Object *id = ObjectDB::get_instance(E->get());
GDScript *s = Object::cast_to<GDScript>(id);
- if (!s)
+ if (!s) {
continue;
+ }
s->update_exports();
}
@@ -520,16 +565,13 @@ void GDScript::update_exports() {
}
void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) {
-
p_sc->path = p_path;
for (Map<StringName, Ref<GDScript>>::Element *E = p_sc->subclasses.front(); E; E = E->next()) {
-
_set_subclass_path(E->get(), p_path);
}
}
Error GDScript::reload(bool p_keep_state) {
-
bool has_instances;
{
MutexLock lock(GDScriptLanguage::singleton->lock);
@@ -541,11 +583,13 @@ Error GDScript::reload(bool p_keep_state) {
String basedir = path;
- if (basedir == "")
+ if (basedir == "") {
basedir = get_path();
+ }
- if (basedir != "")
+ if (basedir != "") {
basedir = basedir.get_base_dir();
+ }
if (source.find("%BASE%") != -1) {
//loading a template, don't parse
@@ -554,22 +598,34 @@ Error GDScript::reload(bool p_keep_state) {
valid = false;
GDScriptParser parser;
- Error err = parser.parse(source, basedir, false, path);
+ Error err = parser.parse(source, path, false);
if (err) {
if (EngineDebugger::is_active()) {
- GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_error_line(), "Parser Error: " + parser.get_error());
+ GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
}
- _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_error_line(), ("Parse Error: " + parser.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ // TODO: Show all error messages.
+ _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
ERR_FAIL_V(ERR_PARSE_ERROR);
}
- bool can_run = ScriptServer::is_scripting_enabled() || parser.is_tool_script();
+ GDScriptAnalyzer analyzer(&parser);
+ err = analyzer.analyze();
+
+ if (err) {
+ if (EngineDebugger::is_active()) {
+ GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
+ }
+ // TODO: Show all error messages.
+ _err_print_error("GDScript::reload", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ ERR_FAIL_V(ERR_PARSE_ERROR);
+ }
+
+ bool can_run = ScriptServer::is_scripting_enabled() || parser.is_tool();
GDScriptCompiler compiler;
err = compiler.compile(&parser, this, p_keep_state);
if (err) {
-
if (can_run) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error());
@@ -585,7 +641,7 @@ Error GDScript::reload(bool p_keep_state) {
const GDScriptWarning &warning = E->get();
if (EngineDebugger::is_active()) {
Vector<ScriptLanguage::StackInfo> si;
- EngineDebugger::get_script_debugger()->send_error("", get_path(), warning.line, warning.get_name(), warning.get_message(), ERR_HANDLER_WARNING, si);
+ EngineDebugger::get_script_debugger()->send_error("", get_path(), warning.start_line, warning.get_name(), warning.get_message(), ERR_HANDLER_WARNING, si);
}
}
#endif
@@ -593,7 +649,6 @@ Error GDScript::reload(bool p_keep_state) {
valid = true;
for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) {
-
_set_subclass_path(E->get(), path);
}
@@ -603,12 +658,10 @@ Error GDScript::reload(bool p_keep_state) {
}
ScriptLanguage *GDScript::get_language() const {
-
return GDScriptLanguage::get_singleton();
}
void GDScript::get_constants(Map<StringName, Variant> *p_constants) {
-
if (p_constants) {
for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
(*p_constants)[E->key()] = E->value();
@@ -638,12 +691,16 @@ uint16_t GDScript::get_rpc_method_id(const StringName &p_method) const {
}
StringName GDScript::get_rpc_method(const uint16_t p_rpc_method_id) const {
- ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName());
+ if (p_rpc_method_id >= rpc_functions.size()) {
+ return StringName();
+ }
return rpc_functions[p_rpc_method_id].name;
}
MultiplayerAPI::RPCMode GDScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const {
- ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED);
+ if (p_rpc_method_id >= rpc_functions.size()) {
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+ }
return rpc_functions[p_rpc_method_id].mode;
}
@@ -665,12 +722,16 @@ uint16_t GDScript::get_rset_property_id(const StringName &p_variable) const {
}
StringName GDScript::get_rset_property(const uint16_t p_rset_member_id) const {
- ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), StringName());
+ if (p_rset_member_id >= rpc_variables.size()) {
+ return StringName();
+ }
return rpc_variables[p_rset_member_id].name;
}
MultiplayerAPI::RPCMode GDScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const {
- ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), MultiplayerAPI::RPC_MODE_DISABLED);
+ if (p_rset_member_id >= rpc_variables.size()) {
+ return MultiplayerAPI::RPC_MODE_DISABLED;
+ }
return rpc_variables[p_rset_member_id].mode;
}
@@ -679,13 +740,10 @@ MultiplayerAPI::RPCMode GDScript::get_rset_mode(const StringName &p_variable) co
}
Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
-
GDScript *top = this;
while (top) {
-
Map<StringName, GDScriptFunction *>::Element *E = top->member_functions.find(p_method);
if (E) {
-
ERR_FAIL_COND_V_MSG(!E->get()->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
return E->get()->call(nullptr, p_args, p_argcount, r_error);
@@ -699,16 +757,12 @@ Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p
}
bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
-
{
-
const GDScript *top = this;
while (top) {
-
{
const Map<StringName, Variant>::Element *E = top->constants.find(p_name);
if (E) {
-
r_ret = E->get();
return true;
}
@@ -717,7 +771,6 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
{
const Map<StringName, Ref<GDScript>>::Element *E = subclasses.find(p_name);
if (E) {
-
r_ret = E->get();
return true;
}
@@ -726,7 +779,6 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
}
if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
-
r_ret = get_source_code();
return true;
}
@@ -734,120 +786,42 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
return false;
}
-bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
+bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
if (p_name == GDScriptLanguage::get_singleton()->strings._script_source) {
-
set_source_code(p_value);
reload();
- } else
+ } else {
return false;
+ }
return true;
}
void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
-
p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
void GDScript::_bind_methods() {
-
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo("new"));
ClassDB::bind_method(D_METHOD("get_as_byte_code"), &GDScript::get_as_byte_code);
}
Vector<uint8_t> GDScript::get_as_byte_code() const {
-
- GDScriptTokenizerBuffer tokenizer;
- return tokenizer.parse_code_string(source);
+ return Vector<uint8_t>();
};
+// TODO: Fully remove this. There's not this kind of "bytecode" anymore.
Error GDScript::load_byte_code(const String &p_path) {
-
- Vector<uint8_t> bytecode;
-
- if (p_path.ends_with("gde")) {
-
- FileAccess *fa = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V(!fa, ERR_CANT_OPEN);
-
- FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
- ERR_FAIL_COND_V(!fae, ERR_CANT_OPEN);
-
- Vector<uint8_t> key;
- key.resize(32);
- for (int i = 0; i < key.size(); i++) {
- key.write[i] = script_encryption_key[i];
- }
-
- Error err = fae->open_and_parse(fa, key, FileAccessEncrypted::MODE_READ);
-
- if (err) {
- fa->close();
- memdelete(fa);
- memdelete(fae);
-
- ERR_FAIL_COND_V(err, err);
- }
-
- bytecode.resize(fae->get_len());
- fae->get_buffer(bytecode.ptrw(), bytecode.size());
- fae->close();
- memdelete(fae);
-
- } else {
-
- bytecode = FileAccess::get_file_as_array(p_path);
- }
-
- ERR_FAIL_COND_V(bytecode.size() == 0, ERR_PARSE_ERROR);
- path = p_path;
-
- String basedir = path;
-
- if (basedir == "")
- basedir = get_path();
-
- if (basedir != "")
- basedir = basedir.get_base_dir();
-
- valid = false;
- GDScriptParser parser;
- Error err = parser.parse_bytecode(bytecode, basedir, get_path());
- if (err) {
- _err_print_error("GDScript::load_byte_code", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_error_line(), ("Parse Error: " + parser.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
- ERR_FAIL_V(ERR_PARSE_ERROR);
- }
-
- GDScriptCompiler compiler;
- err = compiler.compile(&parser, this);
-
- if (err) {
- _err_print_error("GDScript::load_byte_code", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
- ERR_FAIL_V(ERR_COMPILATION_FAILED);
- }
-
- valid = true;
-
- for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) {
-
- _set_subclass_path(E->get(), path);
- }
-
- _init_rpc_methods_properties();
-
- return OK;
+ return ERR_COMPILATION_FAILED;
}
Error GDScript::load_source_code(const String &p_path) {
-
Vector<uint8_t> sourcef;
Error err;
FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
-
ERR_FAIL_COND_V(err, err);
}
@@ -862,7 +836,6 @@ Error GDScript::load_source_code(const String &p_path) {
String s;
if (s.parse_utf8((const char *)w)) {
-
ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded. Please ensure that scripts are saved in valid UTF-8 unicode.");
}
@@ -875,29 +848,45 @@ Error GDScript::load_source_code(const String &p_path) {
}
const Map<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const {
-
return member_functions;
}
StringName GDScript::debug_get_member_by_index(int p_idx) const {
-
for (const Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) {
-
- if (E->get().index == p_idx)
+ if (E->get().index == p_idx) {
return E->key();
+ }
}
return "<error>";
}
Ref<GDScript> GDScript::get_base() const {
-
return base;
}
+bool GDScript::inherits_script(const Ref<Script> &p_script) const {
+ Ref<GDScript> gd = p_script;
+ if (gd.is_null()) {
+ return false;
+ }
+
+ const GDScript *s = this;
+
+ while (s) {
+ if (s == p_script.ptr()) {
+ return true;
+ }
+ s = s->_base;
+ }
+
+ return false;
+}
+
bool GDScript::has_script_signal(const StringName &p_signal) const {
- if (_signals.has(p_signal))
+ if (_signals.has(p_signal)) {
return true;
+ }
if (base.is_valid()) {
return base->has_script_signal(p_signal);
}
@@ -908,10 +897,9 @@ bool GDScript::has_script_signal(const StringName &p_signal) const {
#endif
return false;
}
-void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
for (const Map<StringName, Vector<StringName>>::Element *E = _signals.front(); E; E = E->next()) {
-
MethodInfo mi;
mi.name = E->key();
for (int i = 0; i < E->get().size(); i++) {
@@ -935,7 +923,6 @@ void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
GDScript::GDScript() :
script_list(this) {
-
valid = false;
subclass_count = 0;
initializer = nullptr;
@@ -980,8 +967,9 @@ void GDScript::_save_orphaned_subclasses() {
for (int i = 0; i < weak_subclasses.size(); i++) {
ClassRefWithName subclass = weak_subclasses[i];
Object *obj = ObjectDB::get_instance(subclass.id);
- if (!obj)
+ if (!obj) {
continue;
+ }
// subclass is not released
GDScriptLanguage::get_singleton()->add_orphan_subclass(subclass.fully_qualified_name, subclass.id);
}
@@ -1022,13 +1010,15 @@ void GDScript::_init_rpc_methods_properties() {
}
}
- if (cscript != this)
+ if (cscript != this) {
sub_E = sub_E->next();
+ }
- if (sub_E)
+ if (sub_E) {
cscript = sub_E->get().ptr();
- else
+ } else {
cscript = nullptr;
+ }
}
// Sort so we are 100% that they are always the same.
@@ -1037,10 +1027,21 @@ void GDScript::_init_rpc_methods_properties() {
}
GDScript::~GDScript() {
+ {
+ MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+
+ while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
+ E->self()->_clear_stack();
+ pending_func_states.remove(E);
+ }
+ }
+
for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
memdelete(E->get());
}
+ GDScriptCache::remove_script(get_path());
+
_save_orphaned_subclasses();
#ifdef DEBUG_ENABLED
@@ -1057,7 +1058,6 @@ GDScript::~GDScript() {
//////////////////////////////
bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
-
//member
{
const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
@@ -1092,17 +1092,16 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
GDScript *sptr = script.ptr();
while (sptr) {
-
Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
if (E) {
-
Variant name = p_name;
const Variant *args[2] = { &name, &p_value };
Callable::CallError err;
Variant ret = E->get()->call(this, (const Variant **)args, 2, err);
- if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool())
+ if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
return true;
+ }
}
sptr = sptr->_base;
}
@@ -1111,10 +1110,8 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
}
bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
-
const GDScript *sptr = script.ptr();
while (sptr) {
-
{
const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
if (E) {
@@ -1131,7 +1128,6 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
}
{
-
const GDScript *sl = sptr;
while (sl) {
const Map<StringName, Variant>::Element *E = sl->constants.find(p_name);
@@ -1144,9 +1140,34 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
}
{
+ // Signals.
+ const GDScript *sl = sptr;
+ while (sl) {
+ const Map<StringName, Vector<StringName>>::Element *E = sl->_signals.find(p_name);
+ if (E) {
+ r_ret = Signal(this->owner, E->key());
+ return true; //index found
+ }
+ sl = sl->_base;
+ }
+ }
+
+ {
+ // Methods.
+ const GDScript *sl = sptr;
+ while (sl) {
+ const Map<StringName, GDScriptFunction *>::Element *E = sl->member_functions.find(p_name);
+ if (E) {
+ r_ret = Callable(this->owner, E->key());
+ return true; //index found
+ }
+ sl = sl->_base;
+ }
+ }
+
+ {
const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);
if (E) {
-
Variant name = p_name;
const Variant *args[1] = { &name };
@@ -1165,20 +1186,20 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
}
Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
-
const GDScript *sptr = script.ptr();
while (sptr) {
-
if (sptr->member_info.has(p_name)) {
- if (r_is_valid)
+ if (r_is_valid) {
*r_is_valid = true;
+ }
return sptr->member_info[p_name].type;
}
sptr = sptr->_base;
}
- if (r_is_valid)
+ if (r_is_valid) {
*r_is_valid = false;
+ }
return Variant::NIL;
}
@@ -1189,19 +1210,15 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
List<PropertyInfo> props;
while (sptr) {
-
const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
if (E) {
-
Callable::CallError err;
Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) {
-
ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries.");
Array arr = ret;
for (int i = 0; i < arr.size(); i++) {
-
Dictionary d = arr[i];
ERR_CONTINUE(!d.has("name"));
ERR_CONTINUE(!d.has("type"));
@@ -1210,12 +1227,15 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX);
pinfo.name = d["name"];
ERR_CONTINUE(pinfo.name == "");
- if (d.has("hint"))
+ if (d.has("hint")) {
pinfo.hint = PropertyHint(d["hint"].operator int());
- if (d.has("hint_string"))
+ }
+ if (d.has("hint_string")) {
pinfo.hint_string = d["hint_string"];
- if (d.has("usage"))
+ }
+ if (d.has("usage")) {
pinfo.usage = d["usage"];
+ }
props.push_back(pinfo);
}
@@ -1226,7 +1246,6 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
Vector<_GDScriptMemberSort> msort;
for (Map<StringName, PropertyInfo>::Element *F = sptr->member_info.front(); F; F = F->next()) {
-
_GDScriptMemberSort ms;
ERR_CONTINUE(!sptr->member_indices.has(F->key()));
ms.index = sptr->member_indices[F->key()].index;
@@ -1237,7 +1256,6 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
msort.sort();
msort.invert();
for (int i = 0; i < msort.size(); i++) {
-
props.push_front(sptr->member_info[msort[i].name]);
}
@@ -1245,23 +1263,20 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
}
for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
-
p_properties->push_back(E->get());
}
}
void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
-
const GDScript *sptr = script.ptr();
while (sptr) {
-
for (Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.front(); E; E = E->next()) {
-
MethodInfo mi;
mi.name = E->key();
mi.flags |= METHOD_FLAG_FROM_SCRIPT;
- for (int i = 0; i < E->get()->get_argument_count(); i++)
+ for (int i = 0; i < E->get()->get_argument_count(); i++) {
mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i)));
+ }
p_list->push_back(mi);
}
sptr = sptr->_base;
@@ -1269,19 +1284,19 @@ void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
}
bool GDScriptInstance::has_method(const StringName &p_method) const {
-
const GDScript *sptr = script.ptr();
while (sptr) {
const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
- if (E)
+ if (E) {
return true;
+ }
sptr = sptr->_base;
}
return false;
}
-Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
GDScript *sptr = script.ptr();
while (sptr) {
Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
@@ -1294,42 +1309,7 @@ Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_arg
return Variant();
}
-void GDScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
-
- GDScript *sptr = script.ptr();
- Callable::CallError ce;
-
- while (sptr) {
- Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
- if (E) {
- E->get()->call(this, p_args, p_argcount, ce);
- }
- sptr = sptr->_base;
- }
-}
-
-void GDScriptInstance::_ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount) {
-
- if (sptr->_base)
- _ml_call_reversed(sptr->_base, p_method, p_args, p_argcount);
-
- Callable::CallError ce;
-
- Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
- if (E) {
- E->get()->call(this, p_args, p_argcount, ce);
- }
-}
-
-void GDScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
-
- if (script.ptr()) {
- _ml_call_reversed(script.ptr(), p_method, p_args, p_argcount);
- }
-}
-
void GDScriptInstance::notification(int p_notification) {
-
//notification is not virtual, it gets called at ALL levels just like in C.
Variant value = p_notification;
const Variant *args[1] = { &value };
@@ -1354,27 +1334,28 @@ String GDScriptInstance::to_string(bool *r_valid) {
Variant ret = call(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce);
if (ce.error == Callable::CallError::CALL_OK) {
if (ret.get_type() != Variant::STRING) {
- if (r_valid)
+ if (r_valid) {
*r_valid = false;
+ }
ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String.");
}
- if (r_valid)
+ if (r_valid) {
*r_valid = true;
+ }
return ret.operator String();
}
}
- if (r_valid)
+ if (r_valid) {
*r_valid = false;
+ }
return String();
}
Ref<Script> GDScriptInstance::get_script() const {
-
return script;
}
ScriptLanguage *GDScriptInstance::get_language() {
-
return GDScriptLanguage::get_singleton();
}
@@ -1419,7 +1400,6 @@ MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_vari
}
void GDScriptInstance::reload_members() {
-
#ifdef DEBUG_ENABLED
members.resize(script->member_indices.size()); //resize
@@ -1429,7 +1409,6 @@ void GDScriptInstance::reload_members() {
//pass the values to the new indices
for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) {
-
if (member_indices_cache.has(E->key())) {
Variant value = members[member_indices_cache[E->key()]];
new_members.write[E->get().index] = value;
@@ -1442,7 +1421,6 @@ void GDScriptInstance::reload_members() {
//pass the values to the new indices
member_indices_cache.clear();
for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) {
-
member_indices_cache[E->key()] = E->get().index;
}
@@ -1455,9 +1433,14 @@ GDScriptInstance::GDScriptInstance() {
}
GDScriptInstance::~GDScriptInstance() {
- if (script.is_valid() && owner) {
- MutexLock lock(GDScriptLanguage::singleton->lock);
+ MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+ while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
+ E->self()->_clear_stack();
+ pending_func_states.remove(E);
+ }
+
+ if (script.is_valid() && owner) {
script->instances.erase(owner);
}
}
@@ -1467,14 +1450,12 @@ GDScriptInstance::~GDScriptInstance() {
GDScriptLanguage *GDScriptLanguage::singleton = nullptr;
String GDScriptLanguage::get_name() const {
-
return "GDScript";
}
/* LANGUAGE FUNCTIONS */
void GDScriptLanguage::_add_global(const StringName &p_name, const Variant &p_value) {
-
if (globals.has(p_name)) {
//overwrite existing
global_array.write[globals[p_name]] = p_value;
@@ -1486,7 +1467,6 @@ void GDScriptLanguage::_add_global(const StringName &p_name, const Variant &p_va
}
void GDScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) {
-
_add_global(p_variable, p_value);
}
@@ -1500,11 +1480,9 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) {
}
void GDScriptLanguage::init() {
-
//populate global constants
int gcc = GlobalConstants::get_global_constant_count();
for (int i = 0; i < gcc; i++) {
-
_add_global(StaticCString::create(GlobalConstants::get_global_constant_name(i)), GlobalConstants::get_global_constant_value(i));
}
@@ -1518,14 +1496,15 @@ void GDScriptLanguage::init() {
List<StringName> class_list;
ClassDB::get_class_list(&class_list);
for (List<StringName>::Element *E = class_list.front(); E; E = E->next()) {
-
StringName n = E->get();
String s = String(n);
- if (s.begins_with("_"))
+ if (s.begins_with("_")) {
n = s.substr(1, s.length());
+ }
- if (globals.has(n))
+ if (globals.has(n)) {
continue;
+ }
Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(E->get()));
_add_global(n, nc);
}
@@ -1535,29 +1514,27 @@ void GDScriptLanguage::init() {
List<Engine::Singleton> singletons;
Engine::get_singleton()->get_singletons(&singletons);
for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) {
-
_add_global(E->get().name, E->get().ptr);
}
}
String GDScriptLanguage::get_type() const {
-
return "GDScript";
}
-String GDScriptLanguage::get_extension() const {
+String GDScriptLanguage::get_extension() const {
return "gd";
}
-Error GDScriptLanguage::execute_file(const String &p_path) {
+Error GDScriptLanguage::execute_file(const String &p_path) {
// ??
return OK;
}
+
void GDScriptLanguage::finish() {
}
void GDScriptLanguage::profiling_start() {
-
#ifdef DEBUG_ENABLED
MutexLock lock(this->lock);
@@ -1580,7 +1557,6 @@ void GDScriptLanguage::profiling_start() {
}
void GDScriptLanguage::profiling_stop() {
-
#ifdef DEBUG_ENABLED
MutexLock lock(this->lock);
@@ -1589,7 +1565,6 @@ void GDScriptLanguage::profiling_stop() {
}
int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) {
-
int current = 0;
#ifdef DEBUG_ENABLED
@@ -1597,8 +1572,9 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
- if (current >= p_info_max)
+ if (current >= p_info_max) {
break;
+ }
p_info_arr[current].call_count = elem->self()->profile.call_count;
p_info_arr[current].self_time = elem->self()->profile.self_time;
p_info_arr[current].total_time = elem->self()->profile.total_time;
@@ -1612,7 +1588,6 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,
}
int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) {
-
int current = 0;
#ifdef DEBUG_ENABLED
@@ -1620,8 +1595,9 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
- if (current >= p_info_max)
+ if (current >= p_info_max) {
break;
+ }
if (elem->self()->profile.last_frame_call_count > 0) {
p_info_arr[current].call_count = elem->self()->profile.last_frame_call_count;
p_info_arr[current].self_time = elem->self()->profile.last_frame_self_time;
@@ -1637,12 +1613,11 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_
}
struct GDScriptDepSort {
-
//must support sorting so inheritance works properly (parent must be reloaded first)
bool operator()(const Ref<GDScript> &A, const Ref<GDScript> &B) const {
-
- if (A == B)
+ if (A == B) {
return false; //shouldn't happen but..
+ }
const GDScript *I = B->get_base().ptr();
while (I) {
if (I == A.ptr()) {
@@ -1658,7 +1633,6 @@ struct GDScriptDepSort {
};
void GDScriptLanguage::reload_all_scripts() {
-
#ifdef DEBUG_ENABLED
print_verbose("GDScript: Reloading all scripts");
List<Ref<GDScript>> scripts;
@@ -1680,7 +1654,6 @@ void GDScriptLanguage::reload_all_scripts() {
scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
for (List<Ref<GDScript>>::Element *E = scripts.front(); E; E = E->next()) {
-
print_verbose("GDScript: Reloading: " + E->get()->get_path());
E->get()->load_source_code(E->get()->get_path());
E->get()->reload(true);
@@ -1689,7 +1662,6 @@ void GDScriptLanguage::reload_all_scripts() {
}
void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) {
-
#ifdef DEBUG_ENABLED
List<Ref<GDScript>> scripts;
@@ -1699,7 +1671,6 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
SelfList<GDScript> *elem = script_list.first();
while (elem) {
if (elem->self()->get_path().is_resource_file()) {
-
scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
}
elem = elem->next();
@@ -1715,16 +1686,15 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
for (List<Ref<GDScript>>::Element *E = scripts.front(); E; E = E->next()) {
-
bool reload = E->get() == p_script || to_reload.has(E->get()->get_base());
- if (!reload)
+ if (!reload) {
continue;
+ }
to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant>>>());
if (!p_soft_reload) {
-
//save state and remove script from instances
Map<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[E->get()];
@@ -1733,7 +1703,6 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
//save instance info
List<Pair<StringName, Variant>> state;
if (obj->get_script_instance()) {
-
obj->get_script_instance()->get_property_state(state);
map[obj->get_instance_id()] = state;
obj->set_script(Variant());
@@ -1748,7 +1717,6 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
//save instance info
if (obj->get_script_instance()) {
-
map.insert(obj->get_instance_id(), List<Pair<StringName, Variant>>());
List<Pair<StringName, Variant>> &state = map[obj->get_instance_id()];
obj->get_script_instance()->get_property_state(state);
@@ -1768,18 +1736,17 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
}
for (Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>>::Element *E = to_reload.front(); E; E = E->next()) {
-
Ref<GDScript> scr = E->key();
scr->reload(p_soft_reload);
//restore state if saved
for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = E->get().front(); F; F = F->next()) {
-
List<Pair<StringName, Variant>> &saved_state = F->get();
Object *obj = ObjectDB::get_instance(F->key());
- if (!obj)
+ if (!obj) {
continue;
+ }
if (!p_soft_reload) {
//clear it just in case (may be a pending reload state)
@@ -1818,7 +1785,6 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
}
void GDScriptLanguage::frame() {
-
calls = 0;
#ifdef DEBUG_ENABLED
@@ -1842,7 +1808,7 @@ void GDScriptLanguage::frame() {
/* EDITOR FUNCTIONS */
void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
-
+ // TODO: Add annotations here?
static const char *_reserved_words[] = {
// operators
"and",
@@ -1865,6 +1831,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
// functions
"as",
"assert",
+ "await",
"breakpoint",
"class",
"class_name",
@@ -1872,15 +1839,13 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"is",
"func",
"preload",
- "setget",
"signal",
- "tool",
+ "super",
+ "trait",
"yield",
// var
"const",
"enum",
- "export",
- "onready",
"static",
"var",
// control flow
@@ -1894,19 +1859,12 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"return",
"match",
"while",
- "remote",
- "master",
- "puppet",
- "remotesync",
- "mastersync",
- "puppetsync",
nullptr
};
const char **w = _reserved_words;
while (*w) {
-
p_words->push_back(*w);
w++;
}
@@ -1917,12 +1875,10 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
}
bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
-
return p_type == "GDScript";
}
String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
-
Vector<uint8_t> sourcef;
Error err;
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
@@ -1933,33 +1889,33 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
String source = f->get_as_utf8_string();
GDScriptParser parser;
- parser.parse(source, p_path.get_base_dir(), true, p_path, false, nullptr, true);
-
- if (parser.get_parse_tree() && parser.get_parse_tree()->type == GDScriptParser::Node::TYPE_CLASS) {
+ err = parser.parse(source, p_path, false);
- const GDScriptParser::ClassNode *c = static_cast<const GDScriptParser::ClassNode *>(parser.get_parse_tree());
+ // TODO: Simplify this code by using the analyzer to get full inheritance.
+ if (err == OK) {
+ const GDScriptParser::ClassNode *c = parser.get_tree();
if (r_icon_path) {
- if (c->icon_path.empty() || c->icon_path.is_abs_path())
+ if (c->icon_path.empty() || c->icon_path.is_abs_path()) {
*r_icon_path = c->icon_path;
- else if (c->icon_path.is_rel_path())
+ } else if (c->icon_path.is_rel_path()) {
*r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path();
+ }
}
if (r_base_type) {
-
const GDScriptParser::ClassNode *subclass = c;
String path = p_path;
GDScriptParser subparser;
while (subclass) {
if (subclass->extends_used) {
- if (subclass->extends_file) {
- if (subclass->extends_class.size() == 0) {
- get_global_class_name(subclass->extends_file, r_base_type);
+ if (!subclass->extends_path.empty()) {
+ if (subclass->extends.size() == 0) {
+ get_global_class_name(subclass->extends_path, r_base_type);
subclass = nullptr;
break;
} else {
- Vector<StringName> extend_classes = subclass->extends_class;
+ Vector<StringName> extend_classes = subclass->extends;
- FileAccessRef subfile = FileAccess::open(subclass->extends_file, FileAccess::READ);
+ FileAccessRef subfile = FileAccess::open(subclass->extends_path, FileAccess::READ);
if (!subfile) {
break;
}
@@ -1968,25 +1924,26 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
if (subsource.empty()) {
break;
}
- String subpath = subclass->extends_file;
+ String subpath = subclass->extends_path;
if (subpath.is_rel_path()) {
subpath = path.get_base_dir().plus_file(subpath).simplify_path();
}
- if (OK != subparser.parse(subsource, subpath.get_base_dir(), true, subpath, false, nullptr, true)) {
+ if (OK != subparser.parse(subsource, subpath, false)) {
break;
}
path = subpath;
- if (!subparser.get_parse_tree() || subparser.get_parse_tree()->type != GDScriptParser::Node::TYPE_CLASS) {
- break;
- }
- subclass = static_cast<const GDScriptParser::ClassNode *>(subparser.get_parse_tree());
+ subclass = subparser.get_tree();
while (extend_classes.size() > 0) {
bool found = false;
- for (int i = 0; i < subclass->subclasses.size(); i++) {
- const GDScriptParser::ClassNode *inner_class = subclass->subclasses[i];
- if (inner_class->name == extend_classes[0]) {
+ for (int i = 0; i < subclass->members.size(); i++) {
+ if (subclass->members[i].type != GDScriptParser::ClassNode::Member::CLASS) {
+ continue;
+ }
+
+ const GDScriptParser::ClassNode *inner_class = subclass->members[i].m_class;
+ if (inner_class->identifier->name == extend_classes[0]) {
extend_classes.remove(0);
found = true;
subclass = inner_class;
@@ -1999,8 +1956,8 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
}
}
- } else if (subclass->extends_class.size() == 1) {
- *r_base_type = subclass->extends_class[0];
+ } else if (subclass->extends.size() == 1) {
+ *r_base_type = subclass->extends[0];
subclass = nullptr;
} else {
break;
@@ -2011,183 +1968,13 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
}
}
- return c->name;
+ return c->identifier != nullptr ? String(c->identifier->name) : String();
}
return String();
}
-#ifdef DEBUG_ENABLED
-String GDScriptWarning::get_message() const {
-
-#define CHECK_SYMBOLS(m_amount) ERR_FAIL_COND_V(symbols.size() < m_amount, String());
-
- switch (code) {
- case UNASSIGNED_VARIABLE_OP_ASSIGN: {
- CHECK_SYMBOLS(1);
- return "Using assignment with operation but the variable '" + symbols[0] + "' was not previously assigned a value.";
- } break;
- case UNASSIGNED_VARIABLE: {
- CHECK_SYMBOLS(1);
- return "The variable '" + symbols[0] + "' was used but never assigned a value.";
- } break;
- case UNUSED_VARIABLE: {
- CHECK_SYMBOLS(1);
- return "The local variable '" + symbols[0] + "' is declared but never used in the block. If this is intended, prefix it with an underscore: '_" + symbols[0] + "'";
- } break;
- case SHADOWED_VARIABLE: {
- CHECK_SYMBOLS(2);
- return "The local variable '" + symbols[0] + "' is shadowing an already-defined variable at line " + symbols[1] + ".";
- } break;
- case UNUSED_CLASS_VARIABLE: {
- CHECK_SYMBOLS(1);
- return "The class variable '" + symbols[0] + "' is declared but never used in the script.";
- } break;
- case UNUSED_ARGUMENT: {
- CHECK_SYMBOLS(2);
- return "The argument '" + symbols[1] + "' is never used in the function '" + symbols[0] + "'. If this is intended, prefix it with an underscore: '_" + symbols[1] + "'";
- } break;
- case UNREACHABLE_CODE: {
- CHECK_SYMBOLS(1);
- return "Unreachable code (statement after return) in function '" + symbols[0] + "()'.";
- } break;
- case STANDALONE_EXPRESSION: {
- return "Standalone expression (the line has no effect).";
- } break;
- case VOID_ASSIGNMENT: {
- CHECK_SYMBOLS(1);
- return "Assignment operation, but the function '" + symbols[0] + "()' returns void.";
- } break;
- case NARROWING_CONVERSION: {
- return "Narrowing conversion (float is converted to int and loses precision).";
- } break;
- case FUNCTION_MAY_YIELD: {
- CHECK_SYMBOLS(1);
- return "Assigned variable is typed but the function '" + symbols[0] + "()' may yield and return a GDScriptFunctionState instead.";
- } break;
- case VARIABLE_CONFLICTS_FUNCTION: {
- CHECK_SYMBOLS(1);
- return "Variable declaration of '" + symbols[0] + "' conflicts with a function of the same name.";
- } break;
- case FUNCTION_CONFLICTS_VARIABLE: {
- CHECK_SYMBOLS(1);
- return "Function declaration of '" + symbols[0] + "()' conflicts with a variable of the same name.";
- } break;
- case FUNCTION_CONFLICTS_CONSTANT: {
- CHECK_SYMBOLS(1);
- return "Function declaration of '" + symbols[0] + "()' conflicts with a constant of the same name.";
- } break;
- case INCOMPATIBLE_TERNARY: {
- return "Values of the ternary conditional are not mutually compatible.";
- } break;
- case UNUSED_SIGNAL: {
- CHECK_SYMBOLS(1);
- return "The signal '" + symbols[0] + "' is declared but never emitted.";
- } break;
- case RETURN_VALUE_DISCARDED: {
- CHECK_SYMBOLS(1);
- return "The function '" + symbols[0] + "()' returns a value, but this value is never used.";
- } break;
- case PROPERTY_USED_AS_FUNCTION: {
- CHECK_SYMBOLS(2);
- return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a property with the same name. Did you mean to access it?";
- } break;
- case CONSTANT_USED_AS_FUNCTION: {
- CHECK_SYMBOLS(2);
- return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a constant with the same name. Did you mean to access it?";
- } break;
- case FUNCTION_USED_AS_PROPERTY: {
- CHECK_SYMBOLS(2);
- return "The property '" + symbols[0] + "' was not found in base '" + symbols[1] + "' but there's a method with the same name. Did you mean to call it?";
- } break;
- case INTEGER_DIVISION: {
- return "Integer division, decimal part will be discarded.";
- } break;
- case UNSAFE_PROPERTY_ACCESS: {
- CHECK_SYMBOLS(2);
- return "The property '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
- } break;
- case UNSAFE_METHOD_ACCESS: {
- CHECK_SYMBOLS(2);
- return "The method '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
- } break;
- case UNSAFE_CAST: {
- CHECK_SYMBOLS(1);
- return "The value is cast to '" + symbols[0] + "' but has an unknown type.";
- } break;
- case UNSAFE_CALL_ARGUMENT: {
- CHECK_SYMBOLS(4);
- return "The argument '" + symbols[0] + "' of the function '" + symbols[1] + "' requires a the subtype '" + symbols[2] + "' but the supertype '" + symbols[3] + "' was provided";
- } break;
- case DEPRECATED_KEYWORD: {
- CHECK_SYMBOLS(2);
- return "The '" + symbols[0] + "' keyword is deprecated and will be removed in a future release, please replace its uses by '" + symbols[1] + "'.";
- } break;
- case STANDALONE_TERNARY: {
- return "Standalone ternary conditional operator: the return value is being discarded.";
- }
- case WARNING_MAX: break; // Can't happen, but silences warning
- }
- ERR_FAIL_V_MSG(String(), "Invalid GDScript warning code: " + get_name_from_code(code) + ".");
-
-#undef CHECK_SYMBOLS
-}
-
-String GDScriptWarning::get_name() const {
- return get_name_from_code(code);
-}
-
-String GDScriptWarning::get_name_from_code(Code p_code) {
- ERR_FAIL_COND_V(p_code < 0 || p_code >= WARNING_MAX, String());
-
- static const char *names[] = {
- "UNASSIGNED_VARIABLE",
- "UNASSIGNED_VARIABLE_OP_ASSIGN",
- "UNUSED_VARIABLE",
- "SHADOWED_VARIABLE",
- "UNUSED_CLASS_VARIABLE",
- "UNUSED_ARGUMENT",
- "UNREACHABLE_CODE",
- "STANDALONE_EXPRESSION",
- "VOID_ASSIGNMENT",
- "NARROWING_CONVERSION",
- "FUNCTION_MAY_YIELD",
- "VARIABLE_CONFLICTS_FUNCTION",
- "FUNCTION_CONFLICTS_VARIABLE",
- "FUNCTION_CONFLICTS_CONSTANT",
- "INCOMPATIBLE_TERNARY",
- "UNUSED_SIGNAL",
- "RETURN_VALUE_DISCARDED",
- "PROPERTY_USED_AS_FUNCTION",
- "CONSTANT_USED_AS_FUNCTION",
- "FUNCTION_USED_AS_PROPERTY",
- "INTEGER_DIVISION",
- "UNSAFE_PROPERTY_ACCESS",
- "UNSAFE_METHOD_ACCESS",
- "UNSAFE_CAST",
- "UNSAFE_CALL_ARGUMENT",
- "DEPRECATED_KEYWORD",
- "STANDALONE_TERNARY",
- nullptr
- };
-
- return names[(int)p_code];
-}
-
-GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) {
- for (int i = 0; i < WARNING_MAX; i++) {
- if (get_name_from_code((Code)i) == p_name) {
- return (Code)i;
- }
- }
-
- ERR_FAIL_V_MSG(WARNING_MAX, "Invalid GDScript warning name: " + p_name);
-}
-
-#endif // DEBUG_ENABLED
-
GDScriptLanguage::GDScriptLanguage() {
-
calls = 0;
ERR_FAIL_COND(singleton);
singleton = this;
@@ -2225,14 +2012,13 @@ GDScriptLanguage::GDScriptLanguage() {
GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false);
for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
- bool default_enabled = !warning.begins_with("unsafe_") && i != GDScriptWarning::UNUSED_CLASS_VARIABLE;
+ bool default_enabled = !warning.begins_with("unsafe_");
GLOBAL_DEF("debug/gdscript/warnings/" + warning, default_enabled);
}
#endif // DEBUG_ENABLED
}
GDScriptLanguage::~GDScriptLanguage() {
-
if (_call_stack) {
memdelete_arr(_call_stack);
}
@@ -2245,71 +2031,63 @@ void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const
Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) {
Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name);
- if (!orphan_subclass_element)
+ if (!orphan_subclass_element) {
return Ref<GDScript>();
+ }
ObjectID orphan_subclass = orphan_subclass_element->get();
Object *obj = ObjectDB::get_instance(orphan_subclass);
orphan_subclasses.erase(orphan_subclass_element);
- if (!obj)
+ if (!obj) {
return Ref<GDScript>();
+ }
return Ref<GDScript>(Object::cast_to<GDScript>(obj));
}
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress) {
-
- if (r_error)
+RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+ if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
+ }
- GDScript *script = memnew(GDScript);
-
- Ref<GDScript> scriptres(script);
-
- if (p_path.ends_with(".gde") || p_path.ends_with(".gdc")) {
-
- script->set_script_path(p_original_path); // script needs this.
- script->set_path(p_original_path);
- Error err = script->load_byte_code(p_path);
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load byte code from file '" + p_path + "'.");
-
- } else {
- Error err = script->load_source_code(p_path);
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load source code from file '" + p_path + "'.");
+ Error err;
+ Ref<GDScript> script = GDScriptCache::get_full_script(p_path, err);
- script->set_script_path(p_original_path); // script needs this.
- script->set_path(p_original_path);
+ // TODO: Reintroduce binary and encrypted scripts.
- script->reload();
+ if (script.is_null()) {
+ // Don't fail loading because of parsing error.
+ script.instance();
}
- if (r_error)
+
+ if (r_error) {
*r_error = OK;
+ }
- return scriptres;
+ return script;
}
void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
-
p_extensions->push_back("gd");
- p_extensions->push_back("gdc");
- p_extensions->push_back("gde");
+ // TODO: Reintroduce binary and encrypted scripts.
+ // p_extensions->push_back("gdc");
+ // p_extensions->push_back("gde");
}
bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
-
return (p_type == "Script" || p_type == "GDScript");
}
String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
-
String el = p_path.get_extension().to_lower();
- if (el == "gd" || el == "gdc" || el == "gde")
+ // TODO: Reintroduce binary and encrypted scripts.
+ if (el == "gd" /*|| el == "gdc" || el == "gde"*/) {
return "GDScript";
+ }
return "";
}
void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
-
FileAccessRef file = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_path + "'.");
@@ -2319,7 +2097,7 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S
}
GDScriptParser parser;
- if (OK != parser.parse(source, p_path.get_base_dir(), true, p_path, false, nullptr, true)) {
+ if (OK != parser.parse(source, p_path, false)) {
return;
}
@@ -2329,7 +2107,6 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S
}
Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
-
Ref<GDScript> sqscr = p_resource;
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
@@ -2356,12 +2133,11 @@ Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resou
}
void ResourceFormatSaverGDScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
-
if (Object::cast_to<GDScript>(*p_resource)) {
p_extensions->push_back("gd");
}
}
-bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const {
+bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const {
return Object::cast_to<GDScript>(*p_resource) != nullptr;
}