forked from enlightenment/efl
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:
parent
95e3468aee
commit
da6f5932f1
|
@ -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
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ struct class_context
|
|||
inherit_native,
|
||||
structs,
|
||||
function_ptr,
|
||||
alias,
|
||||
};
|
||||
wrapper_kind current_wrapper_kind;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {}
|
||||
|
|
Loading…
Reference in New Issue