summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <rverschelde@gmail.com>2018-07-26 13:48:37 +0200
committerGitHub <noreply@github.com>2018-07-26 13:48:37 +0200
commit96d37769d90ed9aa52eb23e7672962049d31dfd8 (patch)
tree4017f5cf2e6218825465b9dbe6afa8324039624d /modules
parent0494bbc5ca2a00ea9196efbec51416ae291066ef (diff)
parent0b78e4f9e3824361e4984eedd1c57996eb48c546 (diff)
Merge pull request #20468 from vnen/typed-gds-fixes
General GDScript fixes
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/gdscript_compiler.cpp8
-rw-r--r--modules/gdscript/gdscript_function.cpp34
-rw-r--r--modules/gdscript/gdscript_functions.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.cpp116
4 files changed, 110 insertions, 50 deletions
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 93585a5342..fe393957db 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -140,7 +140,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
} break;
case GDScriptParser::DataType::CLASS: {
result.kind = GDScriptDataType::GDSCRIPT;
- if (p_datatype.class_type->name == StringName()) {
+ if (!p_datatype.class_type->owner) {
result.script_type = Ref<GDScript>(main_script);
} else {
result.script_type = class_map[p_datatype.class_type->name];
@@ -482,7 +482,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
Variant script;
int idx = -1;
- if (cn->cast_type.class_type->name == StringName()) {
+ if (!cn->cast_type.class_type->owner) {
script = codegen.script;
} else {
StringName name = cn->cast_type.class_type->name;
@@ -1181,7 +1181,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
Variant script;
int idx = -1;
- if (assign_type.class_type->name == StringName()) {
+ if (!assign_type.class_type->owner) {
script = codegen.script;
} else {
StringName name = assign_type.class_type->name;
@@ -1994,7 +1994,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
p_script->_signals[name] = p_class->_signals[i].arguments;
}
- if (p_class->name != StringName()) {
+ if (!p_class->owner) {
parsed_classes.insert(p_class->name);
}
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index ec346a6b46..bae3f48923 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -742,13 +742,22 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
+#ifdef DEBUG_ENABLED
if (src->get_type() != var_type) {
- err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
- "' to a variable of type '" + Variant::get_type_name(var_type) + "'.";
- OPCODE_BREAK;
+ if (Variant::can_convert_strict(src->get_type(), var_type)) {
+ Variant::CallError ce;
+ *dst = Variant::construct(var_type, const_cast<const Variant **>(&src), 1, ce);
+ } else {
+ err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
+ "' to a variable of type '" + Variant::get_type_name(var_type) + "'.";
+ OPCODE_BREAK;
+ }
+ } else {
+#endif // DEBUG_ENABLED
+ *dst = *src;
+#ifdef DEBUG_ENABLED
}
-
- *dst = *src;
+#endif // DEBUG_ENABLED
ip += 4;
}
@@ -761,17 +770,22 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_VARIANT_PTR(dst, 2);
GET_VARIANT_PTR(src, 3);
+#ifdef DEBUG_ENABLED
GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *());
GD_ERR_BREAK(!nc);
+ if (!src->get_type() != Variant::OBJECT && !src->get_type() != Variant::NIL) {
+ err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
+ "' to a variable of type '" + nc->get_name() + "'.";
+ OPCODE_BREAK;
+ }
Object *src_obj = src->operator Object *();
- GD_ERR_BREAK(!src_obj);
- if (!ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
+ if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
err_text = "Trying to assign value of type '" + src_obj->get_class_name() +
"' to a variable of type '" + nc->get_name() + "'.";
OPCODE_BREAK;
}
-
+#endif // DEBUG_ENABLED
*dst = *src;
ip += 4;
@@ -785,6 +799,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_VARIANT_PTR(dst, 2);
GET_VARIANT_PTR(src, 3);
+#ifdef DEBUG_ENABLED
Script *base_type = Object::cast_to<Script>(type->operator Object *());
GD_ERR_BREAK(!base_type);
@@ -820,6 +835,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE_BREAK;
}
}
+#endif // DEBUG_ENABLED
*dst = *src;
@@ -1579,7 +1595,7 @@ StringName GDScriptFunction::get_global_name(int p_idx) const {
int GDScriptFunction::get_default_argument_count() const {
- return default_arguments.size();
+ return _default_arg_count;
}
int GDScriptFunction::get_default_argument_addr(int p_idx) const {
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 63286b2e91..f2e52d48dd 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -1412,7 +1412,7 @@ bool GDScriptFunctions::is_deterministic(Function p_func) {
MethodInfo GDScriptFunctions::get_info(Function p_func) {
-#ifdef TOOLS_ENABLED
+#ifdef DEBUG_ENABLED
//using a switch, so the compiler generates a jumptable
switch (p_func) {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index d8ce6e7f17..a0e58e3a37 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3332,6 +3332,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
switch (token) {
+ case GDScriptTokenizer::TK_CURSOR: {
+ tokenizer->advance();
+ } break;
case GDScriptTokenizer::TK_EOF:
p_class->end_line = tokenizer->get_token_line();
case GDScriptTokenizer::TK_ERROR: {
@@ -3552,7 +3555,10 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
DataType argtype;
if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) {
- if (!_parse_type(argtype)) {
+ if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) {
+ argtype.infer_type = true;
+ tokenizer->advance();
+ } else if (!_parse_type(argtype)) {
_set_error("Expected type for argument.");
return;
}
@@ -4187,6 +4193,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
current_export.hint_string = native_class->get_name();
+ current_export.class_name = native_class->get_name();
} else {
current_export = PropertyInfo();
@@ -4546,6 +4553,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
member._export.type = Variant::OBJECT;
member._export.hint = PROPERTY_HINT_RESOURCE_TYPE;
member._export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
+ member._export.hint_string = member.data_type.native_type;
member._export.class_name = member.data_type.native_type;
} else {
_set_error("Invalid export type. Only built-in and native resource types can be exported.", member.line);
@@ -5433,6 +5441,9 @@ GDScriptParser::DataType GDScriptParser::_get_operation_type(const Variant::Oper
if (b_type == Variant::INT || b_type == Variant::REAL) {
Variant::evaluate(Variant::OP_ADD, b, 1, b, r_valid);
}
+ if (a_type == Variant::STRING) {
+ a = "%s"; // Work around for formatting operator (%)
+ }
Variant ret;
Variant::evaluate(p_op, a, b, ret, r_valid);
@@ -6770,7 +6781,26 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
// Check classes in current file
ClassNode *base = NULL;
if (!p_base_type) {
- // Possibly this is a global, check first
+ base = current_class;
+ base_type.has_type = true;
+ base_type.is_constant = true;
+ base_type.kind = DataType::CLASS;
+ base_type.class_type = base;
+ } else {
+ base_type = DataType(*p_base_type);
+ if (base_type.kind == DataType::CLASS) {
+ base = base_type.class_type;
+ }
+ }
+
+ DataType member_type;
+
+ if (_get_member_type(base_type, p_identifier, member_type)) {
+ return member_type;
+ }
+
+ if (!p_base_type) {
+ // Possibly this is a global, check before failing
if (ClassDB::class_exists(p_identifier) || ClassDB::class_exists("_" + p_identifier.operator String())) {
DataType result;
@@ -6796,6 +6826,9 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
result.class_type = outer_class;
return result;
}
+ if (outer_class->constant_expressions.has(p_identifier)) {
+ return outer_class->constant_expressions[p_identifier].type;
+ }
for (int i = 0; i < outer_class->subclasses.size(); i++) {
if (outer_class->subclasses[i] == current_class) {
continue;
@@ -6885,27 +6918,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
}
}
- // Nothing found, keep looking in local scope
-
- base = current_class;
- base_type.has_type = true;
- base_type.is_constant = true;
- base_type.kind = DataType::CLASS;
- base_type.class_type = base;
- } else {
- base_type = *p_base_type;
- if (base_type.kind == DataType::CLASS) {
- base = base_type.class_type;
- }
- }
-
- DataType member_type;
-
- if (_get_member_type(base_type, p_identifier, member_type)) {
- return member_type;
- }
-
- if (!p_base_type) {
// This means looking in the current class, which type is always known
_set_error("Identifier '" + p_identifier.operator String() + "' is not declared in the current scope.", p_line);
}
@@ -7131,11 +7143,9 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
// Arguments
int defaults_ofs = p_function->arguments.size() - p_function->default_values.size();
for (int i = 0; i < p_function->arguments.size(); i++) {
-
- // Resolve types
- p_function->argument_types.write[i] = _resolve_type(p_function->argument_types[i], p_function->line);
-
- if (i >= defaults_ofs) {
+ if (i < defaults_ofs) {
+ p_function->argument_types.write[i] = _resolve_type(p_function->argument_types[i], p_function->line);
+ } else {
if (p_function->default_values[i - defaults_ofs]->type != Node::TYPE_OPERATOR) {
_set_error("Parser bug: invalid argument default value.", p_function->line, p_function->column);
return;
@@ -7150,17 +7160,25 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
DataType def_type = _reduce_node_type(op->arguments[1]);
- if (!_is_type_compatible(p_function->argument_types[i], def_type, true)) {
- String arg_name = p_function->arguments[i];
- _set_error("Value type (" + def_type.to_string() + ") doesn't match the type of argument '" +
- arg_name + "' (" + p_function->arguments[i] + ")",
- p_function->line);
+ if (p_function->argument_types[i].infer_type) {
+ def_type.is_constant = false;
+ p_function->argument_types.write[i] = def_type;
+ } else {
+ p_function->return_type = _resolve_type(p_function->return_type, p_function->line);
+
+ if (!_is_type_compatible(p_function->argument_types[i], def_type, true)) {
+ String arg_name = p_function->arguments[i];
+ _set_error("Value type (" + def_type.to_string() + ") doesn't match the type of argument '" +
+ arg_name + "' (" + p_function->arguments[i] + ")",
+ p_function->line);
+ }
}
}
}
if (!(p_function->name == "_init")) {
// Signature for the initializer may vary
+#ifdef DEBUG_ENABLED
DataType return_type;
List<DataType> arg_types;
int default_arg_count = 0;
@@ -7171,18 +7189,44 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
if (_get_function_signature(base_type, p_function->name, return_type, arg_types, default_arg_count, _static, vararg)) {
bool valid = _static == p_function->_static;
valid = valid && return_type == p_function->return_type;
- valid = valid && p_function->default_values.size() >= default_arg_count;
- valid = valid && arg_types.size() == p_function->arguments.size();
+ int argsize_diff = p_function->arguments.size() - arg_types.size();
+ valid = valid && argsize_diff >= 0;
+ valid = valid && p_function->default_values.size() >= default_arg_count + argsize_diff;
int i = 0;
for (List<DataType>::Element *E = arg_types.front(); valid && E; E = E->next()) {
valid = valid && E->get() == p_function->argument_types[i++];
}
if (!valid) {
- _set_error("Function signature doesn't match the parent.", p_function->line);
+ String parent_signature = return_type.has_type ? return_type.to_string() : "Variant";
+ if (parent_signature == "null") {
+ parent_signature = "void";
+ }
+ parent_signature += " " + p_function->name + "(";
+ if (arg_types.size()) {
+ int i = 0;
+ for (List<DataType>::Element *E = arg_types.front(); E; E = E->next()) {
+ if (E != arg_types.front()) {
+ parent_signature += ", ";
+ }
+ String arg = E->get().to_string();
+ if (arg == "null" || arg == "var") {
+ arg = "Variant";
+ }
+ parent_signature += arg;
+ if (i == arg_types.size() - default_arg_count) {
+ parent_signature += "=default";
+ }
+
+ i++;
+ }
+ }
+ parent_signature += ")";
+ _set_error("Function signature doesn't match the parent. Parent signature is: '" + parent_signature + "'.", p_function->line);
return;
}
}
+#endif // DEBUG_ENABLED
} else {
if (p_function->return_type.has_type && (p_function->return_type.kind != DataType::BUILTIN || p_function->return_type.builtin_type != Variant::NIL)) {
_set_error("Constructor cannot return a value.", p_function->line);