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