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_TYPE_IMPL_HH
17 #define EOLIAN_MONO_TYPE_IMPL_HH
18 
19 #include "grammar/generator.hpp"
20 #include "grammar/klass_def.hpp"
21 #include "grammar/case.hpp"
22 #include "name_helpers.hh"
23 #include "type_match.hh"
24 
25 namespace eolian_mono {
26 
27 namespace eina = efl::eina;
28 
29 template <typename T>
as_const_pointer(T * p)30 T const* as_const_pointer(T* p) { return p; }
31 
32 inline
replace_base_type(attributes::regular_type_def v,std::string name)33 attributes::regular_type_def replace_base_type(attributes::regular_type_def v, std::string name)
34 {
35   v.base_type = name;
36   return v;
37 }
38 
39 template <typename T>
replace_base_integer(attributes::regular_type_def v)40 attributes::regular_type_def replace_base_integer(attributes::regular_type_def v)
41 {
42   bool s = std::is_signed<T>::value;
43   switch (sizeof(T))
44   {
45   case 1: return s ? replace_base_type(v, "sbyte") : replace_base_type(v, "byte");
46   case 2: return s ? replace_base_type(v, "short") : replace_base_type(v, "ushort");
47   case 4: return s ? replace_base_type(v, "int") : replace_base_type(v, "uint");
48   case 8: return s ? replace_base_type(v, "long") : replace_base_type(v, "ulong");
49   default: return v;
50   }
51 }
52 
53 template <typename T>
replace_base_opt_integer(attributes::regular_type_def v)54 attributes::regular_type_def replace_base_opt_integer(attributes::regular_type_def v)
55 {
56   bool s = std::is_signed<T>::value;
57   switch (sizeof(T))
58   {
59   case 1: return s ? replace_base_type(v, "sbyte?") : replace_base_type(v, "byte?");
60   case 2: return s ? replace_base_type(v, "short?") : replace_base_type(v, "ushort?");
61   case 4: return s ? replace_base_type(v, "int?") : replace_base_type(v, "uint?");
62   case 8: return s ? replace_base_type(v, "long?") : replace_base_type(v, "ulong?");
63   default: return v;
64   }
65 }
66 
67 inline
replace_outer(attributes::complex_type_def v,attributes::regular_type_def const & regular)68 attributes::complex_type_def replace_outer(attributes::complex_type_def v, attributes::regular_type_def const& regular)
69 {
70   v.outer = regular;
71   return v;
72 }
73 
74 template <typename OutputIterator, typename Context>
75 struct visitor_regular_type_def_printer
76 {
77    typedef visitor_regular_type_def_printer visitor_type;
78    typedef bool result_type;
79 
80    mutable OutputIterator sink;
81    Context const* context;
82 
operator ()eolian_mono::visitor_regular_type_def_printer83    bool operator()(grammar::attributes::regular_type_def const &regular) const
84    {
85      return as_generator(string).generate(sink, name_helpers::type_full_managed_name(regular), *context);
86    }
87 
88    template<typename T>
operator ()eolian_mono::visitor_regular_type_def_printer89    bool operator()(T const&) const
90    {
91      return true;
92    }
93 };
94 
95 template <typename OutputIterator, typename Context>
96 struct visitor_generate
97 {
98    mutable OutputIterator sink;
99    Context const* context;
100    std::string c_type;
101    bool is_out;
102    bool is_return;
103    bool is_ptr;
104    mutable bool is_optional;
105    bool is_special_subtype;
106 
107    typedef visitor_generate<OutputIterator, Context> visitor_type;
108    typedef bool result_type;
109 
operator ()eolian_mono::visitor_generate110    bool operator()(attributes::regular_type_def const& regular) const
111    {
112       using attributes::regular_type_def;
113       struct match
114       {
115         eina::optional<std::string> name;
116         eina::optional<bool> has_own;
117         std::function<attributes::type_def::variant_type()> function;
118       }
119       const optional_match_table[] =
120         {
121            // signed primitives
122              {"byte", nullptr, [&] { return replace_base_type(regular, "sbyte?"); }}
123            , {"float", nullptr, [&] { return replace_base_type(regular, "float?"); }}
124            , {"double", nullptr, [&] { return replace_base_type(regular, "double?"); }}
125            , {"bool", nullptr, [&] { return replace_base_type(regular, "bool?"); }}
126            , {"short", nullptr, [&] { return replace_base_opt_integer<short>(regular); }}
127            , {"int", nullptr, [&] { return replace_base_opt_integer<int>(regular); }}
128            , {"long", nullptr, [&] { return replace_base_opt_integer<long>(regular); }}
129            , {"llong", nullptr, [&] { return replace_base_opt_integer<long long>(regular); }}
130            , {"int8", nullptr, [&] { return replace_base_type(regular, "sbyte?"); }}
131            , {"int16", nullptr, [&] { return replace_base_type(regular, "short?"); }}
132            , {"int32", nullptr, [&] { return replace_base_type(regular, "int?"); }}
133            , {"int64", nullptr, [&] { return replace_base_type(regular, "long?"); }}
134            , {"ssize", nullptr, [&] { return replace_base_opt_integer<ssize_t>(regular); }}
135            // unsigned primitives
136            , {"ubyte", nullptr, [&] { return replace_base_type(regular, "byte?"); }}
137            , {"ushort", nullptr, [&] { return replace_base_opt_integer<unsigned short>(regular); }}
138            , {"uint", nullptr, [&] { return replace_base_opt_integer<unsigned int>(regular); }}
139            , {"ulong", nullptr, [&] { return replace_base_opt_integer<unsigned long>(regular); }}
140            , {"ullong", nullptr, [&] { return replace_base_opt_integer<unsigned long long>(regular); }}
141            , {"uint8", nullptr, [&] { return replace_base_type(regular, "byte?"); }}
142            , {"uint16", nullptr, [&] { return replace_base_type(regular, "ushort?"); }}
143            , {"uint32", nullptr, [&] { return replace_base_type(regular, "uint?"); }}
144            , {"uint64", nullptr, [&] { return replace_base_type(regular, "ulong?"); }}
145            , {"size", nullptr, [&] { return replace_base_opt_integer<size_t>(regular); }}
146 
147            , {"ptrdiff", nullptr, [&] { return replace_base_opt_integer<ptrdiff_t>(regular); }}
148            , {"intptr", nullptr, [&] { return replace_base_type(regular, "System.IntPtr?"); }}
149            , {"uintptr", nullptr, [&] { return replace_base_type(regular, "System.IntPtr?"); }}
150            , {"void_ptr", nullptr, [&] { return replace_base_type(regular, "System.IntPtr?"); }}
151         };
152       struct match
153       const match_table[] =
154         {
155            // signed primitives
156              {"byte", nullptr, [&] { return replace_base_type(regular, "sbyte"); }}
157            , {"short", nullptr, [&] { return replace_base_integer<short>(regular); }}
158            , {"int", nullptr, [&] { return replace_base_integer<int>(regular); }}
159            , {"long", nullptr, [&] { return replace_base_integer<long>(regular); }}
160            , {"llong", nullptr, [&] { return replace_base_integer<long long>(regular); }}
161            , {"int8", nullptr, [&] { return replace_base_type(regular, "sbyte"); }}
162            , {"int16", nullptr, [&] { return replace_base_type(regular, "short"); }}
163            , {"int32", nullptr, [&] { return replace_base_type(regular, "int"); }}
164            , {"int64", nullptr, [&] { return replace_base_type(regular, "long"); }}
165            , {"ssize", nullptr, [&] { return replace_base_integer<ssize_t>(regular); }}
166            // unsigned primitives
167            , {"ubyte", nullptr, [&] { return replace_base_type(regular, "byte"); }}
168            , {"ushort", nullptr, [&] { return replace_base_integer<unsigned short>(regular); }}
169            , {"uint", nullptr, [&] { return replace_base_integer<unsigned int>(regular); }}
170            , {"ulong", nullptr, [&] { return replace_base_integer<unsigned long>(regular); }}
171            , {"ullong", nullptr, [&] { return replace_base_integer<unsigned long long>(regular); }}
172            , {"uint8", nullptr, [&] { return replace_base_type(regular, "byte"); }}
173            , {"uint16", nullptr, [&] { return replace_base_type(regular, "ushort"); }}
174            , {"uint32", nullptr, [&] { return replace_base_type(regular, "uint"); }}
175            , {"uint64", nullptr, [&] { return replace_base_type(regular, "ulong"); }}
176            , {"size", nullptr, [&] { return replace_base_integer<size_t>(regular); }}
177 
178            , {"ptrdiff", nullptr, [&] { return replace_base_integer<ptrdiff_t>(regular); }}
179            , {"intptr", nullptr, [&] { return replace_base_type(regular, "System.IntPtr"); }}
180            , {"uintptr", nullptr, [&] { return replace_base_type(regular, "System.IntPtr"); }}
181            , {"void_ptr", nullptr, [&] { return replace_base_type(regular, "System.IntPtr"); }}
182            , {"void", nullptr, [&]
183                {
184                   regular_type_def r = regular;
185                   r.namespaces.clear();
186                   if (is_out) // @inout too
187                       r.base_type = "System.IntPtr";
188                   else
189                       r.base_type = "void";
190                   return r;
191               }}
192            , {"Eina.Error", nullptr, [&] // Eina.Error
193               {
194                 return regular_type_def{"Eina.Error", regular.base_qualifier, {}};
195               }} // TODO
196            , {"string", nullptr, [&]
197               {
198                 regular_type_def r = regular;
199                 r.base_qualifier.qualifier ^= qualifier_info::is_ref;
200                 return replace_base_type(r, "System.String");
201               }}
202            , {"mstring", nullptr, [&]
203               {
204                 regular_type_def r = regular;
205                 r.base_qualifier.qualifier ^= qualifier_info::is_ref;
206                 return replace_base_type(r, "System.String");
207               }}
208            , {"stringshare", nullptr, [&]
209               {
210                 regular_type_def r = regular;
211                 r.base_qualifier.qualifier ^= qualifier_info::is_ref;
212                 if (is_special_subtype)
213                   return replace_base_type(r, "Eina.Stringshare");
214                 return replace_base_type(r, "System.String");
215               }}
216            , {"strbuf", nullptr, [&]
217               {
218                 return regular_type_def{"Eina.Strbuf", regular.base_qualifier, {}};
219               }}
220            , {"binbuf", nullptr, [&]
221               {
222                 return regular_type_def{"Eina.Binbuf", regular.base_qualifier, {}};
223               }}
224            , {"event", nullptr, [&]
225               {
226                 return regular_type_def{"Efl.Event", regular.base_qualifier, {}};
227               }}
228            , {"any_value", true, [&]
229               { return regular_type_def{"Eina.Value", regular.base_qualifier, {}};
230               }}
231            , {"any_value", false, [&]
232               { return regular_type_def{"Eina.Value", regular.base_qualifier, {}};
233               }}
234            , {"any_value_ref", nullptr, [&]
235               { return regular_type_def{"Eina.Value", regular.base_qualifier, {}};
236               }} // FIXME add proper support for any_value_ref
237         };
238         std::string full_type_name = name_helpers::type_full_eolian_name(regular);
239         if(eina::optional<bool> b = type_match::get_match
240          (optional_match_table
241           , [&] (match const& m)
242           {
243             return is_optional
244               && (!m.name || *m.name == regular.base_type || *m.name == full_type_name)
245               && (!m.has_own || *m.has_own == (bool)(regular.base_qualifier & qualifier_info::is_own))
246             ;
247           }
248           , [&] (attributes::type_def::variant_type const& v)
249           {
250             return v.visit(*this); // we want to keep is_out info
251           }))
252         {
253            return *b;
254         }
255         else if (is_optional && (regular.is_struct() || regular.is_enum() || regular.is_struct_opaque()))
256         {
257           attributes::regular_type_def r = regular;
258           r.base_type.push_back('?');
259           is_optional = false;
260           return (*this)(r);
261         }
262         else if(eina::optional<bool> b = type_match::get_match
263          (match_table
264           , [&] (match const& m)
265           {
266             return (!m.name || *m.name == regular.base_type || *m.name == full_type_name)
267             && (!m.has_own || *m.has_own == (bool)(regular.base_qualifier & qualifier_info::is_own))
268             ;
269           }
270           , [&] (attributes::type_def::variant_type const& v)
271           {
272             return v.visit(visitor_regular_type_def_printer<OutputIterator, Context>{sink, context}); // we want to keep is_out info
273           }))
274         {
275            return *b;
276         }
277       // in A @optional -> optional<A>
278       // in A& @optional -> optional<A&>
279       // in A& @optional -> optional<A&>
280       // in own(A&) @optional -> A*
281       //
282       // out A @optional -> optional<A&>
283       // out A& @optional -> optional<A&>
284       // out own(A&) @optional -> optional<A*&>
285       // else if(regular.base_qualifier & qualifier_info::is_optional)
286       //  {
287       //    attributes::regular_type_def no_optional_regular = regular;
288       //    no_optional_regular.base_qualifier.qualifier ^= qualifier_info::is_optional;
289       //    if(is_out)
290       //      {
291       //        if(no_optional_regular.base_qualifier & qualifier_info::is_own)
292       //          {
293       //            return as_generator(" ::efl::eina::optional<").generate(sink, attributes::unused, *context)
294       //              && (*this)(no_optional_regular)
295       //              && as_generator("&>").generate(sink, attributes::unused, *context);
296       //         }
297       //        else if(no_optional_regular.base_qualifier & qualifier_info::is_ref)
298       //          {
299       //             no_optional_regular.base_qualifier.qualifier ^= qualifier_info::is_ref;
300       //             return (*this)(no_optional_regular)
301       //               && as_generator("**").generate(sink, attributes::unused, *context);
302       //          }
303       //        else
304       //          return (*this)(no_optional_regular)
305       //            && as_generator("*").generate(sink, attributes::unused, *context);
306       //      }
307       //    else
308       //      {
309       //        // regular.base_qualifier & qualifier_info::is_ref
310       //        return as_generator(" ::efl::eina::optional<").generate(sink, attributes::unused, *context)
311       //          && (*this)(no_optional_regular)
312       //          && as_generator(">").generate(sink, attributes::unused, *context);
313       //      }
314       //  }
315       // else if((is_return || is_out) && regular.base_qualifier & qualifier_info::is_ref
316       //         && regular.base_qualifier & qualifier_info::is_own)
317       //   {
318       //     if(as_generator
319       //        (
320       //         " ::std::unique_ptr<"
321       //         << *(string << "_")
322       //         << string
323       //         << (regular.base_qualifier & qualifier_info::is_const ? " const" : "")
324       //         << ", ::efl::eina::malloc_deleter>"
325       //        )
326       //        .generate(sink, std::make_tuple(regular.namespaces, regular.base_type), *context))
327       //       return true;
328       //     else
329       //       return false;
330       //   }
331       // else if(Eolian_Typedecl const* typedecl = eolian_state_struct_by_name_get(c_type.c_str()))
332       //   {
333       //   return as_generator
334       //        (
335       //         *(string << ".")
336       //         << string
337       //        )
338       //     .generate(sink, std::make_tuple(regular.namespaces, regular.base_type), *context);
339       //   }
340       else
341         {
342           return as_generator(string).generate(sink, name_helpers::type_full_managed_name(regular), *context);
343         }
344    }
operator ()eolian_mono::visitor_generate345    bool operator()(attributes::klass_name klass) const
346    {
347      // Efl.Class is manually handled in a custom marshall to be represented by a System.Type.
348      if (name_helpers::klass_full_concrete_name(klass) == "Efl.Class")
349        return as_generator(lit("Type")).generate(sink, attributes::unused, *context);
350      if(klass.type == attributes::class_type::regular || klass.type == attributes::class_type::abstract_)
351        return as_generator(string).generate(sink, name_helpers::klass_full_concrete_name(klass), *context);
352      else
353        return as_generator(string).generate(sink, name_helpers::klass_full_interface_name(klass), *context);
354    }
operator ()eolian_mono::visitor_generate355    bool operator()(attributes::complex_type_def const& complex) const
356    {
357       using attributes::regular_type_def;
358       using attributes::complex_type_def;
359       using attributes::qualifier_info;
360        struct match
361       {
362         eina::optional<std::string> name;
363         eina::optional<bool> has_own;
364         eina::optional<bool> is_const;
365         std::function<attributes::type_def::variant_type()> function;
366       } const matches[] =
367       {
368         {"list", nullptr, nullptr, [&]
369          {
370            complex_type_def c = complex;
371            c.outer.base_type = "IList";
372            return c;
373          }}
374         , {"array", nullptr, nullptr, [&]
375            {
376            complex_type_def c = complex;
377            c.outer.base_type = "IList";
378            return c;
379          }}
380         , {"hash", nullptr, nullptr
381            , [&]
382            {
383              complex_type_def c = complex;
384              c.outer.base_type = "Eina.Hash";
385              return c;
386          }}
387         , {"future", nullptr, nullptr, [&]
388            {
389              (*this)(regular_type_def{" Eina.Future", complex.outer.base_qualifier, {}});
390              return attributes::type_def::variant_type();
391            }
392           }
393         , {"iterator", nullptr, nullptr, [&]
394            {
395              complex_type_def c = complex;
396              c.outer.base_type = "IEnumerable";
397              return c;
398            }
399           }
400         , {"accessor", nullptr, nullptr, [&]
401            {
402              complex_type_def c = complex;
403              c.outer.base_type = "IEnumerable";
404              return c;
405            }
406           }
407         , {"slice", nullptr, nullptr, [&]
408            {
409              return regular_type_def{" Eina.Slice", complex.outer.base_qualifier, {}};
410            }
411           }
412         , {"rw_slice", nullptr, nullptr, [&]
413            {
414              return regular_type_def{" Eina.RwSlice", complex.outer.base_qualifier, {}};
415            }
416           }
417       };
418 
419       auto default_match = [&] (attributes::complex_type_def const& complex)
420         {
421           regular_type_def no_pointer_regular = complex.outer;
422           // std::vector<attributes::pointer_indirection> pointers;
423           // pointers.swap(no_pointer_regular.pointers);
424           // if(is_out)
425           //   pointers.push_back({{attributes::qualifier_info::is_none, {}}, true});
426           return visitor_type{sink, context, c_type, false, false, false, false, false}(no_pointer_regular)
427             && as_generator("<" << (type(false, false, true) % ", ") << ">").generate(sink, complex.subtypes, *context)
428           ;
429             // && detail::generate_pointers(sink, pointers, *context, false);
430         };
431 
432       if(eina::optional<bool> b = type_match::get_match
433          (matches
434           , [&] (match const& m)
435           {
436             return (!m.name || *m.name == complex.outer.base_type)
437             && (!m.has_own || *m.has_own == bool(complex.outer.base_qualifier & qualifier_info::is_own))
438             && (!m.is_const || *m.is_const == bool(complex.outer.base_qualifier & qualifier_info::is_const));
439           }
440           , [&] (attributes::type_def::variant_type const& v)
441           {
442             if(v.empty())
443               return true;
444             else if(attributes::complex_type_def const* complex
445                = eina::get<attributes::complex_type_def>(&v))
446               return default_match(*complex);
447             else
448               return v.visit(*this);
449           }))
450         return *b;
451       else
452         {
453           return default_match(complex);
454         }
455    }
456 };
457 
458 }
459 
460 #endif
461