eolian_cxx: Fix Eolian C++ generated wrapper inconsistencies

In convert.cc: Reading functions instead of implements to convert the
Eolian_Class. It avoids creation of methods that do not belong to the
class, in special it avoids calling the default constructor twice in the
generated code.

No longer generating one constructor in the C++ wrapper for each eolian
class constructor, since the correct behavior demands that all constructor
should be called. Now the wrappers have "constructor methods" that
must be called when creating a new object.

Updated test cases and examples to match the new interface. Some class
constructors and some test cases have to be removed since they were based
on the wrong assumption that constructors are mutually exclusive.

Created new generators for forwarding parameters and for looping over
the relevant parameters to the C++ wrapper executing a generic lambda.

Added a TODO comment regarding the call of constructor methods of all
base classes. Currently there is no base type with constructors, so this
situation should be discussed more.

Added a TODO comment regarding the way callback parameters are being
processed.
This commit is contained in:
Vitor Sousa 2014-11-11 20:37:47 -02:00
parent ed8ce801cb
commit 132abc3534
15 changed files with 452 additions and 154 deletions

View File

@ -205,45 +205,23 @@ convert_eolian_class_new(Eolian_Class const& klass)
}
void
convert_eolian_implements(efl::eolian::eo_class& cls, Eolian_Class const& klass)
convert_eolian_functions(efl::eolian::eo_class& cls, Eolian_Class const& klass)
{
efl::eina::iterator<const Eolian_Implement> itr = implements_get(klass);
efl::eina::iterator<const Eolian_Implement> end;
while (itr != end)
for(efl::eina::iterator<const Eolian_Function> first ( ::eolian_class_functions_get(&klass, EOLIAN_METHOD))
, last; first != last; ++first)
{
const Eolian_Implement impl = *itr;
assert(!!implement_function(impl));
assert(!!implement_class(impl));
Eolian_Function const& func = *implement_function(impl);
Eolian_Class const& icls = *implement_class(impl);
Eolian_Function const& func = *first;
Eolian_Function_Type const func_type = function_op_type(func);
if (implement_is_property_get(impl))
{
cls.functions.push_back
(_convert_property_get_to_function(icls, func));
}
else if (implement_is_property_set(impl))
{
cls.functions.push_back
(_convert_property_set_to_function(icls, func));
}
else if (function_op_type(func) == eolian_cxx::property.value)
{
cls.functions.push_back
(_convert_property_get_to_function(icls, func));
cls.functions.push_back
(_convert_property_set_to_function(icls, func));
}
else if (function_is_constructor(klass, func))
if (function_is_constructor(klass, func))
{
cls.constructors.push_back({
function_impl(func),
_convert_eolian_parameters(func),
convert_comments_function(icls, func)
convert_comments_function(klass, func)
});
}
else if (implement_is_visible(impl))
else if (function_is_visible(func, func_type))
{
cls.functions.push_back({
function_type(func),
@ -251,10 +229,38 @@ convert_eolian_implements(efl::eolian::eo_class& cls, Eolian_Class const& klass)
function_impl(func),
function_return_type(func),
_convert_eolian_parameters(func),
convert_comments_function(icls, func, eolian_cxx::method)
convert_comments_function(klass, func, eolian_cxx::method)
});
}
++itr;
}
for(efl::eina::iterator<const Eolian_Function> first ( ::eolian_class_functions_get(&klass, EOLIAN_PROPERTY))
, last; first != last; ++first)
{
Eolian_Function const& func = *first;
Eolian_Function_Type t = ::eolian_function_type_get(&func);
if(t == EOLIAN_PROP_GET)
{
cls.functions.push_back
(_convert_property_get_to_function(klass, func));
}
else if(t == EOLIAN_PROP_SET)
{
cls.functions.push_back
(_convert_property_set_to_function(klass, func));
}
else if(t == EOLIAN_PROPERTY)
{
cls.functions.push_back
(_convert_property_get_to_function(klass, func));
cls.functions.push_back
(_convert_property_set_to_function(klass, func));
}
else
{
std::cerr << "Error: Inconsistent type for Eolian function \'" << ::eolian_function_name_get(&func) << "\'." << std::endl;
throw std::runtime_error("Invalid Eolian function type");
}
}
}
@ -263,7 +269,7 @@ convert_eolian_class(const Eolian_Class& klass)
{
efl::eolian::eo_class cls(eolian_cxx::convert_eolian_class_new(klass));
eolian_cxx::convert_eolian_inheritances(cls, klass);
eolian_cxx::convert_eolian_implements(cls, klass);
eolian_cxx::convert_eolian_functions(cls, klass);
eolian_cxx::convert_eolian_events(cls, klass);
efl::eolian::eo_class_validate(cls);
return cls;

View File

@ -50,24 +50,6 @@ _colourable_eo_base_destructor(Eo *obj, Colourable_Data *self EINA_UNUSED)
eo_do_super(obj, MY_CLASS, eo_destructor());
}
void
_colourable_rgb_composite_constructor(Eo *obj, Colourable_Data *self, int r, int g, int b)
{
if(!_colourable_impl_logdomain)
{
_colourable_impl_logdomain
= eina_log_domain_register("colourable", EINA_COLOR_BLUE);
}
self->r = r;
self->g = g;
self->b = b;
DBG("_colourable_rgb_composite_constructor(0x%2.x, %0x2.x, %0x2.x)\n",
(unsigned int)self->r,
(unsigned int)self->g,
(unsigned int)self->b);
eo_do_super(obj, MY_CLASS, eo_constructor());
}
void
_colourable_rgb_24bits_constructor(Eo *obj, Colourable_Data *self, int rgb)
{

View File

@ -4,15 +4,6 @@ class Colourable (Eo.Base)
legacy_prefix: legacy;
data: Colourable_Data;
methods {
rgb_composite_constructor {
/*@ Composite RGB Constructor. */
legacy: null;
params {
@in int r; /*@ The red component. */
@in int g; /*@ The green component. */
@in int b; /*@ The blue component. */
}
}
rgb_24bits_constructor {
/*@ RGB Constructor. */
legacy: null;
@ -60,7 +51,6 @@ class Colourable (Eo.Base)
Eo.Base.destructor;
}
constructors {
.rgb_composite_constructor;
.rgb_24bits_constructor;
}
events {

View File

@ -34,18 +34,6 @@ _colourable_eo_base_destructor(Eo *obj, Colourable_Data *self EINA_UNUSED)
eo_do_super(obj, MY_CLASS, eo_destructor());
}
void
_colourable_rgb_composite_constructor(Eo *obj, Colourable_Data *self, int r, int g, int b)
{
EINA_CXX_DOM_LOG_DBG(domain) << std::showbase << std::hex
<< __func__ << " [ (r, g, b) = ("
<< r << ", " << g << ", " << b << ") ]" << std::endl;
self->r = r;
self->g = g;
self->b = b;
eo_do_super(obj, MY_CLASS, eo_constructor());
}
void
_colourable_rgb_24bits_constructor(Eo *obj, Colourable_Data *self, int rgb)
{

View File

@ -15,7 +15,6 @@ typedef struct _Colourable_Data Colourable_Data;
void _colourable_eo_base_constructor(Eo *obj, Colourable_Data *self);
void _colourable_eo_base_destructor(Eo *obj, Colourable_Data *self);
void _colourable_rgb_composite_constructor(Eo *obj, Colourable_Data *self, int r, int g, int b);
void _colourable_rgb_24bits_constructor(Eo *obj, Colourable_Data *self, int rgb);
void _colourable_print_colour(Eo *obj, Colourable_Data *self);
void _colourable_print_colour(Eo *obj, Colourable_Data *self);

View File

@ -27,20 +27,21 @@ void
example_callbacks()
{
int count = 0;
efl::ecore::poller poller
(ECORE_POLLER_CORE, 1,
efl::ecore::poller poller(
poller.ecore_poller_constructor(ECORE_POLLER_CORE, 1,
[&count, &poller]
{
if (++count == 5)
{
std::cout << std::endl;
ecore_main_loop_quit();
return false;
}
poller.interval_set(2*poller.interval_get());
std::cout << "."<< std::flush;
return true;
});
{
if (++count == 5)
{
std::cout << std::endl;
ecore_main_loop_quit();
return false;
}
poller.interval_set(2*poller.interval_get());
std::cout << "." << std::flush;
return true;
})
);
::ecore_main_loop_begin();
}

View File

@ -16,10 +16,6 @@ using namespace efl;
struct ColourableCircle
: efl::eo::inherit<ColourableCircle, ::colourable>
{
ColourableCircle(int r, int g, int b)
: inherit_base(r, g, b)
{}
ColourableCircle(int rgb)
: inherit_base(efl::eo::args<::colourable>(rgb))
{}
@ -52,7 +48,8 @@ main()
efl::eo::eo_init init;
eina_log_domain_level_set("colourable", EINA_LOG_LEVEL_DBG);
ColourableCircle obj1(0xc0, 0xff, 0xee);
ColourableCircle obj1(0x0);
obj1.composite_colour_set(0xc0, 0xff, 0xee);
ColourableCircle obj2(0xc0ffee);
int r, g, b;

View File

@ -18,11 +18,15 @@ main()
eina_log_domain_level_set("colourablesquare", EINA_LOG_LEVEL_DBG);
int r, g, b;
::colourable obj1(0x123456);
::colourable obj1(
obj1.colourable_rgb_24bits_constructor(0x123456)
);
obj1.colour_set(0xc0ffee);
obj1.composite_colour_get(&r, &g, &b);
::colourablesquare obj2(10);
::colourablesquare obj2(
obj2.colourablesquare_size_constructor(10)
);
obj2.composite_colour_set(r, g, b);
obj2.size_set(11);
assert(obj1.colour_get() == obj2.colour_get());

View File

@ -18,11 +18,15 @@ main()
eina_log_domain_level_set("colourablesquare", EINA_LOG_LEVEL_DBG);
int r, g, b;
::colourable obj1(0x123456);
::colourable obj1(
obj1.colourable_rgb_24bits_constructor(0x123456)
);
obj1.colour_set(0xc0ffee);
obj1.composite_colour_get(&r, &g, &b);
::colourablesquare obj2(0x123456);
::colourablesquare obj2(
obj2.colourablesquare_size_constructor(0x123456)
);
obj2.composite_colour_set(r, g, b);
obj2.size_set(11);
assert(obj1.colour_get() == obj2.colour_get());

View File

@ -77,6 +77,189 @@ operator<<(std::ostream& out, class_inheritance const& x)
return out;
}
struct constructor_functor_type_name
{
eo_constructor const& _ctor;
constructor_functor_type_name(eo_constructor const& ctor)
: _ctor(ctor)
{}
};
inline std::ostream&
operator<<(std::ostream& out, constructor_functor_type_name const& x)
{
out << "_c_" << x._ctor.name;
return out;
}
struct constructor_functor_type_decl
{
eo_constructor const& _ctor;
constructor_functor_type_decl(eo_constructor const& ctor)
: _ctor(ctor)
{}
};
inline std::ostream&
operator<<(std::ostream& out, constructor_functor_type_decl const& x)
{
out << constructor_functor_type_name(x._ctor);
auto cb_it = parameters_find_callback(x._ctor.params);
if(cb_it != x._ctor.params.cend())
{
out << "<F>";
}
return out;
}
struct functors_constructor_methods
{
eo_class const& _cls;
functors_constructor_methods(eo_class const& cls) : _cls(cls) {}
};
inline std::ostream&
operator<<(std::ostream& out, functors_constructor_methods const& x)
{
constructors_container_type::const_iterator it,
first = x._cls.constructors.cbegin(),
last = x._cls.constructors.cend();
for (it = first; it != last; ++it)
{
eo_constructor const& c = *it;
auto cb_it = parameters_find_callback(c.params);
bool has_callback = (cb_it != c.params.cend());
// Struct declaration
if(has_callback)
{
out << tab(1) << "template <typename F>" << endl;
}
out << tab(1) << "struct " << constructor_functor_type_name(c) << endl
<< tab(1) << "{" << endl;
// Struct constructor
out << tab(2) << constructor_functor_type_name(c) << "("
<< parameters_declaration(c.params) << ")"
<< parameters_cxx_generic(c.params,
[](param_data d)
{
if(d.pos == 0u)
d.out << endl << tab(3) << ": ";
else
d.out << ", ";
d.out << d.name << "(" << parameter_forward(d.type, d.name) << ")";
}
)
<< endl
<< tab(2) << "{}" << endl;
// Struct operator()
out << tab(2) << "void operator()()" << endl
<< tab(2) << "{" << endl;
if (has_callback)
{
out << tab(3) << "typedef typename std::remove_reference<F>::type function_type;" << endl
<< tab(3) << "function_type* _tmp_f = new F(this->" << (*cb_it).name << ");" << endl;
}
out << tab(3) << "::" << c.name << "(" << parameters_forward_to_c(c.params) << ");" << endl
<< tab(2) << "}" << endl;
// Struct member variables
out << tab(1) << "private:" << endl
<< parameters_cxx_generic(c.params,
[](param_data d)
{
d.out << tab(2) << parameter_type(d.type) << " " << d.name << ";" << endl;
}
);
// Close struct
out << tab(1) << "};" << endl << endl;
}
return out;
}
struct functions_constructor_methods
{
eo_class const& _cls;
functions_constructor_methods(eo_class const& cls) : _cls(cls) {}
};
inline std::ostream&
operator<<(std::ostream& out, functions_constructor_methods const& x)
{
constructors_container_type::const_iterator it,
first = x._cls.constructors.cbegin(),
last = x._cls.constructors.cend();
for (it = first; it != last; ++it)
{
eo_constructor const& c = *it;
out << comment(c.comment, 1);
unsigned cb_count = parameters_count_callbacks(c.params);
if(cb_count)
out << tab(1) << "template <typename F>" << endl;
out << tab(1) << constructor_functor_type_decl(c) << " " << c.name << "("
<< parameters_declaration(c.params) << ")" << endl
<< tab(1) << "{" << endl
<< tab(2) << "return " << constructor_functor_type_decl(c) << "("
<< parameters_forward(c.params) << ");" << endl
<< tab(1) << "}" << endl << endl;
}
return out;
}
struct constructor_with_constructor_methods
{
eo_class const& _cls;
constructor_with_constructor_methods(eo_class const& cls)
: _cls(cls)
{}
};
inline std::ostream&
operator<<(std::ostream& out, constructor_with_constructor_methods const& x)
{
//
// TODO Require constructor methods of all base classes ?
//
constructors_container_type::const_iterator it,
first = x._cls.constructors.cbegin(),
last = x._cls.constructors.cend();
for (it = first; it != last; ++it)
{
unsigned cb_count = parameters_count_callbacks((*it).params);
if(cb_count)
{
out << tab(1) << "template <typename F>" << endl;
break;
}
}
out << tab(1) << x._cls.name << "(";
for (it = first; it != last; ++it)
{
out << constructor_functor_type_decl(*it)
<< " _c" << (it-first) << ", ";
}
out << "efl::eo::parent_type _p = (efl::eo::parent = nullptr))" << endl
<< tab(2) << ": " << x._cls.name << "(_ctors_call(";
for (it = first; it != last; ++it)
{
out << "_c" << (it-first) << ", ";
}
out << "_p))" << endl
<< tab(1) << "{}" << endl << endl;
return out;
}
struct constructor_eo
{
eo_class const& _cls;
@ -222,6 +405,45 @@ operator<<(std::ostream& out, eo_class_constructors const& x)
return out;
}
struct function_call_constructor_methods
{
eo_class const& _cls;
function_call_constructor_methods(eo_class const& cls) : _cls(cls) {}
};
inline std::ostream&
operator<<(std::ostream& out, function_call_constructor_methods const& x)
{
constructors_container_type::const_iterator it,
first = x._cls.constructors.cbegin(),
last = x._cls.constructors.cend();
for (it = first; it != last; ++it)
{
unsigned cb_count = parameters_count_callbacks((*it).params);
if (cb_count)
{
out << tab(1) << "template <typename F>" << endl;
break;
}
}
out << tab(1) << "static Eo* _ctors_call(";
for (it = first; it != last; ++it)
{
out << constructor_functor_type_decl(*it) << " _c" << (it-first) << ", ";
}
out << "efl::eo::parent_type _p)" << endl
<< tab(1) << "{" << endl
<< tab(2) << "return eo_add_ref(" << x._cls.eo_name << ", _p._eo_raw, ";
for (it = first; it != last; ++it)
{
out << "_c" << (it-first) << "(); ";
}
out << ");" << endl
<< tab(1) << "}" << endl << endl;
return out;
}
} } } // namespace efl { namespace eolian { namespace grammar {
#endif // EOLIAN_CXX_STD_EO_CLASS_CONSTRUCTORS_GENERATOR_HH

