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

1826 lines
61 KiB
C++
Raw Normal View History

/*
* Copyright 2019 by its authors. See AUTHORS.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#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>
#include <iosfwd>
#include <string>
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 std::ostream& operator<<(std::ostream& s, typedecl_type dec)
{
switch(dec)
{
case typedecl_type::unknown:
return s << "unknown";
case typedecl_type::struct_:
return s << "struct_";
case typedecl_type::struct_opaque:
return s << "struct_opaque";
case typedecl_type::enum_:
return s << "enum_";
case typedecl_type::alias:
return s << "alias";
case typedecl_type::function_ptr:
return s << "function_ptr";
};
return s;
}
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& lhs, type_def const& rhs);
bool operator!=(type_def const& lhs, type_def const& rhs);
enum class class_type
{
regular, abstract_, mixin, interface_
};
inline std::ostream& operator<<(std::ostream& s, class_type t)
{
switch(t)
{
case class_type::regular:
return s << "regular";
case class_type::abstract_:
return s << "abstract_";
case class_type::mixin:
return s << "mixin";
case class_type::interface_:
return s << "interface_";
};
return s;
}
struct klass_name
{
std::vector<std::string> namespaces;
std::string eolian_name;
qualifier_def base_qualifier;
class_type type;
std::string klass_get_name;
bool is_beta;
friend inline std::ostream& operator<<(std::ostream& s, klass_name const& name)
{
s << "[ namespaces: {";
std::copy(name.namespaces.begin(), name.namespaces.end(), std::ostream_iterator<std::string>(s, ","));
return s << "}, eolian_name: " << name.eolian_name << " base_qualifier: " << name.base_qualifier
<< " type: " << name.type << " klass_get_name: " << name.klass_get_name << "]";
}
klass_name() {
}
klass_name(std::vector<std::string> namespaces
, std::string eolian_name, qualifier_def base_qualifier
, class_type type, std::string klass_get_name, bool is_beta)
: namespaces(namespaces), eolian_name(eolian_name), base_qualifier(base_qualifier)
, type(type), klass_get_name(klass_get_name), is_beta(is_beta) {}
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)
, klass_get_name( ::eolian_class_c_get_function_name_get(klass))
, is_beta(::eolian_object_is_beta(EOLIAN_OBJECT(klass)))
{
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;
std::string full_text;
documentation_def() = default;
documentation_def(std::string summary, std::string description, std::string since, std::string full_text)
: summary(summary), description(description), since(since), full_text(full_text)
{}
documentation_def(Eolian_Documentation const* eolian_doc)
{
const char *str;
if (!eolian_doc)
return;
str = eolian_documentation_summary_get(eolian_doc);
if (str)
full_text = summary = str;
str = eolian_documentation_description_get(eolian_doc);
if (str) {
description = str;
// Separate summary from description with a blank line
full_text += "\n\n" + description;
}
str = eolian_documentation_since_get(eolian_doc);
if (str) {
since = str;
}
efl::eina::ptr_list<const char, efl::eina::malloc_clone_allocator>
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); }
friend inline std::ostream& operator<<(std::ostream& s, regular_type_def const& def)
{
s << "[ base_type: " << def.base_type << " base_qualifier: " << def.base_qualifier
<< " namespaces: ";
std::copy(def.namespaces.begin(), def.namespaces.end(), std::ostream_iterator<std::string>(s, ", "));
return s << " type_type: " << def.type_type << " is_undefined " << def.is_undefined << "]";
}
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;
friend inline std::ostream& operator<<(std::ostream& s, complex_type_def const& def)
{
s << "[ outer " << def.outer << " subtypes: {";
std::copy(def.subtypes.begin(), def.subtypes.end(), std::ostream_iterator<type_def>(s, ", "));
return s << "}]";
}
};
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);
}
namespace value_ownership
{
const bool moved = true;
const bool unmoved = false;
};
namespace is_by
{
const bool reference = true;
const bool value = false;
};
// type_def represents a type where it is used, like a method parameter or a struc field, in contrast to more
// specifict types like struct_def, class_def, function_def, which represents a declaration of a type.
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;
bool is_beta;
std::string doc_summary;
bool is_value_type;
type_def() = default;
type_def(variant_type original_type, std::string c_type, bool has_own, bool is_ptr, bool is_beta, std::string doc_summary)
: original_type(original_type), c_type(c_type), has_own(has_own), is_ptr(is_ptr), is_beta(is_beta), doc_summary(doc_summary) {}
type_def(Eolian_Type const* eolian_type, Eolian_Unit const* unit, std::string const& ctype, bool is_moved, bool is_reference)
{
set(eolian_type, unit, ctype, is_moved, is_reference);
}
void set(Eolian_Type const* eolian_type, Eolian_Unit const* unit, std::string const & ctype, bool is_moved, bool is_reference);
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;
}
friend inline std::ostream& operator<<(std::ostream& s, type_def const& rhs)
{
return s << "[ original: " << rhs.original_type << " c_type "
<< rhs.c_type << " has_own " << rhs.has_own << " is_ptr "
<< rhs.is_ptr << "]";
}
private:
void set(const char* regular_name, const char* 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, false, false, ""};
inline void type_def::set(Eolian_Type const* eolian_type, Eolian_Unit const* unit, std::string const& ctype, bool is_moved, bool is_reference)
{
c_type = ctype;
is_value_type = ('*' != c_type.back());
// ::eina_stringshare_del(stringshare); // this crashes
Eolian_Type const* stp = eolian_type_base_type_get(eolian_type);
has_own = is_moved;
is_ptr = is_reference || eolian_type_is_ptr(eolian_type);
Eolian_Typedecl const* decl = eolian_type_typedecl_get(eolian_type);
is_beta = decl && eolian_object_is_beta(EOLIAN_OBJECT(decl));
if (decl)
{
documentation_def documentation = eolian_typedecl_documentation_get(decl);
doc_summary = documentation.summary;
}
switch( ::eolian_type_type_get(eolian_type))
{
case EOLIAN_TYPE_VOID:
original_type = attributes::regular_type_def{"void", {qualifiers(eolian_type, is_moved, is_ptr), {}}, {}};
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);
original_type = {regular_type_def{ ::eolian_type_short_name_get(eolian_type), {qualifiers(eolian_type, is_moved, is_ptr), {}}, namespaces, type_type, is_undefined}};
}
else
{
complex_type_def complex
{{::eolian_type_short_name_get(eolian_type), {qualifiers(eolian_type, is_moved, is_ptr), {}}, {}}, {}};
while (stp)
{
complex.subtypes.push_back({stp
, unit
, ::eolian_type_c_type_get(stp)
, static_cast<bool>(eolian_type_is_move(stp))
, is_by::value});
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, is_moved, is_ptr), {}});
}
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:
set("int", "int");
break;
case EOLIAN_EXPR_UINT:
set("uint", "unsigned int");
break;
case EOLIAN_EXPR_FLOAT:
set("float", "float");
break;
case EOLIAN_EXPR_DOUBLE:
set("double", "double");
break;
case EOLIAN_EXPR_STRING:
set("string", "const char *");
break;
case EOLIAN_EXPR_BOOL:
set("bool", "Eina_Bool");
break;
case EOLIAN_EXPR_NULL:
set("null", "void *");
break;
default:
// FIXME implement the remaining types
EINA_LOG_ERR("Unsupported expression type : %d", eolian_exp_type);
std::abort();
break;
}
}
inline void type_def::set(const char* regular_name, const char* c_type)
{
original_type = attributes::regular_type_def{regular_name, {{}, {}}, {}};
this->c_type = c_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;
bool is_beta;
alias_def(Eolian_Typedecl const* alias_obj, Eolian_Unit const* unit)
: is_beta(::eolian_typedecl_is_beta(alias_obj))
{
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
{
auto eolian_type = ::eolian_typedecl_base_type_get(alias_obj);
base_type = type_def(eolian_type
, unit
, ::eolian_type_c_type_get(eolian_type)
, value_ownership::unmoved
, is_by::value);
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 value_def
{
typedef eina::variant<int> variant_type; // FIXME support other types
variant_type value;
std::string literal;
type_def type;
value_def() = default;
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 expression_def
{
value_def value;
std::string serialized;
// We store this explicitly as evaluating the value reduces a name reference
// to a plain string value.
bool is_name_ref;
friend inline bool operator==(expression_def const& lhs, expression_def const& rhs)
{
return lhs.serialized == rhs.serialized;
}
friend inline bool operator!=(expression_def const& lhs, expression_def const& rhs)
{
return !(lhs == rhs);
}
expression_def(Eolian_Expression const* expression) : value(::eolian_expression_eval(expression, EOLIAN_MASK_ALL))
, serialized()
, is_name_ref(::eolian_expression_type_get(expression) == EOLIAN_EXPR_NAME)
{
auto serialized_s = ::eolian_expression_serialize(expression);
serialized = serialized_s;
::eina_stringshare_del(serialized_s);
}
};
struct parameter_def
{
parameter_direction direction;
type_def type;
std::string param_name;
documentation_def documentation;
eina::optional<expression_def> default_value;
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
&& lhs.default_value == rhs.default_value;
}
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_parameter_c_type_get(param, EINA_FALSE)
, eolian_parameter_is_move(param)
, eolian_parameter_is_by_ref(param))
, param_name( ::eolian_parameter_name_get(param))
, default_value(::eolian_parameter_default_value_get(param) ?
::eolian_parameter_default_value_get(param) :
eina::optional<expression_def>{})
, unit(_unit)
{
Eolian_Parameter_Direction direction = ::eolian_parameter_direction_get(param);
switch(direction)
{
case EOLIAN_PARAMETER_UNKNOWN:
case EOLIAN_PARAMETER_IN:
this->direction = parameter_direction::in;
break;
case EOLIAN_PARAMETER_INOUT:
this->direction = parameter_direction::inout;
break;
case EOLIAN_PARAMETER_OUT:
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
};
enum class member_scope
{
scope_unknown,
scope_public,
scope_private,
scope_protected,
};
struct function_def
{
// Klass information for function_def as method
klass_name klass;
// Eolian name of the function
std::string name;
// Actual return type as expected in the C version of this function.
// For property getters, this could be the type of the single
// value it holds
type_def return_type;
// Parameters of this function as the C implementation of it
std::vector<parameter_def> parameters;
// Original return type as declared in the Eo.
type_def explicit_return_type;
// Original Eolian keys of this function. Used only for properties
std::vector<parameter_def> keys;
// Original Eolian values of this function. Used only for properties
std::vector<parameter_def> values;
// Name of this function in the C api
std::string c_name;
std::string filename;
// Namespaces for top-level function pointers
std::vector<std::string> namespaces;
documentation_def documentation;
documentation_def return_documentation;
documentation_def property_documentation;
function_type type;
member_scope scope;
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.keys == rhs.keys
&& lhs.values == rhs.values
&& 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.scope == rhs.scope
&& 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( ::Eolian_Function const* function, Eolian_Function_Type type, Eolian_Typedecl const* tp, Eolian_Unit const* unit)
: return_type(void_), explicit_return_type(void_), unit(unit)
{
Eolian_Type const* r_type = ::eolian_function_return_type_get(function, type);
name = ::eolian_function_name_get(function);
return_documentation = eolian_function_return_documentation_get(function, type);
scope = static_cast<member_scope>(eolian_function_scope_get(function, type));
if(r_type)
{
return_type.set(r_type
, unit
, eolian_function_return_c_type_get(function, type)
, eolian_function_return_is_move(function, type)
, eolian_function_return_is_by_ref(function, type));
explicit_return_type = return_type;
}
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)
{
parameter_def param = {&*param_iterator, unit};
parameters.push_back(param);
keys.push_back(param);
}
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;
if (return_documentation.summary.empty())
return_documentation = values[0].documentation;
}
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);
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()});
is_beta = eolian_function_is_beta(function) || klass.is_beta;
}
else
{
is_beta = tp && eolian_object_is_beta(EOLIAN_OBJECT(tp));
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_protected = eolian_function_scope_get(function, type) == EOLIAN_SCOPE_PROTECTED;
is_static = eolian_function_is_static(function);
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 + ", ::efl::eolian::" + param.type.c_type + "__function_tag>(" + 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; }
};
struct property_def
{
klass_name klass;
std::string name;
documentation_def documentation;
efl::eina::optional<function_def> getter;
efl::eina::optional<function_def> setter;
friend inline bool operator==(property_def const& lhs, property_def const& rhs)
{
return lhs.klass == rhs.klass
&& lhs.name == rhs.name
&& lhs.documentation == rhs.documentation
&& lhs.getter == rhs.getter
&& lhs.setter == rhs.setter;
}
friend inline bool operator!=(property_def const& lhs, property_def const& rhs)
{
return !(lhs == rhs);
}
property_def() = default;
property_def(Eolian_Function const *function, efl::eina::optional<function_def> getter
, efl::eina::optional<function_def> setter, Eolian_Unit const*)
: getter(getter), setter(setter)
{
name = ::eolian_function_name_get(function);
const Eolian_Class *eolian_klass = eolian_function_class_get(function);
klass = klass_name(eolian_klass, {attributes::qualifier_info::is_none, std::string()});
Eolian_Implement const* implement = ::eolian_function_implement_get(function);
if (!implement)
return;
Eolian_Function_Type type = ::eolian_function_type_get(function);
if (type == EOLIAN_PROP_GET || type == EOLIAN_PROP_SET || type == EOLIAN_PROPERTY)
{
documentation = eolian_implement_documentation_get(implement, EOLIAN_PROPERTY);
// If property-level documentation is empty, use the getter- or setter-level
// docs as fallback (if present).
if (documentation.summary.empty())
documentation = eolian_implement_documentation_get(implement, EOLIAN_PROP_GET);
if (documentation.summary.empty())
documentation = eolian_implement_documentation_get(implement, EOLIAN_PROP_SET);
}
}
};
struct constant_def
{
std::string name;
std::string full_name;
type_def base_type;
documentation_def documentation;
std::vector<std::string> namespaces;
Eolian_Value expression_value;
bool is_extern : 1;
friend inline bool operator==(constant_def const& lhs, constant_def const& rhs)
{
return lhs.name == rhs.name
&& lhs.full_name == rhs.full_name
&& lhs.base_type == rhs.base_type
&& lhs.documentation == rhs.documentation
&& lhs.namespaces == rhs.namespaces
&& lhs.expression_value.type == rhs.expression_value.type
&& lhs.expression_value.value.ll == rhs.expression_value.value.ll
&& lhs.is_extern == rhs.is_extern;
}
friend inline bool operator!=(constant_def const& lhs, constant_def const& rhs)
{
return !(lhs == rhs);
}
constant_def() = default;
constant_def(Eolian_Constant const* constant, Eolian_Unit const* unit)
: name(::eolian_constant_short_name_get(constant))
, full_name(::eolian_constant_name_get(constant))
, base_type(::eolian_constant_type_get(constant)
, unit
, ::eolian_type_c_type_get(eolian_constant_type_get(constant))
, value_ownership::unmoved
, is_by::value)
, documentation(::eolian_constant_documentation_get(constant))
, expression_value()
, is_extern(::eolian_constant_is_extern(constant))
{
for(efl::eina::iterator<const char> namespace_iterator( ::eolian_constant_namespaces_get(constant))
, namespace_last; namespace_iterator != namespace_last; ++namespace_iterator)
{
this->namespaces.push_back((&*namespace_iterator));
}
auto expr = ::eolian_constant_value_get(constant);
if (!expr)
throw std::runtime_error("Could not get constant variable value expression");
this->expression_value = ::eolian_expression_eval(expr, ::EOLIAN_MASK_ALL);
}
};
// 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 is_beta, is_protected;
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.is_beta == rhs.is_beta
&& lhs.is_protected == rhs.is_protected
&& 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 is_beta, bool is_protected, documentation_def documentation)
: klass(_klass), type(type), name(name), c_name(c_name), is_beta(is_beta), is_protected(is_protected)
, 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_type_c_type_get(::eolian_event_type_get(event))
, value_ownership::unmoved
, is_by::value}
} : eina::optional<type_def>{})
, name( ::eolian_event_name_get(event))
, c_name( ::eolian_event_c_macro_get(event))
, is_beta( ::eolian_event_is_beta(event) || klass.is_beta)
, is_protected( ::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)) {}
};
struct constructor_def
{
std::string name;
klass_name klass;
function_def function;
bool is_optional;
friend inline bool operator==(constructor_def const& lhs, constructor_def const& rhs)
{
return lhs.name == rhs.name
&& lhs.klass == rhs.klass
&& lhs.function == rhs.function
&& lhs.is_optional == rhs.is_optional;
}
friend inline bool operator!=(constructor_def const& lhs, constructor_def const& rhs)
{
return !(lhs == rhs);
}
constructor_def(Eolian_Constructor const* constructor, Eolian_Unit const* unit)
: name(::eolian_constructor_name_get(constructor))
, klass(::eolian_constructor_class_get(constructor), {})
, is_optional(::eolian_constructor_is_optional(constructor))
{
Eolian_Function const* eo_function = ::eolian_constructor_function_get(constructor);
Eolian_Function_Type eo_func_type = ::eolian_function_type_get(eo_function);
if (eo_func_type == ::EOLIAN_PROPERTY)
eo_func_type = ::EOLIAN_PROP_SET;
function = function_def(eo_function, eo_func_type, NULL, unit);
}
};
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::vector<property_def> properties;
std::vector<constructor_def> constructors;
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;
eina::optional<klass_name> parent;
std::set<klass_name, compare_klass_name_by_name> extensions;
std::string klass_get_name;
bool is_beta;
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 == rhs.filename
&& lhs.namespaces == rhs.namespaces
&& lhs.functions == rhs.functions
&& lhs.properties == rhs.properties
&& lhs.inherits == rhs.inherits
&& lhs.type == rhs.type
&& lhs.events == rhs.events
&& lhs.parts == rhs.parts
&& lhs.klass_get_name == rhs.klass_get_name
&& lhs.is_beta == rhs.is_beta;
}
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;
}
friend inline bool operator==(klass_def const& lhs, klass_name const& rhs)
{
return lhs.namespaces == rhs.namespaces
&& lhs.eolian_name == rhs.eolian_name
&& lhs.type == rhs.type;
}
friend inline bool operator==(klass_name const& lhs, klass_def const& rhs)
{
return rhs == lhs;
}
friend inline bool operator!=(klass_def const& lhs, klass_name const& rhs)
{
return !(lhs == rhs);
}
friend inline bool operator!=(klass_name const& lhs, klass_def const& rhs)
{
return !(rhs == lhs);
}
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::vector<property_def> properties
, std::set<klass_name, compare_klass_name_by_name> inherits
, class_type type
, std::set<klass_name, compare_klass_name_by_name> immediate_inherits
, std::string klass_get_name
, bool is_beta
, Eolian_Unit const* unit)
: eolian_name(eolian_name), cxx_name(cxx_name), filename(filename)
, documentation(documentation)
, namespaces(namespaces)
, functions(functions), properties(properties), inherits(inherits), type(type)
, immediate_inherits(immediate_inherits)
, klass_get_name(klass_get_name)
, is_beta(is_beta)
, unit(unit)
{}
klass_def(std::string _eolian_name, std::string _cxx_name
, std::vector<std::string> _namespaces
, std::vector<function_def> _functions
, std::vector<property_def> _properties
, std::set<klass_name, compare_klass_name_by_name> _inherits
, class_type _type, Eolian_Unit const* unit
, std::string klass_get_name
, bool is_beta)
: eolian_name(_eolian_name), cxx_name(_cxx_name)
, namespaces(_namespaces)
, functions(_functions), properties(_properties), inherits(_inherits), type(_type)
, klass_get_name(klass_get_name), is_beta(is_beta), unit(unit)
{}
klass_def(Eolian_Class const* klass, Eolian_Unit const* unit)
: klass_get_name( ::eolian_class_c_get_function_name_get(klass))
, is_beta(::eolian_class_is_beta(klass))
, 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)
{
efl::eina::optional<function_def> getter(nullptr);
efl::eina::optional<function_def> setter(nullptr);
try {
if(::eolian_function_scope_get(function, EOLIAN_PROP_GET) != EOLIAN_SCOPE_PRIVATE)
{
function_def f(function, EOLIAN_PROP_GET, NULL, unit);
functions.push_back(f);
getter = efl::eina::optional<function_def>(f);
}
} catch(std::exception const&) {}
try {
if(::eolian_function_scope_get(function, EOLIAN_PROP_SET) != EOLIAN_SCOPE_PRIVATE)
{
function_def f(function, EOLIAN_PROP_SET, NULL, unit);
functions.push_back(f);
setter = efl::eina::optional<function_def>(f);
}
} catch(std::exception const&) {}
if (getter.is_engaged() || setter.is_engaged())
properties.push_back({function, getter, setter, unit});
}
else
try {
if(::eolian_function_scope_get(function, func_type) != EOLIAN_SCOPE_PRIVATE)
{
efl::eina::optional<function_def> getter(nullptr);
efl::eina::optional<function_def> setter(nullptr);
function_def f(function, func_type, NULL, unit);
if (func_type == EOLIAN_PROP_GET)
getter = efl::eina::optional<function_def>(f);
else if (func_type == EOLIAN_PROP_SET)
setter = efl::eina::optional<function_def>(f);
functions.push_back(f);
if (func_type == EOLIAN_PROP_GET || func_type == EOLIAN_PROP_SET)
properties.push_back({function, getter, setter, 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_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))
{
parent = eina::optional<klass_name>({::eolian_class_parent_get(klass), {}});
immediate_inherits.insert(*parent);
}
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;
klass_name extension(inherit, {});
immediate_inherits.insert(extension);
extensions.insert(extension);
}
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&) {}
}
for(efl::eina::iterator<Eolian_Constructor const> constructor_iterator(::eolian_class_constructors_get(klass))
, constructor_last; constructor_iterator != constructor_last; ++constructor_iterator)
constructors.push_back({&*constructor_iterator, unit});
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;
}
std::vector<constructor_def> get_all_constructors() const
{
std::vector<constructor_def> ret;
std::copy(constructors.cbegin(), constructors.cend(), std::back_inserter(ret));
for (auto inherit : inherits)
{
klass_def klass(get_klass(inherit, unit), unit);
std::copy(klass.constructors.cbegin(), klass.constructors.cend(),
std::back_inserter(ret));
}
return ret;
}
};
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_constant_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;
bool is_beta;
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);
}
is_beta = eolian_object_is_beta(EOLIAN_OBJECT(enum_obj));
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_typedecl_struct_field_c_type_get(struct_field)
, eolian_typedecl_struct_field_is_move(struct_field)
, eolian_typedecl_struct_field_is_by_ref(struct_field));
} 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;
bool is_beta;
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);
}
is_beta = eolian_object_is_beta(EOLIAN_OBJECT(struct_obj));
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, klass.klass_get_name, klass.is_beta};
}
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