|
@@ -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);
|