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
This commit is contained in:
Lauro Moura 2018-05-10 22:00:07 -03:00
parent 95e3468aee
commit da6f5932f1
11 changed files with 170 additions and 63 deletions

View File

@ -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<typename OutputIterator, typename Context>
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<int, 1> {};
}
} } }
#endif

View File

@ -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";
}
}
}

View File

@ -12,6 +12,7 @@ struct class_context
inherit_native,
structs,
function_ptr,
alias,
};
wrapper_kind current_wrapper_kind;
};

View File

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

View File

@ -32,6 +32,7 @@
#include <eolian/mono/marshall_type_impl.hh>
#include <eolian/mono/marshall_annotation.hh>
#include <eolian/mono/function_pointer.hh>
#include <eolian/mono/alias_definition.hh>
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)

View File

@ -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;
}
}
/// <summary>Enum to handle resource ownership between managed and unmanaged code.</summary>
public enum Ownership {
/// <summary> The resource is owned by the managed code. It should free the handle on disposal.</summary>

View File

@ -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 {

View File

@ -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<std::string> 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<const char> 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

View File

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

View File

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

View File

@ -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 {}