Eolian/Generator: add support for implementation source file.
authorDaniel Zaoui <daniel.zaoui@samsung.com>
Thu, 1 May 2014 12:07:26 +0000 (15:07 +0300)
committerDaniel Zaoui <daniel.zaoui@samsung.com>
Mon, 26 May 2014 10:56:06 +0000 (13:56 +0300)
By using -gi option, the generator appends the functions that are
present into the given eo file and missing into the developer file
(given via -o option as an in/out file).

@feature

src/Makefile_Eolian.am
src/bin/eolian/impl_generator.c [new file with mode: 0644]
src/bin/eolian/impl_generator.h [new file with mode: 0644]
src/bin/eolian/main.c
src/tests/eolian/data/base.eo
src/tests/eolian/data/object.eo [new file with mode: 0644]

index db8ebc9..e311111 100644 (file)
@@ -30,6 +30,8 @@ bin_eolian_eolian_gen_SOURCES = \
                 bin/eolian/common_funcs.h \
                 bin/eolian/eo1_generator.c \
                 bin/eolian/eo1_generator.h \
+                bin/eolian/impl_generator.c \
+                bin/eolian/impl_generator.h \
                 bin/eolian/legacy_generator.c \
                 bin/eolian/legacy_generator.h \
                 bin/eolian/main.c
