felipealmeida pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=1634c141698499ea0fe735c5447c38488e8891ad
commit 1634c141698499ea0fe735c5447c38488e8891ad Author: Lauro Moura <lauromo...@expertisesolutions.com.br> Date: Fri Apr 7 13:54:55 2017 -0300 eolian: function pointers First steps toward explicit function pointer support in eolian. To declare a function pointer type, use the following syntax, similar to a regular eolian method declaration. function FunctionName { params { ... } return: Return type } --- src/bin/eolian/headers.c | 21 +++ src/bin/eolian/sources.c | 52 +++++++ src/bin/eolian/types.c | 45 ++++++ src/lib/eolian/Eolian.h | 26 +++- src/lib/eolian/database_function_api.c | 7 +- src/lib/eolian/database_type_api.c | 9 ++ src/lib/eolian/database_validate.c | 3 + src/lib/eolian/eo_lexer.c | 1 + src/lib/eolian/eo_lexer.h | 1 + src/lib/eolian/eo_parser.c | 108 +++++++++++++ src/lib/eolian/eolian_database.h | 1 + src/tests/eolian/data/function_as_argument.eo | 25 +++ .../eolian/data/function_as_argument_impl_ref.c | 28 ++++ src/tests/eolian/data/function_as_argument_ref.c | 49 ++++++ src/tests/eolian/data/function_as_argument_ref.h | 26 ++++ src/tests/eolian/data/function_types.eot | 30 ++++ src/tests/eolian/data/function_types_ref.h | 18 +++ src/tests/eolian/eolian_generation.c | 32 ++++ src/tests/eolian/eolian_parsing.c | 168 +++++++++++++++++++++ 19 files changed, 646 insertions(+), 4 deletions(-) diff --git a/src/bin/eolian/headers.c b/src/bin/eolian/headers.c index 8538731a44..1d11da860a 100644 --- a/src/bin/eolian/headers.c +++ b/src/bin/eolian/headers.c @@ -128,9 +128,30 @@ _gen_func(const Eolian_Unit *src, const Eolian_Function *fid, EINA_ITERATOR_FOREACH(itr, pr) { const Eolian_Type *prt = eolian_parameter_type_get(pr); + const Eolian_Typedecl *ptd = eolian_type_typedecl_get(prt); const char *prn = eolian_parameter_name_get(pr); Eina_Stringshare *prtn = eolian_type_c_type_get(prt); + if (ptd && eolian_typedecl_type_get(ptd) == EOLIAN_TYPEDECL_FUNCTION_POINTER) + { + nidx += 3; + if (!first) + eina_strbuf_append(buf, ", "); + eina_strbuf_append_printf(buf, "void *%s_data, %s %s, Eina_Free_Cb %s_free_cb", + prn, prtn, prn, prn); + eina_stringshare_del(prtn); + if (!eolian_parameter_is_nonull(pr)) + continue; + if (!flagbuf) + { + flagbuf = eina_strbuf_new(); + eina_strbuf_append_printf(flagbuf, " EINA_ARG_NONNULL(%d", nidx - 1); + } + else + eina_strbuf_append_printf(flagbuf, ", %d", nidx - 1); + continue; + } + ++nidx; if (!first) eina_strbuf_append(buf, ", "); diff --git a/src/bin/eolian/sources.c b/src/bin/eolian/sources.c index 6eb6ad7927..b2d4b2065a 100644 --- a/src/bin/eolian/sources.c +++ b/src/bin/eolian/sources.c @@ -69,6 +69,40 @@ _type_exists(const char *tname, Eina_Strbuf *buf) } static void +_gen_func_pointer_param(const char *name, Eina_Stringshare *c_type, + const Eolian_Typedecl *typedecl EINA_UNUSED, + Eina_Strbuf *params, Eina_Strbuf *params_full, + Eina_Strbuf *params_full_imp, + Eina_Bool is_empty EINA_UNUSED) +{ + Eina_Strbuf *dataname = eina_strbuf_new(); + Eina_Strbuf *freename = eina_strbuf_new(); + + eina_strbuf_append_printf(dataname, "%s_data", name); + eina_strbuf_append_printf(freename, "%s_free_cb", name); + + if (eina_strbuf_length_get(params)) + eina_strbuf_append(params, ", "); + + eina_strbuf_append_printf(params, "%s, %s, %s", + eina_strbuf_string_get(dataname), + name, + eina_strbuf_string_get(freename)); + + eina_strbuf_append_printf(params_full_imp, ", void *%s, %s %s, Eina_Free_Cb %s", + eina_strbuf_string_get(dataname), + c_type, name, + eina_strbuf_string_get(freename)); + eina_strbuf_append_printf(params_full, ", void *%s, %s %s, Eina_Free_Cb %s", + eina_strbuf_string_get(dataname), + c_type, name, + eina_strbuf_string_get(freename)); + + eina_strbuf_free(dataname); + eina_strbuf_free(freename); +} + +static void _append_defval(const Eolian_Unit *src, Eina_Strbuf *buf, const Eolian_Expression *exp, const Eolian_Type *tp) { @@ -212,10 +246,18 @@ _gen_func(const Eolian_Unit *src, const Eolian_Class *cl, const char *prn = eolian_parameter_name_get(pr); const Eolian_Type *pt = eolian_parameter_type_get(pr); Eina_Stringshare *ptn = eolian_type_c_type_get(pt); + const Eolian_Typedecl *ptd = eolian_type_typedecl_get(pt); Eina_Bool had_star = ptn[strlen(ptn) - 1] == '*'; const char *add_star = _get_add_star(ftype, pd); + if (ptd && eolian_typedecl_type_get(ptd) == EOLIAN_TYPEDECL_FUNCTION_POINTER) + { + _gen_func_pointer_param(prn, ptn, ptd, params, params_full, params_full_imp, is_empty); + eina_stringshare_del(ptn); + continue; + } + if (eina_strbuf_length_get(params)) eina_strbuf_append(params, ", "); @@ -828,8 +870,18 @@ _gen_params(const Eolian_Function *fid, Eolian_Function_Type ftype, Eolian_Parameter_Dir pd = eolian_parameter_direction_get(pr); const char *prn = eolian_parameter_name_get(pr); const Eolian_Type *pt = eolian_parameter_type_get(pr); + const Eolian_Typedecl *ptd = eolian_type_typedecl_get(pt); Eina_Stringshare *ptn = eolian_type_c_type_get(pt); + if (ptd && eolian_typedecl_type_get(ptd) == EOLIAN_TYPEDECL_FUNCTION_POINTER) + { + eina_strbuf_append_printf(params, ", %s_data, %s, %s_free_cb", prn, prn, prn); + eina_strbuf_append_printf(params_full, ", void *%s_data, %s %s, Eina_Free_Cb %s_free_cb", prn, ptn, prn, prn); + + eina_stringshare_del(ptn); + continue; + } + Eina_Bool had_star = ptn[strlen(ptn) - 1] == '*'; const char *add_star = _get_add_star(ftype, pd); diff --git a/src/bin/eolian/types.c b/src/bin/eolian/types.c index c1d4e1fa94..9baebed02a 100644 --- a/src/bin/eolian/types.c +++ b/src/bin/eolian/types.c @@ -133,6 +133,51 @@ _type_generate(const Eolian_Unit *src, const Eolian_Typedecl *tp, free(fn); break; } + case EOLIAN_TYPEDECL_FUNCTION_POINTER: + { + const Eolian_Function *fid = eolian_typedecl_function_pointer_get(tp); + + eina_strbuf_append(buf, "typedef "); + + /* Return type */ + const Eolian_Type *rtp = eolian_function_return_type_get(fid, EOLIAN_FUNCTION_POINTER); + if (!rtp) + eina_strbuf_append(buf, "void "); + else + { + Eina_Stringshare *ct = eolian_type_c_type_get(rtp); + eina_strbuf_append_printf(buf, "%s ", ct); + } + + /* Function name */ + char *fn = eo_gen_c_full_name_get(eolian_typedecl_full_name_get(tp)); + eina_strbuf_append_printf(buf, "(*%s)", fn); + free(fn); + + /* Parameters */ + eina_strbuf_append(buf, "(void *data"); + Eina_Iterator *params = eolian_function_parameters_get(fid); + const Eolian_Function_Parameter *param = NULL; + EINA_ITERATOR_FOREACH(params, param) + { + const Eolian_Typedecl *ptd = eolian_type_typedecl_get(eolian_parameter_type_get(param)); + Eina_Stringshare *pn = eolian_parameter_name_get(param); + Eina_Stringshare *pt = eolian_type_c_type_get(eolian_parameter_type_get(param)); + + if (!pn) + pn = ""; // FIXME add some kind of param1/param2 control for null? + + if (ptd && eolian_typedecl_type_get(ptd) == EOLIAN_TYPEDECL_FUNCTION_POINTER) + eina_strbuf_append_printf(buf, ", void *%s_data, %s %s, Eina_Free_Cb %s_free_cb", + pn, pt, pn, pn); + else + eina_strbuf_append_printf(buf, ", %s %s", pt, pn); + + } + eina_strbuf_append(buf, ")"); + + break; + } default: eina_strbuf_reset(buf); break; diff --git a/src/lib/eolian/Eolian.h b/src/lib/eolian/Eolian.h index 02ee4f9d91..8b19fd602b 100644 --- a/src/lib/eolian/Eolian.h +++ b/src/lib/eolian/Eolian.h @@ -183,7 +183,8 @@ typedef enum EOLIAN_PROPERTY, EOLIAN_PROP_SET, EOLIAN_PROP_GET, - EOLIAN_METHOD + EOLIAN_METHOD, + EOLIAN_FUNCTION_POINTER } Eolian_Function_Type; typedef enum @@ -217,7 +218,8 @@ typedef enum EOLIAN_TYPEDECL_STRUCT, EOLIAN_TYPEDECL_STRUCT_OPAQUE, EOLIAN_TYPEDECL_ENUM, - EOLIAN_TYPEDECL_ALIAS + EOLIAN_TYPEDECL_ALIAS, + EOLIAN_TYPEDECL_FUNCTION_POINTER } Eolian_Typedecl_Type; typedef enum @@ -821,6 +823,16 @@ EAPI Eina_Bool eolian_function_is_beta(const Eolian_Function *function_id); EAPI Eina_Bool eolian_function_is_constructor(const Eolian_Function *function_id, const Eolian_Class *klass); /* + * @brief Get whether a function is a function pointer. + * + * @param[in] function_id Id of the function + * @return EINA_TRUE and EINA_FALSE respectively + * + * @ingroup Eolian + */ +EAPI Eina_Bool eolian_function_is_function_pointer(const Eolian_Function *function_id); + +/* * @brief Returns an iterator to the parameter handles for a method/ctor/dtor. * * @param[in] function_id Id of the function @@ -1731,6 +1743,16 @@ EAPI Eina_Iterator *eolian_typedecl_namespaces_get(const Eolian_Typedecl *tp); EAPI Eina_Stringshare *eolian_typedecl_free_func_get(const Eolian_Typedecl *tp); /* + * @breif Get the function object for this function pointer type. + * + * @param[in] tp the type. + * @return the function or NULL; + * + * @ingroup Eolian + */ +EAPI const Eolian_Function *eolian_typedecl_function_pointer_get(const Eolian_Typedecl *tp); + +/* * @brief Get the type of a type. * * @param[in] tp the type. diff --git a/src/lib/eolian/database_function_api.c b/src/lib/eolian/database_function_api.c index d5e5f6136c..a3a00d5380 100644 --- a/src/lib/eolian/database_function_api.c +++ b/src/lib/eolian/database_function_api.c @@ -102,6 +102,7 @@ eolian_function_full_c_name_get(const Eolian_Function *foo_id, case EOLIAN_METHOD: case EOLIAN_PROPERTY: case EOLIAN_PROP_GET: + case EOLIAN_FUNCTION_POINTER: if (foo_id->get_legacy && use_legacy) { if (!strcmp(foo_id->get_legacy, "null")) @@ -120,7 +121,7 @@ eolian_function_full_c_name_get(const Eolian_Function *foo_id, } char tbuf[512]; - const char *prefix = _get_eo_prefix(foo_id, tbuf, use_legacy); + const char *prefix = (ftype != EOLIAN_FUNCTION_POINTER) ? _get_eo_prefix(foo_id, tbuf, use_legacy): tbuf; if (!prefix) return NULL; @@ -278,7 +279,7 @@ EAPI Eina_Iterator * eolian_function_parameters_get(const Eolian_Function *fid) { EINA_SAFETY_ON_NULL_RETURN_VAL(fid, NULL); - if (fid->type != EOLIAN_METHOD) + if (fid->type != EOLIAN_METHOD && fid->type != EOLIAN_FUNCTION_POINTER) return NULL; return (fid->params ? eina_list_iterator_new(fid->params) : NULL); } @@ -303,6 +304,8 @@ eolian_function_return_type_get(const Eolian_Function *fid, Eolian_Function_Type if ((fid->type != EOLIAN_PROP_SET) && (fid->type != EOLIAN_PROPERTY)) return NULL; return fid->set_ret_type; + case EOLIAN_FUNCTION_POINTER: + return (fid->type != EOLIAN_FUNCTION_POINTER) ? NULL : fid->get_ret_type; default: return NULL; } diff --git a/src/lib/eolian/database_type_api.c b/src/lib/eolian/database_type_api.c index 22d95eecec..bbc03fd17d 100644 --- a/src/lib/eolian/database_type_api.c +++ b/src/lib/eolian/database_type_api.c @@ -437,3 +437,12 @@ eolian_typedecl_free_func_get(const Eolian_Typedecl *tp) EINA_SAFETY_ON_NULL_RETURN_VAL(tp, NULL); return tp->freefunc; } + +EAPI const Eolian_Function * +eolian_typedecl_function_pointer_get(EINA_UNUSED const Eolian_Typedecl *tp) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(tp, NULL); + if (eolian_typedecl_type_get(tp) != EOLIAN_TYPEDECL_FUNCTION_POINTER) + return NULL; + return tp->function_pointer; +} diff --git a/src/lib/eolian/database_validate.c b/src/lib/eolian/database_validate.c index 1ce5d4e38f..6df55d4b18 100644 --- a/src/lib/eolian/database_validate.c +++ b/src/lib/eolian/database_validate.c @@ -118,6 +118,9 @@ _validate_typedecl(const Eolian_Typedecl *tp) eina_hash_foreach(tp->fields, (Eina_Hash_Foreach)_ef_map_cb, &succ); return succ; } + case EOLIAN_TYPEDECL_FUNCTION_POINTER: + // FIXME validate functions here + return EINA_TRUE; default: return EINA_FALSE; } diff --git a/src/lib/eolian/eo_lexer.c b/src/lib/eolian/eo_lexer.c index 5521e09b81..f525b41fc8 100644 --- a/src/lib/eolian/eo_lexer.c +++ b/src/lib/eolian/eo_lexer.c @@ -80,6 +80,7 @@ static const char * const ctypes[] = "void *", "Eina_Free_Cb", + "function", }; #undef KW diff --git a/src/lib/eolian/eo_lexer.h b/src/lib/eolian/eo_lexer.h index 45a6ab70f2..9c9b1d25c1 100644 --- a/src/lib/eolian/eo_lexer.h +++ b/src/lib/eolian/eo_lexer.h @@ -58,6 +58,7 @@ enum Tokens \ KW(void_ptr), \ KW(__builtin_free_cb), \ + KW(function), \ KW(__undefined_type), \ \ KW(true), KW(false), KW(null) diff --git a/src/lib/eolian/eo_parser.c b/src/lib/eolian/eo_parser.c index c93b60d521..5ae3f8788f 100644 --- a/src/lib/eolian/eo_parser.c +++ b/src/lib/eolian/eo_parser.c @@ -1406,6 +1406,108 @@ end: _func_pure_virtual_set(ls, prop, has_virtp); } +static Eolian_Typedecl* +parse_function_pointer(Eo_Lexer *ls) +{ + int line, col; + Eolian_Typedecl *def = push_typedecl(ls); + Eina_Strbuf *buf = push_strbuf(ls); + Eolian_Function *meth = NULL; + + Eina_Bool has_const = EINA_FALSE, + has_params = EINA_FALSE, + has_return = EINA_FALSE, + has_c_only = EINA_FALSE, + has_beta = EINA_FALSE; + + eo_lexer_get(ls); + parse_name(ls, buf); + + def->type = EOLIAN_TYPEDECL_FUNCTION_POINTER; + def->is_extern = EINA_FALSE; + + FILL_BASE(def->base, ls, ls->line_number, ls->column); + + _fill_name(eina_stringshare_add(eina_strbuf_string_get(buf)), + &def->full_name, &def->name, &def->namespaces); + + pop_strbuf(ls); + + meth = calloc(1, sizeof(Eolian_Function)); + meth->klass = NULL; + meth->type = EOLIAN_FUNCTION_POINTER; + meth->get_scope = meth->set_scope = EOLIAN_SCOPE_PUBLIC; + meth->name = eina_stringshare_ref(def->name); + FILL_BASE(meth->base, ls, ls->line_number, ls->column); + + def->function_pointer = meth; + + for (;;) switch (ls->t.kw) + { + case KW_at_protected: + eo_lexer_syntax_error(ls, "protected invalid for function pointer"); + return NULL; + case KW_at_const: + CASE_LOCK(ls, const, "const qualifier"); + meth->obj_is_const = EINA_TRUE; + break; + case KW_at_class: + eo_lexer_syntax_error(ls, "class invalid for function pointer"); + return NULL; + case KW_at_c_only: + CASE_LOCK(ls, c_only, "c_only qualifier"); + meth->is_c_only = EINA_TRUE; + eo_lexer_get(ls); + break; + case KW_at_beta: + CASE_LOCK(ls, beta, "beta qualifier"); + meth->is_beta = EINA_TRUE; + eo_lexer_get(ls); + break; + default: + goto body; + } +body: + line = ls->line_number; + col = ls->column; + check_next(ls, '{'); + for (;;) switch (ls->t.kw) + { + case KW_return: + CASE_LOCK(ls, return, "return"); + Eo_Ret_Def ret; + parse_return(ls, &ret, EINA_FALSE); + pop_type(ls); + if (ret.default_ret_val) + { + eo_lexer_syntax_error(ls, "default return value invalid for function pointer"); + return NULL; + } + meth->get_ret_type = ret.type; + meth->get_return_doc = ret.doc; + meth->get_ret_val = NULL; + meth->get_return_warn_unused = EINA_FALSE; + break; + case KW_legacy: // FIXME Do legacy and eo make sense for these new function pointer stuff? + eo_lexer_syntax_error(ls, "legacy invalid for function pointer"); + return NULL; + case KW_eo: + eo_lexer_syntax_error(ls, "eo name invalid for function pointer"); + return NULL; + case KW_params: + CASE_LOCK(ls, params, "params definition"); + parse_params(ls, &meth->params, EINA_TRUE, EINA_FALSE); + break; + default: + goto end; + } +end: + check_match(ls, '}', '{', line, col); + check_next(ls, ';'); + FILL_DOC(ls, def, doc); + return def; +} + static void parse_method(Eo_Lexer *ls) { @@ -2154,6 +2256,12 @@ parse_unit(Eo_Lexer *ls, Eina_Bool eot) pop_typedecl(ls); break; } + case KW_function: + { + database_type_add(parse_function_pointer(ls)); + pop_typedecl(ls); + break; + } case KW_const: case KW_var: { diff --git a/src/lib/eolian/eolian_database.h b/src/lib/eolian/eolian_database.h index 85ac333cbd..c088412898 100644 --- a/src/lib/eolian/eolian_database.h +++ b/src/lib/eolian/eolian_database.h @@ -179,6 +179,7 @@ struct _Eolian_Typedecl Eina_List *namespaces; Eina_Hash *fields; Eina_List *field_list; + Eolian_Function *function_pointer; Eolian_Documentation *doc; Eina_Stringshare *legacy; Eina_Stringshare *freefunc; diff --git a/src/tests/eolian/data/function_as_argument.eo b/src/tests/eolian/data/function_as_argument.eo new file mode 100644 index 0000000000..2eb2cc2a21 --- /dev/null +++ b/src/tests/eolian/data/function_as_argument.eo @@ -0,0 +1,25 @@ +import function_types; + +class Function_As_Argument { + methods { + set_cb { + params { + cb: SimpleFunc; + } + } + + set_nonull_cb { + params { + cb: VoidFunc @nonull; + } + } + + call_cb { + params { + a: int; + b: double; + } + return: own(string); + } + } +} diff --git a/src/tests/eolian/data/function_as_argument_impl_ref.c b/src/tests/eolian/data/function_as_argument_impl_ref.c new file mode 100644 index 0000000000..7e8a89e6eb --- /dev/null +++ b/src/tests/eolian/data/function_as_argument_impl_ref.c @@ -0,0 +1,28 @@ +#define EFL_BETA_API_SUPPORT +#include <Eo.h> +#include "function_as_argument.eo.h" + +typedef struct +{ + +} Function_As_Argument_Data; + +EOLIAN static void +_function_as_argument_set_cb(Eo *obj, Function_As_Argument_Data *pd, void *cb_data, SimpleFunc cb, Eina_Free_Cb cb_free_cb) +{ + +} + +EOLIAN static void +_function_as_argument_set_nonull_cb(Eo *obj, Function_As_Argument_Data *pd, void *cb_data, VoidFunc cb, Eina_Free_Cb cb_free_cb) +{ + +} + +EOLIAN static const char * +_function_as_argument_call_cb(Eo *obj, Function_As_Argument_Data *pd, int a, double b) +{ + +} + +#include "function_as_argument.eo.c" diff --git a/src/tests/eolian/data/function_as_argument_ref.c b/src/tests/eolian/data/function_as_argument_ref.c new file mode 100644 index 0000000000..742f8d8d4e --- /dev/null +++ b/src/tests/eolian/data/function_as_argument_ref.c @@ -0,0 +1,49 @@ + +void _function_as_argument_set_cb(Eo *obj, Function_As_Argument_Data *pd, void *cb_data, SimpleFunc cb, Eina_Free_Cb cb_free_cb); + +EOAPI EFL_VOID_FUNC_BODYV(function_as_argument_set_cb, EFL_FUNC_CALL(cb_data, cb, cb_free_cb), void *cb_data, SimpleFunc cb, Eina_Free_Cb cb_free_cb); + +void _function_as_argument_set_nonull_cb(Eo *obj, Function_As_Argument_Data *pd, void *cb_data, VoidFunc cb, Eina_Free_Cb cb_free_cb); + +EOAPI EFL_VOID_FUNC_BODYV(function_as_argument_set_nonull_cb, EFL_FUNC_CALL(cb_data, cb, cb_free_cb), void *cb_data, VoidFunc cb, Eina_Free_Cb cb_free_cb); + +const char *_function_as_argument_call_cb(Eo *obj, Function_As_Argument_Data *pd, int a, double b); + +EOAPI EFL_FUNC_BODYV(function_as_argument_call_cb, const char *, NULL, EFL_FUNC_CALL(a, b), int a, double b); + +static Eina_Bool +_function_as_argument_class_initializer(Efl_Class *klass) +{ + const Efl_Object_Ops *opsp = NULL, *copsp = NULL; + +#ifndef FUNCTION_AS_ARGUMENT_EXTRA_OPS +#define FUNCTION_AS_ARGUMENT_EXTRA_OPS +#endif + + EFL_OPS_DEFINE(ops, + EFL_OBJECT_OP_FUNC(function_as_argument_set_cb, _function_as_argument_set_cb), + EFL_OBJECT_OP_FUNC(function_as_argument_set_nonull_cb, _function_as_argument_set_nonull_cb), + EFL_OBJECT_OP_FUNC(function_as_argument_call_cb, _function_as_argument_call_cb), + FUNCTION_AS_ARGUMENT_EXTRA_OPS + ); + opsp = &ops; + +#ifdef FUNCTION_AS_ARGUMENT_EXTRA_CLASS_OPS + EFL_OPS_DEFINE(cops, FUNCTION_AS_ARGUMENT_EXTRA_CLASS_OPS); + copsp = &cops; +#endif + + return efl_class_functions_set(klass, opsp, copsp); +} + +static const Efl_Class_Description _function_as_argument_class_desc = { + EO_VERSION, + "Function_As_Argument", + EFL_CLASS_TYPE_REGULAR, + sizeof(Function_As_Argument_Data), + _function_as_argument_class_initializer, + NULL, + NULL +}; + +EFL_DEFINE_CLASS(function_as_argument_class_get, &_function_as_argument_class_desc, NULL, NULL); diff --git a/src/tests/eolian/data/function_as_argument_ref.h b/src/tests/eolian/data/function_as_argument_ref.h new file mode 100644 index 0000000000..5eff241c22 --- /dev/null +++ b/src/tests/eolian/data/function_as_argument_ref.h @@ -0,0 +1,26 @@ +#ifndef _EOLIAN_FUNCTION_POINTERS_H_ +#define _EOLIAN_FUNCTION_POINTERS_H_ + +#ifndef _FUNCTION_AS_ARGUMENT_EO_CLASS_TYPE +#define _FUNCTION_AS_ARGUMENT_EO_CLASS_TYPE + +typedef Eo Function_As_Argument; + +#endif + +#ifndef _FUNCTION_AS_ARGUMENT_EO_TYPES +#define _FUNCTION_AS_ARGUMENT_EO_TYPES + + +#endif +#define FUNCTION_AS_ARGUMENT_CLASS function_as_argument_class_get() + +EWAPI const Efl_Class *function_as_argument_class_get(void); + +EOAPI void function_as_argument_set_cb(Eo *obj, void *cb_data, SimpleFunc cb, Eina_Free_Cb cb_free_cb); + +EOAPI void function_as_argument_set_nonull_cb(Eo *obj, void *cb_data, VoidFunc cb, Eina_Free_Cb cb_free_cb) EINA_ARG_NONNULL(3); + +EOAPI const char *function_as_argument_call_cb(Eo *obj, int a, double b); + +#endif diff --git a/src/tests/eolian/data/function_types.eot b/src/tests/eolian/data/function_types.eot new file mode 100644 index 0000000000..5f067903a8 --- /dev/null +++ b/src/tests/eolian/data/function_types.eot @@ -0,0 +1,30 @@ + +// typedef void (*VoidFunc)(void *data); +function VoidFunc { +}; + +// typedef const char *(*SimpleFunc)(void *data, int a, double b); +function SimpleFunc { + params { + a: int; + b: double; + } + return: string; +}; + +// typedef double (*ComplexFunc)(void *data, const char *a, const char **b); +function ComplexFunc { + params { + @in c: string; + @out d: own(string); + } + return: double; +}; + +// typedef void (*FuncAsArgFunc)(void *data, VoidFunc cb, SimpleFunc another_cb); +function FuncAsArgFunc { + params { + cb: VoidFunc; + another_cb: SimpleFunc; + } +}; diff --git a/src/tests/eolian/data/function_types_ref.h b/src/tests/eolian/data/function_types_ref.h new file mode 100644 index 0000000000..2f534c7d69 --- /dev/null +++ b/src/tests/eolian/data/function_types_ref.h @@ -0,0 +1,18 @@ +#ifndef _EOLIAN_FUNCTION_POINTERS_H_ +#define _EOLIAN_FUNCTION_POINTERS_H_ + +#ifndef _FUNCTION_TYPES_EOT_TYPES +#define _FUNCTION_TYPES_EOT_TYPES + +typedef void (*VoidFunc)(void *data); + +typedef const char * (*SimpleFunc)(void *data, int a, double b); + +typedef double (*ComplexFunc)(void *data, const char * c, const char * d); + +typedef void (*FuncAsArgFunc)(void *data, void *cb_data, VoidFunc cb, Eina_Free_Cb cb_free_cb, void *another_cb_data, SimpleFunc another_cb, Eina_Free_Cb another_cb_free_cb); + + +#endif + +#endif diff --git a/src/tests/eolian/eolian_generation.c b/src/tests/eolian/eolian_generation.c index fe4e55121e..a6f630165b 100644 --- a/src/tests/eolian/eolian_generation.c +++ b/src/tests/eolian/eolian_generation.c @@ -186,6 +186,37 @@ START_TEST(eolian_docs) } END_TEST +START_TEST(eolian_function_pointers) +{ + + // .eot + char output_filepath[PATH_MAX] = ""; + snprintf(output_filepath, PATH_MAX, "%s/eolian_function_pointers", + eina_environment_tmp_get()); + _remove_ref(output_filepath, "h"); + fail_if(0 != _eolian_gen_execute(PACKAGE_DATA_DIR"/data/function_types.eot", "-gh", output_filepath)); + fail_if(!_files_compare(PACKAGE_DATA_DIR"/data/function_types_ref.h", output_filepath, "h")); + + // .eo.h + _remove_ref(output_filepath, "h"); + fail_if(0 != _eolian_gen_execute(PACKAGE_DATA_DIR"/data/function_as_argument.eo", "-gh", output_filepath)); + fail_if(!_files_compare(PACKAGE_DATA_DIR"/data/function_as_argument_ref.h", output_filepath, "h")); + + // .eo.c + _remove_ref(output_filepath, "c"); + fail_if(0 != _eolian_gen_execute(PACKAGE_DATA_DIR"/data/function_as_argument.eo", "-gc", output_filepath)); + fail_if(!_files_compare(PACKAGE_DATA_DIR"/data/function_as_argument_ref.c", output_filepath, "c")); + + // .eo.imp.c + _remove_ref(output_filepath, "c"); + fail_if(0 != _eolian_gen_execute(PACKAGE_DATA_DIR"/data/function_as_argument.eo", "-gi", output_filepath)); + fail_if(!_files_compare(PACKAGE_DATA_DIR"/data/function_as_argument_impl_ref.c", output_filepath, "c")); + /* Check that nothing is added */ + fail_if(0 != _eolian_gen_execute(PACKAGE_DATA_DIR"/data/function_as_argument.eo", "-gi", output_filepath)); + fail_if(!_files_compare(PACKAGE_DATA_DIR"/data/function_as_argument_impl_ref.c", output_filepath, "c")); +} +END_TEST + void eolian_generation_test(TCase *tc) { tcase_add_test(tc, eolian_types_generation); @@ -195,4 +226,5 @@ void eolian_generation_test(TCase *tc) tcase_add_test(tc, eolian_functions_descriptions); tcase_add_test(tc, eolian_import); tcase_add_test(tc, eolian_docs); + tcase_add_test(tc, eolian_function_pointers); } diff --git a/src/tests/eolian/eolian_parsing.c b/src/tests/eolian/eolian_parsing.c index 33acd989f5..e16e6b1c97 100644 --- a/src/tests/eolian/eolian_parsing.c +++ b/src/tests/eolian/eolian_parsing.c @@ -1387,6 +1387,172 @@ START_TEST(eolian_docs) } END_TEST +START_TEST(eolian_function_types) +{ + const Eolian_Typedecl *decl = NULL; + const Eolian_Typedecl *arg_decl = NULL; + const Eolian_Type *type = NULL; + const Eolian_Function *fid = NULL; + const Eolian_Function_Parameter *param = NULL; + const Eolian_Unit *unit = NULL; + Eina_Iterator *iter = NULL; + const char* type_name = NULL; + void *dummy; + + eolian_init(); + + fail_if(!eolian_directory_scan(PACKAGE_DATA_DIR"/data")); + + /* Parsing */ + fail_if(!(unit = eolian_file_parse(PACKAGE_DATA_DIR"/data/function_types.eot"))); + + /* void func(void); */ + fail_if(!(decl = eolian_typedecl_alias_get_by_name(unit, "VoidFunc"))); + fail_if(eolian_typedecl_type_get(decl) != EOLIAN_TYPEDECL_FUNCTION_POINTER); + + fail_if(!(fid = eolian_typedecl_function_pointer_get(decl))); + fail_if(eolian_function_type_get(fid) != EOLIAN_FUNCTION_POINTER); + + fail_if((eolian_function_return_type_get(fid, EOLIAN_FUNCTION_POINTER))); // void is null_return_type? + fail_if((eolian_function_parameters_get(fid))); + + /* Function pointer with return and parameters */ + fail_if(!(decl = eolian_typedecl_alias_get_by_name(unit, "SimpleFunc"))); + fail_if(eolian_typedecl_type_get(decl) != EOLIAN_TYPEDECL_FUNCTION_POINTER); + + fail_if(!(fid = eolian_typedecl_function_pointer_get(decl))); + fail_if(eolian_function_type_get(fid) != EOLIAN_FUNCTION_POINTER); + fail_if(strcmp(eolian_function_name_get(fid), "SimpleFunc")); + + fail_if(!(type = eolian_function_return_type_get(fid, EOLIAN_FUNCTION_POINTER))); // void is null_return_type? + fail_if(!(type_name = eolian_type_c_type_get(type))); + fail_if(strcmp(type_name, "const char *")); + fail_if(!(iter = (eolian_function_parameters_get(fid)))); + + fail_if(!(eina_iterator_next(iter, (void**)¶m))); + fail_if(strcmp(eolian_parameter_name_get(param), "a")); + fail_if(!(type = eolian_parameter_type_get(param))); + fail_if(!(type_name = eolian_type_c_type_get(type))); + fail_if(strcmp(type_name, "int")); + + fail_if(!(eina_iterator_next(iter, (void**)¶m))); + fail_if(strcmp(eolian_parameter_name_get(param), "b")); + fail_if(!(type = eolian_parameter_type_get(param))); + fail_if(!(type_name = eolian_type_c_type_get(type))); + fail_if(strcmp(type_name, "double")); + + fail_if(eina_iterator_next(iter, &dummy)); + + /* Function pointer with parameter attributes (in/out) */ + fail_if(!(decl = eolian_typedecl_alias_get_by_name(unit, "ComplexFunc"))); + fail_if(eolian_typedecl_type_get(decl) != EOLIAN_TYPEDECL_FUNCTION_POINTER); + + fail_if(!(fid = eolian_typedecl_function_pointer_get(decl))); + fail_if(eolian_function_type_get(fid) != EOLIAN_FUNCTION_POINTER); + + fail_if(!(type = eolian_function_return_type_get(fid, EOLIAN_FUNCTION_POINTER))); + fail_if(!(type_name = eolian_type_c_type_get(type))); + fail_if(strcmp(type_name, "double")); + fail_if(!(iter = (eolian_function_parameters_get(fid)))); + + /* in string */ + fail_if(!(eina_iterator_next(iter, (void**)¶m))); + fail_if(strcmp(eolian_parameter_name_get(param), "c")); + fail_if(!(type = eolian_parameter_type_get(param))); + fail_if(eolian_parameter_direction_get(param) != EOLIAN_IN_PARAM); + fail_if(eolian_type_is_own(type)); + fail_if(!(type_name = eolian_type_c_type_get(type))); + fail_if(strcmp(type_name, "const char *")); + + /*out own string */ + fail_if(!(eina_iterator_next(iter, (void**)¶m))); + fail_if(strcmp(eolian_parameter_name_get(param), "d")); + fail_if(eolian_parameter_direction_get(param) != EOLIAN_OUT_PARAM); + fail_if(!(type = eolian_parameter_type_get(param))); + fail_if(!eolian_type_is_own(type)); + fail_if(!(type_name = eolian_type_c_type_get(type))); + fail_if(strcmp(type_name, "const char *")); + + fail_if(eina_iterator_next(iter, &dummy)); + + /* Function pointer receiving another function pointer */ + fail_if(!(decl = eolian_typedecl_alias_get_by_name(unit, "FuncAsArgFunc"))); + fail_if(eolian_typedecl_type_get(decl) != EOLIAN_TYPEDECL_FUNCTION_POINTER); + + fail_if(!(fid = eolian_typedecl_function_pointer_get(decl))); + fail_if(eolian_function_type_get(fid) != EOLIAN_FUNCTION_POINTER); + + fail_if(eolian_function_return_type_get(fid, EOLIAN_FUNCTION_POINTER)); + + fail_if(!(iter = (eolian_function_parameters_get(fid)))); + + fail_if(!(eina_iterator_next(iter, (void**)¶m))); + fail_if(strcmp(eolian_parameter_name_get(param), "cb")); + fail_if(!(type = eolian_parameter_type_get(param))); + fail_if(eolian_parameter_direction_get(param) != EOLIAN_IN_PARAM); + fail_if(eolian_type_is_own(type)); + fail_if(!(type_name = eolian_type_name_get(type))); + fail_if(strcmp(type_name, "VoidFunc")); + fail_if(!(arg_decl = eolian_type_typedecl_get(type))); + fail_if(eolian_typedecl_type_get(arg_decl) != EOLIAN_TYPEDECL_FUNCTION_POINTER); + + fail_if(!(eina_iterator_next(iter, (void**)¶m))); + fail_if(strcmp(eolian_parameter_name_get(param), "another_cb")); + fail_if(eolian_parameter_direction_get(param) != EOLIAN_IN_PARAM); + fail_if(!(type = eolian_parameter_type_get(param))); + fail_if(eolian_type_is_own(type)); + fail_if(eolian_type_type_get(type) != EOLIAN_TYPE_REGULAR); + fail_if(!(type_name = eolian_type_name_get(type))); + fail_if(strcmp(type_name, "SimpleFunc")); + fail_if(!(arg_decl = eolian_type_typedecl_get(type))); + fail_if(eolian_typedecl_type_get(arg_decl) != EOLIAN_TYPEDECL_FUNCTION_POINTER); + + fail_if(eina_iterator_next(iter, &dummy)); + + eolian_shutdown(); +} +END_TEST + +START_TEST(eolian_function_as_arguments) +{ + const Eolian_Class *cls = NULL; + const Eolian_Function *fid = NULL; + const Eolian_Type *type = NULL; + const Eolian_Typedecl *arg_decl = NULL; + const Eolian_Function_Parameter *param = NULL; + const Eolian_Unit *unit = NULL; + Eina_Iterator *iter = NULL; + const char *type_name = NULL; + void *dummy; + + eolian_init(); + + fail_if(!eolian_directory_scan(PACKAGE_DATA_DIR"/data")); + + fail_if(!(unit = eolian_file_parse(PACKAGE_DATA_DIR"/data/function_as_argument.eo"))); + + fail_if(!(cls = eolian_class_get_by_name(unit, "Function_As_Argument"))); + + fail_if(!(fid = eolian_class_function_get_by_name(cls, "set_cb", EOLIAN_METHOD))); + + fail_if(!(iter = (eolian_function_parameters_get(fid)))); + + fail_if(!(eina_iterator_next(iter, (void**)¶m))); + fail_if(strcmp(eolian_parameter_name_get(param), "cb")); + fail_if(!(type = eolian_parameter_type_get(param))); + fail_if(eolian_parameter_direction_get(param) != EOLIAN_IN_PARAM); + fail_if(eolian_type_is_own(type)); + fail_if(!(type_name = eolian_type_name_get(type))); + fail_if(strcmp(type_name, "SimpleFunc")); + fail_if(!(arg_decl = eolian_type_typedecl_get(type))); + fail_if(eolian_typedecl_type_get(arg_decl) != EOLIAN_TYPEDECL_FUNCTION_POINTER); + + fail_if(eina_iterator_next(iter, &dummy)); + + eolian_shutdown(); +} +END_TEST + void eolian_parsing_test(TCase *tc) { tcase_add_test(tc, eolian_simple_parsing); @@ -1408,4 +1574,6 @@ void eolian_parsing_test(TCase *tc) tcase_add_test(tc, eolian_import); tcase_add_test(tc, eolian_decl); tcase_add_test(tc, eolian_docs); + tcase_add_test(tc, eolian_function_types); + tcase_add_test(tc, eolian_function_as_arguments); } --