eolian gen: initial support for reflection api
authorDaniel Kolesa <d.kolesa@samsung.com>
Fri, 15 Feb 2019 16:15:36 +0000 (17:15 +0100)
committerWonki Kim <wonki_.kim@samsung.com>
Fri, 8 Mar 2019 11:49:34 +0000 (20:49 +0900)
This adds support for generating reflection functions for
properties. This support is basic for now, supporting only
primitive types and string(shares), it will be expanded later
as required.

@feature

src/bin/eolian/sources.c
src/tests/eolian/data/class_simple_ref.c
src/tests/eolian/data/function_as_argument_ref.c
src/tests/eolian/data/override_ref.c
src/tests/eolian/data/owning.eo.c

index be19f0e..6e72655 100644 (file)
@@ -322,6 +322,112 @@ _gen_function_param_fallback(Eina_Iterator *itr, Eina_Strbuf *fallback_free_owne
    return owners;
 }
 
+static const char *
+_get_reflect_initf(const Eolian_Type *abtp)
+{
+   Eolian_Type_Builtin_Type btp = eolian_type_builtin_type_get(abtp);
+   const char *initf = NULL;
+   switch (btp)
+     {
+      case EOLIAN_TYPE_BUILTIN_BYTE:
+      case EOLIAN_TYPE_BUILTIN_CHAR:
+        initf = "char"; break;
+      case EOLIAN_TYPE_BUILTIN_UBYTE:
+        initf = "uchar"; break;
+      case EOLIAN_TYPE_BUILTIN_SHORT:
+      case EOLIAN_TYPE_BUILTIN_USHORT:
+      case EOLIAN_TYPE_BUILTIN_INT:
+      case EOLIAN_TYPE_BUILTIN_UINT:
+      case EOLIAN_TYPE_BUILTIN_LONG:
+      case EOLIAN_TYPE_BUILTIN_ULONG:
+      case EOLIAN_TYPE_BUILTIN_INT64:
+      case EOLIAN_TYPE_BUILTIN_UINT64:
+      case EOLIAN_TYPE_BUILTIN_TIME:
+      case EOLIAN_TYPE_BUILTIN_FLOAT:
+      case EOLIAN_TYPE_BUILTIN_DOUBLE:
+      case EOLIAN_TYPE_BUILTIN_BOOL:
+      case EOLIAN_TYPE_BUILTIN_STRING:
+      case EOLIAN_TYPE_BUILTIN_STRINGSHARE:
+        initf = eolian_type_name_get(abtp); break;
+      default:
+        break;
+     }
+   return initf;
+}
+
+static void
+_gen_reflect_get(Eina_Strbuf *buf, const char *cnamel, const Eolian_Type *valt,
+                 const Eolian_Function *fid, Eina_Hash *refh)
+{
+   if (eolian_type_is_ptr(valt))
+     return;
+
+   const Eolian_Type *abtp = eolian_type_aliased_base_get(valt);
+   const char *initf = _get_reflect_initf(abtp);
+   if (!initf)
+     return;
+
+   Eolian_Function_Type et = (Eolian_Function_Type)eina_hash_find(refh, &fid);
+   if (et == EOLIAN_PROP_SET)
+     eina_hash_set(refh, &fid, (void *)EOLIAN_PROPERTY);
+   else
+     eina_hash_set(refh, &fid, (void *)EOLIAN_PROP_GET);
+
+   eina_strbuf_append(buf, "\nstatic Eina_Value\n");
+   eina_strbuf_append_printf(buf, "__eolian_%s_%s_get_reflect(Eo *obj)\n",
+     cnamel, eolian_function_name_get(fid));
+   eina_strbuf_append(buf, "{\n");
+
+   Eina_Stringshare *ct = eolian_type_c_type_get(valt, EOLIAN_C_TYPE_RETURN);
+   const char *starsp = (ct[strlen(ct) - 1] != '*') ? " " : "";
+
+   Eina_Stringshare *fcn = eolian_function_full_c_name_get(fid, EOLIAN_PROP_GET, EINA_FALSE);
+   eina_strbuf_append_printf(buf, "   %s%sval = %s(obj);\n", ct, starsp, fcn);
+   eina_stringshare_del(fcn);
+   eina_stringshare_del(ct);
+
+   eina_strbuf_append_printf(buf, "   return eina_value_%s_init(val);\n", initf);
+   eina_strbuf_append(buf, "}\n\n");
+}
+
+static void
+_gen_reflect_set(Eina_Strbuf *buf, const char *cnamel, const Eolian_Type *valt,
+                 const Eolian_Function *fid, Eina_Hash *refh)
+{
+   if (eolian_type_is_ptr(valt))
+     return;
+
+   const Eolian_Type *abtp = eolian_type_aliased_base_get(valt);
+   const char *initf = _get_reflect_initf(abtp);
+   if (!initf)
+     return;
+
+   Eolian_Function_Type et = (Eolian_Function_Type)eina_hash_find(refh, &fid);
+   if (et == EOLIAN_PROP_GET)
+     eina_hash_set(refh, &fid, (void *)EOLIAN_PROPERTY);
+   else
+     eina_hash_set(refh, &fid, (void *)EOLIAN_PROP_SET);
+
+   eina_strbuf_append(buf, "\nstatic void\n");
+   eina_strbuf_append_printf(buf, "__eolian_%s_%s_set_reflect(Eo *obj, Eina_Value val)\n",
+     cnamel, eolian_function_name_get(fid));
+   eina_strbuf_append(buf, "{\n");
+
+   Eina_Stringshare *ct = eolian_type_c_type_get(valt, EOLIAN_C_TYPE_PARAM);
+   const char *starsp = (ct[strlen(ct) - 1] != '*') ? " " : "";
+   eina_strbuf_append_printf(buf, "   %s%scval;\n", ct, starsp);
+   eina_stringshare_del(ct);
+
+   eina_strbuf_append_printf(buf, "   eina_value_%s_convert(&val, &cval);\n", initf);
+
+   Eina_Stringshare *fcn = eolian_function_full_c_name_get(fid, EOLIAN_PROP_SET, EINA_FALSE);
+   eina_strbuf_append_printf(buf, "   %s(obj, cval);\n", fcn);
+   eina_stringshare_del(fcn);
+
+   eina_strbuf_append(buf, "   eina_value_flush(&val);\n");
+
+   eina_strbuf_append(buf, "}\n\n");
+}
 
 static void
 _emit_class_function(Eina_Strbuf *buf, const Eolian_Function *fid, const Eolian_Type *rtp, Eina_Strbuf *params_full,
@@ -359,7 +465,8 @@ _emit_class_function(Eina_Strbuf *buf, const Eolian_Function *fid, const Eolian_
 static void
 _gen_func(const Eolian_Class *cl, const Eolian_Function *fid,
           Eolian_Function_Type ftype, Eina_Strbuf *buf,
-          const Eolian_Implement *impl, Eina_Strbuf *lbuf)
+          const Eolian_Implement *impl, Eina_Strbuf *lbuf,
+          Eina_Hash *refh)
 {
    Eina_Bool is_empty = eolian_implement_is_empty(impl, ftype);
    Eina_Bool is_auto = eolian_implement_is_auto(impl, ftype);
@@ -369,6 +476,8 @@ _gen_func(const Eolian_Class *cl, const Eolian_Function *fid,
 
    Eina_Bool is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET);
    Eina_Bool var_as_ret = EINA_FALSE;
+   /* assume we're not generating reflection api by default */
+   const Eolian_Type *reflect_type = NULL;
 
    const Eolian_Expression *def_ret = NULL;
    const Eolian_Type *rtp = eolian_function_return_type_get(fid, ftype);
@@ -390,6 +499,8 @@ _gen_func(const Eolian_Class *cl, const Eolian_Function *fid,
                {
                   Eolian_Function_Parameter *pr = d1;
                   rtp = eolian_parameter_type_get(pr);
+                  /* reflect only when returning 1 val */
+                  reflect_type = rtp;
                   var_as_ret = EINA_TRUE;
                   def_ret = eolian_parameter_default_value_get(pr);
                }
@@ -397,7 +508,18 @@ _gen_func(const Eolian_Class *cl, const Eolian_Function *fid,
           }
      }
    else if (ftype == EOLIAN_PROP_SET)
-     func_suffix = "_set";
+     {
+        func_suffix = "_set";
+        Eina_Iterator *itr = eolian_property_values_get(fid, ftype);
+        void *d1, *d2;
+        /* reflect with 1 value */
+        if (eina_iterator_next(itr, &d1) && !eina_iterator_next(itr, &d2))
+          {
+             Eolian_Function_Parameter *pr = d1;
+             reflect_type = eolian_parameter_type_get(pr);
+          }
+        eina_iterator_free(itr);
+     }
 
    Eina_Strbuf *params = eina_strbuf_new(); /* par1, par2, par3, ... */
    Eina_Strbuf *params_full = eina_strbuf_new(); /* T par1, U par2, ... for decl */
@@ -408,6 +530,8 @@ _gen_func(const Eolian_Class *cl, const Eolian_Function *fid,
    /* property keys */
    {
       Eina_Iterator *itr = eolian_property_keys_get(fid, ftype);
+      if (itr) /* has keys: no reflection */
+        reflect_type = NULL;
       Eolian_Function_Parameter *pr;
       EINA_ITERATOR_FOREACH(itr, pr)
         {
@@ -683,6 +807,15 @@ _gen_func(const Eolian_Class *cl, const Eolian_Function *fid,
 
    if (impl_same_class && !eolian_function_is_class(fid))
      {
+        /* generate reflection implementation */
+        if (reflect_type)
+          {
+             if (ftype == EOLIAN_PROP_GET)
+               _gen_reflect_get(buf, cnamel, reflect_type, fid, refh);
+             else
+               _gen_reflect_set(buf, cnamel, reflect_type, fid, refh);
+          }
+
         void *data;
         Eina_Iterator *itr = eolian_property_keys_get(fid, ftype);
         Eina_Bool has_params = eina_iterator_next(itr, &data);
@@ -843,7 +976,33 @@ _gen_opfunc(const Eolian_Function *fid, Eolian_Function_Type ftype,
 }
 
 static void
-_gen_initializer(const Eolian_Class *cl, Eina_Strbuf *buf)
+_gen_reflop(const Eolian_Function *fid, Eina_Strbuf *buf, const char *cnamel, Eina_Hash *refh)
+{
+   Eolian_Function_Type aftype = (Eolian_Function_Type)eina_hash_find(refh, &fid);
+   if (aftype == EOLIAN_UNRESOLVED)
+     return;
+
+   eina_strbuf_append_printf(buf, "      {\"%s\", ", eolian_function_name_get(fid));
+
+   if (aftype == EOLIAN_PROP_SET || aftype == EOLIAN_PROPERTY)
+     {
+        eina_strbuf_append_printf(buf, "__eolian_%s_%s_set_reflect, ",
+          cnamel, eolian_function_name_get(fid));
+     }
+   else
+     eina_strbuf_append(buf, "NULL, ");
+
+   if (aftype == EOLIAN_PROP_GET || aftype == EOLIAN_PROPERTY)
+     {
+        eina_strbuf_append_printf(buf, "__eolian_%s_%s_get_reflect},\n",
+          cnamel, eolian_function_name_get(fid));
+     }
+   else
+     eina_strbuf_append(buf, "NULL},\n");
+}
+
+static void
+_gen_initializer(const Eolian_Class *cl, Eina_Strbuf *buf, Eina_Hash *refh)
 {
    char *cnamel = NULL, *cnameu = NULL;
    eo_gen_class_names_get(cl, NULL, &cnameu, &cnamel);
@@ -852,8 +1011,10 @@ _gen_initializer(const Eolian_Class *cl, Eina_Strbuf *buf)
    eina_strbuf_append(buf, cnamel);
    eina_strbuf_append(buf, "_class_initializer(Efl_Class *klass)\n{\n");
    eina_strbuf_append(buf, "   const Efl_Object_Ops *opsp = NULL;\n\n");
+   eina_strbuf_append(buf, "   const Efl_Object_Property_Reflection_Ops *ropsp = NULL;\n\n");
 
    Eina_Strbuf *ops = eina_strbuf_new();
+   Eina_Strbuf *refls = eina_strbuf_new();
 
    /* start over with clean itearator */
    const Eolian_Implement *imp;
@@ -866,10 +1027,8 @@ _gen_initializer(const Eolian_Class *cl, Eina_Strbuf *buf)
 
         if (eolian_function_is_class(fid)) continue;
 
-        Eina_Strbuf *obuf = ops;
-
-        if (!eina_strbuf_length_get(obuf))
-          eina_strbuf_append_printf(obuf, "   EFL_OPS_DEFINE(ops,\n");
+        if (!eina_strbuf_length_get(ops))
+          eina_strbuf_append_printf(ops, "   EFL_OPS_DEFINE(ops,\n");
 
         Eina_Bool found_get = !!eina_hash_find(_funcs_params_init_get, &imp);
         Eina_Bool found_set = !!eina_hash_find(_funcs_params_init_set, &imp);
@@ -880,17 +1039,20 @@ _gen_initializer(const Eolian_Class *cl, Eina_Strbuf *buf)
         switch (ftype)
           {
            case EOLIAN_PROP_GET:
-             _gen_opfunc(fid, EOLIAN_PROP_GET, obuf, imp, found_get, cnamel, ocnamel);
+             _gen_opfunc(fid, EOLIAN_PROP_GET, ops, imp, found_get, cnamel, ocnamel);
+             _gen_reflop(fid, refls, cnamel, refh);
              break;
            case EOLIAN_PROP_SET:
-             _gen_opfunc(fid, EOLIAN_PROP_SET, obuf, imp, found_set, cnamel, ocnamel);
+             _gen_opfunc(fid, EOLIAN_PROP_SET, ops, imp, found_set, cnamel, ocnamel);
+             _gen_reflop(fid, refls, cnamel, refh);
              break;
            case EOLIAN_PROPERTY:
-             _gen_opfunc(fid, EOLIAN_PROP_SET, obuf, imp, found_set, cnamel, ocnamel);
-             _gen_opfunc(fid, EOLIAN_PROP_GET, obuf, imp, found_get, cnamel, ocnamel);
+             _gen_opfunc(fid, EOLIAN_PROP_SET, ops, imp, found_set, cnamel, ocnamel);
+             _gen_opfunc(fid, EOLIAN_PROP_GET, ops, imp, found_get, cnamel, ocnamel);
+             _gen_reflop(fid, refls, cnamel, refh);
              break;
            default:
-             _gen_opfunc(fid, EOLIAN_METHOD, obuf, imp, found_get, cnamel, ocnamel);
+             _gen_opfunc(fid, EOLIAN_METHOD, ops, imp, found_get, cnamel, ocnamel);
              break;
           }
 
@@ -918,7 +1080,18 @@ _gen_initializer(const Eolian_Class *cl, Eina_Strbuf *buf)
         eina_strbuf_append(buf, "#endif\n\n");
      }
 
-   eina_strbuf_append(buf, "   return efl_class_functions_set(klass, opsp, NULL);\n");
+   if (eina_strbuf_length_get(refls))
+     {
+        eina_strbuf_append(buf, "   static const Efl_Object_Property_Reflection refl_table[] = {\n");
+        eina_strbuf_append_buffer(buf, refls);
+        eina_strbuf_append(buf, "   };\n");
+        eina_strbuf_append(buf, "   static const Efl_Object_Property_Reflection_Ops rops = {\n");
+        eina_strbuf_append(buf, "      refl_table, EINA_C_ARRAY_LENGTH(refl_table)\n");
+        eina_strbuf_append(buf, "   };\n");
+        eina_strbuf_append(buf, "   ropsp = &rops;\n\n");
+     }
+
+   eina_strbuf_append(buf, "   return efl_class_functions_set(klass, opsp, ropsp);\n");
 
    eina_strbuf_free(ops);
 
@@ -962,6 +1135,11 @@ eo_gen_source_gen(const Eolian_Class *cl, Eina_Strbuf *buf)
 
    Eina_Strbuf *lbuf = eina_strbuf_new();
 
+   /* Eolian_Function -> Eolian_Function_Type
+    * maps which parts of which functions are qualified for reflection
+    */
+   Eina_Hash *refh = eina_hash_pointer_new(NULL);
+
    /* method section */
    {
       Eina_Iterator *itr = eolian_class_implements_get(cl);
@@ -974,21 +1152,22 @@ eo_gen_source_gen(const Eolian_Class *cl, Eina_Strbuf *buf)
              {
               case EOLIAN_PROP_GET:
               case EOLIAN_PROP_SET:
-                _gen_func(cl, fid, ftype, buf, imp, lbuf);
+                _gen_func(cl, fid, ftype, buf, imp, lbuf, refh);
                 break;
               case EOLIAN_PROPERTY:
-                _gen_func(cl, fid, EOLIAN_PROP_SET, buf, imp, lbuf);
-                _gen_func(cl, fid, EOLIAN_PROP_GET, buf, imp, lbuf);
+                _gen_func(cl, fid, EOLIAN_PROP_SET, buf, imp, lbuf, refh);
+                _gen_func(cl, fid, EOLIAN_PROP_GET, buf, imp, lbuf, refh);
                 break;
               default:
-                _gen_func(cl, fid, EOLIAN_METHOD, buf, imp, lbuf);
+                _gen_func(cl, fid, EOLIAN_METHOD, buf, imp, lbuf, refh);
              }
         }
       eina_iterator_free(itr);
    }
 
    /* class initializer - contains method defs */
-   _gen_initializer(cl, buf);
+   _gen_initializer(cl, buf, refh);
+   eina_hash_free(refh);
 
    /* class description */
    eina_strbuf_append(buf, "static const Efl_Class_Description _");
index 431f083..3bf9d20 100644 (file)
@@ -2,10 +2,28 @@ EWAPI float BAR = 10.300000f;
 
 Eina_Bool _class_simple_a_set(Eo *obj, Evas_Simple_Data *pd, int value);
 
+
+static void
+__eolian_class_simple_a_set_reflect(Eo *obj, Eina_Value val)
+{
+   int cval;
+   eina_value_int_convert(&val, &cval);
+   efl_canvas_object_simple_a_set(obj, cval);
+   eina_value_flush(&val);
+}
+
 EOAPI EFL_FUNC_BODYV(efl_canvas_object_simple_a_set, Eina_Bool, EINA_TRUE /* true */, EFL_FUNC_CALL(value), int value);
 
 int _class_simple_a_get(const Eo *obj, Evas_Simple_Data *pd);
 
+
+static Eina_Value
+__eolian_class_simple_a_get_reflect(Eo *obj)
+{
+   int val = efl_canvas_object_simple_a_get(obj);
+   return eina_value_int_init(val);
+}
+
 EOAPI EFL_FUNC_BODY_CONST(efl_canvas_object_simple_a_get, int, 100);
 
 void _class_simple_b_set(Eo *obj, Evas_Simple_Data *pd);
@@ -31,6 +49,8 @@ _class_simple_class_initializer(Efl_Class *klass)
 {
    const Efl_Object_Ops *opsp = NULL;
 
+   const Efl_Object_Property_Reflection_Ops *ropsp = NULL;
+
 #ifndef CLASS_SIMPLE_EXTRA_OPS
 #define CLASS_SIMPLE_EXTRA_OPS
 #endif
@@ -45,7 +65,15 @@ _class_simple_class_initializer(Efl_Class *klass)
    );
    opsp = &ops;
 
-   return efl_class_functions_set(klass, opsp, NULL);
+   static const Efl_Object_Property_Reflection refl_table[] = {
+      {"a", __eolian_class_simple_a_set_reflect, __eolian_class_simple_a_get_reflect},
+   };
+   static const Efl_Object_Property_Reflection_Ops rops = {
+      refl_table, EINA_C_ARRAY_LENGTH(refl_table)
+   };
+   ropsp = &rops;
+
+   return efl_class_functions_set(klass, opsp, ropsp);
 }
 
 static const Efl_Class_Description _class_simple_class_desc = {
index edb394e..0c00260 100644 (file)
@@ -16,6 +16,8 @@ _function_as_argument_class_initializer(Efl_Class *klass)
 {
    const Efl_Object_Ops *opsp = NULL;
 
+   const Efl_Object_Property_Reflection_Ops *ropsp = NULL;
+
 #ifndef FUNCTION_AS_ARGUMENT_EXTRA_OPS
 #define FUNCTION_AS_ARGUMENT_EXTRA_OPS
 #endif
@@ -28,7 +30,7 @@ _function_as_argument_class_initializer(Efl_Class *klass)
    );
    opsp = &ops;
 
-   return efl_class_functions_set(klass, opsp, NULL);
+   return efl_class_functions_set(klass, opsp, ropsp);
 }
 
 static const Efl_Class_Description _function_as_argument_class_desc = {
index 729f37e..dbbbbae 100644 (file)
@@ -61,6 +61,8 @@ _override_class_initializer(Efl_Class *klass)
 {
    const Efl_Object_Ops *opsp = NULL;
 
+   const Efl_Object_Property_Reflection_Ops *ropsp = NULL;
+
 #ifndef OVERRIDE_EXTRA_OPS
 #define OVERRIDE_EXTRA_OPS
 #endif
@@ -81,7 +83,7 @@ _override_class_initializer(Efl_Class *klass)
    );
    opsp = &ops;
 
-   return efl_class_functions_set(klass, opsp, NULL);
+   return efl_class_functions_set(klass, opsp, ropsp);
 }
 
 static const Efl_Class_Description _override_class_desc = {
index 7e50483..3df14c9 100644 (file)
@@ -45,6 +45,8 @@ _owning_class_initializer(Efl_Class *klass)
 {
    const Efl_Object_Ops *opsp = NULL;
 
+   const Efl_Object_Property_Reflection_Ops *ropsp = NULL;
+
 #ifndef OWNING_EXTRA_OPS
 #define OWNING_EXTRA_OPS
 #endif
@@ -56,7 +58,7 @@ _owning_class_initializer(Efl_Class *klass)
    );
    opsp = &ops;
 
-   return efl_class_functions_set(klass, opsp, NULL);
+   return efl_class_functions_set(klass, opsp, ropsp);
 }
 
 static const Efl_Class_Description _owning_class_desc = {