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_MARSHALL_TYPE_IMPL_HH
17 #define EOLIAN_MONO_MARSHALL_TYPE_IMPL_HH
18 
19 #include "grammar/generator.hpp"
20 #include "grammar/klass_def.hpp"
21 #include "grammar/case.hpp"
22 #include "helpers.hh"
23 #include "name_helpers.hh"
24 #include "type_match.hh"
25 #include "type_impl.hh"
26 #include "generation_contexts.hh"
27 #include "blacklist.hh"
28 
29 namespace eolian_mono {
30 
31 namespace eina = efl::eina;
32 
33 namespace detail {
34 
35 template <typename OutputIterator, typename Context>
36 struct marshall_type_visitor_generate
37 {
38    mutable OutputIterator sink;
39    Context const* context;
40    std::string c_type;
41    bool is_out;
42    bool is_return;
43    bool is_ptr;
44    bool is_special_subtype;
45 
46    typedef marshall_type_visitor_generate<OutputIterator, Context> visitor_type;
47    typedef bool result_type;
48 
operator ()eolian_mono::detail::marshall_type_visitor_generate49    bool operator()(attributes::regular_type_def const& regular) const
50    {
51       using attributes::regular_type_def;
52 
53       struct match
54       {
55         eina::optional<std::string> name;
56         eina::optional<bool> has_own;
57         std::function<attributes::type_def::variant_type()> function;
58       }
59       const match_table[] =
60         {
61            // signed primitives
62            {"string", true, [&]
63               {
64                 regular_type_def r = regular;
65                 r.base_qualifier.qualifier ^= qualifier_info::is_ref;
66                 return replace_base_type(r, "System.String");
67               }}
68            , {"string", false, [&]
69               {
70                 regular_type_def r = regular;
71                 r.base_qualifier.qualifier ^= qualifier_info::is_ref;
72                 return replace_base_type(r, "System.String");
73               }}
74            , {"mstring", true, [&]
75               {
76                 regular_type_def r = regular;
77                 r.base_qualifier.qualifier ^= qualifier_info::is_ref;
78                 return replace_base_type(r, "System.String");
79               }}
80            , {"mstring", false, [&]
81               {
82                 regular_type_def r = regular;
83                 r.base_qualifier.qualifier ^= qualifier_info::is_ref;
84                 return replace_base_type(r, "System.String");
85               }}
86            , {"stringshare", true, [&]
87               {
88                 regular_type_def r = regular;
89                 r.base_qualifier.qualifier ^= qualifier_info::is_ref;
90                 if (is_special_subtype)
91                   return replace_base_type(r, "Eina.Stringshare");
92                 return replace_base_type(r, "System.String");
93               }}
94            , {"stringshare", false, [&]
95               {
96                 regular_type_def r = regular;
97                 r.base_qualifier.qualifier ^= qualifier_info::is_ref;
98                 if (is_special_subtype)
99                   return replace_base_type(r, "Eina.Stringshare");
100                 return replace_base_type(r, "System.String");
101               }}
102            , {"strbuf", nullptr, [&]
103               {
104                 regular_type_def r = regular;
105                 r.base_qualifier.qualifier ^= qualifier_info::is_ref;
106                 return replace_base_type(r, "Eina.Strbuf");
107               }}
108            , {"Binbuf", true, [&]
109               {
110                 regular_type_def r = regular;
111                 r.base_type = "System.IntPtr";
112                 r.namespaces.clear();
113                 return r;
114               }}
115            , {"Binbuf", false, [&]
116               {
117                 regular_type_def r = regular;
118                 r.base_type = "System.IntPtr";
119                 r.namespaces.clear();
120                 return r;
121               }}
122            , {"binbuf", nullptr, [&]
123               {
124                 regular_type_def r = regular;
125                 r.base_type = "System.IntPtr";
126                 r.namespaces.clear();
127                 return r;
128               }}
129            , {"event", nullptr, [&]
130               {
131                 regular_type_def r = regular;
132                 r.base_type = "Efl.Event";
133                 r.namespaces.clear();
134                 return r;
135               }}
136            , {"any_value", true, [&]
137                {
138                 regular_type_def r = regular;
139                 r.namespaces.clear();
140                 if (is_ptr)
141                     r.base_type = "Eina.Value";
142                 else
143                     r.base_type = "Eina.ValueNative";
144                 return r;
145                }}
146            , {"any_value", false, [&]
147                {
148                 regular_type_def r = regular;
149                 r.namespaces.clear();
150                 if (is_ptr)
151                     r.base_type = "Eina.Value";
152                 else
153                     r.base_type = "Eina.ValueNative";
154                 return r;
155                }}
156            , {"any_value_ref", true, [&]
157                {
158                 regular_type_def r = regular;
159                 r.namespaces.clear();
160                 r.base_type = "Eina.Value";
161                 return r;
162                }}
163            , {"any_value_ref", false, [&]
164                {
165                 regular_type_def r = regular;
166                 r.namespaces.clear();
167                 r.base_type = "Eina.Value";
168                 return r;
169                }}
170            , {"void", nullptr, [&]
171                {
172                 regular_type_def r = regular;
173                 r.namespaces.clear();
174                 if (is_out) // @inout too
175                     r.base_type = "System.IntPtr";
176                 else
177                     r.base_type = "void";
178                 return r;
179                }}
180            , {"Value_Type", nullptr, [&]
181                {
182                 regular_type_def r = regular;
183                 r.namespaces.clear();
184                 r.base_type = "Eina.ValueTypeBox";
185                 return r;
186                }}
187         };
188 
189         if (regular.is_struct() && !blacklist::is_struct_blacklisted(regular) && !(bool)(regular.base_qualifier & qualifier_info::is_own))
190           {
191              if ((is_out || is_return) && is_ptr)
192                  return as_generator("System.IntPtr").generate(sink, attributes::unused, *context);
193              return as_generator(string)
194                     .generate(sink, name_helpers::type_full_managed_name(regular), *context);
195           }
196         else if (eina::optional<bool> b = type_match::get_match
197          (match_table
198           , [&] (match const& m)
199           {
200             return (!m.name || *m.name == regular.base_type)
201             && (!m.has_own || *m.has_own == (bool)(regular.base_qualifier & qualifier_info::is_own))
202             ;
203           }
204           , [&] (attributes::type_def::variant_type const& v)
205           {
206             return v.visit(visitor_regular_type_def_printer<OutputIterator, Context>{sink, context}); // we want to keep is_out info
207           }))
208         {
209            return *b;
210         }
211       else if (is_ptr && helpers::need_pointer_conversion(&regular))
212         {
213            regular_type_def r = regular;
214            r.base_type = "System.IntPtr";
215            r.namespaces.clear();
216            return visitor_generate<OutputIterator, Context>{
217              sink
218              , context
219              , c_type
220              , is_out
221              , is_return
222              , is_ptr
223              , false
224              , is_special_subtype
225            }(r);
226         }
227       else
228         {
229           return visitor_generate<OutputIterator, Context>{
230             sink
231             , context
232             , c_type
233             , is_out
234             , is_return
235             , is_ptr
236             , false
237             , is_special_subtype
238           }(regular);
239         }
240    }
operator ()eolian_mono::detail::marshall_type_visitor_generate241    bool operator()(attributes::klass_name klass_name) const
242    {
243      return visitor_generate<OutputIterator, Context>{
244        sink
245        , context
246        , c_type
247        , is_out
248        , is_return
249        , is_ptr
250        , false
251        , is_special_subtype
252      }(klass_name);
253    }
operator ()eolian_mono::detail::marshall_type_visitor_generate254    bool operator()(attributes::complex_type_def const& complex) const
255    {
256       using attributes::regular_type_def;
257       using attributes::qualifier_info;
258       struct match
259       {
260         eina::optional<std::string> name;
261         eina::optional<bool> has_own;
262         eina::optional<bool> is_const;
263         std::function<attributes::type_def::variant_type()> function;
264       } const matches[] =
265       {
266         {"array", nullptr, nullptr, [&]
267            {
268               return regular_type_def{"System.IntPtr", complex.outer.base_qualifier, {}};
269            }
270         }
271         ,{"list", nullptr, nullptr, [&]
272            {
273               return regular_type_def{"System.IntPtr", complex.outer.base_qualifier, {}};
274            }
275         }
276         ,{"hash", nullptr, nullptr, [&]
277            {
278               return regular_type_def{"System.IntPtr", complex.outer.base_qualifier, {}};
279            }
280         }
281         ,{"iterator", nullptr, nullptr, [&]
282            {
283               return regular_type_def{"System.IntPtr", complex.outer.base_qualifier, {}};
284            }
285         }
286         ,{"accessor", nullptr, nullptr, [&]
287            {
288               return regular_type_def{"System.IntPtr", complex.outer.base_qualifier, {}};
289            }
290         }
291       };
292 
293       auto default_match = [&] (attributes::complex_type_def const& complex)
294         {
295           regular_type_def no_pointer_regular = complex.outer;
296           return visitor_type{sink, context, c_type, false, false, false, false}(no_pointer_regular)
297             && as_generator("<" << (type(false, false, true) % ", ") << ">").generate(sink, complex.subtypes, *context);
298         };
299 
300       if(eina::optional<bool> b = type_match::get_match
301          (matches
302           , [&] (match const& m)
303           {
304             return (!m.name || *m.name == complex.outer.base_type)
305             && (!m.has_own || *m.has_own == bool(complex.outer.base_qualifier & qualifier_info::is_own))
306             && (!m.is_const || *m.is_const == bool(complex.outer.base_qualifier & qualifier_info::is_const));
307           }
308           , [&] (attributes::type_def::variant_type const& v)
309           {
310             if(v.empty())
311               return true;
312             else if(attributes::complex_type_def const* complex
313                = eina::get<attributes::complex_type_def>(&v))
314               return default_match(*complex);
315             else
316               return v.visit(*this);
317           }))
318         {
319            return *b;
320         }
321 
322      return visitor_generate<OutputIterator, Context>{
323        sink
324        , context
325        , c_type
326        , is_out
327        , is_return
328        , is_ptr
329        , false
330        , is_special_subtype
331      }(complex);
332    }
333 };
334 } }
335 
336 #endif
337