From d53038989886a85b75c81a395269f6f349d7d78f Mon Sep 17 00:00:00 2001 From: Vitor Sousa Date: Mon, 12 Jan 2015 12:00:59 -0200 Subject: [PATCH] eolian_cxx: Add protected methods and events to C++ wrappers and fixes Using eina::string_view in eolian generated interfaces (instead of std::string) to allow lightweight passing of both C strings and C++ std::string. Also, No longer using eina::optional in generated headers for types that already implements the concept of null state (like Eo wrappers and eina_accessor). Also fix allocating callback objects require by class methods (i.e. static) in static vectors so the memory will be freed when the programs exit. Added a new test case for testing callbacks on class methods. Moved method definitions and supplementary code from generated C++ wrappers to auxiliary header file (.eo.impl.hh) generated together with the main ".eo.hh" file. Updated Makefiles to list such files in the compilation and cleanup processes. Updated .gitignore to include these new generated files. Made general adjustments on the documentation of generated C++ wrappers Added "PREDEFINED" preprocessor macro definition in the Doxyfile.in in order to make some adjustments for better documentation in the C++ generated headers. Excluding generation of documentation for classes in the "eo_cxx" namespace (the namespace for "abstract" eolian C++ wrappers). Now generating the documentation for the events too. Hiding some auxiliary code from being documented. Some aesthetic adjustments for generated white space. Generate documentation for the main constructor of C++ wrappers and added auxiliary grammars to list parameters names. --- .gitignore | 1 + doc/Doxyfile.in | 6 +- src/Makefile_Ecore_Audio_Cxx.am | 7 ++ src/Makefile_Ecore_Cxx.am | 6 + src/Makefile_Edje_Cxx.am | 2 + src/Makefile_Efl_Cxx.am | 6 + src/Makefile_Eo_Cxx.am | 4 +- src/Makefile_Eolian_Cxx.am | 10 +- src/Makefile_Eolian_Cxx_Helper.am | 3 + src/Makefile_Evas_Cxx.am | 37 +++++- src/bin/eolian_cxx/convert.cc | 3 + src/bin/eolian_cxx/eolian_cxx.cc | 52 +++++++-- src/bin/eolian_cxx/eolian_wrappers.hh | 21 +++- src/bin/eolian_cxx/type_lookup_table.cc | 34 +++--- src/bindings/eo_cxx/eo_concrete.hh | 6 + src/bindings/eo_cxx/eo_cxx_interop.hh | 52 +++++++++ src/examples/eolian_cxx/Makefile.am | 7 +- src/lib/eolian_cxx/eo_generate.hh | 7 +- src/lib/eolian_cxx/eo_types.hh | 31 ++++- src/lib/eolian_cxx/grammar/comment.hh | 8 +- .../eo_class_constructors_generator.hh | 61 +++++++++- .../grammar/eo_class_events_generator.hh | 11 +- .../grammar/eo_class_functions_generator.hh | 18 +-- .../eolian_cxx/grammar/eo_class_generator.hh | 33 ++++-- .../grammar/eo_class_scope_guard_generator.hh | 61 ++++++++++ .../eolian_cxx/grammar/eo_header_generator.hh | 30 +++-- .../grammar/inheritance_base_generator.hh | 73 +++++++++--- .../grammar/parameters_generator.hh | 106 +++++++++++++----- src/lib/eolian_cxx/grammar/type_generator.hh | 26 ++++- src/tests/eolian_cxx/callback.c | 6 + src/tests/eolian_cxx/callback.eo | 6 + .../eolian_cxx/eolian_cxx_test_callback.cc | 13 +++ 32 files changed, 622 insertions(+), 125 deletions(-) create mode 100644 src/lib/eolian_cxx/grammar/eo_class_scope_guard_generator.hh diff --git a/.gitignore b/.gitignore index 4f048401f4..1da486ee1b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ tags *.eo.h *.eo.legacy.h *.eo.hh +*.eo.impl.hh *.eo.lua *.luac .dir-locals.el diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index f18cc4f77b..b4afaf42e7 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -667,7 +667,7 @@ EXCLUDE_PATTERNS = *_private* # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = eo_cxx::* # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see @@ -1441,7 +1441,9 @@ PREDEFINED = EINA_MAGIC_DEBUG \ EAPI= \ EINA_PURE= \ EINA_CONST= \ - EINA_UNUSED= + EINA_UNUSED= \ + EFL_DOXYGEN=1 \ + "EO_CXX_INHERIT(name)=::name" # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/src/Makefile_Ecore_Audio_Cxx.am b/src/Makefile_Ecore_Audio_Cxx.am index 498bcbf887..bf564d2c94 100644 --- a/src/Makefile_Ecore_Audio_Cxx.am +++ b/src/Makefile_Ecore_Audio_Cxx.am @@ -20,6 +20,13 @@ lib/ecore_audio/Ecore_Audio.hh: $(generated_ecore_audio_cxx_bindings) generated_ecore_audio_cxx_all = \ $(generated_ecore_audio_cxx_bindings) \ + lib/ecore_audio/ecore_audio.eo.impl.hh \ + lib/ecore_audio/ecore_audio_in.eo.impl.hh \ + lib/ecore_audio/ecore_audio_out.eo.impl.hh \ + lib/ecore_audio/ecore_audio_in_sndfile.eo.impl.hh \ + lib/ecore_audio/ecore_audio_out_sndfile.eo.impl.hh \ + lib/ecore_audio/ecore_audio_out_pulse.eo.impl.hh \ + lib/ecore_audio/ecore_audio_in_tone.eo.impl.hh \ lib/ecore_audio/Ecore_Audio.hh CLEANFILES += $(generated_ecore_audio_cxx_all) diff --git a/src/Makefile_Ecore_Cxx.am b/src/Makefile_Ecore_Cxx.am index d81651a6b1..b29a1c4868 100644 --- a/src/Makefile_Ecore_Cxx.am +++ b/src/Makefile_Ecore_Cxx.am @@ -22,6 +22,12 @@ lib/ecore/Ecore.eo.hh: $(generated_ecore_cxx_bindings) generated_ecore_cxx_all = \ $(generated_ecore_cxx_bindings) \ + lib/ecore/ecore_poller.eo.impl.hh \ + lib/ecore/ecore_job.eo.impl.hh \ + lib/ecore/ecore_idler.eo.impl.hh \ + lib/ecore/ecore_idle_exiter.eo.impl.hh \ + lib/ecore/ecore_animator.eo.impl.hh \ + lib/ecore/ecore_parent.eo.impl.hh \ lib/ecore/Ecore.eo.hh CLEANFILES += $(generated_ecore_cxx_all) diff --git a/src/Makefile_Edje_Cxx.am b/src/Makefile_Edje_Cxx.am index 8d6b068e98..0b308b0499 100644 --- a/src/Makefile_Edje_Cxx.am +++ b/src/Makefile_Edje_Cxx.am @@ -15,6 +15,8 @@ lib/edje/Edje.hh: $(generated_edje_cxx_bindings) generated_edje_cxx_all = \ $(generated_edje_cxx_bindings) \ + lib/edje/edje_object.eo.impl.hh \ + lib/edje/edje_edit.eo.impl.hh \ lib/edje/Edje.hh CLEANFILES += $(generated_edje_cxx_all) diff --git a/src/Makefile_Efl_Cxx.am b/src/Makefile_Efl_Cxx.am index 9df7c60bdd..c555015729 100644 --- a/src/Makefile_Efl_Cxx.am +++ b/src/Makefile_Efl_Cxx.am @@ -26,6 +26,12 @@ lib/efl/Efl.hh: $(generated_efl_cxx_bindings) generated_efl_cxx_all = \ $(generated_efl_cxx_bindings) \ + lib/efl/interfaces/efl_control.eo.impl.hh \ + lib/efl/interfaces/efl_file.eo.impl.hh \ + lib/efl/interfaces/efl_image.eo.impl.hh \ + lib/efl/interfaces/efl_player.eo.impl.hh \ + lib/efl/interfaces/efl_text.eo.impl.hh \ + lib/efl/interfaces/efl_text_properties.eo.impl.hh \ lib/efl/Efl.hh CLEANFILES += $(generated_efl_cxx_all) diff --git a/src/Makefile_Eo_Cxx.am b/src/Makefile_Eo_Cxx.am index 2f7dda6ada..b6315c8746 100644 --- a/src/Makefile_Eo_Cxx.am +++ b/src/Makefile_Eo_Cxx.am @@ -3,7 +3,9 @@ generated_eo_cxx_bindings = \ lib/eo/eo_base.eo.hh \ -lib/eo/eo_abstract_class.eo.hh +lib/eo/eo_base.eo.impl.hh \ +lib/eo/eo_abstract_class.eo.hh \ +lib/eo/eo_abstract_class.eo.impl.hh ### Library diff --git a/src/Makefile_Eolian_Cxx.am b/src/Makefile_Eolian_Cxx.am index cd58e3e9c1..6dff2671df 100644 --- a/src/Makefile_Eolian_Cxx.am +++ b/src/Makefile_Eolian_Cxx.am @@ -15,6 +15,7 @@ lib/eolian_cxx/eo_validate.hh installed_eoliancxxgrammarheadersdir = $(includedir)/eolian-cxx-@VMAJ@/grammar/ dist_installed_eoliancxxgrammarheaders_DATA = \ lib/eolian_cxx/grammar/comment.hh \ +lib/eolian_cxx/grammar/eo_class_scope_guard_generator.hh \ lib/eolian_cxx/grammar/eo_class_constructors_generator.hh \ lib/eolian_cxx/grammar/eo_class_events_generator.hh \ lib/eolian_cxx/grammar/eo_class_functions_generator.hh \ @@ -95,10 +96,11 @@ tests/eolian_cxx/callback.eo.h \ tests/eolian_cxx/simple.eo.c \ tests/eolian_cxx/simple.eo.h \ tests/eolian_cxx/simple.eo.hh \ -tests/eolian_cxx/a.eo.hh tests/eolian_cxx/a.eo.c tests/eolian_cxx/a.eo.h \ -tests/eolian_cxx/b.eo.hh tests/eolian_cxx/b.eo.c tests/eolian_cxx/b.eo.h \ -tests/eolian_cxx/c.eo.hh tests/eolian_cxx/c.eo.c tests/eolian_cxx/c.eo.h \ -tests/eolian_cxx/d.eo.hh tests/eolian_cxx/d.eo.c tests/eolian_cxx/d.eo.h +tests/eolian_cxx/simple.eo.impl.hh \ +tests/eolian_cxx/a.eo.hh tests/eolian_cxx/a.eo.impl.hh tests/eolian_cxx/a.eo.c tests/eolian_cxx/a.eo.h \ +tests/eolian_cxx/b.eo.hh tests/eolian_cxx/b.eo.impl.hh tests/eolian_cxx/b.eo.c tests/eolian_cxx/b.eo.h \ +tests/eolian_cxx/c.eo.hh tests/eolian_cxx/c.eo.impl.hh tests/eolian_cxx/c.eo.c tests/eolian_cxx/c.eo.h \ +tests/eolian_cxx/d.eo.hh tests/eolian_cxx/d.eo.impl.hh tests/eolian_cxx/d.eo.c tests/eolian_cxx/d.eo.h tests_eolian_cxx_eolian_cxx_suite_CXXFLAGS = \ -I$(top_builddir)/src/lib/efl \ diff --git a/src/Makefile_Eolian_Cxx_Helper.am b/src/Makefile_Eolian_Cxx_Helper.am index cb54cc4c12..bb656c8f28 100644 --- a/src/Makefile_Eolian_Cxx_Helper.am +++ b/src/Makefile_Eolian_Cxx_Helper.am @@ -15,4 +15,7 @@ SUFFIXES += .eo.hh %.eo.hh: %.eo $(_EOLIAN_CXX_DEP) $(AM_V_EOLCXX)$(EOLIAN_CXX) $(EOLIAN_FLAGS) -o $@ $< +%.eo.impl.hh: %.eo.hh $(_EOLIAN_CXX_DEP) + true $< + CLEANFILES += $(BUILT_SOURCES) diff --git a/src/Makefile_Evas_Cxx.am b/src/Makefile_Evas_Cxx.am index 96d5ab13b3..abe1aa6a9c 100644 --- a/src/Makefile_Evas_Cxx.am +++ b/src/Makefile_Evas_Cxx.am @@ -49,15 +49,48 @@ lib/evas/Evas.hh: $(generated_evas_canvas_cxx_bindings) @for i in $(generated_evas_canvas_cxx_bindings); do echo "#include " >> $(top_builddir)/src/lib/evas/Evas.hh; done @echo @ECHO_E@ "#endif\n\n#endif\n" >> $(top_builddir)/src/lib/evas/Evas.hh -CLEANFILES += \ +generated_evas_canvas_cxx_all = \ $(generated_evas_canvas_cxx_bindings) \ +lib/evas/canvas/evas_line.eo.impl.hh \ +lib/evas/canvas/evas_polygon.eo.impl.hh \ +lib/evas/canvas/evas_rectangle.eo.impl.hh \ +lib/evas/canvas/evas_text.eo.impl.hh \ +lib/evas/canvas/evas_textblock.eo.impl.hh \ +lib/evas/canvas/evas_textgrid.eo.impl.hh \ +lib/evas/canvas/evas_signal_interface.eo.impl.hh \ +lib/evas/canvas/evas_object_smart.eo.impl.hh \ +lib/evas/canvas/evas_smart_clipped.eo.impl.hh \ +lib/evas/canvas/evas_table.eo.impl.hh \ +lib/evas/canvas/evas_common_interface.eo.impl.hh \ +lib/evas/canvas/evas_object.eo.impl.hh \ +lib/evas/canvas/evas_canvas.eo.impl.hh \ +lib/evas/canvas/evas_grid.eo.impl.hh \ +lib/evas/canvas/evas_image.eo.impl.hh \ +lib/evas/canvas/evas_out.eo.impl.hh \ +lib/evas/canvas/evas_draggable_interface.eo.impl.hh \ +lib/evas/canvas/evas_clickable_interface.eo.impl.hh \ +lib/evas/canvas/evas_scrollable_interface.eo.impl.hh \ +lib/evas/canvas/evas_selectable_interface.eo.impl.hh \ +lib/evas/canvas/evas_zoomable_interface.eo.impl.hh \ +lib/evas/canvas/evas_box.eo.impl.hh \ +lib/evas/canvas/evas_3d_camera.eo.impl.hh \ +lib/evas/canvas/evas_3d_light.eo.impl.hh \ +lib/evas/canvas/evas_3d_material.eo.impl.hh \ +lib/evas/canvas/evas_3d_mesh.eo.impl.hh \ +lib/evas/canvas/evas_3d_node.eo.impl.hh \ +lib/evas/canvas/evas_3d_object.eo.impl.hh \ +lib/evas/canvas/evas_3d_scene.eo.impl.hh \ +lib/evas/canvas/evas_3d_texture.eo.impl.hh \ lib/evas/Evas.hh +CLEANFILES += \ +$(generated_evas_canvas_cxx_all) + installed_evascxxmainheadersdir = $(includedir)/evas-cxx-@VMAJ@/ nodist_installed_evascxxmainheaders_DATA = lib/evas/Evas.hh installed_evascxxcanvasheadersdir = $(includedir)/evas-cxx-@VMAJ@/canvas -nodist_installed_evascxxcanvasheaders_DATA = $(generated_evas_canvas_cxx_bindings) +nodist_installed_evascxxcanvasheaders_DATA = $(generated_evas_canvas_cxx_all) ### Unit tests diff --git a/src/bin/eolian_cxx/convert.cc b/src/bin/eolian_cxx/convert.cc index d029999411..22ee22f0e5 100644 --- a/src/bin/eolian_cxx/convert.cc +++ b/src/bin/eolian_cxx/convert.cc @@ -141,6 +141,7 @@ _convert_property_set_to_function(Eolian_Class const& klass, efl::eolian::eo_function set_ = { efl::eolian::eo_function::regular_, + function_scope(prop_), function_name(prop_) + "_set", function_impl(prop_) + "_set", function_return_type(prop_, eolian_cxx::setter), @@ -168,6 +169,7 @@ _convert_property_get_to_function(Eolian_Class const& klass, efl::eolian::eo_function get_ = { efl::eolian::eo_function::regular_, + function_scope(prop_), function_name(prop_) + "_get", function_impl(prop_) + "_get", function_return_type(prop_, eolian_cxx::getter), @@ -291,6 +293,7 @@ convert_eolian_functions(efl::eolian::eo_class& cls, Eolian_Class const& klass) { cls.functions.push_back({ function_type(func), + function_scope(func), function_name(func), function_impl(func), function_return_type(func), diff --git a/src/bin/eolian_cxx/eolian_cxx.cc b/src/bin/eolian_cxx/eolian_cxx.cc index 93e9e442ab..7afa10da10 100644 --- a/src/bin/eolian_cxx/eolian_cxx.cc +++ b/src/bin/eolian_cxx/eolian_cxx.cc @@ -119,30 +119,58 @@ generate(const Eolian_Class& klass, eolian_cxx::options_type const& opts) { efl::eolian::eo_class cls = eolian_cxx::convert_eolian_class(klass); efl::eolian::eo_generator_options gen_opts = generator_options(klass); - std::string outname = opts.out_file.empty() ? (class_base_file(klass) + ".hh") : opts.out_file; + std::string header_decl_file_name = opts.out_file.empty() ? (class_base_file(klass) + ".hh") : opts.out_file; + + std::string header_impl_file_name = header_decl_file_name; + std::size_t dot_pos = header_impl_file_name.rfind(".hh"); + if (dot_pos != std::string::npos) + header_impl_file_name.insert(dot_pos, ".impl"); + else + header_impl_file_name.insert(header_impl_file_name.size(), ".impl"); + + std::size_t slash_pos = header_decl_file_name.rfind('/'); + gen_opts.header_decl_file_name = (slash_pos == std::string::npos) ? + header_decl_file_name : + header_decl_file_name.substr(slash_pos+1); + + slash_pos = header_impl_file_name.rfind('/'); + gen_opts.header_impl_file_name = (slash_pos == std::string::npos) ? + header_impl_file_name : + header_impl_file_name.substr(slash_pos+1); + if (!opts.out_dir.empty()) { - outname = opts.out_dir + "/" + outname; + header_decl_file_name = opts.out_dir + "/" + header_decl_file_name; + header_impl_file_name = opts.out_dir + "/" + header_impl_file_name; } if(opts.out_file == "-") { - efl::eolian::generate(std::cout, cls, gen_opts); + efl::eolian::generate(std::cout, std::cout, cls, gen_opts); } else { - std::ofstream outfile; - outfile.open(outname); - if (outfile.good()) - { - efl::eolian::generate(outfile, cls, gen_opts); - outfile.close(); - } - else + std::ofstream header_decl; + header_decl.open(header_decl_file_name); + if (!header_decl.good()) { EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain) - << "Can't open output file: " << outname << std::endl; + << "Can't open output file: " << header_decl_file_name << std::endl; return false; } + + std::ofstream header_impl; + header_impl.open(header_impl_file_name); + if (!header_impl.good()) + { + EINA_CXX_DOM_LOG_ERR(eolian_cxx::domain) + << "Can't open output file: " << header_impl_file_name << std::endl; + return false; + } + + efl::eolian::generate(header_decl, header_impl, cls, gen_opts); + + header_decl.close(); + header_impl.close(); } return true; } diff --git a/src/bin/eolian_cxx/eolian_wrappers.hh b/src/bin/eolian_cxx/eolian_wrappers.hh index d1b28a6f5f..5cad7976c0 100644 --- a/src/bin/eolian_cxx/eolian_wrappers.hh +++ b/src/bin/eolian_cxx/eolian_wrappers.hh @@ -25,6 +25,15 @@ getter_t const getter = {}; struct method_t { static constexpr ::Eolian_Function_Type value = ::EOLIAN_METHOD; }; method_t const method = {}; +inline efl::eolian::eolian_scope +eolian_scope_cxx(Eolian_Object_Scope s) +{ + using efl::eolian::eolian_scope; + return s == EOLIAN_SCOPE_PRIVATE ? eolian_scope::private_ : + s == EOLIAN_SCOPE_PROTECTED ? eolian_scope::protected_ : + eolian_scope::public_; +} + inline const Eolian_Class* class_from_file(std::string const& file) { @@ -195,11 +204,18 @@ function_is_constructor(Eolian_Class const& cls, Eolian_Function const& func) return ::eolian_function_is_constructor(&func, &cls); } +inline efl::eolian::eolian_scope +function_scope(Eolian_Function const& func) +{ + return eolian_scope_cxx(::eolian_function_scope_get(&func)); +} + inline bool function_is_visible(Eolian_Function const& func, Eolian_Function_Type func_type) { - return (::eolian_function_scope_get(&func) == EOLIAN_SCOPE_PUBLIC && - ! ::eolian_function_is_legacy_only(&func, func_type)); + Eolian_Object_Scope s = ::eolian_function_scope_get(&func); + return ((s == EOLIAN_SCOPE_PUBLIC || s == EOLIAN_SCOPE_PROTECTED) && + !::eolian_function_is_legacy_only(&func, func_type)); } inline bool @@ -388,6 +404,7 @@ event_create(Eolian_Class const& klass, const Eolian_Event *event_) std::string name_ = safe_str(name); std::transform(name_.begin(), name_.end(), name_.begin(), [](int c) { return c != ',' ? c : '_'; }); + event.scope = eolian_scope_cxx(::eolian_event_scope_get(event_)); event.name = normalize_spaces(name_); event.eo_name = safe_upper (find_replace(class_full_name(klass), ".", "_") + "_EVENT_" + event.name); diff --git a/src/bin/eolian_cxx/type_lookup_table.cc b/src/bin/eolian_cxx/type_lookup_table.cc index 7fa085e9ba..dd005518fb 100644 --- a/src/bin/eolian_cxx/type_lookup_table.cc +++ b/src/bin/eolian_cxx/type_lookup_table.cc @@ -13,25 +13,25 @@ type_lookup_table {"Ecore_Task_Cb", eolian_type::callback_, {"Ecore.h"}}, {"Ecore_Timeline_Cb", eolian_type::callback_, {"Ecore.h"}}, {"Edje_Signal_Cb", eolian_type::callback_, {"Edje.h"}}, - {"Eina_Accessor *", eolian_type::complex_, false, false, true, "::efl::eina::accessor", {"eina-cxx/eina_accessor.hh"}}, - {"Eina_Bool", eolian_type::simple_, false, false, false, "bool", {}}, - {"Eina_Bool *", eolian_type::simple_, false, false, false, "bool*", {}}, - {"Eina_Inlist *", eolian_type::complex_, false, false, true, "::efl::eina::range_inlist", {"eina-cxx/eina_inlist.hh"}}, - {"Eina_Inlist *", eolian_type::complex_, false, true, true, "::efl::eina::inlist", {"eina-cxx/eina_inlist.hh"}}, - {"Eina_Iterator *", eolian_type::complex_, false, false, true, "::efl::eina::iterator", {"eina-cxx/eina_iterator.hh"}}, - {"Eina_List *", eolian_type::complex_, false, false, true, "::efl::eina::range_list", {"eina-cxx/eina_list.hh"}}, - {"Eina_List *", eolian_type::complex_, false, true, true, "::efl::eina::list", {"eina-cxx/eina_list.hh"}}, - {"const Eina_List *", eolian_type::complex_, true, false, true, "::efl::eina::crange_list", {"eina-cxx/eina_list.hh"}}, + {"Eina_Accessor *", eolian_type::complex_, false, false, true, false, "::efl::eina::accessor", {"eina-cxx/eina_accessor.hh"}}, + {"Eina_Bool", eolian_type::simple_, false, false, false, false, "bool", {}}, + {"Eina_Bool *", eolian_type::simple_, false, false, false, false, "bool*", {}}, + {"Eina_Inlist *", eolian_type::complex_, false, false, true, true, "::efl::eina::range_inlist", {"eina-cxx/eina_inlist.hh"}}, + {"Eina_Inlist *", eolian_type::complex_, false, true, true, true, "::efl::eina::inlist", {"eina-cxx/eina_inlist.hh"}}, + {"Eina_Iterator *", eolian_type::complex_, false, false, true, true, "::efl::eina::iterator", {"eina-cxx/eina_iterator.hh"}}, + {"Eina_List *", eolian_type::complex_, false, false, true, true, "::efl::eina::range_list", {"eina-cxx/eina_list.hh"}}, + {"Eina_List *", eolian_type::complex_, false, true, true, true, "::efl::eina::list", {"eina-cxx/eina_list.hh"}}, + {"const Eina_List *", eolian_type::complex_, true, false, true, true, "::efl::eina::crange_list", {"eina-cxx/eina_list.hh"}}, {"Eio_Filter_Direct_Cb", eolian_type::callback_, {"Eio.h"}}, - {"Emodel *", eolian_type::simple_, false, false, true, "::emodel", {"Emodel.hh"}}, - {"Eo *", eolian_type::simple_, false, true, true, "::efl::eo::concrete", {"eo_concrete.hh"}}, - {"Eo *", eolian_type::simple_, false, false, true, "::efl::eo::concrete", {"eo_concrete.hh"}}, + {"Emodel *", eolian_type::simple_, false, false, true, false, "::emodel", {"Emodel.hh"}}, + {"Eo *", eolian_type::simple_, false, true, true, false, "::efl::eo::concrete", {"eo_concrete.hh"}}, + {"Eo *", eolian_type::simple_, false, false, true, false, "::efl::eo::concrete", {"eo_concrete.hh"}}, //{"Evas_Object_Box_Layout", eolian_type::callback_, {"Evas.h"}}, - {"Evas_Object *", eolian_type::simple_, false, false, true, "::evas::object", {"canvas/evas_object.eo.hh"}}, - {"char *", eolian_type::simple_, false, true, true, "std::unique_ptr", {"memory"}}, - {"const Eina_Inlist *", eolian_type::complex_, false, false, true, "::efl::eina::range_inlist", {"eina-cxx/eina_inlist.hh"}}, - {"const Eina_List *", eolian_type::complex_, false, false, true, "::efl::eina::range_list", {"eina-cxx/eina_ptrlist.hh"}}, - {"const char *", eolian_type::simple_, false, false, true, "std::string", {"string"}}, + {"Evas_Object *", eolian_type::simple_, false, false, true, false, "::evas::object", {"canvas/evas_object.eo.hh"}}, + {"char *", eolian_type::simple_, false, true, true, false, "std::unique_ptr", {"memory"}}, + {"const Eina_Inlist *", eolian_type::complex_, false, false, true, true, "::efl::eina::range_inlist", {"eina-cxx/eina_inlist.hh"}}, + {"const Eina_List *", eolian_type::complex_, false, false, true, true, "::efl::eina::range_list", {"eina-cxx/eina_ptrlist.hh"}}, + {"const char *", eolian_type::simple_, false, false, true, true, "::efl::eina::string_view", {"string"}}, }; } diff --git a/src/bindings/eo_cxx/eo_concrete.hh b/src/bindings/eo_cxx/eo_concrete.hh index 63029a14e7..9e328b1d92 100644 --- a/src/bindings/eo_cxx/eo_concrete.hh +++ b/src/bindings/eo_cxx/eo_concrete.hh @@ -21,6 +21,12 @@ #endif #endif +#if !defined(EFL_DOXYGEN) && !defined(EO_CXX_INHERIT) +# define EO_CXX_INHERIT(name) ::eo_cxx::name +#elif !defined(EO_CXX_INHERIT) +# define EO_CXX_INHERIT(name) ::name +#endif + namespace efl { namespace eo { /// @addtogroup Efl_Cxx_API diff --git a/src/bindings/eo_cxx/eo_cxx_interop.hh b/src/bindings/eo_cxx/eo_cxx_interop.hh index ba6a473fc6..08ca3005ba 100644 --- a/src/bindings/eo_cxx/eo_cxx_interop.hh +++ b/src/bindings/eo_cxx/eo_cxx_interop.hh @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -27,6 +28,20 @@ to_c(eina::optional const& x) return x->c_str(); } +inline const char* +to_c(eina::string_view const& x) +{ + return x.data(); +} + +inline const char* +to_c(eina::optional const& x) +{ + if (!x) + return nullptr; + return x->data(); +} + inline const char* to_c(efl::eina::stringshare const& x) { @@ -196,6 +211,20 @@ to_cxx(const char* x, std::tuple, tag, tag) +{ + return eina::string_view(x); +} + +inline eina::optional +to_cxx(const char* x, std::tuple, tag >) +{ + if (!x) + return nullptr; + return eina::string_view(x); +} + template struct traits { @@ -216,6 +245,13 @@ struct traits typedef const char* type; }; +template +struct traits + , T>::value>::type> +{ + typedef const char* type; +}; + template inline efl::eina::range_list to_cxx(const Eina_List* x, std::tuple, tag< efl::eina::range_list >) @@ -407,6 +443,22 @@ Eina_Bool free_callback_calback(void* data, Eo* obj EINA_UNUSED return EO_CALLBACK_CONTINUE; } +template +inline +std::vector& get_static_callback_vector() +{ + static std::vector vec; + return vec; +} + +template +inline +F* alloc_static_callback(F&& f) +{ + get_static_callback_vector().push_back(std::forward(f)); + return &(get_static_callback_vector().back()); +} + } } // namespace efl { namespace eolian { #endif // EFL_EOLIAN_INTEROP_HH diff --git a/src/examples/eolian_cxx/Makefile.am b/src/examples/eolian_cxx/Makefile.am index a0510f1d57..78420952a1 100644 --- a/src/examples/eolian_cxx/Makefile.am +++ b/src/examples/eolian_cxx/Makefile.am @@ -66,9 +66,11 @@ GENERATED = \ colourable.eo.c \ colourable.eo.h \ colourable.eo.hh \ + colourable.eo.impl.hh \ colourablesquare.eo.c \ colourablesquare.eo.h \ - colourablesquare.eo.hh + colourablesquare.eo.hh \ + colourablesquare.eo.impl.hh BUILT_SOURCES = $(GENERATED) CLEANFILES += $(BUILT_SOURCES) @@ -135,6 +137,9 @@ eolian_cxx_complex_types_01_SOURCES = eolian_cxx_complex_types_01.cc %.eo.hh: %.eo $(AM_V_EOLCXX)$(EOLIAN_CXX) $(EOLIAN_FLAGS) -I${abs_srcdir} -o $@ $< +%.eo.impl.hh: %.eo.hh + true $< + %.eo.c: %.eo $(AM_V_EOL)$(EOLIAN_GEN) --eo --legacy $(EOLIAN_FLAGS) --gc -o $@ $< diff --git a/src/lib/eolian_cxx/eo_generate.hh b/src/lib/eolian_cxx/eo_generate.hh index a509201baa..97e53bb9dc 100644 --- a/src/lib/eolian_cxx/eo_generate.hh +++ b/src/lib/eolian_cxx/eo_generate.hh @@ -10,9 +10,12 @@ namespace efl { namespace eolian { inline void -generate(std::ostream& out, eo_class const& cls, eo_generator_options const& opts) +generate(std::ostream& header_decl, + std::ostream& header_impl, + eo_class const& cls, + eo_generator_options const& opts) { - grammar::eo_header_generator(out, cls, opts); + grammar::eo_headers_generator(header_decl, header_impl, cls, opts); } } } diff --git a/src/lib/eolian_cxx/eo_types.hh b/src/lib/eolian_cxx/eo_types.hh index 38f2d38127..b50e692ac1 100644 --- a/src/lib/eolian_cxx/eo_types.hh +++ b/src/lib/eolian_cxx/eo_types.hh @@ -21,6 +21,12 @@ typedef std::vector functions_container_type; typedef std::vector parameters_container_type; typedef std::vector events_container_type; + +enum class eolian_scope + { + public_, protected_, private_ + }; + struct eolian_type { enum category_type @@ -34,6 +40,7 @@ struct eolian_type , is_const(false) , is_own(false) , is_class(false) + , binding_requires_optional(false) , binding() , includes() {} @@ -43,6 +50,7 @@ struct eolian_type bool is_const_, bool is_own_, bool is_class_, + bool binding_requires_optional_, std::string binding_, includes_container_type includes_) : native(native_) @@ -50,6 +58,7 @@ struct eolian_type , is_const(is_const_) , is_own(is_own_) , is_class(is_class_) + , binding_requires_optional(binding_requires_optional_) , binding(binding_) , includes(includes_) { @@ -60,7 +69,7 @@ struct eolian_type eolian_type(std::string native_, category_type category_, includes_container_type const& includes_) - : eolian_type(native_, category_, false, false, false, "", includes_) + : eolian_type(native_, category_, false, false, false, false, "", includes_) { assert(category == callback_); } @@ -70,6 +79,7 @@ struct eolian_type bool is_const; bool is_own; bool is_class; + bool binding_requires_optional; std::string binding; includes_container_type includes; }; @@ -110,7 +120,7 @@ struct eolian_type_instance }; const efl::eolian::eolian_type -void_type { "void", efl::eolian::eolian_type::simple_, false, false, false, "", {} }; +void_type { "void", efl::eolian::eolian_type::simple_, false, false, false, false, "", {} }; inline bool type_is_void(eolian_type_instance const& type) @@ -150,6 +160,19 @@ type_is_class(eolian_type_instance const& type) return type_is_class(type.front()); } +inline bool +type_binding_requires_optional(eolian_type const& type) +{ + return type.binding_requires_optional; +} + +inline bool +type_binding_requires_optional(eolian_type_instance const& type) +{ + assert(!type.empty()); + return type_binding_requires_optional(type.front()); +} + inline bool type_is_nonull(eolian_type_instance const& type) { @@ -212,6 +235,8 @@ type_is_callback(eolian_type_instance const& type_ins) struct eo_generator_options { + std::string header_decl_file_name; + std::string header_impl_file_name; includes_container_type cxx_headers; includes_container_type c_headers; }; @@ -256,6 +281,7 @@ struct eo_function regular_, class_ }; eo_function_type type; + eolian_scope scope; std::string name; std::string impl; eolian_type_instance ret; @@ -265,6 +291,7 @@ struct eo_function struct eo_event { + eolian_scope scope; std::string name; std::string eo_name; //parameters_container_type params; // XXX desirable. diff --git a/src/lib/eolian_cxx/grammar/comment.hh b/src/lib/eolian_cxx/grammar/comment.hh index 92cc03f35a..21fa3ea38d 100644 --- a/src/lib/eolian_cxx/grammar/comment.hh +++ b/src/lib/eolian_cxx/grammar/comment.hh @@ -19,15 +19,17 @@ struct comment { std::string _doc; int _tab; - comment(std::string const& doc, int tab = 0) - : _doc(doc), _tab(tab) + std::string _if_empty; + comment(std::string const& doc, int tab = 0, std::string const& if_empty = "") + : _doc(doc), _tab(tab), _if_empty(if_empty) {} }; inline std::ostream& operator<<(std::ostream& out, comment const& x) { - std::istringstream ss(x._doc); + std::string const& doc = !x._doc.empty() ? x._doc : x._if_empty; + std::istringstream ss(doc); std::string line; while(std::getline(ss, line)) { diff --git a/src/lib/eolian_cxx/grammar/eo_class_constructors_generator.hh b/src/lib/eolian_cxx/grammar/eo_class_constructors_generator.hh index 86a515edb9..268855284d 100644 --- a/src/lib/eolian_cxx/grammar/eo_class_constructors_generator.hh +++ b/src/lib/eolian_cxx/grammar/eo_class_constructors_generator.hh @@ -46,7 +46,7 @@ operator<<(std::ostream& out, class_inheritance const& x) last = cls.ancestors.cend(); for (it = first; it != last; ++it) { - out << tab(2) << ", ::" << abstract_namespace << "::" << *it << endl; + out << tab(2) << ", EO_CXX_INHERIT(" << *it << ")" << endl; } return out; } @@ -115,6 +115,9 @@ operator<<(std::ostream& out, functors_constructor_methods const& x) { 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 @@ -176,7 +179,10 @@ operator<<(std::ostream& out, functors_constructor_methods const& x) ); // Close struct - out << tab(1) << "};" << endl << endl; + out << tab(1) << "};" << endl; + + // End documentation condition + out << comment("@endcond", 1) << endl; } return out; @@ -208,7 +214,7 @@ operator<<(std::ostream& out, constructor_method_function_declarations const& x) continue; } - out << comment(c.comment, 0) + out << comment(c.comment, 1) << template_parameters_declaration(c.params, 1) << tab(1) << constructor_functor_type_decl(c) << " " << c.name << "(" << parameters_declaration(c.params) << ") const;" << endl << endl; @@ -253,6 +259,51 @@ operator<<(std::ostream& out, constructor_method_function_definitions const& x) 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 " : "") << "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; + } + + out << tab(2) << "Example:" << endl + << tab(2) << "@code" << endl + << tab(2) << full_name(x._cls, false) << " my_" << x._cls.name << "(" << endl; + + for (eo_constructor const& c : x._cls.constructors) + out << tab(3) << "my_" << x._cls.name << "." << c.name << "(" << parameters_names(c.params) << ")," << endl; + + out << tab(3) << "efl::eo::parent = parent_object);" << endl + << tab(2) << "@endcode" << endl + << endl; + + for (eo_constructor const& c : x._cls.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; @@ -274,6 +325,8 @@ operator<<(std::ostream& out, constructor_with_constructor_methods const& x) cb_count += parameters_count_callbacks((*it).params); } + out << comment_constructor_with_constructor_methods(x._cls); + if (cb_count != 0) { out << tab(1) << "template <"; @@ -398,6 +451,8 @@ struct function_call_constructor_methods 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, diff --git a/src/lib/eolian_cxx/grammar/eo_class_events_generator.hh b/src/lib/eolian_cxx/grammar/eo_class_events_generator.hh index 4b7a9b3d4d..b86b4c4243 100644 --- a/src/lib/eolian_cxx/grammar/eo_class_events_generator.hh +++ b/src/lib/eolian_cxx/grammar/eo_class_events_generator.hh @@ -5,6 +5,7 @@ #include #include "type_generator.hh" +#include "eo_class_scope_guard_generator.hh" #include "tab.hh" #include "comment.hh" @@ -42,7 +43,8 @@ struct event_callback_add inline std::ostream& operator<<(std::ostream& out, event_callback_add const& x) { - out << tab(1) << "template " << endl + out << comment(x._event.comment, 1) + << tab(1) << "template " << endl << tab(1) << "::efl::eo::signal_connection" << endl << tab(1) << "callback_" << x._event.name << "_add(F && callback_," << endl << tab(8) << "::efl::eo::callback_priority priority_ =" << endl @@ -75,7 +77,8 @@ struct event_callback_call inline std::ostream& operator<<(std::ostream& out, event_callback_call const& x) { - out << tab(1) << "template " << endl + out << comment(x._event.comment, 1) + << tab(1) << "template " << endl << tab(1) << "void" << endl << tab(1) << "callback_" << x._event.name << "_call(T* info)" << endl << tab(1) << "{" << endl @@ -99,8 +102,12 @@ operator<<(std::ostream& out, events const& x) { for (eo_event const& e : x._events) { + out << scope_guard_head(x._cls, e); + out << event_callback_add(e, x._cls, x._add_cast_to_t) << endl << event_callback_call(e, x._add_cast_to_t); + + out << scope_guard_tail(x._cls, e) << endl; } out << endl; return out; diff --git a/src/lib/eolian_cxx/grammar/eo_class_functions_generator.hh b/src/lib/eolian_cxx/grammar/eo_class_functions_generator.hh index 56b450bada..1a64a8ca98 100644 --- a/src/lib/eolian_cxx/grammar/eo_class_functions_generator.hh +++ b/src/lib/eolian_cxx/grammar/eo_class_functions_generator.hh @@ -10,6 +10,7 @@ #include "parameters_generator.hh" #include "type_generator.hh" #include "namespace_generator.hh" +#include "eo_class_scope_guard_generator.hh" namespace efl { namespace eolian { namespace grammar { @@ -52,7 +53,7 @@ operator<<(std::ostream& out, function_declaration const& x) out << reinterpret_type(func.ret) << " " << func.name << "(" << parameters_declaration(func.params) - << (is_static ? ");" : ") const;") << endl << endl; + << (is_static ? ");" : ") const;") << endl; return out; } @@ -91,10 +92,7 @@ operator<<(std::ostream& out, function_definition const& x) out << tab(1) << func.ret.front().native << " _tmp_ret;" << endl; - if (!is_static) - out << callbacks_heap_alloc("_concrete_eo_ptr()", func.params, 1); - - // TODO : register free callback for static methods + out << callbacks_heap_alloc("_concrete_eo_ptr()", func.params, is_static, 1); out << tab(1) << "eo_do(" << (is_static ? "_eo_class(), " : "_concrete_eo_ptr(), ") @@ -103,7 +101,7 @@ operator<<(std::ostream& out, function_definition const& x) if (!function_is_void(func)) out << tab(1) << "return " << to_cxx(func.ret, "_tmp_ret") << ";" << endl; - out << "}" << endl << endl; + out << "}" << endl; return out; } @@ -120,7 +118,9 @@ operator<<(std::ostream& out, function_declarations const& x) { for (eo_function const& f : x._cls.functions) { - out << function_declaration(x._cls, f) << endl; + out << scope_guard_head(x._cls, f) + << function_declaration(x._cls, f) + << scope_guard_tail(x._cls, f) << endl; } return out; } @@ -140,7 +140,9 @@ operator<<(std::ostream& out, function_definitions const& x) { for (eo_function const& f : x._cls.functions) { - out << function_definition(x._cls, f, x._concrete) << endl; + out << scope_guard_head(x._cls, f) + << function_definition(x._cls, f, x._concrete) + << scope_guard_tail(x._cls, f) << endl; } return out; } diff --git a/src/lib/eolian_cxx/grammar/eo_class_generator.hh b/src/lib/eolian_cxx/grammar/eo_class_generator.hh index 15850abfd3..c1d227cbcc 100644 --- a/src/lib/eolian_cxx/grammar/eo_class_generator.hh +++ b/src/lib/eolian_cxx/grammar/eo_class_generator.hh @@ -40,7 +40,8 @@ struct concrete_eo_ptr_getter inline std::ostream& operator<<(std::ostream& out, concrete_eo_ptr_getter const&) { - out << tab(1) << "Eo* _concrete_eo_ptr() const" << endl + out << comment("@internal", 1) + << tab(1) << "Eo* _concrete_eo_ptr() const" << endl << tab(1) << "{" << endl << tab(2) << "return static_cast<::efl::eo::concrete const*>(static_cast(this))->_eo_ptr();" << endl << tab(1) << "}" << endl << endl; @@ -123,6 +124,8 @@ struct abstract_address_of inline std::ostream& operator<<(std::ostream& out, abstract_address_of const& x) { + out << comment("@cond LOCAL", 1); + out << tab(1) << "template " << endl << tab(1) << "struct address_of" << endl << tab(1) << "{" << endl @@ -134,7 +137,9 @@ operator<<(std::ostream& out, abstract_address_of const& x) << tab(1) << "struct address_const_of" << endl << tab(1) << "{" << endl << tab(2) << address_of_to_pointer(x._cls, true) << endl - << tab(1) << "};" << endl << endl; + << tab(1) << "};" << endl; + + out << comment("@endcond", 1) << endl; return out; } @@ -168,6 +173,7 @@ struct concrete_address_of inline std::ostream& operator<<(std::ostream& out, concrete_address_of const& x) { + out << comment("@cond LOCAL", 1); std::vector names {"address_of", "address_const_of"}; for (int is_const = 0; is_const != 2; ++is_const) { @@ -189,16 +195,18 @@ operator<<(std::ostream& out, concrete_address_of const& x) << (is_const ? " const" : "") << " { return " << name << "(this); }" << endl << endl; } + out << comment("@endcond", 1) << endl; return out; } inline void -eo_class_generator(std::ostream& out, eo_class const& cls) +eo_class_declarations_generator(std::ostream& out, eo_class const& cls) { out << namespace_head(cls) << "struct " << cls.name << ";" << endl << endl << namespace_tail(cls) + << comment("@cond EO_CXX_ABSTRACT") << "namespace " << abstract_namespace << " {" << endl << endl << namespace_head(cls) << comment(cls.comment) @@ -209,12 +217,14 @@ eo_class_generator(std::ostream& out, eo_class const& cls) << eo_class_getter(cls) << class_implicit_conversion_declaration(cls) << abstract_address_of(cls) - << "private:" << endl + << "private:" << endl << endl << concrete_eo_ptr_getter(cls) << "};" << endl << endl << namespace_tail(cls) - << "}" << endl << endl + << "}" << endl + << comment("@endcond") << endl << namespace_head(cls) + << comment(cls.comment, 0, "@brief Class " + cls.name) << "struct " << cls.name << endl << tab(2) << ": ::efl::eo::concrete" << endl << class_inheritance(cls) @@ -229,15 +239,22 @@ eo_class_generator(std::ostream& out, eo_class const& cls) << events(cls, cls.concrete_events) << endl << eo_class_getter(cls) << concrete_address_of(cls) - << "private:" << endl + << "private:" << endl << endl << function_call_constructor_methods(cls) - << tab(2) << "Eo* _concrete_eo_ptr() const { return _eo_ptr(); }" << endl + << comment("@internal", 1) + << tab(1) << "Eo* _concrete_eo_ptr() const { return _eo_ptr(); }" << endl << "};" << endl << endl << "static_assert(sizeof(" << full_name(cls) << ") == sizeof(Eo*), \"\");" << endl << "static_assert(std::is_standard_layout<" << full_name(cls) << ">::value, \"\");" << endl << endl << namespace_tail(cls) - << constructor_method_function_definitions(cls) + << endl; +} + +inline void +eo_class_definitions_generator(std::ostream& out, eo_class const& cls) +{ + out << constructor_method_function_definitions(cls) << function_definitions(cls, true) << function_definitions(cls, false) << class_implicit_conversion_definition(cls); diff --git a/src/lib/eolian_cxx/grammar/eo_class_scope_guard_generator.hh b/src/lib/eolian_cxx/grammar/eo_class_scope_guard_generator.hh new file mode 100644 index 0000000000..9d545c33b3 --- /dev/null +++ b/src/lib/eolian_cxx/grammar/eo_class_scope_guard_generator.hh @@ -0,0 +1,61 @@ +#ifndef EOLIAN_CXX_STD_EO_CLASS_SCOPE_GUARD_GENERATOR_HH +#define EOLIAN_CXX_STD_EO_CLASS_SCOPE_GUARD_GENERATOR_HH + +#include + +#include "type_generator.hh" + +namespace efl { namespace eolian { namespace grammar { + +template +struct _scope_guard_head +{ + eo_class const& _cls; + T const& _e; + _scope_guard_head(eo_class const& cls, T const& e) + : _cls(cls), _e(e) {} +}; + +template +_scope_guard_head scope_guard_head(eo_class const& cls, T const& e) +{ + return _scope_guard_head(cls, e); +} + +template +inline std::ostream& +operator<<(std::ostream& out, _scope_guard_head const& x) +{ + assert(x._e.scope != eolian_scope::private_); + if (x._e.scope == eolian_scope::protected_) + out << "#ifdef " << name_upper(x._cls) << "_PROTECTED" << endl; + return out; +} + +template +struct _scope_guard_tail +{ + eo_class const& _cls; + T const& _e; + _scope_guard_tail(eo_class const& cls, T const& e) + : _cls(cls), _e(e) {} +}; + +template +struct _scope_guard_tail scope_guard_tail(eo_class const& cls, T const& e) +{ + return _scope_guard_tail(cls, e); +} + +template +inline std::ostream& +operator<<(std::ostream& out, _scope_guard_tail const& x) +{ + if (x._e.scope == eolian_scope::protected_) + out << "#endif" << endl; + return out; +} + +} } } + +#endif diff --git a/src/lib/eolian_cxx/grammar/eo_header_generator.hh b/src/lib/eolian_cxx/grammar/eo_header_generator.hh index 56f4e28f97..9ec4a3b480 100644 --- a/src/lib/eolian_cxx/grammar/eo_header_generator.hh +++ b/src/lib/eolian_cxx/grammar/eo_header_generator.hh @@ -115,14 +115,30 @@ include_headers(std::ostream& out, } inline void -eo_header_generator(std::ostream& out, eo_class const& cls, eo_generator_options const& opts) +include_header_impl(std::ostream& out, + eo_class const& cls EINA_UNUSED, + eo_generator_options const& opts) { - onceguard_head(out, cls); - include_headers(out, cls, opts); - eo_class_generator(out, cls); - eo_inheritance_detail_generator(out, cls); - onceguard_tail(out, cls); - out << endl; + out << "#include \"" << opts.header_impl_file_name << "\"" << endl << endl; +} + +inline void +eo_headers_generator(std::ostream& header_decl, + std::ostream& header_impl, + eo_class const& cls, + eo_generator_options const& opts) +{ + onceguard_head(header_decl, cls); + include_headers(header_decl, cls, opts); + eo_class_declarations_generator(header_decl, cls); + include_header_impl(header_decl, cls, opts); + onceguard_tail(header_decl, cls); + header_decl << endl; + + header_impl << comment("@cond EO_CXX_EO_IMPL") << endl; + eo_class_definitions_generator(header_impl, cls); + eo_inheritance_detail_generator(header_impl, cls); + header_impl << endl << comment("@endcond") << endl; } } } } // namespace efl { namespace eolian { namespace grammar { diff --git a/src/lib/eolian_cxx/grammar/inheritance_base_generator.hh b/src/lib/eolian_cxx/grammar/inheritance_base_generator.hh index 38382d5092..11b8f2a29e 100644 --- a/src/lib/eolian_cxx/grammar/inheritance_base_generator.hh +++ b/src/lib/eolian_cxx/grammar/inheritance_base_generator.hh @@ -30,9 +30,10 @@ _ns_as_prefix(eo_class const& cls) struct inheritance_operation { eo_class const& _cls; + eo_function const& _func; functions_container_type::size_type _idx; - inheritance_operation(eo_class const& cls, functions_container_type::size_type idx) - : _cls(cls), _idx(idx) + inheritance_operation(eo_class const& cls, eo_function const& func, functions_container_type::size_type idx) + : _cls(cls), _func(func), _idx(idx) {} }; @@ -40,7 +41,7 @@ inline std::ostream& operator<<(std::ostream& out, inheritance_operation const& x) { assert(x._idx < x._cls.functions.size()); - eo_function const& func = x._cls.functions[x._idx]; + eo_function const& func = x._func; out << tab(1) << "ops[" << x._idx << "].func = reinterpret_cast(& ::" << _ns_as_prefix(x._cls) << "_" @@ -74,17 +75,30 @@ operator<<(std::ostream& out, inheritance_operations_description const& x) << ", Eo_Op_Description* ops)" << endl << "{" << endl << tab(1) << "(void)ops;" << endl; - functions_container_type::size_type n_ops = x._cls.functions.size(); - for (functions_container_type::size_type i=0; i < n_ops; ++i) + + auto funcs = x._cls.functions; + auto part = std::stable_partition(funcs.begin(), funcs.end(), [](eo_function const& f){ return f.scope == eolian_scope::public_; }); + + functions_container_type::size_type op_idx = 0; + for (auto it = funcs.begin(); it != part; ++it, ++op_idx) { - out << inheritance_operation(x._cls, i); + out << inheritance_operation(x._cls, *it, op_idx); + } + + if (part != funcs.end()) + { + out << scope_guard_head(x._cls, *part); + for (auto it = part; it != funcs.end(); ++it, ++op_idx) + out << inheritance_operation(x._cls, *it, op_idx); + out << scope_guard_tail(x._cls, *part); } for (std::string const& parent : x._cls.parents) { out << tab(1) << "initialize_operation_description(::efl::eo::detail::tag<::" - << parent << ">(), &ops[" << x._cls.functions.size() << s << "]);" << endl; + << parent << ">(), &ops[operation_description_class_size< " + << full_name(x._cls) << " >::value" << s << "]);" << endl; s += " + operation_description_class_size<::" + parent + ">::value"; } @@ -110,6 +124,9 @@ operator<<(std::ostream& out, inheritance_wrappers const& x) for (it = first; it != last; ++it) { eo_function const& func = *it; + + out << scope_guard_head(x._cls, func); + out << "template " << endl << reinterpret_type(func.ret) << " " << _ns_as_prefix(x._cls) << "_" @@ -140,7 +157,9 @@ operator<<(std::ostream& out, inheritance_wrappers const& x) if (!function_is_void(func)) out << tab(1) << "return _tmp_ret;" << endl; - out << "}" << endl << endl; + out << "}" << endl; + + out << scope_guard_tail(x._cls, func) << endl; } return out; } @@ -148,8 +167,9 @@ operator<<(std::ostream& out, inheritance_wrappers const& x) struct inheritance_base_operations_size { eo_class const& _cls; - inheritance_base_operations_size(eo_class const& cls) - : _cls(cls) + functions_container_type const& _funcs; + inheritance_base_operations_size(eo_class const& cls, functions_container_type const& funcs) + : _cls(cls), _funcs(funcs) {} }; @@ -160,8 +180,8 @@ operator<<(std::ostream& out, inheritance_base_operations_size const& x) << endl << "struct operation_description_class_size< " << full_name(x._cls) << " >" << endl << "{" << endl - << tab(1) << "static const int value = " - << x._cls.functions.size(); + << tab(1) << "static constexpr int value = " + << x._funcs.size(); for (std::string const& parent : x._cls.parents) { @@ -175,6 +195,27 @@ operator<<(std::ostream& out, inheritance_base_operations_size const& x) return out; } +struct inheritance_base_operations_size_scopes +{ + eo_class const& _cls; + inheritance_base_operations_size_scopes(eo_class const& cls) + : _cls(cls) + {} +}; + +inline std::ostream& +operator<<(std::ostream& out, inheritance_base_operations_size_scopes const& x) +{ + auto funcs = x._cls.functions; + auto part = std::stable_partition(funcs.begin(), funcs.end(), [](eo_function const& f){ return f.scope == eolian_scope::public_; }); + + out << "#ifdef " << name_upper(x._cls) << "_PROTECTED" << endl + << inheritance_base_operations_size(x._cls, funcs) + << "#else" << endl + << inheritance_base_operations_size(x._cls, {funcs.begin(), part}) + << "#endif" << endl << endl; + return out; +} struct inheritance_base_operations_extensions { @@ -230,7 +271,7 @@ operator<<(std::ostream& out, inheritance_base_operations_function const& x) if (!is_void) out << tab(3) << func.ret.front().native << " _tmp_ret = {};" << endl; - out << callbacks_heap_alloc("dynamic_cast(this)->_eo_ptr()", func.params, 3) + out << callbacks_heap_alloc("dynamic_cast(this)->_eo_ptr()", func.params, function_is_static(x._func), 3) << endl; out << tab(3) @@ -241,7 +282,7 @@ operator<<(std::ostream& out, inheritance_base_operations_function const& x) if (!is_void) out << tab(4) << "return " << to_cxx(func.ret, "_tmp_ret") << ";" << endl; - return out << tab(2) << "}" << endl << endl; + return out << tab(2) << "}" << endl; } struct inheritance_base_operations @@ -265,7 +306,9 @@ operator<<(std::ostream& out, inheritance_base_operations const& x) last = x._cls.functions.end(); for (it = first; it != last; ++it) { + out << scope_guard_head(x._cls, *it); out << inheritance_base_operations_function(x._cls, *it); + out << scope_guard_tail(x._cls, *it) << endl; } out << tab(1) << "};" << endl << "};" << endl << endl; @@ -365,7 +408,7 @@ eo_inheritance_detail_generator(std::ostream& out, eo_class const& cls) out << inheritance_wrappers(cls) << "namespace efl { namespace eo { namespace detail {" << endl << endl << inheritance_base_operations(cls) << endl - << inheritance_base_operations_size(cls) + << inheritance_base_operations_size_scopes(cls) << inheritance_operations_description(cls) << inheritance_call_constructors(cls) << inheritance_eo_class_getter(cls) diff --git a/src/lib/eolian_cxx/grammar/parameters_generator.hh b/src/lib/eolian_cxx/grammar/parameters_generator.hh index 20f9e99c52..2d590f2b35 100644 --- a/src/lib/eolian_cxx/grammar/parameters_generator.hh +++ b/src/lib/eolian_cxx/grammar/parameters_generator.hh @@ -105,30 +105,6 @@ operator<<(std::ostream& out, callback_tmp const& x) return out << "_tmp_" << x._name; } -struct -callback_parameter_heap_alloc -{ - eolian_type_instance const& _type; - std::string const& _name; - int _tab; - callback_parameter_heap_alloc(eolian_type_instance const& type, std::string const& name, int tab) - : _type(type) - , _name(name) - , _tab(tab) - {} -}; - -inline std::ostream& -operator<<(std::ostream& out, callback_parameter_heap_alloc const& x) -{ - out << tab(x._tab) << parameter_remove_reference_typedef(x._type, x._name) << endl - << tab(x._tab) << parameter_no_ref_type(x._type, x._name) << "* " - << callback_tmp(x._name) << " = new " - << parameter_no_ref_type(x._type, x._name) << "(std::forward<" - << template_parameter_type(x._type, x._name) << ">(" << x._name << "));" << endl; - return out; -} - struct callback_parameter_free_ev_add { @@ -157,10 +133,12 @@ callbacks_heap_alloc { std::string const& _eo_raw_expr; parameters_container_type const& _params; + bool _is_static_func; int _tab; - callbacks_heap_alloc(std::string const& eo_raw_expr, parameters_container_type const& params, int tab) + callbacks_heap_alloc(std::string const& eo_raw_expr, parameters_container_type const& params, bool is_static_func, int tab) : _eo_raw_expr(eo_raw_expr) , _params(params) + , _is_static_func(is_static_func) , _tab(tab) {} }; @@ -171,12 +149,30 @@ operator<<(std::ostream& out, callbacks_heap_alloc const& x) auto first = x._params.cbegin(), last = x._params.cend(); for (auto it = first; it != last; ++it) { - if (type_is_callback((*it).type) && it+1 != last) + auto type = (*it).type; + auto name = (*it).name; + if (type_is_callback(type) && it+1 != last) { - out << callback_parameter_heap_alloc((*it).type, (*it).name, x._tab) - << tab(x._tab) - << callback_parameter_free_ev_add(x._eo_raw_expr, (*it).type, (*it).name) - << endl << endl; + + out << tab(x._tab) << parameter_remove_reference_typedef(type, name) << endl + << tab(x._tab) << parameter_no_ref_type(type, name) << "* " + << callback_tmp(name) << " = "; + + if (!x._is_static_func) + { + out << "new " << parameter_no_ref_type(type, name) + << "(std::forward< " + << template_parameter_type(type, name) << " >(" << name << "));" << endl + << tab(x._tab) + << callback_parameter_free_ev_add(x._eo_raw_expr, type, name) + << endl << endl; + } + else + { + out << "::efl::eolian::alloc_static_callback< " + << parameter_no_ref_type(type, name) << " >(std::forward< " + << template_parameter_type(type, name) << " >(" << name << "));" << endl; + } ++it; // skip next. } } @@ -272,6 +268,56 @@ operator<<(std::ostream& out, parameters_c_declaration const& x) return out; } +struct +parameters_names +{ + parameters_container_type const& _params; + parameters_names(parameters_container_type const& params) + : _params(params) + {} +}; + +inline std::ostream& +operator<<(std::ostream& out, parameters_names const& x) +{ + auto first = x._params.cbegin(), + last = x._params.cend(); + for (auto it = first; it != last; ++it) + { + if (it != first) + out << ", "; + + out << it->name; + + if (type_is_callback(it->type) && it+1 != last) + ++it; // skip next. + } + return out; +} + +struct +parameters_c_names +{ + parameters_container_type const& _params; + parameters_c_names(parameters_container_type const& params) + : _params(params) + {} +}; + +inline std::ostream& +operator<<(std::ostream& out, parameters_c_names const& x) +{ + auto first = x._params.cbegin(), + last = x._params.cend(); + for (auto it = first; it != last; ++it) + { + if (it != first) + out << ", "; + out << it->name; + } + return out; +} + struct parameters_types { diff --git a/src/lib/eolian_cxx/grammar/type_generator.hh b/src/lib/eolian_cxx/grammar/type_generator.hh index 5913330b42..193d2ea88a 100644 --- a/src/lib/eolian_cxx/grammar/type_generator.hh +++ b/src/lib/eolian_cxx/grammar/type_generator.hh @@ -46,6 +46,21 @@ operator<<(std::ostream& out, abstract_full_name const& x) return out << abstract_namespace << full_name(x._cls); } +struct name_upper +{ + eo_class const& _cls; + name_upper(eo_class const& cls) + : _cls(cls) {} +}; + +inline std::ostream& +operator<<(std::ostream& out, name_upper const& x) +{ + std::string key = x._cls.name; + std::transform(key.begin(), key.end(), key.begin(), ::toupper); + return out << key; +} + struct c_type { eolian_type_instance const& _list; @@ -91,10 +106,13 @@ operator<<(std::ostream& out, efl::eolian::grammar::reinterpret_type const& x) } assert(!res.empty()); - if (x._type.is_out && type_is_binding(x._type.front())) - res += "*"; - else if (!x._type.is_nonull && x._type.front().is_class) - res = "::efl::eina::optional< " + res + " >"; + if (type_is_binding(x._type.front())) + { + if (x._type.is_out) + res += "*"; + else if (!x._type.is_nonull && x._type.front().binding_requires_optional) + res = "::efl::eina::optional< " + res + " >"; + } return out << res; } diff --git a/src/tests/eolian_cxx/callback.c b/src/tests/eolian_cxx/callback.c index 5192fa0a01..ef978fbcbe 100644 --- a/src/tests/eolian_cxx/callback.c +++ b/src/tests/eolian_cxx/callback.c @@ -48,5 +48,11 @@ static void _callback_twocallback(Eo *obj EINA_UNUSED, Callback_Data *pd EINA_UN cb(data); } +static void _callback_test_global_callbacks(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED + , Ecore_Cb cb, void *data) +{ + cb(data); +} + #include "callback.eo.c" diff --git a/src/tests/eolian_cxx/callback.eo b/src/tests/eolian_cxx/callback.eo index 16dd76ee6f..50583064af 100644 --- a/src/tests/eolian_cxx/callback.eo +++ b/src/tests/eolian_cxx/callback.eo @@ -16,6 +16,12 @@ class Callback (Eo.Base) @in Ecore_Cb cb2; } } + test_global_callbacks @class { + params { + @in Ecore_Cb cb; + @in void* data; + } + } } implements { Eo.Base.constructor; diff --git a/src/tests/eolian_cxx/eolian_cxx_test_callback.cc b/src/tests/eolian_cxx/eolian_cxx_test_callback.cc index 5c5d95f035..2acfd09e63 100644 --- a/src/tests/eolian_cxx/eolian_cxx_test_callback.cc +++ b/src/tests/eolian_cxx/eolian_cxx_test_callback.cc @@ -109,10 +109,23 @@ START_TEST(eolian_cxx_test_callback_event_del) } END_TEST +START_TEST(eolian_cxx_test_global_callback) +{ + efl::eo::eo_init i; + + bool called = false; + + callback::test_global_callbacks(std::bind([&called] { called = true; })); + + fail_if(!called); +} +END_TEST + void eolian_cxx_test_callback(TCase* tc) { tcase_add_test(tc, eolian_cxx_test_callback_method); tcase_add_test(tc, eolian_cxx_test_callback_event_add); tcase_add_test(tc, eolian_cxx_test_callback_event_del); + tcase_add_test(tc, eolian_cxx_test_global_callback); }