summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/gdscript_function.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.cpp86
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/language_server/lsp.hpp6
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("(");