From 5901b4601e3a240f6286ab9396d1ea2967ca61bc Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Mon, 27 Nov 2017 19:52:44 +0900 Subject: [PATCH] cxx: Implement support for parts This generates methods like this: Part_Class part_name() const; Which can then be used like: slider.indicator().format_string_set("%1.1f"); --- src/bin/eolian_cxx/eolian_cxx.cc | 8 +++ src/examples/elementary/slider_cxx_example.cc | 11 +-- .../grammar/base_class_definition.hpp | 4 ++ .../eolian_cxx/grammar/class_definition.hpp | 9 ++- .../grammar/class_implementation.hpp | 11 +-- src/lib/eolian_cxx/grammar/klass_def.hpp | 72 ++++++++++++++++--- .../eolian_cxx/grammar/part_declaration.hpp | 44 ++++++++++++ .../grammar/part_implementation.hpp | 72 +++++++++++++++++++ 8 files changed, 210 insertions(+), 21 deletions(-) create mode 100644 src/lib/eolian_cxx/grammar/part_declaration.hpp create mode 100644 src/lib/eolian_cxx/grammar/part_implementation.hpp diff --git a/src/bin/eolian_cxx/eolian_cxx.cc b/src/bin/eolian_cxx/eolian_cxx.cc index 2df5b9ae2d..f3f3c36610 100644 --- a/src/bin/eolian_cxx/eolian_cxx.cc +++ b/src/bin/eolian_cxx/eolian_cxx.cc @@ -144,6 +144,14 @@ generate(const Eolian_Class* klass, eolian_cxx::options_type const& opts, }; klass_function(klass); + for(efl::eina::iterator parts_itr ( ::eolian_class_parts_get(klass)) + , parts_last; parts_itr != parts_last; ++parts_itr) + { + Eolian_Class const* eolian_part_klass = ::eolian_part_class_get(&*parts_itr); + efl::eolian::grammar::attributes::klass_def part_klass(eolian_part_klass, opts.unit); + forward_klasses.insert(part_klass); + } + cpp_headers.erase(eolian_class_file_get(klass) + std::string(".hh")); std::string guard_name; diff --git a/src/examples/elementary/slider_cxx_example.cc b/src/examples/elementary/slider_cxx_example.cc index aa2360ff57..036dadcd1a 100644 --- a/src/examples/elementary/slider_cxx_example.cc +++ b/src/examples/elementary/slider_cxx_example.cc @@ -1,5 +1,7 @@ // g++ -g `pkg-config --cflags --libs elementary-cxx efl-cxx eina-cxx eo-cxx ecore-cxx evas-cxx edje-cxx` slider_cxx_example.cc -o slider_cxx_example +#define EFL_CXXPERIMENTAL + #include using efl::eo::instantiate; @@ -51,13 +53,12 @@ efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED) bx.pack_end(sl4); efl::ui::Slider sl5(instantiate, win); - - // FIXME: C++ part API needs special reference handling! This will show ERR! - efl::eo::downcast(sl5.part("indicator")) - .format_string_set("%1.2f"); - + sl5.indicator().format_string_set("%1.0f rabbit(s)"); + sl5.range_min_max_set(0, 100); + sl5.step_set(1); sl5.direction_set(EFL_UI_DIR_UP); sl5.hint_align_set(EFL_GFX_SIZE_HINT_FILL, 0.5); + sl5.hint_min_set({0, 120}); bx.pack_end(sl5); efl::ui::Slider sl6(instantiate, win); diff --git a/src/lib/eolian_cxx/grammar/base_class_definition.hpp b/src/lib/eolian_cxx/grammar/base_class_definition.hpp index d5fa914b53..edc6afb86a 100644 --- a/src/lib/eolian_cxx/grammar/base_class_definition.hpp +++ b/src/lib/eolian_cxx/grammar/base_class_definition.hpp @@ -14,6 +14,7 @@ #include "grammar/case.hpp" #include "grammar/address_of.hpp" #include "grammar/attribute_reorder.hpp" +#include "grammar/part_declaration.hpp" namespace efl { namespace eolian { namespace grammar { @@ -36,6 +37,9 @@ struct base_class_definition_generator if(!as_generator(*(scope_tab << function_declaration(get_klass_name(cls)))) .generate(sink, cls.functions, context)) return false; + if(!as_generator(*(scope_tab << part_declaration << ";\n")) + .generate(sink, cls.parts, context)) return false; + // static Efl_Class const* _eo_class(); std::string suffix; switch(cls.type) diff --git a/src/lib/eolian_cxx/grammar/class_definition.hpp b/src/lib/eolian_cxx/grammar/class_definition.hpp index 30a9daf134..7367cf7ef0 100644 --- a/src/lib/eolian_cxx/grammar/class_definition.hpp +++ b/src/lib/eolian_cxx/grammar/class_definition.hpp @@ -15,6 +15,7 @@ #include "grammar/attribute_reorder.hpp" #include "grammar/attribute_conditional.hpp" #include "grammar/attribute_replace.hpp" +#include "grammar/part_declaration.hpp" namespace efl { namespace eolian { namespace grammar { @@ -206,11 +207,17 @@ struct class_definition_generator // /// @endcond if(!as_generator(scope_tab << "/// @endcond\n").generate(sink, attributes::unused, context)) return false; + // EXPERIMENTAL: Parts + if(!as_generator("#ifdef EFL_CXXPERIMENTAL\n").generate(sink, attributes::unused, context)) return false; + if(!as_generator(*(scope_tab << part_declaration << ";\n")) + .generate(sink, cls.parts, context)) return false; + if(!as_generator("#endif \n").generate(sink, attributes::unused, context)) return false; + if(!as_generator( scope_tab << "::efl::eo::wref<" << string << "> _get_wref() const { " "return ::efl::eo::wref<" << string << ">(*this); }\n" ).generate(sink, std::make_tuple(cls.cxx_name, cls.cxx_name), context)) return false; - // EXPERIMENTAL + // EXPERIMENTAL: wref and implicit conversion to Eo* if(!as_generator("#ifdef EFL_CXXPERIMENTAL\n").generate(sink, attributes::unused, context)) return false; // For easy wref, operator-> in wref needs to also return a pointer type if(!as_generator( scope_tab << "const " << string << "* operator->() const { return this; }\n" diff --git a/src/lib/eolian_cxx/grammar/class_implementation.hpp b/src/lib/eolian_cxx/grammar/class_implementation.hpp index 373f04efef..60eb075073 100644 --- a/src/lib/eolian_cxx/grammar/class_implementation.hpp +++ b/src/lib/eolian_cxx/grammar/class_implementation.hpp @@ -14,6 +14,7 @@ #include "grammar/namespace.hpp" #include "grammar/type_impl.hpp" #include "grammar/attribute_reorder.hpp" +#include "grammar/part_implementation.hpp" namespace efl { namespace eolian { namespace grammar { @@ -40,19 +41,21 @@ struct class_implementation_generator #ifndef USE_EOCXX_INHERIT_ONLY if(!as_generator( (namespaces - [*function_definition(get_klass_name(cls))] + [*function_definition(get_klass_name(cls)) + << *part_implementation(cls.cxx_name)] << "\n" - )).generate(sink, std::make_tuple(cls.namespaces, cls.functions), ctx)) + )).generate(sink, std::make_tuple(cls.namespaces, cls.functions, cls.parts), ctx)) return false; #endif if(!as_generator( - attribute_reorder<0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3> + attribute_reorder<0, 1, 4, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3> ( "namespace eo_cxx {\n" << namespaces [ *function_definition(get_klass_name(cls)) + << *part_implementation(cls.cxx_name) << "inline " << base_class_name << "::operator " << class_name << "() const { return *static_cast< " << class_name << " const*>(static_cast(this)); }\n" << "inline " << base_class_name << "::operator " << class_name << "&() { return *static_cast< " @@ -61,7 +64,7 @@ struct class_implementation_generator << class_name << " const*>(static_cast(this)); }\n" ] << "}\n" - )).generate(sink, std::make_tuple(cls.namespaces, cls.functions, cpp_namespaces, cls.cxx_name), ctx)) + )).generate(sink, std::make_tuple(cls.namespaces, cls.functions, cpp_namespaces, cls.cxx_name, cls.parts), ctx)) return false; if(!as_generator("#endif\n").generate(sink, std::make_tuple(), ctx)) diff --git a/src/lib/eolian_cxx/grammar/klass_def.hpp b/src/lib/eolian_cxx/grammar/klass_def.hpp index 739390ddc6..fc6d62d5b8 100644 --- a/src/lib/eolian_cxx/grammar/klass_def.hpp +++ b/src/lib/eolian_cxx/grammar/klass_def.hpp @@ -225,6 +225,11 @@ struct type_def } void set(Eolian_Type const* eolian_type, Eolian_Unit const* unit, Eolian_C_Type_Type ctype); void set(Eolian_Expression_Type eolian_exp_type); + + friend inline bool operator<(type_def const& lhs, type_def const& rhs) + { + return lhs.c_type < rhs.c_type; + } }; struct get_qualifier_visitor @@ -690,6 +695,32 @@ auto get(event_def& def) -> decltype(tuple_element::get(def)) return tuple_element::get(def); } +struct part_def +{ + klass_name klass; + std::string name; + //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)) {} +}; + inline Eolian_Class const* get_klass(klass_name const& klass_name_, Eolian_Unit const* unit); struct klass_def @@ -703,6 +734,7 @@ struct klass_def class_type type; std::vector events; std::set immediate_inherits; + std::set parts; friend inline bool operator==(klass_def const& lhs, klass_def const& rhs) { @@ -713,7 +745,8 @@ struct klass_def && lhs.functions == rhs.functions && lhs.inherits == rhs.inherits && lhs.type == rhs.type - && lhs.events == rhs.events; + && lhs.events == rhs.events + && lhs.parts == rhs.parts; } friend inline bool operator!=(klass_def const& lhs, klass_def const& rhs) { @@ -723,7 +756,8 @@ struct klass_def { return lhs.eolian_name < rhs.eolian_name || lhs.cxx_name < rhs.cxx_name - || lhs.namespaces < rhs.namespaces; + || lhs.namespaces < rhs.namespaces + || lhs.parts < rhs.parts; } klass_def(std::string eolian_name, std::string cxx_name, std::string filename @@ -737,6 +771,15 @@ struct klass_def , functions(functions), inherits(inherits), type(type) , immediate_inherits(immediate_inherits) {} + klass_def(std::string _eolian_name, std::string _cxx_name + , std::vector _namespaces + , std::vector _functions + , std::set _inherits + , class_type _type) + : eolian_name(_eolian_name), cxx_name(_cxx_name) + , namespaces(_namespaces) + , functions(_functions), inherits(_inherits), type(_type) + {} klass_def(Eolian_Class const* klass, Eolian_Unit const* unit) { for(efl::eina::iterator namespace_iterator( ::eolian_class_namespaces_get(klass)) @@ -750,8 +793,8 @@ struct klass_def , functions_last; eolian_functions != functions_last; ++eolian_functions) { Eolian_Function const* function = &*eolian_functions; - Eolian_Function_Type type = ::eolian_function_type_get(function); - if(type == EOLIAN_PROPERTY) + Eolian_Function_Type func_type = ::eolian_function_type_get(function); + if(func_type == EOLIAN_PROPERTY) { try { if(! ::eolian_function_is_legacy_only(function, EOLIAN_PROP_GET) @@ -766,9 +809,9 @@ struct klass_def } else try { - if(! ::eolian_function_is_legacy_only(function, type) - && ::eolian_function_scope_get(function, type) != EOLIAN_SCOPE_PRIVATE) - functions.push_back({function, type, unit}); + if(! ::eolian_function_is_legacy_only(function, func_type) + && ::eolian_function_scope_get(function, func_type) != EOLIAN_SCOPE_PRIVATE) + functions.push_back({function, func_type, unit}); } catch(std::exception const&) {} } for(efl::eina::iterator eolian_functions ( ::eolian_class_functions_get(klass, EOLIAN_METHOD)) @@ -776,9 +819,9 @@ struct klass_def { try { Eolian_Function const* function = &*eolian_functions; - Eolian_Function_Type type = eolian_function_type_get(function); + Eolian_Function_Type func_type = eolian_function_type_get(function); if(! ::eolian_function_is_legacy_only(function, EOLIAN_METHOD) - && ::eolian_function_scope_get(function, type) != EOLIAN_SCOPE_PRIVATE) + && ::eolian_function_scope_get(function, func_type) != EOLIAN_SCOPE_PRIVATE) functions.push_back({function, EOLIAN_METHOD, unit}); } catch(std::exception const&) {} } @@ -789,9 +832,9 @@ struct klass_def immediate_inherits.insert({inherit, {}}); } std::function inherit_algo = - [&] (Eolian_Class const* klass) + [&] (Eolian_Class const* inherit_klass) { - for(efl::eina::iterator inherit_iterator ( ::eolian_class_inherits_get(klass)) + for(efl::eina::iterator inherit_iterator ( ::eolian_class_inherits_get(inherit_klass)) , inherit_last; inherit_iterator != inherit_last; ++inherit_iterator) { Eolian_Class const* inherit = &*inherit_iterator; @@ -800,6 +843,13 @@ struct klass_def } }; inherit_algo(klass); + + for(efl::eina::iterator 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: diff --git a/src/lib/eolian_cxx/grammar/part_declaration.hpp b/src/lib/eolian_cxx/grammar/part_declaration.hpp new file mode 100644 index 0000000000..383403c6bd --- /dev/null +++ b/src/lib/eolian_cxx/grammar/part_declaration.hpp @@ -0,0 +1,44 @@ +#ifndef EOLIAN_CXX_PART_DECLARATION_HH +#define EOLIAN_CXX_PART_DECLARATION_HH + +#include "grammar/generator.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" + +namespace efl { namespace eolian { namespace grammar { + +struct part_declaration_generator +{ + template + bool generate(OutputIterator sink, attributes::part_def const& part, Context const& ctx) const + { + if(!as_generator("::efl::eolian::return_traits<::" << *(string << "::")) + .generate(sink, part.klass.namespaces, add_lower_case_context(ctx))) + return false; + if(!as_generator(string << ">::type " << string << "() const") + .generate(sink, std::make_tuple(part.klass.eolian_name, part.name), ctx)) + return false; + + return true; + } +}; + +template <> +struct is_eager_generator : std::true_type {}; + +namespace type_traits { +template <> +struct attributes_needed : std::integral_constant {}; +} + +part_declaration_generator const part_declaration = {}; + +} } } + +#endif diff --git a/src/lib/eolian_cxx/grammar/part_implementation.hpp b/src/lib/eolian_cxx/grammar/part_implementation.hpp new file mode 100644 index 0000000000..cee2fc7fa8 --- /dev/null +++ b/src/lib/eolian_cxx/grammar/part_implementation.hpp @@ -0,0 +1,72 @@ +#ifndef EOLIAN_CXX_PART_IMPLEMENTATION_HH +#define EOLIAN_CXX_PART_IMPLEMENTATION_HH + +#include "grammar/generator.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" + +namespace efl { namespace eolian { namespace grammar { + +struct part_implementation_generator +{ + part_implementation_generator(std::string const& _klass_name) + : klass_name(_klass_name) {} + + template + bool generate(OutputIterator sink, attributes::part_def const& part, Context const& ctx) const + { + if(!as_generator("#ifdef EFL_CXXPERIMENTAL\n").generate(sink, attributes::unused, ctx)) + return false; + + if(!as_generator("::efl::eolian::return_traits<::" << *(string << "::")) + .generate(sink, part.klass.namespaces, add_lower_case_context(ctx))) + return false; + // FIXME: part_def can't depend on klass_def so C type is not known :( + if(!as_generator(string << ">::type "<< string << "::" << string << "() const\n{\n" + << scope_tab << "::Eo *__return_value = ::efl_part" + << "(this->_eo_ptr(), \"" << string << "\");\n" + << scope_tab << "::efl_auto_unref_set(__return_value, false);\n") + .generate(sink, std::make_tuple(part.klass.eolian_name, klass_name, part.name, part.name), ctx)) + return false; + if(!as_generator(scope_tab << "return ::" << *(string << "::")) + .generate(sink, part.klass.namespaces, add_lower_case_context(ctx))) + return false; + if(!as_generator(string << "{__return_value};\n}\n") + .generate(sink, part.klass.eolian_name, ctx)) + return false; + + if(!as_generator("#endif\n").generate(sink, attributes::unused, ctx)) + return false; + + return true; + } + +private: + std::string klass_name; +}; + +template <> +struct is_eager_generator : std::true_type {}; + +namespace type_traits { +template <> +struct attributes_needed : std::integral_constant {}; +} + +struct part_implementation_terminal +{ + part_implementation_generator operator()(std::string klass_name) const + { + return part_implementation_generator{klass_name}; + } +} const part_implementation = {}; + +} } } + +#endif