diff --git a/src/bin/eolian/sources.c b/src/bin/eolian/sources.c index 76f8c64725..e4491a22b3 100644 --- a/src/bin/eolian/sources.c +++ b/src/bin/eolian/sources.c @@ -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 _"); diff --git a/src/tests/eolian/data/class_simple_ref.c b/src/tests/eolian/data/class_simple_ref.c index 431f083952..3bf9d2063b 100644 --- a/src/tests/eolian/data/class_simple_ref.c +++ b/src/tests/eolian/data/class_simple_ref.c @@ -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 = { diff --git a/src/tests/eolian/data/function_as_argument_ref.c b/src/tests/eolian/data/function_as_argument_ref.c index edb394ed67..0c00260e09 100644 --- a/src/tests/eolian/data/function_as_argument_ref.c +++ b/src/tests/eolian/data/function_as_argument_ref.c @@ -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 = { diff --git a/src/tests/eolian/data/override_ref.c b/src/tests/eolian/data/override_ref.c index 729f37e6c4..dbbbbae263 100644 --- a/src/tests/eolian/data/override_ref.c +++ b/src/tests/eolian/data/override_ref.c @@ -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 = { diff --git a/src/tests/eolian/data/owning.eo.c b/src/tests/eolian/data/owning.eo.c index 7e504833c9..3df14c9098 100644 --- a/src/tests/eolian/data/owning.eo.c +++ b/src/tests/eolian/data/owning.eo.c @@ -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 = {