diff options
Diffstat (limited to 'modules/gdscript')
| -rw-r--r-- | modules/gdscript/gdscript.cpp | 64 | ||||
| -rw-r--r-- | modules/gdscript/gdscript.h | 8 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 103 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_compiler.h | 6 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 40 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_function.cpp | 83 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_function.h | 14 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_functions.cpp | 5 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 417 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_parser.h | 9 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_tokenizer.cpp | 50 | ||||
| -rw-r--r-- | modules/gdscript/language_server/gdscript_extend_parser.cpp | 3 | ||||
| -rw-r--r-- | modules/gdscript/language_server/gdscript_workspace.cpp | 3 | ||||
| -rw-r--r-- | modules/gdscript/language_server/lsp.hpp | 33 |
14 files changed, 609 insertions, 229 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 06ab9e226d..8559fac57c 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -376,10 +376,15 @@ void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<Pro } #endif -bool GDScript::_update_exports() { +bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) { #ifdef TOOLS_ENABLED + static Vector<GDScript *> base_caches; + if (!p_recursive_call) + base_caches.clear(); + base_caches.append(this); + bool changed = false; if (source_changed_cache) { @@ -473,7 +478,22 @@ bool GDScript::_update_exports() { placeholder_fallback_enabled = false; if (base_cache.is_valid() && base_cache->is_valid()) { - if (base_cache->_update_exports()) { + for (int i = 0; i < base_caches.size(); i++) { + if (base_caches[i] == base_cache.ptr()) { + if (r_err) + *r_err = true; + valid = false; // to show error in the editor + base_cache->valid = false; + base_cache->inheriters_cache.clear(); // to prevent future stackoverflows + base_cache.unref(); + base.unref(); + _base = nullptr; + ERR_FAIL_V_MSG(false, "Cyclic inheritance in script class."); + } + } + if (base_cache->_update_exports(r_err, true)) { + if (r_err && *r_err) + return false; changed = true; } } @@ -501,7 +521,10 @@ void GDScript::update_exports() { #ifdef TOOLS_ENABLED - _update_exports(); + bool cyclic_error = false; + _update_exports(&cyclic_error); + if (cyclic_error) + return; Set<ObjectID> copy = inheriters_cache; //might get modified @@ -635,12 +658,14 @@ uint16_t GDScript::get_rpc_method_id(const StringName &p_method) const { } StringName GDScript::get_rpc_method(const uint16_t p_rpc_method_id) const { - if (p_rpc_method_id >= rpc_functions.size()) return StringName(); + if (p_rpc_method_id >= rpc_functions.size()) + return StringName(); return rpc_functions[p_rpc_method_id].name; } MultiplayerAPI::RPCMode GDScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - if (p_rpc_method_id >= rpc_functions.size()) return MultiplayerAPI::RPC_MODE_DISABLED; + if (p_rpc_method_id >= rpc_functions.size()) + return MultiplayerAPI::RPC_MODE_DISABLED; return rpc_functions[p_rpc_method_id].mode; } @@ -662,12 +687,14 @@ uint16_t GDScript::get_rset_property_id(const StringName &p_variable) const { } StringName GDScript::get_rset_property(const uint16_t p_rset_member_id) const { - if (p_rset_member_id >= rpc_variables.size()) return StringName(); + if (p_rset_member_id >= rpc_variables.size()) + return StringName(); return rpc_variables[p_rset_member_id].name; } MultiplayerAPI::RPCMode GDScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { - if (p_rset_member_id >= rpc_variables.size()) return MultiplayerAPI::RPC_MODE_DISABLED; + if (p_rset_member_id >= rpc_variables.size()) + return MultiplayerAPI::RPC_MODE_DISABLED; return rpc_variables[p_rset_member_id].mode; } @@ -1052,6 +1079,16 @@ void GDScript::_init_rpc_methods_properties() { } GDScript::~GDScript() { + + { + MutexLock lock(GDScriptLanguage::get_singleton()->lock); + + while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) { + E->self()->_clear_stack(); + pending_func_states.remove(E); + } + } + for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) { memdelete(E->get()); } @@ -1470,9 +1507,15 @@ GDScriptInstance::GDScriptInstance() { } GDScriptInstance::~GDScriptInstance() { - if (script.is_valid() && owner) { - MutexLock lock(GDScriptLanguage::singleton->lock); + MutexLock lock(GDScriptLanguage::get_singleton()->lock); + + while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) { + E->self()->_clear_stack(); + pending_func_states.remove(E); + } + + if (script.is_valid() && owner) { script->instances.erase(owner); } } @@ -2141,7 +2184,8 @@ String GDScriptWarning::get_message() const { case STANDALONE_TERNARY: { return "Standalone ternary conditional operator: the return value is being discarded."; } - case WARNING_MAX: break; // Can't happen, but silences warning + case WARNING_MAX: + break; // Can't happen, but silences warning } ERR_FAIL_V_MSG(String(), "Invalid GDScript warning code: " + get_name_from_code(code) + "."); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 5fdc25669f..b7ac2bd0c5 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -117,6 +117,8 @@ class GDScript : public Script { String fully_qualified_name; SelfList<GDScript> script_list; + SelfList<GDScriptFunctionState>::List pending_func_states; + GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error); void _set_subclass_path(Ref<GDScript> &p_sc, const String &p_path); @@ -133,7 +135,7 @@ class GDScript : public Script { #endif - bool _update_exports(); + bool _update_exports(bool *r_err = nullptr, bool p_recursive_call = false); void _save_orphaned_subclasses(); void _init_rpc_methods_properties(); @@ -254,6 +256,8 @@ class GDScriptInstance : public ScriptInstance { Vector<Variant> members; bool base_ref; + SelfList<GDScriptFunctionState>::List pending_func_states; + void _ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount); public: @@ -347,6 +351,8 @@ struct GDScriptWarning { class GDScriptLanguage : public ScriptLanguage { + friend class GDScriptFunctionState; + static GDScriptLanguage *singleton; Variant *_global_array; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 2bbec29043..473b6fab05 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -177,16 +177,36 @@ int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDS switch (p_expression->op) { - case GDScriptParser::OperatorNode::OP_ASSIGN_ADD: var_op = Variant::OP_ADD; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_SUB: var_op = Variant::OP_SUBTRACT; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_MUL: var_op = Variant::OP_MULTIPLY; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_DIV: var_op = Variant::OP_DIVIDE; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_MOD: var_op = Variant::OP_MODULE; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: var_op = Variant::OP_SHIFT_LEFT; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: var_op = Variant::OP_SHIFT_RIGHT; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_AND: var_op = Variant::OP_BIT_AND; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_OR: var_op = Variant::OP_BIT_OR; break; - case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_XOR: var_op = Variant::OP_BIT_XOR; break; + case GDScriptParser::OperatorNode::OP_ASSIGN_ADD: + var_op = Variant::OP_ADD; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_SUB: + var_op = Variant::OP_SUBTRACT; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_MUL: + var_op = Variant::OP_MULTIPLY; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_DIV: + var_op = Variant::OP_DIVIDE; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_MOD: + var_op = Variant::OP_MODULE; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: + var_op = Variant::OP_SHIFT_LEFT; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: + var_op = Variant::OP_SHIFT_RIGHT; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_AND: + var_op = Variant::OP_BIT_AND; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_OR: + var_op = Variant::OP_BIT_OR; + break; + case GDScriptParser::OperatorNode::OP_ASSIGN_BIT_XOR: + var_op = Variant::OP_BIT_XOR; + break; case GDScriptParser::OperatorNode::OP_INIT_ASSIGN: case GDScriptParser::OperatorNode::OP_ASSIGN: { @@ -861,71 +881,92 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: } break; //unary operators case GDScriptParser::OperatorNode::OP_NEG: { - if (!_create_unary_operator(codegen, on, Variant::OP_NEGATE, p_stack_level)) return -1; + if (!_create_unary_operator(codegen, on, Variant::OP_NEGATE, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_POS: { - if (!_create_unary_operator(codegen, on, Variant::OP_POSITIVE, p_stack_level)) return -1; + if (!_create_unary_operator(codegen, on, Variant::OP_POSITIVE, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_NOT: { - if (!_create_unary_operator(codegen, on, Variant::OP_NOT, p_stack_level)) return -1; + if (!_create_unary_operator(codegen, on, Variant::OP_NOT, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_BIT_INVERT: { - if (!_create_unary_operator(codegen, on, Variant::OP_BIT_NEGATE, p_stack_level)) return -1; + if (!_create_unary_operator(codegen, on, Variant::OP_BIT_NEGATE, p_stack_level)) + return -1; } break; //binary operators (in precedence order) case GDScriptParser::OperatorNode::OP_IN: { - if (!_create_binary_operator(codegen, on, Variant::OP_IN, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_IN, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_EQUAL: { - if (!_create_binary_operator(codegen, on, Variant::OP_EQUAL, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_EQUAL, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_NOT_EQUAL: { - if (!_create_binary_operator(codegen, on, Variant::OP_NOT_EQUAL, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_NOT_EQUAL, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_LESS: { - if (!_create_binary_operator(codegen, on, Variant::OP_LESS, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_LESS, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_LESS_EQUAL: { - if (!_create_binary_operator(codegen, on, Variant::OP_LESS_EQUAL, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_LESS_EQUAL, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_GREATER: { - if (!_create_binary_operator(codegen, on, Variant::OP_GREATER, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_GREATER, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_GREATER_EQUAL: { - if (!_create_binary_operator(codegen, on, Variant::OP_GREATER_EQUAL, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_GREATER_EQUAL, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_ADD: { - if (!_create_binary_operator(codegen, on, Variant::OP_ADD, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_ADD, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_SUB: { - if (!_create_binary_operator(codegen, on, Variant::OP_SUBTRACT, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_SUBTRACT, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_MUL: { - if (!_create_binary_operator(codegen, on, Variant::OP_MULTIPLY, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_MULTIPLY, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_DIV: { - if (!_create_binary_operator(codegen, on, Variant::OP_DIVIDE, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_DIVIDE, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_MOD: { - if (!_create_binary_operator(codegen, on, Variant::OP_MODULE, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_MODULE, p_stack_level)) + return -1; } break; //case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_LEFT,p_stack_level)) return -1;} break; //case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_RIGHT,p_stack_level)) return -1;} break; case GDScriptParser::OperatorNode::OP_BIT_AND: { - if (!_create_binary_operator(codegen, on, Variant::OP_BIT_AND, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_BIT_AND, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_BIT_OR: { - if (!_create_binary_operator(codegen, on, Variant::OP_BIT_OR, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_BIT_OR, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_BIT_XOR: { - if (!_create_binary_operator(codegen, on, Variant::OP_BIT_XOR, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_BIT_XOR, p_stack_level)) + return -1; } break; //shift case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: { - if (!_create_binary_operator(codegen, on, Variant::OP_SHIFT_LEFT, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_SHIFT_LEFT, p_stack_level)) + return -1; } break; case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: { - if (!_create_binary_operator(codegen, on, Variant::OP_SHIFT_RIGHT, p_stack_level)) return -1; + if (!_create_binary_operator(codegen, on, Variant::OP_SHIFT_RIGHT, p_stack_level)) + return -1; } break; //assignment operators case GDScriptParser::OperatorNode::OP_ASSIGN_ADD: diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 34b066b5c7..08e1ec74af 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -123,10 +123,12 @@ class GDScriptCompiler { Vector<int> opcodes; void alloc_stack(int p_level) { - if (p_level >= stack_max) stack_max = p_level + 1; + if (p_level >= stack_max) + stack_max = p_level + 1; } void alloc_call(int p_params) { - if (p_params >= call_max) call_max = p_params; + if (p_params >= call_max) + call_max = p_params; } int current_line; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index ab3228d076..8af98c187f 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1082,16 +1082,36 @@ static bool _guess_expression_type(GDScriptCompletionContext &p_context, const G Variant::Operator vop = Variant::OP_MAX; switch (op->op) { - case GDScriptParser::OperatorNode::OP_ADD: vop = Variant::OP_ADD; break; - case GDScriptParser::OperatorNode::OP_SUB: vop = Variant::OP_SUBTRACT; break; - case GDScriptParser::OperatorNode::OP_MUL: vop = Variant::OP_MULTIPLY; break; - case GDScriptParser::OperatorNode::OP_DIV: vop = Variant::OP_DIVIDE; break; - case GDScriptParser::OperatorNode::OP_MOD: vop = Variant::OP_MODULE; break; - case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: vop = Variant::OP_SHIFT_LEFT; break; - case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: vop = Variant::OP_SHIFT_RIGHT; break; - case GDScriptParser::OperatorNode::OP_BIT_AND: vop = Variant::OP_BIT_AND; break; - case GDScriptParser::OperatorNode::OP_BIT_OR: vop = Variant::OP_BIT_OR; break; - case GDScriptParser::OperatorNode::OP_BIT_XOR: vop = Variant::OP_BIT_XOR; break; + case GDScriptParser::OperatorNode::OP_ADD: + vop = Variant::OP_ADD; + break; + case GDScriptParser::OperatorNode::OP_SUB: + vop = Variant::OP_SUBTRACT; + break; + case GDScriptParser::OperatorNode::OP_MUL: + vop = Variant::OP_MULTIPLY; + break; + case GDScriptParser::OperatorNode::OP_DIV: + vop = Variant::OP_DIVIDE; + break; + case GDScriptParser::OperatorNode::OP_MOD: + vop = Variant::OP_MODULE; + break; + case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: + vop = Variant::OP_SHIFT_LEFT; + break; + case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: + vop = Variant::OP_SHIFT_RIGHT; + break; + case GDScriptParser::OperatorNode::OP_BIT_AND: + vop = Variant::OP_BIT_AND; + break; + case GDScriptParser::OperatorNode::OP_BIT_OR: + vop = Variant::OP_BIT_OR; + break; + case GDScriptParser::OperatorNode::OP_BIT_XOR: + vop = Variant::OP_BIT_XOR; + break; default: { } } diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 44640411bb..df0fac956c 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -294,8 +294,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a line = p_state->line; ip = p_state->ip; alloca_size = p_state->stack.size(); - script = static_cast<GDScript *>(ObjectDB::get_instance(p_state->script_id)); - p_instance = p_state->instance_id.is_valid() ? static_cast<GDScriptInstance *>(ObjectDB::get_instance(p_state->instance_id)->get_script_instance()) : nullptr; + script = p_state->script; + p_instance = p_state->instance; defarg = p_state->defarg; self = p_state->self; @@ -1281,11 +1281,21 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a gdfs->state.alloca_size = alloca_size; gdfs->state.ip = ip + ipofs; gdfs->state.line = line; - gdfs->state.script_id = script->get_instance_id(); + gdfs->state.script = _script; + { + MutexLock lock(GDScriptLanguage::get_singleton()->lock); + _script->pending_func_states.add(&gdfs->scripts_list); + if (p_instance) { + gdfs->state.instance = p_instance; + p_instance->pending_func_states.add(&gdfs->instances_list); + } else { + gdfs->state.instance = NULL; + } + } #ifdef DEBUG_ENABLED + gdfs->state.function_name = name; gdfs->state.script_path = _script->get_path(); #endif - gdfs->state.instance_id = (p_instance && p_instance->get_owner()) ? p_instance->get_owner()->get_instance_id() : ObjectID(); gdfs->state.defarg = defarg; gdfs->function = this; @@ -1833,12 +1843,14 @@ bool GDScriptFunctionState::is_valid(bool p_extended_check) const { return false; if (p_extended_check) { - // Class instance gone? (Otherwise script is valid for sure, because the instance has a ref to the script) - if (state.instance_id.is_valid() && !ObjectDB::get_instance(state.instance_id)) { + MutexLock lock(GDScriptLanguage::get_singleton()->lock); + + // Script gone? + if (!scripts_list.in_list()) { return false; } - // Script gone? (Static method, so there's no instance whose ref to the script can ensure it's valid) - if (!ObjectDB::get_instance(state.script_id)) { + // Class instance gone? (if not static function) + if (state.instance && !instances_list.in_list()) { return false; } } @@ -1849,19 +1861,26 @@ bool GDScriptFunctionState::is_valid(bool p_extended_check) const { Variant GDScriptFunctionState::resume(const Variant &p_arg) { ERR_FAIL_COND_V(!function, Variant()); - if (state.instance_id.is_valid() && !ObjectDB::get_instance(state.instance_id)) { + { + MutexLock lock(GDScriptLanguage::singleton->lock); + + if (!scripts_list.in_list()) { #ifdef DEBUG_ENABLED - ERR_FAIL_V_MSG(Variant(), "Resumed function '" + String(function->get_name()) + "()' after yield, but class instance is gone. At script: " + state.script_path + ":" + itos(state.line)); + ERR_FAIL_V_MSG(Variant(), "Resumed function '" + state.function_name + "()' after yield, but script is gone. At script: " + state.script_path + ":" + itos(state.line)); #else - return Variant(); + return Variant(); #endif - } - if (!ObjectDB::get_instance(state.script_id)) { + } + if (state.instance && !instances_list.in_list()) { #ifdef DEBUG_ENABLED - ERR_FAIL_V_MSG(Variant(), "Resumed function '" + String(function->get_name()) + "()' after yield, but script is gone. At script: " + state.script_path + ":" + itos(state.line)); + ERR_FAIL_V_MSG(Variant(), "Resumed function '" + state.function_name + "()' after yield, but class instance is gone. At script: " + state.script_path + ":" + itos(state.line)); #else - return Variant(); + return Variant(); #endif + } + // Do these now to avoid locking again after the call + scripts_list.remove_from_list(); + instances_list.remove_from_list(); } state.result = p_arg; @@ -1884,6 +1903,8 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { state.result = Variant(); if (completed) { + _clear_stack(); + if (first_state.is_valid()) { first_state->emit_signal("completed", ret); } else { @@ -1893,18 +1914,22 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { #ifdef DEBUG_ENABLED if (EngineDebugger::is_active()) GDScriptLanguage::get_singleton()->exit_function(); - if (state.stack_size) { - //free stack - Variant *stack = (Variant *)state.stack.ptr(); - for (int i = 0; i < state.stack_size; i++) - stack[i].~Variant(); - } #endif } return ret; } +void GDScriptFunctionState::_clear_stack() { + + if (state.stack_size) { + Variant *stack = (Variant *)state.stack.ptr(); + for (int i = 0; i < state.stack_size; i++) + stack[i].~Variant(); + state.stack_size = 0; + } +} + void GDScriptFunctionState::_bind_methods() { ClassDB::bind_method(D_METHOD("resume", "arg"), &GDScriptFunctionState::resume, DEFVAL(Variant())); @@ -1914,18 +1939,20 @@ void GDScriptFunctionState::_bind_methods() { ADD_SIGNAL(MethodInfo("completed", PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); } -GDScriptFunctionState::GDScriptFunctionState() { +GDScriptFunctionState::GDScriptFunctionState() : + scripts_list(this), + instances_list(this) { function = nullptr; } GDScriptFunctionState::~GDScriptFunctionState() { - if (function != nullptr) { - //never called, deinitialize stack - for (int i = 0; i < state.stack_size; i++) { - Variant *v = (Variant *)&state.stack[sizeof(Variant) * i]; - v->~Variant(); - } + _clear_stack(); + + { + MutexLock lock(GDScriptLanguage::singleton->lock); + scripts_list.remove_from_list(); + instances_list.remove_from_list(); } } diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 9d8e23d994..89dbeacf34 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -56,7 +56,8 @@ struct GDScriptDataType { Ref<Script> script_type; bool is_type(const Variant &p_variant, bool p_allow_implicit_conversion = false) const { - if (!has_type) return true; // Can't type check + if (!has_type) + return true; // Can't type check switch (kind) { case UNINITIALIZED: @@ -293,11 +294,12 @@ private: public: struct CallState { - ObjectID script_id; + GDScript *script; + GDScriptInstance *instance; #ifdef DEBUG_ENABLED + StringName function_name; String script_path; #endif - ObjectID instance_id; Vector<uint8_t> stack; int stack_size; Variant self; @@ -357,12 +359,18 @@ class GDScriptFunctionState : public Reference { Variant _signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Ref<GDScriptFunctionState> first_state; + SelfList<GDScriptFunctionState> scripts_list; + SelfList<GDScriptFunctionState> instances_list; + protected: static void _bind_methods(); public: bool is_valid(bool p_extended_check = false) const; Variant resume(const Variant &p_arg = Variant()); + + void _clear_stack(); + GDScriptFunctionState(); ~GDScriptFunctionState(); }; diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index 0199af642f..85a5d86ca0 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -1199,6 +1199,11 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ } r_ret = gdscr->_new(nullptr, -1 /*skip initializer*/, r_error); + if (r_error.error != Callable::CallError::CALL_OK) { + r_ret = Variant(); + return; + } + GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(r_ret)->get_script_instance()); Ref<GDScript> gd_ref = ins->get_script(); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 17077567c7..b03d041aaf 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -72,6 +72,16 @@ bool GDScriptParser::_end_statement() { return false; } +void GDScriptParser::_set_end_statement_error(String p_name) { + String error_msg; + if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER) { + error_msg = vformat("Expected end of statement (\"%s\"), got %s (\"%s\") instead.", p_name, tokenizer->get_token_name(tokenizer->get_token()), tokenizer->get_token_identifier()); + } else { + error_msg = vformat("Expected end of statement (\"%s\"), got %s instead.", p_name, tokenizer->get_token_name(tokenizer->get_token())); + } + _set_error(error_msg); +} + bool GDScriptParser::_enter_indent_block(BlockNode *p_block) { if (tokenizer->get_token() != GDScriptTokenizer::TK_COLON) { @@ -910,10 +920,18 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s e.is_op = true; switch (tokenizer->get_token()) { - case GDScriptTokenizer::TK_OP_ADD: e.op = OperatorNode::OP_POS; break; - case GDScriptTokenizer::TK_OP_SUB: e.op = OperatorNode::OP_NEG; break; - case GDScriptTokenizer::TK_OP_NOT: e.op = OperatorNode::OP_NOT; break; - case GDScriptTokenizer::TK_OP_BIT_INVERT: e.op = OperatorNode::OP_BIT_INVERT; break; + case GDScriptTokenizer::TK_OP_ADD: + e.op = OperatorNode::OP_POS; + break; + case GDScriptTokenizer::TK_OP_SUB: + e.op = OperatorNode::OP_NEG; + break; + case GDScriptTokenizer::TK_OP_NOT: + e.op = OperatorNode::OP_NOT; + break; + case GDScriptTokenizer::TK_OP_BIT_INVERT: + e.op = OperatorNode::OP_BIT_INVERT; + break; default: { } } @@ -1329,25 +1347,55 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s switch (tokenizer->get_token()) { //see operator - case GDScriptTokenizer::TK_OP_IN: op = OperatorNode::OP_IN; break; - case GDScriptTokenizer::TK_OP_EQUAL: op = OperatorNode::OP_EQUAL; break; - case GDScriptTokenizer::TK_OP_NOT_EQUAL: op = OperatorNode::OP_NOT_EQUAL; break; - case GDScriptTokenizer::TK_OP_LESS: op = OperatorNode::OP_LESS; break; - case GDScriptTokenizer::TK_OP_LESS_EQUAL: op = OperatorNode::OP_LESS_EQUAL; break; - case GDScriptTokenizer::TK_OP_GREATER: op = OperatorNode::OP_GREATER; break; - case GDScriptTokenizer::TK_OP_GREATER_EQUAL: op = OperatorNode::OP_GREATER_EQUAL; break; - case GDScriptTokenizer::TK_OP_AND: op = OperatorNode::OP_AND; break; - case GDScriptTokenizer::TK_OP_OR: op = OperatorNode::OP_OR; break; - case GDScriptTokenizer::TK_OP_ADD: op = OperatorNode::OP_ADD; break; - case GDScriptTokenizer::TK_OP_SUB: op = OperatorNode::OP_SUB; break; - case GDScriptTokenizer::TK_OP_MUL: op = OperatorNode::OP_MUL; break; - case GDScriptTokenizer::TK_OP_DIV: op = OperatorNode::OP_DIV; break; + case GDScriptTokenizer::TK_OP_IN: + op = OperatorNode::OP_IN; + break; + case GDScriptTokenizer::TK_OP_EQUAL: + op = OperatorNode::OP_EQUAL; + break; + case GDScriptTokenizer::TK_OP_NOT_EQUAL: + op = OperatorNode::OP_NOT_EQUAL; + break; + case GDScriptTokenizer::TK_OP_LESS: + op = OperatorNode::OP_LESS; + break; + case GDScriptTokenizer::TK_OP_LESS_EQUAL: + op = OperatorNode::OP_LESS_EQUAL; + break; + case GDScriptTokenizer::TK_OP_GREATER: + op = OperatorNode::OP_GREATER; + break; + case GDScriptTokenizer::TK_OP_GREATER_EQUAL: + op = OperatorNode::OP_GREATER_EQUAL; + break; + case GDScriptTokenizer::TK_OP_AND: + op = OperatorNode::OP_AND; + break; + case GDScriptTokenizer::TK_OP_OR: + op = OperatorNode::OP_OR; + break; + case GDScriptTokenizer::TK_OP_ADD: + op = OperatorNode::OP_ADD; + break; + case GDScriptTokenizer::TK_OP_SUB: + op = OperatorNode::OP_SUB; + break; + case GDScriptTokenizer::TK_OP_MUL: + op = OperatorNode::OP_MUL; + break; + case GDScriptTokenizer::TK_OP_DIV: + op = OperatorNode::OP_DIV; + break; case GDScriptTokenizer::TK_OP_MOD: op = OperatorNode::OP_MOD; break; //case GDScriptTokenizer::TK_OP_NEG: op=OperatorNode::OP_NEG ; break; - case GDScriptTokenizer::TK_OP_SHIFT_LEFT: op = OperatorNode::OP_SHIFT_LEFT; break; - case GDScriptTokenizer::TK_OP_SHIFT_RIGHT: op = OperatorNode::OP_SHIFT_RIGHT; break; + case GDScriptTokenizer::TK_OP_SHIFT_LEFT: + op = OperatorNode::OP_SHIFT_LEFT; + break; + case GDScriptTokenizer::TK_OP_SHIFT_RIGHT: + op = OperatorNode::OP_SHIFT_RIGHT; + break; case GDScriptTokenizer::TK_OP_ASSIGN: { _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN; @@ -1364,23 +1412,57 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } } break; - case GDScriptTokenizer::TK_OP_ASSIGN_ADD: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_ADD; break; - case GDScriptTokenizer::TK_OP_ASSIGN_SUB: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SUB; break; - case GDScriptTokenizer::TK_OP_ASSIGN_MUL: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_MUL; break; - case GDScriptTokenizer::TK_OP_ASSIGN_DIV: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_DIV; break; - case GDScriptTokenizer::TK_OP_ASSIGN_MOD: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_MOD; break; - case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SHIFT_LEFT; break; - case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SHIFT_RIGHT; break; - case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_AND; break; - case GDScriptTokenizer::TK_OP_ASSIGN_BIT_OR: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_OR; break; - case GDScriptTokenizer::TK_OP_ASSIGN_BIT_XOR: _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_XOR; break; - case GDScriptTokenizer::TK_OP_BIT_AND: op = OperatorNode::OP_BIT_AND; break; - case GDScriptTokenizer::TK_OP_BIT_OR: op = OperatorNode::OP_BIT_OR; break; - case GDScriptTokenizer::TK_OP_BIT_XOR: op = OperatorNode::OP_BIT_XOR; break; - case GDScriptTokenizer::TK_PR_IS: op = OperatorNode::OP_IS; break; - case GDScriptTokenizer::TK_CF_IF: op = OperatorNode::OP_TERNARY_IF; break; - case GDScriptTokenizer::TK_CF_ELSE: op = OperatorNode::OP_TERNARY_ELSE; break; - default: valid = false; break; + case GDScriptTokenizer::TK_OP_ASSIGN_ADD: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_ADD; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_SUB: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SUB; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_MUL: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_MUL; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_DIV: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_DIV; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_MOD: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_MOD; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SHIFT_LEFT; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_SHIFT_RIGHT; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_AND; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_OR: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_OR; + break; + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_XOR: + _VALIDATE_ASSIGN op = OperatorNode::OP_ASSIGN_BIT_XOR; + break; + case GDScriptTokenizer::TK_OP_BIT_AND: + op = OperatorNode::OP_BIT_AND; + break; + case GDScriptTokenizer::TK_OP_BIT_OR: + op = OperatorNode::OP_BIT_OR; + break; + case GDScriptTokenizer::TK_OP_BIT_XOR: + op = OperatorNode::OP_BIT_XOR; + break; + case GDScriptTokenizer::TK_PR_IS: + op = OperatorNode::OP_IS; + break; + case GDScriptTokenizer::TK_CF_IF: + op = OperatorNode::OP_TERNARY_IF; + break; + case GDScriptTokenizer::TK_CF_ELSE: + op = OperatorNode::OP_TERNARY_ELSE; + break; + default: + valid = false; + break; } if (valid) { @@ -1433,36 +1515,74 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s unary = true; break; - case OperatorNode::OP_MUL: priority = 2; break; - case OperatorNode::OP_DIV: priority = 2; break; - case OperatorNode::OP_MOD: priority = 2; break; + case OperatorNode::OP_MUL: + priority = 2; + break; + case OperatorNode::OP_DIV: + priority = 2; + break; + case OperatorNode::OP_MOD: + priority = 2; + break; - case OperatorNode::OP_ADD: priority = 3; break; - case OperatorNode::OP_SUB: priority = 3; break; + case OperatorNode::OP_ADD: + priority = 3; + break; + case OperatorNode::OP_SUB: + priority = 3; + break; - case OperatorNode::OP_SHIFT_LEFT: priority = 4; break; - case OperatorNode::OP_SHIFT_RIGHT: priority = 4; break; + case OperatorNode::OP_SHIFT_LEFT: + priority = 4; + break; + case OperatorNode::OP_SHIFT_RIGHT: + priority = 4; + break; - case OperatorNode::OP_BIT_AND: priority = 5; break; - case OperatorNode::OP_BIT_XOR: priority = 6; break; - case OperatorNode::OP_BIT_OR: priority = 7; break; + case OperatorNode::OP_BIT_AND: + priority = 5; + break; + case OperatorNode::OP_BIT_XOR: + priority = 6; + break; + case OperatorNode::OP_BIT_OR: + priority = 7; + break; - case OperatorNode::OP_LESS: priority = 8; break; - case OperatorNode::OP_LESS_EQUAL: priority = 8; break; - case OperatorNode::OP_GREATER: priority = 8; break; - case OperatorNode::OP_GREATER_EQUAL: priority = 8; break; + case OperatorNode::OP_LESS: + priority = 8; + break; + case OperatorNode::OP_LESS_EQUAL: + priority = 8; + break; + case OperatorNode::OP_GREATER: + priority = 8; + break; + case OperatorNode::OP_GREATER_EQUAL: + priority = 8; + break; - case OperatorNode::OP_EQUAL: priority = 8; break; - case OperatorNode::OP_NOT_EQUAL: priority = 8; break; + case OperatorNode::OP_EQUAL: + priority = 8; + break; + case OperatorNode::OP_NOT_EQUAL: + priority = 8; + break; - case OperatorNode::OP_IN: priority = 10; break; + case OperatorNode::OP_IN: + priority = 10; + break; case OperatorNode::OP_NOT: priority = 11; unary = true; break; - case OperatorNode::OP_AND: priority = 12; break; - case OperatorNode::OP_OR: priority = 13; break; + case OperatorNode::OP_AND: + priority = 12; + break; + case OperatorNode::OP_OR: + priority = 13; + break; case OperatorNode::OP_TERNARY_IF: priority = 14; @@ -1475,17 +1595,39 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s // Rigth-to-left should be false in this case, otherwise it would always error. break; - case OperatorNode::OP_ASSIGN: priority = 15; break; - case OperatorNode::OP_ASSIGN_ADD: priority = 15; break; - case OperatorNode::OP_ASSIGN_SUB: priority = 15; break; - case OperatorNode::OP_ASSIGN_MUL: priority = 15; break; - case OperatorNode::OP_ASSIGN_DIV: priority = 15; break; - case OperatorNode::OP_ASSIGN_MOD: priority = 15; break; - case OperatorNode::OP_ASSIGN_SHIFT_LEFT: priority = 15; break; - case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: priority = 15; break; - case OperatorNode::OP_ASSIGN_BIT_AND: priority = 15; break; - case OperatorNode::OP_ASSIGN_BIT_OR: priority = 15; break; - case OperatorNode::OP_ASSIGN_BIT_XOR: priority = 15; break; + case OperatorNode::OP_ASSIGN: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_ADD: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_SUB: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_MUL: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_DIV: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_MOD: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_SHIFT_LEFT: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_BIT_AND: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_BIT_OR: + priority = 15; + break; + case OperatorNode::OP_ASSIGN_BIT_XOR: + priority = 15; + break; default: { _set_error("GDScriptParser bug, invalid operator in expression: " + itos(expression[i].op)); @@ -2037,7 +2179,8 @@ bool GDScriptParser::_reduce_export_var_type(Variant &p_value, int p_line) { if (p_value.get_type() == Variant::ARRAY) { Array arr = p_value; for (int i = 0; i < arr.size(); i++) { - if (!_reduce_export_var_type(arr[i], p_line)) return false; + if (!_reduce_export_var_type(arr[i], p_line)) + return false; } return true; } @@ -2046,7 +2189,8 @@ bool GDScriptParser::_reduce_export_var_type(Variant &p_value, int p_line) { Dictionary dict = p_value; for (int i = 0; i < dict.size(); i++) { Variant value = dict.get_value_at_index(i); - if (!_reduce_export_var_type(value, p_line)) return false; + if (!_reduce_export_var_type(value, p_line)) + return false; } return true; } @@ -2734,6 +2878,7 @@ void GDScriptParser::_transform_match_statment(MatchNode *p_match_statement) { IdentifierNode *id2 = alloc_node<IdentifierNode>(); id2->name = local_var->name; + id2->datatype = local_var->datatype; id2->declared_block = branch->body; id2->set_datatype(local_var->assign->get_datatype()); @@ -2937,7 +3082,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { lv->assign = assigned; if (!_end_statement()) { - _set_error("Expected end of statement (\"var\")."); + _set_end_statement_error("var"); return; } @@ -3171,9 +3316,15 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { ConstantNode *cn = alloc_node<ConstantNode>(); switch (args.size()) { - case 1: cn->value = (int)constants[0]; break; - case 2: cn->value = Vector2(constants[0], constants[1]); break; - case 3: cn->value = Vector3(constants[0], constants[1], constants[2]); break; + case 1: + cn->value = (int64_t)constants[0]; + break; + case 2: + cn->value = Vector2i(constants[0], constants[1]); + break; + case 3: + cn->value = Vector3i(constants[0], constants[1], constants[2]); + break; } cn->datatype = _type_from_variant(cn->value); container = cn; @@ -3185,9 +3336,15 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { on->arguments.push_back(tn); switch (args.size()) { - case 1: tn->vtype = Variant::INT; break; - case 2: tn->vtype = Variant::VECTOR2; break; - case 3: tn->vtype = Variant::VECTOR3; break; + case 1: + tn->vtype = Variant::INT; + break; + case 2: + tn->vtype = Variant::VECTOR2I; + break; + case 3: + tn->vtype = Variant::VECTOR3I; + break; } for (int i = 0; i < args.size(); i++) { @@ -3248,7 +3405,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { cf_continue->cf_type = ControlFlowNode::CF_CONTINUE; p_block->statements.push_back(cf_continue); if (!_end_statement()) { - _set_error("Expected end of statement (\"continue\")."); + _set_end_statement_error("continue"); return; } } break; @@ -3260,7 +3417,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { cf_break->cf_type = ControlFlowNode::CF_BREAK; p_block->statements.push_back(cf_break); if (!_end_statement()) { - _set_error("Expected end of statement (\"break\")."); + _set_end_statement_error("break"); return; } } break; @@ -3289,7 +3446,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { cf_return->arguments.push_back(retexpr); p_block->statements.push_back(cf_return); if (!_end_statement()) { - _set_error("Expected end of statement after return expression."); + _set_end_statement_error("return"); return; } } @@ -3326,7 +3483,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { _parse_pattern_block(compiled_branches, match_node->branches, p_static); - if (error_set) return; + if (error_set) + return; ControlFlowNode *match_cf_node = alloc_node<ControlFlowNode>(); match_cf_node->cf_type = ControlFlowNode::CF_MATCH; @@ -3378,7 +3536,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { p_block->statements.push_back(an); if (!_end_statement()) { - _set_error("Expected end of statement after \"assert\".", assert_line); + _set_end_statement_error("assert"); return; } } break; @@ -3389,7 +3547,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { p_block->statements.push_back(bn); if (!_end_statement()) { - _set_error("Expected end of statement after \"breakpoint\"."); + _set_end_statement_error("breakpoint"); return; } } break; @@ -3408,7 +3566,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON && tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { _set_error("Unexpected ':=', use '=' instead. Expected end of statement after expression."); } else { - _set_error(String() + "Expected end of statement after expression, got " + tokenizer->get_token_name(tokenizer->get_token()) + " instead"); + _set_error(vformat("Expected end of statement after expression, got %s instead.", tokenizer->get_token_name(tokenizer->get_token()))); } return; } @@ -3598,7 +3756,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (error_set) return; if (!_end_statement()) { - _set_error("Expected end of statement after \"extends\"."); + _set_end_statement_error("extends"); return; } @@ -4103,7 +4261,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { p_class->_signals.push_back(sig); if (!_end_statement()) { - _set_error("Expected end of statement (\"signal\")."); + _set_end_statement_error("signal"); return; } } break; @@ -4923,7 +5081,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } - if (!_reduce_export_var_type(cn->value, member.line)) return; + if (!_reduce_export_var_type(cn->value, member.line)) + return; member._export.type = cn->value.get_type(); member._export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; @@ -4960,6 +5119,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = member.identifier; + id->datatype = member.data_type; OperatorNode *op = alloc_node<OperatorNode>(); op->op = OperatorNode::OP_INIT_ASSIGN; @@ -5002,6 +5162,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = member.identifier; + id->datatype = member.data_type; OperatorNode *op = alloc_node<OperatorNode>(); op->op = OperatorNode::OP_INIT_ASSIGN; @@ -5044,7 +5205,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { p_class->variables.push_back(member); if (!_end_statement()) { - _set_error("Expected end of statement (\"continue\")."); + _set_end_statement_error("var"); return; } } break; @@ -5124,7 +5285,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { p_class->constant_expressions.insert(const_id, constant); if (!_end_statement()) { - _set_error("Expected end of statement (constant).", line); + _set_end_statement_error("const"); return; } @@ -5278,7 +5439,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (!_end_statement()) { - _set_error("Expected end of statement (\"enum\")."); + _set_end_statement_error("enum"); return; } @@ -5438,8 +5599,10 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive } } - if (base_class) break; - if (found) continue; + if (base_class) + break; + if (found) + continue; if (p->constant_expressions.has(base)) { if (p->constant_expressions[base].expression->type != Node::TYPE_CONSTANT) { @@ -5541,10 +5704,12 @@ void GDScriptParser::_determine_inheritance(ClassNode *p_class, bool p_recursive } String GDScriptParser::DataType::to_string() const { - if (!has_type) return "var"; + if (!has_type) + return "var"; switch (kind) { case BUILTIN: { - if (builtin_type == Variant::NIL) return "null"; + if (builtin_type == Variant::NIL) + return "null"; return Variant::get_type_name(builtin_type); } break; case NATIVE: { @@ -5708,8 +5873,10 @@ bool GDScriptParser::_parse_type(DataType &r_type, bool p_can_be_void) { } GDScriptParser::DataType GDScriptParser::_resolve_type(const DataType &p_source, int p_line) { - if (!p_source.has_type) return p_source; - if (p_source.kind != DataType::UNRESOLVED) return p_source; + if (!p_source.has_type) + return p_source; + if (p_source.kind != DataType::UNRESOLVED) + return p_source; Vector<String> full_name = p_source.native_type.operator String().split(".", false); int name_part = 0; @@ -6647,6 +6814,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = cn->value.operator StringName(); + id->datatype = cn->datatype; op->op = OperatorNode::OP_INDEX_NAMED; op->arguments.write[1] = id; @@ -6948,7 +7116,8 @@ bool GDScriptParser::_get_function_signature(DataType &p_base_type, const String native = "_" + native.operator String(); } if (!ClassDB::class_exists(native)) { - if (!check_types) return false; + if (!check_types) + return false; ERR_FAIL_V_MSG(false, "Parser bug: Class '" + String(native) + "' not found."); } @@ -7039,7 +7208,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat par_types.write[i - 1] = _reduce_node_type(p_call->arguments[i]); } - if (error_set) return DataType(); + if (error_set) + return DataType(); // Special case: check copy constructor. Those are defined implicitly in Variant. if (par_types.size() == 1) { @@ -7107,7 +7277,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat err += "' matches the signature '"; err += Variant::get_type_name(tn->vtype) + "("; for (int i = 0; i < par_types.size(); i++) { - if (i > 0) err += ", "; + if (i > 0) + err += ", "; err += par_types[i].to_string(); } err += ")'."; @@ -7465,7 +7636,8 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN native = "_" + native.operator String(); } if (!ClassDB::class_exists(native)) { - if (!check_types) return false; + if (!check_types) + return false; ERR_FAIL_V_MSG(false, "Parser bug: Class \"" + String(native) + "\" not found."); } @@ -7571,6 +7743,10 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType } if (_get_member_type(base_type, p_identifier, member_type)) { + if (!p_base_type && current_function && current_function->_static) { + _set_error("Can't access member variable (\"" + p_identifier.operator String() + "\") from a static function.", p_line); + return DataType(); + } return member_type; } @@ -7758,12 +7934,14 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { // Function declarations for (int i = 0; i < p_class->static_functions.size(); i++) { _check_function_types(p_class->static_functions[i]); - if (error_set) return; + if (error_set) + return; } for (int i = 0; i < p_class->functions.size(); i++) { _check_function_types(p_class->functions[i]); - if (error_set) return; + if (error_set) + return; } // Class variables @@ -7802,7 +7980,7 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { ConstantNode *tgt_type = alloc_node<ConstantNode>(); tgt_type->line = v.line; - tgt_type->value = (int)v.data_type.builtin_type; + tgt_type->value = (int64_t)v.data_type.builtin_type; OperatorNode *convert_call = alloc_node<OperatorNode>(); convert_call->line = v.line; @@ -7838,7 +8016,8 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { } // Setter and getter - if (v.setter == StringName() && v.getter == StringName()) continue; + if (v.setter == StringName() && v.getter == StringName()) + continue; bool found_getter = false; bool found_setter = false; @@ -7881,10 +8060,12 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { return; } } - if (found_getter && found_setter) break; + if (found_getter && found_setter) + break; } - if ((found_getter || v.getter == StringName()) && (found_setter || v.setter == StringName())) continue; + if ((found_getter || v.getter == StringName()) && (found_setter || v.setter == StringName())) + continue; // Check for static functions for (int j = 0; j < p_class->static_functions.size(); j++) { @@ -7915,7 +8096,8 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { for (int i = 0; i < p_class->subclasses.size(); i++) { current_class = p_class->subclasses[i]; _check_class_level_types(current_class); - if (error_set) return; + if (error_set) + return; current_class = p_class; } } @@ -8063,7 +8245,8 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { _check_block_types(current_block); current_block = nullptr; current_function = nullptr; - if (error_set) return; + if (error_set) + return; } for (int i = 0; i < p_class->functions.size(); i++) { @@ -8073,7 +8256,8 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { _check_block_types(current_block); current_block = nullptr; current_function = nullptr; - if (error_set) return; + if (error_set) + return; } #ifdef DEBUG_ENABLED @@ -8094,7 +8278,8 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { for (int i = 0; i < p_class->subclasses.size(); i++) { current_class = p_class->subclasses[i]; _check_class_blocks_types(current_class); - if (error_set) return; + if (error_set) + return; current_class = p_class; } } @@ -8179,7 +8364,7 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { ConstantNode *tgt_type = alloc_node<ConstantNode>(); tgt_type->line = lv->line; - tgt_type->value = (int)lv->datatype.builtin_type; + tgt_type->value = (int64_t)lv->datatype.builtin_type; tgt_type->datatype = _type_from_variant(tgt_type->value); OperatorNode *convert_call = alloc_node<OperatorNode>(); @@ -8357,7 +8542,8 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { _add_warning(GDScriptWarning::RETURN_VALUE_DISCARDED, op->line, func_name); } #endif // DEBUG_ENABLED - if (error_set) return; + if (error_set) + return; } break; case OperatorNode::OP_YIELD: { _mark_line_as_safe(op->line); @@ -8392,7 +8578,8 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { } } - if (!function_type.has_type) break; + if (!function_type.has_type) + break; if (function_type.kind == DataType::BUILTIN && function_type.builtin_type == Variant::NIL) { // Return void, should not have arguments @@ -8452,7 +8639,8 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { current_block = p_block->sub_blocks[i]; _check_block_types(current_block); current_block = p_block; - if (error_set) return; + if (error_set) + return; } #ifdef DEBUG_ENABLED @@ -8595,7 +8783,8 @@ Error GDScriptParser::_parse(const String &p_base_path) { current_function = nullptr; current_block = nullptr; - if (for_completion) check_types = false; + if (for_completion) + check_types = false; // Resolve all class-level stuff before getting into function blocks _check_class_level_types(main_class); @@ -8784,7 +8973,7 @@ int GDScriptParser::get_completion_argument_index() { return completion_argument; } -int GDScriptParser::get_completion_identifier_is_function() { +bool GDScriptParser::get_completion_identifier_is_function() { return completion_ident_is_call; } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index f254352423..a33417e536 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -624,6 +624,7 @@ private: void _parse_extends(ClassNode *p_class); void _parse_class(ClassNode *p_class); bool _end_statement(); + void _set_end_statement_error(String p_name); void _determine_inheritance(ClassNode *p_class, bool p_recursive = true); bool _parse_type(DataType &r_type, bool p_can_be_void = false); @@ -647,12 +648,14 @@ private: void _check_block_types(BlockNode *p_block); _FORCE_INLINE_ void _mark_line_as_safe(int p_line) const { #ifdef DEBUG_ENABLED - if (safe_lines) safe_lines->insert(p_line); + if (safe_lines) + safe_lines->insert(p_line); #endif // DEBUG_ENABLED } _FORCE_INLINE_ void _mark_line_as_unsafe(int p_line) const { #ifdef DEBUG_ENABLED - if (safe_lines) safe_lines->erase(p_line); + if (safe_lines) + safe_lines->erase(p_line); #endif // DEBUG_ENABLED } @@ -683,7 +686,7 @@ public: BlockNode *get_completion_block(); FunctionNode *get_completion_function(); int get_completion_argument_index(); - int get_completion_identifier_is_function(); + bool get_completion_identifier_is_function(); const List<String> &get_dependencies() const { return dependencies; } diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index d42ca52731..1c8282e13e 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -803,19 +803,36 @@ void GDScriptTokenizerText::_advance() { switch (next) { - case 'a': res = 7; break; - case 'b': res = 8; break; - case 't': res = 9; break; - case 'n': res = 10; break; - case 'v': res = 11; break; - case 'f': res = 12; break; - case 'r': res = 13; break; - case '\'': res = '\''; break; - case '\"': res = '\"'; break; - case '\\': res = '\\'; break; - case '/': - res = '/'; - break; //wtf + case 'a': + res = '\a'; + break; + case 'b': + res = '\b'; + break; + case 't': + res = '\t'; + break; + case 'n': + res = '\n'; + break; + case 'v': + res = '\v'; + break; + case 'f': + res = '\f'; + break; + case 'r': + res = '\r'; + break; + case '\'': + res = '\''; + break; + case '\"': + res = '\"'; + break; + case '\\': + res = '\\'; + break; case 'u': { // hex number @@ -847,6 +864,10 @@ void GDScriptTokenizerText::_advance() { i += 3; } break; + case '\n': { + line++; + column = 1; + } break; default: { _make_error("Invalid escape sequence"); @@ -854,7 +875,8 @@ void GDScriptTokenizerText::_advance() { } break; } - str += res; + if (next != '\n') + str += res; } else { if (CharType(GETCHAR(i)) == '\n') { diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index b2c6b0e1ab..a6b749059a 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -385,7 +385,8 @@ String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) { int start_line = p_docs_down ? p_line : p_line - 1; for (int i = start_line; true; i += step) { - if (i < 0 || i >= lines.size()) break; + if (i < 0 || i >= lines.size()) + break; String line_comment = lines[i].strip_edges(true, false); if (line_comment.begins_with("#")) { diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 32fc8f36f0..be036b44c4 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -185,7 +185,8 @@ Array GDScriptWorkspace::symbol(const Dictionary &p_params) { } Error GDScriptWorkspace::initialize() { - if (initialized) return OK; + if (initialized) + return OK; DocData *doc = EditorHelp::get_doc_data(); for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) { diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index 124fcbfed8..e469a26df8 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -282,7 +282,8 @@ struct Command { Dictionary dict; dict["title"] = title; dict["command"] = command; - if (arguments.size()) dict["arguments"] = arguments; + if (arguments.size()) + dict["arguments"] = arguments; return dict; } }; @@ -946,16 +947,20 @@ struct CompletionItem { dict["preselect"] = preselect; dict["sortText"] = sortText; dict["filterText"] = filterText; - if (commitCharacters.size()) dict["commitCharacters"] = commitCharacters; + if (commitCharacters.size()) + dict["commitCharacters"] = commitCharacters; dict["command"] = command.to_json(); } return dict; } void load(const Dictionary &p_dict) { - if (p_dict.has("label")) label = p_dict["label"]; - if (p_dict.has("kind")) kind = p_dict["kind"]; - if (p_dict.has("detail")) detail = p_dict["detail"]; + if (p_dict.has("label")) + label = p_dict["label"]; + if (p_dict.has("kind")) + kind = p_dict["kind"]; + if (p_dict.has("detail")) + detail = p_dict["detail"]; if (p_dict.has("documentation")) { Variant doc = p_dict["documentation"]; if (doc.get_type() == Variant::STRING) { @@ -965,12 +970,18 @@ struct CompletionItem { documentation.value = v["value"]; } } - if (p_dict.has("deprecated")) deprecated = p_dict["deprecated"]; - if (p_dict.has("preselect")) preselect = p_dict["preselect"]; - if (p_dict.has("sortText")) sortText = p_dict["sortText"]; - if (p_dict.has("filterText")) filterText = p_dict["filterText"]; - if (p_dict.has("insertText")) insertText = p_dict["insertText"]; - if (p_dict.has("data")) data = p_dict["data"]; + if (p_dict.has("deprecated")) + deprecated = p_dict["deprecated"]; + if (p_dict.has("preselect")) + preselect = p_dict["preselect"]; + if (p_dict.has("sortText")) + sortText = p_dict["sortText"]; + if (p_dict.has("filterText")) + filterText = p_dict["filterText"]; + if (p_dict.has("insertText")) + insertText = p_dict["insertText"]; + if (p_dict.has("data")) + data = p_dict["data"]; } }; |