diff options
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/gdscript.cpp | 16 | ||||
-rw-r--r-- | modules/gdscript/gdscript.h | 1 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 101 | ||||
-rw-r--r-- | modules/gdscript/gdscript_tokenizer.cpp | 9 | ||||
-rw-r--r-- | modules/gdscript/gdscript_vm.cpp | 2 | ||||
-rw-r--r-- | modules/gdscript/language_server/gdscript_language_protocol.h | 2 |
6 files changed, 117 insertions, 14 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index e4d3ed118c..68da588c3d 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -361,7 +361,7 @@ ScriptInstance *GDScript::instance_create(Object *p_this) { 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 instantiated in object of type: '" + p_this->get_class() + "'"); + GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'"); } ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type '" + p_this->get_class() + "'" + "."); } @@ -789,6 +789,14 @@ void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) { } } +String GDScript::_get_debug_path() const { + if (is_built_in() && !get_name().is_empty()) { + return get_name() + " (" + get_path().get_slice("::", 0) + ")"; + } else { + return get_path(); + } +} + Error GDScript::reload(bool p_keep_state) { bool has_instances; { @@ -832,7 +840,7 @@ Error GDScript::reload(bool p_keep_state) { Error err = parser.parse(source, path, false); 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); + GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_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.is_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(), false, ERR_HANDLER_SCRIPT); @@ -844,7 +852,7 @@ Error GDScript::reload(bool p_keep_state) { 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); + GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message); } const List<GDScriptParser::ParserError>::Element *e = parser.get_errors().front(); @@ -867,7 +875,7 @@ Error GDScript::reload(bool 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()); + GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error()); } _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT); ERR_FAIL_V(ERR_COMPILATION_FAILED); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 791f8a1431..ade4f247c9 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -135,6 +135,7 @@ class GDScript : public Script { GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error); void _set_subclass_path(Ref<GDScript> &p_sc, const String &p_path); + String _get_debug_path() const; #ifdef TOOLS_ENABLED Set<PlaceHolderScriptInstance *> placeholders; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index b96139ac51..bde6783322 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -740,10 +740,24 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)() #endif // TOOLS_ENABLED if (member->identifier != nullptr) { - // Enums may be unnamed. - // TODO: Consider names in outer scope too, for constants and classes (and static functions?) - if (current_class->members_indices.has(member->identifier->name)) { - push_error(vformat(R"(%s "%s" has the same name as a previously declared %s.)", p_member_kind.capitalize(), member->identifier->name, current_class->get_member(member->identifier->name).get_type_name()), member->identifier); + if (!((String)member->identifier->name).is_empty()) { // Enums may be unnamed. + List<MethodInfo> gdscript_funcs; + GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs); + for (MethodInfo &info : gdscript_funcs) { + if (info.name == member->identifier->name) { + push_error(vformat(R"(%s "%s" has the same name as a built-in function.)", p_member_kind.capitalize(), member->identifier->name), member->identifier); + return; + } + } + if (current_class->members_indices.has(member->identifier->name)) { + push_error(vformat(R"(%s "%s" has the same name as a previously declared %s.)", p_member_kind.capitalize(), member->identifier->name, current_class->get_member(member->identifier->name).get_type_name()), member->identifier); + } else if (Variant::has_utility_function(member->identifier->name)) { + push_error(vformat(R"(%s "%s" has the same name as a built-in function.)", p_member_kind.capitalize(), member->identifier->name), member->identifier); + } else if (ClassDB::class_exists(member->identifier->name)) { + push_error(vformat(R"(%s "%s" has the same name as a global class.)", p_member_kind.capitalize(), member->identifier->name), member->identifier); + } else { + current_class->add_member(member); + } } else { current_class->add_member(member); } @@ -811,9 +825,27 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper return nullptr; } + GDScriptParser::IdentifierNode *identifier = parse_identifier(); + + List<MethodInfo> gdscript_funcs; + GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs); + for (MethodInfo &info : gdscript_funcs) { + if (info.name == identifier->name) { + push_error(vformat(R"(Local var "%s" has the same name as a built-in function.)", identifier->name), identifier); + return nullptr; + } + } + if (Variant::has_utility_function(identifier->name)) { + push_error(vformat(R"(Local var "%s" has the same name as a built-in function.)", identifier->name), identifier); + return nullptr; + } else if (ClassDB::class_exists(identifier->name)) { + push_error(vformat(R"(Local var "%s" has the same name as a global class.)", identifier->name), identifier); + return nullptr; + } + VariableNode *variable = alloc_node<VariableNode>(); - variable->identifier = parse_identifier(); - variable->export_info.name = variable->identifier->name; + variable->identifier = identifier; + variable->export_info.name = identifier->name; if (match(GDScriptTokenizer::Token::COLON)) { if (check(GDScriptTokenizer::Token::NEWLINE)) { @@ -1066,8 +1098,26 @@ GDScriptParser::ParameterNode *GDScriptParser::parse_parameter() { return nullptr; } + GDScriptParser::IdentifierNode *identifier = parse_identifier(); + + List<MethodInfo> gdscript_funcs; + GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs); + for (MethodInfo &info : gdscript_funcs) { + if (info.name == identifier->name) { + push_error(vformat(R"(Parameter "%s" has the same name as a built-in function.)", identifier->name), identifier); + return nullptr; + } + } + if (Variant::has_utility_function(identifier->name)) { + push_error(vformat(R"(Parameter "%s" has the same name as a built-in function.)", identifier->name), identifier); + return nullptr; + } else if (ClassDB::class_exists(identifier->name)) { + push_error(vformat(R"(Parameter "%s" has the same name as a global class.)", identifier->name), identifier); + return nullptr; + } + ParameterNode *parameter = alloc_node<ParameterNode>(); - parameter->identifier = parse_identifier(); + parameter->identifier = identifier; if (match(GDScriptTokenizer::Token::COLON)) { if (check((GDScriptTokenizer::Token::EQUAL))) { @@ -1145,13 +1195,31 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() { HashMap<StringName, int> elements; + List<MethodInfo> gdscript_funcs; + GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs); + do { if (check(GDScriptTokenizer::Token::BRACE_CLOSE)) { break; // Allow trailing comma. } if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier for enum key.)")) { EnumNode::Value item; - item.identifier = parse_identifier(); + GDScriptParser::IdentifierNode *identifier = parse_identifier(); + + for (MethodInfo &info : gdscript_funcs) { + if (info.name == identifier->name) { + push_error(vformat(R"(Enum member "%s" has the same name as a built-in function.)", identifier->name), identifier); + return nullptr; + } + } + if (Variant::has_utility_function(identifier->name)) { + push_error(vformat(R"(Enum member "%s" has the same name as a built-in function.)", identifier->name), identifier); + return nullptr; + } else if (ClassDB::class_exists(identifier->name)) { + push_error(vformat(R"(Enum member "%s" has the same name as a global class.)", identifier->name), identifier); + return nullptr; + } + item.identifier = identifier; item.parent_enum = enum_node; item.line = previous.start_line; item.leftmost_column = previous.leftmost_column; @@ -2774,6 +2842,23 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p get_node->chain.push_back(identifier); } while (match(GDScriptTokenizer::Token::SLASH)); return get_node; + } else if (match(GDScriptTokenizer::Token::SLASH)) { + GetNodeNode *get_node = alloc_node<GetNodeNode>(); + IdentifierNode *identifier_root = alloc_node<IdentifierNode>(); + get_node->chain.push_back(identifier_root); + int chain_position = 0; + do { + make_completion_context(COMPLETION_GET_NODE, get_node, chain_position++); + if (!current.is_node_name()) { + push_error(R"(Expect node path after "/".)"); + return nullptr; + } + advance(); + IdentifierNode *identifier = alloc_node<IdentifierNode>(); + identifier->name = previous.get_identifier(); + get_node->chain.push_back(identifier); + } while (match(GDScriptTokenizer::Token::SLASH)); + return get_node; } else { push_error(R"(Expect node path as string or identifier after "$".)"); return nullptr; diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index cd247d1d26..3725fb58f5 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -795,6 +795,15 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() { char32_t ch = _peek(); + if (ch == 0x200E || ch == 0x200F || (ch >= 0x202A && ch <= 0x202E) || (ch >= 0x2066 && ch <= 0x2069)) { + Token error = make_error("Invisible text direction control character present in the string, escape it (\"\\u" + String::num_int64(ch, 16) + "\") to avoid confusion."); + error.start_column = column; + error.leftmost_column = error.start_column; + error.end_column = column + 1; + error.rightmost_column = error.end_column; + push_error(error); + } + if (ch == '\\') { // Escape pattern. _advance(); diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index a1cc2246d6..6dd8c3e0dd 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -3309,7 +3309,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } int err_line = line; if (err_text == "") { - err_text = "Internal Script Error! - opcode #" + itos(last_opcode) + " (report please)."; + err_text = "Internal script error! Opcode: " + itos(last_opcode) + " (please report)."; } if (!GDScriptLanguage::get_singleton()->debug_break(err_text, false)) { diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h index 899446fb42..a4a63a23a8 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -38,7 +38,7 @@ #include "gdscript_workspace.h" #include "lsp.hpp" -#include "modules/modules_enabled.gen.h" +#include "modules/modules_enabled.gen.h" // For jsonrpc. #ifdef MODULE_JSONRPC_ENABLED #include "modules/jsonrpc/jsonrpc.h" #else |