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_NAME_HELPERS_HH
17 #define EOLIAN_MONO_NAME_HELPERS_HH
18
19 #include <algorithm>
20 #include <cctype>
21 #include <iterator>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 #include <map>
26 #include "utils.hh"
27
28 #include "grammar/integral.hpp"
29 #include "grammar/generator.hpp"
30 #include "grammar/klass_def.hpp"
31 #include "grammar/list.hpp"
32 #include "grammar/string.hpp"
33 #include "grammar/integral.hpp"
34
35 using efl::eolian::grammar::as_generator;
36 using efl::eolian::grammar::string;
37 using efl::eolian::grammar::lit;
38 using efl::eolian::grammar::operator*;
39
40 namespace eolian_mono {
41
42 /* Utility functions for naming things. Compared to the utils.hh, this header has higher level
43 * functions, dealing with the knowledge of how to convert the items to the C# style we are using, for
44 * example, while being too short to be implemented as full-fledged generators.
45 */
46 namespace name_helpers {
47
48 namespace attributes = efl::eolian::grammar::attributes;
49
50 namespace detail {
is_equal(std::string const & lhs,std::string const & rhs)51 inline bool is_equal(std::string const& lhs, std::string const& rhs)
52 {
53 return lhs == rhs;
54 }
55 }
56
57 // Forward declarations
58 template<typename T>
59 inline std::string klass_concrete_or_interface_name(T const& klass);
60
identity(std::string const & str)61 inline std::string identity(std::string const& str)
62 {
63 return str;
64 }
65
escape_keyword(std::string const & name)66 inline std::string escape_keyword(std::string const& name)
67 {
68 using detail::is_equal;
69 if(is_equal(name, "delete")
70 || is_equal(name, "do")
71 || is_equal(name, "lock")
72 || is_equal(name, "event")
73 || is_equal(name, "in")
74 || is_equal(name, "out")
75 || is_equal(name, "object")
76 || is_equal(name, "interface")
77 || is_equal(name, "string")
78 || is_equal(name, "internal")
79 || is_equal(name, "fixed")
80 || is_equal(name, "var")
81 || is_equal(name, "base"))
82 return "kw_" + name;
83
84 if (is_equal(name, "Finalize"))
85 return name + "Add"; // Eo's Finalize is actually the end of efl_add.
86 return name;
87 }
88
89 typedef std::function<std::string(std::string const&)> string_transform_func;
90
join_namespaces(std::vector<std::string> const & namespaces,char separator,string_transform_func func=identity)91 inline std::string join_namespaces(std::vector<std::string> const& namespaces, char separator,
92 string_transform_func func=identity)
93 {
94 std::stringstream s;
95 for (auto&& n : namespaces)
96 s << func(n) << separator;
97
98 return s.str();
99 }
100
101 static const std::vector<std::string> verbs =
102 {
103 "add",
104 "get",
105 "is",
106 "del",
107 "thaw",
108 "freeze",
109 "save",
110 "wait",
111 "eject",
112 "raise",
113 "lower",
114 "load",
115 "dup",
116 "reset",
117 "unload",
118 "close",
119 "set",
120 "interpolate",
121 "has",
122 "grab",
123 "check",
124 "find",
125 "ungrab",
126 "unset",
127 "clear",
128 "pop",
129 "new",
130 "peek",
131 "push",
132 "update",
133 "show",
134 "move",
135 "hide",
136 "calculate",
137 "resize",
138 "attach",
139 "pack",
140 "unpack",
141 "emit",
142 "call",
143 "append",
144 "apply",
145 "bind",
146 "cancel",
147 "copy",
148 "create",
149 "cut",
150 "delete",
151 "deselect",
152 "detach",
153 "do",
154 "gen",
155 "insert",
156 "iterate",
157 "join",
158 "leave",
159 "limit",
160 "paste",
161 "parse",
162 "prepend",
163 "process",
164 "query",
165 "refresh",
166 "remove",
167 "register",
168 "reject",
169 "release",
170 "reply",
171 "send",
172 "select",
173 "serialize",
174 "steal",
175 "sync",
176 "toggle",
177 "unbind",
178 "unregister",
179 "unselect"
180 };
181
182 const std::vector<std::string> not_verbs =
183 {
184 "below",
185 "above",
186 "name",
187 "unfreezable",
188 "value",
189 "r",
190 "g",
191 "b",
192 "a",
193 "finalize",
194 "destructor",
195 "to",
196 "circle",
197 "rect",
198 "path",
199 "commands",
200 "type",
201 "colorspace"
202 "op",
203 "type",
204 "properties",
205 "status",
206 "status",
207 "relative",
208 "ptr",
209 "pair",
210 "pos",
211 "end"
212 };
213
reorder_verb(std::vector<std::string> & names)214 void reorder_verb(std::vector<std::string> &names)
215 {
216 if (names.size() <= 1)
217 return;
218
219 std::string verb = names.back();
220
221 if (std::find(verbs.begin(), verbs.end(), verb) != verbs.end())
222 {
223 names.pop_back();
224 names.insert(names.begin(), verb);
225 }
226 }
227
managed_namespace(std::string const & ns)228 inline std::string managed_namespace(std::string const& ns)
229 {
230 return escape_keyword(utils::remove_all(ns, '_'));
231 }
232
managed_name(std::string const & name,char separator='_')233 inline std::string managed_name(std::string const& name, char separator='_')
234 {
235 auto tokens = utils::split(name, separator);
236 return utils::to_pascal_case(tokens);
237 }
238
managed_method_name(attributes::function_def const & f)239 inline std::string managed_method_name(attributes::function_def const& f)
240 {
241 std::vector<std::string> names = utils::split(f.name, '_');
242
243 name_helpers::reorder_verb(names);
244
245 std::string candidate = escape_keyword(utils::to_pascal_case(names));
246
247 // Some eolian methods have the same name as their parent class
248 if (candidate == klass_concrete_or_interface_name(f.klass))
249 candidate = "Do" + candidate;
250
251 // Avoid clashing with System.Object.GetType
252 if (candidate == "GetType" || candidate == "SetType")
253 {
254 candidate.insert(3, managed_name(f.klass.eolian_name));
255 }
256
257 return candidate;
258 }
259
full_managed_name(std::string const & name)260 inline std::string full_managed_name(std::string const& name)
261 {
262 std::stringstream ss;
263
264 auto words = utils::split(name, '.');
265 std::transform(words.begin(), words.end(), words.begin(), [](std::string const& word) {
266 return managed_name(word);
267 });
268
269 auto b = std::begin(words), e = std::end(words);
270
271 if (b != e)
272 {
273 std::copy(b, std::prev(e), std::ostream_iterator<std::string>(ss, "."));
274 b = std::prev(e);
275 }
276
277 // Avoid trailing separator
278 if (b != e)
279 ss << *b;
280
281 return ss.str();
282 }
283
alias_full_eolian_name(attributes::alias_def const & alias)284 inline std::string alias_full_eolian_name(attributes::alias_def const& alias)
285 {
286
287 std::string eolian_name = utils::remove_all(alias.eolian_name, '_');
288 return join_namespaces(alias.namespaces, '.') + eolian_name;
289 }
290
managed_async_method_name(attributes::function_def const & f)291 inline std::string managed_async_method_name(attributes::function_def const& f)
292 {
293 return managed_method_name(f) + "Async";
294 }
function_ptr_full_eolian_name(attributes::function_def const & func)295 inline std::string function_ptr_full_eolian_name(attributes::function_def const& func)
296 {
297 return join_namespaces(func.namespaces, '.') + func.name;
298 }
299
type_full_eolian_name(attributes::regular_type_def const & type)300 inline std::string type_full_eolian_name(attributes::regular_type_def const& type)
301 {
302 return join_namespaces(type.namespaces, '.') + type.base_type;
303 }
304
type_full_managed_name(attributes::regular_type_def const & type)305 inline std::string type_full_managed_name(attributes::regular_type_def const& type)
306 {
307 return join_namespaces(type.namespaces, '.', managed_namespace) + utils::remove_all(type.base_type, '_');
308 }
309
struct_full_eolian_name(attributes::struct_def const & struct_)310 inline std::string struct_full_eolian_name(attributes::struct_def const& struct_)
311 {
312 return join_namespaces(struct_.namespaces, '.') + struct_.cxx_name;
313 }
314
315 template<typename T>
typedecl_managed_name(T const & item)316 inline std::string typedecl_managed_name(T const& item)
317 {
318 return utils::remove_all(item.cxx_name, '_');
319 }
320
typedecl_managed_name(attributes::function_def const & func)321 inline std::string typedecl_managed_name(attributes::function_def const& func)
322 {
323 return utils::remove_all(func.name, '_');
324 }
325
326
enum_field_managed_name(std::string name)327 inline std::string enum_field_managed_name(std::string name)
328 {
329 std::vector<std::string> names = utils::split(name, '_');
330 return utils::to_pascal_case(names);
331 }
332
to_field_name(std::string const & in)333 inline std::string to_field_name(std::string const& in)
334 {
335 std::vector<std::string> names = utils::split(in, '_');
336 return utils::to_camel_case(names);
337 }
338
339
340
341 template<typename T>
property_managed_name(T const & klass,std::string const & name)342 inline std::string property_managed_name(T const& klass, std::string const& name)
343 {
344 auto names = utils::split(name, '_');
345 // No need to escape keyword here as it will be capitalized and already
346 // namespaced inside the owner class.
347 auto managed_name = utils::to_pascal_case(names);
348 auto managed_klass_name = klass_concrete_or_interface_name(klass);
349
350 if (managed_name == "Type")
351 managed_name = managed_klass_name + managed_name;
352
353 return managed_name;
354 }
355
property_managed_name(attributes::property_def const & property)356 inline std::string property_managed_name(attributes::property_def const& property)
357 {
358 return property_managed_name(property.klass, property.name);
359 }
360
managed_part_name(attributes::part_def const & part)361 inline std::string managed_part_name(attributes::part_def const& part)
362 {
363 std::vector<std::string> names = utils::split(part.name, '_');
364 return utils::to_pascal_case(names) + "Part";
365 }
366
367 // Class name translation (interface/concrete/inherit/etc)
368 struct klass_interface_name_generator
369 {
370
371 template <typename T>
operator ()eolian_mono::name_helpers::klass_interface_name_generator372 std::string operator()(T const& klass) const
373 {
374 return ((klass.type == attributes::class_type::mixin
375 || klass.type == attributes::class_type::interface_) ? "I" : "")
376 + utils::remove_all(klass.eolian_name, '_');
377 }
378
379 template <typename OutputIterator, typename Attr, typename Context>
generateeolian_mono::name_helpers::klass_interface_name_generator380 bool generate(OutputIterator sink, Attr const& attribute, Context const& context) const
381 {
382 return as_generator((*this).operator()<Attr>(attribute)).generate(sink, attributes::unused, context);
383 }
384 } const klass_interface_name;
385
386 struct klass_full_interface_name_generator
387 {
388 template <typename T>
operator ()eolian_mono::name_helpers::klass_full_interface_name_generator389 std::string operator()(T const& klass) const
390 {
391 return join_namespaces(klass.namespaces, '.', managed_namespace) + klass_interface_name(klass);
392 }
393
394 template <typename OutputIterator, typename Attr, typename Context>
generateeolian_mono::name_helpers::klass_full_interface_name_generator395 bool generate(OutputIterator sink, Attr const& attribute, Context const& context) const
396 {
397 return as_generator((*this).operator()<Attr>(attribute)).generate(sink, attributes::unused, context);
398 }
399 } const klass_full_interface_name;
400
401 template<typename T>
klass_concrete_name(T const & klass)402 inline std::string klass_concrete_name(T const& klass)
403 {
404 return utils::remove_all(klass.eolian_name, '_');
405 }
406
407 template<typename T>
klass_concrete_or_interface_name(T const & klass)408 inline std::string klass_concrete_or_interface_name(T const& klass)
409 {
410 switch(klass.type)
411 {
412 case attributes::class_type::abstract_:
413 case attributes::class_type::regular:
414 return klass_concrete_name(klass);
415 default:
416 return klass_interface_name(klass);
417 }
418 }
419
420 struct klass_full_concrete_name_generator
421 {
422 template <typename T>
operator ()eolian_mono::name_helpers::klass_full_concrete_name_generator423 std::string operator()(T const& klass) const
424 {
425 return join_namespaces(klass.namespaces, '.', managed_namespace) + klass_concrete_name(klass);
426 }
427
428 template <typename OutputIterator, typename Attr, typename Context>
generateeolian_mono::name_helpers::klass_full_concrete_name_generator429 bool generate(OutputIterator sink, Attr const& attribute, Context const& context) const
430 {
431 return as_generator((*this).operator()<Attr>(attribute)).generate(sink, attributes::unused, context);
432 }
433 } const klass_full_concrete_name;
434
435 struct klass_full_concrete_or_interface_name_generator
436 {
437 template <typename T>
operator ()eolian_mono::name_helpers::klass_full_concrete_or_interface_name_generator438 std::string operator()(T const& klass) const
439 {
440 switch(klass.type)
441 {
442 case attributes::class_type::abstract_:
443 case attributes::class_type::regular:
444 return klass_full_concrete_name(klass);
445 default:
446 return klass_full_interface_name(klass);
447 }
448 }
449
450 template <typename OutputIterator, typename Context>
generateeolian_mono::name_helpers::klass_full_concrete_or_interface_name_generator451 bool generate(OutputIterator, attributes::unused_type, Context const&) const
452 {
453 return true;
454 }
455
456 template <typename OutputIterator, typename Attr, typename Context>
generateeolian_mono::name_helpers::klass_full_concrete_or_interface_name_generator457 bool generate(OutputIterator sink, Attr const& attribute, Context const& context) const
458 {
459 return as_generator((*this).operator()<Attr>(attribute)).generate(sink, attributes::unused, context);
460 }
461 } const klass_full_concrete_or_interface_name;
462
463 template<typename T>
klass_inherit_name(T const & klass)464 inline std::string klass_inherit_name(T const& klass)
465 {
466 return klass_concrete_name(klass);
467 }
468
469 template<typename T>
klass_native_inherit_name(T const & klass)470 inline std::string klass_native_inherit_name(T const& klass)
471 {
472 return ((klass.type == attributes::class_type::mixin
473 || klass.type == attributes::class_type::interface_) ? klass_interface_name(klass) : "") + "NativeMethods";
474 }
475
476 template<typename T>
klass_full_native_inherit_name(T const & klass)477 inline std::string klass_full_native_inherit_name(T const& klass)
478 {
479 if(klass.type == attributes::class_type::mixin
480 || klass.type == attributes::class_type::interface_)
481 return join_namespaces(klass.namespaces, '.', managed_namespace) + klass_native_inherit_name(klass);
482
483 return klass_full_concrete_name(klass) + "." + klass_native_inherit_name(klass);
484 }
485
486 template<typename T>
klass_get_name(T const & clsname)487 inline std::string klass_get_name(T const& clsname)
488 {
489 return clsname.klass_get_name;
490 }
491
492 template<typename T>
klass_get_full_name(T const & clsname)493 inline std::string klass_get_full_name(T const& clsname)
494 {
495 if(clsname.type == attributes::class_type::mixin
496 || clsname.type == attributes::class_type::interface_)
497 return klass_get_name(clsname);
498
499 return klass_full_concrete_name(clsname) + "." + klass_get_name(clsname);
500 }
501
502 // Events
managed_event_name(std::string const & name)503 inline std::string managed_event_name(std::string const& name)
504 {
505 return utils::to_pascal_case(utils::split(name, "_,"), "") + "Event";
506 }
507
managed_event_args_short_name(attributes::event_def const & evt)508 inline std::string managed_event_args_short_name(attributes::event_def const& evt)
509 {
510 return utils::remove_all(evt.klass.eolian_name, '_') + name_helpers::managed_event_name(evt.name) + "Args";
511 }
512
managed_event_args_name(attributes::event_def evt)513 inline std::string managed_event_args_name(attributes::event_def evt)
514 {
515 return join_namespaces(evt.klass.namespaces, '.', managed_namespace) +
516 managed_event_args_short_name(evt);
517 }
518
translate_inherited_event_name(const attributes::event_def & evt,const attributes::klass_def & klass)519 inline std::string translate_inherited_event_name(const attributes::event_def &evt, const attributes::klass_def &klass)
520 {
521 return join_namespaces(klass.namespaces, '_') + klass_interface_name(klass) + "_" + managed_event_name(evt.name);
522 }
523
524 // Open/close namespaces
525 template<typename OutputIterator, typename Context>
open_namespaces(OutputIterator sink,std::vector<std::string> namespaces,Context const & context)526 bool open_namespaces(OutputIterator sink, std::vector<std::string> namespaces, Context const& context)
527 {
528 std::transform(namespaces.begin(), namespaces.end(), namespaces.begin(), managed_namespace);
529
530 std::string joined_namespace = join_namespaces(namespaces, '.');
531 if (joined_namespace.empty()) return true;
532 joined_namespace.pop_back();
533
534 return as_generator("namespace " << string << " {\n").generate(sink, joined_namespace, context);
535 }
536
537 template<typename OutputIterator, typename Context>
close_namespaces(OutputIterator sink,std::vector<std::string> const & namespaces,Context const & context)538 bool close_namespaces(OutputIterator sink, std::vector<std::string> const& namespaces, Context const& context)
539 {
540 if (namespaces.empty()) return true;
541 return as_generator("}\n\n").generate(sink, attributes::unused, context);
542 }
543
constructor_managed_name(std::string full_name)544 std::string constructor_managed_name(std::string full_name)
545 {
546 auto tokens = utils::split(full_name, '.');
547
548 return managed_name(tokens.at(tokens.size()-1));
549 }
550
translate_value_type(std::string const & name)551 std::string translate_value_type(std::string const& name)
552 {
553 static std::map<std::string, std::string> table = {
554 {"sbyte", "SByte"},
555 {"byte","Byte"},
556 {"short","Int16"},
557 {"ushort","UInt16"},
558 {"int", "Int32"},
559 {"uint","UInt32"},
560 {"long","Int64"},
561 {"ulong","UInt64"},
562 {"char","Char"},
563 {"float","Single"},
564 {"double","Double"},
565 {"bool","Boolean"},
566 {"decimal","Decimal"},
567 };
568
569 auto found = table.find(name);
570
571 if (found != table.end())
572 return found->second;
573
574 return name;
575 }
576
577
578 // Field names //
579 struct struct_field_name_generator
580 {
581 template <typename OutputIterator, typename Context>
generateeolian_mono::name_helpers::struct_field_name_generator582 bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const
583 {
584 return as_generator(string).generate(sink, name_helpers::to_field_name(field.name), context);
585 }
586 } const struct_field_name {};
587
588 // Property names //
589 struct struct_property_name_generator
590 {
591 template <typename OutputIterator, typename Context>
generateeolian_mono::name_helpers::struct_property_name_generator592 bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const
593 {
594 return as_generator(string).generate(sink, name_helpers::managed_name(field.name), context);
595 }
596 } const struct_property_name {};
597
598 } // namespace name_helpers
599
600 } // namespace eolian_mono
601
602
603 namespace efl { namespace eolian { namespace grammar {
604
605 template <>
606 struct is_eager_generator<eolian_mono::name_helpers::klass_interface_name_generator> : std::true_type {};
607 template <>
608 struct is_generator<eolian_mono::name_helpers::klass_interface_name_generator> : std::true_type {};
609
610 template <>
611 struct is_eager_generator<eolian_mono::name_helpers::klass_full_interface_name_generator> : std::true_type {};
612 template <>
613 struct is_generator<eolian_mono::name_helpers::klass_full_interface_name_generator> : std::true_type {};
614
615 template <>
616 struct is_eager_generator<eolian_mono::name_helpers::klass_full_concrete_or_interface_name_generator> : std::true_type {};
617 template <>
618 struct is_generator<eolian_mono::name_helpers::klass_full_concrete_or_interface_name_generator> : std::true_type {};
619
620 template <>
621 struct is_eager_generator<eolian_mono::name_helpers::klass_full_concrete_name_generator> : std::true_type {};
622 template <>
623 struct is_generator<eolian_mono::name_helpers::klass_full_concrete_name_generator> : std::true_type {};
624
625 template <>
626 struct is_eager_generator<eolian_mono::name_helpers::struct_field_name_generator> : std::true_type {};
627 template <>
628 struct is_generator< ::eolian_mono::name_helpers::struct_field_name_generator> : std::true_type {};
629
630 template <>
631 struct is_eager_generator<eolian_mono::name_helpers::struct_property_name_generator> : std::true_type {};
632 template <>
633 struct is_generator< ::eolian_mono::name_helpers::struct_property_name_generator> : std::true_type {};
634
635 namespace type_traits {
636 template <>
637 struct attributes_needed<struct ::eolian_mono::name_helpers::klass_full_concrete_or_interface_name_generator> : std::integral_constant<int, 1> {};
638
639 template <>
640 struct attributes_needed< ::eolian_mono::name_helpers::struct_field_name_generator> : std::integral_constant<int, 1> {};
641 template <>
642 struct attributes_needed< ::eolian_mono::name_helpers::struct_property_name_generator> : std::integral_constant<int, 1> {};
643
644 }
645
646 } } }
647
648 #endif
649