1 /*
2  * Copyright 2019 by its authors. See AUTHORS.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef EOLIAN_MONO_HELPERS_HH
17 #define EOLIAN_MONO_HELPERS_HH
18 
19 #include "grammar/klass_def.hpp"
20 #include "blacklist.hh"
21 #include "generation_contexts.hh"
22 #include "name_helpers.hh"
23 
24 namespace eolian_mono {
25 
26 namespace helpers {
27 
28 /* General helpers, not related directly with generating strings (those go in the name_helpers.hh). */
29 
30 namespace attributes = efl::eolian::grammar::attributes;
31 
need_struct_conversion(attributes::regular_type_def const * regular)32 inline bool need_struct_conversion(attributes::regular_type_def const* regular)
33 {
34    return regular && regular->is_struct() && !blacklist::is_struct_blacklisted(*regular);
35 }
36 
need_struct_conversion(attributes::parameter_def const & param,attributes::regular_type_def const * regular)37 inline bool need_struct_conversion(attributes::parameter_def const& param, attributes::regular_type_def const* regular)
38 {
39    if (param.direction == attributes::parameter_direction::in && param.type.has_own)
40      return false;
41 
42    return need_struct_conversion(regular);
43 }
44 
need_struct_conversion_in_return(attributes::type_def const & ret_type,attributes::parameter_direction const & direction)45 inline bool need_struct_conversion_in_return(attributes::type_def const& ret_type, attributes::parameter_direction const& direction)
46 {
47    auto regular = efl::eina::get<attributes::regular_type_def>(&ret_type.original_type);
48 
49    if (!regular->is_struct())
50      return false;
51 
52    if (regular->is_struct() && (direction == attributes::parameter_direction::out || direction == attributes::parameter_direction::unknown))
53      return false;
54 
55    if (ret_type.has_own)
56      return false;
57 
58    return true;
59 }
60 
need_pointer_conversion(attributes::regular_type_def const * regular)61 inline bool need_pointer_conversion(attributes::regular_type_def const* regular)
62 {
63    if (!regular)
64      return false;
65 
66    if (regular->is_enum()
67        || (regular->is_struct() && name_helpers::type_full_eolian_name(*regular) != "Eina.Binbuf")
68       )
69      return true;
70 
71    std::set<std::string> const types {
72      "bool", "char"
73      , "byte" , "short" , "int" , "long" , "llong" , "int8" , "int16" , "int32" , "int64" , "ssize"
74      , "ubyte", "ushort", "uint", "ulong", "ullong", "uint8", "uint16", "uint32", "uint64", "size"
75      , "ptrdiff"
76      , "float", "double"
77    };
78    if (types.find(regular->base_type) != types.end())
79      return true;
80 
81    return false;
82 }
83 
84 // While klass_def has immediate_inherits, we need a way to get all interfaces inherited by an interface
85 // either directly or through another interface.
interface_inherits(attributes::klass_def const & cls)86 std::set<attributes::klass_name, attributes::compare_klass_name_by_name> interface_inherits(attributes::klass_def const& cls)
87 {
88    std::set<attributes::klass_name, attributes::compare_klass_name_by_name> inherits;
89 
90    std::function<void(attributes::klass_name const&)> inherit_algo =
91        [&] (attributes::klass_name const& klass)
92        {
93           // TODO we could somehow cache klass_def instantiations
94           attributes::klass_def c(get_klass(klass, cls.unit), cls.unit);
95           for(auto&& inherit : c.immediate_inherits)
96             {
97                switch(inherit.type)
98                  {
99                  case attributes::class_type::mixin:
100                  case attributes::class_type::interface_:
101                    inherits.insert(inherit);
102                    inherit_algo(inherit);
103                    break;
104                  case attributes::class_type::regular:
105                  case attributes::class_type::abstract_:
106                    inherit_algo(inherit);
107                  default:
108                    break;
109                  }
110             }
111        };
112 
113    inherit_algo(get_klass_name(cls));
114 
115 
116    return inherits;
117 }
118 
119 // Returns the set of interfaces implemented by this type that haven't been implemented
120 // by a regular parent class.
121 template<typename Context>
non_implemented_interfaces(attributes::klass_def const & cls,Context const & context)122 std::set<attributes::klass_name, attributes::compare_klass_name_by_name> non_implemented_interfaces(attributes::klass_def const& cls, Context const& context)
123 {
124    auto options = efl::eolian::grammar::context_find_tag<options_context>(context);
125    std::set<attributes::klass_name, attributes::compare_klass_name_by_name> implemented_interfaces;
126    std::set<attributes::klass_name, attributes::compare_klass_name_by_name> interfaces;
127 
128    std::function<void(attributes::klass_name const&, bool)> inherit_algo =
129        [&] (attributes::klass_name const& klass, bool is_implemented)
130        {
131           // TODO we could somehow cache klass_def instantiations
132           attributes::klass_def c(get_klass(klass, cls.unit), cls.unit);
133           for(auto&& inherit : c.immediate_inherits)
134             {
135                if (inherit.is_beta && !options.want_beta)
136                    continue;
137 
138                switch(inherit.type)
139                  {
140                  case attributes::class_type::mixin:
141                  case attributes::class_type::interface_:
142                    interfaces.insert(inherit);
143                    if (is_implemented)
144                      implemented_interfaces.insert(inherit);
145                    inherit_algo(inherit, is_implemented);
146                    break;
147                  case attributes::class_type::abstract_:
148                  case attributes::class_type::regular:
149                    inherit_algo(inherit, true);
150                  default:
151                    break;
152                  }
153             }
154        };
155 
156    inherit_algo(get_klass_name(cls), false);
157 
158    for (auto&& inherit : implemented_interfaces)
159      interfaces.erase(inherit);
160 
161 
162    return interfaces;
163 }
164 
165 
166 /*
167  * Determines whether this class has any regular ancestor or not
168  */
has_regular_ancestor(attributes::klass_def const & cls)169 bool has_regular_ancestor(attributes::klass_def const& cls)
170 {
171    auto inherits = cls.inherits;
172    std::function<bool(attributes::klass_name const&)> is_regular =
173        [&] (attributes::klass_name const& klass)
174        {
175           return klass.type == attributes::class_type::regular || klass.type == attributes::class_type::abstract_;
176        };
177 
178    return std::any_of(inherits.begin(), inherits.end(), is_regular);
179 }
180 
181 /*
182  * Sugar for checking if a given class in in the inheritance tree
183  */
inherits_from(attributes::klass_def const & cls,std::string const & name)184 bool inherits_from(attributes::klass_def const& cls, std::string const& name)
185 {
186    return std::any_of(cls.inherits.begin(), cls.inherits.end(),
187            [&](attributes::klass_name const& inherit)
188            {
189                 return name_helpers::klass_full_concrete_or_interface_name(inherit) == name;
190            });
191 }
192 
193 /*
194  * Gets all methods that this class should implement (i.e. that come from an unimplemented interface/mixin and the class itself)
195  */
196 template<typename Context>
get_all_implementable_methods(attributes::klass_def const & cls,Context const & context)197 std::vector<attributes::function_def> get_all_implementable_methods(attributes::klass_def const& cls, Context const& context)
198 {
199    bool want_beta = efl::eolian::grammar::context_find_tag<options_context>(context).want_beta;
200    std::vector<attributes::function_def> ret;
201    auto filter_beta = [&want_beta](attributes::function_def const& func) {
202        if (!want_beta)
203          return !func.is_beta;
204        else
205          return true;
206    };
207 
208    std::copy_if(cls.functions.begin(), cls.functions.end(), std::back_inserter(ret), filter_beta);
209 
210    // Non implemented interfaces
211    std::set<attributes::klass_name, attributes::compare_klass_name_by_name> implemented_interfaces;
212    std::set<attributes::klass_name, attributes::compare_klass_name_by_name> interfaces;
213    std::function<void(attributes::klass_name const&, bool)> inherit_algo =
214        [&] (attributes::klass_name const &klass, bool is_implemented)
215        {
216            attributes::klass_def c(get_klass(klass, cls.unit), cls.unit);
217            for (auto&& inherit: c.immediate_inherits)
218              {
219                 switch(inherit.type)
220                   {
221                   case attributes::class_type::mixin:
222                   case attributes::class_type::interface_:
223                     interfaces.insert(inherit);
224                     if (is_implemented)
225                       implemented_interfaces.insert(inherit);
226                     inherit_algo(inherit, is_implemented);
227                     break;
228                   case attributes::class_type::abstract_:
229                   case attributes::class_type::regular:
230                     inherit_algo(inherit, true);
231                   default:
232                     break;
233                   }
234              }
235        };
236 
237    inherit_algo(attributes::get_klass_name(cls), false);
238 
239    for (auto&& inherit : implemented_interfaces)
240      interfaces.erase(inherit);
241 
242     for (auto&& inherit : interfaces)
243     {
244         attributes::klass_def klass(get_klass(inherit, cls.unit), cls.unit);
245         std::copy_if(klass.functions.cbegin(), klass.functions.cend(), std::back_inserter(ret), filter_beta);
246     }
247 
248   return ret;
249 }
250 
251 /*
252  * Gets all properties that this class should implement (i.e. that come from an unimplemented interface/mixin and the class itself)
253  */
254 template<typename Context>
get_all_implementable_properties(attributes::klass_def const & cls,Context const & context)255 std::vector<attributes::property_def> get_all_implementable_properties(attributes::klass_def const& cls, Context const& context)
256 {
257    bool want_beta = efl::eolian::grammar::context_find_tag<options_context>(context).want_beta;
258    std::vector<attributes::property_def> ret;
259    auto filter_beta = [&want_beta](attributes::property_def const& prop) {
260        if (!want_beta)
261          return prop.getter && !prop.setter ? !prop.getter->is_beta
262            : prop.getter && prop.setter ? !prop.getter->is_beta || !prop.setter->is_beta
263            : true
264            ;
265        else
266          return true;
267    };
268 
269    std::copy_if(cls.properties.begin(), cls.properties.end(), std::back_inserter(ret), filter_beta);
270 
271    // Non implemented interfaces
272    std::set<attributes::klass_name, attributes::compare_klass_name_by_name> implemented_interfaces;
273    std::set<attributes::klass_name, attributes::compare_klass_name_by_name> interfaces;
274    std::function<void(attributes::klass_name const&, bool)> inherit_algo =
275        [&] (attributes::klass_name const &klass, bool is_implemented)
276        {
277            attributes::klass_def c(get_klass(klass, cls.unit), cls.unit);
278            for (auto&& inherit: c.immediate_inherits)
279              {
280                 switch(inherit.type)
281                   {
282                   case attributes::class_type::mixin:
283                   case attributes::class_type::interface_:
284                     interfaces.insert(inherit);
285                     if (is_implemented)
286                       implemented_interfaces.insert(inherit);
287                     inherit_algo(inherit, is_implemented);
288                     break;
289                   case attributes::class_type::abstract_:
290                   case attributes::class_type::regular:
291                     inherit_algo(inherit, true);
292                   default:
293                     break;
294                   }
295              }
296        };
297 
298    inherit_algo(attributes::get_klass_name(cls), false);
299 
300    for (auto&& inherit : implemented_interfaces)
301      interfaces.erase(inherit);
302 
303     for (auto&& inherit : interfaces)
304     {
305         attributes::klass_def klass(get_klass(inherit, cls.unit), cls.unit);
306         std::copy_if(klass.properties.cbegin(), klass.properties.cend(), std::back_inserter(ret), filter_beta);
307     }
308 
309   return ret;
310 }
311 
312 template<typename Klass>
is_managed_interface(Klass const & klass)313 inline bool is_managed_interface(Klass const& klass)
314 {
315     return klass.type == attributes::class_type::interface_
316            || klass.type == attributes::class_type::mixin;
317 }
318 
319 
320 /*
321  * Gets all methods that this class should register (i.e. that comes from it and non-public interface methods
322  * that this class is the first one implementing)
323  */
324 template<typename Context>
get_all_registerable_methods(attributes::klass_def const & cls,Context const & context)325 std::vector<attributes::function_def> get_all_registerable_methods(attributes::klass_def const& cls, Context const& context)
326 {
327    std::vector<attributes::function_def> ret;
328 
329    auto implementable_methods = get_all_implementable_methods(cls, context);
330 
331    std::copy_if(implementable_methods.cbegin(), implementable_methods.cend(), std::back_inserter(ret)
332                 , [&cls](attributes::function_def const & func) {
333 
334                     if (cls == func.klass)
335                       return true;
336 
337                     if (is_managed_interface(func.klass) && func.is_static)
338                       return true;
339 
340                     if (!is_managed_interface(func.klass) || func.scope != attributes::member_scope::scope_public)
341                       return true;
342                     return false;
343                });
344 
345    return ret;
346 }
347 
is_function_registerable(attributes::function_def func,attributes::klass_def const & cls)348 bool is_function_registerable (attributes::function_def func, attributes::klass_def const& cls)
349 {
350   if (cls == func.klass)
351     return true;
352 
353   if (is_managed_interface(func.klass) && func.is_static)
354     return true;
355 
356   if (!is_managed_interface(func.klass) || func.scope != attributes::member_scope::scope_public)
357     return true;
358   return false;
359 }
360 
361 // /*
362 //  * Gets all methods that this class should register (i.e. that comes from it and non-public interface methods
363 //  * that this class is the first one implementing)
364 //  */
365 // template<typename Context>
366 // std::vector<attributes::property_def> get_all_registerable_properties(attributes::klass_def const& cls, Context const& context)
367 // {
368 //    std::vector<attributes::property_def> ret;
369 
370 //    auto implementable_properties = get_all_implementable_properties(cls, context);
371 
372 //    std::copy_if(implementable_properties.cbegin(), implementable_properties.cend(), std::back_inserter(ret)
373 //                 , [&cls](attributes::property_def const & property) {
374 //                   auto klass = property.getter ? property.getter->klass
375 //                     : property.setter->klass;
376 
377 //                     if (cls == klass)
378 //                       return true;
379 
380 //                     if (is_managed_interface(klass) && ((property.getter && property.getter->is_static)
381 //                                                         || (property.setter && property.setter->is_static)))
382 //                       return true;
383 
384 //                     if (!is_managed_interface(klass) || ((property.getter && property.getter->scope != attributes::member_scope::scope_public)
385 //                                                          || (property.setter && property.setter->scope != attributes::member_scope::scope_public)))
386 //                       return true;
387 //                     return false;
388 //                });
389 
390 //    return ret;
391 // }
392 
393 /*
394  * Checks whether the given is unique going up the inheritance tree from leaf_klass
395  */
is_unique_event(attributes::event_def const & evt,attributes::klass_def const & leaf_klass)396 inline bool is_unique_event(attributes::event_def const& evt
397                          , attributes::klass_def const& leaf_klass)
398 {
399   auto events = leaf_klass.get_all_events();
400   int i = 1;
401   return !std::any_of(events.cbegin(), events.cend(),
402                          [&evt, &i](const attributes::event_def &other) {
403                             return evt.name == other.name && i++ == 2;
404                      });
405 }
406 
reorder_constructors(std::vector<attributes::constructor_def> constructors)407 inline std::vector<attributes::constructor_def> reorder_constructors(std::vector<attributes::constructor_def> constructors)
408 {
409   auto is_required = [](attributes::constructor_def const& ctr) { return !ctr.is_optional; };
410   auto is_object_parent = [](attributes::constructor_def const& ctr)
411                           {
412                             return (ctr.klass.namespaces.size() == 1
413                                     && ctr.klass.namespaces[0] == "Efl"
414                                     && ctr.klass.eolian_name == "Object"
415                                     && ctr.name == "Efl.Object.parent");
416                           };
417   std::stable_partition(constructors.begin(), constructors.end(), is_required);
418   constructors.erase (std::remove_if (constructors.begin(), constructors.end(), is_object_parent), constructors.end());
419   return constructors;
420 }
421 
422 } // namespace helpers
423 
424 } // namespace eolian_mono
425 
426 #endif
427