View File

@ -37,15 +37,17 @@ eo_class_generator(std::ostream& out, eo_class const& cls)
<< "struct " << cls.name << endl
<< tab(2) << ": " << class_inheritance(cls)
<< '{' << endl
<< functors_constructor_methods(cls)
<< functions_constructor_methods(cls)
<< constructor_with_constructor_methods(cls)
<< constructor_eo(cls)
<< constructors(cls)
<< copy_constructor(cls)
<< destructor(cls)
<< functions(cls.functions)
<< events(cls)
<< eo_class_getter(cls)
<< "private:" << endl
<< eo_class_constructors(cls)
<< function_call_constructor_methods(cls)
<< "};" << endl
<< "static_assert(sizeof(" << cls.name << ") == sizeof(Eo*), \"sizeof(" << cls.name << ") != sizeof(Eo*)\");" << endl
<< "static_assert(std::is_standard_layout<" << cls.name << ">::value, \"'" << cls.name << "' is not standard layout\");"

View File

@ -10,6 +10,105 @@
namespace efl { namespace eolian { namespace grammar {
struct
parameter_type
{
eolian_type_instance const& _type;
parameter_type(eolian_type_instance const& t)
: _type(t)
{}
};
inline std::ostream&
operator<<(std::ostream& out, parameter_type const& x)
{
if(type_is_callback(x._type))
out << "F";
else
out << reinterpret_type(x._type);
return out;
}
struct
parameter_forward
{
eolian_type_instance const& _type;
std::string const& _name;
parameter_forward(eolian_type_instance const& type, std::string const& name)
: _type(type)
, _name(name)
{}
};
inline std::ostream&
operator<<(std::ostream& out, parameter_forward const& x)
{
if (type_is_callback(x._type))
{
out << "std::forward<F>(" << x._name << ")";
}
else
out << x._name;
return out;
}
struct param_data
{
std::ostream& out;
unsigned pos;
eolian_type_instance const& type;
std::string const& name;
int cb_idx;
bool is_cb;
param_data(std::ostream& out_, unsigned pos_, eolian_type_instance const& type_, std::string const& name_, int cb_idx_)
: out(out_)
, pos(pos_)
, type(type_)
, name(name_)
, cb_idx(cb_idx_)
, is_cb(cb_idx_ >= 0)
{}
};
template <typename T>
struct
_parameters_cxx_generic
{
parameters_container_type const& _params;
T _fparam;
_parameters_cxx_generic(parameters_container_type const& params, T fparam)
: _params(params)
, _fparam(fparam)
{}
};
template <typename T>
std::ostream&
operator<<(std::ostream& out, _parameters_cxx_generic<T> const& x)
{
int cb_idx = 0u;
auto first = x._params.cbegin(),
last = x._params.cend();
for (auto it = first; it != last; ++it)
{
if (type_is_callback((*it).type) && it+1 != last)
{
x._fparam(param_data(out, it - first, (*it).type, (*it).name, cb_idx++));
++it; // skip next.
}
else
x._fparam(param_data(out, it - first, (*it).type, (*it).name, -1));
}
return out;
}
template <typename T>
_parameters_cxx_generic<T>
parameters_cxx_generic(parameters_container_type const& params, T fparam)
{
return _parameters_cxx_generic<T>(params, fparam);
}
struct
parameters_declaration
{
@ -28,6 +127,8 @@ operator<<(std::ostream& out, parameters_declaration const& x)
{
if (it != first)
out << ", ";
// TODO What to do when callback happens in the middle of parameters
// and does not have a following userdata pointer ?
if (type_is_callback((*it).type) && it+1 != last)
{
out << "F && " << (*it).name;
@ -193,6 +294,59 @@ operator<<(std::ostream& out, constructor_parameters_list const& x)
return out;
}
struct
parameters_forward
{
parameters_container_type const& _params;
parameters_forward(parameters_container_type const& params)
: _params(params)
{}
};
inline std::ostream&
operator<<(std::ostream& out, parameters_forward const& x)
{
auto first = x._params.cbegin(), last = x._params.cend();
for (auto it = first; it != last; ++it)
{
if (it != first)
out << ", ";
out << parameter_forward((*it).type, (*it).name);
if (type_is_callback((*it).type) && it+1 != last)
{
++it; // skip next.
}
}
return out;
}
struct
parameters_forward_to_c
{
parameters_container_type const& _params;
parameters_forward_to_c(parameters_container_type const& params)
: _params(params)
{}
};
inline std::ostream&
operator<<(std::ostream& out, parameters_forward_to_c const& x)
{
auto first = x._params.cbegin(), last = x._params.cend();
for (auto it = first; it != last; ++it)
{
if (it != first)
out << ", ";
if (type_is_callback((*it).type) && it + 1 != last)
{
out << to_c((*it).type, (*it).name) << ", _tmp_f";
++it; // skip next
}
else
out << to_c((*it).type, (*it).name);
}
return out;
}
} } } // namespace efl { namespace eolian { namespace grammar {

View File

@ -28,7 +28,7 @@ static Eina_Bool _callback_callback_added(void* data EINA_UNUSED, Eo* obj EINA_U
return EINA_TRUE;
}
static void _callback_default_constructor(Eo *obj EINA_UNUSED, Callback_Data *pd EINA_UNUSED)
static void _callback_eo_base_constructor(Eo *obj EINA_UNUSED, Callback_Data *pd EINA_UNUSED)
{
pd->callbacks = 0;
eo_do_super(obj, MY_CLASS, eo_constructor());
@ -37,27 +37,6 @@ static void _callback_default_constructor(Eo *obj EINA_UNUSED, Callback_Data *pd
, &_callback_callback_added, pd);
}
static void _callback_constructor(Eo *obj EINA_UNUSED, Callback_Data *pd EINA_UNUSED, Ecore_Cb cb, void *data)
{
pd->callbacks = 0;
eo_do_super(obj, MY_CLASS, eo_constructor());
eo_event_callback_priority_add(EO_BASE_EVENT_CALLBACK_ADD, EO_CALLBACK_PRIORITY_DEFAULT
, &_callback_callback_added, pd);
cb(data);
}
static void _callback_constructor2(Eo *obj EINA_UNUSED, Callback_Data *pd EINA_UNUSED, Ecore_Cb cb, void *data
, Ecore_Cb cb2 EINA_UNUSED)
{
pd->callbacks = 0;
eo_do_super(obj, MY_CLASS, eo_constructor());
eo_event_callback_priority_add(EO_BASE_EVENT_CALLBACK_ADD, EO_CALLBACK_PRIORITY_DEFAULT
, &_callback_callback_added, pd);
cb(data);
}
static void _callback_onecallback(Eo *obj EINA_UNUSED, Callback_Data *pd EINA_UNUSED, Ecore_Cb cb, void *data)
{
cb(data);

View File

@ -3,21 +3,6 @@ class Callback (Eo.Base)
legacy_prefix: null;
data: Callback_Data;
methods {
default_constructor {
}
constructor {
params {
@in Ecore_Cb cb;
@in void* data;
}
}
constructor2 {
params {
@in Ecore_Cb cb;
@in void* data;
@in Ecore_Cb cb2;
}
}
onecallback {
params {
@in Ecore_Cb cb;
@ -32,12 +17,10 @@ class Callback (Eo.Base)
}
}
}
constructors {
.default_constructor;
.constructor;
.constructor2;
}
implements {
Eo.Base.constructor;
}
events {
call_on_add;
}
}
}

View File

@ -12,18 +12,6 @@
void foo(void*) {}
START_TEST(eolian_cxx_test_callback_constructor)
{
efl::eo::eo_init i;
bool called1 = false, called2 = false;
::callback c1 (std::bind([&called1] { called1 = true; }));
::callback c2 (std::bind([&called2] { called2 = true; }), &foo);
fail_if(!called1);
fail_if(!called2);
}
END_TEST
START_TEST(eolian_cxx_test_callback_method)
{
efl::eo::eo_init i;
@ -124,7 +112,6 @@ END_TEST
void
eolian_cxx_test_callback(TCase* tc)
{
tcase_add_test(tc, eolian_cxx_test_callback_constructor);
tcase_add_test(tc, eolian_cxx_test_callback_method);
tcase_add_test(tc, eolian_cxx_test_callback_event_add);
tcase_add_test(tc, eolian_cxx_test_callback_event_del);