1 #include "main.h"
2 #include "docs.h"
3 
4 /* Used to store the function names that will have to be appended
5  * with __eolian during C generation. Needed when params have to
6  * be initialized and for future features.
7  */
8 static Eina_Hash *_funcs_params_init_get = NULL;
9 static Eina_Hash *_funcs_params_init_set = NULL;
10 
11 static const char *
_get_add_star(Eolian_Function_Type ftype,Eolian_Parameter_Direction pdir)12 _get_add_star(Eolian_Function_Type ftype, Eolian_Parameter_Direction pdir)
13 {
14    if (ftype == EOLIAN_PROP_GET)
15      return "*";
16    if ((pdir == EOLIAN_PARAMETER_OUT) || (pdir == EOLIAN_PARAMETER_INOUT))
17      return "*";
18    return "";
19 }
20 
21 static Eina_Bool
_function_exists(const char * fname,Eina_Strbuf * buf)22 _function_exists(const char *fname, Eina_Strbuf *buf)
23 {
24    const char *ptr = eina_strbuf_string_get(buf);
25    size_t flen = strlen(fname);
26    while ((ptr = strstr(ptr, fname)) != NULL)
27      {
28         switch (*(ptr - 1))
29           {
30            case '\n':
31            case ' ':
32              switch (*(ptr + flen))
33                {
34                 case ' ':
35                 case '(':
36                   return EINA_TRUE;
37                }
38           }
39         ++ptr;
40      }
41    return EINA_FALSE;
42 }
43 
44 /* Check if the type is used in the file, not if it is a typedef... */
45 static Eina_Bool
_type_exists(const char * tname,Eina_Strbuf * buf)46 _type_exists(const char *tname, Eina_Strbuf *buf)
47 {
48    const char *ptr = eina_strbuf_string_get(buf);
49    size_t tlen = strlen(tname);
50    while ((ptr = strstr(ptr, tname)) != NULL)
51      {
52         switch (*(ptr - 1))
53           {
54            case '\n':
55            case ' ':
56            case ',':
57              switch (*(ptr + tlen))
58                {
59                 case '\n':
60                 case ' ':
61                 case ',':
62                 case ';':
63                   return EINA_TRUE;
64                }
65           }
66         ++ptr;
67      }
68    return EINA_FALSE;
69 }
70 
71 static void
_gen_func_pointer_param(const char * name,Eina_Stringshare * c_type,const Eolian_Typedecl * typedecl EINA_UNUSED,Eina_Strbuf * params,Eina_Strbuf * params_full,Eina_Strbuf * params_full_imp,Eina_Bool is_empty EINA_UNUSED)72 _gen_func_pointer_param(const char *name, Eina_Stringshare *c_type,
73                         const Eolian_Typedecl *typedecl EINA_UNUSED,
74                         Eina_Strbuf *params, Eina_Strbuf *params_full,
75                         Eina_Strbuf *params_full_imp,
76                         Eina_Bool is_empty EINA_UNUSED)
77 {
78    Eina_Strbuf *dataname = eina_strbuf_new();
79    Eina_Strbuf *freename = eina_strbuf_new();
80 
81    eina_strbuf_append_printf(dataname, "%s_data", name);
82    eina_strbuf_append_printf(freename, "%s_free_cb", name);
83 
84    if (eina_strbuf_length_get(params))
85      eina_strbuf_append(params, ", ");
86 
87    eina_strbuf_append_printf(params, "%s, %s, %s",
88                              eina_strbuf_string_get(dataname),
89                              name,
90                              eina_strbuf_string_get(freename));
91 
92    eina_strbuf_append_printf(params_full_imp, ", void *%s, %s %s, Eina_Free_Cb %s",
93                              eina_strbuf_string_get(dataname),
94                              c_type, name,
95                              eina_strbuf_string_get(freename));
96    eina_strbuf_append_printf(params_full, ", void *%s, %s %s, Eina_Free_Cb %s",
97                              eina_strbuf_string_get(dataname),
98                              c_type, name,
99                              eina_strbuf_string_get(freename));
100 
101    eina_strbuf_free(dataname);
102    eina_strbuf_free(freename);
103 }
104 
105 static void
_append_defval(Eina_Strbuf * buf,const Eolian_Expression * exp,const Eolian_Type * tp,const char * ctp)106 _append_defval(Eina_Strbuf *buf, const Eolian_Expression *exp, const Eolian_Type *tp, const char *ctp)
107 {
108    if (exp)
109      {
110         Eolian_Value val = eolian_expression_eval(exp, EOLIAN_MASK_ALL);
111         Eina_Stringshare *lit = eolian_expression_value_to_literal(&val);
112         if (lit)
113           {
114              eina_strbuf_append(buf, lit);
115              Eina_Stringshare *exps = eolian_expression_serialize(exp);
116              if (exps && strcmp(lit, exps))
117                eina_strbuf_append_printf(buf, " /* %s */", exps);
118              eina_stringshare_del(exps);
119              eina_stringshare_del(lit);
120              return;
121           }
122         else WRN("evaluation of default value failed");
123      }
124    /* default value or fallback */
125    const Eolian_Type *btp = eolian_type_aliased_base_get(tp);
126    if (eolian_type_is_ptr(btp) || strchr(ctp, '*'))
127      {
128         eina_strbuf_append(buf, "NULL");
129         return;
130      }
131    const Eolian_Typedecl *tdcl = eolian_type_typedecl_get(btp);
132    if (tdcl && (eolian_typedecl_type_get(tdcl) == EOLIAN_TYPEDECL_STRUCT))
133      {
134         char *sn = eo_gen_c_full_name_get(eolian_typedecl_name_get(tdcl));
135         if (eina_streq(sn, "Eina_Rect"))
136           eina_strbuf_append(buf, "(EINA_RECT_EMPTY())");
137         else
138           eina_strbuf_append_printf(buf, "((%s){0})", sn);
139         free(sn);
140         return;
141      }
142    /* slices are value types that don't boil down to pointers */
143    switch (eolian_type_builtin_type_get(btp))
144      {
145       case EOLIAN_TYPE_BUILTIN_SLICE:
146       case EOLIAN_TYPE_BUILTIN_RW_SLICE:
147         eina_strbuf_append_printf(buf, "((%s){0})", eolian_type_c_name_get(btp));
148         return;
149       default:
150         break;
151      }
152    /* enums and remaining regulars... 0 should do */
153    eina_strbuf_append(buf, "0");
154 }
155 
156 static const char *
_free_func_get(const Eolian_Type * type)157 _free_func_get(const Eolian_Type *type)
158 {
159    const Eolian_Type *ab = eolian_type_aliased_base_get(type);
160    switch (eolian_type_builtin_type_get(ab))
161      {
162       /* simple types */
163       case EOLIAN_TYPE_BUILTIN_MSTRING:
164         return "free";
165       case EOLIAN_TYPE_BUILTIN_STRINGSHARE:
166         return "eina_stringshare_del";
167       case EOLIAN_TYPE_BUILTIN_ANY_VALUE:
168         return "eina_value_flush";
169       case EOLIAN_TYPE_BUILTIN_ANY_VALUE_REF:
170         return "eina_value_free";
171       case EOLIAN_TYPE_BUILTIN_STRBUF:
172         return "eina_strbuf_free";
173       case EOLIAN_TYPE_BUILTIN_BINBUF:
174         return "eina_binbuf_free";
175       /* complex types */
176       case EOLIAN_TYPE_BUILTIN_ACCESSOR:
177         return "eina_accessor_free";
178       case EOLIAN_TYPE_BUILTIN_ARRAY:
179         return "eina_array_free";
180       case EOLIAN_TYPE_BUILTIN_FUTURE:
181         return "(void)";
182       case EOLIAN_TYPE_BUILTIN_ITERATOR:
183         return "eina_iterator_free";
184       case EOLIAN_TYPE_BUILTIN_HASH:
185         return "eina_hash_free";
186       case EOLIAN_TYPE_BUILTIN_LIST:
187         return "eina_list_free";
188       /* class and user types */
189       case EOLIAN_TYPE_BUILTIN_INVALID:
190         if (eolian_type_type_get(ab) == EOLIAN_TYPE_CLASS)
191           return "efl_del";
192         else
193           return eolian_typedecl_free_func_get(eolian_type_typedecl_get(ab));
194       /* no free func */
195       default:
196         return NULL;
197      }
198 }
199 
200 static void
_generate_normal_free(Eina_Strbuf ** buf,const Eolian_Type * type,const Eina_Strbuf * parameter,const char * additional_intention)201 _generate_normal_free(Eina_Strbuf **buf, const Eolian_Type *type, const Eina_Strbuf *parameter, const char *additional_intention)
202 {
203    const char *free_func = _free_func_get(type);
204    if (!free_func)
205      {
206         printf("No free type %s\n", eolian_type_short_name_get(type));
207         return;
208      }
209 
210    if (eolian_type_builtin_type_get(type) == EOLIAN_TYPE_BUILTIN_HASH)
211      {
212         eina_strbuf_append_printf(*buf,"   eina_hash_free_cb_set(");
213         eina_strbuf_append_buffer(*buf, parameter);
214         eina_strbuf_append(*buf, ",NULL);\n");
215      }
216 
217    eina_strbuf_append_printf(*buf,"   %s%s(", additional_intention, free_func);
218    eina_strbuf_append_buffer(*buf, parameter);
219    eina_strbuf_append(*buf, ");\n");
220 }
221 
222 static void
_generate_loop_content(Eina_Strbuf ** buf,const Eolian_Type * inner_type,const Eina_Strbuf * iter_param)223 _generate_loop_content(Eina_Strbuf **buf, const Eolian_Type *inner_type, const Eina_Strbuf *iter_param)
224 {
225    eina_strbuf_append(*buf, "     {\n");
226    _generate_normal_free(buf, inner_type, iter_param, "     ");
227    eina_strbuf_append(*buf, "     }\n");
228 }
229 
230 static void
_generate_iterative_free(Eina_Strbuf ** buf,const Eolian_Type * type,const Eolian_Type * inner_type,Eolian_Function_Parameter * parameter,Eina_Strbuf * param)231 _generate_iterative_free(Eina_Strbuf **buf, const Eolian_Type *type, const Eolian_Type *inner_type, Eolian_Function_Parameter *parameter, Eina_Strbuf *param)
232 {
233    Eina_Strbuf *iterator_header, *iter_param;
234 
235    iterator_header = eina_strbuf_new();
236    iter_param = eina_strbuf_new();
237 
238    Eolian_Type_Builtin_Type t = eolian_type_builtin_type_get(type);
239 
240    eina_strbuf_append_printf(iter_param, "%s_iter", eolian_parameter_name_get(parameter));
241 
242    //generate the field definition
243    eina_strbuf_append_printf(*buf, "   %s", eolian_type_c_type_get(inner_type));
244    eina_strbuf_append_buffer(*buf, iter_param);
245    eina_strbuf_append(*buf, ";\n");
246 
247 
248    if (t == EOLIAN_TYPE_BUILTIN_LIST)
249      {
250         eina_strbuf_append_printf(*buf, "   EINA_LIST_FREE(");
251         eina_strbuf_append_buffer(*buf, param);
252         eina_strbuf_append_char(*buf, ',');
253         eina_strbuf_append_buffer(*buf, iter_param);
254         eina_strbuf_append(*buf, ")\n");
255         _generate_loop_content(buf, inner_type, iter_param);
256      }
257    else if (t == EOLIAN_TYPE_BUILTIN_ITERATOR)
258      {
259         eina_strbuf_append_printf(*buf, "   EINA_ITERATOR_FOREACH(");
260         eina_strbuf_append_buffer(*buf, param);
261         eina_strbuf_append_char(*buf, ',');
262         eina_strbuf_append_buffer(*buf, iter_param);
263         eina_strbuf_append(*buf, ")\n");
264         _generate_loop_content(buf, inner_type, iter_param);
265      }
266    else if (t == EOLIAN_TYPE_BUILTIN_ACCESSOR)
267      {
268         eina_strbuf_append_printf(*buf, "   unsigned int %s_i = 0;\n", eolian_parameter_name_get(parameter));
269         eina_strbuf_append_printf(*buf, "   EINA_ACCESSOR_FOREACH(");
270         eina_strbuf_append_buffer(*buf, param);
271         eina_strbuf_append_printf(*buf, ",%s_i,", eolian_parameter_name_get(parameter));
272         eina_strbuf_append_buffer(*buf, iter_param);
273         eina_strbuf_append(*buf, ")\n");
274         _generate_loop_content(buf, inner_type, iter_param);
275      }
276    else if (t == EOLIAN_TYPE_BUILTIN_HASH)
277      {
278         eina_strbuf_append_printf(*buf,"   eina_hash_free_cb_set(");
279         eina_strbuf_append_buffer(*buf, param);
280         eina_strbuf_append_printf(*buf, ",%s);\n",_free_func_get(inner_type));
281         eina_strbuf_append_printf(*buf,"   eina_hash_free(");
282         eina_strbuf_append_buffer(*buf, param);
283         eina_strbuf_append(*buf, ");\n");
284      }
285    else if (t == EOLIAN_TYPE_BUILTIN_ARRAY)
286      {
287         eina_strbuf_append_printf(*buf, "   while((");
288         eina_strbuf_append_buffer(*buf, iter_param);
289         eina_strbuf_append_printf(*buf, " = eina_array_pop(");
290         eina_strbuf_append_buffer(*buf, param);
291         eina_strbuf_append_printf(*buf, ")))\n");
292         _generate_loop_content(buf, inner_type, iter_param);
293         eina_strbuf_append_printf(*buf, "   eina_array_free(");
294         eina_strbuf_append_buffer(*buf, param);
295         eina_strbuf_append_printf(*buf, ");\n");
296       }
297    else
298      {
299         printf("Error, container unknown?! %d\n", (int)t);
300      }
301 
302    eina_strbuf_free(iterator_header);
303    eina_strbuf_free(iter_param);
304 }
305 
306 static int
_gen_function_param_fallback(Eina_Iterator * itr,Eina_Strbuf * fallback_free_ownership,Eina_Strbuf * param_call)307 _gen_function_param_fallback(Eina_Iterator *itr, Eina_Strbuf *fallback_free_ownership, Eina_Strbuf *param_call)
308 {
309    Eolian_Function_Parameter *pr;
310    int owners = 0;
311 
312    EINA_ITERATOR_FOREACH(itr, pr)
313      {
314         const Eolian_Type *type, *inner_type;
315 
316         type = eolian_parameter_type_get(pr);
317         inner_type = eolian_type_base_type_get(type);
318 
319         //check if they should be freed or just ignored
320         if (!eolian_parameter_is_move(pr) || eolian_parameter_direction_get(pr) == EOLIAN_PARAMETER_OUT)
321           {
322              eina_strbuf_append_printf(fallback_free_ownership, "   (void)%s;\n", eolian_parameter_name_get(pr));
323              /* FIXME: quick hack to avoid warnings, but should be rewritten properly */
324              if (eolian_type_typedecl_get(type) &&
325                  eolian_typedecl_type_get(eolian_type_typedecl_get(type)) == EOLIAN_TYPEDECL_FUNCTION_POINTER)
326                {
327                    eina_strbuf_append_printf(fallback_free_ownership, "   (void)%s_data;\n", eolian_parameter_name_get(pr));
328                    eina_strbuf_append_printf(fallback_free_ownership, "   (void)%s_free_cb;\n", eolian_parameter_name_get(pr));
329                }
330              continue;
331           }
332 
333         owners ++;
334 
335         eina_strbuf_reset(param_call);
336 
337         if (eolian_parameter_direction_get(pr) == EOLIAN_PARAMETER_INOUT)
338           eina_strbuf_append_char(param_call, '*');
339         eina_strbuf_append(param_call, eolian_parameter_name_get(pr));
340 
341         //check if we might want to free or handle the children
342         if (!inner_type || !eolian_type_is_move(inner_type))
343           {
344              _generate_normal_free(&fallback_free_ownership, type, param_call, "");
345           }
346         else if (inner_type && eolian_type_is_move(inner_type))
347           {
348              _generate_iterative_free(&fallback_free_ownership, type, inner_type, pr, param_call);
349           }
350       }
351    eina_iterator_free(itr);
352 
353    return owners;
354 }
355 
356 static const char *
_get_reflect_initf(const Eolian_Type * abtp)357 _get_reflect_initf(const Eolian_Type *abtp)
358 {
359    Eolian_Type_Builtin_Type btp = eolian_type_builtin_type_get(abtp);
360    const char *initf = NULL;
361    switch (btp)
362      {
363       case EOLIAN_TYPE_BUILTIN_BYTE:
364       case EOLIAN_TYPE_BUILTIN_CHAR:
365         initf = "char"; break;
366       case EOLIAN_TYPE_BUILTIN_UBYTE:
367         initf = "uchar"; break;
368       case EOLIAN_TYPE_BUILTIN_SHORT:
369       case EOLIAN_TYPE_BUILTIN_USHORT:
370       case EOLIAN_TYPE_BUILTIN_INT:
371       case EOLIAN_TYPE_BUILTIN_UINT:
372       case EOLIAN_TYPE_BUILTIN_LONG:
373       case EOLIAN_TYPE_BUILTIN_ULONG:
374       case EOLIAN_TYPE_BUILTIN_INT64:
375       case EOLIAN_TYPE_BUILTIN_UINT64:
376       case EOLIAN_TYPE_BUILTIN_TIME:
377       case EOLIAN_TYPE_BUILTIN_FLOAT:
378       case EOLIAN_TYPE_BUILTIN_DOUBLE:
379       case EOLIAN_TYPE_BUILTIN_BOOL:
380       case EOLIAN_TYPE_BUILTIN_STRING:
381       case EOLIAN_TYPE_BUILTIN_STRINGSHARE:
382         initf = eolian_type_name_get(abtp); break;
383       default:
384         break;
385      }
386    return initf;
387 }
388 
389 static void
_gen_reflect_get(Eina_Strbuf * buf,const char * cnamel,const Eolian_Function_Parameter * pr,const Eolian_Function * fid,Eina_Hash * refh)390 _gen_reflect_get(Eina_Strbuf *buf, const char *cnamel,
391                  const Eolian_Function_Parameter *pr,
392                  const Eolian_Function *fid, Eina_Hash *refh)
393 {
394    const Eolian_Type *valt = eolian_parameter_type_get(pr);
395    if (eolian_type_is_ptr(valt))
396      return;
397 
398    const Eolian_Type *abtp = eolian_type_aliased_base_get(valt);
399    const char *initf = _get_reflect_initf(abtp);
400    if (!initf)
401      return;
402 
403    Eolian_Function_Type et = (Eolian_Function_Type)eina_hash_find(refh, &fid);
404    if (et == EOLIAN_PROP_SET)
405      eina_hash_set(refh, &fid, (void *)EOLIAN_PROPERTY);
406    else
407      eina_hash_set(refh, &fid, (void *)EOLIAN_PROP_GET);
408 
409    eina_strbuf_append(buf, "\nstatic Eina_Value\n");
410    eina_strbuf_append_printf(buf, "__eolian_%s_%s_get_reflect(const Eo *obj)\n",
411      cnamel, eolian_function_name_get(fid));
412    eina_strbuf_append(buf, "{\n");
413 
414    Eina_Stringshare *ct = eolian_parameter_c_type_get(pr, EINA_TRUE);
415    const char *starsp = (ct[strlen(ct) - 1] != '*') ? " " : "";
416 
417    Eina_Stringshare *fcn = eolian_function_full_c_name_get(fid, EOLIAN_PROP_GET);
418    eina_strbuf_append_printf(buf, "   %s%sval = %s(obj);\n", ct, starsp, fcn);
419    eina_stringshare_del(fcn);
420    eina_stringshare_del(ct);
421 
422    eina_strbuf_append_printf(buf, "   return eina_value_%s_init(val);\n", initf);
423    eina_strbuf_append(buf, "}\n\n");
424 }
425 
426 static void
_gen_reflect_set(Eina_Strbuf * buf,const char * cnamel,const Eolian_Function_Parameter * pr,const Eolian_Function * fid,Eina_Hash * refh)427 _gen_reflect_set(Eina_Strbuf *buf, const char *cnamel,
428                  const Eolian_Function_Parameter *pr,
429                  const Eolian_Function *fid, Eina_Hash *refh)
430 {
431    const Eolian_Type *valt = eolian_parameter_type_get(pr);
432    if (eolian_type_is_ptr(valt))
433      return;
434 
435    const Eolian_Type *abtp = eolian_type_aliased_base_get(valt);
436    const char *initf = _get_reflect_initf(abtp);
437    if (!initf)
438      return;
439 
440    Eolian_Function_Type et = (Eolian_Function_Type)eina_hash_find(refh, &fid);
441    if (et == EOLIAN_PROP_GET)
442      eina_hash_set(refh, &fid, (void *)EOLIAN_PROPERTY);
443    else
444      eina_hash_set(refh, &fid, (void *)EOLIAN_PROP_SET);
445 
446    eina_strbuf_append(buf, "\nstatic Eina_Error\n");
447    eina_strbuf_append_printf(buf, "__eolian_%s_%s_set_reflect(Eo *obj, Eina_Value val)\n",
448      cnamel, eolian_function_name_get(fid));
449    eina_strbuf_append(buf, "{\n");
450    eina_strbuf_append(buf, "   Eina_Error r = 0;");
451 
452    Eina_Stringshare *ct = eolian_parameter_c_type_get(pr, EINA_FALSE);
453    const char *starsp = (ct[strlen(ct) - 1] != '*') ? " " : "";
454    eina_strbuf_append_printf(buf, "   %s%scval;\n", ct, starsp);
455    eina_stringshare_del(ct);
456 
457    eina_strbuf_append_printf(buf, "   if (!eina_value_%s_convert(&val, &cval))\n", initf);
458    eina_strbuf_append(buf, "      {\n");
459    eina_strbuf_append(buf, "         r = EINA_ERROR_VALUE_FAILED;\n");
460    eina_strbuf_append(buf, "         goto end;\n");
461    eina_strbuf_append(buf, "      }\n");
462 
463    Eina_Stringshare *fcn = eolian_function_full_c_name_get(fid, EOLIAN_PROP_SET);
464    eina_strbuf_append_printf(buf, "   %s(obj, cval);\n", fcn);
465    eina_stringshare_del(fcn);
466 
467    eina_strbuf_append(buf, " end:\n");
468    eina_strbuf_append(buf, "   eina_value_flush(&val);\n");
469    eina_strbuf_append(buf, "   return r;\n");
470 
471    eina_strbuf_append(buf, "}\n\n");
472 }
473 
474 static void
_emit_class_function(Eina_Strbuf * buf,const Eolian_Function * fid,const Eolian_Function_Type ftype,const Eolian_Type * rtp,const char * rtpn,Eina_Strbuf * params_full,const char * ocnamel,const char * func_suffix,Eina_Strbuf * params,const char * function_name)475 _emit_class_function(Eina_Strbuf *buf, const Eolian_Function *fid, const Eolian_Function_Type ftype, const Eolian_Type *rtp, const char *rtpn, Eina_Strbuf *params_full,
476                      const char *ocnamel, const char *func_suffix, Eina_Strbuf *params, const char *function_name)
477 {
478    eina_strbuf_append(buf, "EOAPI ");
479    eina_strbuf_append(buf, rtpn);
480    eina_strbuf_append(buf, " ");
481    eina_strbuf_append(buf, function_name);
482    eina_strbuf_append(buf, "(");
483    if (eina_strbuf_length_get(params_full) == 0)
484      eina_strbuf_append(buf, "void");
485    else
486      eina_strbuf_append_buffer(buf, params_full);
487    eina_strbuf_append(buf, ")\n");
488    eina_strbuf_append(buf, "{\n");
489    eina_strbuf_append_printf(buf, "   const Efl_Class *klass = %s();\n", eolian_class_c_get_function_name_get(eolian_function_class_get(fid)));
490    if (!!strcmp(rtpn, "void") && rtp)
491      {
492         const Eolian_Expression *default_value_expression = eolian_function_return_default_value_get(fid, ftype);
493 
494         eina_strbuf_append_printf(buf, "   EINA_SAFETY_ON_NULL_RETURN_VAL(klass,");
495         _append_defval(buf, default_value_expression, rtp, rtpn);
496         eina_strbuf_append_printf(buf, ");\n");
497 
498         eina_strbuf_append(buf, "   return ");
499      }
500    else
501      {
502         eina_strbuf_append(buf, "   EINA_SAFETY_ON_NULL_RETURN(klass);\n");
503         eina_strbuf_append(buf, "   ");
504      }
505    eina_strbuf_append_printf(buf, "_%s", ocnamel);
506    eina_strbuf_append_char(buf, '_');
507    eina_strbuf_append(buf, eolian_function_name_get(fid));
508    eina_strbuf_append(buf, func_suffix);
509    eina_strbuf_append(buf, "(");
510    eina_strbuf_append_buffer(buf, params);
511    eina_strbuf_append(buf, ");\n");
512    eina_strbuf_append(buf, "}\n");
513 }
514 
515 static void
_gen_func(const Eolian_Class * cl,const Eolian_Function * fid,Eolian_Function_Type ftype,Eina_Strbuf * buf,const Eolian_Implement * impl,Eina_Hash * refh)516 _gen_func(const Eolian_Class *cl, const Eolian_Function *fid,
517           Eolian_Function_Type ftype, Eina_Strbuf *buf,
518           const Eolian_Implement *impl, Eina_Hash *refh)
519 {
520    Eina_Bool is_empty = eolian_implement_is_empty(impl, ftype);
521    Eina_Bool is_auto = eolian_implement_is_auto(impl, ftype);
522 
523    if ((ftype != EOLIAN_PROP_GET) && (ftype != EOLIAN_PROP_SET))
524      ftype = eolian_function_type_get(fid);
525 
526    Eina_Bool is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET);
527    Eina_Bool var_as_ret = EINA_FALSE;
528    /* assume we're not generating reflection api by default */
529    const Eolian_Function_Parameter *reflect_param = NULL;
530 
531    const Eolian_Expression *def_ret = NULL;
532    const Eolian_Type *rtp = eolian_function_return_type_get(fid, ftype);
533    Eina_Stringshare *rtpn = NULL;
534    if (rtp)
535      {
536         is_auto = EINA_FALSE; /* can't do auto if func returns */
537         def_ret = eolian_function_return_default_value_get(fid, ftype);
538         rtpn = eolian_function_return_c_type_get(fid, ftype);
539      }
540 
541    const char *func_suffix = "";
542    if (ftype == EOLIAN_PROP_GET)
543      {
544         func_suffix = "_get";
545         if (!rtp)
546           {
547              void *d1, *d2;
548              Eina_Iterator *itr = eolian_property_values_get(fid, ftype);
549              if (eina_iterator_next(itr, &d1) && !eina_iterator_next(itr, &d2))
550                {
551                   Eolian_Function_Parameter *pr = d1;
552                   rtp = eolian_parameter_type_get(pr);
553                   /* reflect only when returning 1 val */
554                   if (!eolian_parameter_is_by_ref(pr))
555                     reflect_param = pr;
556                   var_as_ret = EINA_TRUE;
557                   def_ret = eolian_parameter_default_value_get(pr);
558                   rtpn = eolian_parameter_c_type_get(pr, EINA_TRUE);
559                }
560              eina_iterator_free(itr);
561           }
562      }
563    else if (ftype == EOLIAN_PROP_SET)
564      {
565         func_suffix = "_set";
566         Eina_Iterator *itr = eolian_property_values_get(fid, ftype);
567         void *d1, *d2;
568         /* reflect with 1 value */
569         if (eina_iterator_next(itr, &d1) && !eina_iterator_next(itr, &d2))
570           {
571              Eolian_Function_Parameter *pr = d1;
572              if (!eolian_parameter_is_by_ref(pr))
573                reflect_param = pr;
574           }
575         eina_iterator_free(itr);
576      }
577 
578    Eina_Strbuf *params = eina_strbuf_new(); /* par1, par2, par3, ... */
579    Eina_Strbuf *params_full = eina_strbuf_new(); /* T par1, U par2, ... for decl */
580    Eina_Strbuf *params_full_imp = eina_strbuf_new(); /* as above, for impl */
581    Eina_Strbuf *params_init = eina_strbuf_new(); /* default value inits */
582    Eina_Strbuf *fallback_free_ownership = eina_strbuf_new(); /* list of function calls that are freeing the owned parameters, or doing nothing on the normal parameters, NULL if there is nothing owned*/
583 
584    /* property keys */
585    {
586       Eina_Iterator *itr = eolian_property_keys_get(fid, ftype);
587       if (itr) /* has keys: no reflection */
588         reflect_param = NULL;
589       Eolian_Function_Parameter *pr;
590       EINA_ITERATOR_FOREACH(itr, pr)
591         {
592            const char *prn = eolian_parameter_name_get(pr);
593            Eina_Stringshare *ptn = eolian_parameter_c_type_get(pr, EINA_FALSE);
594 
595            if (eina_strbuf_length_get(params))
596              eina_strbuf_append(params, ", ");
597            eina_strbuf_append(params, prn);
598 
599            if (eina_strbuf_length_get(params_full) || !eolian_function_is_static(fid))
600              {
601                 eina_strbuf_append(params_full, ", ");
602                 eina_strbuf_append(params_full_imp, ", ");
603              }
604            eina_strbuf_append_printf(params_full, "%s", ptn);
605            eina_strbuf_append_printf(params_full_imp, "%s", ptn);
606 
607            if (ptn[strlen(ptn) - 1] != '*')
608              {
609                 eina_strbuf_append_char(params_full, ' ');
610                 eina_strbuf_append_char(params_full_imp, ' ');
611              }
612            eina_strbuf_append(params_full, prn);
613            eina_strbuf_append(params_full_imp, prn);
614            if (is_empty || is_auto)
615              eina_strbuf_append(params_full_imp, " EINA_UNUSED");
616 
617            eina_stringshare_del(ptn);
618         }
619       eina_iterator_free(itr);
620    }
621 
622    /* check if we have owning data that we would have to free in a error case */
623    if (ftype == EOLIAN_PROP_GET)
624      {
625         eina_strbuf_free(fallback_free_ownership);
626         fallback_free_ownership = NULL;
627      }
628    else
629      {
630           Eina_Iterator *itr;
631           int owners = 0;
632           Eina_Strbuf *param_call;
633 
634           param_call = eina_strbuf_new();
635 
636           if (is_prop)
637             {
638                itr = eolian_property_values_get(fid, ftype);
639                owners += _gen_function_param_fallback(itr, fallback_free_ownership, param_call);
640                itr = eolian_property_keys_get(fid, ftype);
641                owners += _gen_function_param_fallback(itr, fallback_free_ownership, param_call);
642             }
643           else
644             {
645                itr = eolian_function_parameters_get(fid);
646                owners += _gen_function_param_fallback(itr, fallback_free_ownership, param_call);
647             }
648 
649           if (owners == 0)
650             {
651                eina_strbuf_free(fallback_free_ownership);
652                fallback_free_ownership = NULL;
653             }
654 
655         eina_strbuf_free(param_call);
656      }
657 
658    /* property values or method params if applicable */
659    if (!var_as_ret)
660      {
661         Eina_Iterator *itr;
662         if (is_prop)
663           itr = eolian_property_values_get(fid, ftype);
664         else
665           itr = eolian_function_parameters_get(fid);
666         Eolian_Function_Parameter *pr;
667         EINA_ITERATOR_FOREACH(itr, pr)
668           {
669              Eolian_Parameter_Direction pd = eolian_parameter_direction_get(pr);
670              const Eolian_Expression *dfv = eolian_parameter_default_value_get(pr);
671              const char *prn = eolian_parameter_name_get(pr);
672              const Eolian_Type *pt = eolian_parameter_type_get(pr);
673              Eina_Stringshare *ptn = eolian_parameter_c_type_get(pr, EINA_FALSE);
674              const Eolian_Typedecl *ptd = eolian_type_typedecl_get(pt);
675 
676              Eina_Bool had_star = ptn[strlen(ptn) - 1] == '*';
677              const char *add_star = _get_add_star(ftype, pd);
678 
679              if (ptd && eolian_typedecl_type_get(ptd) == EOLIAN_TYPEDECL_FUNCTION_POINTER)
680                {
681                   _gen_func_pointer_param(prn, ptn, ptd, params, params_full, params_full_imp, is_empty);
682                   eina_stringshare_del(ptn);
683                   continue;
684                }
685 
686              if (eina_strbuf_length_get(params))
687                eina_strbuf_append(params, ", ");
688 
689              if (eina_strbuf_length_get(params_full_imp) || !eolian_function_is_static(fid))
690                eina_strbuf_append(params_full_imp, ", ");
691              eina_strbuf_append(params_full_imp, ptn);
692              if (!had_star)
693                eina_strbuf_append_char(params_full_imp, ' ');
694              eina_strbuf_append(params_full_imp, add_star);
695              eina_strbuf_append(params_full_imp, prn);
696              if ((!dfv || ftype == EOLIAN_PROP_SET) && is_empty)
697                eina_strbuf_append(params_full_imp, " EINA_UNUSED");
698              eina_strbuf_append(params, prn);
699 
700              if (eina_strbuf_length_get(params_full) || !eolian_function_is_static(fid))
701                eina_strbuf_append(params_full, ", ");
702              eina_strbuf_append(params_full, ptn);
703              if (!had_star)
704                eina_strbuf_append_char(params_full, ' ');
705              eina_strbuf_append(params_full, add_star);
706              eina_strbuf_append(params_full, prn);
707 
708              if (is_auto)
709                {
710                   if (ftype == EOLIAN_PROP_SET)
711                     eina_strbuf_append_printf(params_init, "   pd->%s = %s;\n", prn, prn);
712                   else
713                     {
714                        eina_strbuf_append_printf(params_init, "   if (%s) *%s = pd->%s;\n",
715                                                  prn, prn, prn);
716                     }
717                }
718              else if ((ftype != EOLIAN_PROP_SET) && dfv)
719                {
720                   Eolian_Value val = eolian_expression_eval(dfv, EOLIAN_MASK_ALL);
721                   if (val.type)
722                     {
723                        Eina_Stringshare *vals = eolian_expression_value_to_literal(&val);
724                        eina_strbuf_append_printf(params_init, "   if (%s) *%s = %s;",
725                                                  prn, prn, vals);
726                        eina_stringshare_del(vals);
727                        if (eolian_expression_type_get(dfv) == EOLIAN_EXPR_NAME)
728                          {
729                             Eina_Stringshare *vs = eolian_expression_serialize(dfv);
730                             eina_strbuf_append_printf(params_init, " /* %s */", vs);
731                             eina_stringshare_del(vs);
732                          }
733                        eina_strbuf_append_char(params_init, '\n');
734                     }
735                }
736 
737              eina_stringshare_del(ptn);
738           }
739         eina_iterator_free(itr);
740      }
741 
742    Eina_Bool impl_same_class = (eolian_implement_class_get(impl) == cl);
743    Eina_Bool impl_need = EINA_TRUE;
744    if (impl_same_class && eolian_implement_is_pure_virtual(impl, ftype))
745      impl_need = EINA_FALSE;
746 
747    if (!rtpn)
748      rtpn = eina_stringshare_add("void");
749 
750    char *cname = NULL, *cnamel = NULL, *ocnamel = NULL;
751    eo_gen_class_names_get(cl, &cname, NULL, &cnamel);
752    eo_gen_class_names_get(eolian_implement_class_get(impl), NULL, NULL, &ocnamel);
753 
754    if (impl_need)
755      {
756         /* figure out the data type */
757         Eina_Stringshare *dt = NULL;
758         if (eolian_function_is_static(fid))
759           dt = eina_stringshare_add("void");
760         else
761           dt = eolian_class_c_data_type_get(cl);
762 
763         eina_strbuf_append_char(buf, '\n');
764         /* no need for prototype with empty/auto impl */
765         if (!is_empty && !is_auto)
766           {
767              /* T _class_name[_orig_class]_func_name_suffix */
768              eina_strbuf_append(buf, rtpn);
769              if (rtpn[strlen(rtpn) - 1] != '*')
770                eina_strbuf_append_char(buf, ' ');
771              eina_strbuf_append_char(buf, '_');
772              eina_strbuf_append(buf, cnamel);
773              if (!impl_same_class)
774                eina_strbuf_append_printf(buf, "_%s", ocnamel);
775              eina_strbuf_append_char(buf, '_');
776              eina_strbuf_append(buf, eolian_function_name_get(fid));
777              eina_strbuf_append(buf, func_suffix);
778              /* ([const ]Eo *obj, Data_Type *pd, impl_full_params); */
779              eina_strbuf_append_char(buf, '(');
780              if (!eolian_function_is_static(fid))
781                {
782                   if ((ftype == EOLIAN_PROP_GET) || eolian_function_object_is_const(fid))
783                     eina_strbuf_append(buf, "const ");
784                   eina_strbuf_append(buf, "Eo *obj, ");
785                   eina_strbuf_append(buf, dt);
786                   eina_strbuf_append(buf, " *pd");
787                }
788              eina_strbuf_append(buf, eina_strbuf_string_get(params_full_imp));
789              if (eina_strbuf_length_get(params_full_imp) == 0 && eolian_function_is_static(fid))
790                eina_strbuf_append(buf, "void");
791              eina_strbuf_append(buf, ");\n\n");
792           }
793 
794         if (is_empty || is_auto || eina_strbuf_length_get(params_init))
795           {
796              /* we need to give the internal function name to Eo,
797               * use this hash table as indication
798               */
799              if (ftype == EOLIAN_PROP_SET)
800                eina_hash_add(_funcs_params_init_set, &impl, impl);
801              else
802                eina_hash_add(_funcs_params_init_get, &impl, impl);
803              /* generation of intermediate __eolian_... */
804              eina_strbuf_append(buf, "static ");
805              eina_strbuf_append(buf, rtpn);
806              if (rtpn[strlen(rtpn) - 1] != '*')
807                eina_strbuf_append_char(buf, ' ');
808              eina_strbuf_append(buf, "__eolian_");
809              eina_strbuf_append(buf, cnamel);
810              if (!impl_same_class)
811                eina_strbuf_append_printf(buf, "_%s", ocnamel);
812              eina_strbuf_append_char(buf, '_');
813              eina_strbuf_append(buf, eolian_function_name_get(fid));
814              eina_strbuf_append(buf, func_suffix);
815              eina_strbuf_append_char(buf, '(');
816              if ((ftype == EOLIAN_PROP_GET) || eolian_function_object_is_const(fid))
817                eina_strbuf_append(buf, "const ");
818              eina_strbuf_append(buf, "Eo *obj");
819              if (is_empty || is_auto)
820                eina_strbuf_append(buf, " EINA_UNUSED");
821              eina_strbuf_append(buf, ", ");
822              eina_strbuf_append(buf, dt);
823              eina_strbuf_append(buf, " *pd");
824              if (is_empty || (is_auto && !eina_strbuf_length_get(params_init)))
825                eina_strbuf_append(buf, " EINA_UNUSED");
826              eina_strbuf_append(buf, eina_strbuf_string_get(params_full_imp));
827              eina_strbuf_append(buf, ")\n{\n");
828           }
829         if (eina_strbuf_length_get(params_init))
830           eina_strbuf_append(buf, eina_strbuf_string_get(params_init));
831         if (is_empty || is_auto)
832           {
833              if (rtp)
834                {
835                   eina_strbuf_append(buf, "   return ");
836                   _append_defval(buf, def_ret, rtp, rtpn);
837                   eina_strbuf_append(buf, ";\n");
838                }
839              eina_strbuf_append(buf, "}\n\n");
840           }
841         else if (eina_strbuf_length_get(params_init))
842           {
843              eina_strbuf_append(buf, "   ");
844              if (rtp)
845                eina_strbuf_append(buf, "return ");
846              eina_strbuf_append_char(buf, '_');
847              eina_strbuf_append(buf, cnamel);
848              if (!impl_same_class)
849                eina_strbuf_append_printf(buf, "_%s", ocnamel);
850              eina_strbuf_append_char(buf, '_');
851              eina_strbuf_append(buf, eolian_function_name_get(fid));
852              eina_strbuf_append(buf, func_suffix);
853              eina_strbuf_append(buf, "(obj, pd, ");
854              eina_strbuf_append(buf, eina_strbuf_string_get(params));
855              eina_strbuf_append(buf, ");\n}\n\n");
856           }
857 
858         eina_stringshare_del(dt);
859      }
860 
861    if (impl_same_class && !eolian_function_is_static(fid))
862      {
863         /* generate reflection implementation */
864         if (reflect_param)
865           {
866              if (ftype == EOLIAN_PROP_GET)
867                _gen_reflect_get(buf, cnamel, reflect_param, fid, refh);
868              else
869                _gen_reflect_set(buf, cnamel, reflect_param, fid, refh);
870           }
871 
872         void *data;
873         Eina_Iterator *itr = eolian_property_keys_get(fid, ftype);
874         Eina_Bool has_params = eina_iterator_next(itr, &data);
875         eina_iterator_free(itr);
876 
877         if (!has_params && !var_as_ret)
878           {
879              if (is_prop)
880                itr = eolian_property_values_get(fid, ftype);
881              else
882                itr = eolian_function_parameters_get(fid);
883              has_params = eina_iterator_next(itr, &data);
884              eina_iterator_free(itr);
885           }
886 
887         if (fallback_free_ownership)
888           {
889              //we have owned parameters we need to take care of
890              eina_strbuf_append_printf(buf, "static void\n");
891              eina_strbuf_append_printf(buf, "_%s_ownership_fallback(%s)\n{\n", eolian_function_full_c_name_get(fid, ftype), eina_strbuf_string_get(params_full) + 2);
892 
893              eina_strbuf_append_buffer(buf, fallback_free_ownership);
894              eina_strbuf_append_printf(buf, "}\n\n");
895           }
896 
897         eina_strbuf_append(buf, "EOAPI EFL_");
898         if (!strcmp(rtpn, "void"))
899           eina_strbuf_append(buf, "VOID_");
900         eina_strbuf_append(buf, "FUNC_BODY");
901         if (has_params)
902           eina_strbuf_append_char(buf, 'V');
903         if ((ftype == EOLIAN_PROP_GET) || eolian_function_object_is_const(fid)
904             || eolian_function_is_static(fid))
905           {
906              eina_strbuf_append(buf, "_CONST");
907           }
908 
909         if (fallback_free_ownership)
910           eina_strbuf_append(buf, "_FALLBACK");
911 
912         eina_strbuf_append_char(buf, '(');
913 
914         Eina_Stringshare *eofn = eolian_function_full_c_name_get(fid, ftype);
915         eina_strbuf_append(buf, eofn);
916 
917         if (strcmp(rtpn, "void"))
918           {
919              eina_strbuf_append_printf(buf, ", %s, ", rtpn);
920              _append_defval(buf, def_ret, rtp, rtpn);
921           }
922 
923         if (fallback_free_ownership)
924           eina_strbuf_append_printf(buf, ", _%s_ownership_fallback(%s);", eolian_function_full_c_name_get(fid, ftype), eina_strbuf_string_get(params));
925 
926         if (has_params)
927           {
928              eina_strbuf_append(buf, ", EFL_FUNC_CALL(");
929              eina_strbuf_append(buf, eina_strbuf_string_get(params));
930              eina_strbuf_append_char(buf, ')');
931              eina_strbuf_append(buf, eina_strbuf_string_get(params_full));
932           }
933 
934         eina_strbuf_append(buf, ");\n");
935 
936         eina_stringshare_del(eofn);
937      }
938    if (impl_same_class && eolian_function_is_static(fid))
939      _emit_class_function(buf, fid, ftype, rtp, rtpn, params_full, ocnamel, func_suffix, params, eolian_function_full_c_name_get(fid, ftype));
940 
941    free(cname);
942    free(cnamel);
943    free(ocnamel);
944 
945    eina_stringshare_del(rtpn);
946 
947    eina_strbuf_free(params);
948    eina_strbuf_free(params_full);
949    eina_strbuf_free(params_full_imp);
950    eina_strbuf_free(params_init);
951    if (fallback_free_ownership)
952      eina_strbuf_free(fallback_free_ownership);
953 }
954 
955 static void
_gen_opfunc(const Eolian_Function * fid,Eolian_Function_Type ftype,Eina_Strbuf * buf,const Eolian_Implement * impl,Eina_Bool pinit,const char * cnamel,const char * ocnamel)956 _gen_opfunc(const Eolian_Function *fid, Eolian_Function_Type ftype,
957             Eina_Strbuf *buf, const Eolian_Implement *impl, Eina_Bool pinit,
958             const char *cnamel, const char *ocnamel)
959 {
960    Eina_Stringshare *fnm = eolian_function_full_c_name_get(fid, ftype);
961    eina_strbuf_append(buf, "      EFL_OBJECT_OP_FUNC(");
962    eina_strbuf_append(buf, fnm);
963    eina_strbuf_append(buf, ", ");
964    if (!ocnamel && eolian_implement_is_pure_virtual(impl, ftype))
965      eina_strbuf_append(buf, "NULL),\n");
966    else
967      {
968         if (pinit)
969           eina_strbuf_append(buf, "__eolian");
970         eina_strbuf_append_printf(buf, "_%s_", cnamel);
971         if (ocnamel)
972           eina_strbuf_append_printf(buf, "%s_", ocnamel);
973         eina_strbuf_append(buf, eolian_function_name_get(fid));
974         if (ftype == EOLIAN_PROP_GET)
975           eina_strbuf_append(buf, "_get");
976         else if (ftype == EOLIAN_PROP_SET)
977           eina_strbuf_append(buf, "_set");
978         eina_strbuf_append(buf, "),\n");
979      }
980 }
981 
982 static void
_gen_reflop(const Eolian_Function * fid,Eina_Strbuf * buf,const char * cnamel,Eina_Hash * refh)983 _gen_reflop(const Eolian_Function *fid, Eina_Strbuf *buf, const char *cnamel, Eina_Hash *refh)
984 {
985    Eolian_Function_Type aftype = (Eolian_Function_Type)eina_hash_find(refh, &fid);
986    if (aftype == EOLIAN_UNRESOLVED)
987      return;
988 
989    eina_strbuf_append_printf(buf, "      {\"%s\", ", eolian_function_name_get(fid));
990 
991    if (aftype == EOLIAN_PROP_SET || aftype == EOLIAN_PROPERTY)
992      {
993         eina_strbuf_append_printf(buf, "__eolian_%s_%s_set_reflect, ",
994           cnamel, eolian_function_name_get(fid));
995      }
996    else
997      eina_strbuf_append(buf, "NULL, ");
998 
999    if (aftype == EOLIAN_PROP_GET || aftype == EOLIAN_PROPERTY)
1000      {
1001         eina_strbuf_append_printf(buf, "__eolian_%s_%s_get_reflect},\n",
1002           cnamel, eolian_function_name_get(fid));
1003      }
1004    else
1005      eina_strbuf_append(buf, "NULL},\n");
1006 }
1007 
1008 static void
_gen_initializer(const Eolian_Class * cl,Eina_Strbuf * buf,Eina_Hash * refh)1009 _gen_initializer(const Eolian_Class *cl, Eina_Strbuf *buf, Eina_Hash *refh)
1010 {
1011    char *cnamel = NULL, *cnameu = NULL;
1012    eo_gen_class_names_get(cl, NULL, &cnameu, &cnamel);
1013 
1014    eina_strbuf_append(buf, "\nstatic Eina_Bool\n_");
1015    eina_strbuf_append(buf, cnamel);
1016    eina_strbuf_append(buf, "_class_initializer(Efl_Class *klass)\n{\n");
1017    eina_strbuf_append(buf, "   const Efl_Object_Ops *opsp = NULL;\n\n");
1018    eina_strbuf_append(buf, "   const Efl_Object_Property_Reflection_Ops *ropsp = NULL;\n\n");
1019 
1020    Eina_Strbuf *ops = eina_strbuf_new();
1021    Eina_Strbuf *refls = eina_strbuf_new();
1022 
1023    /* start over with clean itearator */
1024    const Eolian_Implement *imp;
1025    Eina_Iterator *itr = eolian_class_implements_get(cl);
1026    EINA_ITERATOR_FOREACH(itr, imp)
1027      {
1028         const Eolian_Class *icl = eolian_implement_class_get(imp);
1029         Eolian_Function_Type ftype;
1030         const Eolian_Function *fid = eolian_implement_function_get(imp, &ftype);
1031 
1032         if (eolian_function_is_static(fid)) continue;
1033 
1034         if (!eina_strbuf_length_get(ops))
1035           eina_strbuf_append_printf(ops, "   EFL_OPS_DEFINE(ops,\n");
1036 
1037         Eina_Bool found_get = !!eina_hash_find(_funcs_params_init_get, &imp);
1038         Eina_Bool found_set = !!eina_hash_find(_funcs_params_init_set, &imp);
1039         char *ocnamel = NULL;
1040         if (cl != icl)
1041           eo_gen_class_names_get(icl, NULL, NULL, &ocnamel);
1042 
1043         switch (ftype)
1044           {
1045            case EOLIAN_PROP_GET:
1046              _gen_opfunc(fid, EOLIAN_PROP_GET, ops, imp, found_get, cnamel, ocnamel);
1047              _gen_reflop(fid, refls, cnamel, refh);
1048              break;
1049            case EOLIAN_PROP_SET:
1050              _gen_opfunc(fid, EOLIAN_PROP_SET, ops, imp, found_set, cnamel, ocnamel);
1051              _gen_reflop(fid, refls, cnamel, refh);
1052              break;
1053            case EOLIAN_PROPERTY:
1054              _gen_opfunc(fid, EOLIAN_PROP_SET, ops, imp, found_set, cnamel, ocnamel);
1055              _gen_opfunc(fid, EOLIAN_PROP_GET, ops, imp, found_get, cnamel, ocnamel);
1056              _gen_reflop(fid, refls, cnamel, refh);
1057              break;
1058            default:
1059              _gen_opfunc(fid, EOLIAN_METHOD, ops, imp, found_get, cnamel, ocnamel);
1060              break;
1061           }
1062 
1063         free(ocnamel);
1064      }
1065    eina_iterator_free(itr);
1066 
1067    if (eina_strbuf_length_get(ops))
1068      {
1069         /* make sure the extras are defined */
1070         eina_strbuf_append_printf(buf, "#ifndef %s_EXTRA_OPS\n", cnameu);
1071         eina_strbuf_append_printf(buf, "#define %s_EXTRA_OPS\n", cnameu);
1072         eina_strbuf_append(buf, "#endif\n\n");
1073 
1074         eina_strbuf_append_printf(ops, "      %s_EXTRA_OPS\n   );\n", cnameu);
1075         eina_strbuf_append(buf, eina_strbuf_string_get(ops));
1076         eina_strbuf_append(buf, "   opsp = &ops;\n\n");
1077      }
1078    else
1079      {
1080         /* no predefined, but if custom ones are required define it anyway */
1081         eina_strbuf_append_printf(buf, "#ifdef %s_EXTRA_OPS\n", cnameu);
1082         eina_strbuf_append_printf(buf, "   EFL_OPS_DEFINE(ops, %s_EXTRA_OPS);\n", cnameu);
1083         eina_strbuf_append(buf, "   opsp = &ops;\n");
1084         eina_strbuf_append(buf, "#endif\n\n");
1085      }
1086 
1087    if (eina_strbuf_length_get(refls))
1088      {
1089         eina_strbuf_append(buf, "   static const Efl_Object_Property_Reflection refl_table[] = {\n");
1090         eina_strbuf_append_buffer(buf, refls);
1091         eina_strbuf_append(buf, "   };\n");
1092         eina_strbuf_append(buf, "   static const Efl_Object_Property_Reflection_Ops rops = {\n");
1093         eina_strbuf_append(buf, "      refl_table, EINA_C_ARRAY_LENGTH(refl_table)\n");
1094         eina_strbuf_append(buf, "   };\n");
1095         eina_strbuf_append(buf, "   ropsp = &rops;\n\n");
1096      }
1097 
1098    eina_strbuf_append(buf, "   return efl_class_functions_set(klass, opsp, ropsp);\n");
1099 
1100    eina_strbuf_free(ops);
1101    eina_strbuf_free(refls);
1102 
1103    eina_strbuf_append(buf, "}\n\n");
1104 
1105    free(cnameu);
1106    free(cnamel);
1107 }
1108 
1109 void
eo_gen_source_gen(const Eolian_Class * cl,Eina_Strbuf * buf)1110 eo_gen_source_gen(const Eolian_Class *cl, Eina_Strbuf *buf)
1111 {
1112    if (!cl)
1113      return;
1114 
1115    _funcs_params_init_get = eina_hash_pointer_new(NULL);
1116    _funcs_params_init_set = eina_hash_pointer_new(NULL);
1117 
1118    char *cnamel = NULL;
1119    eo_gen_class_names_get(cl, NULL, NULL, &cnamel);
1120 
1121    /* event section, they come first */
1122    {
1123       Eina_Iterator *itr = eolian_class_events_get(cl);
1124       Eolian_Event *ev;
1125       EINA_ITERATOR_FOREACH(itr, ev)
1126         {
1127            Eina_Stringshare *evn = eolian_event_c_macro_get(ev);
1128            eina_strbuf_append(buf, "EWAPI const Efl_Event_Description _");
1129            eina_strbuf_append(buf, evn);
1130            eina_strbuf_append(buf, " =\n   EFL_EVENT_DESCRIPTION");
1131            if (eolian_event_is_hot(ev))
1132              eina_strbuf_append(buf, "_HOT");
1133            if (eolian_event_is_restart(ev))
1134              eina_strbuf_append(buf, "_RESTART");
1135            eina_strbuf_append_printf(buf, "(\"%s\");\n", eolian_event_name_get(ev));
1136            eina_stringshare_del(evn);
1137         }
1138       eina_iterator_free(itr);
1139    }
1140 
1141    /* Eolian_Function -> Eolian_Function_Type
1142     * maps which parts of which functions are qualified for reflection
1143     */
1144    Eina_Hash *refh = eina_hash_pointer_new(NULL);
1145 
1146    /* method section */
1147    {
1148       Eina_Iterator *itr = eolian_class_implements_get(cl);
1149       const Eolian_Implement *imp;
1150       EINA_ITERATOR_FOREACH(itr, imp)
1151         {
1152            Eolian_Function_Type ftype = EOLIAN_UNRESOLVED;
1153            const Eolian_Function *fid = eolian_implement_function_get(imp, &ftype);
1154            switch (ftype)
1155              {
1156               case EOLIAN_PROP_GET:
1157               case EOLIAN_PROP_SET:
1158                 _gen_func(cl, fid, ftype, buf, imp, refh);
1159                 break;
1160               case EOLIAN_PROPERTY:
1161                 _gen_func(cl, fid, EOLIAN_PROP_SET, buf, imp, refh);
1162                 _gen_func(cl, fid, EOLIAN_PROP_GET, buf, imp, refh);
1163                 break;
1164               default:
1165                 _gen_func(cl, fid, EOLIAN_METHOD, buf, imp, refh);
1166              }
1167         }
1168       eina_iterator_free(itr);
1169    }
1170 
1171    /* class initializer - contains method defs */
1172    _gen_initializer(cl, buf, refh);
1173    eina_hash_free(refh);
1174 
1175    /* class description */
1176    eina_strbuf_append(buf, "static const Efl_Class_Description _");
1177    eina_strbuf_append(buf, cnamel);
1178    eina_strbuf_append(buf, "_class_desc = {\n"
1179                            "   EO_VERSION,\n");
1180    eina_strbuf_append_printf(buf, "   \"%s\",\n", eolian_class_name_get(cl));
1181 
1182    switch (eolian_class_type_get(cl))
1183      {
1184       case EOLIAN_CLASS_ABSTRACT:
1185         eina_strbuf_append(buf, "   EFL_CLASS_TYPE_REGULAR_NO_INSTANT,\n");
1186         break;
1187       case EOLIAN_CLASS_MIXIN:
1188         eina_strbuf_append(buf, "   EFL_CLASS_TYPE_MIXIN,\n");
1189         break;
1190       case EOLIAN_CLASS_INTERFACE:
1191         eina_strbuf_append(buf, "   EFL_CLASS_TYPE_INTERFACE,\n");
1192         break;
1193       default:
1194         eina_strbuf_append(buf, "   EFL_CLASS_TYPE_REGULAR,\n");
1195         break;
1196      }
1197 
1198    Eina_Stringshare *dt = eolian_class_c_data_type_get(cl);
1199    if (!strcmp(dt, "void"))
1200      eina_strbuf_append(buf, "   0,\n");
1201    else
1202      eina_strbuf_append_printf(buf, "   sizeof(%s),\n", dt);
1203    eina_stringshare_del(dt);
1204 
1205    eina_strbuf_append_printf(buf, "   _%s_class_initializer,\n", cnamel);
1206 
1207    if (eolian_class_ctor_enable_get(cl))
1208      eina_strbuf_append_printf(buf, "   _%s_class_constructor,\n", cnamel);
1209    else
1210      eina_strbuf_append(buf, "   NULL,\n");
1211 
1212    if (eolian_class_dtor_enable_get(cl))
1213      eina_strbuf_append_printf(buf, "   _%s_class_destructor\n", cnamel);
1214    else
1215      eina_strbuf_append(buf, "   NULL\n");
1216 
1217    eina_strbuf_append(buf, "};\n\n");
1218 
1219    /* class def */
1220    eina_strbuf_append(buf, "EFL_DEFINE_CLASS(");
1221 
1222    Eina_Stringshare *cgfunc = eolian_class_c_get_function_name_get(cl);
1223    eina_strbuf_append(buf, cgfunc);
1224    eina_stringshare_del(cgfunc);
1225 
1226    eina_strbuf_append_printf(buf, ", &_%s_class_desc", cnamel);
1227 
1228    /* inherits in EFL_DEFINE_CLASS */
1229    {
1230       const Eolian_Class *icl = eolian_class_parent_get(cl);
1231       /* no inherits, NULL parent */
1232       if (!icl)
1233         eina_strbuf_append(buf, ", NULL");
1234       else
1235         {
1236            Eina_Stringshare *mname = eolian_class_c_macro_get(icl);
1237            eina_strbuf_append_printf(buf, ", %s", mname);
1238            eina_stringshare_del(mname);
1239         }
1240       Eina_Iterator *itr = eolian_class_extensions_get(cl);
1241       EINA_ITERATOR_FOREACH(itr, icl)
1242         {
1243            Eina_Stringshare *mname = eolian_class_c_macro_get(icl);
1244            eina_strbuf_append_printf(buf, ", %s", mname);
1245            eina_stringshare_del(mname);
1246         }
1247       eina_iterator_free(itr);
1248    }
1249 
1250    /* terminate inherits */
1251    eina_strbuf_append(buf, ", NULL);\n");
1252 
1253    /* and we're done */
1254    free(cnamel);
1255    eina_hash_free(_funcs_params_init_get);
1256    eina_hash_free(_funcs_params_init_set);
1257 }
1258 
1259 static void
_gen_params(const Eolian_Function * fid,Eolian_Function_Type ftype,Eina_Bool var_as_ret,Eina_Strbuf * params,Eina_Strbuf * params_full)1260 _gen_params(const Eolian_Function *fid, Eolian_Function_Type ftype,
1261             Eina_Bool var_as_ret, Eina_Strbuf *params, Eina_Strbuf *params_full)
1262 {
1263    Eina_Bool is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET);
1264 
1265    /* property keys */
1266    {
1267       Eina_Iterator *itr = eolian_property_keys_get(fid, ftype);
1268       Eolian_Function_Parameter *pr;
1269       EINA_ITERATOR_FOREACH(itr, pr)
1270         {
1271            const char *prn = eolian_parameter_name_get(pr);
1272            Eina_Stringshare *ptn = eolian_parameter_c_type_get(pr, EINA_FALSE);
1273 
1274            eina_strbuf_append(params, ", ");
1275            eina_strbuf_append(params, prn);
1276 
1277            eina_strbuf_append_printf(params_full, ", %s", ptn);
1278            if (ptn[strlen(ptn) - 1] != '*')
1279              eina_strbuf_append_char(params_full, ' ');
1280            eina_strbuf_append(params_full, prn);
1281 
1282            eina_stringshare_del(ptn);
1283         }
1284       eina_iterator_free(itr);
1285    }
1286 
1287    /* property values or method params if applicable */
1288    if (!var_as_ret)
1289      {
1290         Eina_Iterator *itr;
1291         if (is_prop)
1292           itr = eolian_property_values_get(fid, ftype);
1293         else
1294           itr = eolian_function_parameters_get(fid);
1295         Eolian_Function_Parameter *pr;
1296         EINA_ITERATOR_FOREACH(itr, pr)
1297           {
1298              Eolian_Parameter_Direction pd = eolian_parameter_direction_get(pr);
1299              const char *prn = eolian_parameter_name_get(pr);
1300              const Eolian_Type *pt = eolian_parameter_type_get(pr);
1301              const Eolian_Typedecl *ptd = eolian_type_typedecl_get(pt);
1302              Eina_Stringshare *ptn = eolian_parameter_c_type_get(pr, EINA_FALSE);
1303 
1304              if (ptd && eolian_typedecl_type_get(ptd) == EOLIAN_TYPEDECL_FUNCTION_POINTER)
1305                {
1306                   eina_strbuf_append_printf(params, ", %s_data, %s, %s_free_cb", prn, prn, prn);
1307                   eina_strbuf_append_printf(params_full, ", void *%s_data, %s %s, Eina_Free_Cb %s_free_cb", prn, ptn, prn, prn);
1308 
1309                   eina_stringshare_del(ptn);
1310                   continue;
1311                }
1312 
1313              Eina_Bool had_star = ptn[strlen(ptn) - 1] == '*';
1314              const char *add_star = _get_add_star(ftype, pd);
1315 
1316              eina_strbuf_append(params, ", ");
1317              eina_strbuf_append(params, prn);
1318 
1319              eina_strbuf_append(params_full, ", ");
1320              eina_strbuf_append(params_full, ptn);
1321              if (!had_star)
1322                eina_strbuf_append_char(params_full, ' ');
1323              eina_strbuf_append(params_full, add_star);
1324              eina_strbuf_append(params_full, prn);
1325 
1326              eina_stringshare_del(ptn);
1327           }
1328         eina_iterator_free(itr);
1329      }
1330 }
1331 
1332 static void
_gen_proto(const Eolian_Class * cl,const Eolian_Function * fid,Eolian_Function_Type ftype,Eina_Strbuf * buf,const Eolian_Implement * impl,const char * dtype,const char * cnamel)1333 _gen_proto(const Eolian_Class *cl, const Eolian_Function *fid,
1334            Eolian_Function_Type ftype, Eina_Strbuf *buf,
1335            const Eolian_Implement *impl, const char *dtype, const char *cnamel)
1336 {
1337    Eina_Bool impl_same_class = (eolian_implement_class_get(impl) == cl);
1338    if (impl_same_class && eolian_implement_is_pure_virtual(impl, ftype))
1339      return;
1340 
1341    char *ocnamel = NULL;
1342    if (!impl_same_class)
1343      eo_gen_class_names_get(eolian_implement_class_get(impl), NULL, NULL, &ocnamel);
1344 
1345    char fname[256 + 128], iname[256];
1346    if (!impl_same_class)
1347      snprintf(iname, sizeof(iname), "%s_%s", cnamel, ocnamel);
1348    else
1349      snprintf(iname, sizeof(iname), "%s", cnamel);
1350 
1351    snprintf(fname, sizeof(fname), "_%s_%s%s", iname, eolian_function_name_get(fid),
1352             (ftype == EOLIAN_PROP_GET)
1353                ? "_get" : ((ftype == EOLIAN_PROP_SET) ? "_set" : ""));
1354 
1355    if (_function_exists(fname, buf))
1356      {
1357         free(ocnamel);
1358         return;
1359      }
1360 
1361    printf("generating function %s...\n", fname);
1362 
1363    Eina_Bool var_as_ret = EINA_FALSE;
1364    const Eolian_Type *rtp = eolian_function_return_type_get(fid, ftype);
1365    Eina_Stringshare *rtpn = NULL;
1366    if ((ftype == EOLIAN_PROP_GET) && !rtp)
1367      {
1368         void *d1, *d2;
1369         Eina_Iterator *itr = eolian_property_values_get(fid, ftype);
1370         if (eina_iterator_next(itr, &d1) && !eina_iterator_next(itr, &d2))
1371           {
1372              Eolian_Function_Parameter *pr = d1;
1373              rtp = eolian_parameter_type_get(pr);
1374              rtpn = eolian_parameter_c_type_get(pr, EINA_FALSE);
1375              var_as_ret = EINA_TRUE;
1376           }
1377         eina_iterator_free(itr);
1378      }
1379 
1380    eina_strbuf_append(buf, "EOLIAN static ");
1381    if (rtp)
1382      {
1383         if (!rtpn)
1384           rtpn = eolian_function_return_c_type_get(fid, ftype);
1385         eina_strbuf_append(buf, rtpn);
1386         eina_stringshare_del(rtpn);
1387      }
1388    else
1389      eina_strbuf_append(buf, "void");
1390 
1391    eina_strbuf_append_printf(buf, "\n%s(", fname);
1392 
1393    if ((ftype == EOLIAN_PROP_GET) || eolian_function_object_is_const(fid))
1394      eina_strbuf_append(buf, "const ");
1395 
1396    eina_strbuf_append(buf, "Eo *obj, ");
1397    if (strcmp(dtype, "void"))
1398      eina_strbuf_append_printf(buf, "%s *pd", dtype);
1399    else
1400      eina_strbuf_append(buf, "void *pd EINA_UNUSED");
1401 
1402    /* gen params here */
1403    Eina_Strbuf *params = eina_strbuf_new();
1404    Eina_Strbuf *params_full = eina_strbuf_new();
1405    _gen_params(fid, ftype, var_as_ret, params, params_full);
1406 
1407    if (eina_strbuf_length_get(params_full))
1408      eina_strbuf_append(buf, eina_strbuf_string_get(params_full));
1409 
1410    eina_strbuf_append(buf, ")\n{\n");
1411 
1412    const char *efname = eolian_function_name_get(fid);
1413    if (strlen(efname) >= (sizeof("destructor") - 1) && !impl_same_class)
1414      if (!strcmp(efname + strlen(efname) - sizeof("destructor") + 1, "destructor"))
1415        {
1416           Eina_Stringshare *fcn = eolian_function_full_c_name_get(fid, ftype);
1417           Eina_Stringshare *mname = eolian_class_c_macro_get(cl);
1418           eina_strbuf_append(buf, "   ");
1419           eina_strbuf_append(buf, fcn);
1420           eina_stringshare_del(fcn);
1421           eina_strbuf_append_printf(buf, "(efl_super(obj, %s)", mname);
1422           eina_stringshare_del(mname);
1423           if (eina_strbuf_length_get(params))
1424             eina_strbuf_append(buf, eina_strbuf_string_get(params));
1425           eina_strbuf_append(buf, ");\n");
1426        }
1427    eina_strbuf_append(buf, "\n}\n\n");
1428 
1429    eina_strbuf_free(params_full);
1430    eina_strbuf_free(params);
1431    free(ocnamel);
1432 }
1433 
1434 void
eo_gen_impl_gen(const Eolian_Class * cl,Eina_Strbuf * buf)1435 eo_gen_impl_gen(const Eolian_Class *cl, Eina_Strbuf *buf)
1436 {
1437    if (!cl)
1438      return;
1439 
1440    char *cname = NULL, *cnamel = NULL;
1441    eo_gen_class_names_get(cl, &cname, NULL, &cnamel);
1442 
1443    Eina_Strbuf *beg = eina_strbuf_new();
1444 
1445    if (!_type_exists("EFL_BETA_API_SUPPORT", buf))
1446      {
1447         printf("generating EFL_BETA_API_SUPPORT...\n");
1448         eina_strbuf_append(beg, "#define EFL_BETA_API_SUPPORT\n");
1449      }
1450 
1451    if (!_type_exists("<Eo.h>", buf))
1452      {
1453         printf("generating includes for <Eo.h> and \"%s.eo.h\"...\n", cnamel);
1454         eina_strbuf_append(beg, "#include <Eo.h>\n");
1455         eina_strbuf_append_printf(beg, "#include \"%s.eo.h\"\n\n", cnamel);
1456      }
1457 
1458    /* determine data type name */
1459    Eina_Stringshare *dt = eolian_class_c_data_type_get(cl);
1460 
1461    /* generate data type struct */
1462    if (strcmp(dt, "void") && !_type_exists(dt, buf))
1463      {
1464         printf("generating data type structure %s...\n", dt);
1465         eina_strbuf_append_printf(beg, "typedef struct\n{\n\n} %s;\n\n", dt);
1466      }
1467 
1468    if (eina_strbuf_length_get(beg))
1469      eina_strbuf_prepend(buf, eina_strbuf_string_get(beg));
1470 
1471    eina_strbuf_free(beg);
1472 
1473    /* method section */
1474    {
1475       Eina_Iterator *itr = eolian_class_implements_get(cl);
1476       const Eolian_Implement *imp;
1477       EINA_ITERATOR_FOREACH(itr, imp)
1478         {
1479            Eolian_Function_Type ftype = EOLIAN_UNRESOLVED;
1480            const Eolian_Function *fid = eolian_implement_function_get(imp, &ftype);
1481            switch (ftype)
1482              {
1483               case EOLIAN_PROP_GET:
1484               case EOLIAN_PROP_SET:
1485                 _gen_proto(cl, fid, ftype, buf, imp, dt, cnamel);
1486                 break;
1487               case EOLIAN_PROPERTY:
1488                 _gen_proto(cl, fid, EOLIAN_PROP_SET, buf, imp, dt, cnamel);
1489                 _gen_proto(cl, fid, EOLIAN_PROP_GET, buf, imp, dt, cnamel);
1490                 break;
1491               default:
1492                 _gen_proto(cl, fid, EOLIAN_METHOD, buf, imp, dt, cnamel);
1493              }
1494         }
1495       eina_iterator_free(itr);
1496    }
1497 
1498    /* free the data type */
1499    eina_stringshare_del(dt);
1500 
1501    if (eolian_class_ctor_enable_get(cl))
1502      {
1503         char fname[128];
1504         snprintf(fname, sizeof(fname), "_%s_class_constructor", cnamel);
1505         if (!_function_exists(fname, buf))
1506           {
1507              printf("generating function %s...\n", fname);
1508              eina_strbuf_append_printf(buf,
1509                                        "EOLIAN static void\n"
1510                                        "_%s_class_constructor(Efl_Class *klass)\n"
1511                                        "{\n\n"
1512                                        "}\n\n", cnamel);
1513           }
1514      }
1515 
1516    if (eolian_class_dtor_enable_get(cl))
1517      {
1518         char fname[128];
1519         snprintf(fname, sizeof(fname), "_%s_class_destructor", cnamel);
1520         if (!_function_exists(fname, buf))
1521           {
1522              printf("generating function %s...\n", fname);
1523              eina_strbuf_append_printf(buf,
1524                                        "EOLIAN static void\n"
1525                                        "_%s_class_destructor(Efl_Class *klass)\n"
1526                                        "{\n\n"
1527                                        "}\n\n", cnamel);
1528           }
1529      }
1530 
1531    printf("removing includes for \"%s.eo.c\"\n", cnamel);
1532    char ibuf[512];
1533    snprintf(ibuf, sizeof(ibuf), "\n#include \"%s.eo.c\"\n", cnamel);
1534    eina_strbuf_replace_all(buf, ibuf, "\n");
1535 
1536    printf("generating include for \"%s.eo.c\"\n", cnamel);
1537    eina_strbuf_append_printf(buf, "#include \"%s.eo.c\"\n", cnamel);
1538 
1539    free(cname);
1540    free(cnamel);
1541 }
1542