eolian gen: initial support for reflection api

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
This commit is contained in:
Daniel Kolesa 2019-02-15 17:15:36 +01:00
parent 4935202caa
commit 8952c05ddd
5 changed files with 235 additions and 22 deletions

View File

@ -322,11 +322,118 @@ _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
_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);
@ -336,6 +443,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);
@ -357,6 +466,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);
}
@ -364,7 +475,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 */
@ -375,6 +497,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)
{
@ -650,6 +774,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);
@ -832,7 +965,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);
@ -841,8 +1000,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;
@ -855,10 +1016,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);
@ -869,17 +1028,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;
}
@ -907,7 +1069,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);
@ -951,6 +1124,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);
@ -963,21 +1141,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 _");

View 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 = {

View 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 = {

View 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 = {

View 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 = {