diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index 848b6f3886e..e1ece03dfde 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -580,14 +580,20 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) { bool vararg = Variant::is_utility_function_vararg(name); func["is_vararg"] = Variant::is_utility_function_vararg(name); func["hash"] = Variant::get_utility_function_hash(name); + Array arguments; + const Vector def_args = Variant::get_utility_function_default_arguments(name); int argcount = Variant::get_utility_function_argument_count(name); for (int i = 0; i < argcount; i++) { Dictionary arg; String argname = vararg ? "arg" + itos(i + 1) : Variant::get_utility_function_argument_name(name, i); arg["name"] = argname; arg["type"] = get_builtin_or_variant_type_name(Variant::get_utility_function_argument_type(name, i)); - //no default value support in utility functions + + const int dargidx = Variant::get_utility_function_default_argument_index(name, i); + if (dargidx >= 0) { + arg["default_value"] = def_args[dargidx].get_construct_string(); + } arguments.push_back(arg); } diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 3060f31970c..a32c283255c 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -551,7 +551,7 @@ public: static uint32_t rand(); static _ALWAYS_INLINE_ double randd() { return (double)rand() / (double)Math::RANDOM_32BIT_MAX; } static _ALWAYS_INLINE_ float randf() { return (float)rand() / (float)Math::RANDOM_32BIT_MAX; } - static double randfn(double mean, double deviation); + static double randfn(double mean = 0.0, double deviation = 1.0); static double random(double from, double to); static float random(float from, float to); diff --git a/core/variant/variant.h b/core/variant/variant.h index 1cb3580c010..479b5dd432d 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -752,6 +752,8 @@ public: static int get_utility_function_argument_count(const StringName &p_name); static Variant::Type get_utility_function_argument_type(const StringName &p_name, int p_arg); static String get_utility_function_argument_name(const StringName &p_name, int p_arg); + static Vector get_utility_function_default_arguments(const StringName &p_name); + static int get_utility_function_default_argument_index(const StringName &p_name, int p_arg); static bool has_utility_function_return_value(const StringName &p_name); static Variant::Type get_utility_function_return_type(const StringName &p_name); static bool is_utility_function_vararg(const StringName &p_name); diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 7534a154a1c..6076f65c8b0 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -1228,47 +1228,19 @@ bool VariantUtilityFunctions::is_same(const Variant &p_a, const Variant &p_b) { return p_a.identity_compare(p_b); } -#ifdef DEBUG_METHODS_ENABLED -#define VCALLR *ret = p_func(VariantCasterAndValidate

::cast(p_args, Is, r_error)...) -#define VCALL p_func(VariantCasterAndValidate

::cast(p_args, Is, r_error)...) -#else -#define VCALLR *ret = p_func(VariantCaster

::cast(*p_args[Is])...) -#define VCALL p_func(VariantCaster

::cast(*p_args[Is])...) -#endif - -template -static _FORCE_INLINE_ void call_helperpr(R (*p_func)(P...), Variant *ret, const Variant **p_args, Callable::CallError &r_error, IndexSequence) { - r_error.error = Callable::CallError::CALL_OK; - VCALLR; - (void)p_args; // avoid gcc warning - (void)r_error; -} - -template -static _FORCE_INLINE_ void validated_call_helperpr(R (*p_func)(P...), Variant *ret, const Variant **p_args, IndexSequence) { - *ret = p_func(VariantCaster

