Eolian/Generator: add support for implementation source file.

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
This commit is contained in:
Daniel Zaoui 2014-05-01 15:07:26 +03:00
parent 8d18e2db3c
commit a541aecf76
6 changed files with 445 additions and 10 deletions

View 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

View File

@ -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;
}

View File

@ -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

View 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;

View File

@ -5,4 +5,7 @@ class Base {
destructor {
}
}
implements {
virtual::constructor;
}
}

View File

@ -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;
}
}