diff options
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/gdscript.cpp | 19 | ||||
-rw-r--r-- | modules/gdscript/gdscript.h | 8 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 25 | ||||
-rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 60 | ||||
-rw-r--r-- | modules/gdscript/gdscript_functions.cpp | 30 | ||||
-rw-r--r-- | modules/gdscript/gdscript_functions.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 113 |
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) { |