diff options
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/gd_compiler.cpp | 2 | ||||
-rw-r--r-- | modules/gdscript/gd_editor.cpp | 284 | ||||
-rw-r--r-- | modules/gdscript/gd_function.cpp | 8 | ||||
-rw-r--r-- | modules/gdscript/gd_parser.cpp | 43 | ||||
-rw-r--r-- | modules/gdscript/gd_parser.h | 4 | ||||
-rw-r--r-- | modules/gdscript/gd_script.cpp | 16 | ||||
-rw-r--r-- | modules/gdscript/gd_script.h | 2 |
7 files changed, 265 insertions, 94 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index c243f88b7a..2aa24e88a9 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -1971,7 +1971,7 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa p_script->placeholders.erase(psi); //remove placeholder GDInstance *instance = memnew(GDInstance); - instance->base_ref = E->get()->cast_to<Reference>(); + instance->base_ref = Object::cast_to<Reference>(E->get()); instance->members.resize(p_script->member_indices.size()); instance->script = Ref<GDScript>(p_script); instance->owner = E->get(); diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 3fa0a38024..905c784ab9 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -30,6 +30,7 @@ #include "editor/editor_settings.h" #include "gd_compiler.h" #include "gd_script.h" +#include "global_constants.h" #include "os/file_access.h" #include "project_settings.h" #ifdef TOOLS_ENABLED @@ -355,6 +356,7 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na struct GDCompletionIdentifier { + String enumeration; StringName obj_type; Ref<GDScript> script; Variant::Type type; @@ -370,8 +372,8 @@ static GDCompletionIdentifier _get_type_from_variant(const Variant &p_variant) { Object *obj = p_variant; if (obj) { /* - if (obj->cast_to<GDNativeClass>()) { - t.obj_type=obj->cast_to<GDNativeClass>()->get_name(); + if (Object::cast_to<GDNativeClass>(obj)) { + t.obj_type=Object::cast_to<GDNativeClass>(obj)->get_name(); t.value=Variant(); } else { */ @@ -595,8 +597,7 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser: if (id.operator String() == "new" && base.value.get_type() == Variant::OBJECT) { Object *obj = base.value; - if (obj && obj->cast_to<GDNativeClass>()) { - GDNativeClass *gdnc = obj->cast_to<GDNativeClass>(); + if (GDNativeClass *gdnc = Object::cast_to<GDNativeClass>(obj)) { r_type.type = Variant::OBJECT; r_type.value = Variant(); r_type.obj_type = gdnc->get_name(); @@ -608,7 +609,7 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser: #ifdef TOOLS_ENABLED MethodBind *mb = ClassDB::get_method(base.obj_type, id); - PropertyInfo pi = mb->get_argument_info(-1); + PropertyInfo pi = mb->get_return_info(); //try calling the function if constant and all args are constant, should not crash.. Object *baseptr = base.value; @@ -809,6 +810,32 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser: if (p1.value.get_type() == Variant::OBJECT) { //?? + if (p1.obj_type != StringName() && p2.type == Variant::STRING) { + StringName index = p2.value; + bool valid; + Variant::Type t = ClassDB::get_property_type(p1.obj_type, index, &valid); + if (t != Variant::NIL && valid) { + r_type.type = t; + if (t == Variant::INT) { +//check for enum! +#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) + + StringName getter = ClassDB::get_property_getter(p1.obj_type, index); + if (getter != StringName()) { + MethodBind *mb = ClassDB::get_method(p1.obj_type, getter); + if (mb) { + PropertyInfo rt = mb->get_return_info(); + if (rt.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + r_type.enumeration = rt.class_name; + } + } + } +#endif + } + + return true; + } + } } else if (p1.value.get_type() != Variant::NIL) { bool valid; @@ -902,12 +929,42 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser: static bool _guess_identifier_type_in_block(GDCompletionContext &context, int p_line, const StringName &p_identifier, GDCompletionIdentifier &r_type) { + if (context.block->if_condition && context.block->if_condition->type == GDParser::Node::TYPE_OPERATOR && static_cast<const GDParser::OperatorNode *>(context.block->if_condition)->op == GDParser::OperatorNode::OP_IS) { + //is used, check if identifier is in there! this helps resolve in blocks that are (if (identifier is value)): which are very common.. + //super dirty hack, but very useful + //credit: Zylann + //TODO: this could be hacked to detect ANDed conditions too.. + const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(context.block->if_condition); + if (op->arguments[0]->type == GDParser::Node::TYPE_IDENTIFIER && static_cast<const GDParser::IdentifierNode *>(op->arguments[0])->name == p_identifier) { + //bingo + if (_guess_expression_type(context, op->arguments[1], op->line, r_type)) { + return true; + } + } + } + GDCompletionIdentifier gdi = _get_native_class(context); if (gdi.obj_type != StringName()) { bool valid; Variant::Type t = ClassDB::get_property_type(gdi.obj_type, p_identifier, &valid); if (t != Variant::NIL && valid) { r_type.type = t; + if (t == Variant::INT) { +//check for enum! +#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) + + StringName getter = ClassDB::get_property_getter(gdi.obj_type, p_identifier); + if (getter != StringName()) { + MethodBind *mb = ClassDB::get_method(gdi.obj_type, getter); + if (mb) { + PropertyInfo rt = mb->get_return_info(); + if (rt.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + r_type.enumeration = rt.class_name; + } + } + } +#endif + } return true; } } @@ -1041,11 +1098,11 @@ static bool _guess_identifier_type(GDCompletionContext &context, int p_line, con PropertyInfo arg = E->get().arguments[argindex]; - int scp = arg.name.find(":"); + int scp = String(arg.name).find(":"); if (scp != -1) { r_type.type = Variant::OBJECT; - r_type.obj_type = arg.name.substr(scp + 1, arg.name.length()); + r_type.obj_type = String(arg.name).substr(scp + 1, String(arg.name).length()); return true; } else { @@ -1271,7 +1328,7 @@ static void _find_identifiers_in_class(GDCompletionContext &context, bool p_stat for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) continue; - if (E->get().name.find("/") != -1) + if (String(E->get().name).find("/") != -1) continue; result.insert(E->get().name); } @@ -1436,7 +1493,7 @@ void get_directory_contents(EditorFileSystemDirectory *p_dir, Set<String> &r_lis } } -static void _find_type_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, const StringName &p_method, const GDCompletionIdentifier &id, int p_argidx, Set<String> &result, String &arghint) { +static void _find_type_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, const StringName &p_method, const GDCompletionIdentifier &id, int p_argidx, Set<String> &result, bool &r_forced, String &arghint) { //print_line("find type arguments?"); if (id.type == Variant::OBJECT && id.obj_type != StringName()) { @@ -1451,46 +1508,45 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N if (id.value.get_type()) { Object *obj = id.value; - if (obj) { - - GDScript *scr = obj->cast_to<GDScript>(); - if (scr) { - while (scr) { + GDScript *scr = Object::cast_to<GDScript>(obj); + if (scr) { + while (scr) { - for (const Map<StringName, GDFunction *>::Element *E = scr->get_member_functions().front(); E; E = E->next()) { - if (E->get()->is_static() && p_method == E->get()->get_name()) { - arghint = "static func " + String(p_method) + "("; - for (int i = 0; i < E->get()->get_argument_count(); i++) { - if (i > 0) - arghint += ", "; - else - arghint += " "; - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - arghint += "var " + E->get()->get_argument_name(i); - int deffrom = E->get()->get_argument_count() - E->get()->get_default_argument_count(); - if (i >= deffrom) { - int defidx = deffrom - i; - if (defidx >= 0 && defidx < E->get()->get_default_argument_count()) { - arghint += "=" + E->get()->get_default_argument(defidx).get_construct_string(); - } - } - if (i == p_argidx) { - arghint += String::chr(0xFFFF); + for (const Map<StringName, GDFunction *>::Element *E = scr->get_member_functions().front(); E; E = E->next()) { + if (E->get()->is_static() && p_method == E->get()->get_name()) { + arghint = "static func " + String(p_method) + "("; + for (int i = 0; i < E->get()->get_argument_count(); i++) { + if (i > 0) + arghint += ", "; + else + arghint += " "; + if (i == p_argidx) { + arghint += String::chr(0xFFFF); + } + arghint += "var " + E->get()->get_argument_name(i); + int deffrom = E->get()->get_argument_count() - E->get()->get_default_argument_count(); + if (i >= deffrom) { + int defidx = deffrom - i; + if (defidx >= 0 && defidx < E->get()->get_default_argument_count()) { + arghint += "=" + E->get()->get_default_argument(defidx).get_construct_string(); } } - arghint += ")"; - return; //found + if (i == p_argidx) { + arghint += String::chr(0xFFFF); + } } + arghint += ")"; + return; //found } - - if (scr->get_base().is_valid()) - scr = scr->get_base().ptr(); - else - scr = NULL; } - } else { + + if (scr->get_base().is_valid()) + scr = scr->get_base().ptr(); + else + scr = NULL; + } + } else { + if (obj) { on_script = obj->get_script(); } } @@ -1642,8 +1698,43 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N } } else { - //regular method +//regular method +#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) + if (p_argidx < m->get_argument_count()) { + PropertyInfo pi = m->get_argument_info(p_argidx); + + if (pi.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + String enumeration = pi.class_name; + if (enumeration.find(".") != -1) { + //class constant + List<StringName> constants; + String cls = enumeration.get_slice(".", 0); + String enm = enumeration.get_slice(".", 1); + + ClassDB::get_enum_constants(cls, enm, &constants); + //constants.sort_custom<StringName::AlphCompare>(); + for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { + String add = cls + "." + E->get(); + result.insert(add); + r_forced = true; + } + } else { + + //global constant + StringName current_enum = enumeration; + + for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { + if (GlobalConstants::get_global_constant_enum(i) == current_enum) { + result.insert(GlobalConstants::get_global_constant_name(i)); + r_forced = true; + } + } + //global + } + } + } +#endif if (p_method.operator String() == "connect" || (p_method.operator String() == "emit_signal" && p_argidx == 0)) { if (p_argidx == 0) { @@ -1664,6 +1755,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N for (List<MethodInfo>::Element *E = sigs.front(); E; E = E->next()) { result.insert("\"" + E->get().name + "\""); + r_forced = true; } } else if (p_argidx == 2) { @@ -1671,6 +1763,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N if (context._class) { for (int i = 0; i < context._class->functions.size(); i++) { result.insert("\"" + context._class->functions[i]->name + "\""); + r_forced = true; } } } @@ -1696,6 +1789,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N //print_line("found "+s); String name = s.get_slice("/", 1); result.insert("\"/root/" + name + "\""); + r_forced = true; } } @@ -1707,11 +1801,12 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N for (List<String>::Element *E = options.front(); E; E = E->next()) { result.insert(E->get()); + r_forced = true; } } } - arghint = _get_visual_datatype(m->get_argument_info(-1), false) + " " + p_method.operator String() + String("("); + arghint = _get_visual_datatype(m->get_return_info(), false) + " " + p_method.operator String() + String("("); for (int i = 0; i < m->get_argument_count(); i++) { if (i > 0) @@ -1750,7 +1845,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N } } -static void _find_call_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, int p_argidx, Set<String> &result, String &arghint) { +static void _find_call_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, int p_argidx, Set<String> &result, bool &r_forced, String &arghint) { if (!p_node || p_node->type != GDParser::Node::TYPE_OPERATOR) { @@ -1905,7 +2000,7 @@ static void _find_call_arguments(GDCompletionContext &context, const GDParser::N if (!context._class->owner) ci.value = context.base; - _find_type_arguments(context, p_node, p_line, id->name, ci, p_argidx, result, arghint); + _find_type_arguments(context, p_node, p_line, id->name, ci, p_argidx, result, r_forced, arghint); //guess type.. /* List<MethodInfo> methods; @@ -1927,7 +2022,7 @@ static void _find_call_arguments(GDCompletionContext &context, const GDParser::N GDCompletionIdentifier ci; if (_guess_expression_type(context, op->arguments[0], p_line, ci)) { - _find_type_arguments(context, p_node, p_line, id->name, ci, p_argidx, result, arghint); + _find_type_arguments(context, p_node, p_line, id->name, ci, p_argidx, result, r_forced, arghint); return; } } @@ -2027,14 +2122,14 @@ static void _find_call_arguments(GDCompletionContext &context, const GDParser::N #endif } -Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint) { +Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) { GDParser p; p.parse(p_code, p_base_path, false, "", true); bool isfunction = false; Set<String> options; - + r_forced = false; GDCompletionContext context; context._class = p.get_completion_class(); context.block = p.get_completion_block(); @@ -2073,6 +2168,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base String opt = E->get().strip_edges(); if (opt.begins_with("\"") && opt.ends_with("\"")) { + r_forced = true; String idopt = opt.substr(1, opt.length() - 2); if (idopt.replace("/", "_").is_valid_identifier()) { options.insert(idopt); @@ -2111,7 +2207,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) continue; - if (E->get().name.find("/") != -1) + if (String(E->get().name).find("/") != -1) continue; options.insert(E->get().name); } @@ -2123,28 +2219,27 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base if (t.value.get_type()) { Object *obj = t.value; - if (obj) { - - GDScript *scr = obj->cast_to<GDScript>(); - if (scr) { - while (scr) { + GDScript *scr = Object::cast_to<GDScript>(obj); + if (scr) { + while (scr) { - if (!isfunction) { - for (const Map<StringName, Variant>::Element *E = scr->get_constants().front(); E; E = E->next()) { - options.insert(E->key()); - } + if (!isfunction) { + for (const Map<StringName, Variant>::Element *E = scr->get_constants().front(); E; E = E->next()) { + options.insert(E->key()); } - for (const Map<StringName, GDFunction *>::Element *E = scr->get_member_functions().front(); E; E = E->next()) { - if (E->get()->is_static()) - options.insert(E->key()); - } - - if (scr->get_base().is_valid()) - scr = scr->get_base().ptr(); - else - scr = NULL; } - } else { + for (const Map<StringName, GDFunction *>::Element *E = scr->get_member_functions().front(); E; E = E->next()) { + if (E->get()->is_static()) + options.insert(E->key()); + } + + if (scr->get_base().is_valid()) + scr = scr->get_base().ptr(); + else + scr = NULL; + } + } else { + if (obj) { on_script = obj->get_script(); } } @@ -2245,7 +2340,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) continue; - if (E->get().name.find("/") != -1) + if (String(E->get().name).find("/") != -1) continue; r_options->push_back(E->get().name); } @@ -2277,7 +2372,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base t.value.get_property_list(&pl); for (List<PropertyInfo>::Element *E = pl.front(); E; E = E->next()) { - if (E->get().name.find("/") == -1) + if (String(E->get().name).find("/") == -1) options.insert(E->get().name); } } @@ -2297,7 +2392,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } break; case GDParser::COMPLETION_CALL_ARGUMENTS: { - _find_call_arguments(context, p.get_completion_node(), p.get_completion_line(), p.get_completion_argument_index(), options, r_call_hint); + _find_call_arguments(context, p.get_completion_node(), p.get_completion_line(), p.get_completion_argument_index(), options, r_forced, r_call_hint); } break; case GDParser::COMPLETION_VIRTUAL_FUNC: { @@ -2344,6 +2439,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base ClassDB::get_signal_list(t.obj_type, &sigs); for (List<MethodInfo>::Element *E = sigs.front(); E; E = E->next()) { options.insert("\"" + E->get().name + "\""); + r_forced = true; } } @@ -2353,6 +2449,42 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths")) get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options); } break; + case GDParser::COMPLETION_ASSIGN: { +#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) + + GDCompletionIdentifier ci; + if (_guess_expression_type(context, p.get_completion_node(), p.get_completion_line(), ci)) { + + String enumeration = ci.enumeration; + if (enumeration.find(".") != -1) { + //class constant + List<StringName> constants; + String cls = enumeration.get_slice(".", 0); + String enm = enumeration.get_slice(".", 1); + + ClassDB::get_enum_constants(cls, enm, &constants); + //constants.sort_custom<StringName::AlphCompare>(); + for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { + String add = cls + "." + E->get(); + r_options->push_back(add); + r_forced = true; + } + } else { + + //global constant + StringName current_enum = enumeration; + + for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { + if (GlobalConstants::get_global_constant_enum(i) == current_enum) { + r_options->push_back(GlobalConstants::get_global_constant_name(i)); + r_forced = true; + } + } + //global + } + } +#endif + } break; } for (Set<String>::Element *E = options.front(); E; E = E->next()) { @@ -2364,7 +2496,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base #else -Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint) { +Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) { return OK; } @@ -2701,9 +2833,9 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol Object *obj = value; if (obj) { - if (obj->cast_to<GDNativeClass>()) { + if (Object::cast_to<GDNativeClass>(obj)) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; - r_result.class_name = obj->cast_to<GDNativeClass>()->get_name(); + r_result.class_name = Object::cast_to<GDNativeClass>(obj)->get_name(); } else { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp index 13a7480a36..3b78573f58 100644 --- a/modules/gdscript/gd_function.cpp +++ b/modules/gdscript/gd_function.cpp @@ -371,7 +371,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a Object *obj_A = *a; Object *obj_B = *b; - GDScript *scr_B = obj_B->cast_to<GDScript>(); + GDScript *scr_B = Object::cast_to<GDScript>(obj_B); bool extends_ok = false; @@ -397,7 +397,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } else { - GDNativeClass *nc = obj_B->cast_to<GDNativeClass>(); + GDNativeClass *nc = Object::cast_to<GDNativeClass>(obj_B); if (!nc) { @@ -1434,7 +1434,7 @@ Variant GDFunctionState::_signal_callback(const Variant **p_args, int p_argcount // If the return value is a GDFunctionState reference, // then the function did yield again after resuming. if (ret.is_ref()) { - GDFunctionState *gdfs = ret.operator Object *()->cast_to<GDFunctionState>(); + GDFunctionState *gdfs = Object::cast_to<GDFunctionState>((Object *)&ret); if (gdfs && gdfs->function == function) completed = false; } @@ -1490,7 +1490,7 @@ Variant GDFunctionState::resume(const Variant &p_arg) { // If the return value is a GDFunctionState reference, // then the function did yield again after resuming. if (ret.is_ref()) { - GDFunctionState *gdfs = ret.operator Object *()->cast_to<GDFunctionState>(); + GDFunctionState *gdfs = Object::cast_to<GDFunctionState>((Object *)&ret); if (gdfs && gdfs->function == function) completed = false; } diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 7d3857266e..48da2135fa 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -1044,6 +1044,7 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool return NULL; \ } \ p_allow_assign = false; + switch (tokenizer->get_token()) { //see operator case GDTokenizer::TK_OP_IN: op = OperatorNode::OP_IN; break; @@ -1065,7 +1066,22 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool //case GDTokenizer::TK_OP_NEG: op=OperatorNode::OP_NEG ; break; case GDTokenizer::TK_OP_SHIFT_LEFT: op = OperatorNode::OP_SHIFT_LEFT; break; case GDTokenizer::TK_OP_SHIFT_RIGHT: op = OperatorNode::OP_SHIFT_RIGHT; break; - case GDTokenizer::TK_OP_ASSIGN: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN; break; + case GDTokenizer::TK_OP_ASSIGN: { + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN; + + if (tokenizer->get_token(1) == GDTokenizer::TK_CURSOR) { + //code complete assignment + completion_type = COMPLETION_ASSIGN; + completion_node = expr; + completion_class = current_class; + completion_function = current_function; + completion_line = tokenizer->get_token_line(); + completion_block = current_block; + completion_found = true; + tokenizer->advance(); + } + + } break; case GDTokenizer::TK_OP_ASSIGN_ADD: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_ADD; break; case GDTokenizer::TK_OP_ASSIGN_SUB: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SUB; break; case GDTokenizer::TK_OP_ASSIGN_MUL: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_MUL; break; @@ -1894,7 +1910,26 @@ GDParser::PatternNode *GDParser::_parse_pattern(bool p_static) { return NULL; } - if (value->type != Node::TYPE_IDENTIFIER && value->type != Node::TYPE_CONSTANT) { + if (value->type == Node::TYPE_OPERATOR) { + // Maybe it's SomeEnum.VALUE + Node *current_value = value; + + while (current_value->type == Node::TYPE_OPERATOR) { + OperatorNode *op_node = static_cast<OperatorNode *>(current_value); + + if (op_node->op != OperatorNode::OP_INDEX_NAMED) { + _set_error("Invalid operator in pattern. Only index (`A.B`) is allowed"); + return NULL; + } + current_value = op_node->arguments[0]; + } + + if (current_value->type != Node::TYPE_IDENTIFIER) { + _set_error("Only constant expression or variables allowed in a pattern"); + return NULL; + } + + } else if (value->type != Node::TYPE_IDENTIFIER && value->type != Node::TYPE_CONSTANT) { _set_error("Only constant expressions or variables allowed in a pattern"); return NULL; } @@ -2435,6 +2470,8 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { cf_if->body = alloc_node<BlockNode>(); cf_if->body->parent_block = p_block; + cf_if->body->if_condition = condition; //helps code completion + p_block->sub_blocks.push_back(cf_if->body); if (!_enter_indent_block(cf_if->body)) { @@ -3922,7 +3959,7 @@ void GDParser::_parse_class(ClassNode *p_class) { member._export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; if (cn->value.get_type() == Variant::OBJECT) { Object *obj = cn->value; - Resource *res = obj->cast_to<Resource>(); + Resource *res = Object::cast_to<Resource>(obj); if (res == NULL) { _set_error("Exported constant not a type or resource."); return; diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 3ad3466624..177552d279 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -146,10 +146,13 @@ public: Vector<StringName> variables; Vector<int> variable_lines; + Node *if_condition; //tiny hack to improve code completion on if () blocks + //the following is useful for code completion List<BlockNode *> sub_blocks; int end_line; BlockNode() { + if_condition = NULL; type = TYPE_BLOCK; end_line = -1; parent_block = NULL; @@ -441,6 +444,7 @@ public: COMPLETION_INDEX, COMPLETION_VIRTUAL_FUNC, COMPLETION_YIELD, + COMPLETION_ASSIGN, }; private: diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 23201dc1b0..68c1fb3635 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -73,7 +73,7 @@ Variant GDNativeClass::_new() { ERR_FAIL_COND_V(!o, Variant()); } - Reference *ref = o->cast_to<Reference>(); + Reference *ref = Object::cast_to<Reference>(o); if (ref) { return REF(ref); } else { @@ -161,7 +161,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Variant::CallErro owner = memnew(Reference); //by default, no base means use reference } - Reference *r = owner->cast_to<Reference>(); + Reference *r = Object::cast_to<Reference>(owner); if (r) { ref = REF(r); } @@ -397,7 +397,7 @@ ScriptInstance *GDScript::instance_create(Object *p_this) { } Variant::CallError unchecked_error; - return _create_instance(NULL, 0, p_this, p_this->cast_to<Reference>(), unchecked_error); + return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error); } bool GDScript::instance_has(const Object *p_this) const { @@ -575,9 +575,7 @@ void GDScript::update_exports() { //print_line("update exports for "+get_path()+" ic: "+itos(copy.size())); for (Set<ObjectID>::Element *E = copy.front(); E; E = E->next()) { Object *id = ObjectDB::get_instance(E->get()); - if (!id) - continue; - GDScript *s = id->cast_to<GDScript>(); + GDScript *s = Object::cast_to<GDScript>(id); if (!s) continue; s->update_exports(); @@ -616,7 +614,7 @@ Error GDScript::reload(bool p_keep_state) { if (basedir != "") basedir = basedir.get_base_dir(); - if (basedir != "" && basedir.find("res://") == -1 && basedir.find("user://") == -1) { + if (source.find("%BASE%") != -1) { //loading a template, don't parse return OK; } @@ -2006,11 +2004,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 (p_resource->cast_to<GDScript>()) { + if (Object::cast_to<GDScript>(*p_resource)) { p_extensions->push_back("gd"); } } bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const { - return p_resource->cast_to<GDScript>() != NULL; + return Object::cast_to<GDScript>(*p_resource) != NULL; } diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 17e7b0bc03..441f87474e 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -390,7 +390,7 @@ public: virtual int find_function(const String &p_function, const String &p_code) const; virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return OK; } - virtual Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint); + virtual Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint); #ifdef TOOLS_ENABLED virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_base_path, Object *p_owner, LookupResult &r_result); #endif |