summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/SCsub11
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml6
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml2
-rw-r--r--modules/gdscript/gdscript.cpp2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp10
-rw-r--r--modules/gdscript/gdscript_editor.cpp30
-rw-r--r--modules/gdscript/gdscript_function.cpp13
-rw-r--r--modules/gdscript/gdscript_functions.cpp36
-rw-r--r--modules/gdscript/gdscript_functions.h1
-rw-r--r--modules/gdscript/gdscript_parser.cpp244
-rw-r--r--modules/gdscript/gdscript_parser.h8
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp2
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp6
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp4
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp4
-rw-r--r--modules/gdscript/register_types.cpp15
16 files changed, 305 insertions, 89 deletions
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub
index 6285e6bb54..74e653ce43 100644
--- a/modules/gdscript/SCsub
+++ b/modules/gdscript/SCsub
@@ -8,5 +8,12 @@ env_gdscript = env_modules.Clone()
env_gdscript.add_source_files(env.modules_sources, "*.cpp")
if env['tools']:
- env_gdscript.add_source_files(env.modules_sources, "./editor/*.cpp")
- env_gdscript.add_source_files(env.modules_sources, "./language_server/*.cpp")
+ env_gdscript.add_source_files(env.modules_sources, "./editor/*.cpp")
+
+ # Those two modules are required for the language server protocol
+ if env['module_jsonrpc_enabled'] and env['module_websocket_enabled']:
+ env_gdscript.add_source_files(env.modules_sources, "./language_server/*.cpp")
+ else:
+ # Using a define in the disabled case, to avoid having an extra define
+ # in regular builds where all modules are enabled.
+ env_gdscript.Append(CPPDEFINES=['GDSCRIPT_NO_LSP'])
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index ad47323613..4efa90fd86 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -1115,7 +1115,11 @@
<argument index="1" name="step" type="float">
</argument>
<description>
- Snaps float value [code]s[/code] to a given [code]step[/code].
+ Snaps float value [code]s[/code] to a given [code]step[/code]. This can also be used to round a floating point number to an arbitrary number of decimals.
+ [codeblock]
+ stepify(100, 32) # Returns 96
+ stepify(3.14159, 0.01) # Returns 3.14
+ [/codeblock]
</description>
</method>
<method name="str" qualifiers="vararg">
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index d606a41fab..6f43361914 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -19,7 +19,7 @@
</description>
</method>
<method name="new" qualifiers="vararg">
- <return type="Object">
+ <return type="Variant">
</return>
<description>
Returns a new instance of the script.
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 5dab063061..c8ec80c101 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -99,7 +99,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 CONSTRUCT */
#ifndef NO_THREADS
GDScriptLanguage::singleton->lock->lock();
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 7166189416..dea2225e91 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1520,8 +1520,16 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo
if (ret2 < 0)
return ERR_PARSE_ERROR;
+ int message_ret = 0;
+ if (as->message) {
+ message_ret = _parse_expression(codegen, as->message, p_stack_level + 1, false);
+ if (message_ret < 0)
+ return ERR_PARSE_ERROR;
+ }
+
codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSERT);
codegen.opcodes.push_back(ret2);
+ codegen.opcodes.push_back(message_ret);
#endif
} break;
case GDScriptParser::Node::TYPE_BREAKPOINT: {
@@ -2064,7 +2072,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
}
instance->owner->set_script_instance(instance);
- /* STEP 2, INITIALIZE AND CONSRTUCT */
+ /* STEP 2, INITIALIZE AND CONSTRUCT */
Variant::CallError ce;
p_script->initializer->call(instance, NULL, 0, ce);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 7c01e85ff7..9b3bf8ad5b 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -223,7 +223,7 @@ bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const
_debug_parse_err_line = p_line;
_debug_parse_err_file = p_file;
_debug_error = p_error;
- ScriptDebugger::get_singleton()->debug(this, false);
+ ScriptDebugger::get_singleton()->debug(this, false, true);
return true;
} else {
return false;
@@ -237,7 +237,8 @@ bool GDScriptLanguage::debug_break(const String &p_error, bool p_allow_continue)
_debug_parse_err_line = -1;
_debug_parse_err_file = "";
_debug_error = p_error;
- ScriptDebugger::get_singleton()->debug(this, p_allow_continue);
+ bool is_error_breakpoint = p_error != "Breakpoint";
+ ScriptDebugger::get_singleton()->debug(this, p_allow_continue, is_error_breakpoint);
return true;
} else {
return false;
@@ -1936,9 +1937,18 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
Ref<GDScript> script = base_type.script_type;
if (script.is_valid()) {
if (!_static && !p_only_functions) {
- for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) {
- ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_MEMBER);
- r_result.insert(option.display, option);
+ if (p_context.base && p_context.base->get_script_instance()) {
+ List<PropertyInfo> members;
+ p_context.base->get_script_instance()->get_property_list(&members);
+ for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER);
+ r_result.insert(option.display, option);
+ }
+ } else {
+ for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) {
+ ScriptCodeCompletionOption option(E->get().operator String(), ScriptCodeCompletionOption::KIND_MEMBER);
+ r_result.insert(option.display, option);
+ }
}
}
if (!p_only_functions) {
@@ -2826,6 +2836,16 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
ScriptCodeCompletionOption option(Variant::get_type_name((Variant::Type)i), ScriptCodeCompletionOption::KIND_CLASS);
options.insert(option.display, option);
}
+ List<PropertyInfo> props;
+ ProjectSettings::get_singleton()->get_property_list(&props);
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ String s = E->get().name;
+ if (!s.begins_with("autoload/")) {
+ continue;
+ }
+ ScriptCodeCompletionOption option(s.get_slice("/", 1), ScriptCodeCompletionOption::KIND_CLASS);
+ options.insert(option.display, option);
+ }
}
List<StringName> native_classes;
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index 68f2a9473e..bdeea9cef3 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -1475,20 +1475,25 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
DISPATCH_OPCODE;
OPCODE(OPCODE_ASSERT) {
- CHECK_SPACE(2);
+ CHECK_SPACE(3);
#ifdef DEBUG_ENABLED
GET_VARIANT_PTR(test, 1);
+ GET_VARIANT_PTR(message, 2);
bool result = test->booleanize();
if (!result) {
-
- err_text = "Assertion failed.";
+ const String &message_str = *message;
+ if (message_str.empty()) {
+ err_text = "Assertion failed.";
+ } else {
+ err_text = "Assertion failed: " + message_str;
+ }
OPCODE_BREAK;
}
#endif
- ip += 2;
+ ip += 3;
}
DISPATCH_OPCODE;
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index ad8bf5b2c0..97790e00bb 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -106,6 +106,7 @@ const char *GDScriptFunctions::get_func_name(Function p_func) {
"typeof",
"type_exists",
"char",
+ "ord",
"str",
"print",
"printt",
@@ -665,6 +666,33 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
CharType result[2] = { *p_args[0], 0 };
r_ret = String(result);
} break;
+ case TEXT_ORD: {
+
+ VALIDATE_ARG_COUNT(1);
+
+ if (p_args[0]->get_type() != Variant::STRING) {
+
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ r_ret = Variant();
+ return;
+ }
+
+ String str = p_args[0]->operator String();
+
+ if (str.length() != 1) {
+
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ r_ret = RTR("Expected a string of length 1 (a character).");
+ return;
+ }
+
+ r_ret = str.get(0);
+
+ } break;
case TEXT_STR: {
if (p_arg_count < 1) {
r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
@@ -1507,6 +1535,7 @@ bool GDScriptFunctions::is_deterministic(Function p_func) {
case TYPE_OF:
case TYPE_EXISTS:
case TEXT_CHAR:
+ case TEXT_ORD:
case TEXT_STR:
case COLOR8:
case LEN:
@@ -1849,6 +1878,13 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
return mi;
} break;
+ case TEXT_ORD: {
+
+ MethodInfo mi("ord", PropertyInfo(Variant::STRING, "char"));
+ mi.return_val.type = Variant::INT;
+ return mi;
+
+ } break;
case TEXT_STR: {
MethodInfo mi("str");
diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h
index 8f7ba76d2c..9ea5dd46cf 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/gdscript/gdscript_functions.h
@@ -97,6 +97,7 @@ public:
TYPE_OF,
TYPE_EXISTS,
TEXT_CHAR,
+ TEXT_ORD,
TEXT_STR,
TEXT_PRINT,
TEXT_PRINT_TABBED,
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index a9f22225a0..967b0c83ae 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -252,6 +252,16 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
}
+ // Check that the next token is not TK_CURSOR and if it is, the offset should be incremented.
+ int next_valid_offset = 1;
+ if (tokenizer->get_token(next_valid_offset) == GDScriptTokenizer::TK_CURSOR) {
+ next_valid_offset++;
+ // There is a chunk of the identifier that also needs to be ignored (not always there!)
+ if (tokenizer->get_token(next_valid_offset) == GDScriptTokenizer::TK_IDENTIFIER) {
+ next_valid_offset++;
+ }
+ }
+
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
//subexpression ()
tokenizer->advance();
@@ -668,7 +678,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
expr = cn;
}
- } else if (tokenizer->get_token(1) == GDScriptTokenizer::TK_PARENTHESIS_OPEN && tokenizer->is_token_literal()) {
+ } else if (tokenizer->get_token(next_valid_offset) == GDScriptTokenizer::TK_PARENTHESIS_OPEN && tokenizer->is_token_literal()) {
// We check with is_token_literal, as this allows us to use match/sync/etc. as a name
//function or constructor
@@ -1197,7 +1207,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (_get_completable_identifier(COMPLETION_INDEX, identifier)) {
if (identifier == StringName()) {
- identifier = "@temp"; //so it parses allright
+ identifier = "@temp"; //so it parses alright
}
completion_node = op;
@@ -1389,9 +1399,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
unary = true;
break;
case OperatorNode::OP_NEG:
- priority = 1;
- unary = true;
- break;
case OperatorNode::OP_POS:
priority = 1;
unary = true;
@@ -2836,15 +2843,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
assigned = subexpr;
} else {
- ConstantNode *c = alloc_node<ConstantNode>();
- if (lv->datatype.has_type && lv->datatype.kind == DataType::BUILTIN) {
- Variant::CallError err;
- c->value = Variant::construct(lv->datatype.builtin_type, NULL, 0, err);
- } else {
- c->value = Variant();
- }
- c->line = var_line;
- assigned = c;
+ assigned = _get_default_value_for_type(lv->datatype, var_line);
}
lv->assign = assigned;
//must be added later, to avoid self-referencing.
@@ -3270,15 +3269,36 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
case GDScriptTokenizer::TK_PR_ASSERT: {
tokenizer->advance();
- Node *condition = _parse_and_reduce_expression(p_block, p_static);
- if (!condition) {
- if (_recover_from_completion()) {
- break;
- }
+
+ if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
+ _set_error("Expected '(' after assert");
return;
}
+
+ tokenizer->advance();
+
+ Vector<Node *> args;
+ const bool result = _parse_arguments(p_block, args, p_static);
+ if (!result) {
+ return;
+ }
+
+ if (args.empty() || args.size() > 2) {
+ _set_error("Wrong number of arguments, expected 1 or 2");
+ return;
+ }
+
AssertNode *an = alloc_node<AssertNode>();
- an->condition = condition;
+ an->condition = _reduce_expression(args[0], p_static);
+
+ if (args.size() == 2) {
+ an->message = _reduce_expression(args[1], p_static);
+ } else {
+ ConstantNode *message_node = alloc_node<ConstantNode>();
+ message_node->value = String();
+ an->message = message_node;
+ }
+
p_block->statements.push_back(an);
if (!_end_statement()) {
@@ -3366,7 +3386,7 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) {
return;
}
- if (!p_class->constant_expressions.empty() || !p_class->subclasses.empty() || !p_class->functions.empty() || !p_class->variables.empty() || p_class->classname_used) {
+ if (!p_class->constant_expressions.empty() || !p_class->subclasses.empty() || !p_class->functions.empty() || !p_class->variables.empty()) {
_set_error("\"extends\" must be used before anything else.");
return;
@@ -3523,6 +3543,15 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
+ if (p_class->classname_used && ProjectSettings::get_singleton()->has_setting("autoload/" + p_class->name)) {
+ const String autoload_path = ProjectSettings::get_singleton()->get_setting("autoload/" + p_class->name);
+ if (autoload_path.begins_with("*")) {
+ // It's a singleton, and not just a regular AutoLoad script.
+ _set_error("The class \"" + p_class->name + "\" conflicts with the AutoLoad singleton of the same name, and is therefore redundant. Remove the class_name declaration to fix this error.");
+ }
+ return;
+ }
+
tokenizer->advance(2);
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
@@ -4829,35 +4858,29 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- Variant::Type initial_type = member.data_type.has_type ? member.data_type.builtin_type : member._export.type;
-
- if (initial_type != Variant::NIL && initial_type != Variant::OBJECT) {
- IdentifierNode *id = alloc_node<IdentifierNode>();
- id->name = member.identifier;
+ Node *expr;
- Node *expr;
+ if (member.data_type.has_type) {
+ expr = _get_default_value_for_type(member.data_type);
+ } else {
+ DataType exported_type;
+ exported_type.has_type = true;
+ exported_type.kind = DataType::BUILTIN;
+ exported_type.builtin_type = member._export.type;
+ expr = _get_default_value_for_type(exported_type);
+ }
- // Make sure arrays and dictionaries are not shared
- if (initial_type == Variant::ARRAY) {
- expr = alloc_node<ArrayNode>();
- } else if (initial_type == Variant::DICTIONARY) {
- expr = alloc_node<DictionaryNode>();
- } else {
- ConstantNode *cn = alloc_node<ConstantNode>();
- Variant::CallError ce2;
- cn->value = Variant::construct(initial_type, NULL, 0, ce2);
- expr = cn;
- }
+ IdentifierNode *id = alloc_node<IdentifierNode>();
+ id->name = member.identifier;
- OperatorNode *op = alloc_node<OperatorNode>();
- op->op = OperatorNode::OP_INIT_ASSIGN;
- op->arguments.push_back(id);
- op->arguments.push_back(expr);
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op = OperatorNode::OP_INIT_ASSIGN;
+ op->arguments.push_back(id);
+ op->arguments.push_back(expr);
- p_class->initializer->statements.push_back(op);
+ p_class->initializer->statements.push_back(op);
- member.initial_assignment = op;
- }
+ member.initial_assignment = op;
}
if (autoexport && member.data_type.has_type) {
@@ -5245,6 +5268,31 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive
return;
}
p = NULL;
+ } else {
+ List<PropertyInfo> props;
+ ProjectSettings::get_singleton()->get_property_list(&props);
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ String s = E->get().name;
+ if (!s.begins_with("autoload/")) {
+ continue;
+ }
+ String name = s.get_slice("/", 1);
+ if (name == base) {
+ String singleton_path = ProjectSettings::get_singleton()->get(s);
+ if (singleton_path.begins_with("*")) {
+ singleton_path = singleton_path.right(1);
+ }
+ if (!singleton_path.begins_with("res://")) {
+ singleton_path = "res://" + singleton_path;
+ }
+ base_script = ResourceLoader::load(singleton_path);
+ if (!base_script.is_valid()) {
+ _set_error("Class '" + base + "' could not be fully loaded (script error or cyclic inheritance).", p_class->line);
+ return;
+ }
+ p = NULL;
+ }
+ }
}
while (p) {
@@ -5589,9 +5637,49 @@ GDScriptParser::DataType GDScriptParser::_resolve_type(const DataType &p_source,
}
name_part++;
continue;
- } else {
- p = current_class;
}
+ List<PropertyInfo> props;
+ ProjectSettings::get_singleton()->get_property_list(&props);
+ String singleton_path;
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ String s = E->get().name;
+ if (!s.begins_with("autoload/")) {
+ continue;
+ }
+ String name = s.get_slice("/", 1);
+ if (name == id) {
+ singleton_path = ProjectSettings::get_singleton()->get(s);
+ if (singleton_path.begins_with("*")) {
+ singleton_path = singleton_path.right(1);
+ }
+ if (!singleton_path.begins_with("res://")) {
+ singleton_path = "res://" + singleton_path;
+ }
+ break;
+ }
+ }
+ if (!singleton_path.empty()) {
+ Ref<Script> script = ResourceLoader::load(singleton_path);
+ Ref<GDScript> gds = script;
+ if (gds.is_valid()) {
+ if (!gds->is_valid()) {
+ _set_error("Class '" + id + "' could not be fully loaded (script error or cyclic inheritance).", p_line);
+ return DataType();
+ }
+ result.kind = DataType::GDSCRIPT;
+ result.script_type = gds;
+ } else if (script.is_valid()) {
+ result.kind = DataType::SCRIPT;
+ result.script_type = script;
+ } else {
+ _set_error("Couldn't fully load singleton script '" + id + "' (possible cyclic reference or parse error).", p_line);
+ return DataType();
+ }
+ name_part++;
+ continue;
+ }
+
+ p = current_class;
} else if (base_type.kind == DataType::CLASS) {
p = base_type.class_type;
}
@@ -5652,28 +5740,35 @@ GDScriptParser::DataType GDScriptParser::_resolve_type(const DataType &p_source,
}
}
- // Still look for class constants in parent script
+ // Still look for class constants in parent scripts
if (!found && (base_type.kind == DataType::GDSCRIPT || base_type.kind == DataType::SCRIPT)) {
Ref<Script> scr = base_type.script_type;
ERR_FAIL_COND_V(scr.is_null(), result);
- Map<StringName, Variant> constants;
- scr->get_constants(&constants);
+ while (scr.is_valid()) {
+ Map<StringName, Variant> constants;
+ scr->get_constants(&constants);
- if (constants.has(id)) {
- Ref<GDScript> gds = constants[id];
+ if (constants.has(id)) {
+ Ref<GDScript> gds = constants[id];
- if (gds.is_valid()) {
- result.kind = DataType::GDSCRIPT;
- result.script_type = gds;
- found = true;
- } else {
- Ref<Script> scr2 = constants[id];
- if (scr2.is_valid()) {
- result.kind = DataType::SCRIPT;
- result.script_type = scr2;
+ if (gds.is_valid()) {
+ result.kind = DataType::GDSCRIPT;
+ result.script_type = gds;
found = true;
+ } else {
+ Ref<Script> scr2 = constants[id];
+ if (scr2.is_valid()) {
+ result.kind = DataType::SCRIPT;
+ result.script_type = scr2;
+ found = true;
+ }
}
}
+ if (found) {
+ break;
+ } else {
+ scr = scr->get_base_script();
+ }
}
}
@@ -6065,6 +6160,31 @@ bool GDScriptParser::_is_type_compatible(const DataType &p_container, const Data
return false;
}
+GDScriptParser::Node *GDScriptParser::_get_default_value_for_type(const DataType &p_type, int p_line) {
+ Node *result;
+
+ if (p_type.has_type && p_type.kind == DataType::BUILTIN && p_type.builtin_type != Variant::NIL && p_type.builtin_type != Variant::OBJECT) {
+ if (p_type.builtin_type == Variant::ARRAY) {
+ result = alloc_node<ArrayNode>();
+ } else if (p_type.builtin_type == Variant::DICTIONARY) {
+ result = alloc_node<DictionaryNode>();
+ } else {
+ ConstantNode *c = alloc_node<ConstantNode>();
+ Variant::CallError err;
+ c->value = Variant::construct(p_type.builtin_type, NULL, 0, err);
+ result = c;
+ }
+ } else {
+ ConstantNode *c = alloc_node<ConstantNode>();
+ c->value = Variant();
+ result = c;
+ }
+
+ result->line = p_line;
+
+ return result;
+}
+
GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
#ifdef DEBUG_ENABLED
if (p_node->get_datatype().has_type && p_node->type != Node::TYPE_ARRAY && p_node->type != Node::TYPE_DICTIONARY) {
@@ -6510,7 +6630,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
return DataType();
}
}
- if (check_types && !node_type.has_type) {
+ if (check_types && !node_type.has_type && base_type.kind == DataType::BUILTIN) {
// Can infer indexing type for some variant types
DataType result;
result.has_type = true;
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 72aa819a8c..04ce9cf4c6 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -481,7 +481,12 @@ public:
struct AssertNode : public Node {
Node *condition;
- AssertNode() { type = TYPE_ASSERT; }
+ Node *message;
+ AssertNode() :
+ condition(0),
+ message(0) {
+ type = TYPE_ASSERT;
+ }
};
struct BreakpointNode : public Node {
@@ -610,6 +615,7 @@ private:
bool _get_function_signature(DataType &p_base_type, const StringName &p_function, DataType &r_return_type, List<DataType> &r_arg_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) const;
bool _get_member_type(const DataType &p_base_type, const StringName &p_member, DataType &r_member_type) const;
bool _is_type_compatible(const DataType &p_container, const DataType &p_expression, bool p_allow_implicit_conversion = false) const;
+ Node *_get_default_value_for_type(const DataType &p_type, int p_line = -1);
DataType _reduce_node_type(Node *p_node);
DataType _reduce_function_call_type(const OperatorNode *p_call);
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 45f9ec9c6a..9e8727ec58 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -189,6 +189,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
lsp::DocumentSymbol symbol;
const GDScriptParser::ClassNode::Constant &c = E->value();
const GDScriptParser::ConstantNode *node = dynamic_cast<const GDScriptParser::ConstantNode *>(c.expression);
+ ERR_FAIL_COND(!node);
symbol.name = E->key();
symbol.kind = lsp::SymbolKind::Constant;
symbol.deprecated = false;
@@ -674,6 +675,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
const GDScriptParser::ClassNode::Constant &c = E->value();
const GDScriptParser::ConstantNode *node = dynamic_cast<const GDScriptParser::ConstantNode *>(c.expression);
+ ERR_FAIL_COND_V(!node, class_api);
Dictionary api;
api["name"] = E->key();
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index afe461b68e..ce3de9bc3b 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -100,9 +100,10 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
String root_uri = p_params["rootUri"];
String root = p_params["rootPath"];
- bool is_same_workspace = root == workspace->root;
+ bool is_same_workspace;
+#ifndef WINDOWS_ENABLED
is_same_workspace = root.to_lower() == workspace->root.to_lower();
-#ifdef WINDOWS_ENABLED
+#else
is_same_workspace = root.replace("\\", "/").to_lower() == workspace->root.to_lower();
#endif
@@ -142,6 +143,7 @@ void GDScriptLanguageProtocol::poll() {
Error GDScriptLanguageProtocol::start(int p_port) {
if (server == NULL) {
server = dynamic_cast<WebSocketServer *>(ClassDB::instance("WebSocketServer"));
+ ERR_FAIL_COND_V(!server, FAILED);
server->set_buffers(8192, 1024, 8192, 1024); // 8mb should be way more than enough
server->connect("data_received", this, "on_data_received");
server->connect("client_connected", this, "on_client_connected");
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index 9bea4557ac..62c212a2bd 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -64,7 +64,7 @@ void GDScriptLanguageServer::thread_main(void *p_userdata) {
void GDScriptLanguageServer::start() {
int port = (int)_EDITOR_GET("network/language_server/remote_port");
if (protocol.start(port) == OK) {
- EditorNode::get_log()->add_message("** GDScript Language Server Started **");
+ EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR);
ERR_FAIL_COND(thread != NULL || thread_exit);
thread_exit = false;
thread = Thread::create(GDScriptLanguageServer::thread_main, this);
@@ -78,7 +78,7 @@ void GDScriptLanguageServer::stop() {
memdelete(thread);
thread = NULL;
protocol.stop();
- EditorNode::get_log()->add_message("** GDScript Language Server Stopped **");
+ EditorNode::get_log()->add_message("--- GDScript language server stopped ---", EditorLog::MSG_TYPE_EDITOR);
}
void register_lsp_types() {
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index f211fae526..7c58c7aa15 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -380,8 +380,8 @@ GDScriptTextDocument::~GDScriptTextDocument() {
memdelete(file_checker);
}
-void GDScriptTextDocument::sync_script_content(const String &p_uri, const String &p_content) {
- String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_uri);
+void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {
+ String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path);
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
}
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index d07949b34b..94b9e8c2d9 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -34,10 +34,8 @@
#include "core/io/resource_loader.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
-#include "editor/gdscript_highlighter.h"
#include "gdscript.h"
#include "gdscript_tokenizer.h"
-#include "language_server/gdscript_language_server.h"
GDScriptLanguage *script_language_gd = NULL;
Ref<ResourceFormatLoaderGDScript> resource_loader_gd;
@@ -45,10 +43,15 @@ Ref<ResourceFormatSaverGDScript> resource_saver_gd;
#ifdef TOOLS_ENABLED
-#include "core/engine.h"
#include "editor/editor_export.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/gdscript_highlighter.h"
+
+#ifndef GDSCRIPT_NO_LSP
+#include "core/engine.h"
+#include "language_server/gdscript_language_server.h"
+#endif // !GDSCRIPT_NO_LSP
class EditorExportGDScript : public EditorExportPlugin {
@@ -137,13 +140,15 @@ static void _editor_init() {
gd_export.instance();
EditorExport::get_singleton()->add_export_plugin(gd_export);
+#ifndef GDSCRIPT_NO_LSP
register_lsp_types();
GDScriptLanguageServer *lsp_plugin = memnew(GDScriptLanguageServer);
EditorNode::get_singleton()->add_editor_plugin(lsp_plugin);
Engine::get_singleton()->add_singleton(Engine::Singleton("GDScriptLanguageProtocol", GDScriptLanguageProtocol::get_singleton()));
+#endif // !GDSCRIPT_NO_LSP
}
-#endif
+#endif // TOOLS_ENABLED
void register_gdscript_types() {
@@ -162,7 +167,7 @@ void register_gdscript_types() {
#ifdef TOOLS_ENABLED
ScriptEditor::register_create_syntax_highlighter_function(GDScriptSyntaxHighlighter::create);
EditorNode::add_init_callback(_editor_init);
-#endif
+#endif // TOOLS_ENABLED
}
void unregister_gdscript_types() {