#include "grammar/klass_def.hpp"
#include "grammar/header.hpp"
#include "grammar/impl_header.hpp"
+#include "grammar/types_definition.hpp"
namespace eolian_cxx {
}
static bool
-generate(const Eolian_Class* klass, eolian_cxx::options_type const& opts)
+generate(const Eolian_Class* klass, eolian_cxx::options_type const& opts,
+ std::string const& cpp_types_header)
{
std::string header_decl_file_name = opts.out_file.empty()
? (::eolian_class_file_get(klass) + std::string(".hh")) : opts.out_file;
}
};
klass_function(klass);
-
+
cpp_headers.erase(eolian_class_file_get(klass) + std::string(".hh"));
-
+
std::string guard_name;
as_generator(*(efl::eolian::grammar::string << "_") << efl::eolian::grammar::string << "_EO_HH")
.generate(std::back_insert_iterator<std::string>(guard_name)
, efl::eolian::grammar::context_null{});
std::tuple<std::string, std::set<std::string>&, std::set<std::string>&
+ , std::string const&
, std::vector<efl::eolian::grammar::attributes::klass_def>&
, std::vector<efl::eolian::grammar::attributes::klass_def>&
, std::vector<efl::eolian::grammar::attributes::klass_def>&
, std::vector<efl::eolian::grammar::attributes::klass_def>&
> attributes
- {guard_name, c_headers, cpp_headers, klasses, forward_klasses, klasses, klasses};
+ {guard_name, c_headers, cpp_headers, cpp_types_header, klasses, forward_klasses, klasses, klasses};
if(opts.out_file == "-")
{
return true;
}
+static bool
+types_generate(std::string const& fname, options_type const& opts,
+ std::string& cpp_types_header)
+{
+ using namespace efl::eolian::grammar::attributes;
+
+ std::vector<function_def> functions;
+ Eina_Iterator *itr = eolian_declarations_get_by_file(fname.c_str());
+ /* const */ Eolian_Declaration *decl;
+
+ // Build list of functions with their parameters
+ while(::eina_iterator_next(itr, reinterpret_cast<void**>(&decl)))
+ {
+ Eolian_Declaration_Type dt = eolian_declaration_type_get(decl);
+ if (dt != EOLIAN_DECL_ALIAS)
+ continue;
+
+ const Eolian_Typedecl *tp = eolian_declaration_data_type_get(decl);
+ if (!tp || eolian_typedecl_is_extern(tp))
+ continue;
+
+ if (::eolian_typedecl_type_get(tp) != EOLIAN_TYPEDECL_FUNCTION_POINTER)
+ continue;
+
+ const Eolian_Function *func = eolian_typedecl_function_pointer_get(tp);
+ if (!func) return false;
+
+ Eina_Iterator *param_itr = eolian_function_parameters_get(func);
+ std::vector<parameter_def> params;
+
+ /* const */ Eolian_Function_Parameter *param;
+ while (::eina_iterator_next(param_itr, reinterpret_cast<void **>(¶m)))
+ {
+ parameter_direction param_dir;
+ switch (eolian_parameter_direction_get(param))
+ {
+ /* Note: Inverted on purpose, as the direction objects are
+ * passed is inverted (from C to C++ for function pointers).
+ * FIXME: This is probably not right in all cases. */
+ case EOLIAN_IN_PARAM: param_dir = parameter_direction::out; break;
+ case EOLIAN_INOUT_PARAM: param_dir = parameter_direction::inout; break;
+ case EOLIAN_OUT_PARAM: param_dir = parameter_direction::in; break;
+ default: return false;
+ }
+
+ const Eolian_Type *param_type_eolian = eolian_parameter_type_get(param);
+ type_def param_type(param_type_eolian, opts.unit, EOLIAN_C_TYPE_PARAM);
+ std::string param_name = eolian_parameter_name_get(param);
+ std::string param_c_type = eolian_type_c_type_get(param_type_eolian, EOLIAN_C_TYPE_PARAM);
+ parameter_def param_def(param_dir, param_type, param_name, param_c_type);
+ params.push_back(std::move(param_def));
+ }
+ ::eina_iterator_free(param_itr);
+
+ const Eolian_Type *ret_type_eolian = eolian_function_return_type_get(func, EOLIAN_FUNCTION_POINTER);
+
+ type_def ret_type = void_;
+ if (ret_type_eolian)
+ ret_type = type_def(ret_type_eolian, opts.unit, EOLIAN_C_TYPE_RETURN);
+
+ /*
+ // List namespaces. Not used as function_wrapper lives in efl::eolian.
+ std::vector<std::string> namespaces;
+ Eina_Iterator *ns_itr = eolian_typedecl_namespaces_get(tp);
+ char *ns;
+ while (::eina_iterator_next(ns_itr, reinterpret_cast<void**>(&ns)))
+ namespaces.push_back(std::string(ns));
+ ::eina_iterator_free(ns_itr);
+ */
+
+ std::string name = eolian_function_name_get(func);
+ std::string c_name = eolian_typedecl_full_name_get(tp);
+ std::replace(c_name.begin(), c_name.end(), '.', '_');
+ bool beta = eolian_function_is_beta(func);
+
+ function_def def(ret_type, name, params, c_name, beta, false, true);
+ functions.push_back(std::move(def));
+ }
+ ::eina_iterator_free(itr);
+
+ if (functions.empty())
+ return true;
+
+ std::stringstream sink;
+
+ sink.write("\n", 1);
+ if (!efl::eolian::grammar::types_definition
+ .generate(std::ostream_iterator<char>(sink),
+ functions, efl::eolian::grammar::context_null()))
+ return false;
+
+ cpp_types_header = sink.str();
+
+ return true;
+}
+
static void
run(options_type const& opts)
{
if(!opts.main_header)
{
- const Eolian_Class *klass = NULL;
+ const Eolian_Class *klass = nullptr;
char* dup = strdup(opts.in_files[0].c_str());
char* base = basename(dup);
- klass = ::eolian_class_get_by_file(NULL, base);
+ std::string cpp_types_header;
+ klass = ::eolian_class_get_by_file(nullptr, base);
free(dup);
if (klass)
{
- if (!generate(klass, opts))
+ if (!types_generate(base, opts, cpp_types_header) ||
+ !generate(klass, opts, cpp_types_header))
{
EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain)
<< "Error generating: " << ::eolian_class_name_get(klass)
struct out_traits<void*> { typedef void*& type; };
template <typename T>
struct out_traits<efl::shared_future<T>> { typedef efl::shared_future<T>& type; };
+template <>
+struct out_traits<efl::eina::strbuf> { typedef efl::eina::strbuf_wrapper& type; };
template <typename T>
struct inout_traits { typedef T& type; };
template <typename T, typename U, bool Own = false, typename V>
T convert_to_c(V&& object);
-template <typename F, typename T>
-void* data_function_ptr_to_c(T)
-{
- return nullptr;
-}
-
-template <typename F, typename T>
-F function_ptr_to_c()
-{
- return nullptr;
-}
-
-template <typename F, typename T>
-Eina_Free_Cb free_function_ptr_to_c()
-{
- return nullptr;
-}
+template <typename U, typename F, typename V=void> struct function_wrapper;
namespace impl {
bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& ctx) const
{
attributes::qualifier_def qualifier = param.type.original_type.visit(attributes::get_qualifier_visitor{});
- bool is_function_ptr = param.type.original_type.visit(this->is_function_ptr);
- if(is_function_ptr)
- return as_generator
- (
- attribute_reorder<-1, -1, 2, -1, -1, -1, -1>
- (
- " ::efl::eolian::data_function_ptr_to_c<" << c_type
- << ", " << parameter_type
- << ">(" << string << ")"
-
- ", ::efl::eolian::function_ptr_to_c<" << c_type
- << ", " << parameter_type
- << ">()"
- ", ::efl::eolian::free_function_ptr_to_c<" << c_type
- << ", " << parameter_type
- << ">()"
- )
- ).generate(sink, param, ctx);
+ if (param.type.original_type.visit(this->is_function_ptr))
+ {
+ // FIXME: This supports only one function pointer.
+ return as_generator("fw->data_to_c(), fw->func_to_c(), fw->free_to_c()")
+ .generate(sink, param, ctx);
+ }
else
return as_generator
(
+
#ifndef EOLIAN_CXX_FUNCTION_DECLARATION_HH
#define EOLIAN_CXX_FUNCTION_DECLARATION_HH
!as_generator("#ifdef " << *(string << "_") << string << "_" << string << "_BETA\n")
.generate(sink, std::make_tuple(_klass_name.namespaces, _klass_name.eolian_name, suffix), add_upper_case_context(ctx)))
return false;
+
+ std::string template_statement(f.template_statement());
+ if (!template_statement.empty() &&
+ !as_generator(template_statement << " ")
+ .generate(sink, attributes::unused, ctx))
+ return false;
+
if(!as_generator
("::efl::eolian::return_traits<" << grammar::type(true) << ">::type " << string << "(" << (parameter % ", ") << ") const;\n")
.generate(sink, std::make_tuple(f.return_type, escape_keyword(f.name), f.parameters), ctx))
#include "grammar/attribute_conditional.hpp"
#include "grammar/attribute_reorder.hpp"
#include "grammar/type_impl.hpp"
+#include "grammar/eps.hpp"
namespace efl { namespace eolian { namespace grammar {
!as_generator("#ifdef " << *(string << "_") << string << "_PROTECTED\n")
.generate(sink, std::make_tuple(_klass_name.namespaces, _klass_name.eolian_name), add_upper_case_context(ctx)))
return false;
-
+
+ std::string template_statement(f.template_statement());
+ if (!template_statement.empty() &&
+ !as_generator(template_statement << "\n")
+ .generate(sink, attributes::unused, ctx))
+ return false;
+
if(!as_generator
("inline ::efl::eolian::return_traits<" << grammar::type(true) << ">::type " << string << "::" << string << "(" << (parameter % ", ") << ") const\n{\n")
.generate(sink, std::make_tuple(f.return_type, _klass_name.eolian_name, escape_keyword(f.name), f.parameters), ctx))
return false;
+ std::vector<std::string> opening_statements(f.opening_statements());
+ if (!opening_statements.empty() &&
+ !as_generator(scope_tab << *(string) << "\n")
+ .generate(sink, std::make_tuple(opening_statements), ctx))
+ return false;
+
auto out_declaration =
attribute_conditional([] (attributes::parameter_def const& p) -> bool
{ return p.direction == attributes::parameter_direction::out; })
scope_tab << "::efl::eolian::assign_out<" << parameter_type << ", " << c_type
<<
(
- attribute_conditional([] (attributes::type_def const& type)
- { return type.original_type.visit(attributes::get_qualifier_visitor{}) & qualifier_info::is_own; })
+ attribute_conditional([] (attributes::type_def const& typ)
+ { return typ.original_type.visit(attributes::get_qualifier_visitor{}) & qualifier_info::is_own; })
[
", true"
] | eps
<< "#include <Eina.hh>\n"
"#include <Eo.hh>\n"
<< *header_include_directive // sequence<string>
+ << string // extra header <string>
<< *class_declaration // sequence<class> | class
<< *class_forward_declaration // sequence<class> | class
<< "\nnamespace eo_cxx {\n"
std::string filename;
bool is_beta;
bool is_protected;
+ bool is_function_pointer;
friend inline bool operator==(function_def const& lhs, function_def const& rhs)
{
&& lhs.c_name == rhs.c_name
&& lhs.filename == rhs.filename
&& lhs.is_beta == rhs.is_beta
- && lhs.is_protected == rhs.is_protected;
+ && lhs.is_protected == rhs.is_protected
+ && lhs.is_function_pointer == rhs.is_function_pointer;
}
friend inline bool operator!=(function_def const& lhs, function_def const& rhs)
{
return !(lhs == rhs);
}
-
+ function_def() = default;
function_def(type_def return_type, std::string name, std::vector<parameter_def> parameters
, std::string c_name, std::string filename, bool is_beta)
: return_type(return_type), name(name), parameters(parameters), c_name(c_name), filename(filename), is_beta(is_beta) {}
- function_def() = default;
+ function_def(type_def _return_type, std::string const& _name,
+ std::vector<parameter_def> const& _parameters,
+ std::string const& _c_name,
+ bool _is_beta = false,
+ bool _is_protected = false,
+ bool _is_function_pointer = false)
+ : return_type(_return_type), name(_name), parameters(_parameters),
+ c_name(_c_name), is_beta(_is_beta), is_protected(_is_protected),
+ is_function_pointer(_is_function_pointer) {}
+
function_def( ::Eolian_Function const* function, Eolian_Function_Type type, Eolian_Unit const* unit)
: return_type(void_)
{
is_protected = eolian_function_scope_get(function, type) == EOLIAN_SCOPE_PROTECTED;
is_protected = eolian_function_scope_get(function, type) == EOLIAN_SCOPE_PROTECTED;
}
+
+ 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>(¶m.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
+ {
+ // FIXME: Supports only one function pointer
+ 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>(¶m.type.original_type);
+ if (typ && typ->is_function_ptr)
+ {
+ char typenam[2] = { 0, };
+ typenam[0] = template_typename++;
+ std::string statement = "auto fw = new ::efl::eolian::function_wrapper<";
+ statement += param.c_type + ", " + typenam + ">(" + param.param_name + ");";
+ statements.push_back(statement);
+ }
+ }
+ return statements;
+ }
};
template <>
dir = "in";
break;
}
+
+ attributes::regular_type_def const* typ =
+ efl::eina::get<attributes::regular_type_def>(¶m.type.original_type);
+ if (typ && typ->is_function_ptr)
+ return as_generator("F").generate(sink, attributes::unused, context);
+
return as_generator
(
" ::efl::eolian::" << string << "_traits<"
parameter_type_generator const parameter_type = {};
+
+/* */
struct parameter_generator
{
template <typename OutputIterator, typename Context>
struct is_generator<parameter_generator> : std::true_type {};
namespace type_traits {
template <>
-struct attributes_needed<parameter_generator> : std::integral_constant<int, 1> {};
+struct attributes_needed<parameter_generator> : std::integral_constant<int, 1> {};
}
parameter_generator const parameter = {};
+
+
+/* */
+struct parameter_as_argument_generator
+{
+ template <typename OutputIterator, typename Context>
+ bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
+ {
+ return as_generator(parameter_type << "(" << string << ")").generate(sink, std::make_tuple(param, param.param_name), context);
+ }
+};
+
+template <>
+struct is_eager_generator<parameter_as_argument_generator> : std::true_type {};
+namespace type_traits {
+template <>
+struct attributes_needed<parameter_as_argument_generator> : std::integral_constant<int, 1> {};
+}
+parameter_as_argument_generator const parameter_as_argument = {};
} } }
--- /dev/null
+#ifndef EOLIAN_CXX_TYPE_FUNCTION_DECLARATION_HH
+#define EOLIAN_CXX_TYPE_FUNCTION_DECLARATION_HH
+
+#include "grammar/generator.hpp"
+#include "grammar/klass_def.hpp"
+
+#include "grammar/string.hpp"
+#include "grammar/indentation.hpp"
+#include "grammar/list.hpp"
+#include "grammar/alternative.hpp"
+#include "grammar/type.hpp"
+#include "grammar/parameter.hpp"
+#include "grammar/keyword.hpp"
+#include "grammar/converting_argument.hpp"
+#include "grammar/eps.hpp"
+
+namespace efl { namespace eolian { namespace grammar {
+
+/** This generates the caller struct for function pointers. */
+struct type_function_declaration_generator {
+ type_function_declaration_generator() {}
+
+ template <typename OutputIterator, typename Context>
+ bool generate(OutputIterator sink, attributes::function_def const& f, Context const& ctx) const
+ {
+ std::string guard = f.c_name + "_defined";
+
+ if (!as_generator("#ifndef " << string << "\n" <<
+ "#define " << string << "\n")
+ .generate(sink, std::make_tuple(guard, guard), add_upper_case_context(ctx)))
+ return false;
+
+ // efl::eolian::function_wrapper<T, F>
+ if (!as_generator("namespace efl { namespace eolian {\n")
+ .generate(sink, attributes::unused, add_lower_case_context(ctx)))
+ return false;
+
+ if (!as_generator(
+ "template <typename F>\n"
+ "struct function_wrapper<" << string << ", F> {\n"
+ << scope_tab << "function_wrapper(F cxx_func) : _cxx_func(cxx_func) {}\n"
+ ).generate(sink, f.c_name, ctx))
+ return false;
+
+ if (!as_generator(
+ scope_tab << "void *data_to_c() { return static_cast<void *>(this); }\n"
+ << scope_tab << string << " func_to_c() const { return &caller; }\n"
+ << scope_tab << "Eina_Free_Cb free_to_c() const { return &deleter; }\n"
+ << "private:\n"
+ << scope_tab << "F _cxx_func;\n"
+ << scope_tab << "static void deleter(void *data) {\n"
+ << scope_tab << scope_tab << "delete static_cast<function_wrapper<" << string << ", F>*>(data);\n"
+ << scope_tab << "}\n"
+ ).generate(sink, std::make_tuple(f.c_name, f.c_name), ctx))
+ return false;
+
+ std::vector<std::string> c_args;
+ for (auto itr : f.parameters)
+ c_args.push_back(", " + itr.c_type + " " + itr.param_name);
+ if (!as_generator(
+ scope_tab << "static " << string << " caller(void *cxx_call_data"
+ << *(string) << ") {\n"
+ << scope_tab << scope_tab << "auto fw = static_cast<function_wrapper<"
+ << string << ", F>*>(cxx_call_data);\n"
+ ).generate(sink, std::make_tuple(f.return_type.c_type, c_args, f.c_name), ctx))
+ return false;
+
+ if (f.return_type != attributes::void_
+ && !as_generator(scope_tab << scope_tab << "auto __return_value =\n")
+ .generate(sink, attributes::unused, ctx))
+ return false;
+
+ if (!f.parameters.empty())
+ {
+ std::vector<attributes::parameter_def> params;
+ for (auto itr = f.parameters.begin() + 1; itr != f.parameters.end(); itr++)
+ params.push_back(*itr);
+ if (!as_generator(
+ scope_tab << scope_tab << "fw->_cxx_func(" << parameter_as_argument << *(", " << parameter_as_argument) << ");\n"
+ ).generate(sink, std::make_tuple(*f.parameters.begin(), params), ctx))
+ return false;
+ }
+
+ if (f.return_type != attributes::void_
+ && !as_generator(scope_tab << scope_tab << "return ::efl::eolian::convert_to_c<"
+ << type << ">(__return_value);\n")
+ .generate(sink, f.return_type, ctx))
+ return false;
+
+ if (!as_generator(scope_tab << "}\n").generate(sink, attributes::unused, ctx))
+ return false;
+
+ if (!as_generator("};\n"
+ "} }\n"
+ "#endif\n\n")
+ .generate(sink, attributes::unused, ctx))
+ return false;
+
+ return true;
+ }
+};
+
+template <>
+struct is_eager_generator<type_function_declaration_generator> : std::true_type {};
+
+namespace type_traits {
+template <>
+struct attributes_needed<type_function_declaration_generator> : std::integral_constant<int, 1> {};
+}
+
+struct type_function_declaration_terminal
+{
+ type_function_declaration_generator operator()() const
+ {
+ return type_function_declaration_generator{};
+ }
+} const type_function_declaration = {};
+
+} } }
+
+#endif
--- /dev/null
+#ifndef EOLIAN_CXX_TYPES_DEFINITION_HH
+#define EOLIAN_CXX_TYPES_DEFINITION_HH
+
+#include "header_guards.hpp"
+#include "eps.hpp"
+#include "string.hpp"
+#include "sequence.hpp"
+#include "kleene.hpp"
+#include "header_include_directive.hpp"
+#include "type_function_declaration.hpp"
+
+namespace efl { namespace eolian { namespace grammar {
+
+struct types_definition_generator
+{
+ template <typename OutputIterator, typename Context>
+ bool generate(OutputIterator sink, std::vector<attributes::function_def> const& functions, Context const& ctx) const
+ {
+ if(!as_generator(*(type_function_declaration()))
+ .generate(sink, functions, ctx))
+ return false;
+ return true;
+ }
+};
+
+template <>
+struct is_eager_generator<types_definition_generator> : std::true_type {};
+
+namespace type_traits {
+template <>
+struct attributes_needed<types_definition_generator> : std::integral_constant<int, 1> {};
+}
+
+types_definition_generator const types_definition = {};
+
+} } }
+
+#endif