diff options
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/gdscript_function.cpp | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 86 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.h | 2 | ||||
-rw-r--r-- | modules/gdscript/language_server/lsp.hpp | 6 |
4 files changed, 89 insertions, 7 deletions
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 92e07ab874..fc0c4b3138 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -1818,8 +1818,6 @@ 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 { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 57531ed13b..0e498f6895 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3151,6 +3151,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { cf_while->body = alloc_node<BlockNode>(); cf_while->body->parent_block = p_block; + cf_while->body->can_break = true; + cf_while->body->can_continue = true; p_block->sub_blocks.push_back(cf_while->body); if (!_enter_indent_block(cf_while->body)) { @@ -3165,7 +3167,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { if (error_set) { return; } - p_block->has_return = cf_while->body->has_return; p_block->statements.push_back(cf_while); } break; case GDScriptTokenizer::TK_CF_FOR: { @@ -3278,6 +3279,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { cf_for->body = alloc_node<BlockNode>(); cf_for->body->parent_block = p_block; + cf_for->body->can_break = true; + cf_for->body->can_continue = true; p_block->sub_blocks.push_back(cf_for->body); if (!_enter_indent_block(cf_for->body)) { @@ -3304,10 +3307,24 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { if (error_set) { return; } - p_block->has_return = cf_for->body->has_return; p_block->statements.push_back(cf_for); } break; case GDScriptTokenizer::TK_CF_CONTINUE: { + BlockNode *upper_block = p_block; + bool is_continue_valid = false; + while (upper_block) { + if (upper_block->can_continue) { + is_continue_valid = true; + break; + } + upper_block = upper_block->parent_block; + } + + if (!is_continue_valid) { + _set_error("Unexpected keyword \"continue\" outside a loop."); + return; + } + _mark_line_as_safe(tokenizer->get_token_line()); tokenizer->advance(); ControlFlowNode *cf_continue = alloc_node<ControlFlowNode>(); @@ -3319,6 +3336,21 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } } break; case GDScriptTokenizer::TK_CF_BREAK: { + BlockNode *upper_block = p_block; + bool is_break_valid = false; + while (upper_block) { + if (upper_block->can_break) { + is_break_valid = true; + break; + } + upper_block = upper_block->parent_block; + } + + if (!is_break_valid) { + _set_error("Unexpected keyword \"break\" outside a loop."); + return; + } + _mark_line_as_safe(tokenizer->get_token_line()); tokenizer->advance(); ControlFlowNode *cf_break = alloc_node<ControlFlowNode>(); @@ -3384,6 +3416,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { BlockNode *compiled_branches = alloc_node<BlockNode>(); compiled_branches->parent_block = p_block; compiled_branches->parent_class = p_block->parent_class; + compiled_branches->can_continue = true; p_block->sub_blocks.push_back(compiled_branches); @@ -4088,6 +4121,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { sig.name = tokenizer->get_token_identifier(); sig.emissions = 0; sig.line = tokenizer->get_token_line(); + + for (int i = 0; i < current_class->_signals.size(); i++) { + if (current_class->_signals[i].name == sig.name) { + _set_error("The signal \"" + sig.name + "\" already exists in this class (at line: " + itos(current_class->_signals[i].line) + ")."); + return; + } + } + tokenizer->advance(); if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN) { @@ -7913,6 +7954,47 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { } } + // Signals + DataType base = p_class->base_type; + + while (base.kind == DataType::CLASS) { + ClassNode *base_class = base.class_type; + for (int i = 0; i < p_class->_signals.size(); i++) { + for (int j = 0; j < base_class->_signals.size(); j++) { + if (p_class->_signals[i].name == base_class->_signals[j].name) { + _set_error("The signal \"" + p_class->_signals[i].name + "\" already exists in a parent class.", p_class->_signals[i].line); + return; + } + } + } + base = base_class->base_type; + } + + StringName native; + if (base.kind == DataType::GDSCRIPT || base.kind == DataType::SCRIPT) { + Ref<Script> scr = base.script_type; + if (scr.is_valid() && scr->is_valid()) { + native = scr->get_instance_base_type(); + for (int i = 0; i < p_class->_signals.size(); i++) { + if (scr->has_script_signal(p_class->_signals[i].name)) { + _set_error("The signal \"" + p_class->_signals[i].name + "\" already exists in a parent class.", p_class->_signals[i].line); + return; + } + } + } + } else if (base.kind == DataType::NATIVE) { + native = base.native_type; + } + + if (native != StringName()) { + for (int i = 0; i < p_class->_signals.size(); i++) { + if (ClassDB::has_signal(native, p_class->_signals[i].name)) { + _set_error("The signal \"" + p_class->_signals[i].name + "\" already exists in a parent class.", p_class->_signals[i].line); + return; + } + } + } + // Inner classes for (int i = 0; i < p_class->subclasses.size(); i++) { current_class = p_class->subclasses[i]; diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index cfcca9584e..7dedb6d6f9 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -231,6 +231,8 @@ public: List<Node *> statements; Map<StringName, LocalVarNode *> variables; bool has_return = false; + bool can_break = false; + bool can_continue = false; Node *if_condition = nullptr; //tiny hack to improve code completion on if () blocks diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index 44a0076107..cf27a1578c 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -486,7 +486,7 @@ struct TextDocumentSyncOptions { * If present save notifications are sent to the server. If omitted the notification should not be * sent. */ - SaveOptions save; + bool save = false; Dictionary to_json() { Dictionary dict; @@ -494,7 +494,7 @@ struct TextDocumentSyncOptions { dict["willSave"] = willSave; dict["openClose"] = openClose; dict["change"] = change; - dict["save"] = save.to_json(); + dict["save"] = save; return dict; } }; @@ -1656,7 +1656,7 @@ struct ServerCapabilities { _FORCE_INLINE_ Dictionary to_json() { Dictionary dict; - dict["textDocumentSync"] = (int)textDocumentSync.change; + dict["textDocumentSync"] = textDocumentSync.to_json(); dict["completionProvider"] = completionProvider.to_json(); signatureHelpProvider.triggerCharacters.push_back(","); signatureHelpProvider.triggerCharacters.push_back("("); |