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**)&param)));
+   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**)&param)));
+   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**)&param)));
+   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**)&param)));
+   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**)&param)));
+   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**)&param)));
+   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**)&param)));
+   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);
 }

-- 


Reply via email to