::cast(*p_args[Is])...); - (void)p_args; -} - -template -static _FORCE_INLINE_ void ptr_call_helperpr(R (*p_func)(P...), void *ret, const void **p_args, IndexSequence) { - PtrToArg::encode(p_func(PtrToArg

::convert(p_args[Is])...), ret); - (void)p_args; -} - template -static _FORCE_INLINE_ void call_helperr(R (*p_func)(P...), Variant *ret, const Variant **p_args, Callable::CallError &r_error) { - call_helperpr(p_func, ret, p_args, r_error, BuildIndexSequence{}); +static _FORCE_INLINE_ void call_helperr(R (*p_func)(P...), Variant *ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { + call_with_variant_args_static_ret_dv(p_func, p_args, p_argcount, *ret, r_error, p_defvals); } template static _FORCE_INLINE_ void validated_call_helperr(R (*p_func)(P...), Variant *ret, const Variant **p_args) { - validated_call_helperpr(p_func, ret, p_args, BuildIndexSequence{}); + call_with_validated_variant_args_static_method_ret(p_func, p_args, ret); } template static _FORCE_INLINE_ void ptr_call_helperr(R (*p_func)(P...), void *ret, const void **p_args) { - ptr_call_helperpr(p_func, ret, p_args, BuildIndexSequence{}); + call_with_ptr_args_static_method_ret(p_func, p_args, ret); } template @@ -1288,20 +1260,6 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helperr(R (*p_func)(P...)) { // WITHOUT RET -template -static _FORCE_INLINE_ void call_helperp(void (*p_func)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence) { - r_error.error = Callable::CallError::CALL_OK; - VCALL; - (void)p_args; - (void)r_error; -} - -template -static _FORCE_INLINE_ void validated_call_helperp(void (*p_func)(P...), const Variant **p_args, IndexSequence) { - p_func(VariantCaster

::cast(*p_args[Is])...); - (void)p_args; -} - template static _FORCE_INLINE_ void ptr_call_helperp(void (*p_func)(P...), const void **p_args, IndexSequence) { p_func(PtrToArg

::convert(p_args[Is])...); @@ -1309,18 +1267,18 @@ static _FORCE_INLINE_ void ptr_call_helperp(void (*p_func)(P...), const void **p } template -static _FORCE_INLINE_ void call_helper(void (*p_func)(P...), const Variant **p_args, Callable::CallError &r_error) { - call_helperp(p_func, p_args, r_error, BuildIndexSequence{}); +static _FORCE_INLINE_ void call_helper(void (*p_func)(P...), const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { + call_with_variant_args_static_dv(p_func, p_args, p_argcount, r_error, p_defvals); } template static _FORCE_INLINE_ void validated_call_helper(void (*p_func)(P...), const Variant **p_args) { - validated_call_helperp(p_func, p_args, BuildIndexSequence{}); + call_with_validated_variant_args_static_method(p_func, p_args); } template static _FORCE_INLINE_ void ptr_call_helper(void (*p_func)(P...), const void **p_args) { - ptr_call_helperp(p_func, p_args, BuildIndexSequence{}); + call_with_ptr_args_static_method(p_func, p_args); } template @@ -1338,105 +1296,134 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { return Variant::NIL; } -#define FUNCBINDR(m_func, m_args, m_category) \ - class Func_##m_func { \ - public: \ - static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ - call_helperr(VariantUtilityFunctions::m_func, r_ret, p_args, r_error); \ - } \ - static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ - validated_call_helperr(VariantUtilityFunctions::m_func, r_ret, p_args); \ - } \ - static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ - ptr_call_helperr(VariantUtilityFunctions::m_func, ret, p_args); \ - } \ - static int get_argument_count() { \ - return get_arg_count_helperr(VariantUtilityFunctions::m_func); \ - } \ - static Variant::Type get_argument_type(int p_arg) { \ - return get_arg_type_helperr(VariantUtilityFunctions::m_func, p_arg); \ - } \ - static Variant::Type get_return_type() { \ - return get_ret_type_helperr(VariantUtilityFunctions::m_func); \ - } \ - static bool has_return_type() { \ - return true; \ - } \ - static bool is_vararg() { return false; } \ - static Variant::UtilityFunctionType get_type() { return m_category; } \ - }; \ - register_utility_function(#m_func, m_args) +#define FUNCBINDR(m_func, m_args, m_category) \ + class Func_##m_func { \ + public: \ + static void call(Variant *r_ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { \ + call_helperr(VariantUtilityFunctions::m_func, r_ret, p_args, p_argcount, varray(), r_error); \ + } \ + static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ + validated_call_helperr(VariantUtilityFunctions::m_func, r_ret, p_args); \ + } \ + static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ + ptr_call_helperr(VariantUtilityFunctions::m_func, ret, p_args); \ + } \ + static int get_argument_count() { \ + return get_arg_count_helperr(VariantUtilityFunctions::m_func); \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return get_arg_type_helperr(VariantUtilityFunctions::m_func, p_arg); \ + } \ + static Variant::Type get_return_type() { \ + return get_ret_type_helperr(VariantUtilityFunctions::m_func); \ + } \ + static bool has_return_type() { \ + return true; \ + } \ + static bool is_vararg() { return false; } \ + static Variant::UtilityFunctionType get_type() { return m_category; } \ + }; \ + register_utility_function(#m_func, m_args, varray()) -#define FUNCBINDVR(m_func, m_args, m_category) \ - class Func_##m_func { \ - public: \ - static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ - r_error.error = Callable::CallError::CALL_OK; \ - *r_ret = VariantUtilityFunctions::m_func(*p_args[0], r_error); \ - } \ - static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ - Callable::CallError ce; \ - *r_ret = VariantUtilityFunctions::m_func(*p_args[0], ce); \ - } \ - static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ - Callable::CallError ce; \ - PtrToArg::encode(VariantUtilityFunctions::m_func(PtrToArg::convert(p_args[0]), ce), ret); \ - } \ - static int get_argument_count() { \ - return 1; \ - } \ - static Variant::Type get_argument_type(int p_arg) { \ - return Variant::NIL; \ - } \ - static Variant::Type get_return_type() { \ - return Variant::NIL; \ - } \ - static bool has_return_type() { \ - return true; \ - } \ - static bool is_vararg() { return false; } \ - static Variant::UtilityFunctionType get_type() { return m_category; } \ - }; \ - register_utility_function(#m_func, m_args) +#define FUNCBINDRD(m_func, m_args, m_defvals, m_category) \ + class Func_##m_func { \ + public: \ + static void call(Variant *r_ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { \ + call_helperr(VariantUtilityFunctions::m_func, r_ret, p_args, p_argcount, p_defvals, r_error); \ + } \ + static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ + validated_call_helperr(VariantUtilityFunctions::m_func, r_ret, p_args); \ + } \ + static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ + ptr_call_helperr(VariantUtilityFunctions::m_func, ret, p_args); \ + } \ + static int get_argument_count() { \ + return get_arg_count_helperr(VariantUtilityFunctions::m_func); \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return get_arg_type_helperr(VariantUtilityFunctions::m_func, p_arg); \ + } \ + static Variant::Type get_return_type() { \ + return get_ret_type_helperr(VariantUtilityFunctions::m_func); \ + } \ + static bool has_return_type() { \ + return true; \ + } \ + static bool is_vararg() { return false; } \ + static Variant::UtilityFunctionType get_type() { return m_category; } \ + }; \ + register_utility_function(#m_func, m_args, m_defvals) -#define FUNCBINDVR2(m_func, m_args, m_category) \ - class Func_##m_func { \ - public: \ - static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ - r_error.error = Callable::CallError::CALL_OK; \ - *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], r_error); \ - } \ - static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ - Callable::CallError ce; \ - *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], ce); \ - } \ - static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ - Callable::CallError ce; \ - Variant r; \ - r = VariantUtilityFunctions::m_func(PtrToArg::convert(p_args[0]), PtrToArg::convert(p_args[1]), ce); \ - PtrToArg::encode(r, ret); \ - } \ - static int get_argument_count() { \ - return 2; \ - } \ - static Variant::Type get_argument_type(int p_arg) { \ - return Variant::NIL; \ - } \ - static Variant::Type get_return_type() { \ - return Variant::NIL; \ - } \ - static bool has_return_type() { \ - return true; \ - } \ - static bool is_vararg() { return false; } \ - static Variant::UtilityFunctionType get_type() { return m_category; } \ - }; \ - register_utility_function(#m_func, m_args) +#define FUNCBINDVR(m_func, m_args, m_category) \ + class Func_##m_func { \ + public: \ + static void call(Variant *r_ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { \ + r_error.error = Callable::CallError::CALL_OK; \ + *r_ret = VariantUtilityFunctions::m_func(*p_args[0], r_error); \ + } \ + static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ + Callable::CallError ce; \ + *r_ret = VariantUtilityFunctions::m_func(*p_args[0], ce); \ + } \ + static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ + Callable::CallError ce; \ + PtrToArg::encode(VariantUtilityFunctions::m_func(PtrToArg::convert(p_args[0]), ce), ret); \ + } \ + static int get_argument_count() { \ + return 1; \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return Variant::NIL; \ + } \ + static Variant::Type get_return_type() { \ + return Variant::NIL; \ + } \ + static bool has_return_type() { \ + return true; \ + } \ + static bool is_vararg() { return false; } \ + static Variant::UtilityFunctionType get_type() { return m_category; } \ + }; \ + register_utility_function(#m_func, m_args, varray()) + +#define FUNCBINDVR2(m_func, m_args, m_category) \ + class Func_##m_func { \ + public: \ + static void call(Variant *r_ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { \ + r_error.error = Callable::CallError::CALL_OK; \ + *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], r_error); \ + } \ + static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ + Callable::CallError ce; \ + *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], ce); \ + } \ + static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ + Callable::CallError ce; \ + Variant r; \ + r = VariantUtilityFunctions::m_func(PtrToArg::convert(p_args[0]), PtrToArg::convert(p_args[1]), ce); \ + PtrToArg::encode(r, ret); \ + } \ + static int get_argument_count() { \ + return 2; \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return Variant::NIL; \ + } \ + static Variant::Type get_return_type() { \ + return Variant::NIL; \ + } \ + static bool has_return_type() { \ + return true; \ + } \ + static bool is_vararg() { return false; } \ + static Variant::UtilityFunctionType get_type() { return m_category; } \ + }; \ + register_utility_function(#m_func, m_args, varray()) #define FUNCBINDVR3(m_func, m_args, m_category) \ class Func_##m_func { \ public: \ - static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ + static void call(Variant *r_ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { \ r_error.error = Callable::CallError::CALL_OK; \ *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], *p_args[2], r_error); \ } \ @@ -1465,175 +1452,176 @@ static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) { static bool is_vararg() { return false; } \ static Variant::UtilityFunctionType get_type() { return m_category; } \ }; \ - register_utility_function(#m_func, m_args) + register_utility_function(#m_func, m_args, varray()) -#define FUNCBINDVARARG(m_func, m_args, m_category) \ - class Func_##m_func { \ - public: \ - static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ - r_error.error = Callable::CallError::CALL_OK; \ - *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \ - } \ - static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ - Callable::CallError c; \ - *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, c); \ - } \ - static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ - Vector args; \ - for (int i = 0; i < p_argcount; i++) { \ - args.push_back(PtrToArg::convert(p_args[i])); \ - } \ - Vector argsp; \ - for (int i = 0; i < p_argcount; i++) { \ - argsp.push_back(&args[i]); \ - } \ - Variant r; \ - validated_call(&r, (const Variant **)argsp.ptr(), p_argcount); \ - PtrToArg::encode(r, ret); \ - } \ - static int get_argument_count() { \ - return 2; \ - } \ - static Variant::Type get_argument_type(int p_arg) { \ - return Variant::NIL; \ - } \ - static Variant::Type get_return_type() { \ - return Variant::NIL; \ - } \ - static bool has_return_type() { \ - return true; \ - } \ - static bool is_vararg() { \ - return true; \ - } \ - static Variant::UtilityFunctionType get_type() { \ - return m_category; \ - } \ - }; \ - register_utility_function(#m_func, m_args) +#define FUNCBINDVARARG(m_func, m_args, m_category) \ + class Func_##m_func { \ + public: \ + static void call(Variant *r_ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { \ + r_error.error = Callable::CallError::CALL_OK; \ + *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \ + } \ + static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ + Callable::CallError c; \ + *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, c); \ + } \ + static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ + Vector args; \ + for (int i = 0; i < p_argcount; i++) { \ + args.push_back(PtrToArg::convert(p_args[i])); \ + } \ + Vector argsp; \ + for (int i = 0; i < p_argcount; i++) { \ + argsp.push_back(&args[i]); \ + } \ + Variant r; \ + validated_call(&r, (const Variant **)argsp.ptr(), p_argcount); \ + PtrToArg::encode(r, ret); \ + } \ + static int get_argument_count() { \ + return 2; \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return Variant::NIL; \ + } \ + static Variant::Type get_return_type() { \ + return Variant::NIL; \ + } \ + static bool has_return_type() { \ + return true; \ + } \ + static bool is_vararg() { \ + return true; \ + } \ + static Variant::UtilityFunctionType get_type() { \ + return m_category; \ + } \ + }; \ + register_utility_function(#m_func, m_args, varray()) -#define FUNCBINDVARARGS(m_func, m_args, m_category) \ - class Func_##m_func { \ - public: \ - static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ - r_error.error = Callable::CallError::CALL_OK; \ - *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \ - } \ - static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ - Callable::CallError c; \ - *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, c); \ - } \ - static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ - Vector args; \ - for (int i = 0; i < p_argcount; i++) { \ - args.push_back(PtrToArg::convert(p_args[i])); \ - } \ - Vector argsp; \ - for (int i = 0; i < p_argcount; i++) { \ - argsp.push_back(&args[i]); \ - } \ - Variant r; \ - validated_call(&r, (const Variant **)argsp.ptr(), p_argcount); \ - PtrToArg::encode(r.operator String(), ret); \ - } \ - static int get_argument_count() { \ - return 1; \ - } \ - static Variant::Type get_argument_type(int p_arg) { \ - return Variant::NIL; \ - } \ - static Variant::Type get_return_type() { \ - return Variant::STRING; \ - } \ - static bool has_return_type() { \ - return true; \ - } \ - static bool is_vararg() { \ - return true; \ - } \ - static Variant::UtilityFunctionType get_type() { \ - return m_category; \ - } \ - }; \ - register_utility_function(#m_func, m_args) +#define FUNCBINDVARARGS(m_func, m_args, m_category) \ + class Func_##m_func { \ + public: \ + static void call(Variant *r_ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { \ + r_error.error = Callable::CallError::CALL_OK; \ + *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \ + } \ + static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ + Callable::CallError c; \ + *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, c); \ + } \ + static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ + Vector args; \ + for (int i = 0; i < p_argcount; i++) { \ + args.push_back(PtrToArg::convert(p_args[i])); \ + } \ + Vector argsp; \ + for (int i = 0; i < p_argcount; i++) { \ + argsp.push_back(&args[i]); \ + } \ + Variant r; \ + validated_call(&r, (const Variant **)argsp.ptr(), p_argcount); \ + PtrToArg::encode(r.operator String(), ret); \ + } \ + static int get_argument_count() { \ + return 1; \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return Variant::NIL; \ + } \ + static Variant::Type get_return_type() { \ + return Variant::STRING; \ + } \ + static bool has_return_type() { \ + return true; \ + } \ + static bool is_vararg() { \ + return true; \ + } \ + static Variant::UtilityFunctionType get_type() { \ + return m_category; \ + } \ + }; \ + register_utility_function(#m_func, m_args, varray()) -#define FUNCBINDVARARGV(m_func, m_args, m_category) \ - class Func_##m_func { \ - public: \ - static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ - r_error.error = Callable::CallError::CALL_OK; \ - VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \ - } \ - static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ - Callable::CallError c; \ - VariantUtilityFunctions::m_func(p_args, p_argcount, c); \ - } \ - static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ - Vector args; \ - for (int i = 0; i < p_argcount; i++) { \ - args.push_back(PtrToArg::convert(p_args[i])); \ - } \ - Vector argsp; \ - for (int i = 0; i < p_argcount; i++) { \ - argsp.push_back(&args[i]); \ - } \ - Variant r; \ - validated_call(&r, (const Variant **)argsp.ptr(), p_argcount); \ - } \ - static int get_argument_count() { \ - return 1; \ - } \ - static Variant::Type get_argument_type(int p_arg) { \ - return Variant::NIL; \ - } \ - static Variant::Type get_return_type() { \ - return Variant::NIL; \ - } \ - static bool has_return_type() { \ - return false; \ - } \ - static bool is_vararg() { \ - return true; \ - } \ - static Variant::UtilityFunctionType get_type() { \ - return m_category; \ - } \ - }; \ - register_utility_function(#m_func, m_args) +#define FUNCBINDVARARGV(m_func, m_args, m_category) \ + class Func_##m_func { \ + public: \ + static void call(Variant *r_ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { \ + r_error.error = Callable::CallError::CALL_OK; \ + VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \ + } \ + static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ + Callable::CallError c; \ + VariantUtilityFunctions::m_func(p_args, p_argcount, c); \ + } \ + static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ + Vector args; \ + for (int i = 0; i < p_argcount; i++) { \ + args.push_back(PtrToArg::convert(p_args[i])); \ + } \ + Vector argsp; \ + for (int i = 0; i < p_argcount; i++) { \ + argsp.push_back(&args[i]); \ + } \ + Variant r; \ + validated_call(&r, (const Variant **)argsp.ptr(), p_argcount); \ + } \ + static int get_argument_count() { \ + return 1; \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return Variant::NIL; \ + } \ + static Variant::Type get_return_type() { \ + return Variant::NIL; \ + } \ + static bool has_return_type() { \ + return false; \ + } \ + static bool is_vararg() { \ + return true; \ + } \ + static Variant::UtilityFunctionType get_type() { \ + return m_category; \ + } \ + }; \ + register_utility_function(#m_func, m_args, varray()) -#define FUNCBIND(m_func, m_args, m_category) \ - class Func_##m_func { \ - public: \ - static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \ - call_helper(VariantUtilityFunctions::m_func, p_args, r_error); \ - } \ - static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ - validated_call_helper(VariantUtilityFunctions::m_func, p_args); \ - } \ - static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ - ptr_call_helper(VariantUtilityFunctions::m_func, p_args); \ - } \ - static int get_argument_count() { \ - return get_arg_count_helper(VariantUtilityFunctions::m_func); \ - } \ - static Variant::Type get_argument_type(int p_arg) { \ - return get_arg_type_helper(VariantUtilityFunctions::m_func, p_arg); \ - } \ - static Variant::Type get_return_type() { \ - return get_ret_type_helper(VariantUtilityFunctions::m_func); \ - } \ - static bool has_return_type() { \ - return false; \ - } \ - static bool is_vararg() { return false; } \ - static Variant::UtilityFunctionType get_type() { return m_category; } \ - }; \ - register_utility_function(#m_func, m_args) +#define FUNCBIND(m_func, m_args, m_category) \ + class Func_##m_func { \ + public: \ + static void call(Variant *r_ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) { \ + call_helper(VariantUtilityFunctions::m_func, p_args, p_argcount, varray(), r_error); \ + } \ + static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \ + validated_call_helper(VariantUtilityFunctions::m_func, p_args); \ + } \ + static void ptrcall(void *ret, const void **p_args, int p_argcount) { \ + ptr_call_helper(VariantUtilityFunctions::m_func, p_args); \ + } \ + static int get_argument_count() { \ + return get_arg_count_helper(VariantUtilityFunctions::m_func); \ + } \ + static Variant::Type get_argument_type(int p_arg) { \ + return get_arg_type_helper(VariantUtilityFunctions::m_func, p_arg); \ + } \ + static Variant::Type get_return_type() { \ + return get_ret_type_helper(VariantUtilityFunctions::m_func); \ + } \ + static bool has_return_type() { \ + return false; \ + } \ + static bool is_vararg() { return false; } \ + static Variant::UtilityFunctionType get_type() { return m_category; } \ + }; \ + register_utility_function(#m_func, m_args, varray()) struct VariantUtilityFunctionInfo { - void (*call_utility)(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = nullptr; + void (*call_utility)(Variant *r_ret, const Variant **p_args, int p_argcount, const Vector &p_defvals, Callable::CallError &r_error) = nullptr; Variant::ValidatedUtilityFunction validated_call_utility = nullptr; Variant::PTRUtilityFunction ptr_call_utility = nullptr; + Vector default_arguments; Vector argnames; bool is_vararg = false; bool returns_value = false; @@ -1647,7 +1635,7 @@ static OAHashMap utility_function_table; static List utility_function_name_table; template -static void register_utility_function(const String &p_name, const Vector &argnames) { +static void register_utility_function(const String &p_name, const Vector &argnames, const Vector &p_def_args) { String name = p_name; if (name.begins_with("_")) { name = name.substr(1, name.length() - 1); @@ -1660,6 +1648,7 @@ static void register_utility_function(const String &p_name, const Vector bfi.validated_call_utility = T::validated_call; bfi.ptr_call_utility = T::ptrcall; bfi.is_vararg = T::is_vararg(); + bfi.default_arguments = p_def_args; bfi.argnames = argnames; bfi.argcount = T::get_argument_count(); if (!bfi.is_vararg) { @@ -1786,7 +1775,7 @@ void Variant::_register_variant_utility_functions() { FUNCBINDR(randf, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM); FUNCBINDR(randi_range, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_RANDOM); FUNCBINDR(randf_range, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_RANDOM); - FUNCBINDR(randfn, sarray("mean", "deviation"), Variant::UTILITY_FUNC_TYPE_RANDOM); + FUNCBINDRD(randfn, sarray("mean", "deviation"), varray(0.0, 1.0), Variant::UTILITY_FUNC_TYPE_RANDOM); FUNCBIND(seed, sarray("base"), Variant::UTILITY_FUNC_TYPE_RANDOM); FUNCBINDR(rand_from_seed, sarray("seed"), Variant::UTILITY_FUNC_TYPE_RANDOM); @@ -1843,9 +1832,9 @@ void Variant::call_utility_function(const StringName &p_name, Variant *r_ret, co return; } - if (unlikely(!bfi->is_vararg && p_argcount < bfi->argcount)) { + if (unlikely(!bfi->is_vararg && p_argcount < bfi->argcount - bfi->default_arguments.size())) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.expected = bfi->argcount; + r_error.expected = bfi->argcount - bfi->default_arguments.size(); return; } @@ -1855,7 +1844,7 @@ void Variant::call_utility_function(const StringName &p_name, Variant *r_ret, co return; } - bfi->call_utility(r_ret, p_args, p_argcount, r_error); + bfi->call_utility(r_ret, p_args, p_argcount, bfi->default_arguments, r_error); } bool Variant::has_utility_function(const StringName &p_name) { @@ -1907,6 +1896,7 @@ MethodInfo Variant::get_utility_function_info(const StringName &p_name) { arg.name = bfi->argnames[i]; info.arguments.push_back(arg); } + info.default_arguments = bfi->default_arguments; } return info; } @@ -1920,6 +1910,24 @@ int Variant::get_utility_function_argument_count(const StringName &p_name) { return bfi->argcount; } +Vector Variant::get_utility_function_default_arguments(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); + if (!bfi) { + return varray(); + } + + return bfi->default_arguments; +} + +int Variant::get_utility_function_default_argument_index(const StringName &p_name, int p_arg) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); + if (!bfi) { + return false; + } + + return p_arg - (bfi->argcount - bfi->default_arguments.size()); +} + Variant::Type Variant::get_utility_function_argument_type(const StringName &p_name, int p_arg) { const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { diff --git a/core/variant/variant_utility.h b/core/variant/variant_utility.h index 75cde4942b5..0d7ab13ab26 100644 --- a/core/variant/variant_utility.h +++ b/core/variant/variant_utility.h @@ -119,7 +119,7 @@ struct VariantUtilityFunctions { static void randomize(); static int64_t randi(); static double randf(); - static double randfn(double mean, double deviation); + static double randfn(double mean = 0.0, double deviation = 1.0); static int64_t randi_range(int64_t from, int64_t to); static double randf_range(double from, double to); static void seed(int64_t s); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 2cd3a517224..7871ccb349e 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1033,8 +1033,8 @@ - - + + Returns a [url=https://en.wikipedia.org/wiki/Normal_distribution]normally-distributed[/url], pseudo-random floating-point value from the specified [param mean] and a standard [param deviation]. This is also known as a Gaussian distribution. [b]Note:[/b] This method uses the [url=https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform]Box-Muller transform[/url] algorithm. diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 331dacf6adb..7bfd3c8cb74 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -981,6 +981,7 @@ void DocTools::generate(BitField p_flags) { if (Variant::is_utility_function_vararg(E)) { md.qualifiers = "vararg"; } else { + const Vector def_args = Variant::get_utility_function_default_arguments(E); for (int i = 0; i < Variant::get_utility_function_argument_count(E); i++) { PropertyInfo pi; pi.type = Variant::get_utility_function_argument_type(E, i); @@ -990,6 +991,12 @@ void DocTools::generate(BitField p_flags) { } DocData::ArgumentDoc ad; DocData::argument_doc_from_arginfo(ad, pi); + + const int dargidx = Variant::get_utility_function_default_argument_index(E, i); + if (dargidx >= 0) { + ad.default_value = DocData::get_default_value_string(def_args[dargidx]); + } + md.arguments.push_back(ad); } } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index e73b4c945c7..45649f6211f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -77,6 +77,7 @@ static MethodInfo info_from_utility_func(const StringName &p_function) { pi.type = Variant::get_utility_function_argument_type(p_function, i); info.arguments.push_back(pi); } + info.default_arguments = Variant::get_utility_function_default_arguments(p_function); } return info; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index d8b44a558f6..5b45813bea7 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -621,6 +621,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) { gen->write_construct(result, GDScriptParser::get_builtin_type(call->function_name), arguments); } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) { + int arg_count = Variant::get_utility_function_argument_count(call->function_name); + + if (call->arguments.size() < arg_count) { + Vector def_args = Variant::get_utility_function_default_arguments(call->function_name); + + for (int i = call->arguments.size(); i < arg_count; i++) { + const int dargidx = Variant::get_utility_function_default_argument_index(call->function_name, i); + + if (dargidx >= 0) { + arguments.push_back(codegen.add_constant(def_args[dargidx])); + } + } + } + // Variant utility function. gen->write_call_utility(result, call->function_name, arguments); } else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) { diff --git a/tests/core/variant/test_variant.h b/tests/core/variant/test_variant.h index be615975f88..afc68fb0a79 100644 --- a/tests/core/variant/test_variant.h +++ b/tests/core/variant/test_variant.h @@ -2167,12 +2167,19 @@ TEST_CASE("[Variant] Utility functions") { if (Variant::is_utility_function_vararg(E)) { md.is_vararg = true; } else { + const Vector def_args = Variant::get_utility_function_default_arguments(E); for (int i = 0; i < Variant::get_utility_function_argument_count(E); i++) { ArgumentData arg; arg.type = Variant::get_utility_function_argument_type(E, i); arg.name = Variant::get_utility_function_argument_name(E, i); arg.position = i; + const int dargidx = Variant::get_utility_function_default_argument_index(E, i); + if (dargidx >= 0) { + arg.has_defval = true; + arg.defval = def_args[dargidx]; + } + md.arguments.push_back(arg); } } @@ -2187,6 +2194,13 @@ TEST_CASE("[Variant] Utility functions") { TEST_COND((arg.name.is_empty() || arg.name.begins_with("_unnamed_arg")), vformat("Unnamed argument in position %d of function '%s'.", arg.position, E.name)); + + if (arg.has_defval) { + const bool arg_defval_assignable_to_type = arg.type == arg.defval.get_type(); + + TEST_COND(!arg_defval_assignable_to_type, + vformat("Invalid default value for parameter '%s' of function '%s'.", arg.name, E.name)); + } } } }