diff options
author | Daniel Kolesa <d.kolesa@osg.samsung.com> | 2016-09-23 17:49:44 +0200 |
---|---|---|
committer | Daniel Kolesa <d.kolesa@osg.samsung.com> | 2016-10-07 11:54:23 +0200 |
commit | 6c4d705d55947a3ec22cdb8cf6337b7ab2548145 (patch) | |
tree | ef9d06a91f8c039f421f4499347b8fa5f40b3acd /src | |
parent | 56cd773836278bbb78708fd526c1f0fda7e801c8 (diff) | |
download | efl-6c4d705d55947a3ec22cdb8cf6337b7ab2548145.tar.gz |
eolian gen2: initial partial source generation
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/eolian2/headers.c | 17 | ||||
-rw-r--r-- | src/bin/eolian2/main.c | 41 | ||||
-rw-r--r-- | src/bin/eolian2/main.h | 2 | ||||
-rw-r--r-- | src/bin/eolian2/sources.c | 436 |
4 files changed, 481 insertions, 15 deletions
diff --git a/src/bin/eolian2/headers.c b/src/bin/eolian2/headers.c index 0b1247d3fc..fa18a4614d 100644 --- a/src/bin/eolian2/headers.c +++ b/src/bin/eolian2/headers.c @@ -199,20 +199,8 @@ eo_gen_header_gen(const Eolian_Class *cl, Eina_Strbuf *buf, Eina_Bool legacy) return; char *cname = NULL, *cnameu = NULL, *cnamel = NULL; - - cname = eo_gen_c_full_name_get(eolian_class_full_name_get(cl)); - if (!cname) - goto end; - - cnameu = strdup(cname); - if (!cnameu) - goto end; - eina_str_toupper(&cnameu); - - cnamel = strdup(cname); - if (!cnamel) - goto end; - eina_str_tolower(&cnamel); + if (!eo_gen_class_names_get(cl, &cname, &cnameu, &cnamel)) + return; /* class definition */ @@ -319,7 +307,6 @@ events: eina_iterator_free(itr); } -end: free(cname); free(cnameu); free(cnamel); diff --git a/src/bin/eolian2/main.c b/src/bin/eolian2/main.c index a2e0e34e1e..18985e8a1f 100644 --- a/src/bin/eolian2/main.c +++ b/src/bin/eolian2/main.c @@ -233,6 +233,47 @@ char *eo_gen_c_full_name_get(const char *nm) return buf; } +Eina_Bool eo_gen_class_names_get(const Eolian_Class *cl, char **cname, + char **cnameu, char **cnamel) +{ + char *cn = NULL, *cnu = NULL, *cnl = NULL; + cn = eo_gen_c_full_name_get(eolian_class_full_name_get(cl)); + if (!cn) + return EINA_FALSE; + if (cname) + *cname = cn; + + if (cnameu) + { + cnu = strdup(cn); + if (!cnu) + { + free(cn); + return EINA_FALSE; + } + eina_str_toupper(&cnu); + *cnameu = cnu; + } + + if (cnamel) + { + cnl = strdup(cn); + if (!cnl) + { + free(cn); + free(cnu); + return EINA_FALSE; + } + eina_str_tolower(&cnl); + *cnamel = cnl; + } + + if (!cname) + free(cn); + + return EINA_TRUE; +} + static Eina_Bool _write_header(const char *ofname, const char *ifname, Eina_Bool legacy) { diff --git a/src/bin/eolian2/main.h b/src/bin/eolian2/main.h index 9ac6312cef..fc12597b4f 100644 --- a/src/bin/eolian2/main.h +++ b/src/bin/eolian2/main.h @@ -36,5 +36,7 @@ extern int _eolian_gen_log_dom; #define CRIT(...) EINA_LOG_DOM_CRIT(_eolian_gen_log_dom, __VA_ARGS__) char *eo_gen_c_full_name_get(const char *nm); +Eina_Bool eo_gen_class_names_get(const Eolian_Class *cl, char **cname, + char **cnameu, char **cnamel); #endif diff --git a/src/bin/eolian2/sources.c b/src/bin/eolian2/sources.c index abfd6a5c19..badc3789b3 100644 --- a/src/bin/eolian2/sources.c +++ b/src/bin/eolian2/sources.c @@ -1,12 +1,419 @@ #include "main.h" #include "docs.h" +/* Used to store the function names that will have to be appended + * with __eolian during C generation. Needed when params have to + * be initialized and for future features. + */ +static Eina_Hash *_funcs_params_init = NULL; + +static const char * +_get_add_star(Eolian_Function_Type ftype, Eolian_Parameter_Dir pdir) +{ + if (ftype == EOLIAN_PROP_GET) + return "*"; + if ((pdir == EOLIAN_OUT_PARAM) || (pdir == EOLIAN_INOUT_PARAM)) + return "*"; + return ""; +} + +static void +_gen_func(const Eolian_Class *cl, const Eolian_Function *fid, + Eolian_Function_Type ftype, Eina_Strbuf *buf, + const Eolian_Implement *impl) +{ + Eina_Bool is_empty = eolian_implement_is_empty(impl); + Eina_Bool is_auto = eolian_implement_is_auto(impl); + + if ((ftype != EOLIAN_PROP_GET) && (ftype != EOLIAN_PROP_SET)) + ftype = eolian_function_type_get(fid); + + Eina_Bool is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET); + Eina_Bool var_as_ret = EINA_FALSE; + + const Eolian_Expression *def_ret = NULL; + const Eolian_Type *rtp = eolian_function_return_type_get(fid, ftype); + if (rtp) + { + is_auto = EINA_FALSE; /* can't do auto if func returns */ + def_ret = eolian_function_return_default_value_get(fid, ftype); + } + + const char *func_suffix = ""; + if (ftype == EOLIAN_PROP_GET) + { + func_suffix = "_get"; + if (!rtp) + { + void *d1, *d2; + Eina_Iterator *itr = eolian_property_values_get(fid, ftype); + if (eina_iterator_next(itr, &d1) && !eina_iterator_next(itr, &d2)) + { + Eolian_Function_Parameter *pr = d1; + rtp = eolian_parameter_type_get(pr); + var_as_ret = EINA_TRUE; + def_ret = eolian_parameter_default_value_get(pr); + } + eina_iterator_free(itr); + } + } + else if (ftype == EOLIAN_PROP_SET) + func_suffix = "_set"; + + Eina_Strbuf *params = eina_strbuf_new(); /* par1, par2, par3, ... */ + Eina_Strbuf *params_full = eina_strbuf_new(); /* T par1, U par2, ... for decl */ + Eina_Strbuf *params_full_imp = eina_strbuf_new(); /* as above, for impl */ + Eina_Strbuf *params_init = eina_strbuf_new(); /* default value inits */ + + Eina_Bool has_promise = EINA_FALSE; + Eina_Stringshare *promise_param_name = NULL; + Eina_Stringshare *promise_param_type = NULL; + + /* property keys */ + { + Eina_Iterator *itr = eolian_property_keys_get(fid, ftype); + Eolian_Function_Parameter *pr; + EINA_ITERATOR_FOREACH(itr, pr) + { + 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); + + if (eina_strbuf_length_get(params)) + eina_strbuf_append(params, ", "); + eina_strbuf_append(params, prn); + + eina_strbuf_append_printf(params_full, ", %s %s", ptn, prn); + eina_strbuf_append_printf(params_full_imp, ", %s %s", ptn, prn); + if (is_empty) + eina_strbuf_append(params_full_imp, " EINA_UNUSED"); + + eina_stringshare_del(ptn); + } + eina_iterator_free(itr); + } + + /* property values or method params if applicable */ + if (!var_as_ret) + { + Eina_Iterator *itr; + if (is_prop) + itr = eolian_property_values_get(fid, ftype); + else + itr = eolian_function_parameters_get(fid); + Eolian_Function_Parameter *pr; + EINA_ITERATOR_FOREACH(itr, pr) + { + Eolian_Parameter_Dir pd = eolian_parameter_direction_get(pr); + const Eolian_Expression *dfv = eolian_parameter_default_value_get(pr); + 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); + + Eina_Bool had_star = !!strchr(ptn, '*'); + const char *add_star = _get_add_star(ftype, pd); + + if (eina_strbuf_length_get(params)) + eina_strbuf_append(params, ", "); + + /* XXX: this is really bad */ + if (!has_promise && !strcmp(ptn, "Eina_Promise *") && !is_prop + && (pd == EOLIAN_INOUT_PARAM)) + { + has_promise = EINA_TRUE; + promise_param_name = eina_stringshare_add(prn); + promise_param_type = eolian_type_c_type_get(eolian_type_base_type_get(pt)); + eina_strbuf_append(params_full_imp, ", Eina_Promise_Owner *"); + eina_strbuf_append(params_full_imp, prn); + if (is_empty && !dfv) + eina_strbuf_append(params_full_imp, " EINA_UNUSED"); + eina_strbuf_append(params, "__eo_promise"); + } + else + { + eina_strbuf_append(params_full_imp, ", "); + eina_strbuf_append(params_full_imp, ptn); + if (!had_star) + eina_strbuf_append_char(params_full_imp, ' '); + eina_strbuf_append(params_full_imp, add_star); + eina_strbuf_append(params_full_imp, prn); + if (!dfv && is_empty) + eina_strbuf_append(params_full_imp, " EINA_UNUSED"); + eina_strbuf_append(params, prn); + } + + eina_strbuf_append(params_full, ", "); + eina_strbuf_append(params_full, ptn); + if (!had_star) + eina_strbuf_append_char(params_full, ' '); + eina_strbuf_append(params_full, add_star); + eina_strbuf_append(params_full, prn); + + if (is_auto) + { + if (ftype == EOLIAN_PROP_SET) + eina_strbuf_append_printf(params_init, " %s = pd->%s;\n", prn, prn); + else + { + eina_strbuf_append_printf(params_init, " if (%s) *%s = pd->%s\n", + prn, prn, prn); + } + } + else if ((ftype != EOLIAN_PROP_SET) && dfv) + { + Eolian_Value val = eolian_expression_eval(dfv, EOLIAN_MASK_ALL); + if (val.type) + { + Eina_Stringshare *vals = eolian_expression_value_to_literal(&val); + eina_strbuf_append_printf(params_init, " if (%s) *%s = %s;", + prn, prn, vals); + eina_stringshare_del(vals); + if (eolian_expression_type_get(dfv) == EOLIAN_EXPR_NAME) + { + Eina_Stringshare *vs = eolian_expression_serialize(dfv); + eina_strbuf_append_printf(params_init, " /* %s */", vs); + eina_stringshare_del(vs); + } + eina_strbuf_append_char(params_init, '\n'); + } + } + + eina_stringshare_del(ptn); + } + eina_iterator_free(itr); + } + + Eina_Bool impl_same_class = (eolian_implement_class_get(impl) == cl); + Eina_Bool impl_need = EINA_TRUE; + if (impl_same_class && eolian_function_is_virtual_pure(fid, ftype)) + impl_need = EINA_FALSE; + + Eina_Stringshare *rtpn = rtp ? eolian_type_c_type_get(rtp) + : eina_stringshare_add("void"); + + char *cnamel, *ocnamel = NULL; + if (!eo_gen_class_names_get(cl, NULL, NULL, &cnamel)) + goto end; + if (!eo_gen_class_names_get(eolian_implement_class_get(impl), NULL, NULL, &ocnamel)) + goto end; + + if (impl_need) + { + /* figure out the data type */ + Eina_Bool is_cf = eolian_function_is_class(fid); + const char *dt = eolian_class_data_type_get(cl); + char adt[128]; + if (is_cf || (dt && !strcmp(dt, "null"))) + snprintf(adt, sizeof(adt), "void"); + else if (dt) + snprintf(adt, sizeof(adt), "%s", dt); + else + snprintf(adt, sizeof(adt), "%s_Data", eolian_class_full_name_get(cl)); + + eina_strbuf_append_char(buf, '\n'); + /* no need for prototype with empty/auto impl */ + if (!is_empty && !is_auto) + { + /* T _class_name[_orig_class]_func_name_suffix */ + eina_strbuf_append(buf, rtpn); + if (!strchr(rtpn, '*')) + eina_strbuf_append_char(buf, ' '); + eina_strbuf_append_char(buf, '_'); + eina_strbuf_append(buf, cnamel); + if (!impl_same_class) + eina_strbuf_append_printf(buf, "_%s", ocnamel); + eina_strbuf_append_char(buf, '_'); + eina_strbuf_append(buf, eolian_function_name_get(fid)); + eina_strbuf_append(buf, func_suffix); + /* ([const ]Eo *obj, Data_Type *pd, impl_full_params); */ + eina_strbuf_append_char(buf, '('); + if (eolian_function_object_is_const(fid)) + eina_strbuf_append(buf, "const "); + eina_strbuf_append(buf, "Eo *obj, "); + eina_strbuf_append(buf, adt); + eina_strbuf_append(buf, " *pd"); + eina_strbuf_append(buf, eina_strbuf_string_get(params_full_imp)); + eina_strbuf_append(buf, ");\n\n"); + } + + if (is_empty || is_auto || eina_strbuf_length_get(params_init)) + { + /* we need to give the internal function name to Eo, + * use this hash table as indication + */ + eina_hash_add(_funcs_params_init, + eina_stringshare_add(eolian_function_name_get(fid)), (void *)ftype); + /* generation of intermediate __eolian_... */ + eina_strbuf_append(buf, "static "); + eina_strbuf_append(buf, rtpn); + if (!strchr(rtpn, '*')) + eina_strbuf_append_char(buf, ' '); + eina_strbuf_append(buf, "__eolian_"); + eina_strbuf_append(buf, cnamel); + if (!impl_same_class) + eina_strbuf_append_printf(buf, "_%s", ocnamel); + eina_strbuf_append_char(buf, '_'); + eina_strbuf_append(buf, eolian_function_name_get(fid)); + eina_strbuf_append(buf, func_suffix); + eina_strbuf_append_char(buf, '('); + if (eolian_function_object_is_const(fid)) + eina_strbuf_append(buf, "const "); + eina_strbuf_append(buf, "Eo *obj"); + if (is_empty || is_auto) + eina_strbuf_append(buf, " EINA_UNUSED"); + eina_strbuf_append(buf, ", "); + eina_strbuf_append(buf, adt); + eina_strbuf_append(buf, " *pd"); + eina_strbuf_append(buf, eina_strbuf_string_get(params_full_imp)); + eina_strbuf_append(buf, ")\n{\n"); + } + if (eina_strbuf_length_get(params_init)) + eina_strbuf_append(buf, eina_strbuf_string_get(params_init)); + if (is_empty || is_auto) + { + if (rtp) + { + const char *vals = NULL; + if (def_ret) + { + Eolian_Value val = eolian_expression_eval(def_ret, EOLIAN_MASK_ALL); + if (val.type) + vals = eolian_expression_value_to_literal(&val); + } + eina_strbuf_append_printf(buf, " return %s;\n", vals ? vals : "0"); + eina_stringshare_del(vals); + } + eina_strbuf_append(buf, "}\n\n"); + } + else if (eina_strbuf_length_get(params_init)) + { + eina_strbuf_append(buf, " "); + if (rtp) + eina_strbuf_append(buf, "return "); + eina_strbuf_append_char(buf, '_'); + eina_strbuf_append(buf, cnamel); + if (!impl_same_class) + eina_strbuf_append_printf(buf, "_%s", ocnamel); + eina_strbuf_append_char(buf, '_'); + eina_strbuf_append(buf, eolian_function_name_get(fid)); + eina_strbuf_append(buf, func_suffix); + eina_strbuf_append(buf, "(obj, pd, "); + eina_strbuf_append(buf, eina_strbuf_string_get(params)); + eina_strbuf_append(buf, ");\n}\n\n"); + } + } + + if (impl_same_class) + { + /* XXX: bad */ + if (has_promise) + { + eina_strbuf_append_printf(buf, + "#undef _EFL_OBJECT_API_BEFORE_HOOK\n#undef _EFL_OBJECT_API_AFTER_HOOK\n#undef _EFL_OBJECT_API_CALL_HOOK\n" + "#define _EFL_OBJECT_API_BEFORE_HOOK _EINA_PROMISE_BEFORE_HOOK(%s, %s%s)\n" + "#define _EFL_OBJECT_API_AFTER_HOOK _EINA_PROMISE_AFTER_HOOK(%s)\n" + "#define _EFL_OBJECT_API_CALL_HOOK(x) _EINA_PROMISE_CALL_HOOK(EFL_FUNC_CALL(%s))\n\n", + promise_param_type, rtpn, + eina_strbuf_string_get(params_full_imp), + promise_param_name, + eina_strbuf_string_get(params)); + } + + void *data; + Eina_Iterator *itr = eolian_property_keys_get(fid, ftype); + Eina_Bool has_params = eina_iterator_next(itr, &data); + eina_iterator_free(itr); + + if (!has_params && !var_as_ret) + { + if (is_prop) + itr = eolian_property_values_get(fid, ftype); + else + itr = eolian_function_parameters_get(fid); + has_params = eina_iterator_next(itr, &data); + eina_iterator_free(itr); + } + + eina_strbuf_append(buf, "EOAPI EFL_"); + if (!strcmp(rtpn, "void")) + eina_strbuf_append(buf, "VOID_"); + eina_strbuf_append(buf, "FUNC_BODY"); + if (has_params) + eina_strbuf_append_char(buf, 'V'); + if ((ftype == EOLIAN_PROP_GET) || eolian_function_object_is_const(fid) + || eolian_function_is_class(fid)) + { + eina_strbuf_append(buf, "_CONST"); + } + eina_strbuf_append_char(buf, '('); + + Eina_Stringshare *eofn = eolian_function_full_c_name_get(fid, ftype, EINA_FALSE); + eina_strbuf_append(buf, eofn); + eina_stringshare_del(eofn); + + if (strcmp(rtpn, "void")) + { + const char *vals = NULL; + if (def_ret) + { + Eolian_Value val = eolian_expression_eval(def_ret, EOLIAN_MASK_ALL); + if (val.type) + vals = eolian_expression_value_to_literal(&val); + } + eina_strbuf_append_printf(buf, ", %s, %s", rtpn, vals ? vals : "0"); + if (vals && (eolian_expression_type_get(def_ret) == EOLIAN_EXPR_NAME)) + { + Eina_Stringshare *valn = eolian_expression_serialize(def_ret); + eina_strbuf_append_printf(buf, " /* %s */", valn); + eina_stringshare_del(valn); + } + eina_stringshare_del(vals); + } + if (has_params) + { + eina_strbuf_append(buf, ", EFL_FUNC_CALL("); + eina_strbuf_append(buf, eina_strbuf_string_get(params)); + eina_strbuf_append_char(buf, ')'); + eina_strbuf_append(buf, eina_strbuf_string_get(params_full)); + } + + eina_strbuf_append(buf, ");\n"); + + if (has_promise) + { + eina_strbuf_append(buf, "\n#undef _EFL_OBJECT_API_BEFORE_HOOK\n#undef _EFL_OBJECT_API_AFTER_HOOK\n#undef _EFL_OBJECT_API_CALL_HOOK\n" + "#define _EFL_OBJECT_API_BEFORE_HOOK\n#define _EFL_OBJECT_API_AFTER_HOOK\n" + "#define _EFL_OBJECT_API_CALL_HOOK(x) x\n"); + } + } + +end: + free(cnamel); + free(ocnamel); + + eina_stringshare_del(rtpn); + + eina_stringshare_del(promise_param_name); + eina_stringshare_del(promise_param_type); + + eina_strbuf_free(params); + eina_strbuf_free(params_full); + eina_strbuf_free(params_full_imp); + eina_strbuf_free(params_init); +} + void eo_gen_source_gen(const Eolian_Class *cl, Eina_Strbuf *buf) { if (!cl) return; + char *cname = NULL, *cnameu = NULL, *cnamel = NULL; + if (!eo_gen_class_names_get(cl, &cname, &cnameu, &cnamel)) + return; + + _funcs_params_init = eina_hash_stringshared_new(NULL); + /* event section, they come first */ { Eina_Iterator *itr = eolian_class_events_get(cl); @@ -26,4 +433,33 @@ eo_gen_source_gen(const Eolian_Class *cl, Eina_Strbuf *buf) } eina_iterator_free(itr); } + + /* method section */ + { + Eina_Iterator *itr = eolian_class_implements_get(cl); + const Eolian_Implement *imp; + EINA_ITERATOR_FOREACH(itr, imp) + { + if (eolian_implement_class_get(imp) != cl) + continue; + Eolian_Function_Type ftype = EOLIAN_UNRESOLVED; + const Eolian_Function *fid = eolian_implement_function_get(imp, &ftype); + switch (ftype) + { + case EOLIAN_PROP_GET: + case EOLIAN_PROP_SET: + _gen_func(cl, fid, ftype, buf, imp); + break; + case EOLIAN_PROPERTY: + _gen_func(cl, fid, EOLIAN_PROP_SET, buf, imp); + _gen_func(cl, fid, EOLIAN_PROP_GET, buf, imp); + break; + default: + _gen_func(cl, fid, EOLIAN_UNRESOLVED, buf, imp); + } + } + eina_iterator_free(itr); + } + + eina_hash_free(_funcs_params_init); } |