#ifndef EOLIAN_CXX_STD_EO_CLASS_CONSTRUCTORS_GENERATOR_HH #define EOLIAN_CXX_STD_EO_CLASS_CONSTRUCTORS_GENERATOR_HH #include #include #include "eo_types.hh" #include "tab.hh" #include "comment.hh" #include "parameters_generator.hh" #include "namespace_generator.hh" namespace efl { namespace eolian { namespace grammar { struct class_name { std::string _name; class_name(std::string name) : _name(name) {} }; inline std::ostream& operator<<(std::ostream& out, class_name const& x) { out << x._name; return out; } struct class_inheritance { eo_class const& _cls; class_inheritance(eo_class const& cls) : _cls(cls) {} }; inline std::ostream& operator<<(std::ostream& out, class_inheritance const& x) { eo_class const& cls = x._cls; ancestors_container_type::const_iterator it, first = cls.ancestors.cbegin(), last = cls.ancestors.cend(); for (it = first; it != last; ++it) { out << tab(2) << ", EO_CXX_INHERIT(" << *it << ")" << endl; } return out; } struct constructor_functor_type_name { eo_constructor const& _ctor; constructor_functor_type_name(eo_constructor const& ctor) : _ctor(ctor) {} }; inline std::ostream& operator<<(std::ostream& out, constructor_functor_type_name const& x) { out << "_c_" << x._ctor.name; return out; } struct constructor_functor_type_decl { eo_constructor const& _ctor; constructor_functor_type_decl(eo_constructor const& ctor) : _ctor(ctor) {} }; inline std::ostream& operator<<(std::ostream& out, constructor_functor_type_decl const& x) { out << constructor_functor_type_name(x._ctor); if (parameters_count_callbacks(x._ctor.params) == 0) return out; bool comma = false; out << "<"; auto first = x._ctor.params.cbegin(), last = x._ctor.params.cend(); for(auto it = first; it != last; ++it) { if (type_is_callback((*it).type) && it+1 != last) { if (comma) out << ", "; else comma = true; out << template_parameter_type((*it).type, (*it).name); } } return out << ">"; } struct functors_constructor_methods { eo_class const& _cls; functors_constructor_methods(eo_class const& cls) : _cls(cls) {} }; inline std::ostream& operator<<(std::ostream& out, functors_constructor_methods const& x) { constructors_container_type::const_iterator it, first = x._cls.all_constructors.cbegin(), last = x._cls.all_constructors.cend(); for (it = first; it != last; ++it) { eo_constructor const& c = *it; // Hide documentation condition out << comment("@cond LOCAL", 1); // Struct declaration out << template_parameters_declaration(c.params, 1) << tab(1) << "struct " << constructor_functor_type_name(c) << endl << tab(1) << "{" << endl; // Callbacks typedefs out << parameters_cxx_generic(c.params, [](param_data d) { if (d.is_cb) d.out << tab(2) << parameter_remove_reference_typedef(d.type, d.name) << endl; } ) << endl; // Struct constructor out << tab(2) << "explicit " << constructor_functor_type_name(c) << "(" << parameters_declaration(c.params) << ")" << parameters_cxx_generic(c.params, [](param_data d) { if(d.pos == 0u) d.out << endl << tab(3) << ": "; else d.out << ", "; if (d.is_cb) d.out << callback_tmp(d.name) << "(new " << template_parameter_type(d.type, d.name) << "(" << parameter_forward(d.type, d.name) << "))"; else d.out << d.name << "(" << parameter_forward(d.type, d.name) << ")"; } ) << endl << tab(2) << "{}" << endl; // Struct operator() out << tab(2) << "void operator()()" << endl << tab(2) << "{" << endl << tab(3) << "::" << c.impl << "(" << parameters_forward_to_c(c.params) << ");" << endl << tab(2) << "}" << endl; // Register event to free allocated callbacks when the Eo* is deleted out << tab(2) << "void register_ev_del_free_callback(Eo* _eoptr)" << endl << tab(2) << "{" << endl << tab(3) << "(void) _eoptr;" << endl << parameters_cxx_generic(c.params, [](param_data d) { if (d.is_cb) d.out << tab(3) << "eo_do(_eoptr," << endl << tab(4) << "eo_event_callback_add(EO_EV_DEL, " << "&::efl::eolian::free_callback_calback<" << parameter_no_ref_type(d.type, d.name) << ">, " << callback_tmp(d.name) << "));" << endl; }) << tab(2) << "}" << endl; // Struct member variables out << endl << parameters_cxx_generic(c.params, [](param_data d) { d.out << tab(2); if (d.is_cb) d.out << parameter_no_ref_type(d.type, d.name) << "* " << callback_tmp(d.name); else d.out << parameter_type(d.type, d.name) << " " << d.name; d.out << ";" << endl; } ); // Close struct out << tab(1) << "};" << endl; // End documentation condition out << comment("@endcond", 1) << endl; } return out; } struct constructor_method_function_declarations { eo_class const& _cls; constructor_method_function_declarations(eo_class const& cls) : _cls(cls) {} }; inline std::ostream& operator<<(std::ostream& out, constructor_method_function_declarations const& x) { constructors_container_type::const_iterator it, first = x._cls.all_constructors.cbegin(), last = x._cls.all_constructors.cend(); for (it = first; it != last; ++it) { eo_constructor const& c = *it; // "eo_constructor" is already called in the eo_add_ref macro (used in // _ctors_call). // Creating a function with this name yields an error in the eo_add_ref // macro expansion, because "eo_constructor" will refers to the class // function instead of the Eo.Base function which is intended. if (c.name == "eo_constructor") { continue; } out << comment(c.comment, 1) << template_parameters_declaration(c.params, 1) << tab(1) << "static " << constructor_functor_type_decl(c) << " " << c.name << "(" << parameters_declaration(c.params) << ");" << endl << endl; } return out; } struct constructor_method_function_definitions { eo_class const& _cls; constructor_method_function_definitions(eo_class const& cls) : _cls(cls) {} }; inline std::ostream& operator<<(std::ostream& out, constructor_method_function_definitions const& x) { constructors_container_type::const_iterator it, first = x._cls.all_constructors.cbegin(), last = x._cls.all_constructors.cend(); for (it = first; it != last; ++it) { eo_constructor const& c = *it; // Same explanation as the one in constructor_method_function_declarations if (c.name == "eo_constructor") { continue; } out << template_parameters_declaration(c.params, 0) << "inline " << full_name(x._cls) << "::" << constructor_functor_type_decl(c) << " " << full_name(x._cls, false) << "::" << c.name << "(" << parameters_declaration(c.params) << ")" << endl << "{" << endl << tab(1) << "return " << constructor_functor_type_decl(c) << "(" << parameters_forward(c.params) << ");" << endl << "}" << endl << endl; } return out; } struct comment_constructor_with_constructor_methods { eo_class const& _cls; comment_constructor_with_constructor_methods(eo_class const& cls) : _cls(cls) {} }; inline std::ostream& operator<<(std::ostream& out, comment_constructor_with_constructor_methods const& x) { out << tab(1) << "/**" << endl << tab(2) << "@brief Constructs a new " << full_name(x._cls, false) << " object." << endl << endl << tab(2) << "Constructs a new " << full_name(x._cls, false) << " object. If you want this object to be a child" << endl << tab(2) << "of another Eo object, use an @ref efl::eo::parent expression, like the example." << endl << endl; if (x._cls.constructors.size()) { bool singular = (x._cls.constructors.size() == 1); out << tab(2) << "Since this class have " << (singular ? "a " : "") << "necessary constructor method" << (singular ? "" : "s") << ", you must call " << (singular ? "it" : "each one of them") << endl << tab(2) << "in the right place within this constructor parameters." << endl << endl; } if (!x._cls.optional_constructors.empty()) { out << tab(2) << "Optional constructors may be called in any combination as the" << endl << tab(2) << "last parameters." << endl << endl; } out << tab(2) << "Example:" << endl << tab(2) << "@code" << endl << tab(2) << full_name(x._cls, false) << " my_" << x._cls.name << "(efl::eo::parent = parent_object"; for (eo_constructor const& c : x._cls.all_constructors) out << "," << endl << tab(3) << "my_" << x._cls.name << "." << c.name << "(" << parameters_names(c.params) << ")"; out << ");" << endl << tab(2) << "@endcode" << endl << endl; for (eo_constructor const& c : x._cls.all_constructors) out << tab(2) << "@see " << x._cls.name << "::" << c.name << endl; out << tab(2) << "@see " << x._cls.name << "(Eo* eo)" << endl; return out << tab(1) << "*/" << endl; } struct constructor_with_constructor_methods { eo_class const& _cls; bool _with_parent; constructor_with_constructor_methods(eo_class const& cls, bool with_parent) : _cls(cls) , _with_parent(with_parent) {} }; inline std::ostream& operator<<(std::ostream& out, constructor_with_constructor_methods const& x) { unsigned cb_count = 0; constructors_container_type::const_iterator it, first = x._cls.constructors.cbegin(), last = x._cls.constructors.cend(); for (it = first; it != last; ++it) { cb_count += parameters_count_callbacks((*it).params); } if (cb_count != 0 || !x._cls.optional_constructors.empty()) { out << tab(1) << "template <"; for (unsigned i = 0; i != cb_count; ++i) { if (i != 0) out << ", "; out << "typename F" << i; } if (!x._cls.optional_constructors.empty()) { if (cb_count != 0) out << ", "; out << "typename... FOpts"; } out << ">" << endl; } out << tab(1) << "explicit " << x._cls.name << "("; if (x._with_parent) out << "::efl::eo::parent_type _p"; { unsigned cb_idx = 0; for (it = first; it != last; ++it) { if (x._with_parent || it != first) out << ", "; out << constructor_functor_type_name(*it); if (cb_count != 0 && parameters_count_callbacks((*it).params) != 0) { out << "<" << parameters_cxx_generic((*it).params, [&cb_idx](param_data d) { if (d.is_cb) d.out << (d.cb_idx ? ", " : "") << "F" << cb_idx++; }) << ">"; } out << " _c" << (it-first); } assert(cb_idx == cb_count); } if (!x._cls.optional_constructors.empty()) { if (x._with_parent || first != last) out << ", "; out << "FOpts&&... _opts"; } out << ")" << endl << tab(2) << ": " << x._cls.name << "(_ctors_call(" << (x._with_parent ? "_p" : "::efl::eo::parent = nullptr"); for (it = first; it != last; ++it) { out << ", _c" << (it-first); } if (!x._cls.optional_constructors.empty()) { out << ", std::forward(_opts)..."; } out << "))" << endl << tab(1) << "{}" << endl; return out; } struct constructors_with_constructor_methods { eo_class const& _cls; constructors_with_constructor_methods(eo_class const& cls) : _cls(cls) {} }; inline std::ostream& operator<<(std::ostream& out, constructors_with_constructor_methods const& x) { out << tab(1) << "//@{" << endl << comment_constructor_with_constructor_methods(x._cls) << constructor_with_constructor_methods(x._cls, true) << endl << constructor_with_constructor_methods(x._cls, false) << tab(1) << "//@}" << endl << endl; return out; } struct constructor_eo { eo_class const& _cls; constructor_eo(eo_class const& cls) : _cls(cls) {} }; inline std::ostream& operator<<(std::ostream& out, constructor_eo const& x) { std::string doc = "@brief Eo Constructor.\n\n" "Constructs the object from an Eo* pointer stealing its ownership.\n\n" "@param eo The Eo object pointer.\n\n"; out << comment(doc, 1) << tab(1) << "explicit " << x._cls.name << "(Eo* eo)" << endl << tab(2) << ": ::efl::eo::concrete(eo)" << endl << tab(1) << "{}" << endl << endl; out << comment( "@brief nullptr_t Constructor.\n\n" "Constructs an empty (null) object.\n\n" , 1 ) << tab(1) << "explicit " << x._cls.name << "(std::nullptr_t)" << endl << tab(2) << ": ::efl::eo::concrete(nullptr)" << endl << tab(1) << "{}" << endl << endl; return out; } struct copy_constructor { eo_class const& _cls; copy_constructor(eo_class const& cls) : _cls(cls) {} }; inline std::ostream& operator<<(std::ostream& out, copy_constructor const& x) { std::string doc = "@brief Copy Constructor.\n\n"; out << comment(doc, 1) << tab(1) << x._cls.name << "(" << x._cls.name << " const& other)" << endl << tab(2) << ": " << x._cls.name << "(eo_ref(other._eo_ptr()))" << endl << tab(1) << "{}" << endl << endl; return out; } struct destructor { eo_class const& _cls; destructor(eo_class const& cls) : _cls(cls) {} }; inline std::ostream& operator<<(std::ostream& out, destructor const& x) { out << tab(1) << '~' << x._cls.name << "() {}" << endl << endl; return out; } struct function_call_constructor_methods { eo_class const& _cls; function_call_constructor_methods(eo_class const& cls) : _cls(cls) {} }; inline std::ostream& operator<<(std::ostream& out, function_call_constructor_methods const& x) { out << comment("@internal", 1); unsigned cb_count = 0; constructors_container_type::const_iterator it, first = x._cls.constructors.cbegin(), last = x._cls.constructors.cend(); for (it = first; it != last; ++it) { cb_count += parameters_count_callbacks((*it).params); } if (cb_count != 0 || !x._cls.optional_constructors.empty()) { out << tab(1) << "template <"; for (unsigned i = 0; i != cb_count; ++i) { if (i != 0) out << ", "; out << "typename F" << i; } if (!x._cls.optional_constructors.empty()) { if (cb_count != 0) out << ", "; out << "typename... FOpts"; } out << ">" << endl; } unsigned cb_idx = 0; out << tab(1) << "static Eo* _ctors_call(::efl::eo::parent_type _p"; for (it = first; it != last; ++it) { out << ", " << constructor_functor_type_name(*it); if (cb_count != 0 && parameters_count_callbacks((*it).params) != 0) { out << "<" << parameters_cxx_generic((*it).params, [&cb_idx](param_data d) { if (d.is_cb) d.out << (d.cb_idx ? ", " : "") << "F" << cb_idx++; }) << ">"; } out << " _c" << (it-first); } assert(cb_idx == cb_count); if (!x._cls.optional_constructors.empty()) out << ", FOpts&&... _opts"; out << ")" << endl << tab(1) << "{" << endl << tab(2) << "Eo* _ret_eo = eo_add_ref(" << x._cls.eo_name << ", _p._eo_raw"; for (it = first; it != last; ++it) { out << ", _c" << (it-first) << "()"; } if (!x._cls.optional_constructors.empty()) out << ", ::efl::eolian::call_ctors(_opts...)"; out << ");" << endl << endl; for (it = first; it != last; ++it) out << tab(2) << "_c" << (it-first) << ".register_ev_del_free_callback(_ret_eo);" << endl; if (!x._cls.optional_constructors.empty()) out << tab(2) << "::efl::eolian::register_ev_del_free_callback(_ret_eo, _opts...);" << endl; out << tab(2) << "return _ret_eo;" << endl << tab(1) << "}" << endl << endl; return out; } } } } // namespace efl { namespace eolian { namespace grammar { #endif // EOLIAN_CXX_STD_EO_CLASS_CONSTRUCTORS_GENERATOR_HH