diff --git a/src/bin/eolian/impl_generator.c b/src/bin/eolian/impl_generator.c
new file mode 100644 (file)
index 0000000..b2abf0e
--- /dev/null
@@ -0,0 +1,281 @@
+#include <Eina.h>
+#include <string.h>
+
+#include "Eolian.h"
+#include "impl_generator.h"
+#include "common_funcs.h"
+
+static Eina_Bool
+_params_generate(Eolian_Function foo, Eolian_Function_Type ftype, Eina_Bool var_as_ret, Eina_Strbuf *params)
+{
+   const Eina_List *itr;
+   Eolian_Function_Parameter param;
+   eina_strbuf_reset(params);
+   EINA_LIST_FOREACH(eolian_property_keys_list_get(foo), itr, param)
+     {
+        const char *pname;
+        const char *ptype;
+        eolian_parameter_information_get(param, NULL, &ptype, &pname, NULL);
+        Eina_Bool had_star = !!strchr(ptype, '*');
+        Eina_Bool is_const = eolian_parameter_const_attribute_get(param, ftype == EOLIAN_PROP_GET);
+        if (eina_strbuf_length_get(params)) eina_strbuf_append(params, ", ");
+        eina_strbuf_append_printf(params, "%s%s%s%s",
+              is_const?"const ":"", ptype,
+              had_star?"":" ",
+              pname);
+     }
+   if (!var_as_ret)
+     {
+        Eina_Bool add_star = (ftype == EOLIAN_PROP_GET);
+        EINA_LIST_FOREACH(eolian_parameters_list_get(foo), itr, param)
+          {
+             const char *pname;
+             const char *ptype;
+             Eolian_Parameter_Dir pdir;
+             eolian_parameter_information_get(param, &pdir, &ptype, &pname, NULL);
+             Eina_Bool is_const = eolian_parameter_const_attribute_get(param, ftype == EOLIAN_PROP_GET);
+             Eina_Bool had_star = !!strchr(ptype, '*');
+             if (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) add_star = (pdir == EOLIAN_OUT_PARAM);
+             if (eina_strbuf_length_get(params)) eina_strbuf_append(params, ", ");
+             eina_strbuf_append_printf(params, "%s%s%s%s%s",
+                   is_const?"const ":"",
+                   ptype, had_star?"":" ", add_star?"*":"", pname);
+          }
+     }
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_function_exists(const char* func_name, Eina_Strbuf *buffer)
+{
+   const char *ptr = eina_strbuf_string_get(buffer);
+   int func_len = strlen(func_name);
+   while ((ptr = strstr(ptr, func_name)) != NULL)
+     {
+        switch (*(ptr - 1))
+          {
+           case '\n': case ' ':
+                {
+                   switch (*(ptr + func_len))
+                     {
+                      case ' ': case '(':
+                         return EINA_TRUE;
+                     }
+                }
+           default:
+              ptr++; /* so strstr doesn't fall again on func_name */
+          }
+     }
+   return EINA_FALSE;
+}
+
+/* Check if the type is used in the file, not if it is a typedef... */
+static Eina_Bool
+_type_exists(const char* type_name, Eina_Strbuf *buffer)
+{
+   const char *ptr = eina_strbuf_string_get(buffer);
+   int type_len = strlen(type_name);
+   while ((ptr = strstr(ptr, type_name)) != NULL)
+     {
+        switch (*(ptr - 1))
+          {
+           case '\n': case ' ': case ',':
+                {
+                   switch (*(ptr + type_len))
+                     {
+                      case '\n': case ' ': case ',': case ';':
+                         return EINA_TRUE;
+                     }
+                }
+           default:
+              ptr++; /* so strstr doesn't fall again on type_name */
+          }
+     }
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_prototype_generate(Eolian_Function foo, Eolian_Function_Type ftype, Eina_Strbuf *data_type_buf, char *impl_name, Eina_Strbuf *buffer)
+{
+   Eina_Bool var_as_ret = EINA_FALSE, ret_const = EINA_FALSE;
+   Eina_Strbuf *params = NULL;
+   char func_name[100];
+
+   if (!impl_name && eolian_function_is_virtual_pure(foo, ftype)) return EINA_TRUE;
+
+   sprintf(func_name, "_%s_%s%s",
+         impl_name?impl_name:lowclass, eolian_function_name_get(foo),
+         ftype == EOLIAN_PROP_GET?"_get": (ftype == EOLIAN_PROP_SET?"_set":""));
+
+   if (_function_exists(func_name, buffer)) return EINA_TRUE;
+
+   printf("Generation of function %s\n", func_name);
+   const char *rettype = eolian_function_return_type_get(foo, ftype);
+   if (ftype == EOLIAN_PROP_GET && !rettype)
+     {
+        const Eina_List *l = eolian_parameters_list_get(foo);
+        if (eina_list_count(l) == 1)
+          {
+             Eolian_Function_Parameter param = eina_list_data_get(l);
+             eolian_parameter_information_get(param, NULL, &rettype, NULL, NULL);
+             var_as_ret = EINA_TRUE;
+             ret_const = eolian_parameter_const_attribute_get(param, EINA_TRUE);
+          }
+     }
+
+   params = eina_strbuf_new();
+   _params_generate(foo, ftype, var_as_ret, params);
+   if (eina_strbuf_length_get(params))
+      eina_strbuf_prepend_printf(params, ", ");
+
+   eina_strbuf_append_printf(buffer,
+         "EOLIAN static %s%s\n%s(%sEo *obj, %s *pd%s%s)\n{\n\n}\n\n",
+         ret_const?"const ":"", !rettype?"void":rettype,
+         func_name,
+         eolian_function_object_is_const(foo)?"const ":"",
+         !eina_strbuf_length_get(data_type_buf) ? "void" : eina_strbuf_string_get(data_type_buf),
+         !eina_strbuf_length_get(data_type_buf) ? " EINA_UNUSED" : "",
+         eina_strbuf_string_get(params)
+         );
+
+   eina_strbuf_free(params);
+   return EINA_TRUE;
+}
+
+Eina_Bool
+impl_source_generate(const char *class_name, Eina_Strbuf *buffer)
+{
+   Eina_Bool ret = EINA_FALSE;
+   Eina_Strbuf *data_type_buf = eina_strbuf_new();
+   const Eina_List *itr_funcs;
+   Eolian_Function foo;
+   Eina_Strbuf *begin = eina_strbuf_new();
+
+   _class_func_names_fill(class_name, NULL);
+
+   if (!_type_exists("EFL_BETA_API_SUPPORT", buffer))
+     {
+        printf("Generation of EFL_BETA_API_SUPPORT\n");
+        eina_strbuf_append_printf(begin, "#define EFL_BETA_API_SUPPORT\n");
+     }
+
+   if (!_type_exists("<Eo.h>", buffer))
+     {
+        printf("Generation of #include <Eo.h> and \"%s.eo.h\"\n", lowclass);
+        eina_strbuf_append_printf(begin, "#include <Eo.h>\n#include \"%s.eo.h\"\n\n", lowclass);
+     }
+
+   /* Little calculation of the prefix of the data */
+   const char *data_type = eolian_class_data_type_get(class_name);
+   if (data_type)
+     {
+        if (strcmp(data_type, "null"))
+           eina_strbuf_append_printf(data_type_buf, "%s", data_type);
+     }
+   else
+      eina_strbuf_append_printf(data_type_buf, "%s_Data", class_name);
+
+   /* Definition of the structure */
+   const char *data_type_str = eina_strbuf_string_get(data_type_buf);
+   if (!_type_exists(data_type_str, buffer) && 0 != eina_strbuf_length_get(data_type_buf))
+     {
+        printf("Generation of type %s\n", data_type_str);
+        eina_strbuf_append_printf(begin, "typedef struct\n{\n\n} %s;\n\n", data_type_str);
+     }
+
+   if (eina_strbuf_length_get(begin))
+      eina_strbuf_prepend_printf(buffer, "%s", eina_strbuf_string_get(begin));
+   eina_strbuf_free(begin);
+
+   /* Properties */
+   EINA_LIST_FOREACH(eolian_class_functions_list_get(class_name, EOLIAN_PROPERTY), itr_funcs, foo)
+     {
+        const Eolian_Function_Type ftype = eolian_function_type_get(foo);
+        if (ftype == EOLIAN_PROP_SET || ftype == EOLIAN_PROPERTY)
+           _prototype_generate(foo, EOLIAN_PROP_SET, data_type_buf, NULL, buffer);
+
+        if (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROPERTY)
+           _prototype_generate(foo, EOLIAN_PROP_GET, data_type_buf, NULL, buffer);
+     }
+
+   /* Methods */
+   EINA_LIST_FOREACH(eolian_class_functions_list_get(class_name, EOLIAN_METHOD), itr_funcs, foo)
+     {
+        _prototype_generate(foo, EOLIAN_METHOD, data_type_buf, NULL, buffer);
+     }
+
+   /* Custom constructors */
+   EINA_LIST_FOREACH(eolian_class_functions_list_get(class_name, EOLIAN_CTOR), itr_funcs, foo)
+     {
+        _prototype_generate(foo, EOLIAN_CTOR, data_type_buf, NULL, buffer);
+     }
+
+   if (eolian_class_implements_list_get(class_name))
+     {
+        Eolian_Implement impl_desc;
+        EINA_LIST_FOREACH(eolian_class_implements_list_get(class_name), itr_funcs, impl_desc)
+          {
+             const char *func_name;
+             const char *impl_class;
+             Eolian_Function_Type ftype;
+
+             eolian_implement_information_get(impl_desc, &impl_class, &func_name, &ftype);
+
+             _class_func_names_fill(impl_class, NULL);
+
+             char implname[0xFF];
+             char *tmp = implname;
+             sprintf(implname, "%s_%s", class_name, impl_class);
+             eina_str_tolower(&tmp);
+
+             foo = eolian_class_function_find_by_name(impl_class, func_name, ftype);
+             if (!foo)
+               {
+                  ERR ("Failed to generate implementation of %s:%s - missing form super class", impl_class, func_name);
+                  goto end;
+               }
+
+             switch (ftype)
+               {
+                case EOLIAN_PROP_SET: case EOLIAN_PROP_GET:
+                   _prototype_generate(foo, ftype, data_type_buf, implname, buffer);
+                   break;
+                default:
+                   _prototype_generate(foo, eolian_function_type_get(foo), data_type_buf, implname, buffer);
+                   break;
+               }
+          }
+     }
+
+   _class_func_names_fill(class_name, NULL);
+   if (eolian_class_ctor_enable_get(class_name))
+     {
+        char func_name[100];
+        sprintf(func_name, "_%s_class_constructor", lowclass);
+        if (!_function_exists(func_name, buffer))
+          {
+             printf("Generation of function %s\n", func_name);
+             eina_strbuf_append_printf(buffer,
+                   "EOLIAN static void\n_%s_class_constructor(Eo_Class *klass)\n{\n\n}\n\n",
+                   lowclass);
+          }
+     }
+
+   if (eolian_class_dtor_enable_get(class_name))
+     {
+        char func_name[100];
+        sprintf(func_name, "_%s_class_destructor", lowclass);
+        if (!_function_exists(func_name, buffer))
+          {
+             printf("Generation of function %s\n", func_name);
+             eina_strbuf_append_printf(buffer, "EOLIAN static void\n_%s_class_destructor(Eo_Class *klass)\n{\n\n}\n\n",
+                   lowclass);
+          }
+     }
+
+   ret = EINA_TRUE;
+end:
+   eina_strbuf_free(data_type_buf);
+   return ret;
+}
+
diff --git a/src/bin/eolian/impl_generator.h b/src/bin/eolian/impl_generator.h
new file mode 100644 (file)
index 0000000..b6793d7
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef IMPL_GENERATOR_H
+#define IMPL_GENERATOR_H
+
+#include<Eina.h>
+
+/*
+ * @brief Generate the implementation source code of a class
+ *
+ * This function generates all the source code of a class.
+ *
+ * @param[in] classname class name
+ * @param[inout] buf buffer to fill
+ *
+ * @return EINA_TRUE on success, EINA_FALSE on error.
+ *
+ */
+Eina_Bool
+impl_source_generate(const char *classname, Eina_Strbuf *buf);
+
+#endif
+
+
index 91e44dd..576d18c 100644 (file)
@@ -5,6 +5,7 @@
 #include "Eolian.h"
 #include "legacy_generator.h"
 #include "eo1_generator.h"
+#include "impl_generator.h"
 #include "common_funcs.h"
 
 static char*
@@ -118,6 +119,59 @@ end:
    return ret;
 }
 
+static Eina_Bool
+_generate_impl_c_file(char *filename, const char *classname)
+{
+   Eina_Bool ret = EINA_FALSE;
+   long file_size = 0;
+
+   FILE* fd = fopen(filename, "rb");
+   if (!fd)
+     {
+        ERR("Couldnt open file %s for reading", filename);
+        goto end;
+     }
+
+   fseek(fd, 0, SEEK_END);
+   file_size = ftell(fd);
+   fseek(fd, 0, SEEK_SET);
+   char *content = malloc(file_size + 1);
+   fread(content, file_size, 1, fd);
+   content[file_size] = '\0';
+   fclose(fd);
+
+   if (!content)
+     {
+        ERR("Couldnt read file %s", filename);
+        goto end;
+     }
+
+   Eina_Strbuf *buffer = eina_strbuf_manage_new(content);
+
+   if (!impl_source_generate(classname, buffer))
+     {
+        ERR("Failed to generate source for %s", classname);
+        goto end;
+     }
+
+   fd = fopen(filename, "wb");
+   if (!fd)
+     {
+        ERR("Couldnt open file %s for writing", filename);
+        goto end;
+     }
+
+   const char *text = eina_strbuf_string_get(buffer);
+   if (text) fputs(text, fd);
+
+   fclose(fd);
+
+   ret = EINA_TRUE;
+end:
+   eina_strbuf_free(buffer);
+   return ret;
+}
+
 // TODO join with header gen.
 static Eina_Bool
 _generate_legacy_header_file(char *filename, const char *classname)
@@ -160,7 +214,8 @@ enum
 {
    NO_WAY_GEN,
    H_GEN,
-   C_GEN
+   C_GEN,
+   C_IMPL_GEN
 };
 static int gen_opt = NO_WAY_GEN;
 static int eo_needed = 0;
@@ -198,6 +253,7 @@ int main(int argc, char **argv)
           {"help",       no_argument,         0, 'h'},
           {"gh",         no_argument,         &gen_opt, H_GEN},
           {"gc",         no_argument,         &gen_opt, C_GEN},
+          {"gi",         no_argument,         &gen_opt, C_IMPL_GEN},
           {"output",     required_argument,   0, 'o'},
           {"legacy",     no_argument,         (int *)&legacy_support, EINA_TRUE},
           {"include",    required_argument,   0, 'I'},
@@ -233,15 +289,14 @@ int main(int argc, char **argv)
 
    if (help)
      {
-        printf("Usage: %s [-h/--help] [-v/--verbose] [-I/--include input_dir] [--legacy] [--gh|--gc|--ah] [--output/-o outfile] file.eo ... \n", argv[0]);
+        printf("Usage: %s [-h/--help] [-v/--verbose] [-I/--include input_dir] [--legacy] [--gh|--gc|--gi] [--output/-o outfile] file.eo ... \n", argv[0]);
         printf("       --help/-h Print that help\n");
         printf("       --include/-I Include 'input_dir' as directory to search .eo files into\n");
         printf("       --output/-o Force output filename to 'outfile'\n");
         printf("       --eo Set generator to eo mode. Must be specified\n");
-        printf("       --gh Generate c header file [.h]\n");
-        printf("       --gc Generate c source file [.c]\n");
-        printf("       --ah Append eo class definitions to an existing c header file [.h]\n");
-        printf("       --al Append legacy function definitions to an existing c header file [.h]\n");
+        printf("       --gh Generate C header file [.h]\n");
+        printf("       --gc Generate C source file [.c]\n");
+        printf("       --gi Generate C implementation source file [.c]. The output will be a series of functions that have to be filled.\n");
         printf("       --legacy Generate legacy\n");
         ret = 0;
         goto end;
@@ -284,10 +339,8 @@ int main(int argc, char **argv)
      {
         if (!output_filename)
           {
-             output_filename = malloc(strlen(eina_list_data_get(files4gen)) + 5);
-             strcpy(output_filename, eina_list_data_get(files4gen));
-             if (C_GEN == gen_opt) strcat(output_filename, ".c");
-             else strcat(output_filename, ".h");
+             ERR("You must use -o argument for files generation.");
+             goto end;
           }
         switch (gen_opt)
           {
@@ -306,6 +359,12 @@ int main(int argc, char **argv)
                    ret = _generate_c_file(output_filename, classname, legacy_support)?0:1;
                    break;
                 }
+           case C_IMPL_GEN:
+                {
+                   INF("Generating user source file %s\n", output_filename);
+                   ret = _generate_impl_c_file(output_filename, classname) ? 0 : 1;
+                   break;
+                }
            default:
               ERR("Bad generation option\n");
               break;
index e8132b8..a252140 100644 (file)
@@ -5,4 +5,7 @@ class Base {
       destructor {
       }
    }
+   implements {
+      virtual::constructor;
+   }
 }
diff --git a/src/tests/eolian/data/object.eo b/src/tests/eolian/data/object.eo
new file mode 100644 (file)
index 0000000..d250c85
--- /dev/null
@@ -0,0 +1,68 @@
+class Object (Base) {
+   constructors {
+      constructor_1 {
+         params {
+            @in int a;
+            @in char b;
+         }
+      }
+      constructor_2 {
+      }
+   }
+   properties {
+      a {
+         set {
+            return Eina_Bool(EINA_FALSE);
+            value: const;
+         }
+         get {
+         }
+         keys {
+            const char *part;
+         }
+         values {
+            @own Eina_List *<int> value;
+         }
+      }
+      b {
+         set {
+         }
+         get {
+            /* set as virtual pure - no implementation expected */
+         }
+         values {
+            @own Eina_List *<int> value;
+         }
+      }
+   }
+   methods {
+      foo1 {
+         /*@ comment foo */
+         params {
+            @in int a; /*@ a */
+            @inout char *b;
+            @out double c;
+         }
+         return char *(NULL); /*@ comment for method return */
+      }
+      foo2 {
+         /*@ comment foo */
+         params {
+            @in int a;
+            @in const char *b;
+         }
+         const;
+      }
+      pure_foo3 {
+         /* set as virtual pure - no implementation expected */
+      }
+   }
+   implements {
+      class::constructor;
+      class::destructor;
+      Base::constructor;
+      Base::destructor;
+      virtual::pure_foo3;
+      virtual::b::get;
+   }
+}