summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgnacio Etcheverry <ignalfonsore@gmail.com>2020-01-02 13:54:16 +0100
committerIgnacio Etcheverry <ignalfonsore@gmail.com>2020-01-02 13:54:20 +0100
commit844a8d215b1fa768440d5233c532f6e71c54fc14 (patch)
treeeae988c1ae1d36466f5ceca09e0eee57e62bb8d8
parentea75ea50d2b0f76c44e02e6fd8a558788cc375f6 (diff)
Mono/C#: Make 'GD.Print' and its variants fallback to 'ToString()'
Up until now, 'GD.Print' would convert parameters first to Variant and only then to String. This meant parameters that cannot be converted to Variant would be printed as "Null". This commit makes 'GD.Print' fallback to 'System.Object.ToString()' if the parameter could not be converted to Variant. The same applies to all 'GD.Print' variants: 'GD.PrintS', 'GD.PrintT', 'GD.PrintErr' and 'GD.PrintRaw'.
-rw-r--r--modules/mono/glue/gd_glue.cpp96
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp84
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h6
3 files changed, 153 insertions, 33 deletions
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index 041d29c7bf..9bea625450 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -71,48 +71,114 @@ MonoObject *godot_icall_GD_instance_from_id(uint64_t p_instance_id) {
}
void godot_icall_GD_print(MonoArray *p_what) {
- Array what = GDMonoMarshal::mono_array_to_Array(p_what);
String str;
- for (int i = 0; i < what.size(); i++)
- str += what[i].operator String();
+ int length = mono_array_length(p_what);
+
+ for (int i = 0; i < length; i++) {
+ MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+ MonoException *exc = NULL;
+ String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return;
+ }
+
+ str += elem_str;
+ }
+
print_line(str);
}
void godot_icall_GD_printerr(MonoArray *p_what) {
- Array what = GDMonoMarshal::mono_array_to_Array(p_what);
+
String str;
- for (int i = 0; i < what.size(); i++)
- str += what[i].operator String();
+ int length = mono_array_length(p_what);
+
+ for (int i = 0; i < length; i++) {
+ MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+ MonoException *exc = NULL;
+ String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return;
+ }
+
+ str += elem_str;
+ }
+
print_error(str);
}
void godot_icall_GD_printraw(MonoArray *p_what) {
- Array what = GDMonoMarshal::mono_array_to_Array(p_what);
String str;
- for (int i = 0; i < what.size(); i++)
- str += what[i].operator String();
+ int length = mono_array_length(p_what);
+
+ for (int i = 0; i < length; i++) {
+ MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+ MonoException *exc = NULL;
+ String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return;
+ }
+
+ str += elem_str;
+ }
+
OS::get_singleton()->print("%s", str.utf8().get_data());
}
void godot_icall_GD_prints(MonoArray *p_what) {
- Array what = GDMonoMarshal::mono_array_to_Array(p_what);
String str;
- for (int i = 0; i < what.size(); i++) {
+ int length = mono_array_length(p_what);
+
+ for (int i = 0; i < length; i++) {
+ MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+ MonoException *exc = NULL;
+ String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return;
+ }
+
if (i)
str += " ";
- str += what[i].operator String();
+
+ str += elem_str;
}
+
print_line(str);
}
void godot_icall_GD_printt(MonoArray *p_what) {
- Array what = GDMonoMarshal::mono_array_to_Array(p_what);
String str;
- for (int i = 0; i < what.size(); i++) {
+ int length = mono_array_length(p_what);
+
+ for (int i = 0; i < length; i++) {
+ MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
+
+ MonoException *exc = NULL;
+ String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return;
+ }
+
if (i)
str += "\t";
- str += what[i].operator String();
+
+ str += elem_str;
}
+
print_line(str);
}
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 24fcd27bbb..b81c20348d 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -700,15 +700,11 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
}
-Variant mono_object_to_variant(MonoObject *p_obj) {
- if (!p_obj)
- return Variant();
+Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) {
- ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
-
- ERR_FAIL_COND_V(!type.type_class, Variant());
+ ERR_FAIL_COND_V(!p_type.type_class, Variant());
- switch (type.type_encoding) {
+ switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
return (bool)unbox<MonoBoolean>(p_obj);
@@ -745,7 +741,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
} break;
case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = type.type_class;
+ GDMonoClass *vtclass = p_type.type_class;
if (vtclass == CACHED_CLASS(Vector2))
return MARSHALLED_IN(Vector2, (GDMonoMarshal::M_Vector2 *)mono_object_unbox(p_obj));
@@ -783,7 +779,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
+ MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
return mono_array_to_Array((MonoArray *)p_obj);
@@ -809,11 +805,15 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
if (array_type->eklass == CACHED_CLASS_RAW(Color))
return mono_array_to_PoolColorArray((MonoArray *)p_obj);
- ERR_FAIL_V_MSG(Variant(), "Attempted to convert a managed array of unmarshallable element type to Variant.");
+ if (p_fail_with_err) {
+ ERR_FAIL_V_MSG(Variant(), "Attempted to convert a managed array of unmarshallable element type to Variant.");
+ } else {
+ return Variant();
+ }
} break;
case MONO_TYPE_CLASS: {
- GDMonoClass *type_class = type.type_class;
+ GDMonoClass *type_class = p_type.type_class;
// GodotObject
if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
@@ -871,18 +871,18 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
} break;
case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type());
+ MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
MonoException *exc = NULL;
- MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
+ MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
UNHANDLED_EXCEPTION(exc);
return *unbox<Dictionary *>(ret);
}
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
MonoException *exc = NULL;
- MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
+ MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
UNHANDLED_EXCEPTION(exc);
return *unbox<Array *>(ret);
}
@@ -893,7 +893,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj);
}
- if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj);
}
@@ -901,14 +901,62 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
}
- if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+ if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
}
} break;
}
- ERR_FAIL_V_MSG(Variant(), "Attempted to convert an unmarshallable managed type to Variant. Name: '" +
- type.type_class->get_name() + "' Encoding: " + itos(type.type_encoding) + ".");
+ if (p_fail_with_err) {
+ ERR_FAIL_V_MSG(Variant(), "Attempted to convert an unmarshallable managed type to Variant. Name: '" +
+ p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
+ } else {
+ return Variant();
+ }
+}
+
+Variant mono_object_to_variant(MonoObject *p_obj) {
+ if (!p_obj)
+ return Variant();
+
+ ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
+
+ return mono_object_to_variant_impl(p_obj, type);
+}
+
+Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
+ if (!p_obj)
+ return Variant();
+
+ return mono_object_to_variant_impl(p_obj, p_type);
+}
+
+Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_type) {
+ if (!p_obj)
+ return Variant();
+
+ return mono_object_to_variant_impl(p_obj, p_type, /* fail_with_err: */ false);
+}
+
+String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
+ ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
+ Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type);
+
+ if (var.get_type() == Variant::NIL && p_obj != NULL) {
+ // Cannot convert MonoObject* to Variant; fallback to 'ToString()'.
+ MonoException *exc = NULL;
+ MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc);
+
+ if (exc) {
+ if (r_exc)
+ *r_exc = exc;
+ return String();
+ }
+
+ return GDMonoMarshal::mono_string_to_godot(mono_str);
+ } else {
+ return var.operator String();
+ }
}
MonoArray *Array_to_mono_array(const Array &p_array) {
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index d0665f7c0d..e662e7814e 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -115,6 +115,12 @@ _FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant &p_var, const Ma
}
Variant mono_object_to_variant(MonoObject *p_obj);
+Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type);
+Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_type);
+
+/// Tries to convert the MonoObject* to Variant and then convert the Variant to String.
+/// If the MonoObject* cannot be converted to Variant, then 'ToString()' is called instead.
+String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc);
// Array