GDScript: Fix some lambda bugs
This commit is contained in:
parent
3ed4497113
commit
b1eb737719
|
@ -21,13 +21,3 @@ indent_size = 4
|
||||||
[*.{yml,yaml}]
|
[*.{yml,yaml}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
# GDScript unit test files
|
|
||||||
[*.gd]
|
|
||||||
indent_style = tab
|
|
||||||
indent_size = 4
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.out]
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
[*.gd]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.out]
|
||||||
|
insert_final_newline = true
|
|
@ -84,7 +84,7 @@ void GDScriptCompiler::_set_error(const String &p_error, const GDScriptParser::N
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner) {
|
GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner, bool p_handle_metatype) {
|
||||||
if (!p_datatype.is_set() || !p_datatype.is_hard_type() || p_datatype.is_coroutine) {
|
if (!p_datatype.is_set() || !p_datatype.is_hard_type() || p_datatype.is_coroutine) {
|
||||||
return GDScriptDataType();
|
return GDScriptDataType();
|
||||||
}
|
}
|
||||||
|
@ -101,11 +101,25 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
|
||||||
result.builtin_type = p_datatype.builtin_type;
|
result.builtin_type = p_datatype.builtin_type;
|
||||||
} break;
|
} break;
|
||||||
case GDScriptParser::DataType::NATIVE: {
|
case GDScriptParser::DataType::NATIVE: {
|
||||||
|
if (p_handle_metatype && p_datatype.is_meta_type) {
|
||||||
|
result.kind = GDScriptDataType::NATIVE;
|
||||||
|
result.builtin_type = Variant::OBJECT;
|
||||||
|
result.native_type = GDScriptNativeClass::get_class_static();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
result.kind = GDScriptDataType::NATIVE;
|
result.kind = GDScriptDataType::NATIVE;
|
||||||
result.native_type = p_datatype.native_type;
|
result.native_type = p_datatype.native_type;
|
||||||
result.builtin_type = p_datatype.builtin_type;
|
result.builtin_type = p_datatype.builtin_type;
|
||||||
} break;
|
} break;
|
||||||
case GDScriptParser::DataType::SCRIPT: {
|
case GDScriptParser::DataType::SCRIPT: {
|
||||||
|
if (p_handle_metatype && p_datatype.is_meta_type) {
|
||||||
|
result.kind = GDScriptDataType::NATIVE;
|
||||||
|
result.builtin_type = Variant::OBJECT;
|
||||||
|
result.native_type = p_datatype.script_type.is_valid() ? p_datatype.script_type->get_class() : Script::get_class_static();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
result.kind = GDScriptDataType::SCRIPT;
|
result.kind = GDScriptDataType::SCRIPT;
|
||||||
result.builtin_type = p_datatype.builtin_type;
|
result.builtin_type = p_datatype.builtin_type;
|
||||||
result.script_type_ref = p_datatype.script_type;
|
result.script_type_ref = p_datatype.script_type;
|
||||||
|
@ -113,6 +127,13 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
|
||||||
result.native_type = p_datatype.native_type;
|
result.native_type = p_datatype.native_type;
|
||||||
} break;
|
} break;
|
||||||
case GDScriptParser::DataType::CLASS: {
|
case GDScriptParser::DataType::CLASS: {
|
||||||
|
if (p_handle_metatype && p_datatype.is_meta_type) {
|
||||||
|
result.kind = GDScriptDataType::NATIVE;
|
||||||
|
result.builtin_type = Variant::OBJECT;
|
||||||
|
result.native_type = GDScript::get_class_static();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
result.kind = GDScriptDataType::GDSCRIPT;
|
result.kind = GDScriptDataType::GDSCRIPT;
|
||||||
result.builtin_type = p_datatype.builtin_type;
|
result.builtin_type = p_datatype.builtin_type;
|
||||||
result.native_type = p_datatype.native_type;
|
result.native_type = p_datatype.native_type;
|
||||||
|
@ -148,6 +169,12 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case GDScriptParser::DataType::ENUM:
|
case GDScriptParser::DataType::ENUM:
|
||||||
|
if (p_handle_metatype && p_datatype.is_meta_type) {
|
||||||
|
result.kind = GDScriptDataType::BUILTIN;
|
||||||
|
result.builtin_type = Variant::DICTIONARY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
result.kind = GDScriptDataType::BUILTIN;
|
result.kind = GDScriptDataType::BUILTIN;
|
||||||
result.builtin_type = p_datatype.builtin_type;
|
result.builtin_type = p_datatype.builtin_type;
|
||||||
break;
|
break;
|
||||||
|
@ -159,7 +186,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_datatype.has_container_element_type()) {
|
if (p_datatype.has_container_element_type()) {
|
||||||
result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type(), p_owner));
|
result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type(), p_owner, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -533,7 +560,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
||||||
} break;
|
} break;
|
||||||
case GDScriptParser::Node::CAST: {
|
case GDScriptParser::Node::CAST: {
|
||||||
const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression);
|
const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression);
|
||||||
GDScriptDataType cast_type = _gdtype_from_datatype(cn->get_datatype(), codegen.script);
|
GDScriptDataType cast_type = _gdtype_from_datatype(cn->get_datatype(), codegen.script, false);
|
||||||
|
|
||||||
GDScriptCodeGenerator::Address result;
|
GDScriptCodeGenerator::Address result;
|
||||||
if (cast_type.has_type) {
|
if (cast_type.has_type) {
|
||||||
|
@ -911,7 +938,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
||||||
GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(type_test->get_datatype(), codegen.script));
|
GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(type_test->get_datatype(), codegen.script));
|
||||||
|
|
||||||
GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, type_test->operand);
|
GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, type_test->operand);
|
||||||
GDScriptDataType test_type = _gdtype_from_datatype(type_test->test_datatype, codegen.script);
|
GDScriptDataType test_type = _gdtype_from_datatype(type_test->test_datatype, codegen.script, false);
|
||||||
if (r_error) {
|
if (r_error) {
|
||||||
return GDScriptCodeGenerator::Address();
|
return GDScriptCodeGenerator::Address();
|
||||||
}
|
}
|
||||||
|
@ -2587,7 +2614,7 @@ Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type, p_script);
|
GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type, p_script, false);
|
||||||
|
|
||||||
int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type];
|
int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type];
|
||||||
p_script->native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
|
p_script->native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
|
||||||
|
|
|
@ -124,7 +124,7 @@ class GDScriptCompiler {
|
||||||
Error _create_binary_operator(CodeGen &codegen, const GDScriptParser::BinaryOpNode *on, Variant::Operator op, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
|
Error _create_binary_operator(CodeGen &codegen, const GDScriptParser::BinaryOpNode *on, Variant::Operator op, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
|
||||||
Error _create_binary_operator(CodeGen &codegen, const GDScriptParser::ExpressionNode *p_left_operand, const GDScriptParser::ExpressionNode *p_right_operand, Variant::Operator op, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
|
Error _create_binary_operator(CodeGen &codegen, const GDScriptParser::ExpressionNode *p_left_operand, const GDScriptParser::ExpressionNode *p_right_operand, Variant::Operator op, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
|
||||||
|
|
||||||
GDScriptDataType _gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner);
|
GDScriptDataType _gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner, bool p_handle_metatype = true);
|
||||||
|
|
||||||
GDScriptCodeGenerator::Address _parse_assign_right_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::AssignmentNode *p_assignmentint, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
|
GDScriptCodeGenerator::Address _parse_assign_right_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::AssignmentNode *p_assignmentint, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
|
||||||
GDScriptCodeGenerator::Address _parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root = false, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
|
GDScriptCodeGenerator::Address _parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root = false, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
|
||||||
|
|
|
@ -79,13 +79,48 @@ void GDScriptLambdaCallable::call(const Variant **p_arguments, int p_argcount, V
|
||||||
args.resize(p_argcount + captures_amount);
|
args.resize(p_argcount + captures_amount);
|
||||||
for (int i = 0; i < captures_amount; i++) {
|
for (int i = 0; i < captures_amount; i++) {
|
||||||
args.write[i] = &captures[i];
|
args.write[i] = &captures[i];
|
||||||
|
if (captures[i].get_type() == Variant::OBJECT) {
|
||||||
|
bool was_freed = false;
|
||||||
|
captures[i].get_validated_object_with_check(was_freed);
|
||||||
|
if (was_freed) {
|
||||||
|
ERR_PRINT(vformat(R"(Lambda capture at index %d was freed. Passed "null" instead.)", i));
|
||||||
|
static Variant nil;
|
||||||
|
args.write[i] = &nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < p_argcount; i++) {
|
for (int i = 0; i < p_argcount; i++) {
|
||||||
args.write[i + captures_amount] = p_arguments[i];
|
args.write[i + captures_amount] = p_arguments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
r_return_value = function->call(nullptr, args.ptrw(), args.size(), r_call_error);
|
r_return_value = function->call(nullptr, args.ptrw(), args.size(), r_call_error);
|
||||||
r_call_error.argument -= captures_amount;
|
switch (r_call_error.error) {
|
||||||
|
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
|
||||||
|
r_call_error.argument -= captures_amount;
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (r_call_error.argument < 0) {
|
||||||
|
ERR_PRINT(vformat("GDScript bug (please report): Invalid value of lambda capture at index %d.", captures_amount + r_call_error.argument));
|
||||||
|
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // TODO: Add a more suitable error code.
|
||||||
|
r_call_error.argument = 0;
|
||||||
|
r_call_error.expected = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
|
||||||
|
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
|
||||||
|
r_call_error.expected -= captures_amount;
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (r_call_error.expected < 0) {
|
||||||
|
ERR_PRINT("GDScript bug (please report): Invalid lambda captures count.");
|
||||||
|
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // TODO: Add a more suitable error code.
|
||||||
|
r_call_error.argument = 0;
|
||||||
|
r_call_error.expected = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
r_return_value = function->call(nullptr, p_arguments, p_argcount, r_call_error);
|
r_return_value = function->call(nullptr, p_arguments, p_argcount, r_call_error);
|
||||||
}
|
}
|
||||||
|
@ -148,13 +183,48 @@ void GDScriptLambdaSelfCallable::call(const Variant **p_arguments, int p_argcoun
|
||||||
args.resize(p_argcount + captures_amount);
|
args.resize(p_argcount + captures_amount);
|
||||||
for (int i = 0; i < captures_amount; i++) {
|
for (int i = 0; i < captures_amount; i++) {
|
||||||
args.write[i] = &captures[i];
|
args.write[i] = &captures[i];
|
||||||
|
if (captures[i].get_type() == Variant::OBJECT) {
|
||||||
|
bool was_freed = false;
|
||||||
|
captures[i].get_validated_object_with_check(was_freed);
|
||||||
|
if (was_freed) {
|
||||||
|
ERR_PRINT(vformat(R"(Lambda capture at index %d was freed. Passed "null" instead.)", i));
|
||||||
|
static Variant nil;
|
||||||
|
args.write[i] = &nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < p_argcount; i++) {
|
for (int i = 0; i < p_argcount; i++) {
|
||||||
args.write[i + captures_amount] = p_arguments[i];
|
args.write[i + captures_amount] = p_arguments[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), args.ptrw(), args.size(), r_call_error);
|
r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), args.ptrw(), args.size(), r_call_error);
|
||||||
r_call_error.argument -= captures_amount;
|
switch (r_call_error.error) {
|
||||||
|
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
|
||||||
|
r_call_error.argument -= captures_amount;
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (r_call_error.argument < 0) {
|
||||||
|
ERR_PRINT(vformat("GDScript bug (please report): Invalid value of lambda capture at index %d.", captures_amount + r_call_error.argument));
|
||||||
|
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // TODO: Add a more suitable error code.
|
||||||
|
r_call_error.argument = 0;
|
||||||
|
r_call_error.expected = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
|
||||||
|
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
|
||||||
|
r_call_error.expected -= captures_amount;
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (r_call_error.expected < 0) {
|
||||||
|
ERR_PRINT("GDScript bug (please report): Invalid lambda captures count.");
|
||||||
|
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // TODO: Add a more suitable error code.
|
||||||
|
r_call_error.argument = 0;
|
||||||
|
r_call_error.expected = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), p_arguments, p_argcount, r_call_error);
|
r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), p_arguments, p_argcount, r_call_error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
|
||||||
|
|
||||||
if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
|
if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
|
||||||
int errorarg = p_err.argument;
|
int errorarg = p_err.argument;
|
||||||
|
ERR_FAIL_COND_V_MSG(errorarg < 0 || argptrs[errorarg] == nullptr, "GDScript bug (please report): Invalid CallError argument index or null pointer.", "Invalid CallError argument index or null pointer.");
|
||||||
// Handle the Object to Object case separately as we don't have further class details.
|
// Handle the Object to Object case separately as we don't have further class details.
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
if (p_err.expected == Variant::OBJECT && argptrs[errorarg]->get_type() == p_err.expected) {
|
if (p_err.expected == Variant::OBJECT && argptrs[errorarg]->get_type() == p_err.expected) {
|
||||||
|
@ -128,9 +129,9 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
|
||||||
err_text = "Invalid type in " + p_where + ". Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(p_err.expected)) + ".";
|
err_text = "Invalid type in " + p_where + ". Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(p_err.expected)) + ".";
|
||||||
}
|
}
|
||||||
} else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
|
} else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
|
||||||
err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
|
err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.expected) + " arguments.";
|
||||||
} else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
|
} else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
|
||||||
err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
|
err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.expected) + " arguments.";
|
||||||
} else if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
|
} else if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
|
||||||
err_text = "Invalid call. Nonexistent " + p_where + ".";
|
err_text = "Invalid call. Nonexistent " + p_where + ".";
|
||||||
} else if (p_err.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
|
} else if (p_err.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
|
||||||
|
@ -511,13 +512,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
||||||
if (p_argcount != _argument_count) {
|
if (p_argcount != _argument_count) {
|
||||||
if (p_argcount > _argument_count) {
|
if (p_argcount > _argument_count) {
|
||||||
r_err.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
r_err.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
|
||||||
r_err.argument = _argument_count;
|
r_err.expected = _argument_count;
|
||||||
|
|
||||||
call_depth--;
|
call_depth--;
|
||||||
return _get_default_variant_for_data_type(return_type);
|
return _get_default_variant_for_data_type(return_type);
|
||||||
} else if (p_argcount < _argument_count - _default_arg_count) {
|
} else if (p_argcount < _argument_count - _default_arg_count) {
|
||||||
r_err.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
r_err.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||||
r_err.argument = _argument_count - _default_arg_count;
|
r_err.expected = _argument_count - _default_arg_count;
|
||||||
call_depth--;
|
call_depth--;
|
||||||
return _get_default_variant_for_data_type(return_type);
|
return _get_default_variant_for_data_type(return_type);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -5,6 +5,8 @@ class MyClass:
|
||||||
|
|
||||||
enum MyEnum {}
|
enum MyEnum {}
|
||||||
|
|
||||||
|
const Utils = preload("../../utils.notest.gd")
|
||||||
|
|
||||||
static var test_static_var_untyped
|
static var test_static_var_untyped
|
||||||
static var test_static_var_weak_null = null
|
static var test_static_var_weak_null = null
|
||||||
static var test_static_var_weak_int = 1
|
static var test_static_var_weak_int = 1
|
||||||
|
@ -58,68 +60,13 @@ func test():
|
||||||
var script: Script = get_script()
|
var script: Script = get_script()
|
||||||
for property in script.get_property_list():
|
for property in script.get_property_list():
|
||||||
if str(property.name).begins_with("test_"):
|
if str(property.name).begins_with("test_"):
|
||||||
if not (property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE):
|
print(Utils.get_property_signature(property, true))
|
||||||
print("Error: Missing `PROPERTY_USAGE_SCRIPT_VARIABLE` flag.")
|
|
||||||
print("static var ", property.name, ": ", get_type(property))
|
|
||||||
for property in get_property_list():
|
for property in get_property_list():
|
||||||
if str(property.name).begins_with("test_"):
|
if str(property.name).begins_with("test_"):
|
||||||
if not (property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE):
|
print(Utils.get_property_signature(property))
|
||||||
print("Error: Missing `PROPERTY_USAGE_SCRIPT_VARIABLE` flag.")
|
|
||||||
print("var ", property.name, ": ", get_type(property))
|
|
||||||
for method in get_method_list():
|
for method in get_method_list():
|
||||||
if str(method.name).begins_with("test_"):
|
if str(method.name).begins_with("test_"):
|
||||||
print(get_signature(method))
|
print(Utils.get_method_signature(method))
|
||||||
for method in get_signal_list():
|
for method in get_signal_list():
|
||||||
if str(method.name).begins_with("test_"):
|
if str(method.name).begins_with("test_"):
|
||||||
print(get_signature(method, true))
|
print(Utils.get_method_signature(method, true))
|
||||||
|
|
||||||
func get_type(property: Dictionary, is_return: bool = false) -> String:
|
|
||||||
match property.type:
|
|
||||||
TYPE_NIL:
|
|
||||||
if property.usage & PROPERTY_USAGE_NIL_IS_VARIANT:
|
|
||||||
return "Variant"
|
|
||||||
return "void" if is_return else "null"
|
|
||||||
TYPE_BOOL:
|
|
||||||
return "bool"
|
|
||||||
TYPE_INT:
|
|
||||||
if property.usage & PROPERTY_USAGE_CLASS_IS_ENUM:
|
|
||||||
return property.class_name
|
|
||||||
return "int"
|
|
||||||
TYPE_STRING:
|
|
||||||
return "String"
|
|
||||||
TYPE_DICTIONARY:
|
|
||||||
return "Dictionary"
|
|
||||||
TYPE_ARRAY:
|
|
||||||
if property.hint == PROPERTY_HINT_ARRAY_TYPE:
|
|
||||||
return "Array[%s]" % property.hint_string
|
|
||||||
return "Array"
|
|
||||||
TYPE_OBJECT:
|
|
||||||
if not str(property.class_name).is_empty():
|
|
||||||
return property.class_name
|
|
||||||
return "Object"
|
|
||||||
return "<error>"
|
|
||||||
|
|
||||||
func get_signature(method: Dictionary, is_signal: bool = false) -> String:
|
|
||||||
var result: String = ""
|
|
||||||
if method.flags & METHOD_FLAG_STATIC:
|
|
||||||
result += "static "
|
|
||||||
result += ("signal " if is_signal else "func ") + method.name + "("
|
|
||||||
|
|
||||||
var args: Array[Dictionary] = method.args
|
|
||||||
var default_args: Array = method.default_args
|
|
||||||
var mandatory_argc: int = args.size() - default_args.size()
|
|
||||||
for i in args.size():
|
|
||||||
if i > 0:
|
|
||||||
result += ", "
|
|
||||||
var arg: Dictionary = args[i]
|
|
||||||
result += arg.name + ": " + get_type(arg)
|
|
||||||
if i >= mandatory_argc:
|
|
||||||
result += " = " + var_to_str(default_args[i - mandatory_argc])
|
|
||||||
|
|
||||||
result += ")"
|
|
||||||
if is_signal:
|
|
||||||
if get_type(method.return, true) != "void":
|
|
||||||
print("Error: Signal return type must be `void`.")
|
|
||||||
else:
|
|
||||||
result += " -> " + get_type(method.return, true)
|
|
||||||
return result
|
|
||||||
|
|
|
@ -6,13 +6,13 @@ static var test_static_var_hard_int: int
|
||||||
var test_var_untyped: Variant
|
var test_var_untyped: Variant
|
||||||
var test_var_weak_null: Variant
|
var test_var_weak_null: Variant
|
||||||
var test_var_weak_int: Variant
|
var test_var_weak_int: Variant
|
||||||
var test_var_weak_int_exported: int
|
@export var test_var_weak_int_exported: int
|
||||||
var test_var_weak_variant_type: Variant
|
var test_var_weak_variant_type: Variant
|
||||||
var test_var_weak_variant_type_exported: Variant.Type
|
@export var test_var_weak_variant_type_exported: Variant.Type
|
||||||
var test_var_hard_variant: Variant
|
var test_var_hard_variant: Variant
|
||||||
var test_var_hard_int: int
|
var test_var_hard_int: int
|
||||||
var test_var_hard_variant_type: Variant.Type
|
var test_var_hard_variant_type: Variant.Type
|
||||||
var test_var_hard_variant_type_exported: Variant.Type
|
@export var test_var_hard_variant_type_exported: Variant.Type
|
||||||
var test_var_hard_node_process_mode: Node.ProcessMode
|
var test_var_hard_node_process_mode: Node.ProcessMode
|
||||||
var test_var_hard_my_enum: TestMemberInfo.MyEnum
|
var test_var_hard_my_enum: TestMemberInfo.MyEnum
|
||||||
var test_var_hard_array: Array
|
var test_var_hard_array: Array
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
class MyClass:
|
||||||
|
const TEST = 10
|
||||||
|
|
||||||
|
enum MyEnum {A, B, C}
|
||||||
|
|
||||||
|
const Utils = preload("../../utils.notest.gd")
|
||||||
|
const Other = preload("./metatypes.notest.gd")
|
||||||
|
|
||||||
|
var test_native := JSON
|
||||||
|
var test_script := Other
|
||||||
|
var test_class := MyClass
|
||||||
|
var test_enum := MyEnum
|
||||||
|
|
||||||
|
func check_gdscript_native_class(value: Variant) -> void:
|
||||||
|
print(var_to_str(value).get_slice(",", 0).trim_prefix("Object("))
|
||||||
|
|
||||||
|
func check_gdscript(value: GDScript) -> void:
|
||||||
|
print(value.get_class())
|
||||||
|
|
||||||
|
func check_enum(value: Dictionary) -> void:
|
||||||
|
print(value)
|
||||||
|
|
||||||
|
func test():
|
||||||
|
for property in get_property_list():
|
||||||
|
if str(property.name).begins_with("test_"):
|
||||||
|
print(Utils.get_property_signature(property))
|
||||||
|
|
||||||
|
check_gdscript_native_class(test_native)
|
||||||
|
check_gdscript(test_script)
|
||||||
|
check_gdscript(test_class)
|
||||||
|
check_enum(test_enum)
|
||||||
|
|
||||||
|
print(test_native.stringify([]))
|
||||||
|
print(test_script.TEST)
|
||||||
|
print(test_class.TEST)
|
||||||
|
print(test_enum.keys())
|
|
@ -0,0 +1 @@
|
||||||
|
const TEST = 100
|
|
@ -0,0 +1,13 @@
|
||||||
|
GDTEST_OK
|
||||||
|
var test_native: GDScriptNativeClass
|
||||||
|
var test_script: GDScript
|
||||||
|
var test_class: GDScript
|
||||||
|
var test_enum: Dictionary
|
||||||
|
GDScriptNativeClass
|
||||||
|
GDScript
|
||||||
|
GDScript
|
||||||
|
{ "A": 0, "B": 1, "C": 2 }
|
||||||
|
[]
|
||||||
|
100
|
||||||
|
10
|
||||||
|
["A", "B", "C"]
|
|
@ -0,0 +1,137 @@
|
||||||
|
static func get_type(property: Dictionary, is_return: bool = false) -> String:
|
||||||
|
match property.type:
|
||||||
|
TYPE_NIL:
|
||||||
|
if property.usage & PROPERTY_USAGE_NIL_IS_VARIANT:
|
||||||
|
return "Variant"
|
||||||
|
return "void" if is_return else "null"
|
||||||
|
TYPE_INT:
|
||||||
|
if property.usage & PROPERTY_USAGE_CLASS_IS_ENUM:
|
||||||
|
if property.class_name == &"":
|
||||||
|
return "<unknown enum>"
|
||||||
|
return property.class_name
|
||||||
|
TYPE_ARRAY:
|
||||||
|
if property.hint == PROPERTY_HINT_ARRAY_TYPE:
|
||||||
|
if str(property.hint_string).is_empty():
|
||||||
|
return "Array[<unknown type>]"
|
||||||
|
return "Array[%s]" % property.hint_string
|
||||||
|
TYPE_OBJECT:
|
||||||
|
if not str(property.class_name).is_empty():
|
||||||
|
return property.class_name
|
||||||
|
return variant_get_type_name(property.type)
|
||||||
|
|
||||||
|
static func get_property_signature(property: Dictionary, is_static: bool = false) -> String:
|
||||||
|
var result: String = ""
|
||||||
|
if not (property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE):
|
||||||
|
printerr("Missing `PROPERTY_USAGE_SCRIPT_VARIABLE` flag.")
|
||||||
|
if property.usage & PROPERTY_USAGE_DEFAULT:
|
||||||
|
result += "@export "
|
||||||
|
if is_static:
|
||||||
|
result += "static "
|
||||||
|
result += "var " + property.name + ": " + get_type(property)
|
||||||
|
return result
|
||||||
|
|
||||||
|
static func get_method_signature(method: Dictionary, is_signal: bool = false) -> String:
|
||||||
|
var result: String = ""
|
||||||
|
if method.flags & METHOD_FLAG_STATIC:
|
||||||
|
result += "static "
|
||||||
|
result += ("signal " if is_signal else "func ") + method.name + "("
|
||||||
|
|
||||||
|
var args: Array[Dictionary] = method.args
|
||||||
|
var default_args: Array = method.default_args
|
||||||
|
var mandatory_argc: int = args.size() - default_args.size()
|
||||||
|
for i in args.size():
|
||||||
|
if i > 0:
|
||||||
|
result += ", "
|
||||||
|
var arg: Dictionary = args[i]
|
||||||
|
result += arg.name + ": " + get_type(arg)
|
||||||
|
if i >= mandatory_argc:
|
||||||
|
result += " = " + var_to_str(default_args[i - mandatory_argc])
|
||||||
|
|
||||||
|
result += ")"
|
||||||
|
if is_signal:
|
||||||
|
if get_type(method.return, true) != "void":
|
||||||
|
printerr("Signal return type must be `void`.")
|
||||||
|
else:
|
||||||
|
result += " -> " + get_type(method.return, true)
|
||||||
|
return result
|
||||||
|
|
||||||
|
static func variant_get_type_name(type: Variant.Type) -> String:
|
||||||
|
match type:
|
||||||
|
TYPE_NIL:
|
||||||
|
return "Nil" # `Nil` in core, `null` in GDScript.
|
||||||
|
TYPE_BOOL:
|
||||||
|
return "bool"
|
||||||
|
TYPE_INT:
|
||||||
|
return "int"
|
||||||
|
TYPE_FLOAT:
|
||||||
|
return "float"
|
||||||
|
TYPE_STRING:
|
||||||
|
return "String"
|
||||||
|
TYPE_VECTOR2:
|
||||||
|
return "Vector2"
|
||||||
|
TYPE_VECTOR2I:
|
||||||
|
return "Vector2i"
|
||||||
|
TYPE_RECT2:
|
||||||
|
return "Rect2"
|
||||||
|
TYPE_RECT2I:
|
||||||
|
return "Rect2i"
|
||||||
|
TYPE_VECTOR3:
|
||||||
|
return "Vector3"
|
||||||
|
TYPE_VECTOR3I:
|
||||||
|
return "Vector3i"
|
||||||
|
TYPE_TRANSFORM2D:
|
||||||
|
return "Transform2D"
|
||||||
|
TYPE_VECTOR4:
|
||||||
|
return "Vector4"
|
||||||
|
TYPE_VECTOR4I:
|
||||||
|
return "Vector4i"
|
||||||
|
TYPE_PLANE:
|
||||||
|
return "Plane"
|
||||||
|
TYPE_QUATERNION:
|
||||||
|
return "Quaternion"
|
||||||
|
TYPE_AABB:
|
||||||
|
return "AABB"
|
||||||
|
TYPE_BASIS:
|
||||||
|
return "Basis"
|
||||||
|
TYPE_TRANSFORM3D:
|
||||||
|
return "Transform3D"
|
||||||
|
TYPE_PROJECTION:
|
||||||
|
return "Projection"
|
||||||
|
TYPE_COLOR:
|
||||||
|
return "Color"
|
||||||
|
TYPE_STRING_NAME:
|
||||||
|
return "StringName"
|
||||||
|
TYPE_NODE_PATH:
|
||||||
|
return "NodePath"
|
||||||
|
TYPE_RID:
|
||||||
|
return "RID"
|
||||||
|
TYPE_OBJECT:
|
||||||
|
return "Object"
|
||||||
|
TYPE_CALLABLE:
|
||||||
|
return "Callable"
|
||||||
|
TYPE_SIGNAL:
|
||||||
|
return "Signal"
|
||||||
|
TYPE_DICTIONARY:
|
||||||
|
return "Dictionary"
|
||||||
|
TYPE_ARRAY:
|
||||||
|
return "Array"
|
||||||
|
TYPE_PACKED_BYTE_ARRAY:
|
||||||
|
return "PackedByteArray"
|
||||||
|
TYPE_PACKED_INT32_ARRAY:
|
||||||
|
return "PackedInt32Array"
|
||||||
|
TYPE_PACKED_INT64_ARRAY:
|
||||||
|
return "PackedInt64Array"
|
||||||
|
TYPE_PACKED_FLOAT32_ARRAY:
|
||||||
|
return "PackedFloat32Array"
|
||||||
|
TYPE_PACKED_FLOAT64_ARRAY:
|
||||||
|
return "PackedFloat64Array"
|
||||||
|
TYPE_PACKED_STRING_ARRAY:
|
||||||
|
return "PackedStringArray"
|
||||||
|
TYPE_PACKED_VECTOR2_ARRAY:
|
||||||
|
return "PackedVector2Array"
|
||||||
|
TYPE_PACKED_VECTOR3_ARRAY:
|
||||||
|
return "PackedVector3Array"
|
||||||
|
TYPE_PACKED_COLOR_ARRAY:
|
||||||
|
return "PackedColorArray"
|
||||||
|
push_error("Argument `type` is invalid. Use `TYPE_*` constants.")
|
||||||
|
return "<invalid type>"
|
Loading…
Reference in New Issue