efl/src/lib/eolian_cxx/grammar/klass_def.hpp

1368 lines
44 KiB
C++
Raw Normal View History

#ifndef EOLIAN_CXX_KLASS_DEF_HH
#define EOLIAN_CXX_KLASS_DEF_HH
#include "grammar/type_traits.hpp"
#include "grammar/attributes.hpp"
#include "grammar/qualifier_def.hpp"
#include "grammar/string.hpp"
#include "grammar/sequence.hpp"
#include "grammar/kleene.hpp"
#include "grammar/case.hpp"
#include <Eolian.h>
#include <Eina.hh>
#include <vector>
#include <memory>
#include <set>
namespace efl { namespace eolian { namespace grammar {
namespace attributes {
struct complex_type_def;
}
namespace attributes {
template <typename...Args, std::size_t I>
bool lexicographical_compare_impl(std::tuple<Args...> const&
, std::tuple<Args...> const&
, std::integral_constant<std::size_t, I>
, std::true_type)
{
return true;
}
template <typename...Args, std::size_t I>
bool lexicographical_compare_impl(std::tuple<Args...> const& lhs
, std::tuple<Args...> const& rhs
, std::integral_constant<std::size_t, I>
, std::false_type)
{
return std::get<I>(lhs) < std::get<I>(rhs)
|| (!(std::get<I>(rhs) < std::get<I>(lhs))
&& lexicographical_compare_impl(lhs, rhs, std::integral_constant<std::size_t, I+1>()
, std::integral_constant<bool, I + 1 == sizeof...(Args)>())
)
;
}
template <typename...Args>
bool lexicographical_compare(std::tuple<Args...> const& lhs
, std::tuple<Args...> const& rhs)
{
return lexicographical_compare_impl(lhs, rhs, std::integral_constant<std::size_t, 0ul>(), std::false_type());
}
template <typename T, typename U>
bool lexicographical_compare(std::tuple<T, U> const& lhs
, std::tuple<T, U> const& rhs)
{
return std::get<0>(lhs) < std::get<0>(rhs)
|| (!(std::get<0>(rhs) < std::get<0>(lhs))
&& std::get<1>(lhs) < std::get<1>(rhs));
}
enum class typedecl_type
{
unknown,
struct_,
struct_opaque,
enum_,
alias,
function_ptr,
};
inline typedecl_type typedecl_type_get(Eolian_Typedecl const* decl)
{
if (!decl)
return typedecl_type::unknown;
Eolian_Typedecl_Type t = eolian_typedecl_type_get(decl);
switch (t)
{
case EOLIAN_TYPEDECL_UNKNOWN: return typedecl_type::unknown;
case EOLIAN_TYPEDECL_STRUCT: return typedecl_type::struct_;
case EOLIAN_TYPEDECL_STRUCT_OPAQUE: return typedecl_type::struct_opaque;
case EOLIAN_TYPEDECL_ENUM: return typedecl_type::enum_;
case EOLIAN_TYPEDECL_ALIAS: return typedecl_type::alias;
case EOLIAN_TYPEDECL_FUNCTION_POINTER: return typedecl_type::function_ptr;
default: return typedecl_type::unknown;
}
}
struct type_def;
bool operator==(type_def const& rhs, type_def const& lhs);
bool operator!=(type_def const& rhs, type_def const& lhs);
enum class class_type
{
regular, abstract_, mixin, interface_
};
struct klass_name
{
std::vector<std::string> namespaces;
std::string eolian_name;
qualifier_def base_qualifier;
class_type type;
klass_name() {
}
klass_name(std::vector<std::string> namespaces
, std::string eolian_name, qualifier_def base_qualifier
, class_type type)
: namespaces(namespaces), eolian_name(eolian_name), base_qualifier(base_qualifier)
, type(type) {}
klass_name(Eolian_Class const* klass, qualifier_def base_qualifier)
2018-03-12 08:03:37 -07:00
: eolian_name( ::eolian_class_short_name_get(klass))
, base_qualifier(base_qualifier)
{
for(efl::eina::iterator<const char> namespace_iterator ( ::eolian_class_namespaces_get(klass))
, namespace_last; namespace_iterator != namespace_last; ++namespace_iterator)
{
namespaces.push_back(&*namespace_iterator);
}
switch(eolian_class_type_get(klass))
{
case EOLIAN_CLASS_REGULAR:
type = class_type::regular;
break;
case EOLIAN_CLASS_ABSTRACT:
type = class_type::abstract_;
break;
case EOLIAN_CLASS_MIXIN:
type = class_type::mixin;
break;
case EOLIAN_CLASS_INTERFACE:
type = class_type::interface_;
break;
default:
throw std::runtime_error("Class with unknown type");
}
}
};
inline bool operator==(klass_name const& lhs, klass_name const& rhs)
{
return lhs.namespaces == rhs.namespaces && lhs.eolian_name == rhs.eolian_name
&& lhs.base_qualifier == rhs.base_qualifier/* && lhs.pointers == rhs.pointers*/;
}
inline bool operator!=(klass_name const& lhs, klass_name const& rhs)
{
return !(lhs == rhs);
}
inline bool operator<(klass_name const& lhs, klass_name const& rhs)
{
typedef std::tuple<std::vector<std::string>const&
, std::string const&
, qualifier_def const&
, class_type
> tuple_type;
return lexicographical_compare(tuple_type(lhs.namespaces, lhs.eolian_name
, lhs.base_qualifier
, lhs.type)
, tuple_type(rhs.namespaces, rhs.eolian_name
, rhs.base_qualifier
, rhs.type));
}
struct documentation_def
{
std::string summary;
std::string description;
std::string since;
std::vector<std::string> desc_paragraphs;
documentation_def() {}
documentation_def(std::string summary, std::string description, std::string since)
: summary(summary), description(description), since(since)
{}
documentation_def(Eolian_Documentation const* eolian_doc)
{
const char *str;
if (!eolian_doc)
return;
str = eolian_documentation_summary_get(eolian_doc);
if (str)
summary = str;
str = eolian_documentation_description_get(eolian_doc);
if (str)
description = str;
str = eolian_documentation_since_get(eolian_doc);
if (str)
since = str;
efl::eina::ptr_list<const char> l(eolian_documentation_string_split(description.c_str()));
for (auto&& i : l)
desc_paragraphs.push_back({&i});
}
friend inline bool operator==(documentation_def const& lhs, documentation_def const& rhs)
{
return lhs.summary == rhs.summary
&& lhs.description == rhs.description
&& lhs.since == rhs.since;
}
};
template <>
struct tuple_element<0ul, klass_name>
{
typedef std::vector<std::string> type;
static type& get(klass_name& klass) { return klass.namespaces; }
static type const& get(klass_name const& klass) { return klass.namespaces; }
};
template <>
struct tuple_element<1ul, klass_name>
{
typedef std::string type;
static type& get(klass_name& klass) { return klass.eolian_name; }
static type const& get(klass_name const& klass) { return klass.eolian_name; }
};
template <int N>
struct tuple_element<N, klass_name const> : tuple_element<N, klass_name> {};
template <int N>
typename tuple_element<N, klass_name>::type&
get(klass_name& klass)
{
return tuple_element<N, klass_name>::get(klass);
}
template <int N>
typename tuple_element<N, klass_name>::type const&
get(klass_name const& klass)
{
return tuple_element<N, klass_name>::get(klass);
}
struct regular_type_def
{
regular_type_def() : type_type(typedecl_type::unknown), is_undefined(false) {}
regular_type_def(std::string base_type, qualifier_def qual, std::vector<std::string> namespaces
, typedecl_type type_type = typedecl_type::unknown, bool is_undefined = false)
: base_type(std::move(base_type)), base_qualifier(qual), namespaces(std::move(namespaces))
, type_type(type_type), is_undefined(is_undefined) {}
bool is_type(typedecl_type tt) const { return type_type == tt; }
bool is_unknown() const { return is_type(typedecl_type::unknown); }
bool is_struct() const { return is_type(typedecl_type::struct_); }
bool is_struct_opaque() const { return is_type(typedecl_type::struct_opaque); }
bool is_enum() const { return is_type(typedecl_type::enum_); }
bool is_alias() const { return is_type(typedecl_type::alias); }
bool is_function_ptr() const { return is_type(typedecl_type::function_ptr); }
std::string base_type;
qualifier_def base_qualifier;
std::vector<std::string> namespaces;
typedecl_type type_type;
bool is_undefined;
};
inline bool operator==(regular_type_def const& rhs, regular_type_def const& lhs)
{
return rhs.base_type == lhs.base_type && rhs.base_qualifier == lhs.base_qualifier;
}
inline bool operator!=(regular_type_def const& rhs, regular_type_def const& lhs)
{
return !(rhs == lhs);
}
struct complex_type_def
{
regular_type_def outer;
std::vector<type_def> subtypes;
};
inline bool operator==(complex_type_def const& lhs, complex_type_def const& rhs)
{
return lhs.outer == rhs.outer && lhs.subtypes == rhs.subtypes;
}
inline bool operator!=(complex_type_def const& lhs, complex_type_def const& rhs)
{
return !(lhs == rhs);
}
struct type_def
{
2016-08-15 10:47:00 -07:00
typedef eina::variant<klass_name, regular_type_def, complex_type_def> variant_type;
variant_type original_type;
std::string c_type;
bool has_own;
bool is_ptr;
type_def() {}
type_def(variant_type original_type, std::string c_type, bool has_own)
: original_type(original_type), c_type(c_type), has_own(has_own) {}
type_def(Eolian_Type const* eolian_type, Eolian_Unit const* unit, Eolian_C_Type_Type ctype)
{
set(eolian_type, unit, ctype);
}
void set(Eolian_Type const* eolian_type, Eolian_Unit const* unit, Eolian_C_Type_Type ctype);
void set(Eolian_Expression_Type eolian_exp_type);
friend inline bool operator<(type_def const& lhs, type_def const& rhs)
{
return lhs.c_type < rhs.c_type;
}
};
struct get_qualifier_visitor
{
typedef qualifier_def result_type;
template <typename T>
qualifier_def operator()(T const& object) const
{
return object.base_qualifier;
}
qualifier_def operator()(complex_type_def const& complex) const
{
return complex.outer.base_qualifier;
}
};
inline bool operator==(type_def const& lhs, type_def const& rhs)
{
return lhs.original_type == rhs.original_type && lhs.c_type == rhs.c_type;
}
inline bool operator!=(type_def const& lhs, type_def const& rhs)
{
return !(lhs == rhs);
}
type_def const void_ {attributes::regular_type_def{"void", {qualifier_info::is_none, {}}, {}}, "void", false};
inline void type_def::set(Eolian_Type const* eolian_type, Eolian_Unit const* unit, Eolian_C_Type_Type ctype)
{
c_type = ::eolian_type_c_type_get(eolian_type, ctype);
// ::eina_stringshare_del(stringshare); // this crashes
Eolian_Type const* stp = eolian_type_base_type_get(eolian_type);
has_own = !!::eolian_type_is_owned(eolian_type);
is_ptr = !!::eolian_type_is_ptr(eolian_type);
switch( ::eolian_type_type_get(eolian_type))
{
case EOLIAN_TYPE_VOID:
original_type = attributes::regular_type_def{"void", {qualifiers(eolian_type), {}}, {}};
break;
case EOLIAN_TYPE_REGULAR:
if (!stp)
{
bool is_undefined = false;
Eolian_Typedecl const* decl = eolian_type_typedecl_get(eolian_type);
typedecl_type type_type = (decl ? typedecl_type_get(decl) : typedecl_type::unknown);
if(decl && eolian_typedecl_type_get(decl) == EOLIAN_TYPEDECL_ALIAS)
{
Eolian_Type const* aliased = eolian_typedecl_base_type_get(decl);
if(aliased && eolian_type_type_get(aliased) == EOLIAN_TYPE_UNDEFINED)
{
is_undefined = true;
}
}
if(c_type == "va_list *")
throw std::runtime_error("");
std::vector<std::string> namespaces;
for(efl::eina::iterator<const char> namespace_iterator( ::eolian_type_namespaces_get(eolian_type))
, namespace_last; namespace_iterator != namespace_last; ++namespace_iterator)
namespaces.push_back(&*namespace_iterator);
2018-03-12 08:28:28 -07:00
original_type = {regular_type_def{ ::eolian_type_short_name_get(eolian_type), {qualifiers(eolian_type), {}}, namespaces, type_type, is_undefined}};
}
else
{
complex_type_def complex
2018-03-12 08:28:28 -07:00
{{::eolian_type_short_name_get(eolian_type), {qualifiers(eolian_type), {}}, {}}, {}};
while (stp)
{
complex.subtypes.push_back({stp, unit, EOLIAN_C_TYPE_DEFAULT});
stp = eolian_type_next_type_get(stp);
}
original_type = complex;
}
break;
case EOLIAN_TYPE_CLASS:
{
Eolian_Class const* klass = eolian_type_class_get(eolian_type);
original_type = klass_name(klass, {qualifiers(eolian_type), {}});
}
break;
default:
throw std::runtime_error("Type not supported");
break;
}
}
inline void type_def::set(Eolian_Expression_Type eolian_exp_type)
{
switch(eolian_exp_type)
{
case EOLIAN_EXPR_INT:
original_type = attributes::regular_type_def{"int", {{}, {}}, {}};
c_type = "int";
break;
default:
// FIXME implement the remaining types
EINA_LOG_ERR("Unsupported expression type");
std::abort();
break;
}
}
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
};
namespace detail {
struct add_optional_qualifier_visitor
{
typedef void result_type;
template <typename T>
void operator()(T& object) const
{
object.base_qualifier.qualifier |= qualifier_info::is_optional;
}
void operator()(complex_type_def& complex) const
{
(*this)(complex.outer);
}
};
}
struct parameter_def
{
parameter_direction direction;
type_def type;
std::string param_name;
documentation_def documentation;
Eolian_Unit const* unit;
friend inline bool operator==(parameter_def const& lhs, parameter_def const& rhs)
{
return lhs.direction == rhs.direction
&& lhs.type == rhs.type
&& lhs.param_name == rhs.param_name
&& lhs.documentation == rhs.documentation;
}
friend inline bool operator!=(parameter_def const& lhs, parameter_def const& rhs)
{
return !(lhs == rhs);
}
parameter_def(parameter_direction direction, type_def type, std::string param_name,
documentation_def documentation, Eolian_Unit const* unit)
: direction(std::move(direction)), type(std::move(type)), param_name(std::move(param_name)), documentation(documentation), unit(unit) {}
parameter_def(Eolian_Function_Parameter const* param, Eolian_Unit const* unit)
: type( ::eolian_parameter_type_get(param), unit, EOLIAN_C_TYPE_PARAM)
, param_name( ::eolian_parameter_name_get(param)), unit(unit)
{
Eolian_Parameter_Dir direction = ::eolian_parameter_direction_get(param);
switch(direction)
{
case EOLIAN_UNKNOWN_PARAM:
case EOLIAN_IN_PARAM:
this->direction = parameter_direction::in;
break;
case EOLIAN_INOUT_PARAM:
this->direction = parameter_direction::inout;
break;
case EOLIAN_OUT_PARAM:
this->direction = parameter_direction::out;
break;
}
if( ::eolian_parameter_is_optional(param))
type.original_type.visit(detail::add_optional_qualifier_visitor{});
documentation = eolian_parameter_documentation_get(param);
}
};
template <>
struct tuple_element<0ul, parameter_def>
{
typedef parameter_direction type;
static type const& get(parameter_def const& p) { return p.direction; }
static type& get(parameter_def& p) { return p.direction; }
};
template <>
struct tuple_element<1ul, parameter_def>
{
typedef type_def type;
static type const& get(parameter_def const& p) { return p.type; }
static type& get(parameter_def& p) { return p.type; }
};
template <>
struct tuple_element<2ul, parameter_def>
{
typedef std::string type;
static type const& get(parameter_def const& p) { return p.param_name; }
static type& get(parameter_def& p) { return p.param_name; }
};
template <>
struct tuple_element<3ul, parameter_def>
{
typedef std::string type;
static type const& get(parameter_def const& p) { return p.type.c_type; }
static type& get(parameter_def& p) { return p.type.c_type; }
};
template <int I>
typename tuple_element<I, parameter_def>::type const& get(parameter_def const& p)
{ return tuple_element<I, parameter_def>::get(p); }
template <int I>
typename tuple_element<I, parameter_def>::type& get(parameter_def& p)
{ return tuple_element<I, parameter_def>::get(p); }
enum class function_type
{
unresolved,
property,
prop_set,
prop_get,
method,
function_pointer
};
struct function_def
{
klass_name klass; // Klass information for function_def as method
type_def return_type;
std::string name;
std::vector<parameter_def> parameters;
std::string c_name;
std::string filename;
std::vector<std::string> namespaces; // Namespaces for top-level function pointers
documentation_def documentation;
documentation_def return_documentation;
documentation_def property_documentation;
function_type type;
bool is_beta;
bool is_protected;
bool is_static;
Eolian_Unit const* unit;
friend inline bool operator==(function_def const& lhs, function_def const& rhs)
{
return lhs.klass == rhs.klass
&& lhs.return_type == rhs.return_type
&& lhs.name == rhs.name
&& lhs.parameters == rhs.parameters
&& lhs.c_name == rhs.c_name
&& lhs.filename == rhs.filename
&& lhs.namespaces == rhs.namespaces
&& lhs.documentation == rhs.documentation
&& lhs.return_documentation == rhs.return_documentation
&& lhs.property_documentation == rhs.property_documentation
&& lhs.type == rhs.type
&& lhs.is_beta == rhs.is_beta
&& lhs.is_protected == rhs.is_protected
&& lhs.is_static == rhs.is_static;
}
friend inline bool operator!=(function_def const& lhs, function_def const& rhs)
{
return !(lhs == rhs);
}
function_def() = default;
function_def(klass_name _klass,
type_def _return_type, std::string const& _name,
std::vector<parameter_def> const& _parameters,
std::string const& _c_name,
std::string _filename,
std::vector<std::string> const& _namespaces,
documentation_def _documentation,
documentation_def _return_documentation,
documentation_def _property_documentation,
function_type _type,
bool _is_beta = false,
bool _is_protected = false,
Eolian_Unit const* unit = nullptr)
: klass(_klass), return_type(_return_type), name(_name),
parameters(_parameters), c_name(_c_name), filename(_filename),
namespaces(_namespaces),
documentation(_documentation),
return_documentation(_return_documentation),
property_documentation(_property_documentation),
type(_type),
is_beta(_is_beta), is_protected(_is_protected),
unit(unit) {}
function_def( ::Eolian_Function const* function, Eolian_Function_Type type, Eolian_Typedecl const* tp, Eolian_Unit const* unit)
: return_type(void_), unit(unit)
{
Eolian_Type const* r_type = ::eolian_function_return_type_get(function, type);
name = ::eolian_function_name_get(function);
if(r_type)
return_type.set(r_type, unit, EOLIAN_C_TYPE_RETURN);
if(type == EOLIAN_METHOD || type == EOLIAN_FUNCTION_POINTER)
{
for(efl::eina::iterator<Eolian_Function_Parameter> param_iterator ( ::eolian_function_parameters_get(function))
, param_last; param_iterator != param_last; ++param_iterator)
{
parameters.push_back({&*param_iterator, unit});
}
}
else if(type == EOLIAN_PROP_GET || type == EOLIAN_PROP_SET)
{
if(type == EOLIAN_PROP_GET)
name += "_get";
else
name += "_set";
for(efl::eina::iterator<Eolian_Function_Parameter> param_iterator
( ::eolian_property_keys_get(function, type))
, param_last; param_iterator != param_last; ++param_iterator)
{
parameters.push_back({&*param_iterator, unit});
}
std::vector<parameter_def> values;
for(efl::eina::iterator<Eolian_Function_Parameter> param_iterator
( ::eolian_property_values_get(function, type))
, param_last; param_iterator != param_last; ++param_iterator)
{
values.push_back({&*param_iterator, unit});
}
if(!r_type && type == EOLIAN_PROP_GET && values.size() == 1)
{
return_type = values[0].type;
}
else if(type == EOLIAN_PROP_GET)
{
for(auto&& v : values)
{
v.direction = parameter_direction::out;
parameters.push_back(v);
}
}
else
parameters.insert(parameters.end(), values.begin(), values.end());
}
c_name = eolian_function_full_c_name_get(function, type, EINA_FALSE);
if (type != EOLIAN_FUNCTION_POINTER)
{
const Eolian_Class *eolian_klass = eolian_function_class_get(function);
filename = eolian_object_file_get((const Eolian_Object *)eolian_klass);
klass = klass_name(eolian_klass,
{attributes::qualifier_info::is_none, std::string()});
}
else
{
filename = "";
if (tp)
{
for (efl::eina::iterator<const char> ns_iterator(::eolian_typedecl_namespaces_get(tp)), ns_last;
ns_iterator != ns_last;
ns_iterator++)
namespaces.push_back(&*ns_iterator);
}
}
is_beta = eolian_function_is_beta(function);
is_protected = eolian_function_scope_get(function, type) == EOLIAN_SCOPE_PROTECTED;
is_static = eolian_function_is_class(function);
return_documentation = eolian_function_return_documentation_get(function, type);
Eolian_Implement const* implement = eolian_function_implement_get(function);
if (!implement)
return;
documentation = eolian_implement_documentation_get(implement, type);
if (type == EOLIAN_PROP_GET || type == EOLIAN_PROP_SET)
property_documentation = eolian_implement_documentation_get(implement, EOLIAN_PROPERTY);
switch (type)
{
case EOLIAN_UNRESOLVED:
this->type = function_type::unresolved;
break;
case EOLIAN_PROPERTY:
this->type = function_type::property;
break;
case EOLIAN_PROP_GET:
this->type = function_type::prop_get;
break;
case EOLIAN_PROP_SET:
this->type = function_type::prop_set;
break;
case EOLIAN_METHOD:
this->type = function_type::method;
break;
case EOLIAN_FUNCTION_POINTER:
this->type = function_type::function_pointer;
break;
}
}
std::string template_statement() const
{
std::string statement;
char template_typename = 'F';
for (auto const& param : this->parameters)
{
attributes::regular_type_def const* typ =
efl::eina::get<attributes::regular_type_def>(&param.type.original_type);
if (typ && typ->is_function_ptr())
{
char typenam[2] = { 0, };
typenam[0] = template_typename++;
if (statement.empty())
statement = std::string("template <typename ") + typenam;
else
statement += std::string(", typename ") + typenam;
}
}
if (statement.empty()) return statement;
else return statement + ">";
}
std::vector<std::string> opening_statements() const
{
std::vector<std::string> statements;
char template_typename = 'F';
for (auto const& param : this->parameters)
{
attributes::regular_type_def const* typ =
efl::eina::get<attributes::regular_type_def>(&param.type.original_type);
if (typ && typ->is_function_ptr())
{
char typenam[2] = { 0, };
typenam[0] = template_typename++;
std::string statement = "auto fw_" + param.param_name + " = new ::efl::eolian::function_wrapper<";
statement += param.type.c_type + ", " + typenam + ">(" + param.param_name + ");";
statements.push_back(statement);
}
}
return statements;
}
};
template <>
struct tuple_element<0ul, function_def>
{
typedef type_def type;
static type& get(function_def& f) { return f.return_type; }
static type const& get(function_def const& f) { return f.return_type; }
};
template <>
struct tuple_element<1ul, function_def>
{
typedef std::string type;
static type& get(function_def& f) { return f.name; }
static type const& get(function_def const& f) { return f.name; }
};
template <>
struct tuple_element<2ul, function_def>
{
typedef std::vector<parameter_def> type;
static type& get(function_def& f) { return f.parameters; }
static type const& get(function_def const& f) { return f.parameters; }
};
// template <int N>
// struct tuple_element<N, function_def const> : tuple_element<N, function_def> {};
// template <int N>
// struct tuple_element<N, function_def&> : tuple_element<N, function_def> {};
// template <int N>
// struct tuple_element<N, function_def const&> : tuple_element<N, function_def> {};
// template <std::size_t I>
// typename tuple_element<I, function_def>::type const&
// get(function_def const& f)
// {
// return tuple_element<I, function_def>::get(f);
// }
// template <std::size_t I>
// typename tuple_element<I, function_def>::type&
// get(function_def& f)
// {
// return tuple_element<I, function_def>::get(f);
// }
struct compare_klass_name_by_name
{
bool operator()(klass_name const& lhs, klass_name const& rhs) const
{
return lhs.namespaces < rhs.namespaces
|| (!(rhs.namespaces < lhs.namespaces) && lhs.eolian_name < rhs.eolian_name);
}
};
struct event_def
{
klass_name klass;
eina::optional<type_def> type;
std::string name, c_name;
bool beta, protect;
documentation_def documentation;
friend inline bool operator==(event_def const& lhs, event_def const& rhs)
{
return lhs.klass == rhs.klass
&& lhs.type == rhs.type
&& lhs.name == rhs.name
&& lhs.c_name == rhs.c_name
&& lhs.beta == rhs.beta
&& lhs.protect == rhs.protect
&& lhs.documentation == rhs.documentation;
}
friend inline bool operator!=(event_def const& lhs, event_def const& rhs)
{
return !(lhs == rhs);
}
event_def(klass_name _klass, type_def type, std::string name, std::string c_name,
bool beta, bool protect, documentation_def documentation)
: klass(_klass), type(type), name(name), c_name(c_name), beta(beta), protect(protect)
, documentation(documentation) {}
event_def(Eolian_Event const* event, Eolian_Class const* cls, Eolian_Unit const* unit)
: klass(cls, {attributes::qualifier_info::is_none, std::string()})
, type( ::eolian_event_type_get(event) ? eina::optional<type_def>{{::eolian_event_type_get(event), unit, EOLIAN_C_TYPE_DEFAULT}} : eina::optional<type_def>{})
, name( ::eolian_event_name_get(event))
, c_name( ::eolian_event_c_name_get(event))
, beta( ::eolian_event_is_beta(event))
, protect( ::eolian_event_scope_get(event) == EOLIAN_SCOPE_PROTECTED)
, documentation( ::eolian_event_documentation_get(event)) {}
};
template <>
struct tuple_element<0, event_def>
{
typedef eina::optional<type_def> type;
static type& get(event_def& def) { return def.type; }
static type const& get(event_def const& def) { return def.type; }
};
template <>
struct tuple_element<1, event_def>
{
typedef std::string type;
static type& get(event_def& def) { return def.name; }
static type const& get(event_def const& def) { return def.name; }
};
template <>
struct tuple_element<2, event_def>
{
typedef std::string type;
static type& get(event_def& def) { return def.c_name; }
static type const& get(event_def const& def) { return def.c_name; }
};
template <int N>
struct tuple_element<N, event_def const> : tuple_element<N, event_def> {};
template <int N>
auto get(event_def const& def) -> decltype(tuple_element<N, event_def>::get(def))
{
return tuple_element<N, event_def>::get(def);
}
template <int N>
auto get(event_def& def) -> decltype(tuple_element<N, event_def>::get(def))
{
return tuple_element<N, event_def>::get(def);
}
struct part_def
{
klass_name klass;
std::string name;
documentation_def documentation;
//bool beta, protect; // can it be applied??
friend inline bool operator==(part_def const& lhs, part_def const& rhs)
{
return lhs.klass == rhs.klass
&& lhs.name == rhs.name;
}
friend inline bool operator!=(part_def const& lhs, part_def const& rhs)
{
return !(lhs == rhs);
}
friend inline bool operator<(part_def const& lhs, part_def const& rhs)
{
return lhs.name < rhs.name ||
lhs.klass < rhs.klass;
}
part_def(Eolian_Part const* part, Eolian_Unit const*)
: klass(klass_name(::eolian_part_class_get(part), {attributes::qualifier_info::is_none, std::string()}))
, name(::eolian_part_name_get(part))
, documentation(::eolian_part_documentation_get(part)) {}
};
inline Eolian_Class const* get_klass(klass_name const& klass_name_, Eolian_Unit const* unit);
struct klass_def
{
std::string eolian_name;
std::string cxx_name;
std::string filename;
documentation_def documentation;
std::vector<std::string> namespaces;
std::vector<function_def> functions;
std::set<klass_name, compare_klass_name_by_name> inherits;
class_type type;
std::vector<event_def> events;
std::set<klass_name, compare_klass_name_by_name> immediate_inherits;
std::set<part_def> parts;
Eolian_Unit const* unit;
friend inline bool operator==(klass_def const& lhs, klass_def const& rhs)
{
return lhs.eolian_name == rhs.eolian_name
&& lhs.cxx_name == rhs.cxx_name
&& lhs.filename == lhs.filename
&& lhs.namespaces == rhs.namespaces
&& lhs.functions == rhs.functions
&& lhs.inherits == rhs.inherits
&& lhs.type == rhs.type
&& lhs.events == rhs.events
&& lhs.parts == rhs.parts;
}
friend inline bool operator!=(klass_def const& lhs, klass_def const& rhs)
{
return !(lhs == rhs);
}
friend inline bool operator<(klass_def const& lhs, klass_def const& rhs)
{
return lhs.eolian_name < rhs.eolian_name
|| lhs.cxx_name < rhs.cxx_name
|| lhs.namespaces < rhs.namespaces
|| lhs.parts < rhs.parts;
}
klass_def(std::string eolian_name, std::string cxx_name, std::string filename
, documentation_def documentation
, std::vector<std::string> namespaces
, std::vector<function_def> functions
, std::set<klass_name, compare_klass_name_by_name> inherits
, class_type type
, std::set<klass_name, compare_klass_name_by_name> immediate_inherits)
: eolian_name(eolian_name), cxx_name(cxx_name), filename(filename)
, documentation(documentation)
, namespaces(namespaces)
, functions(functions), inherits(inherits), type(type)
, immediate_inherits(immediate_inherits)
{}
klass_def(std::string _eolian_name, std::string _cxx_name
, std::vector<std::string> _namespaces
, std::vector<function_def> _functions
, std::set<klass_name, compare_klass_name_by_name> _inherits
, class_type _type, Eolian_Unit const* unit)
: eolian_name(_eolian_name), cxx_name(_cxx_name)
, namespaces(_namespaces)
, functions(_functions), inherits(_inherits), type(_type), unit(unit)
{}
klass_def(Eolian_Class const* klass, Eolian_Unit const* unit) : unit(unit)
{
for(efl::eina::iterator<const char> namespace_iterator( ::eolian_class_namespaces_get(klass))
, namespace_last; namespace_iterator != namespace_last; ++namespace_iterator)
{
this->namespaces.push_back(&*namespace_iterator);
}
2018-03-12 08:03:37 -07:00
cxx_name = eolian_name = eolian_class_short_name_get(klass);
filename = eolian_object_file_get((const Eolian_Object *)klass);
for(efl::eina::iterator<Eolian_Function const> eolian_functions ( ::eolian_class_functions_get(klass, EOLIAN_PROPERTY))
, functions_last; eolian_functions != functions_last; ++eolian_functions)
{
Eolian_Function const* function = &*eolian_functions;
Eolian_Function_Type func_type = ::eolian_function_type_get(function);
if(func_type == EOLIAN_PROPERTY)
{
try {
if(! ::eolian_function_is_legacy_only(function, EOLIAN_PROP_GET)
&& ::eolian_function_scope_get(function, EOLIAN_PROP_GET) != EOLIAN_SCOPE_PRIVATE)
functions.push_back({function, EOLIAN_PROP_GET, NULL, unit});
} catch(std::exception const&) {}
try {
if(! ::eolian_function_is_legacy_only(function, EOLIAN_PROP_SET)
&& ::eolian_function_scope_get(function, EOLIAN_PROP_SET) != EOLIAN_SCOPE_PRIVATE)
functions.push_back({function, EOLIAN_PROP_SET, NULL, unit});
} catch(std::exception const&) {}
}
else
try {
if(! ::eolian_function_is_legacy_only(function, func_type)
&& ::eolian_function_scope_get(function, func_type) != EOLIAN_SCOPE_PRIVATE)
functions.push_back({function, func_type, NULL, unit});
} catch(std::exception const&) {}
}
for(efl::eina::iterator<Eolian_Function const> eolian_functions ( ::eolian_class_functions_get(klass, EOLIAN_METHOD))
, functions_last; eolian_functions != functions_last; ++eolian_functions)
{
try {
Eolian_Function const* function = &*eolian_functions;
Eolian_Function_Type func_type = eolian_function_type_get(function);
if(! ::eolian_function_is_legacy_only(function, EOLIAN_METHOD)
&& ::eolian_function_scope_get(function, func_type) != EOLIAN_SCOPE_PRIVATE)
functions.push_back({function, EOLIAN_METHOD, NULL, unit});
} catch(std::exception const&) {}
}
if(::eolian_class_parent_get(klass))
immediate_inherits.insert({::eolian_class_parent_get(klass), {}});
for(efl::eina::iterator<Eolian_Class const> inherit_iterator ( ::eolian_class_extensions_get(klass))
, inherit_last; inherit_iterator != inherit_last; ++inherit_iterator)
{
Eolian_Class const* inherit = &*inherit_iterator;
immediate_inherits.insert({inherit, {}});
}
std::function<void(Eolian_Class const*)> inherit_algo =
[&] (Eolian_Class const* inherit_klass)
{
if(::eolian_class_parent_get(inherit_klass))
{
Eolian_Class const* inherit = ::eolian_class_parent_get(inherit_klass);
inherits.insert({inherit, {}});
inherit_algo(inherit);
}
for(efl::eina::iterator<Eolian_Class const> inherit_iterator ( ::eolian_class_extensions_get(inherit_klass))
, inherit_last; inherit_iterator != inherit_last; ++inherit_iterator)
{
Eolian_Class const* inherit = &*inherit_iterator;
inherits.insert({inherit, {}});
inherit_algo(inherit);
}
};
inherit_algo(klass);
for(efl::eina::iterator<Eolian_Part const> parts_itr ( ::eolian_class_parts_get(klass))
, parts_last; parts_itr != parts_last; ++parts_itr)
{
parts.insert({&*parts_itr, unit});
}
switch(eolian_class_type_get(klass))
{
case EOLIAN_CLASS_REGULAR:
type = class_type::regular;
break;
case EOLIAN_CLASS_ABSTRACT:
type = class_type::abstract_;
break;
case EOLIAN_CLASS_MIXIN:
type = class_type::mixin;
break;
case EOLIAN_CLASS_INTERFACE:
type = class_type::interface_;
break;
default:
throw std::runtime_error("Class with unknown type");
}
for(efl::eina::iterator<Eolian_Event const> event_iterator( ::eolian_class_events_get(klass))
, event_last; event_iterator != event_last; ++event_iterator)
{
try {
events.push_back({&*event_iterator, klass, unit});
} catch(std::exception const&) {}
}
documentation = eolian_class_documentation_get(klass);
}
// TODO memoize the return?
std::vector<function_def> get_all_methods() const
{
std::vector<function_def> ret;
std::copy(functions.cbegin(), functions.cend(), std::back_inserter(ret));
for (auto inherit : inherits)
{
klass_def klass(get_klass(inherit, unit), unit);
std::copy(klass.functions.cbegin(), klass.functions.cend(),
std::back_inserter(ret));
}
return ret;
}
std::vector<part_def> get_all_parts() const
{
std::vector<part_def> ret;
std::copy(parts.cbegin(), parts.cend(), std::back_inserter(ret));
for (auto inherit : inherits)
{
klass_def klass(get_klass(inherit, unit), unit);
std::copy(klass.parts.cbegin(), klass.parts.cend(),
std::back_inserter(ret));
}
return ret;
}
csharp: Change to new class API. Summary: As discussed in T7204: - Eo Interfaces/mixins -> C# Interfaces with concrete class implementations - Eo Regular/Abstracts -> Proper C# classes - Added some new generators and helper methods. - Refactored the class generator, splitting into helper methods Eo handles now are stored only in the "root" class in any given inheritance tree (generally, Efl.Object), and accessible to each child. Methods also are defined in a single place instead of repeatedly generated in everyfile, reducing the size of the generated .dll from 30MB to around 4.5MB. Mixins are generated as C# interfaces but any regular class it inherits from is lost, as we can't have interfaces inheriting from regular classes. This will be dealt with in a later commit. Summary of API Changes: - Merged Inherit/Concrete classes. (These suffixes disappear from regular classes). - Interface still have implementations with 'Concrete' suffix for when they are returned from methods. - Removed 'I' from interface names. - Removed interfaces for regular/abstract Eo classes. - Concrete classes for interfaces/mixins hold the event argument struct. - Removed '_' from classes, enums, structs, etc, as indicated in C# naming conventions. - Namespaces are now Camel.Cased. - Renamed IWrapper's raw_handle/raw_klass to NativeHandle/NativeClass Also renamed the test classes as after the namespace change, the test namespace Test can conflict with the helper Test namespace. (And use more meaningful names than Test.Testing...) Also Fixes T7336 by removing a deprecated example and adding efl_loop_timer_example to build system. Fixes T7451 by hiding the class_get DllImports and renaming the IWrapper fields. The native handlers are used in the manual binding. Still need to work: - As there are still some events names clashing (e.g. Efl.Ui.Bg with "resize" from Efl.Gfx.Entity and Efl.Gfx.Image), Events are currently declared on the interface and implemented "namespaced" in the classes, requiring the cast to the interface to access the event. - The Mixin Conundrum. Mixin inheritance will be dealt in a future commit. Depends on D7260 Reviewers: segfaultxavi, vitor.sousa, felipealmeida, Jaehyun_Cho Reviewed By: vitor.sousa Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: T7451, T7336 Differential Revision: https://phab.enlightenment.org/D7262
2018-11-29 15:04:37 -08:00
std::vector<event_def> get_all_events() const
{
std::vector<event_def> ret;
std::copy(events.cbegin(), events.cend(), std::back_inserter(ret));
for (auto inherit : inherits)
{
klass_def klass(get_klass(inherit, unit), unit);
std::copy(klass.events.cbegin(), klass.events.cend(),
std::back_inserter(ret));
}
return ret;
}
};
struct value_def
{
typedef eina::variant<int> variant_type; // FIXME support other types
variant_type value;
std::string literal;
type_def type;
value_def() {}
value_def(Eolian_Value value_obj)
{
type.set(value_obj.type);
value = value_obj.value.i;
literal = eolian_expression_value_to_literal(&value_obj);
}
};
struct enum_value_def
{
value_def value;
std::string name;
std::string c_name;
documentation_def documentation;
2018-01-18 22:58:52 -08:00
enum_value_def(Eolian_Enum_Type_Field const* enum_field, Eolian_Unit const*)
{
name = eolian_typedecl_enum_field_name_get(enum_field);
c_name = eolian_typedecl_enum_field_c_name_get(enum_field);
auto exp = eolian_typedecl_enum_field_value_get(enum_field, EINA_TRUE);
value = eolian_expression_eval(exp, EOLIAN_MASK_INT); // FIXME hardcoded int
documentation = eolian_typedecl_enum_field_documentation_get(enum_field);
}
};
struct enum_def
{
std::string eolian_name;
std::string cxx_name;
std::vector<std::string> namespaces;
std::vector<enum_value_def> fields;
documentation_def documentation;
enum_def(Eolian_Typedecl const* enum_obj, Eolian_Unit const* unit)
{
for(efl::eina::iterator<const char> namespace_iterator( ::eolian_typedecl_namespaces_get(enum_obj))
, namespace_last; namespace_iterator != namespace_last; ++namespace_iterator)
{
this->namespaces.push_back((&*namespace_iterator));
}
2018-03-12 08:28:28 -07:00
cxx_name = eolian_name = eolian_typedecl_short_name_get(enum_obj);
for (efl::eina::iterator<const Eolian_Enum_Type_Field> field_iterator(::eolian_typedecl_enum_fields_get(enum_obj))
, field_last; field_iterator != field_last; ++field_iterator)
{
// Fill the types
enum_value_def field_def(&*field_iterator, unit);
this->fields.push_back(field_def);
}
documentation = ::eolian_typedecl_documentation_get(enum_obj);
}
};
struct struct_field_def
{
type_def type;
std::string name;
documentation_def documentation;
struct_field_def(Eolian_Struct_Type_Field const* struct_field, Eolian_Unit const* unit)
{
name = eolian_typedecl_struct_field_name_get(struct_field);
try {
type.set(eolian_typedecl_struct_field_type_get(struct_field), unit, EOLIAN_C_TYPE_DEFAULT);
} catch(std::runtime_error const&) { /* Silently skip pointer fields*/ }
documentation = ::eolian_typedecl_struct_field_documentation_get(struct_field);
}
};
struct struct_def
{
std::string eolian_name;
std::string cxx_name;
std::vector<std::string> namespaces;
std::vector<struct_field_def> fields;
documentation_def documentation;
struct_def(Eolian_Typedecl const* struct_obj, Eolian_Unit const* unit)
{
for(efl::eina::iterator<const char> namespace_iterator( ::eolian_typedecl_namespaces_get(struct_obj))
, namespace_last; namespace_iterator != namespace_last; ++namespace_iterator)
{
this->namespaces.push_back((&*namespace_iterator));
}
2018-03-12 08:28:28 -07:00
cxx_name = eolian_name = eolian_typedecl_short_name_get(struct_obj);
for(efl::eina::iterator<const Eolian_Struct_Type_Field> field_iterator(::eolian_typedecl_struct_fields_get(struct_obj))
, field_last; field_iterator != field_last; ++field_iterator)
{
struct_field_def field_def(&*field_iterator, unit);
this->fields.push_back(field_def);
}
documentation = ::eolian_typedecl_documentation_get(struct_obj);
}
};
inline klass_name get_klass_name(klass_def const& klass)
{
return {klass.namespaces, klass.eolian_name, {qualifier_info::is_none, {}}, klass.type};
}
inline Eolian_Class const* get_klass(klass_name const& klass_name_, Eolian_Unit const* unit)
{
std::string klass_name;
if(!as_generator(*(string << ".") << string)
.generate(std::back_insert_iterator<std::string>(klass_name)
, std::make_tuple(klass_name_.namespaces, klass_name_.eolian_name)
, context_null{}))
return nullptr;
else
return ::eolian_unit_class_by_name_get(unit, klass_name.c_str());
}
inline std::vector<std::string> cpp_namespaces(std::vector<std::string> namespaces)
{
if(namespaces.empty())
namespaces.push_back("nonamespace");
return namespaces;
}
inline bool has_events(klass_def const &klass)
{
for (auto&& e : klass.events)
{
(void)e;
return true;
}
for (auto&& c : klass.inherits)
{
attributes::klass_def parent(get_klass(c, klass.unit), klass.unit);
for (auto&& e : parent.events)
{
(void)e;
return true;
}
}
return false;
}
template<typename T>
inline bool has_type_return(klass_def const &klass, T visitor)
{
for (auto&& f : klass.functions)
{
if (f.return_type.original_type.visit(visitor))
return true;
}
for (auto&& c : klass.inherits)
{
attributes::klass_def parent(get_klass(c, klass.unit), klass.unit);
if (has_type_return(parent, visitor))
return true;
}
return false;
}
struct string_return_visitor
{
typedef string_return_visitor visitor_type;
typedef bool result_type;
template <typename T>
bool operator()(T const&) const { return false; }
bool operator()(regular_type_def const& regular) const
{
return regular.base_type == "string";
}
};
struct stringshare_return_visitor
{
typedef stringshare_return_visitor visitor_type;
typedef bool result_type;
template <typename T>
bool operator()(T const&) const { return false; }
bool operator()(regular_type_def const& regular) const
{
return regular.base_type == "stringshare";
}
};
inline bool has_string_return(klass_def const &klass)
{
return has_type_return(klass, string_return_visitor{});
}
inline bool has_stringshare_return(klass_def const &klass)
{
return has_type_return(klass, stringshare_return_visitor{});
}
}
namespace type_traits {
template <>
struct is_tuple<attributes::parameter_def> : std::true_type {};
template <>
struct is_tuple<attributes::event_def> : std::true_type {};
}
} } }
#endif