summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/gdscript.cpp4
-rw-r--r--modules/gdscript/gdscript_editor.cpp9
-rw-r--r--modules/gdscript/gdscript_function.cpp4
-rw-r--r--modules/gdscript/gdscript_functions.cpp4
-rw-r--r--modules/gdscript/gdscript_parser.cpp106
-rw-r--r--modules/gdscript/gdscript_parser.h22
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp81
-rw-r--r--modules/gdscript/gdscript_tokenizer.h10
8 files changed, 140 insertions, 100 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index db7f8d22e6..edb296437b 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -199,7 +199,7 @@ StringName GDScript::get_instance_base_type() const {
if (native.is_valid())
return native->get_name();
- if (base.is_valid())
+ if (base.is_valid() && base->is_valid())
return base->get_instance_base_type();
return StringName();
}
@@ -486,7 +486,7 @@ bool GDScript::_update_exports() {
placeholder_fallback_enabled = false;
- if (base_cache.is_valid()) {
+ if (base_cache.is_valid() && base_cache->is_valid()) {
if (base_cache->_update_exports()) {
changed = true;
}
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 9b3bf8ad5b..1d82735328 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1944,11 +1944,10 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
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);
- }
+ }
+ 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) {
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index 83d02e4977..d8816726ce 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -1561,14 +1561,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
//error
// function, file, line, error, explanation
String err_file;
- if (p_instance && p_instance->script->is_valid() && p_instance->script->path != "")
+ if (p_instance && ObjectDB::instance_validate(p_instance->owner) && p_instance->script->is_valid() && p_instance->script->path != "")
err_file = p_instance->script->path;
else if (script)
err_file = script->path;
if (err_file == "")
err_file = "<built-in>";
String err_func = name;
- if (p_instance && p_instance->script->is_valid() && p_instance->script->name != "")
+ if (p_instance && ObjectDB::instance_validate(p_instance->owner) && p_instance->script->is_valid() && p_instance->script->name != "")
err_func = p_instance->script->name + "." + err_func;
int err_line = line;
if (err_text == "") {
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index d9535d0f1f..185eb6c3fc 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -589,7 +589,8 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
r_ret = wref;
}
} else if (p_args[0]->get_type() == Variant::NIL) {
- r_ret = memnew(WeakRef);
+ Ref<WeakRef> wref = memnew(WeakRef);
+ r_ret = wref;
} else {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
@@ -1273,6 +1274,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
if (err != OK) {
r_ret = Variant();
+ ERR_PRINTS(vformat("Error parsing JSON at line %s: %s", errl, errs));
}
} break;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index cf326bef36..9d229adb2a 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -89,8 +89,8 @@ bool GDScriptParser::_enter_indent_block(BlockNode *p_block) {
if (tokenizer->get_token() != GDScriptTokenizer::TK_NEWLINE) {
// be more python-like
- int current = tab_level.back()->get();
- tab_level.push_back(current);
+ IndentLevel current_level = indent_level.back()->get();
+ indent_level.push_back(current_level);
return true;
//_set_error("newline expected after ':'.");
//return false;
@@ -105,12 +105,19 @@ bool GDScriptParser::_enter_indent_block(BlockNode *p_block) {
} else if (tokenizer->get_token(1) != GDScriptTokenizer::TK_NEWLINE) {
int indent = tokenizer->get_token_line_indent();
- int current = tab_level.back()->get();
- if (indent <= current) {
+ int tabs = tokenizer->get_token_line_tab_indent();
+ IndentLevel current_level = indent_level.back()->get();
+ IndentLevel new_indent(indent, tabs);
+ if (new_indent.is_mixed(current_level)) {
+ _set_error("Mixed tabs and spaces in indentation.");
return false;
}
- tab_level.push_back(indent);
+ if (indent <= current_level.indent) {
+ return false;
+ }
+
+ indent_level.push_back(new_indent);
tokenizer->advance();
return true;
@@ -858,11 +865,23 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
if (current_function) {
int arg_idx = current_function->arguments.find(identifier);
if (arg_idx != -1) {
- if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) {
- // Assignment is not really usage
- current_function->arguments_usage.write[arg_idx] = current_function->arguments_usage[arg_idx] - 1;
- } else {
- current_function->arguments_usage.write[arg_idx] = current_function->arguments_usage[arg_idx] + 1;
+ switch (tokenizer->get_token()) {
+ case GDScriptTokenizer::TK_OP_ASSIGN_ADD:
+ case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND:
+ case GDScriptTokenizer::TK_OP_ASSIGN_BIT_OR:
+ case GDScriptTokenizer::TK_OP_ASSIGN_BIT_XOR:
+ case GDScriptTokenizer::TK_OP_ASSIGN_DIV:
+ case GDScriptTokenizer::TK_OP_ASSIGN_MOD:
+ case GDScriptTokenizer::TK_OP_ASSIGN_MUL:
+ case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT:
+ case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT:
+ case GDScriptTokenizer::TK_OP_ASSIGN_SUB:
+ case GDScriptTokenizer::TK_OP_ASSIGN: {
+ // Assignment is not really usage
+ } break;
+ default: {
+ current_function->arguments_usage.write[arg_idx] = current_function->arguments_usage[arg_idx] + 1;
+ }
}
}
}
@@ -2213,7 +2232,7 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
}
void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode *> &p_branches, bool p_static) {
- int indent_level = tab_level.back()->get();
+ IndentLevel current_level = indent_level.back()->get();
p_block->has_return = true;
@@ -2228,7 +2247,7 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran
if (error_set)
return;
- if (indent_level > tab_level.back()->get()) {
+ if (current_level.indent > indent_level.back()->get().indent) {
break; // go back a level
}
@@ -2683,7 +2702,7 @@ void GDScriptParser::_transform_match_statment(MatchNode *p_match_statement) {
void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
- int indent_level = tab_level.back()->get();
+ IndentLevel current_level = indent_level.back()->get();
#ifdef DEBUG_ENABLED
@@ -2696,9 +2715,13 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
bool is_first_line = true;
while (true) {
- if (!is_first_line && tab_level.back()->prev() && tab_level.back()->prev()->get() == indent_level) {
+ if (!is_first_line && indent_level.back()->prev() && indent_level.back()->prev()->get().indent == current_level.indent) {
+ if (indent_level.back()->prev()->get().is_mixed(current_level)) {
+ _set_error("Mixed tabs and spaces in indentation.");
+ return;
+ }
// pythonic single-line expression, don't parse future lines
- tab_level.pop_back();
+ indent_level.pop_back();
p_block->end_line = tokenizer->get_token_line();
return;
}
@@ -2708,7 +2731,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
if (error_set)
return;
- if (indent_level > tab_level.back()->get()) {
+ if (current_level.indent > indent_level.back()->get().indent) {
p_block->end_line = tokenizer->get_token_line();
return; //go back a level
}
@@ -2912,14 +2935,14 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline())
;
- if (tab_level.back()->get() < indent_level) { //not at current indent level
+ if (indent_level.back()->get().indent < current_level.indent) { //not at current indent level
p_block->end_line = tokenizer->get_token_line();
return;
}
if (tokenizer->get_token() == GDScriptTokenizer::TK_CF_ELIF) {
- if (tab_level.back()->get() > indent_level) {
+ if (indent_level.back()->get().indent > current_level.indent) {
_set_error("Invalid indentation.");
return;
@@ -2967,7 +2990,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
} else if (tokenizer->get_token() == GDScriptTokenizer::TK_CF_ELSE) {
- if (tab_level.back()->get() > indent_level) {
+ if (indent_level.back()->get().indent > current_level.indent) {
_set_error("Invalid indentation.");
return;
}
@@ -3339,32 +3362,45 @@ bool GDScriptParser::_parse_newline() {
if (tokenizer->get_token(1) != GDScriptTokenizer::TK_EOF && tokenizer->get_token(1) != GDScriptTokenizer::TK_NEWLINE) {
+ IndentLevel current_level = indent_level.back()->get();
int indent = tokenizer->get_token_line_indent();
- int current_indent = tab_level.back()->get();
+ int tabs = tokenizer->get_token_line_tab_indent();
+ IndentLevel new_level(indent, tabs);
- if (indent > current_indent) {
+ if (new_level.is_mixed(current_level)) {
+ _set_error("Mixed tabs and spaces in indentation.");
+ return false;
+ }
+
+ if (indent > current_level.indent) {
_set_error("Unexpected indentation.");
return false;
}
- if (indent < current_indent) {
+ if (indent < current_level.indent) {
- while (indent < current_indent) {
+ while (indent < current_level.indent) {
//exit block
- if (tab_level.size() == 1) {
+ if (indent_level.size() == 1) {
_set_error("Invalid indentation. Bug?");
return false;
}
- tab_level.pop_back();
+ indent_level.pop_back();
- if (tab_level.back()->get() < indent) {
+ if (indent_level.back()->get().indent < indent) {
_set_error("Unindent does not match any outer indentation level.");
return false;
}
- current_indent = tab_level.back()->get();
+
+ if (indent_level.back()->get().is_mixed(current_level)) {
+ _set_error("Mixed tabs and spaces in indentation.");
+ return false;
+ }
+
+ current_level = indent_level.back()->get();
}
tokenizer->advance();
@@ -3462,7 +3498,7 @@ void GDScriptParser::_parse_extends(ClassNode *p_class) {
void GDScriptParser::_parse_class(ClassNode *p_class) {
- int indent_level = tab_level.back()->get();
+ IndentLevel current_level = indent_level.back()->get();
while (true) {
@@ -3470,7 +3506,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
if (error_set)
return;
- if (indent_level > tab_level.back()->get()) {
+ if (current_level.indent > indent_level.back()->get().indent) {
p_class->end_line = tokenizer->get_token_line();
return; //go back a level
}
@@ -6109,12 +6145,18 @@ bool GDScriptParser::_is_type_compatible(const DataType &p_container, const Data
break;
}
+ // Some classes are prefixed with `_` internally
+ if (!ClassDB::class_exists(expr_native)) {
+ expr_native = "_" + expr_native;
+ }
+
switch (p_container.kind) {
case DataType::NATIVE: {
if (p_container.is_meta_type) {
return ClassDB::is_parent_class(expr_native, GDScriptNativeClass::get_class_static());
} else {
- return ClassDB::is_parent_class(expr_native, p_container.native_type);
+ StringName container_native = ClassDB::class_exists(p_container.native_type) ? p_container.native_type : StringName("_" + p_container.native_type);
+ return ClassDB::is_parent_class(expr_native, container_native);
}
} break;
case DataType::SCRIPT:
@@ -8544,8 +8586,8 @@ void GDScriptParser::clear() {
validating = false;
for_completion = false;
error_set = false;
- tab_level.clear();
- tab_level.push_back(0);
+ indent_level.clear();
+ indent_level.push_back(IndentLevel(0, 0));
error_line = 0;
error_column = 0;
pending_newline = -1;
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 04ce9cf4c6..93557d745d 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -552,7 +552,27 @@ private:
int pending_newline;
- List<int> tab_level;
+ struct IndentLevel {
+ int indent;
+ int tabs;
+
+ bool is_mixed(IndentLevel other) {
+ return (
+ (indent == other.indent && tabs != other.tabs) ||
+ (indent > other.indent && tabs < other.tabs) ||
+ (indent < other.indent && tabs > other.tabs));
+ }
+
+ IndentLevel() :
+ indent(0),
+ tabs(0) {}
+
+ IndentLevel(int p_indent, int p_tabs) :
+ indent(p_indent),
+ tabs(p_tabs) {}
+ };
+
+ List<IndentLevel> indent_level;
String base_path;
String self_path;
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 8b20b0ff48..23a86f8d2b 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -450,11 +450,11 @@ void GDScriptTokenizerText::_make_error(const String &p_error) {
tk_rb_pos = (tk_rb_pos + 1) % TK_RB_SIZE;
}
-void GDScriptTokenizerText::_make_newline(int p_spaces) {
+void GDScriptTokenizerText::_make_newline(int p_indentation, int p_tabs) {
TokenData &tk = tk_rb[tk_rb_pos];
tk.type = TK_NEWLINE;
- tk.constant = p_spaces;
+ tk.constant = Vector2(p_indentation, p_tabs);
tk.line = line;
tk.col = column;
tk_rb_pos = (tk_rb_pos + 1) % TK_RB_SIZE;
@@ -511,33 +511,6 @@ void GDScriptTokenizerText::_advance() {
case ' ':
INCPOS(1);
continue;
- case '\n': {
- line++;
- INCPOS(1);
- column = 1;
- int i = 0;
- while (true) {
- if (GETCHAR(i) == ' ') {
- if (file_indent_type == INDENT_NONE) file_indent_type = INDENT_SPACES;
- if (file_indent_type != INDENT_SPACES) {
- _make_error("Spaces used for indentation in tab-indented file!");
- return;
- }
- } else if (GETCHAR(i) == '\t') {
- if (file_indent_type == INDENT_NONE) file_indent_type = INDENT_TABS;
- if (file_indent_type != INDENT_TABS) {
- _make_error("Tabs used for indentation in space-indented file!");
- return;
- }
- } else {
- break; // not indentation anymore
- }
- i++;
- }
-
- _make_newline(i);
- return;
- }
case '#': { // line comment skip
#ifdef DEBUG_ENABLED
String comment;
@@ -565,33 +538,34 @@ void GDScriptTokenizerText::_advance() {
ignore_warnings = true;
}
#endif // DEBUG_ENABLED
+ FALLTHROUGH;
+ }
+ case '\n': {
+ line++;
INCPOS(1);
+ bool used_spaces = false;
+ int tabs = 0;
column = 1;
- line++;
int i = 0;
while (true) {
if (GETCHAR(i) == ' ') {
- if (file_indent_type == INDENT_NONE) file_indent_type = INDENT_SPACES;
- if (file_indent_type != INDENT_SPACES) {
- _make_error("Spaces used for indentation in tab-indented file!");
- return;
- }
+ i++;
+ used_spaces = true;
} else if (GETCHAR(i) == '\t') {
- if (file_indent_type == INDENT_NONE) file_indent_type = INDENT_TABS;
- if (file_indent_type != INDENT_TABS) {
- _make_error("Tabs used for indentation in space-indented file!");
+ if (used_spaces) {
+ _make_error("Spaces used before tabs on a line");
return;
}
+ i++;
+ tabs++;
} else {
break; // not indentation anymore
}
- i++;
}
- _make_newline(i);
+ _make_newline(i, tabs);
return;
-
- } break;
+ }
case '/': {
switch (GETCHAR(1)) {
@@ -849,12 +823,8 @@ void GDScriptTokenizerText::_advance() {
_make_error("Unterminated String");
return;
}
- if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
- _make_error("Malformed hex constant in string");
- return;
- }
- CharType v;
+ CharType v = 0;
if (c >= '0' && c <= '9') {
v = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -864,8 +834,8 @@ void GDScriptTokenizerText::_advance() {
v = c - 'A';
v += 10;
} else {
- ERR_PRINT("BUG");
- v = 0;
+ _make_error("Malformed hex constant in string");
+ return;
}
res <<= 4;
@@ -1112,7 +1082,6 @@ void GDScriptTokenizerText::set_code(const String &p_code) {
ignore_warnings = false;
#endif // DEBUG_ENABLED
last_error = "";
- file_indent_type = INDENT_NONE;
for (int i = 0; i < MAX_LOOKAHEAD + 1; i++)
_advance();
}
@@ -1187,7 +1156,17 @@ int GDScriptTokenizerText::get_token_line_indent(int p_offset) const {
int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD - 1) % TK_RB_SIZE;
ERR_FAIL_COND_V(tk_rb[ofs].type != TK_NEWLINE, 0);
- return tk_rb[ofs].constant;
+ return tk_rb[ofs].constant.operator Vector2().x;
+}
+
+int GDScriptTokenizerText::get_token_line_tab_indent(int p_offset) const {
+
+ ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, 0);
+ ERR_FAIL_COND_V(p_offset >= MAX_LOOKAHEAD, 0);
+
+ int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD - 1) % TK_RB_SIZE;
+ ERR_FAIL_COND_V(tk_rb[ofs].type != TK_NEWLINE, 0);
+ return tk_rb[ofs].constant.operator Vector2().y;
}
String GDScriptTokenizerText::get_token_error(int p_offset) const {
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 89d586b912..58749012b7 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -168,6 +168,7 @@ public:
virtual int get_token_line(int p_offset = 0) const = 0;
virtual int get_token_column(int p_offset = 0) const = 0;
virtual int get_token_line_indent(int p_offset = 0) const = 0;
+ virtual int get_token_line_tab_indent(int p_offset = 0) const = 0;
virtual String get_token_error(int p_offset = 0) const = 0;
virtual void advance(int p_amount = 1) = 0;
#ifdef DEBUG_ENABLED
@@ -205,7 +206,7 @@ class GDScriptTokenizerText : public GDScriptTokenizer {
};
void _make_token(Token p_type);
- void _make_newline(int p_spaces = 0);
+ void _make_newline(int p_indentation = 0, int p_tabs = 0);
void _make_identifier(const StringName &p_identifier);
void _make_built_in_func(GDScriptFunctions::Function p_func);
void _make_constant(const Variant &p_constant);
@@ -222,11 +223,6 @@ class GDScriptTokenizerText : public GDScriptTokenizer {
int tk_rb_pos;
String last_error;
bool error_flag;
- enum {
- INDENT_NONE,
- INDENT_SPACES,
- INDENT_TABS,
- } file_indent_type;
#ifdef DEBUG_ENABLED
Vector<Pair<int, String> > warning_skips;
@@ -245,6 +241,7 @@ public:
virtual int get_token_line(int p_offset = 0) const;
virtual int get_token_column(int p_offset = 0) const;
virtual int get_token_line_indent(int p_offset = 0) const;
+ virtual int get_token_line_tab_indent(int p_offset = 0) const;
virtual const Variant &get_token_constant(int p_offset = 0) const;
virtual String get_token_error(int p_offset = 0) const;
virtual void advance(int p_amount = 1);
@@ -283,6 +280,7 @@ public:
virtual int get_token_line(int p_offset = 0) const;
virtual int get_token_column(int p_offset = 0) const;
virtual int get_token_line_indent(int p_offset = 0) const;
+ virtual int get_token_line_tab_indent(int p_offset = 0) const { return 0; }
virtual const Variant &get_token_constant(int p_offset = 0) const;
virtual String get_token_error(int p_offset = 0) const;
virtual void advance(int p_amount = 1);