374 lines
11 KiB
C++
374 lines
11 KiB
C++
|
|
#include <vector>
|
|
#include <set>
|
|
#include <map>
|
|
#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;
|
|
typedef std::map<efl::eolian::eo_event, bool> event_map;
|
|
|
|
void
|
|
add_ancestor_recursive(const char* klass_name, std::set<std::string>& ancestor)
|
|
{
|
|
if (!klass_name)
|
|
return;
|
|
|
|
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;
|
|
}
|
|
|
|
ancestor.insert(class_format_cxx(safe_str(klass_name)));
|
|
|
|
Eina_Iterator* inheritances = ::eolian_class_inherits_get(klass);
|
|
void* curr = 0;
|
|
|
|
EINA_ITERATOR_FOREACH(inheritances, curr)
|
|
{
|
|
add_ancestor_recursive(static_cast<const char*>(curr), ancestor);
|
|
}
|
|
eina_iterator_free(inheritances);
|
|
}
|
|
|
|
void
|
|
add_events_recursive(event_map& events, Eolian_Class const& klass, std::set<std::string>& ancestors)
|
|
{
|
|
for (efl::eolian::eo_event const& e : event_list(klass))
|
|
{
|
|
auto it = events.find(e);
|
|
if (it == events.end())
|
|
events[e] = true;
|
|
else
|
|
it->second = false;
|
|
}
|
|
|
|
Eina_Iterator* inheritances = ::eolian_class_inherits_get(&klass);
|
|
void* curr = 0;
|
|
|
|
EINA_ITERATOR_FOREACH(inheritances, curr)
|
|
{
|
|
const char* ancestor_name = static_cast<const char*>(curr);
|
|
if (!ancestor_name || ancestors.find(ancestor_name) != ancestors.end())
|
|
continue;
|
|
|
|
Eolian_Class const* ancestor_klass = ::eolian_class_get_by_name(ancestor_name);
|
|
if (!ancestor_klass)
|
|
{
|
|
std::cerr << "Error: could not get eolian class name `" << ancestor_name << "'" << std::endl;
|
|
continue;
|
|
}
|
|
ancestors.insert(ancestor_name);
|
|
add_events_recursive(events, *ancestor_klass, ancestors);
|
|
}
|
|
|
|
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),
|
|
parameter_name(*id)
|
|
});
|
|
}
|
|
eina_iterator_free(parameters);
|
|
return list;
|
|
}
|
|
|
|
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_scope(prop_),
|
|
function_is_beta(prop_),
|
|
function_name(prop_) + "_set",
|
|
function_impl(prop_) + "_set",
|
|
function_return_type(prop_, eolian_cxx::setter),
|
|
_convert_eolian_parameters(::eolian_property_values_get(&prop_, EOLIAN_PROP_SET),
|
|
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_PROP_SET),
|
|
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_scope(prop_),
|
|
function_is_beta(prop_),
|
|
function_name(prop_) + "_get",
|
|
function_impl(prop_) + "_get",
|
|
function_return_type(prop_, eolian_cxx::getter),
|
|
_convert_eolian_parameters(::eolian_property_values_get(&prop_, EOLIAN_PROP_GET),
|
|
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_PROP_GET),
|
|
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_;
|
|
}
|
|
|
|
static efl::eolian::eo_function
|
|
_convert_function(Eolian_Class const& klass, Eolian_Function const& func)
|
|
{
|
|
return {
|
|
function_type(func),
|
|
function_scope(func),
|
|
function_is_beta(func),
|
|
function_name(func),
|
|
function_impl(func),
|
|
function_return_type(func),
|
|
_convert_eolian_parameters(func),
|
|
convert_comments_function(klass, func, eolian_cxx::method)
|
|
};
|
|
}
|
|
|
|
|
|
void
|
|
convert_eolian_inheritances(efl::eolian::eo_class& cls, Eolian_Class const& klass)
|
|
{
|
|
Eina_Iterator *inheritances =
|
|
::eolian_class_inherits_get(&klass);
|
|
void *curr;
|
|
|
|
std::set<std::string> ancestors;
|
|
|
|
EINA_ITERATOR_FOREACH(inheritances, curr)
|
|
{
|
|
const char* klass_name = static_cast<const char*>(curr);
|
|
cls.parents.push_back(class_format_cxx(safe_str(klass_name)));
|
|
add_ancestor_recursive(klass_name, ancestors);
|
|
}
|
|
eina_iterator_free(inheritances);
|
|
|
|
cls.ancestors.assign(ancestors.begin(), ancestors.end());
|
|
}
|
|
|
|
void
|
|
convert_eolian_events(efl::eolian::eo_class& cls, Eolian_Class const& klass)
|
|
{
|
|
efl::eolian::events_container_type events = event_list(klass);
|
|
cls.own_events.reserve(cls.own_events.size() + events.size());
|
|
cls.own_events.insert(cls.own_events.end(), events.begin(), events.end());
|
|
|
|
event_map concrete_events;
|
|
std::set<std::string> ancestors;
|
|
|
|
add_events_recursive(concrete_events, klass, ancestors);
|
|
|
|
for (auto const& e : events)
|
|
{
|
|
concrete_events[e] = true;
|
|
}
|
|
|
|
for (auto const& pair : concrete_events)
|
|
{
|
|
if (pair.second)
|
|
cls.concrete_events.push_back(pair.first);
|
|
}
|
|
}
|
|
|
|
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);
|
|
if(cls.name_space.empty())
|
|
cls.name_space = "nonamespace";
|
|
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;
|
|
|
|
if (function_is_visible(func, function_op_type(func)) &&
|
|
!function_is_constructor(klass, func))
|
|
{
|
|
cls.functions.push_back(_convert_function(klass, func));
|
|
}
|
|
}
|
|
if (class_eo_name(klass) != "EO_BASE_CLASS")
|
|
for(efl::eina::iterator<const Eolian_Constructor> first ( ::eolian_class_constructors_get(&klass))
|
|
, last; first != last; ++first)
|
|
{
|
|
Eolian_Constructor const& ctor = *first;
|
|
Eolian_Function const& func = *(::eolian_constructor_function_get(&ctor));
|
|
|
|
efl::eolian::eo_function f;
|
|
if (function_op_type(func) == EOLIAN_METHOD)
|
|
f = _convert_function(klass, func);
|
|
else
|
|
f = _convert_property_set_to_function(klass, func);
|
|
|
|
|
|
(::eolian_constructor_is_optional(&ctor) ?
|
|
cls.optional_constructors :
|
|
cls.constructors
|
|
).push_back({
|
|
function_name(func),
|
|
f.impl,
|
|
f.params,
|
|
f.comment
|
|
});
|
|
}
|
|
|
|
cls.all_constructors = cls.constructors;
|
|
cls.all_constructors.insert(cls.all_constructors.end(),
|
|
cls.optional_constructors.begin(), cls.optional_constructors.end());
|
|
|
|
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 {
|