Tizen 2.4 SDK Rev6 Release
[framework/uifw/efl.git] / src / bin / eolian / legacy_generator.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include <Eina.h>
6 #include <string.h>
7
8 #include "Eolian.h"
9
10 #include "legacy_generator.h"
11 #include "common_funcs.h"
12
13 static _eolian_class_vars class_env;
14
15 static const char
16 tmpl_eapi_funcdef[] = "\n\
17 /**\n\
18  *\n\
19 @#desc\n\
20  *\n\
21 @#list_desc_param\
22  */\n\
23 EAPI @#type_return%s(@#params)@#flags;\n\
24 ";
25
26 /*@#CLASS_CHECK(obj) @#check_ret;\n\*/
27 static const char
28 tmpl_eapi_body[] ="\
29 \n\
30 EAPI @#ret_type\n\
31 @#eapi_func(@#full_params)\n\
32 {\n\
33    return eo_do(@#eo_obj, @#eo_func(@#eo_params));\n\
34 }\n\
35 ";
36 static const char
37 tmpl_eapi_body_void[] ="\
38 \n\
39 EAPI void\n\
40 @#eapi_func(@#full_params)\n\
41 {\n\
42    eo_do(@#eo_obj, @#eo_func(@#eo_params));\n\
43 }\n\
44 ";
45
46 static void
47 _eapi_decl_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, Eolian_Function_Type ftype, Eina_Strbuf *buf)
48 {
49    _eolian_class_func_vars func_env;
50    const char *funcname = eolian_function_name_get(funcid);
51    const Eolian_Type *rettypet = NULL;
52    const char *rettype = NULL;
53    Eina_Bool var_as_ret = EINA_FALSE;
54    Eina_Bool add_star = EINA_FALSE;
55    Eina_Bool ret_const = EINA_FALSE;
56    Eina_Iterator *itr;
57    void *data, *data2;
58    Eina_Strbuf *flags = NULL;
59    int leg_param_idx = 1; /* Index of the parameter inside the legacy function. It begins from 1 since obj is the first. */
60
61    Eina_Strbuf *fbody = eina_strbuf_new();
62    Eina_Strbuf *fparam = eina_strbuf_new();
63    Eina_Strbuf *descparam = eina_strbuf_new();
64
65    _class_func_env_create(class, funcname, ftype, &func_env);
66    rettypet = eolian_function_return_type_get(funcid, ftype);
67    if (ftype == EOLIAN_PROP_GET)
68      {
69         add_star = EINA_TRUE;
70         if (!rettypet)
71           {
72              itr = eolian_function_parameters_get(funcid);
73              /* We want to check if there is only one parameter */
74              if (eina_iterator_next(itr, &data) && !eina_iterator_next(itr, &data2))
75                {
76                   rettypet = eolian_parameter_type_get((Eolian_Function_Parameter*)data);
77                   var_as_ret = EINA_TRUE;
78                   ret_const = eolian_parameter_const_attribute_get(data, EINA_TRUE);
79                }
80              eina_iterator_free(itr);
81           }
82      }
83
84    if (func_env.legacy_func[0] == '\0') goto end;
85    eina_strbuf_append_printf(fbody, tmpl_eapi_funcdef, func_env.legacy_func);
86
87    if (!eolian_function_is_class(funcid))
88      {
89         if (ftype == EOLIAN_PROP_GET || eolian_function_object_is_const(funcid))
90            eina_strbuf_append(fparam, "const ");
91         eina_strbuf_append_printf(fparam, "%s *obj", class_env.full_classname);
92      }
93    Eina_Strbuf *linedesc = eina_strbuf_new();
94    const char *common_desc = eolian_function_description_get(funcid, EOLIAN_UNRESOLVED);
95    const char *specific_desc = (ftype == EOLIAN_PROP_SET || ftype == EOLIAN_PROP_GET) ?
96          eolian_function_description_get(funcid, ftype) : NULL;
97    if (!common_desc && !specific_desc) eina_strbuf_append(linedesc, "No description supplied.");
98    if (common_desc) eina_strbuf_append_printf(linedesc, "%s\n", common_desc);
99    if (specific_desc) eina_strbuf_append(linedesc, specific_desc);
100    if (eina_strbuf_length_get(linedesc))
101      {
102         eina_strbuf_replace_all(linedesc, "\n", "\n * ");
103         eina_strbuf_replace_all(linedesc, " * \n", " *\n");
104         eina_strbuf_prepend(linedesc," * ");
105      }
106    else
107      {
108         eina_strbuf_append(linedesc," *");
109      }
110    // TIZEN_ONLY(20160125): add parameter "obj" documentation
111    Eina_Bool has_param_obj = !!strstr(eina_strbuf_string_get(linedesc), "param[in] obj");
112
113    eina_strbuf_replace_all(fbody, "@#desc", eina_strbuf_string_get(linedesc));
114    eina_strbuf_free(linedesc);
115
116    if (!has_param_obj)
117      {
118         Eolian_Class_Type type;
119         char *ch, *nm;
120
121         eina_strbuf_append(descparam, " * @param[in] obj The ");
122
123         type = eolian_class_type_get(class);
124
125         nm = strdup(eolian_class_name_get(class));
126         eina_str_tolower(&nm);
127         while ((ch = strchr(nm, '.'))) *ch = ' ';
128         while ((ch = strchr(nm, '_'))) *ch = ' ';
129
130         if (!strncmp(nm, "object", strlen("object")))
131           {
132              ch = nm + strlen("object");
133              if (*ch)
134                {
135                   while (*ch == ' ') ch++;
136                   eina_strbuf_append(descparam, ch);
137                   if ((type == EOLIAN_CLASS_REGULAR) ||
138                       (type == EOLIAN_CLASS_ABSTRACT))
139                     eina_strbuf_append(descparam, " object\n");
140                }
141              else
142                {
143                   free(nm);
144                   nm = strdup(eolian_class_full_name_get(class));
145                   eina_str_tolower(&nm);
146                   while ((ch = strchr(nm, '.'))) *ch = ' ';
147                   while ((ch = strchr(nm, '_'))) *ch = ' ';
148                   eina_strbuf_append(descparam, nm);
149                   eina_strbuf_append_char(descparam, '\n');
150                }
151           }
152         else
153           {
154              eina_strbuf_append(descparam, nm);
155              if ((type == EOLIAN_CLASS_REGULAR) ||
156                  (type == EOLIAN_CLASS_ABSTRACT))
157                eina_strbuf_append(descparam, " object\n");
158           }
159         free(nm);
160      }
161    //
162    itr = eolian_property_keys_get(funcid);
163    EINA_ITERATOR_FOREACH(itr, data)
164      {
165         Eolian_Function_Parameter *param = data;
166         const Eolian_Type *ptypet = eolian_parameter_type_get(param);
167         const char *pname = eolian_parameter_name_get(param);
168         const char *ptype = eolian_type_c_type_get(ptypet);
169         const char *pdesc = eolian_parameter_description_get(param);
170         leg_param_idx++;
171         if (eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, ", ");
172         eina_strbuf_append_printf(fparam, "%s%s %s",
173               eolian_parameter_const_attribute_get(data, ftype == EOLIAN_PROP_GET)?"const":"",
174               ptype, pname);
175         eina_stringshare_del(ptype);
176         eina_strbuf_append_printf(descparam, " * @param[in] %s %s\n", pname, pdesc?pdesc:"No description supplied.");
177         if (eolian_parameter_is_nonull((Eolian_Function_Parameter*)data))
178           {
179              if (!flags)
180                {
181                   flags = eina_strbuf_new();
182                   eina_strbuf_append_printf(flags, " EINA_ARG_NONNULL(%d", leg_param_idx);
183                }
184              else
185                 eina_strbuf_append_printf(flags, ", %d", leg_param_idx);
186           }
187      }
188    eina_iterator_free(itr);
189    if (!var_as_ret)
190      {
191        itr = eolian_function_parameters_get(funcid);
192        EINA_ITERATOR_FOREACH(itr, data)
193          {
194             Eolian_Function_Parameter *param = data;
195             const Eolian_Type *ptypet = eolian_parameter_type_get(param);
196             const char *pname = eolian_parameter_name_get(param);
197             const char *ptype = eolian_type_c_type_get(ptypet);
198             const char *pdesc = eolian_parameter_description_get(param);
199             Eolian_Parameter_Dir pdir = eolian_parameter_direction_get(param);
200             // TIZEN_ONLY(20150725): for doxygen 1.7.6.1
201             //const char *str_dir[] = {"in", "out", "inout"};
202             const char *str_dir[] = {"in", "out", "in,out"};
203             Eina_Bool had_star = !!strchr(ptype, '*');
204             if (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) add_star = (pdir == EOLIAN_OUT_PARAM || pdir == EOLIAN_INOUT_PARAM);
205             if (ftype == EOLIAN_PROP_GET) pdir = EOLIAN_OUT_PARAM;
206             if (ftype == EOLIAN_PROP_SET) pdir = EOLIAN_IN_PARAM;
207             leg_param_idx++;
208             if (eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, ", ");
209             eina_strbuf_append_printf(fparam, "%s%s%s%s%s",
210                   eolian_parameter_const_attribute_get(data, ftype == EOLIAN_PROP_GET)?"const ":"",
211                   ptype, had_star?"":" ", add_star?"*":"", pname);
212             eina_stringshare_del(ptype);
213             const char *dir_str = str_dir[(int)pdir];
214             eina_strbuf_append_printf(descparam, " * @param[%s] %s %s\n", dir_str, pname, pdesc?pdesc:"No description supplied.");
215             if (eolian_parameter_is_nonull((Eolian_Function_Parameter*)data))
216               {
217                  if (!flags)
218                    {
219                       flags = eina_strbuf_new();
220                       eina_strbuf_append_printf(flags, " EINA_ARG_NONNULL(%d", leg_param_idx);
221                    }
222                  else
223                     eina_strbuf_append_printf(flags, ", %d", leg_param_idx);
224               }
225          }
226        eina_iterator_free(itr);
227      }
228    if (!eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, "void");
229    if (flags) eina_strbuf_append_printf(flags, ")");
230
231    if (rettypet) rettype = eolian_type_c_type_get(rettypet);
232
233    eina_strbuf_replace_all(fbody, "@#params", eina_strbuf_string_get(fparam));
234    eina_strbuf_replace_all(fbody, "@#list_desc_param", eina_strbuf_string_get(descparam));
235    eina_strbuf_reset(fparam);
236    eina_strbuf_append_printf(fparam, "%s%s%s",
237          ret_const ? "const " : "",
238          rettype ? rettype : "void",
239          rettype && strchr(rettype, '*')?"":" ");
240    eina_strbuf_replace_all(fbody, "@#type_return", eina_strbuf_string_get(fparam));
241    if (eolian_function_return_is_warn_unused(funcid, ftype))
242      {
243         Eina_Bool no_nonull = !flags;
244         if (no_nonull) flags = eina_strbuf_new();
245         eina_strbuf_prepend(flags, " EINA_WARN_UNUSED_RESULT");
246      }
247    if (flags)
248       eina_strbuf_replace_all(fbody, "@#flags", eina_strbuf_string_get(flags));
249    eina_strbuf_replace_all(fbody, "@#flags", (eolian_function_return_is_warn_unused(funcid, ftype)) ? " EINA_WARN_UNUSED_RESULT" : "");
250    eina_strbuf_append(buf, eina_strbuf_string_get(fbody));
251
252    if (rettype) eina_stringshare_del(rettype);
253
254 end:
255    eina_strbuf_free(flags);
256    eina_strbuf_free(fbody);
257    eina_strbuf_free(fparam);
258    eina_strbuf_free(descparam);
259 }
260
261 static void
262 _eapi_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, Eolian_Function_Type ftype, Eina_Strbuf *buf)
263 {
264    _eolian_class_func_vars func_env;
265    char tmpstr[0xFF];
266    Eina_Bool var_as_ret = EINA_FALSE;
267    const Eolian_Type *rettypet = NULL;
268    const char *rettype = NULL;
269    const char *retname = NULL;
270    Eina_Bool ret_const = EINA_FALSE;
271    Eina_Bool add_star = EINA_FALSE;
272    Eina_Bool ret_is_void = EINA_FALSE;
273
274    Eina_Strbuf *fbody = eina_strbuf_new();
275    Eina_Strbuf *fparam = eina_strbuf_new();
276    Eina_Strbuf *eoparam = eina_strbuf_new();
277
278    Eina_Iterator *itr;
279    void *data, *data2;
280
281    _class_func_env_create(class, eolian_function_name_get(funcid), ftype, &func_env);
282    rettypet = eolian_function_return_type_get(funcid, ftype);
283    if (rettypet) rettype = eolian_type_c_type_get(rettypet);
284    if (rettype && !strcmp(rettype, "void")) ret_is_void = EINA_TRUE;
285    retname = "ret";
286    if (ftype == EOLIAN_PROP_GET)
287      {
288         add_star = EINA_TRUE;
289         if (!rettypet)
290           {
291              itr = eolian_function_parameters_get(funcid);
292              /* We want to check if there is only one parameter */
293              if (eina_iterator_next(itr, &data) && !eina_iterator_next(itr, &data2))
294                {
295                   Eolian_Function_Parameter *param = data;
296                   rettypet = eolian_parameter_type_get(param);
297                   retname = eolian_parameter_name_get(param);
298                   var_as_ret = EINA_TRUE;
299                   ret_const = eolian_parameter_const_attribute_get(data, EINA_TRUE);
300                }
301              eina_iterator_free(itr);
302           }
303      }
304
305    if (func_env.legacy_func[0] == '\0') goto end;
306
307    if (!rettype && rettypet) rettype = eolian_type_c_type_get(rettypet);
308
309    if (rettype && (!ret_is_void))
310      eina_strbuf_append(fbody, tmpl_eapi_body);
311    else
312      eina_strbuf_append(fbody, tmpl_eapi_body_void);
313
314    if (!eolian_function_is_class(funcid))
315      {
316         if (ftype == EOLIAN_PROP_GET || eolian_function_object_is_const(funcid))
317            eina_strbuf_append(fparam, "const ");
318         eina_strbuf_append_printf(fparam, "%s *obj", class_env.full_classname);
319         char cbuf[256];
320         snprintf(cbuf, sizeof(cbuf), "(%s *)obj", class_env.full_classname);
321         eina_strbuf_replace_all(fbody, "@#eo_obj", cbuf);
322      }
323    else
324      {
325         Eina_Strbuf *class_buf = eina_strbuf_new();
326         _template_fill(class_buf, "@#CLASS_@#CLASSTYPE", class, NULL, NULL, EINA_TRUE);
327         eina_strbuf_replace_all(fbody, "@#eo_obj", eina_strbuf_string_get(class_buf));
328         eina_strbuf_free(class_buf);
329      }
330    eina_strbuf_replace_all(fbody, "@#eapi_func", func_env.legacy_func);
331    eina_strbuf_replace_all(fbody, "@#eo_func", func_env.lower_eo_func);
332
333    tmpstr[0] = '\0';
334
335    itr = eolian_property_keys_get(funcid);
336    EINA_ITERATOR_FOREACH(itr, data)
337      {
338         Eolian_Function_Parameter *param = data;
339         const Eolian_Type *ptypet = eolian_parameter_type_get(param);
340         const char *pname = eolian_parameter_name_get(param);
341         const char *ptype = eolian_type_c_type_get(ptypet);
342         if (eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, ", ");
343         eina_strbuf_append_printf(fparam, "%s%s %s",
344               eolian_parameter_const_attribute_get(data, ftype == EOLIAN_PROP_GET)?"const ":"",
345               ptype, pname);
346         eina_stringshare_del(ptype);
347         if (eina_strbuf_length_get(eoparam)) eina_strbuf_append(eoparam, ", ");
348         eina_strbuf_append_printf(eoparam, "%s", pname);
349      }
350    eina_iterator_free(itr);
351    if (!var_as_ret)
352    {
353       itr = eolian_function_parameters_get(funcid);
354       EINA_ITERATOR_FOREACH(itr, data)
355         {
356             Eolian_Function_Parameter *param = data;
357             const Eolian_Type *ptypet = eolian_parameter_type_get(param);
358             const char *pname = eolian_parameter_name_get(param);
359             const char *ptype = eolian_type_c_type_get(ptypet);
360             Eolian_Parameter_Dir pdir = eolian_parameter_direction_get(param);
361             Eina_Bool had_star = !!strchr(ptype, '*');
362             if (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) add_star = (pdir == EOLIAN_OUT_PARAM || pdir == EOLIAN_INOUT_PARAM);
363             if (eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, ", ");
364             eina_strbuf_append_printf(fparam, "%s%s%s%s%s",
365                   eolian_parameter_const_attribute_get(data, ftype == EOLIAN_PROP_GET)?"const ":"",
366                   ptype, had_star?"":" ", add_star?"*":"", pname);
367             eina_stringshare_del(ptype);
368             if (eina_strbuf_length_get(eoparam)) eina_strbuf_append(eoparam, ", ");
369             eina_strbuf_append_printf(eoparam, "%s", pname);
370         }
371       eina_iterator_free(itr);
372    }
373    if (!eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, "void");
374
375    if (rettype && (!ret_is_void))
376      {
377         char tmp_ret_str[0xFF];
378         sprintf (tmp_ret_str, "%s%s", ret_const?"const ":"", rettype);
379              const Eolian_Expression *default_ret_val =
380                 eolian_function_return_default_value_get(funcid, ftype);
381              const char *val_str = NULL;
382              if (default_ret_val)
383                {
384                   Eolian_Value val = eolian_expression_eval_type
385                     (default_ret_val, rettypet);
386                   if (val.type)
387                     val_str = eolian_expression_value_to_literal(&val);
388                }
389              Eina_Bool had_star = !!strchr(rettype, '*');
390              sprintf (tmpstr, "   %s%s%s%s = %s;\n",
391                    ret_const?"const ":"", rettype, had_star?"":" ", retname,
392                    val_str?val_str:"0");
393
394              eina_strbuf_replace_all(fbody, "@#ret_type", tmp_ret_str);
395              eina_strbuf_replace_all(fbody, "@#ret_init_val", tmpstr);
396      }
397
398    eina_strbuf_replace_all(fbody, "@#full_params", eina_strbuf_string_get(fparam));
399    eina_strbuf_replace_all(fbody, "@#eo_params", eina_strbuf_string_get(eoparam));
400
401    eina_strbuf_replace_all(fbody, "@#ret_val", (rettype && !ret_is_void) ? retname : "");
402
403    eina_strbuf_append(buf, eina_strbuf_string_get(fbody));
404
405    if (rettype) eina_stringshare_del(rettype);
406
407 end:
408    eina_strbuf_free(fbody);
409    eina_strbuf_free(fparam);
410    eina_strbuf_free(eoparam);
411 }
412
413 Eina_Bool
414 legacy_header_generate(const Eolian_Class *class, Eina_Strbuf *buf)
415 {
416    _class_env_create(class, NULL, &class_env);
417
418    const char *desc = eolian_class_description_get(class);
419    if (desc)
420      {
421         Eina_Strbuf *linedesc = eina_strbuf_new();
422         eina_strbuf_append(linedesc, "/**\n");
423         eina_strbuf_append(linedesc, desc);
424         eina_strbuf_replace_all(linedesc, "\n", "\n * ");
425         eina_strbuf_append(linedesc, "\n */\n");
426         eina_strbuf_replace_all(linedesc, " * \n", " *\n"); /* Remove trailing whitespaces */
427         eina_strbuf_append(buf, eina_strbuf_string_get(linedesc));
428         eina_strbuf_free(linedesc);
429      }
430
431    Eina_Iterator *itr = eolian_class_implements_get(class);
432    if (itr)
433      {
434         const Eolian_Implement *impl;
435         EINA_ITERATOR_FOREACH(itr, impl)
436           {
437              if (eolian_implement_class_get(impl) != class)
438                continue;
439              Eolian_Function_Type ftype = EOLIAN_UNRESOLVED;
440              const Eolian_Function *fid = eolian_implement_function_get(impl, &ftype);
441              switch (ftype)
442                {
443                 case EOLIAN_PROP_GET: case EOLIAN_PROP_SET:
444                   _eapi_decl_func_generate(class, fid, ftype, buf);
445                   break;
446                 case EOLIAN_PROPERTY:
447                   _eapi_decl_func_generate(class, fid, EOLIAN_PROP_SET, buf);
448                   _eapi_decl_func_generate(class, fid, EOLIAN_PROP_GET, buf);
449                   break;
450                 default:
451                   _eapi_decl_func_generate(class, fid, EOLIAN_METHOD, buf);
452                   break;
453                }
454           }
455         eina_iterator_free(itr);
456      }
457    return EINA_TRUE;
458 }
459
460 Eina_Bool
461 legacy_source_generate(const Eolian_Class *class, Eina_Strbuf *buf)
462 {
463    Eina_Bool ret = EINA_FALSE;
464    Eina_Iterator *itr;
465
466    _class_env_create(class, NULL, &class_env);
467
468    Eina_Strbuf *tmpbuf = eina_strbuf_new();
469    Eina_Strbuf *str_bodyf = eina_strbuf_new();
470
471    if ((itr = eolian_class_implements_get(class)))
472      {
473         const Eolian_Implement *impl;
474         EINA_ITERATOR_FOREACH(itr, impl)
475           {
476              if (eolian_implement_class_get(impl) != class)
477                continue;
478              Eolian_Function_Type ftype = EOLIAN_UNRESOLVED;
479              const Eolian_Function *fid = eolian_implement_function_get(impl, &ftype);
480              switch (ftype)
481                {
482                 case EOLIAN_PROP_GET: case EOLIAN_PROP_SET:
483                   _eapi_func_generate(class, fid, ftype, str_bodyf);
484                   break;
485                 case EOLIAN_PROPERTY:
486                   _eapi_func_generate(class, fid, EOLIAN_PROP_SET, str_bodyf);
487                   _eapi_func_generate(class, fid, EOLIAN_PROP_GET, str_bodyf);
488                   break;
489                 default:
490                   _eapi_func_generate(class, fid, EOLIAN_METHOD, str_bodyf);
491                   break;
492                }
493           }
494         eina_iterator_free(itr);
495      }
496
497    eina_strbuf_append(buf, eina_strbuf_string_get(str_bodyf));
498
499    ret = EINA_TRUE;
500    eina_strbuf_free(tmpbuf);
501    eina_strbuf_free(str_bodyf);
502
503    return ret;
504 }