efl/src/bin/eolian_cxx/convert.cc

304 lines
9.2 KiB
C++

#include <vector>
#include <algorithm>
#include <cassert>
#include <cstddef>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <Eina.hh>
#include <Eolian.h>
#include "eo_types.hh"
#include "eo_validate.hh"
#include "safe_strings.hh"
#include "convert_comments.hh"
#include "eolian_wrappers.hh"
namespace eolian_cxx {
extern efl::eina::log_domain domain;
void
remove_repeated_base(const char* klass_name, efl::eolian::parents_container_type& cont)
{
Eolian_Class const* klass = ::eolian_class_get_by_name(klass_name);
if (!klass)
{
std::cerr << "Error: could not get eolian class name `" << klass_name << "'" << std::endl;
return;
}
Eina_Iterator* inheritances = ::eolian_class_inherits_get(klass);
void* curr = 0;
EINA_ITERATOR_FOREACH(inheritances, curr)
{
if (!curr)
continue;
const char* parent = static_cast<const char*>(curr);
cont.erase(
std::remove(cont.begin(), cont.end(), safe_lower(class_format_cxx(parent)))
, cont.end());
remove_repeated_base(parent, cont);
}
eina_iterator_free(inheritances);
}
static efl::eolian::parameters_container_type
_convert_eolian_parameters(Eina_Iterator *parameters,
Eolian_Function_Type func_type)
{
if (parameters == NULL) return {};
assert(func_type != EOLIAN_PROPERTY);
void *curr;
efl::eolian::parameters_container_type list;
EINA_ITERATOR_FOREACH(parameters, curr)
{
const Eolian_Function_Parameter *id =
(static_cast<const Eolian_Function_Parameter*>(curr));
list.push_back
({
parameter_type(*id, func_type),
parameter_name(*id)
});
}
eina_iterator_free(parameters);
return list;
}
static efl::eolian::parameters_container_type
_convert_eolian_parameters(Eolian_Function const& func, getter_t func_type)
{
return _convert_eolian_parameters
(::eolian_function_parameters_get(&func), func_type.value);
}
static efl::eolian::parameters_container_type
_convert_eolian_parameters(Eina_Iterator *parameters, getter_t func_type)
{
return _convert_eolian_parameters(parameters, func_type.value);
}
static efl::eolian::parameters_container_type
_convert_eolian_parameters(Eina_Iterator *parameters, setter_t func_type)
{
return _convert_eolian_parameters(parameters, func_type.value);
}
static efl::eolian::parameters_container_type
_convert_eolian_parameters(Eolian_Function const& func)
{
assert(function_op_type(func) != EOLIAN_PROPERTY);
return _convert_eolian_parameters
(::eolian_function_parameters_get(&func), function_op_type(func));
}
static efl::eolian::eo_function
_convert_property_set_to_function(Eolian_Class const& klass,
Eolian_Function const& prop_)
{
efl::eolian::eo_function set_ =
{
efl::eolian::eo_function::regular_,
function_name(prop_) + "_set",
function_impl(prop_) + "_set",
function_return_type(prop_, eolian_cxx::setter),
_convert_eolian_parameters(::eolian_function_parameters_get(&prop_),
eolian_cxx::setter),
convert_comments_function(klass, prop_, eolian_cxx::setter)
};
efl::eolian::parameters_container_type keys =
_convert_eolian_parameters(::eolian_property_keys_get(&prop_),
eolian_cxx::setter);
if (!keys.empty())
{
keys.reserve(keys.size() + set_.params.size());
keys.insert(keys.end(), set_.params.begin(),
set_.params.end());
set_.params = keys;
}
return set_;
}
static efl::eolian::eo_function
_convert_property_get_to_function(Eolian_Class const& klass,
Eolian_Function const& prop_)
{
efl::eolian::eo_function get_ =
{
efl::eolian::eo_function::regular_,
function_name(prop_) + "_get",
function_impl(prop_) + "_get",
function_return_type(prop_, eolian_cxx::getter),
_convert_eolian_parameters(prop_, eolian_cxx::getter),
convert_comments_function(klass, prop_, eolian_cxx::getter)
};
// if the getter has a single parameter and a void return
// it is transformed into a getter with no parameters
// that actually returns what would be the first argument.
if (get_.params.size() == 1 && efl::eolian::type_is_void(get_.ret) &&
!function_return_is_explicit_void(prop_, eolian_cxx::getter))
{
get_.ret = get_.params[0].type;
get_.params.clear();
}
else // otherwise just create the described getter
{
std::transform
(get_.params.begin(), get_.params.end(), get_.params.begin(),
[](efl::eolian::eo_parameter const& param)
{
efl::eolian::eolian_type getter_param_type =
type_to_native(param.type);
getter_param_type.native += "*";
return efl::eolian::eo_parameter
{ { getter_param_type }, param.name };
});
}
efl::eolian::parameters_container_type keys =
_convert_eolian_parameters(::eolian_property_keys_get(&prop_),
eolian_cxx::getter);
if (!keys.empty())
{
keys.reserve(keys.size() + get_.params.size());
keys.insert(keys.end(), get_.params.begin(),
get_.params.end());
get_.params = keys;
}
return get_;
}
void
convert_eolian_inheritances(efl::eolian::eo_class& cls, Eolian_Class const& klass)
{
Eina_Iterator *inheritances =
::eolian_class_inherits_get(&klass);
void *curr;
EINA_ITERATOR_FOREACH(inheritances, curr)
{
std::string parent = safe_lower(static_cast<const char*>(curr));
cls.parents.push_back(class_format_cxx(parent));
}
eina_iterator_free(inheritances);
if (cls.parents.empty())
return;
inheritances = ::eolian_class_inherits_get(&klass);
EINA_ITERATOR_FOREACH(inheritances, curr)
{
if (curr)
remove_repeated_base(static_cast<const char*>(curr), cls.parents);
}
eina_iterator_free(inheritances);
}
void
convert_eolian_events(efl::eolian::eo_class& cls, Eolian_Class const& klass)
{
efl::eolian::events_container_type events = event_list(klass);
cls.events.reserve(cls.events.size() + events.size());
cls.events.insert(cls.events.end(), events.begin(), events.end());
}
efl::eolian::eo_class
convert_eolian_class_new(Eolian_Class const& klass)
{
efl::eolian::eo_class cls;
cls.type = class_type(klass);
cls.name = class_name(klass);
cls.name_space = class_namespace_full(klass);
cls.eo_name = class_eo_name(klass);
cls.comment = convert_comments_class(klass);
return cls;
}
void
convert_eolian_functions(efl::eolian::eo_class& cls, Eolian_Class const& klass)
{
for(efl::eina::iterator<const Eolian_Function> first ( ::eolian_class_functions_get(&klass, EOLIAN_METHOD))
, last; first != last; ++first)
{
Eolian_Function const& func = *first;
Eolian_Function_Type const func_type = function_op_type(func);
if (!function_is_visible(func, func_type))
continue;
if (function_is_constructor(klass, func))
{
cls.constructors.push_back({
function_impl(func),
_convert_eolian_parameters(func),
convert_comments_function(klass, func)
});
}
else
{
cls.functions.push_back({
function_type(func),
function_name(func),
function_impl(func),
function_return_type(func),
_convert_eolian_parameters(func),
convert_comments_function(klass, func, eolian_cxx::method)
});
}
}
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 (!function_is_visible(func, t))
continue;
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");
}
}
}
efl::eolian::eo_class
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_functions(cls, klass);
eolian_cxx::convert_eolian_events(cls, klass);
efl::eolian::eo_class_validate(cls);
return cls;
}
} // namespace eolian_cxx {