cedric pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=dc954d8dba4538ef6cc70cb28bd6c622031825b5
commit dc954d8dba4538ef6cc70cb28bd6c622031825b5 Author: Felipe Magno de Almeida <fel...@expertisesolutions.com.br> Date: Fri Apr 1 22:50:28 2016 -0300 eolian: add Eolian support for Eina Promises Add a promise object to allows Eolian interface to include promises as a way to have asynchronous value return and composibility. The usage is like this in a .eo file: class Foo { methods { bar { params { @inout promise: Promise<int>; } } } } Which will create the following API interface: void foo_bar(Eo* obj, Eina_Promise** promise); and a Eina_Promise_Owner for the implementation, like this: void _foo_bar(Eo* obj, Private_Data* pdata, Eina_Promise_Owner* promise); Signed-off-by: Cedric Bail <ced...@osg.samsung.com> --- src/Makefile_Eolian.am | 13 +++++--- src/bin/eolian/eo_generator.c | 48 ++++++++++++++++++++++++++--- src/lib/eina/eina_promise.h | 20 ++++++++++++ src/lib/eolian/eo_lexer.c | 3 +- src/lib/eolian/eo_lexer.h | 9 ++++-- src/lib/eolian/eo_parser.c | 2 +- src/tests/eolian/eolian_generated_promise.c | 46 +++++++++++++++++++++++++++ src/tests/eolian/generated_promise.eo | 42 +++++++++++++++++++++++++ 8 files changed, 170 insertions(+), 13 deletions(-) diff --git a/src/Makefile_Eolian.am b/src/Makefile_Eolian.am index 2f4554c..a542127 100644 --- a/src/Makefile_Eolian.am +++ b/src/Makefile_Eolian.am @@ -111,19 +111,24 @@ tests/eolian/eolian_suite tests_eolian_eolian_suite_SOURCES = \ tests/eolian/eolian_parsing.c \ tests/eolian/eolian_generation.c \ +tests/eolian/eolian_generated_promise.c \ tests/eolian/eolian_suite.c \ tests/eolian/eolian_suite.h -tests_eolian_eolian_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +tests/eolian/tests_eolian_eolian_suite-eolian_generated_promise.$(OBJEXT): tests/eolian/generated_promise.eo.h tests/eolian/generated_promise.eo.c + +CLEANFILES += tests/eolian/generated_promise.eo.h tests/eolian/generated_promise.eo.c + +tests_eolian_eolian_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl -I$(top_builddir)/src/tests/eolian \ -DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eolian\" \ -DPACKAGE_DATA_DIR=\"$(top_srcdir)/src/tests/eolian\" \ -DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)\" \ @CHECK_CFLAGS@ \ -@EOLIAN_CFLAGS@ +@EOLIAN_CFLAGS@ @EO_CFLAGS@ TESTS += tests/eolian/eolian_suite -tests_eolian_eolian_suite_LDADD = @CHECK_LIBS@ @USE_EOLIAN_LIBS@ -tests_eolian_eolian_suite_DEPENDENCIES = @USE_EOLIAN_INTERNAL_LIBS@ +tests_eolian_eolian_suite_LDADD = @CHECK_LIBS@ @USE_EOLIAN_LIBS@ @USE_EO_LIBS@ +tests_eolian_eolian_suite_DEPENDENCIES = @USE_EOLIAN_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ tests_eolian_eolian_suite.$(OBJEXT): $(EOLIAN_TESTS_EOS_GENERATED) endif diff --git a/src/bin/eolian/eo_generator.c b/src/bin/eolian/eo_generator.c index 22efb10..78e8108 100644 --- a/src/bin/eolian/eo_generator.c +++ b/src/bin/eolian/eo_generator.c @@ -311,6 +311,9 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, if (ftype != EOLIAN_PROP_GET && ftype != EOLIAN_PROP_SET) ftype = eolian_function_type_get(funcid); Eina_Bool is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET); + Eina_Bool has_promise = EINA_FALSE; + const char* promise_param_name = NULL; + const char* promise_value_type = NULL; Eina_Bool need_implementation = EINA_TRUE; if (!impl_env && eolian_function_is_virtual_pure(funcid, ftype)) need_implementation = EINA_FALSE; @@ -318,6 +321,7 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, Eina_Strbuf *va_args = eina_strbuf_new(); Eina_Strbuf *params = eina_strbuf_new(); /* only variables names */ Eina_Strbuf *full_params = eina_strbuf_new(); /* variables types + names */ + Eina_Strbuf *impl_full_params = eina_strbuf_new(); /* variables types + names */ Eina_Strbuf *params_init = eina_strbuf_new(); /* init of variables to default */ rettypet = eolian_function_return_type_get(funcid, ftype); @@ -360,6 +364,8 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, eina_strbuf_append_printf(params, "%s", pname); eina_strbuf_append_printf(full_params, ", %s %s%s", ptype, pname, is_empty || is_auto?" EINA_UNUSED":""); + eina_strbuf_append_printf(impl_full_params, ", %s %s%s", + ptype, pname, is_empty || is_auto?" EINA_UNUSED":""); eina_stringshare_del(ptype); } eina_iterator_free(itr); @@ -375,9 +381,33 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, const char *ptype = eolian_type_c_type_get(ptypet); Eolian_Parameter_Dir pdir = eolian_parameter_direction_get(param); Eina_Bool had_star = !!strchr(ptype, '*'); + if (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) add_star = (pdir == EOLIAN_OUT_PARAM || pdir == EOLIAN_INOUT_PARAM); + + if(!has_promise && !strcmp(ptype, "Eina_Promise *") && + (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) && pdir == EOLIAN_INOUT_PARAM) + { + Eina_Iterator* promise_values; + has_promise = EINA_TRUE; + promise_param_name = eina_stringshare_add(pname); + promise_values = eolian_type_subtypes_get(eolian_type_base_type_get(ptypet)); + Eolian_Type* subtype; + if(eina_iterator_next(promise_values, (void**)&subtype)) + promise_value_type = eolian_type_c_type_get(subtype); + eina_strbuf_append_printf(impl_full_params, ", Eina_Promise_Owner *%s%s", + pname, is_empty && !dflt_value ?" EINA_UNUSED":""); + } + else + { + eina_strbuf_append_printf(impl_full_params, ", %s%s%s%s%s", + ptype, had_star?"":" ", add_star?"*":"", pname, is_empty && !dflt_value ?" EINA_UNUSED":""); + } + if (eina_strbuf_length_get(params)) eina_strbuf_append(params, ", "); - eina_strbuf_append_printf(params, "%s", pname); + if(has_promise) + eina_strbuf_append_printf(params, "%s", "__eo_promise"); + else + eina_strbuf_append_printf(params, "%s", pname); eina_strbuf_append_printf(full_params, ", %s%s%s%s%s", ptype, had_star?"":" ", add_star?"*":"", pname, is_empty && !dflt_value ?" EINA_UNUSED":""); if (is_auto) @@ -439,7 +469,7 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, impl_env?impl_env->lower_classname:"", eolian_function_name_get(funcid), suffix, eolian_function_object_is_const(funcid)?"const ":"", - eina_strbuf_string_get(full_params)); + eina_strbuf_string_get(impl_full_params)); } if (is_empty || is_auto || eina_strbuf_length_get(params_init)) @@ -457,7 +487,7 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, eolian_function_object_is_const(funcid)?"const ":"", is_empty || is_auto?" EINA_UNUSED":"", is_empty || (is_auto && !eina_strbuf_length_get(params_init))?" EINA_UNUSED":"", - eina_strbuf_string_get(full_params)); + eina_strbuf_string_get(impl_full_params)); } if (eina_strbuf_length_get(params_init)) { @@ -511,11 +541,21 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, Eina_Bool ret_is_void = (!rettype || !strcmp(rettype, "void")); _class_func_env_create(class, eolian_function_name_get(funcid), ftype, &func_env); eina_strbuf_append_printf(eo_func_decl, - "EOAPI EO_%sFUNC_BODY%s%s(%s, _EO_EMPTY_HOOK, _EO_EMPTY_HOOK", + "EOAPI EO_%sFUNC_BODY%s%s(%s", ret_is_void?"VOID_":"", has_params?"V":"", (ftype == EOLIAN_PROP_GET || eolian_function_object_is_const(funcid) || eolian_function_is_class(funcid))?"_CONST":"", func_env.lower_eo_func); + if(has_promise) + { + eina_strbuf_append_printf(eo_func_decl, + ", _EINA_PROMISE_BEFORE_HOOK(%s, %s%s) _EO_EMPTY_HOOK, _EINA_PROMISE_AFTER_HOOK(%s) _EO_EMPTY_HOOK", + promise_value_type, !rettype ? "void" : rettype, + eina_strbuf_string_get(impl_full_params), + promise_param_name); + } + else + eina_strbuf_append_printf(eo_func_decl, ", _EO_EMPTY_HOOK, _EO_EMPTY_HOOK"); if (!ret_is_void) { const char *val_str = NULL; diff --git a/src/lib/eina/eina_promise.h b/src/lib/eina/eina_promise.h index fa9376f..70584e4 100644 --- a/src/lib/eina/eina_promise.h +++ b/src/lib/eina/eina_promise.h @@ -438,4 +438,24 @@ EAPI void eina_promise_owner_default_manual_then_set(Eina_Promise_Owner* promise */ EAPI void eina_promise_owner_default_call_then(Eina_Promise_Owner* promise); + +/* + * @internal + */ +#define _EINA_PROMISE_BEFORE_HOOK(PromiseValue, Ret, ...) \ + Eina_Promise_Owner* __eo_promise = eina_promise_default_add(sizeof(PromiseValue)); \ + typedef Ret (*_Eo__Promise_func_)(Eo*, void *obj_data, ##__VA_ARGS__); \ + _Eo__Promise_func_ const _promise_func = (_Eo__Promise_func_)_func_; \ + { \ + _Eo__Promise_func_ const _func_ = _promise_func; + + +/* + * @internal + */ +#define _EINA_PROMISE_AFTER_HOOK(Promise) \ + } \ + if(Promise) \ + *Promise = eina_promise_owner_promise_get(__eo_promise); + #endif diff --git a/src/lib/eolian/eo_lexer.c b/src/lib/eolian/eo_lexer.c index 0e98313..dff540c 100644 --- a/src/lib/eolian/eo_lexer.c +++ b/src/lib/eolian/eo_lexer.c @@ -73,9 +73,10 @@ static const char * const ctypes[] = "void", "Eina_Accessor", "Eina_Array", "Eina_Iterator", "Eina_Hash", "Eina_List", + "Eina_Promise", "Eina_Value", - "Eo_Event_Cb" + "Eo_Event_Cb", }; #undef KW diff --git a/src/lib/eolian/eo_lexer.h b/src/lib/eolian/eo_lexer.h index b28a3fc..c43e3df 100644 --- a/src/lib/eolian/eo_lexer.h +++ b/src/lib/eolian/eo_lexer.h @@ -50,9 +50,12 @@ enum Tokens \ KW(void), \ \ - KW(accessor), KW(array), KW(iterator), KW(hash), KW(list), KW(generic_value), \ + KW(accessor), KW(array), KW(iterator), KW(hash), KW(list), \ + KW(promise), \ + KW(generic_value), \ \ - KW(__builtin_event_cb), KW(__undefined_type), \ + KW(__builtin_event_cb), \ + KW(__undefined_type), \ \ KW(true), KW(false), KW(null) @@ -206,4 +209,4 @@ void eo_lexer_context_pop (Eo_Lexer *ls); void eo_lexer_context_restore(Eo_Lexer *ls); void eo_lexer_context_clear (Eo_Lexer *ls); -#endif /* __EO_LEXER_H__ */ \ No newline at end of file +#endif /* __EO_LEXER_H__ */ diff --git a/src/lib/eolian/eo_parser.c b/src/lib/eolian/eo_parser.c index e02fd57..9b8ec2a 100644 --- a/src/lib/eolian/eo_parser.c +++ b/src/lib/eolian/eo_parser.c @@ -782,7 +782,7 @@ parse_type_void_base(Eo_Lexer *ls, Eina_Bool noptr) _fill_name(eina_stringshare_ref(ls->t.value.s), &def->full_name, &def->name, &def->namespaces); eo_lexer_get(ls); - if (tpid >= KW_accessor && tpid <= KW_list) + if (tpid >= KW_accessor && tpid <= KW_promise) { int bline = ls->line_number, bcol = ls->column; def->type = EOLIAN_TYPE_COMPLEX; diff --git a/src/tests/eolian/eolian_generated_promise.c b/src/tests/eolian/eolian_generated_promise.c new file mode 100644 index 0000000..2d0e6f6 --- /dev/null +++ b/src/tests/eolian/eolian_generated_promise.c @@ -0,0 +1,46 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <Eina.h> +#include <Eo.h> + +#include <check.h> + +struct Generated_Promise_Data {}; +typedef struct Generated_Promise_Data Generated_Promise_Data; + +static Eina_Promise * _generated_promise_prop1_get(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED) +{ + return NULL; +} + +static void _generated_promise_prop2_get(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED, int *i EINA_UNUSED, + Eina_Promise **promise1 EINA_UNUSED) +{ +} + +static void _generated_promise_prop3_set(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED, + Eina_Promise *promise1 EINA_UNUSED) +{ +} + +static void _generated_promise_method1(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED, + Eina_Promise_Owner *promise1 EINA_UNUSED) +{ +} + +static void _generated_promise_method2(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED, + Eina_Promise **promise1 EINA_UNUSED) +{ +} + +static void _generated_promise_method3(Eo *obj EINA_UNUSED, Generated_Promise_Data *pd EINA_UNUSED, + Eina_Promise *promise1 EINA_UNUSED) +{ + ck_assert(promise1 != NULL); +} + +#include "generated_promise.eo.h" +#include "generated_promise.eo.c" diff --git a/src/tests/eolian/generated_promise.eo b/src/tests/eolian/generated_promise.eo new file mode 100644 index 0000000..66c1a68 --- /dev/null +++ b/src/tests/eolian/generated_promise.eo @@ -0,0 +1,42 @@ +class Generated_Promise (Eo.Base) +{ + legacy_prefix: null; + methods { + method1 { + params { + @inout promise1: promise<int>*; + } + } + method2 { + params { + @out promise1: promise<int>*; + } + } + method3 { + params { + @in promise1: promise<int>*; + } + } + @property prop1 { + get {} + values { + promise1: promise<int>*; + } + } + @property prop2 { + get {} + values { + i: int; + promise1: promise<int>*; + } + } + @property prop3 { + set {} + values { + promise1: promise<int>*; + } + } + } +} + + --