summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/gdscript.cpp19
-rw-r--r--modules/gdscript/gdscript.h8
-rw-r--r--modules/gdscript/gdscript_compiler.cpp25
-rw-r--r--modules/gdscript/gdscript_editor.cpp60
-rw-r--r--modules/gdscript/gdscript_functions.cpp30
-rw-r--r--modules/gdscript/gdscript_functions.h2
-rw-r--r--modules/gdscript/gdscript_parser.cpp113
7 files changed, 232 insertions, 25 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 55ea8a5f24..41a810ff00 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -100,7 +100,7 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
#endif
instance->owner->set_script_instance(instance);
-/* STEP 2, INITIALIZE AND CONSRTUCT */
+ /* STEP 2, INITIALIZE AND CONSRTUCT */
#ifndef NO_THREADS
GDScriptLanguage::singleton->lock->lock();
@@ -615,6 +615,23 @@ 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();
+ }
+ }
+}
+
+void GDScript::get_members(Set<StringName> *p_members) {
+ if (p_members) {
+ for (Set<StringName>::Element *E = members.front(); E; E = E->next()) {
+ p_members->insert(E->get());
+ }
+ }
+}
+
Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
GDScript *top = this;
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 3f6f431938..6e5d59ad0e 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -198,6 +198,9 @@ public:
return -1;
}
+ virtual void get_constants(Map<StringName, Variant> *p_constants);
+ virtual void get_members(Set<StringName> *p_members);
+
GDScript();
~GDScript();
};
@@ -219,7 +222,7 @@ class GDScriptInstance : public ScriptInstance {
void _ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount);
public:
- _FORCE_INLINE_ Object *get_owner() { return owner; }
+ virtual Object *get_owner() { return owner; }
virtual bool set(const StringName &p_name, const Variant &p_value);
virtual bool get(const StringName &p_name, Variant &r_ret) const;
@@ -407,7 +410,8 @@ public:
virtual String debug_get_stack_level_source(int p_level) const;
virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
- virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
+ virtual ScriptInstance *debug_get_stack_level_instance(int p_level);
+ virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1);
virtual void reload_all_scripts();
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 3121a61436..4cd6472b7f 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1686,21 +1686,44 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons
base_class = p->subclasses[base];
break;
}
+
+ if (p->constants.has(base)) {
+
+ base_class = p->constants[base];
+ if (base_class.is_null()) {
+ _set_error("Constant is not a class: " + base, p_class);
+ return ERR_SCRIPT_FAILED;
+ }
+ break;
+ }
+
p = p->_owner;
}
if (base_class.is_valid()) {
+ String ident = base;
+
for (int i = 1; i < p_class->extends_class.size(); i++) {
String subclass = p_class->extends_class[i];
+ ident += ("." + subclass);
+
if (base_class->subclasses.has(subclass)) {
base_class = base_class->subclasses[subclass];
+ } else if (base_class->constants.has(subclass)) {
+
+ Ref<GDScript> new_base_class = base_class->constants[subclass];
+ if (new_base_class.is_null()) {
+ _set_error("Constant is not a class: " + ident, p_class);
+ return ERR_SCRIPT_FAILED;
+ }
+ base_class = new_base_class;
} else {
- _set_error("Could not find subclass: " + subclass, p_class);
+ _set_error("Could not find subclass: " + ident, p_class);
return ERR_FILE_NOT_FOUND;
}
}
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index a74b8a8483..5a76acea6e 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -33,7 +33,7 @@
#include "gdscript_compiler.h"
#include "global_constants.h"
#include "os/file_access.h"
-#include "project_settings.h"
+#include "core/engine.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_file_system.h"
@@ -280,10 +280,62 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *
p_values->push_back(instance->debug_get_member_by_index(E->get().index));
}
}
-void GDScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
- //no globals are really reachable in gdscript
+ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) {
+
+ ERR_FAIL_COND_V(_debug_parse_err_line >= 0, NULL);
+ ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, NULL);
+
+ int l = _debug_call_stack_pos - p_level - 1;
+ ScriptInstance *instance = _call_stack[l].instance;
+
+ return instance;
}
+
+void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
+
+ const Map<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map();
+ const Variant *globals = GDScriptLanguage::get_singleton()->get_global_array();
+
+ List<Pair<String, Variant> > cinfo;
+ get_public_constants(&cinfo);
+
+ for (const Map<StringName, int>::Element *E = name_idx.front(); E; E = E->next()) {
+
+ if (ClassDB::class_exists(E->key()) || Engine::get_singleton()->has_singleton(E->key()))
+ continue;
+
+ bool is_script_constant = false;
+ for (List<Pair<String, Variant> >::Element *CE = cinfo.front(); CE; CE = CE->next()) {
+ if (CE->get().first == E->key()) {
+ is_script_constant = true;
+ break;
+ }
+ }
+ if (is_script_constant)
+ continue;
+
+ const Variant &var = globals[E->value()];
+ if (Object *obj = var) {
+ if (Object::cast_to<GDScriptNativeClass>(obj))
+ continue;
+ }
+
+ bool skip = false;
+ for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
+ if (E->key() == GlobalConstants::get_global_constant_name(i)) {
+ skip = true;
+ break;
+ }
+ }
+ if (skip)
+ continue;
+
+ p_globals->push_back(E->key());
+ p_values->push_back(var);
+ }
+}
+
String GDScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
if (_debug_parse_err_line >= 0)
@@ -1743,7 +1795,7 @@ static void _find_type_arguments(GDScriptCompletionContext &context, const GDScr
}
} else {
-//regular method
+ //regular method
#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
if (p_argidx < m->get_argument_count()) {
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index c6066ceefb..ca0a9582a7 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -84,6 +84,8 @@ const char *GDScriptFunctions::get_func_name(Function p_func) {
"rad2deg",
"linear2db",
"db2linear",
+ "polar2cartesian",
+ "cartesian2polar",
"wrapi",
"wrapf",
"max",
@@ -408,6 +410,22 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
VALIDATE_ARG_NUM(0);
r_ret = Math::db2linear((double)*p_args[0]);
} break;
+ case MATH_POLAR2CARTESIAN: {
+ VALIDATE_ARG_COUNT(2);
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ double r = *p_args[0];
+ double th = *p_args[1];
+ r_ret = Vector2(r * Math::cos(th), r * Math::sin(th));
+ } break;
+ case MATH_CARTESIAN2POLAR: {
+ VALIDATE_ARG_COUNT(2);
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ double x = *p_args[0];
+ double y = *p_args[1];
+ r_ret = Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x));
+ } break;
case MATH_WRAP: {
VALIDATE_ARG_COUNT(3);
r_ret = Math::wrapi((int64_t)*p_args[0], (int64_t)*p_args[1], (int64_t)*p_args[2]);
@@ -1296,6 +1314,8 @@ bool GDScriptFunctions::is_deterministic(Function p_func) {
case MATH_RAD2DEG:
case MATH_LINEAR2DB:
case MATH_DB2LINEAR:
+ case MATH_POLAR2CARTESIAN:
+ case MATH_CARTESIAN2POLAR:
case MATH_WRAP:
case MATH_WRAPF:
case LOGIC_MAX:
@@ -1526,6 +1546,16 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
mi.return_val.type = Variant::REAL;
return mi;
} break;
+ case MATH_POLAR2CARTESIAN: {
+ MethodInfo mi("polar2cartesian", PropertyInfo(Variant::REAL, "r"), PropertyInfo(Variant::REAL, "th"));
+ mi.return_val.type = Variant::VECTOR2;
+ return mi;
+ } break;
+ case MATH_CARTESIAN2POLAR: {
+ MethodInfo mi("cartesian2polar", PropertyInfo(Variant::REAL, "x"), PropertyInfo(Variant::REAL, "y"));
+ mi.return_val.type = Variant::VECTOR2;
+ return mi;
+ } break;
case MATH_WRAP: {
MethodInfo mi("wrapi", PropertyInfo(Variant::INT, "value"), PropertyInfo(Variant::INT, "min"), PropertyInfo(Variant::INT, "max"));
mi.return_val.type = Variant::INT;
diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h
index ecbede83a8..d1c5815cec 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/gdscript/gdscript_functions.h
@@ -75,6 +75,8 @@ public:
MATH_RAD2DEG,
MATH_LINEAR2DB,
MATH_DB2LINEAR,
+ MATH_POLAR2CARTESIAN,
+ MATH_CARTESIAN2POLAR,
MATH_WRAP,
MATH_WRAPF,
LOGIC_MAX,
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 29b9865b1d..bee9ef1998 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -2971,18 +2971,37 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) {
}
while (true) {
- if (tokenizer->get_token() != GDScriptTokenizer::TK_IDENTIFIER) {
- _set_error("Invalid 'extends' syntax, expected string constant (path) and/or identifier (parent class).");
- return;
- }
+ switch (tokenizer->get_token()) {
+
+ case GDScriptTokenizer::TK_IDENTIFIER: {
+
+ StringName identifier = tokenizer->get_token_identifier();
+ p_class->extends_class.push_back(identifier);
+ }
+ break;
- StringName identifier = tokenizer->get_token_identifier();
- p_class->extends_class.push_back(identifier);
+ case GDScriptTokenizer::TK_PERIOD:
+ break;
+
+ default: {
+
+ _set_error("Invalid 'extends' syntax, expected string constant (path) and/or identifier (parent class).");
+ return;
+ }
+ }
tokenizer->advance(1);
- if (tokenizer->get_token() != GDScriptTokenizer::TK_PERIOD)
- return;
+
+ switch (tokenizer->get_token()) {
+
+ case GDScriptTokenizer::TK_IDENTIFIER:
+ case GDScriptTokenizer::TK_PERIOD:
+ continue;
+
+ default:
+ return;
+ }
}
}
@@ -3758,22 +3777,82 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
current_export.hint = PROPERTY_HINT_NONE;
}
- } else if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER) {
+ } else {
- String identifier = tokenizer->get_token_identifier();
- if (!ClassDB::is_parent_class(identifier, "Resource")) {
+ parenthesis++;
+ Node *subexpr = _parse_and_reduce_expression(p_class, true, true);
+ if (!subexpr) {
+ if (_recover_from_completion()) {
+ break;
+ }
+ return;
+ }
+ parenthesis--;
+ if (subexpr->type != Node::TYPE_CONSTANT) {
current_export = PropertyInfo();
- _set_error("Export hint not a type or resource.");
+ _set_error("Expected a constant expression.");
}
- current_export.type = Variant::OBJECT;
- current_export.hint = PROPERTY_HINT_RESOURCE_TYPE;
- current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
+ Variant constant = static_cast<ConstantNode *>(subexpr)->value;
- current_export.hint_string = identifier;
+ if (constant.get_type() == Variant::OBJECT) {
+ GDScriptNativeClass *native_class = Object::cast_to<GDScriptNativeClass>(constant);
- tokenizer->advance();
+ if (native_class && ClassDB::is_parent_class(native_class->get_name(), "Resource")) {
+ current_export.type = Variant::OBJECT;
+ current_export.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
+
+ current_export.hint_string = native_class->get_name();
+
+ } else {
+ current_export = PropertyInfo();
+ _set_error("Export hint not a resource type.");
+ }
+ } else if (constant.get_type() == Variant::DICTIONARY) {
+ // Enumeration
+ bool is_flags = false;
+
+ if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
+ tokenizer->advance();
+
+ if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FLAGS") {
+ is_flags = true;
+ tokenizer->advance();
+ } else {
+ current_export = PropertyInfo();
+ _set_error("Expected 'FLAGS' after comma.");
+ }
+ }
+
+ current_export.type = Variant::INT;
+ current_export.hint = is_flags ? PROPERTY_HINT_FLAGS : PROPERTY_HINT_ENUM;
+ Dictionary enum_values = constant;
+
+ List<Variant> keys;
+ enum_values.get_key_list(&keys);
+
+ bool first = true;
+ for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
+ if (enum_values[E->get()].get_type() == Variant::INT) {
+ if (!first)
+ current_export.hint_string += ",";
+ else
+ first = false;
+
+ current_export.hint_string += E->get().operator String().camelcase_to_underscore(true).capitalize().xml_escape();
+ if (!is_flags) {
+ current_export.hint_string += ":";
+ current_export.hint_string += enum_values[E->get()].operator String().xml_escape();
+ }
+ }
+ }
+ } else {
+ current_export = PropertyInfo();
+ _set_error("Expected type for export.");
+ return;
+ }
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) {