summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/gdscript.cpp52
-rw-r--r--modules/gdscript/gdscript_function.cpp57
-rw-r--r--modules/gdscript/gdscript_parser.cpp124
3 files changed, 141 insertions, 92 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index ef86ccae14..1f5f5035f9 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -421,31 +421,40 @@ bool GDScript::_update_exports() {
base_cache = Ref<GDScript>();
}
- if (c->extends_used && String(c->extends_file) != "" && String(c->extends_file) != get_path()) {
-
- String path = c->extends_file;
- if (path.is_rel_path()) {
-
- String base = get_path();
- if (base == "" || base.is_rel_path()) {
-
- ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());
- } else {
- path = base.get_base_dir().plus_file(path);
+ if (c->extends_used) {
+ String path = "";
+ if (String(c->extends_file) != "" && String(c->extends_file) != get_path()) {
+ path = c->extends_file;
+ if (path.is_rel_path()) {
+
+ String base = get_path();
+ if (base == "" || base.is_rel_path()) {
+
+ ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());
+ } else {
+ path = base.get_base_dir().plus_file(path);
+ }
}
+ } else if (c->extends_class.size() != 0) {
+ String base = c->extends_class[0];
+
+ if (ScriptServer::is_global_class(base))
+ path = ScriptServer::get_global_class_path(base);
}
- if (path != get_path()) {
+ if (path != "") {
+ if (path != get_path()) {
- Ref<GDScript> bf = ResourceLoader::load(path);
+ Ref<GDScript> bf = ResourceLoader::load(path);
- if (bf.is_valid()) {
+ if (bf.is_valid()) {
- base_cache = bf;
- bf->inheriters_cache.insert(get_instance_id());
+ base_cache = bf;
+ bf->inheriters_cache.insert(get_instance_id());
+ }
+ } else {
+ ERR_PRINT(("Path extending itself in " + path).utf8().get_data());
}
- } else {
- ERR_PRINT(("Path extending itself in " + path).utf8().get_data());
}
}
@@ -469,8 +478,15 @@ bool GDScript::_update_exports() {
for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
E->get()->set_build_failed(true);
}
+ return false;
}
} else {
+ if (!valid) {
+ for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ E->get()->set_build_failed(true);
+ }
+ return false;
+ }
}
if (base_cache.is_valid()) {
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index 5d23c19342..cd6c21a629 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -477,56 +477,53 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_VARIANT_PTR(dst, 3);
#ifdef DEBUG_ENABLED
- if (a->get_type() != Variant::OBJECT || a->operator Object *() == NULL) {
-
- err_text = "Left operand of 'is' is not an instance of anything.";
- OPCODE_BREAK;
- }
if (b->get_type() != Variant::OBJECT || b->operator Object *() == NULL) {
err_text = "Right operand of 'is' is not a class.";
OPCODE_BREAK;
}
#endif
- Object *obj_A = *a;
- Object *obj_B = *b;
-
- GDScript *scr_B = Object::cast_to<GDScript>(obj_B);
bool extends_ok = false;
+ if (a->get_type() == Variant::OBJECT && a->operator Object *() != NULL) {
+ Object *obj_A = *a;
+ Object *obj_B = *b;
- if (scr_B) {
- //if B is a script, the only valid condition is that A has an instance which inherits from the script
- //in other situation, this shoul return false.
+ GDScript *scr_B = Object::cast_to<GDScript>(obj_B);
- if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {
+ if (scr_B) {
+ //if B is a script, the only valid condition is that A has an instance which inherits from the script
+ //in other situation, this shoul return false.
- GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
- //bool found=false;
- while (cmp) {
+ if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language() == GDScriptLanguage::get_singleton()) {
- if (cmp == scr_B) {
- //inherits from script, all ok
- extends_ok = true;
- break;
- }
+ GDScript *cmp = static_cast<GDScript *>(obj_A->get_script_instance()->get_script().ptr());
+ //bool found=false;
+ while (cmp) {
- cmp = cmp->_base;
+ if (cmp == scr_B) {
+ //inherits from script, all ok
+ extends_ok = true;
+ break;
+ }
+
+ cmp = cmp->_base;
+ }
}
- }
- } else {
+ } else {
- GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(obj_B);
+ GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(obj_B);
#ifdef DEBUG_ENABLED
- if (!nc) {
+ if (!nc) {
- err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "').";
- OPCODE_BREAK;
- }
+ err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "').";
+ OPCODE_BREAK;
+ }
#endif
- extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
+ extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
+ }
}
*dst = extends_ok;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 1d26700fa0..0926c1a1ab 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3752,6 +3752,19 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
BlockNode *block = alloc_node<BlockNode>();
block->parent_class = p_class;
+ FunctionNode *function = alloc_node<FunctionNode>();
+ function->name = name;
+ function->arguments = arguments;
+ function->argument_types = argument_types;
+ function->default_values = default_values;
+ function->_static = _static;
+ function->line = fnline;
+#ifdef DEBUG_ENABLED
+ function->arguments_usage = arguments_usage;
+#endif // DEBUG_ENABLED
+ function->rpc_mode = rpc_mode;
+ rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
+
if (name == "_init") {
if (_static) {
@@ -3782,7 +3795,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
parenthesis++;
while (true) {
+ current_function = function;
Node *arg = _parse_and_reduce_expression(p_class, _static);
+ current_function = NULL;
cparent->arguments.push_back(arg);
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
@@ -3826,19 +3841,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- FunctionNode *function = alloc_node<FunctionNode>();
- function->name = name;
function->return_type = return_type;
- function->arguments = arguments;
- function->argument_types = argument_types;
- function->default_values = default_values;
- function->_static = _static;
- function->line = fnline;
-#ifdef DEBUG_ENABLED
- function->arguments_usage = arguments_usage;
-#endif // DEBUG_ENABLED
- function->rpc_mode = rpc_mode;
- rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
if (_static)
p_class->static_functions.push_back(function);
@@ -4840,6 +4843,21 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
tokenizer->advance();
if (tokenizer->is_token_literal(0, true)) {
enum_name = tokenizer->get_token_literal();
+
+ if (current_class->constant_expressions.has(enum_name)) {
+ _set_error("A constant named '" + String(enum_name) + "' already exists in this class (at line: " +
+ itos(current_class->constant_expressions[enum_name].expression->line) + ").");
+ return;
+ }
+
+ for (int i = 0; i < current_class->variables.size(); i++) {
+ if (current_class->variables[i].identifier == enum_name) {
+ _set_error("A variable named '" + String(enum_name) + "' already exists in this class (at line: " +
+ itos(current_class->variables[i].line) + ").");
+ return;
+ }
+ }
+
tokenizer->advance();
}
if (tokenizer->get_token() != GDScriptTokenizer::TK_CURLY_BRACKET_OPEN) {
@@ -4866,26 +4884,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
} else { // tokenizer->is_token_literal(0, true)
- ClassNode::Constant constant;
-
StringName const_id = tokenizer->get_token_literal();
- if (current_class->constant_expressions.has(const_id)) {
- _set_error("A constant named '" + String(const_id) + "' already exists in this class (at line: " +
- itos(current_class->constant_expressions[const_id].expression->line) + ").");
- return;
- }
-
- for (int i = 0; i < current_class->variables.size(); i++) {
- if (current_class->variables[i].identifier == const_id) {
- _set_error("A variable named '" + String(const_id) + "' already exists in this class (at line: " +
- itos(current_class->variables[i].line) + ").");
- return;
- }
- }
-
tokenizer->advance();
+ ConstantNode *enum_value_expr;
+
if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) {
tokenizer->advance();
@@ -4902,23 +4906,20 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- ConstantNode *subexpr_const = static_cast<ConstantNode *>(subexpr);
+ enum_value_expr = static_cast<ConstantNode *>(subexpr);
- if (subexpr_const->value.get_type() != Variant::INT) {
+ if (enum_value_expr->value.get_type() != Variant::INT) {
_set_error("Expected an int value for enum");
return;
}
- last_assign = subexpr_const->value;
-
- constant.expression = subexpr_const;
+ last_assign = enum_value_expr->value;
} else {
last_assign = last_assign + 1;
- ConstantNode *cn = alloc_node<ConstantNode>();
- cn->value = last_assign;
- cn->datatype = _type_from_variant(cn->value);
- constant.expression = cn;
+ enum_value_expr = alloc_node<ConstantNode>();
+ enum_value_expr->value = last_assign;
+ enum_value_expr->datatype = _type_from_variant(enum_value_expr->value);
}
if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
@@ -4926,14 +4927,29 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
if (enum_name != "") {
- const ConstantNode *cn = static_cast<const ConstantNode *>(constant.expression);
- enum_dict[const_id] = cn->value;
- }
+ enum_dict[const_id] = enum_value_expr->value;
+ } else {
+ if (current_class->constant_expressions.has(const_id)) {
+ _set_error("A constant named '" + String(const_id) + "' already exists in this class (at line: " +
+ itos(current_class->constant_expressions[const_id].expression->line) + ").");
+ return;
+ }
+
+ for (int i = 0; i < current_class->variables.size(); i++) {
+ if (current_class->variables[i].identifier == const_id) {
+ _set_error("A variable named '" + String(const_id) + "' already exists in this class (at line: " +
+ itos(current_class->variables[i].line) + ").");
+ return;
+ }
+ }
- constant.type.has_type = true;
- constant.type.kind = DataType::BUILTIN;
- constant.type.builtin_type = Variant::INT;
- p_class->constant_expressions.insert(const_id, constant);
+ ClassNode::Constant constant;
+ constant.type.has_type = true;
+ constant.type.kind = DataType::BUILTIN;
+ constant.type.builtin_type = Variant::INT;
+ constant.expression = enum_value_expr;
+ p_class->constant_expressions.insert(const_id, constant);
+ }
}
}
@@ -6419,6 +6435,10 @@ bool GDScriptParser::_get_function_signature(DataType &p_base_type, const String
StringName native;
if (p_base_type.kind == DataType::GDSCRIPT) {
base_gdscript = p_base_type.script_type;
+ if (base_gdscript.is_null() || !base_gdscript->is_valid()) {
+ // GDScript wasn't properly compíled, don't bother trying
+ return false;
+ }
} else if (p_base_type.kind == DataType::SCRIPT) {
base_script = p_base_type.script_type;
} else if (p_base_type.kind == DataType::NATIVE) {
@@ -6459,6 +6479,12 @@ bool GDScriptParser::_get_function_signature(DataType &p_base_type, const String
base_script = base_script->get_base_script();
}
+ if (native == StringName()) {
+ // Empty native class, might happen in some Script implementations
+ // Just ignore it
+ return false;
+ }
+
#ifdef DEBUG_METHODS_ENABLED
// Only native remains
@@ -6901,6 +6927,10 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
Ref<GDScript> gds;
if (base_type.kind == DataType::GDSCRIPT) {
gds = base_type.script_type;
+ if (gds.is_null() || !gds->is_valid()) {
+ // GDScript wasn't properly compíled, don't bother trying
+ return false;
+ }
}
Ref<Script> scr;
@@ -6963,6 +6993,12 @@ bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringN
scr = scr->get_base_script();
}
+ if (native == StringName()) {
+ // Empty native class, might happen in some Script implementations
+ // Just ignore it
+ return false;
+ }
+
// Check ClassDB
if (!ClassDB::class_exists(native)) {
native = "_" + native.operator String();