From da6f5932f1ec0392d23d84907863271810d90567 Mon Sep 17 00:00:00 2001 From: Lauro Moura Date: Thu, 10 May 2018 22:00:07 -0300 Subject: [PATCH] efl_mono: Support type aliases. Summary: Due to the absence of typedef from C#, we generate thin structs with implicit operators to allow reference the data from their typedef'd name from C#. The other alternatives would be always converting to the lowest base on the alias stack (losing the meaningfulness of the typedef name) or using the 'using' directive. The latter has the restriction that it makes an alias visible only in the file they are declared. Reviewers: felipealmeida, cedric, segfaultxavi Reviewed By: segfaultxavi Subscribers: zmike Tags: #efl Differential Revision: https://phab.enlightenment.org/D6157 --- .../eolian/mono/alias_definition.hh | 77 +++++++++++++++++++ src/bin/eolian_mono/eolian/mono/blacklist.hh | 5 ++ .../eolian/mono/generation_contexts.hh | 1 + .../eolian_mono/eolian/mono/name_helpers.hh | 5 ++ src/bin/eolian_mono/eolian_mono.cc | 21 +++-- src/bindings/mono/eina_mono/eina_common.cs | 14 ---- src/bindings/mono/eo_mono/workaround.cs | 43 ----------- src/lib/eolian_cxx/grammar/klass_def.hpp | 33 ++++++++ src/tests/efl_mono/Eo.cs | 16 ++++ src/tests/efl_mono/libefl_mono_native_test.c | 6 ++ src/tests/efl_mono/test_testing.eo | 12 +++ 11 files changed, 170 insertions(+), 63 deletions(-) create mode 100644 src/bin/eolian_mono/eolian/mono/alias_definition.hh diff --git a/src/bin/eolian_mono/eolian/mono/alias_definition.hh b/src/bin/eolian_mono/eolian/mono/alias_definition.hh new file mode 100644 index 0000000000..91659fb7bd --- /dev/null +++ b/src/bin/eolian_mono/eolian/mono/alias_definition.hh @@ -0,0 +1,77 @@ +#ifndef EOLIAN_MONO_ALIAS_DEFINITION_HH +#define EOLIAN_MONO_ALIAS_DEFINITION_HH + +#include "grammar/generator.hpp" +#include "grammar/klass_def.hpp" +#include "grammar/indentation.hpp" + +#include "using_decl.hh" +#include "name_helpers.hh" +#include "blacklist.hh" +#include "documentation.hh" +#include "generation_contexts.hh" + +namespace eolian_mono { + +struct alias_definition_generator +{ + template + bool generate(OutputIterator sink, attributes::alias_def const& alias, Context const& context) const + { + if (blacklist::is_alias_blacklisted(alias)) + { + EINA_CXX_DOM_LOG_DBG(eolian_mono::domain) << "Alias " << name_helpers::alias_full_eolian_name(alias) << "is blacklisted. Skipping."; + return true; + } + + if (alias.is_undefined) + { + EINA_CXX_DOM_LOG_DBG(eolian_mono::domain) << "Alias " << name_helpers::alias_full_eolian_name(alias) << "is undefined. Skipping."; + return true; + } + + if (!name_helpers::open_namespaces(sink, alias.namespaces, context)) + return false; + + std::string const& alias_name = alias.eolian_name; + if (!as_generator( + "public struct " << alias_name << " {\n" + << scope_tab << "private " << type << " payload;\n" + << scope_tab << "public static implicit operator " << alias_name << "(" << type << " x)\n" + << scope_tab << "{\n" + << scope_tab << scope_tab << "return new " << alias_name << "{payload=x};\n" + << scope_tab << "}\n" + << scope_tab << "public static implicit operator " << type << "(" << alias_name << " x)\n" + << scope_tab << "{\n" + << scope_tab << scope_tab << "return x.payload;\n" + << scope_tab << "}\n" + << "}\n" + ).generate(sink, std::make_tuple(alias.base_type, alias.base_type, alias.base_type), context)) + return false; + + if (!name_helpers::close_namespaces(sink, alias.namespaces, context)) + return false; + + return true; + } +} const alias_definition {}; + +} + +namespace efl { namespace eolian { namespace grammar { + +template<> +struct is_eager_generator< ::eolian_mono::alias_definition_generator> : std::true_type {}; +template<> +struct is_generator< ::eolian_mono::alias_definition_generator> : std::true_type {}; + +namespace type_traits { + +template<> +struct attributes_needed< ::eolian_mono::alias_definition_generator> : std::integral_constant {}; + +} + +} } } + +#endif diff --git a/src/bin/eolian_mono/eolian/mono/blacklist.hh b/src/bin/eolian_mono/eolian/mono/blacklist.hh index fe1640ea67..6fe4d584c4 100644 --- a/src/bin/eolian_mono/eolian/mono/blacklist.hh +++ b/src/bin/eolian_mono/eolian/mono/blacklist.hh @@ -73,6 +73,11 @@ inline bool is_struct_blacklisted(attributes::regular_type_def const& struct_) return is_struct_blacklisted(name_helpers::type_full_eolian_name(struct_)); } +inline bool is_alias_blacklisted(attributes::alias_def const& alias) +{ + return name_helpers::alias_full_eolian_name(alias) == "Eina.Error"; +} + } } diff --git a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh index d7e31ddae2..7f94de7736 100644 --- a/src/bin/eolian_mono/eolian/mono/generation_contexts.hh +++ b/src/bin/eolian_mono/eolian/mono/generation_contexts.hh @@ -12,6 +12,7 @@ struct class_context inherit_native, structs, function_ptr, + alias, }; wrapper_kind current_wrapper_kind; }; diff --git a/src/bin/eolian_mono/eolian/mono/name_helpers.hh b/src/bin/eolian_mono/eolian/mono/name_helpers.hh index bba06e9221..6dd0cc567c 100644 --- a/src/bin/eolian_mono/eolian/mono/name_helpers.hh +++ b/src/bin/eolian_mono/eolian/mono/name_helpers.hh @@ -187,6 +187,11 @@ inline std::string managed_method_name(attributes::function_def const& f) return candidate; } +inline std::string alias_full_eolian_name(attributes::alias_def const& alias) +{ + return join_namespaces(alias.namespaces, '.') + alias.eolian_name; +} + inline std::string function_ptr_full_eolian_name(attributes::function_def const& func) { return join_namespaces(func.namespaces, '.') + func.name; diff --git a/src/bin/eolian_mono/eolian_mono.cc b/src/bin/eolian_mono/eolian_mono.cc index 7f65a4fcaa..9bb5263fbf 100644 --- a/src/bin/eolian_mono/eolian_mono.cc +++ b/src/bin/eolian_mono/eolian_mono.cc @@ -32,6 +32,7 @@ #include #include #include +#include namespace eolian_mono { @@ -137,13 +138,21 @@ run(options_type const& opts) efl::eolian::grammar::context_null()); EINA_ITERATOR_FOREACH(aliases, tp) { - if (eolian_typedecl_type_get(tp) != EOLIAN_TYPEDECL_FUNCTION_POINTER) - continue; + if (eolian_typedecl_type_get(tp) == EOLIAN_TYPEDECL_FUNCTION_POINTER) + { + const Eolian_Function *fp = eolian_typedecl_function_pointer_get(tp); + efl::eolian::grammar::attributes::function_def function_def(fp, EOLIAN_FUNCTION_POINTER, tp, opts.unit); + if (!eolian_mono::function_pointer.generate(iterator, function_def, context)) + throw std::runtime_error("Failed to generate function pointer wrapper"); + } + else // Regular aliases + { + efl::eolian::grammar::attributes::alias_def alias(tp, opts.unit); + auto alias_cxt = context_add_tag(class_context{class_context::alias}, context); - const Eolian_Function *fp = eolian_typedecl_function_pointer_get(tp); - efl::eolian::grammar::attributes::function_def function_def(fp, EOLIAN_FUNCTION_POINTER, tp, opts.unit); - if (!eolian_mono::function_pointer.generate(iterator, function_def, context)) - throw std::runtime_error("Failed to generate function pointer wrapper"); + if (!eolian_mono::alias_definition.generate(iterator, alias, alias_cxt)) + throw std::runtime_error("Failed to generate alias."); + } } if (klass) diff --git a/src/bindings/mono/eina_mono/eina_common.cs b/src/bindings/mono/eina_mono/eina_common.cs index 9063095ff4..fd9d888bb5 100644 --- a/src/bindings/mono/eina_mono/eina_common.cs +++ b/src/bindings/mono/eina_mono/eina_common.cs @@ -145,20 +145,6 @@ public static class StringConversion } } -public struct Unicode { - private uint val; - - public static implicit operator Unicode(uint x) - { - return new Unicode{val=x}; - } - public static implicit operator uint(Unicode x) - { - return x.val; - } -} - - /// Enum to handle resource ownership between managed and unmanaged code. public enum Ownership { /// The resource is owned by the managed code. It should free the handle on disposal. diff --git a/src/bindings/mono/eo_mono/workaround.cs b/src/bindings/mono/eo_mono/workaround.cs index df5eb818d1..cf95b71002 100644 --- a/src/bindings/mono/eo_mono/workaround.cs +++ b/src/bindings/mono/eo_mono/workaround.cs @@ -137,32 +137,6 @@ public delegate void Signal_Cb(IntPtr data, IntPtr obj, IntPtr emission, IntPtr namespace access { -public struct State_Set { - private ulong mask; - - public static implicit operator State_Set(ulong x) - { - return new State_Set{mask=x}; - } - public static implicit operator ulong(State_Set x) - { - return x.mask; - } -} - -public struct Relation_Set { - private IntPtr mask; - - public static implicit operator Relation_Set(IntPtr x) - { - return new Relation_Set{mask=x}; - } - public static implicit operator IntPtr(Relation_Set x) - { - return x.mask; - } -} - public struct Action_Data { public IntPtr name; public IntPtr action; @@ -172,23 +146,6 @@ public struct Action_Data { } // namespace access -namespace font { - -public struct Size { - private int mask; - - public static implicit operator Size(int x) - { - return new Size{mask=x}; - } - public static implicit operator int(Size x) - { - return x.mask; - } -} - -} - } // namespace efl namespace evas { namespace font { diff --git a/src/lib/eolian_cxx/grammar/klass_def.hpp b/src/lib/eolian_cxx/grammar/klass_def.hpp index 24969ab37a..d8b61458ce 100644 --- a/src/lib/eolian_cxx/grammar/klass_def.hpp +++ b/src/lib/eolian_cxx/grammar/klass_def.hpp @@ -414,6 +414,39 @@ inline void type_def::set(Eolian_Expression_Type eolian_exp_type) } } +struct alias_def +{ + std::string eolian_name; + std::string cxx_name; + std::vector namespaces; + bool is_undefined; + type_def base_type {}; + documentation_def documentation; + + alias_def(Eolian_Typedecl const* alias_obj, Eolian_Unit const* unit) + { + cxx_name = eolian_name = ::eolian_typedecl_short_name_get(alias_obj); + + for(efl::eina::iterator namespace_iterator( ::eolian_typedecl_namespaces_get(alias_obj)) + , namespace_last; namespace_iterator != namespace_last; ++namespace_iterator) + { + this->namespaces.push_back((&*namespace_iterator)); + } + + Eolian_Type const* bt = ::eolian_typedecl_base_type_get(alias_obj); + if (eolian_type_type_get(bt) == EOLIAN_TYPE_UNDEFINED) + is_undefined = true; + else + { + base_type = type_def(::eolian_typedecl_base_type_get(alias_obj), unit, EOLIAN_C_TYPE_DEFAULT); + is_undefined = false; + } + + documentation = ::eolian_typedecl_documentation_get(alias_obj); + + } +}; + enum class parameter_direction { unknown, in, inout, out diff --git a/src/tests/efl_mono/Eo.cs b/src/tests/efl_mono/Eo.cs index c78027b5c6..db89fb8c4f 100644 --- a/src/tests/efl_mono/Eo.cs +++ b/src/tests/efl_mono/Eo.cs @@ -208,4 +208,20 @@ class TestKlassMethods } } +class TestTypedefs +{ + public static void basic_typedef_test() + { + test.ITesting obj = new test.Testing(); + test.MyInt input = 1900; + test.MyInt receiver; + + int ret = obj.BypassTypedef(input, out receiver); + + Test.AssertEquals((test.MyInt)ret, input); + Test.AssertEquals(receiver, input); + + } +} + } diff --git a/src/tests/efl_mono/libefl_mono_native_test.c b/src/tests/efl_mono/libefl_mono_native_test.c index 4cf06debe8..a20f1cdc89 100644 --- a/src/tests/efl_mono/libefl_mono_native_test.c +++ b/src/tests/efl_mono/libefl_mono_native_test.c @@ -3777,6 +3777,12 @@ void _test_testing_call_format_cb(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_ func_free_cb(func_data); } +Test_MyInt _test_testing_bypass_typedef(EINA_UNUSED Eo *obj, EINA_UNUSED Test_Testing_Data *pd, Test_MyInt data, Test_MyInt *receiver) +{ + *receiver = data; + return data; +} + /* Class Properties */ static int _test_testing_klass_prop = 0; diff --git a/src/tests/efl_mono/test_testing.eo b/src/tests/efl_mono/test_testing.eo index f759228136..3c15652ba5 100644 --- a/src/tests/efl_mono/test_testing.eo +++ b/src/tests/efl_mono/test_testing.eo @@ -1,5 +1,7 @@ import eina_types; +type Test.MyInt: int; + enum Test.SampleEnum { v0, v1, @@ -57,6 +59,7 @@ struct Test.StructSimple fstring: string; fmstring: mstring; fstringshare: stringshare; + fmyint: Test.MyInt; } struct Test.StructComplex { @@ -1596,6 +1599,15 @@ class Test.Testing (Efl.Object, Efl.Part) { } } + bypass_typedef { + params { + @in data: Test.MyInt; + @out receiver: Test.MyInt; + } + + return: Test.MyInt; + } + @property klass_prop @class { get {} set {}