From 56bad2beb0e9c5606987eb91a1a6f4f71d3052a2 Mon Sep 17 00:00:00 2001 From: Daniel Zaoui Date: Thu, 4 Sep 2014 13:22:31 +0300 Subject: [PATCH] Eolian/Generator: support @empty and @auto. Local and base class functions are supported. When @empty is provided, dummy functions (initializing the parameters with default values if needed) are generated. When @auto is provided on properties, access to internal data variables is done. On set, it will assign parameters values to private data members. On get, parameters are set with private data members values. See the supplied tests as examples. @feature --- src/Makefile_Eolian.am | 3 +- src/bin/eolian/eo_generator.c | 158 +++++++++++++++++++++---------- src/tests/eolian/data/base.eo | 9 ++ src/tests/eolian/data/class_simple_ref.c | 5 +- src/tests/eolian/data/override.eo | 28 ++++++ src/tests/eolian/data/override_ref.c | 82 ++++++++++++++++ src/tests/eolian/eolian_generation.c | 17 ++++ 7 files changed, 249 insertions(+), 53 deletions(-) create mode 100644 src/tests/eolian/data/override_ref.c diff --git a/src/Makefile_Eolian.am b/src/Makefile_Eolian.am index 5df0ebf..128d32d 100644 --- a/src/Makefile_Eolian.am +++ b/src/Makefile_Eolian.am @@ -117,5 +117,6 @@ tests/eolian/data/enum.eo \ tests/eolian/data/free_func.eo \ tests/eolian/data/typedef_ref.c \ tests/eolian/data/struct_ref.c \ -tests/eolian/data/class_simple_ref.c +tests/eolian/data/class_simple_ref.c \ +tests/eolian/data/override_ref.c diff --git a/src/bin/eolian/eo_generator.c b/src/bin/eolian/eo_generator.c index 0a292f0..56e40ab 100644 --- a/src/bin/eolian/eo_generator.c +++ b/src/bin/eolian/eo_generator.c @@ -339,7 +339,7 @@ eo_header_generate(const Eolian_Class *class, Eina_Strbuf *buf) } static Eina_Bool -eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, Eolian_Function_Type ftype, Eina_Strbuf *buf, _eolian_class_vars *impl_env) +eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, Eolian_Function_Type ftype, Eina_Strbuf *buf, Eolian_Implement *impl, _eolian_class_vars *impl_env) { _eolian_class_func_vars func_env; const char *suffix = ""; @@ -351,6 +351,9 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, Eina_Iterator *itr; void *data, *data2; const Eolian_Expression *default_ret_val = NULL; + Eina_Bool is_empty = impl ? eolian_implement_is_empty(impl) : eolian_function_is_empty(funcid, ftype); + Eina_Bool is_auto = impl ? eolian_implement_is_auto(impl) : eolian_function_is_auto(funcid, ftype); + if (ftype != EOLIAN_PROP_GET && ftype != EOLIAN_PROP_SET) ftype = eolian_function_type_get(funcid); Eina_Bool need_implementation = EINA_TRUE; if (!impl_env && eolian_function_is_virtual_pure(funcid, ftype)) need_implementation = EINA_FALSE; @@ -363,7 +366,10 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, rettypet = eolian_function_return_type_get(funcid, ftype); if (rettypet) - default_ret_val = eolian_function_return_default_value_get(funcid, ftype); + { + is_auto = EINA_FALSE; /* We block auto when the function has to return something */ + default_ret_val = eolian_function_return_default_value_get(funcid, ftype); + } if (ftype == EOLIAN_PROP_GET) { suffix = "_get"; @@ -398,9 +404,9 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, Eina_Bool is_const = eolian_parameter_const_attribute_get(data, ftype == EOLIAN_PROP_GET); if (eina_strbuf_length_get(params)) eina_strbuf_append(params, ", "); eina_strbuf_append_printf(params, "%s", pname); - eina_strbuf_append_printf(full_params, ", %s%s %s", + eina_strbuf_append_printf(full_params, ", %s%s %s%s", is_const?"const ":"", - ptype, pname); + ptype, pname, is_empty || is_auto?" EINA_UNUSED":""); eina_stringshare_del(ptype); } eina_iterator_free(itr); @@ -410,6 +416,7 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, EINA_ITERATOR_FOREACH(itr, data) { Eolian_Function_Parameter *param = data; + const Eolian_Expression *dflt_value = eolian_parameter_default_value_get(param); const Eolian_Type *ptypet = eolian_parameter_type_get(param); const char *pname = eolian_parameter_name_get(param); const char *ptype = eolian_type_c_type_get(ptypet); @@ -419,30 +426,44 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, if (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) add_star = (pdir == EOLIAN_OUT_PARAM || pdir == EOLIAN_INOUT_PARAM); if (eina_strbuf_length_get(params)) eina_strbuf_append(params, ", "); eina_strbuf_append_printf(params, "%s", pname); - eina_strbuf_append_printf(full_params, ", %s%s%s%s%s", + eina_strbuf_append_printf(full_params, ", %s%s%s%s%s%s", is_const?"const ":"", - ptype, had_star?"":" ", add_star?"*":"", pname); - if (ftype != EOLIAN_PROP_SET) + ptype, had_star?"":" ", add_star?"*":"", pname, is_empty && !dflt_value ?" EINA_UNUSED":""); + if (is_auto) { - const Eolian_Expression *dflt_value = eolian_parameter_default_value_get(param); - if (dflt_value) + if (ftype == EOLIAN_PROP_SET) { - const char *val_str = NULL; - Eolian_Value val = eolian_expression_eval - (dflt_value, EOLIAN_MASK_ALL); - if (val.type) + eina_strbuf_append_printf(params_init, + " %s = pd->%s;\n", pname, pname); + } + else + { + eina_strbuf_append_printf(params_init, + " if (%s) *%s = pd->%s;\n", pname, pname, pname); + } + } + else { + if (ftype != EOLIAN_PROP_SET) + { + if (dflt_value) { - val_str = eolian_expression_value_to_literal(&val); - eina_strbuf_append_printf(params_init, - " if (%s) *%s = %s;", - pname, pname, val_str); - if (eolian_expression_type_get(dflt_value) == EOLIAN_EXPR_ENUM) + const char *val_str = NULL; + Eolian_Value val = eolian_expression_eval + (dflt_value, EOLIAN_MASK_ALL); + if (val.type) { - Eina_Stringshare *string = eolian_expression_serialize(dflt_value); - eina_strbuf_append_printf(params_init, " /* %s */", string); - eina_stringshare_del(string); + val_str = eolian_expression_value_to_literal(&val); + eina_strbuf_append_printf(params_init, + " if (%s) *%s = %s;", + pname, pname, val_str); + if (eolian_expression_type_get(dflt_value) == EOLIAN_EXPR_ENUM) + { + Eina_Stringshare *string = eolian_expression_serialize(dflt_value); + eina_strbuf_append_printf(params_init, " /* %s */", string); + eina_stringshare_del(string); + } + eina_strbuf_append_printf(params_init, "\n"); } - eina_strbuf_append_printf(params_init, "\n"); } } } @@ -457,25 +478,59 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, { Eina_Strbuf *ret_param = eina_strbuf_new(); eina_strbuf_append_printf(fbody, "\n"); - eina_strbuf_append_printf(fbody, "%s%s _%s%s%s_%s%s(Eo *obj, @#Datatype_Data *pd@#full_params);\n\n", - ret_const?"const ":"", rettype?rettype:"void", - class_env.lower_classname, - impl_env?"_":"", - impl_env?impl_env->lower_classname:"", - eolian_function_name_get(funcid), suffix); + /* Generation of the user function prototype declaration - not needed when @auto and @empty are indicated */ + if (!is_empty && !is_auto) + { + eina_strbuf_append_printf(fbody, "%s%s _%s%s%s_%s%s(Eo *obj, @#Datatype_Data *pd%s);\n\n", + ret_const?"const ":"", rettype?rettype:"void", + class_env.lower_classname, + impl_env?"_":"", + impl_env?impl_env->lower_classname:"", + eolian_function_name_get(funcid), suffix, + eina_strbuf_string_get(full_params)); + } - if (eina_strbuf_length_get(params_init)) + if (is_empty || is_auto || eina_strbuf_length_get(params_init)) { + /* We need to give the internal function name to Eo. We use this hash table as indication */ eina_hash_add(_funcs_params_init, - eina_stringshare_add(eolian_function_name_get(funcid)), funcid); - eina_strbuf_append_printf(fbody, "static %s%s __eolian_%s%s%s_%s%s(Eo *obj, @#Datatype_Data *pd@#full_params)\n{\n%s\n", + eina_stringshare_add(eolian_function_name_get(funcid)), (void *)ftype); + /* Generation of the intermediate function __eolian_... */ + eina_strbuf_append_printf(fbody, "static %s%s __eolian_%s%s%s_%s%s(Eo *obj%s, @#Datatype_Data *pd%s%s)\n{\n", ret_const?"const ":"", rettype?rettype:"void", class_env.lower_classname, impl_env?"_":"", impl_env?impl_env->lower_classname:"", eolian_function_name_get(funcid), suffix, - eina_strbuf_string_get(params_init)); - eina_strbuf_append_printf(fbody, " %s_%s%s%s_%s%s(obj, pd, %s);\n}\n\n", + is_empty || is_auto?" EINA_UNUSED":"", + is_empty || (is_auto && !eina_strbuf_length_get(params_init))?" EINA_UNUSED":"", + eina_strbuf_string_get(full_params)); + } + if (eina_strbuf_length_get(params_init)) + { + eina_strbuf_append_printf(fbody, "%s", eina_strbuf_string_get(params_init)); + } + if (is_auto || is_empty) + { + if (rettype) + { + /* return for auto and empty */ + const char *val_str = NULL; + if (default_ret_val) + { + Eolian_Value val = eolian_expression_eval + (default_ret_val, EOLIAN_MASK_ALL); + if (val.type) + val_str = eolian_expression_value_to_literal(&val); + } + eina_strbuf_append_printf(fbody, " return %s;\n", val_str?val_str:"0"); + } + eina_strbuf_append_printf(fbody, "}\n\n"); + } + else if (eina_strbuf_length_get(params_init)) + { + /* Generation of the user function invocation, e.g return _user_foo(obj, pd, ...) */ + eina_strbuf_append_printf(fbody, " %s_%s%s%s_%s%s(obj, pd, %s);\n}\n\n", rettype?"return ":"", class_env.lower_classname, impl_env?"_":"", @@ -528,6 +583,7 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, } if (has_params) { + eina_strbuf_replace_all(full_params, " EINA_UNUSED", ""); eina_strbuf_append_printf(eo_func_decl, ", EO_FUNC_CALL(%s)%s", eina_strbuf_string_get(params), eina_strbuf_string_get(full_params)); @@ -540,7 +596,6 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, if (need_implementation) { Eina_Bool is_cf = eolian_function_is_class(funcid); - eina_strbuf_replace_all(fbody, "@#full_params", eina_strbuf_string_get(full_params)); const char *data_type = eolian_class_data_type_get(class); if (is_cf || (data_type && !strcmp(data_type, "null"))) eina_strbuf_replace_all(fbody, "@#Datatype_Data", "void"); @@ -585,9 +640,9 @@ eo_op_desc_generate(const Eolian_Class *class, const Eolian_Function *fid, Eolia eina_strbuf_append_printf(buf, "\n EO_OP_%sFUNC(%s, ", class_str, func_env.lower_eo_func); if (!is_virtual_pure) { + Eolian_Function_Type ftype2 = (Eolian_Function_Type) eina_hash_find(_funcs_params_init, funcname); eina_strbuf_append_printf(buf, "%s_%s_%s%s, \"%s\"),", - eina_hash_find(_funcs_params_init, funcname) - && ftype != EOLIAN_PROP_SET?"__eolian":"", + ftype == ftype2?"__eolian":"", class_env.lower_classname, funcname, suffix, desc); } else @@ -731,19 +786,24 @@ eo_source_end_generate(const Eolian_Class *class, Eina_Strbuf *buf) const Eolian_Function *fnid = NULL; const char *funcname = NULL; const char *rets; - char *tp = implname; const char *names[] = { "", "getter ", "setter " }; - if ((impl_class = eolian_implement_class_get(impl_desc))) + impl_class = eolian_implement_class_get(impl_desc); + + if (impl_class) { + char *tp = implname; if (impl_class == class) continue; fnid = eolian_implement_function_get(impl_desc, &ftype); _class_env_create(impl_class, NULL, &impl_env); funcname = eolian_function_name_get(fnid); - sprintf(implname, "%s_%s", class_env.full_classname, impl_env.full_classname); + sprintf(implname, "%s_%s_%s", + eolian_implement_is_auto(impl_desc) || eolian_implement_is_empty(impl_desc)? + "__eolian":"", + class_env.full_classname, impl_env.full_classname); eina_str_tolower(&tp); } @@ -766,22 +826,22 @@ eo_source_end_generate(const Eolian_Class *class, Eina_Strbuf *buf) case EOLIAN_PROP_SET: case EOLIAN_PROP_GET: case EOLIAN_PROPERTY: if (ftype != EOLIAN_PROP_GET) { - eina_strbuf_append_printf(str_op, "\n EO_OP_%sFUNC_OVERRIDE(%s_set, _%s_%s_set),", + eina_strbuf_append_printf(str_op, "\n EO_OP_%sFUNC_OVERRIDE(%s_set, %s_%s_set),", class_str, rets, implname, funcname); - eo_bind_func_generate(class, fnid, EOLIAN_PROP_SET, str_bodyf, &impl_env); + eo_bind_func_generate(class, fnid, EOLIAN_PROP_SET, str_bodyf, impl_desc, &impl_env); } if (ftype != EOLIAN_PROP_SET) { - eina_strbuf_append_printf(str_op, "\n EO_OP_%sFUNC_OVERRIDE(%s_get, _%s_%s_get),", + eina_strbuf_append_printf(str_op, "\n EO_OP_%sFUNC_OVERRIDE(%s_get, %s_%s_get),", class_str, rets, implname, funcname); - eo_bind_func_generate(class, fnid, EOLIAN_PROP_GET, str_bodyf, &impl_env); + eo_bind_func_generate(class, fnid, EOLIAN_PROP_GET, str_bodyf, impl_desc, &impl_env); } break; default: - eina_strbuf_append_printf(str_op, "\n EO_OP_%sFUNC_OVERRIDE(%s, _%s_%s),", + eina_strbuf_append_printf(str_op, "\n EO_OP_%sFUNC_OVERRIDE(%s, %s_%s),", class_str, rets, implname, funcname); - eo_bind_func_generate(class, fnid, ftype, str_bodyf, &impl_env); + eo_bind_func_generate(class, fnid, ftype, str_bodyf, impl_desc, &impl_env); break; } eina_stringshare_del(rets); @@ -929,17 +989,17 @@ eo_source_generate(const Eolian_Class *class, Eina_Strbuf *buf) switch (ftype) { case EOLIAN_PROP_GET: case EOLIAN_PROP_SET: - if (!eo_bind_func_generate(class, fid, ftype, str_bodyf, NULL)) + if (!eo_bind_func_generate(class, fid, ftype, str_bodyf, NULL, NULL)) goto end; break; case EOLIAN_PROPERTY: - if (!eo_bind_func_generate(class, fid, EOLIAN_PROP_SET, str_bodyf, NULL)) + if (!eo_bind_func_generate(class, fid, EOLIAN_PROP_SET, str_bodyf, NULL, NULL)) goto end; - if (!eo_bind_func_generate(class, fid, EOLIAN_PROP_GET, str_bodyf, NULL)) + if (!eo_bind_func_generate(class, fid, EOLIAN_PROP_GET, str_bodyf, NULL, NULL)) goto end; break; default: - if (!eo_bind_func_generate(class, fid, EOLIAN_UNRESOLVED, str_bodyf, NULL)) + if (!eo_bind_func_generate(class, fid, EOLIAN_UNRESOLVED, str_bodyf, NULL, NULL)) goto end; break; } diff --git a/src/tests/eolian/data/base.eo b/src/tests/eolian/data/base.eo index 5956014..3b701b5 100644 --- a/src/tests/eolian/data/base.eo +++ b/src/tests/eolian/data/base.eo @@ -1,4 +1,13 @@ class Base { + properties { + z { + values { + int a; + char b; + float c; + } + } + } methods { constructor { } diff --git a/src/tests/eolian/data/class_simple_ref.c b/src/tests/eolian/data/class_simple_ref.c index 51a4f4a..a7b868d 100644 --- a/src/tests/eolian/data/class_simple_ref.c +++ b/src/tests/eolian/data/class_simple_ref.c @@ -15,9 +15,8 @@ char * _class_simple_foo(Eo *obj, Evas_Simple_Data *pd, int a, char *b, double * static char * __eolian_class_simple_foo(Eo *obj, Evas_Simple_Data *pd, int a, char *b, double *c) { - if (c) *c = 1337.600000; - - return _class_simple_foo(obj, pd, a, b, c); + if (c) *c = 1337.600000; + return _class_simple_foo(obj, pd, a, b, c); } EOAPI EO_FUNC_BODYV(evas_obj_simple_foo, char *, NULL, EO_FUNC_CALL(a, b, c), int a, char *b, double *c); diff --git a/src/tests/eolian/data/override.eo b/src/tests/eolian/data/override.eo index c728b97..4eb3477 100644 --- a/src/tests/eolian/data/override.eo +++ b/src/tests/eolian/data/override.eo @@ -11,12 +11,37 @@ class Override (Base) { } get { } + keys { + int idx; + } + values { + float a; + char b; + int c; + } + } + c { + set { + } + get { + } + keys { + int idx; + } + values { + int c(50); + } } } methods { foo { } bar { + params { + @in int idx; + @out int a (250); + @out char *str (null); + } } } implements { @@ -25,5 +50,8 @@ class Override (Base) { @virtual .foo; @auto .b.set; @empty .bar; + @auto .c.get; + @auto Base.z.get; + @empty Base.z.set; } } diff --git a/src/tests/eolian/data/override_ref.c b/src/tests/eolian/data/override_ref.c new file mode 100644 index 0000000..103536a --- /dev/null +++ b/src/tests/eolian/data/override_ref.c @@ -0,0 +1,82 @@ +EOAPI EO_VOID_FUNC_BODY(override_a_set); +EOAPI EO_VOID_FUNC_BODY(override_foo); + +static void __eolian_override_b_set(Eo *obj EINA_UNUSED, Override_Data *pd, int idx EINA_UNUSED, float a, char b, int c) +{ + a = pd->a; + b = pd->b; + c = pd->c; +} + +EOAPI EO_VOID_FUNC_BODYV(override_b_set, EO_FUNC_CALL(idx, a, b, c), int idx, float a, char b, int c); + +static void __eolian_override_bar(Eo *obj EINA_UNUSED, Override_Data *pd EINA_UNUSED, int idx EINA_UNUSED, int *a, char **str) +{ + if (a) *a = 250; + if (str) *str = NULL; +} + +EOAPI EO_VOID_FUNC_BODYV(override_bar, EO_FUNC_CALL(idx, a, str), int idx, int *a, char **str); + +static int __eolian_override_c_get(Eo *obj EINA_UNUSED, Override_Data *pd EINA_UNUSED, int idx EINA_UNUSED) +{ + return 50; +} + +EOAPI EO_FUNC_BODYV(override_c_get, int, 50, EO_FUNC_CALL(idx), int idx); + +void _override_a_get(Eo *obj, Override_Data *pd); + +EOAPI EO_VOID_FUNC_BODY(override_a_get); + +void _override_b_get(Eo *obj, Override_Data *pd, int idx, float *a, char *b, int *c); + +EOAPI EO_VOID_FUNC_BODYV(override_b_get, EO_FUNC_CALL(idx, a, b, c), int idx, float *a, char *b, int *c); + +void _override_c_set(Eo *obj, Override_Data *pd, int idx, int c); + +EOAPI EO_VOID_FUNC_BODYV(override_c_set, EO_FUNC_CALL(idx, c), int idx, int c); + +void _override_base_constructor(Eo *obj, Override_Data *pd); + + +static void __eolian_override_base_z_get(Eo *obj EINA_UNUSED, Override_Data *pd, int *a, char *b, float *c) +{ + if (a) *a = pd->a; + if (b) *b = pd->b; + if (c) *c = pd->c; +} + + +static void __eolian_override_base_z_set(Eo *obj EINA_UNUSED, Override_Data *pd EINA_UNUSED, int a EINA_UNUSED, char b EINA_UNUSED, float c EINA_UNUSED) +{ +} + + +static Eo_Op_Description _override_op_desc[] = { + EO_OP_FUNC_OVERRIDE(base_constructor, _override_base_constructor), + EO_OP_FUNC_OVERRIDE(base_z_get, __eolian_override_base_z_get), + EO_OP_FUNC_OVERRIDE(base_z_set, __eolian_override_base_z_set), + EO_OP_FUNC(override_a_set, NULL, ""), + EO_OP_FUNC(override_foo, NULL, ""), + EO_OP_FUNC(override_b_set, __eolian_override_b_set, ""), + EO_OP_FUNC(override_bar, __eolian_override_bar, ""), + EO_OP_FUNC(override_c_get, __eolian_override_c_get, ""), + EO_OP_FUNC(override_a_get, _override_a_get, ""), + EO_OP_FUNC(override_b_get, _override_b_get, ""), + EO_OP_FUNC(override_c_set, _override_c_set, ""), + EO_OP_SENTINEL +}; + +static const Eo_Class_Description _override_class_desc = { + EO_VERSION, + "Override", + EO_CLASS_TYPE_REGULAR, + EO_CLASS_DESCRIPTION_OPS(_override_op_desc), + NULL, + sizeof(Override_Data), + NULL, + NULL +}; + +EO_DEFINE_CLASS(override_class_get, &_override_class_desc, BASE_CLASS, NULL); \ No newline at end of file diff --git a/src/tests/eolian/eolian_generation.c b/src/tests/eolian/eolian_generation.c index 25246c1..8161ea9 100644 --- a/src/tests/eolian/eolian_generation.c +++ b/src/tests/eolian/eolian_generation.c @@ -140,10 +140,27 @@ START_TEST(eolian_default_values_generation) } END_TEST +START_TEST(eolian_override_generation) +{ + char output_filepath[PATH_MAX] = ""; + snprintf(output_filepath, PATH_MAX, "%s/eolian_output.c", +#ifdef HAVE_EVIL + (char *)evil_tmpdir_get() +#else + "/tmp" +#endif + ); + remove(output_filepath); + fail_if(0 != _eolian_gen_execute(PACKAGE_DATA_DIR"/data/override.eo", "--eo --gc", output_filepath)); + fail_if(!_files_compare(PACKAGE_DATA_DIR"/data/override_ref.c", output_filepath)); +} +END_TEST + void eolian_generation_test(TCase *tc) { tcase_add_test(tc, eolian_types_generation); tcase_add_test(tc, eolian_default_values_generation); + tcase_add_test(tc, eolian_override_generation); tcase_add_test(tc, eolian_dev_impl_code); } -- 2.7.4