summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gdscript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript.cpp')
-rw-r--r--modules/gdscript/gdscript.cpp207
1 files changed, 157 insertions, 50 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 0da7752940..19b264d764 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -35,6 +35,7 @@
#include "gdscript_compiler.h"
#include "gdscript_parser.h"
#include "gdscript_rpc_callable.h"
+#include "gdscript_tokenizer_buffer.h"
#include "gdscript_warning.h"
#ifdef TOOLS_ENABLED
@@ -94,7 +95,7 @@ Variant GDScriptNativeClass::_new() {
}
Object *GDScriptNativeClass::instantiate() {
- return ClassDB::instantiate(name);
+ return ClassDB::instantiate_no_placeholders(name);
}
Variant GDScriptNativeClass::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
@@ -162,13 +163,14 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
_super_implicit_constructor(this, instance, r_error);
if (r_error.error != Callable::CallError::CALL_OK) {
+ String error_text = Variant::get_call_error_text(instance->owner, "@implicit_new", nullptr, 0, r_error);
instance->script = Ref<GDScript>();
instance->owner->set_script_instance(nullptr);
{
MutexLock lock(GDScriptLanguage::singleton->mutex);
instances.erase(p_owner);
}
- ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance.");
+ ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance: " + error_text);
}
if (p_argcount < 0) {
@@ -179,13 +181,14 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
if (initializer != nullptr) {
initializer->call(instance, p_args, p_argcount, r_error);
if (r_error.error != Callable::CallError::CALL_OK) {
+ String error_text = Variant::get_call_error_text(instance->owner, "_init", p_args, p_argcount, r_error);
instance->script = Ref<GDScript>();
instance->owner->set_script_instance(nullptr);
{
MutexLock lock(GDScriptLanguage::singleton->mutex);
instances.erase(p_owner);
}
- ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance.");
+ ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance: " + error_text);
}
}
//@TODO make thread safe
@@ -351,6 +354,21 @@ bool GDScript::has_static_method(const StringName &p_method) const {
return member_functions.has(p_method) && member_functions[p_method]->is_static();
}
+int GDScript::get_script_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method);
+ if (!E) {
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+ }
+
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return E->value->get_argument_count();
+}
+
MethodInfo GDScript::get_method_info(const StringName &p_method) const {
HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method);
if (!E) {
@@ -660,6 +678,27 @@ Error GDScript::_static_init() {
#ifdef TOOLS_ENABLED
+void GDScript::_static_default_init() {
+ for (const KeyValue<StringName, MemberInfo> &E : static_variables_indices) {
+ const GDScriptDataType &type = E.value.data_type;
+ // Only initialize builtin types, which are not expected to be `null`.
+ if (!type.has_type || type.kind != GDScriptDataType::BUILTIN) {
+ continue;
+ }
+ if (type.builtin_type == Variant::ARRAY && type.has_container_element_type(0)) {
+ Array default_value;
+ const GDScriptDataType &element_type = type.get_container_element_type(0);
+ default_value.set_typed(element_type.builtin_type, element_type.native_type, element_type.script_type);
+ static_variables.write[E.value.index] = default_value;
+ } else {
+ Variant default_value;
+ Callable::CallError err;
+ Variant::construct(type.builtin_type, default_value, nullptr, 0, err);
+ static_variables.write[E.value.index] = default_value;
+ }
+ }
+}
+
void GDScript::_save_old_static_data() {
old_static_variables_indices = static_variables_indices;
old_static_variables = static_variables;
@@ -721,10 +760,18 @@ Error GDScript::reload(bool p_keep_state) {
if (source_path.is_empty()) {
source_path = get_path();
}
- Ref<GDScript> cached_script = GDScriptCache::get_cached_script(source_path);
- if (!source_path.is_empty() && cached_script.is_null()) {
- MutexLock lock(GDScriptCache::singleton->mutex);
- GDScriptCache::singleton->shallow_gdscript_cache[source_path] = Ref<GDScript>(this);
+ if (!source_path.is_empty()) {
+ if (GDScriptCache::get_cached_script(source_path).is_null()) {
+ MutexLock lock(GDScriptCache::singleton->mutex);
+ GDScriptCache::singleton->shallow_gdscript_cache[source_path] = Ref<GDScript>(this);
+ }
+ if (GDScriptCache::has_parser(source_path)) {
+ Error err = OK;
+ Ref<GDScriptParserRef> parser_ref = GDScriptCache::get_parser(source_path, GDScriptParserRef::EMPTY, err);
+ if (parser_ref.is_valid() && parser_ref->get_source_hash() != source.hash()) {
+ GDScriptCache::remove_parser(source_path);
+ }
+ }
}
}
@@ -738,7 +785,12 @@ Error GDScript::reload(bool p_keep_state) {
valid = false;
GDScriptParser parser;
- Error err = parser.parse(source, path, false);
+ Error err;
+ if (!binary_tokens.is_empty()) {
+ err = parser.parse_binary(binary_tokens, path);
+ } else {
+ err = parser.parse(source, path, false);
+ }
if (err) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
@@ -810,6 +862,9 @@ Error GDScript::reload(bool p_keep_state) {
#ifdef TOOLS_ENABLED
if (can_run && p_keep_state) {
_restore_old_static_data();
+ } else if (!can_run) {
+ // Initialize static variables with sane default values even if the constructor isn't called.
+ _static_default_init();
}
#endif
@@ -1048,6 +1103,19 @@ Error GDScript::load_source_code(const String &p_path) {
return OK;
}
+void GDScript::set_binary_tokens_source(const Vector<uint8_t> &p_binary_tokens) {
+ binary_tokens = p_binary_tokens;
+}
+
+const Vector<uint8_t> &GDScript::get_binary_tokens_source() const {
+ return binary_tokens;
+}
+
+Vector<uint8_t> GDScript::get_as_binary_tokens() const {
+ GDScriptTokenizerBuffer tokenizer;
+ return tokenizer.parse_code_string(source, GDScriptTokenizerBuffer::COMPRESS_NONE);
+}
+
const HashMap<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const {
return member_functions;
}
@@ -1149,7 +1217,7 @@ GDScript *GDScript::get_root_script() {
RBSet<GDScript *> GDScript::get_dependencies() {
RBSet<GDScript *> dependencies;
- _get_dependencies(dependencies, this);
+ _collect_dependencies(dependencies, this);
dependencies.erase(this);
return dependencies;
@@ -1255,52 +1323,55 @@ GDScript *GDScript::_get_gdscript_from_variant(const Variant &p_variant) {
return Object::cast_to<GDScript>(obj);
}
-void GDScript::_get_dependencies(RBSet<GDScript *> &p_dependencies, const GDScript *p_except) {
+void GDScript::_collect_function_dependencies(GDScriptFunction *p_func, RBSet<GDScript *> &p_dependencies, const GDScript *p_except) {
+ if (p_func == nullptr) {
+ return;
+ }
+ for (GDScriptFunction *lambda : p_func->lambdas) {
+ _collect_function_dependencies(lambda, p_dependencies, p_except);
+ }
+ for (const Variant &V : p_func->constants) {
+ GDScript *scr = _get_gdscript_from_variant(V);
+ if (scr != nullptr && scr != p_except) {
+ scr->_collect_dependencies(p_dependencies, p_except);
+ }
+ }
+}
+
+void GDScript::_collect_dependencies(RBSet<GDScript *> &p_dependencies, const GDScript *p_except) {
if (p_dependencies.has(this)) {
return;
}
- p_dependencies.insert(this);
+ if (this != p_except) {
+ p_dependencies.insert(this);
+ }
for (const KeyValue<StringName, GDScriptFunction *> &E : member_functions) {
- if (E.value == nullptr) {
- continue;
- }
- for (const Variant &V : E.value->constants) {
- GDScript *scr = _get_gdscript_from_variant(V);
- if (scr != nullptr && scr != p_except) {
- scr->_get_dependencies(p_dependencies, p_except);
- }
- }
+ _collect_function_dependencies(E.value, p_dependencies, p_except);
}
if (implicit_initializer) {
- for (const Variant &V : implicit_initializer->constants) {
- GDScript *scr = _get_gdscript_from_variant(V);
- if (scr != nullptr && scr != p_except) {
- scr->_get_dependencies(p_dependencies, p_except);
- }
- }
+ _collect_function_dependencies(implicit_initializer, p_dependencies, p_except);
}
if (implicit_ready) {
- for (const Variant &V : implicit_ready->constants) {
- GDScript *scr = _get_gdscript_from_variant(V);
- if (scr != nullptr && scr != p_except) {
- scr->_get_dependencies(p_dependencies, p_except);
- }
- }
+ _collect_function_dependencies(implicit_ready, p_dependencies, p_except);
+ }
+
+ if (static_initializer) {
+ _collect_function_dependencies(static_initializer, p_dependencies, p_except);
}
for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
if (E.value != p_except) {
- E.value->_get_dependencies(p_dependencies, p_except);
+ E.value->_collect_dependencies(p_dependencies, p_except);
}
}
for (const KeyValue<StringName, Variant> &E : constants) {
GDScript *scr = _get_gdscript_from_variant(E.value);
if (scr != nullptr && scr != p_except) {
- scr->_get_dependencies(p_dependencies, p_except);
+ scr->_collect_dependencies(p_dependencies, p_except);
}
}
}
@@ -1381,6 +1452,13 @@ String GDScript::debug_get_script_name(const Ref<Script> &p_script) {
}
#endif
+String GDScript::canonicalize_path(const String &p_path) {
+ if (p_path.get_extension() == "gdc") {
+ return p_path.get_basename() + ".gd";
+ }
+ return p_path;
+}
+
GDScript::UpdatableFuncPtr::UpdatableFuncPtr(GDScriptFunction *p_function) {
if (p_function == nullptr) {
return;
@@ -1885,19 +1963,41 @@ bool GDScriptInstance::has_method(const StringName &p_method) const {
return false;
}
-Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- GDScript *sptr = script.ptr();
- if (unlikely(p_method == SNAME("_ready"))) {
- // Call implicit ready first, including for the super classes.
- while (sptr) {
- if (sptr->implicit_ready) {
- sptr->implicit_ready->call(this, nullptr, 0, r_error);
+int GDScriptInstance::get_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
+ const GDScript *sptr = script.ptr();
+ while (sptr) {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_method);
+ if (E) {
+ if (r_is_valid) {
+ *r_is_valid = true;
}
- sptr = sptr->_base;
+ return E->value->get_argument_count();
}
+ sptr = sptr->_base;
+ }
+
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return 0;
+}
- // Reset this back for the regular call.
- sptr = script.ptr();
+void GDScriptInstance::_call_implicit_ready_recursively(GDScript *p_script) {
+ // Call base class first.
+ if (p_script->_base) {
+ _call_implicit_ready_recursively(p_script->_base);
+ }
+ if (p_script->implicit_ready) {
+ Callable::CallError err;
+ p_script->implicit_ready->call(this, nullptr, 0, err);
+ }
+}
+
+Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ GDScript *sptr = script.ptr();
+ if (unlikely(p_method == SNAME("_ready"))) {
+ // Call implicit ready first, including for the super classes recursively.
+ _call_implicit_ready_recursively(sptr);
}
while (sptr) {
HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);
@@ -2573,7 +2673,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
}
}
-bool GDScriptLanguage::is_control_flow_keyword(String p_keyword) const {
+bool GDScriptLanguage::is_control_flow_keyword(const String &p_keyword) const {
// Please keep alphabetical order.
return p_keyword == "break" ||
p_keyword == "continue" ||
@@ -2786,11 +2886,12 @@ Ref<GDScript> GDScriptLanguage::get_script_by_fully_qualified_name(const String
Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
Error err;
- Ref<GDScript> scr = GDScriptCache::get_full_script(p_path, err, "", p_cache_mode == CACHE_MODE_IGNORE);
+ bool ignoring = p_cache_mode == CACHE_MODE_IGNORE || p_cache_mode == CACHE_MODE_IGNORE_DEEP;
+ Ref<GDScript> scr = GDScriptCache::get_full_script(p_original_path, err, "", ignoring);
if (err && scr.is_valid()) {
// If !scr.is_valid(), the error was likely from scr->load_source_code(), which already generates an error.
- ERR_PRINT_ED(vformat(R"(Failed to load script "%s" with error "%s".)", p_path, error_names[err]));
+ ERR_PRINT_ED(vformat(R"(Failed to load script "%s" with error "%s".)", p_original_path, error_names[err]));
}
if (r_error) {
@@ -2803,6 +2904,7 @@ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const Str
void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("gd");
+ p_extensions->push_back("gdc");
}
bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
@@ -2811,13 +2913,13 @@ bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
String el = p_path.get_extension().to_lower();
- if (el == "gd") {
+ if (el == "gd" || el == "gdc") {
return "GDScript";
}
return "";
}
-void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
+void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *r_dependencies, bool p_add_types) {
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_path + "'.");
@@ -2831,8 +2933,13 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S
return;
}
+ GDScriptAnalyzer analyzer(&parser);
+ if (OK != analyzer.analyze()) {
+ return;
+ }
+
for (const String &E : parser.get_dependencies()) {
- p_dependencies->push_back(E);
+ r_dependencies->push_back(E);
}
}