forked from enlightenment/efl
417 lines
15 KiB
C
417 lines
15 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <Eina.h>
|
|
#include <string.h>
|
|
|
|
#include "Eolian.h"
|
|
|
|
#include "legacy_generator.h"
|
|
#include "docs_generator.h"
|
|
#include "common_funcs.h"
|
|
|
|
static _eolian_class_vars class_env;
|
|
|
|
static const char
|
|
tmpl_eapi_funcdef[] = "EAPI @#type_return%s(@#params)@#flags;\n";
|
|
|
|
/*@#CLASS_CHECK(obj) @#check_ret;\n\*/
|
|
static const char
|
|
tmpl_eapi_body[] ="\
|
|
\n\
|
|
EAPI @#ret_type\n\
|
|
@#eapi_func(@#full_params)\n\
|
|
{\n\
|
|
return @#eo_func(@#eo_obj@#eo_params);\n\
|
|
}\n\
|
|
";
|
|
static const char
|
|
tmpl_eapi_body_void[] ="\
|
|
\n\
|
|
EAPI void\n\
|
|
@#eapi_func(@#full_params)\n\
|
|
{\n\
|
|
@#eo_func(@#eo_obj@#eo_params);\n\
|
|
}\n\
|
|
";
|
|
|
|
static void
|
|
_eapi_decl_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, Eolian_Function_Type ftype, Eina_Strbuf *buf)
|
|
{
|
|
_eolian_class_func_vars func_env;
|
|
const char *funcname = eolian_function_name_get(funcid);
|
|
const Eolian_Type *rettypet = NULL;
|
|
const char *rettype = NULL;
|
|
Eina_Bool var_as_ret = EINA_FALSE;
|
|
Eina_Bool is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET);
|
|
Eina_Iterator *itr;
|
|
void *data, *data2;
|
|
Eina_Strbuf *flags = NULL;
|
|
int leg_param_idx = 1; /* Index of the parameter inside the legacy function. It begins from 1 since obj is the first. */
|
|
|
|
Eina_Strbuf *fbody = eina_strbuf_new();
|
|
Eina_Strbuf *fparam = eina_strbuf_new();
|
|
|
|
_class_func_env_create(class, funcname, ftype, &func_env);
|
|
rettypet = eolian_function_return_type_get(funcid, ftype);
|
|
if (ftype == EOLIAN_PROP_GET)
|
|
{
|
|
if (!rettypet)
|
|
{
|
|
itr = eolian_property_values_get(funcid, ftype);
|
|
/* We want to check if there is only one parameter */
|
|
if (eina_iterator_next(itr, &data) && !eina_iterator_next(itr, &data2))
|
|
{
|
|
rettypet = eolian_parameter_type_get((Eolian_Function_Parameter*)data);
|
|
var_as_ret = EINA_TRUE;
|
|
}
|
|
eina_iterator_free(itr);
|
|
}
|
|
}
|
|
|
|
if (func_env.legacy_func[0] == '\0') goto end;
|
|
|
|
Eina_Bool hasnewdocs = eolian_function_documentation_get(funcid, EOLIAN_UNRESOLVED) ||
|
|
eolian_function_documentation_get(funcid, ftype);
|
|
if (hasnewdocs)
|
|
{
|
|
Eina_Strbuf *dbuf = docs_generate_function(funcid, ftype, 0, EINA_TRUE);
|
|
eina_strbuf_append_char(fbody, '\n');
|
|
eina_strbuf_append(fbody, eina_strbuf_string_get(dbuf));
|
|
eina_strbuf_append_char(fbody, '\n');
|
|
eina_strbuf_free(dbuf);
|
|
}
|
|
|
|
eina_strbuf_append_printf(fbody, tmpl_eapi_funcdef, func_env.legacy_func);
|
|
|
|
if (!eolian_function_is_class(funcid))
|
|
{
|
|
if (ftype == EOLIAN_PROP_GET || eolian_function_object_is_const(funcid))
|
|
eina_strbuf_append(fparam, "const ");
|
|
eina_strbuf_append_printf(fparam, "%s *obj", class_env.full_classname);
|
|
}
|
|
|
|
itr = eolian_property_keys_get(funcid, ftype);
|
|
EINA_ITERATOR_FOREACH(itr, data)
|
|
{
|
|
Eolian_Function_Parameter *param = data;
|
|
const Eolian_Type *ptypet = eolian_parameter_type_get(param);
|
|
const char *pname = eolian_parameter_name_get(param);
|
|
const char *ptype = eolian_type_c_type_get(ptypet);
|
|
leg_param_idx++;
|
|
if (eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, ", ");
|
|
eina_strbuf_append_printf(fparam, "%s %s", ptype, pname);
|
|
eina_stringshare_del(ptype);
|
|
|
|
if (eolian_parameter_is_nonull((Eolian_Function_Parameter*)data))
|
|
{
|
|
if (!flags)
|
|
{
|
|
flags = eina_strbuf_new();
|
|
eina_strbuf_append_printf(flags, " EINA_ARG_NONNULL(%d", leg_param_idx);
|
|
}
|
|
else
|
|
eina_strbuf_append_printf(flags, ", %d", leg_param_idx);
|
|
}
|
|
}
|
|
eina_iterator_free(itr);
|
|
if (!var_as_ret)
|
|
{
|
|
itr = is_prop ? eolian_property_values_get(funcid, ftype) : eolian_function_parameters_get(funcid);
|
|
EINA_ITERATOR_FOREACH(itr, data)
|
|
{
|
|
Eolian_Function_Parameter *param = data;
|
|
const Eolian_Type *ptypet = eolian_parameter_type_get(param);
|
|
const char *pname = eolian_parameter_name_get(param);
|
|
const char *ptype = eolian_type_c_type_get(ptypet);
|
|
Eolian_Parameter_Dir pdir = eolian_parameter_direction_get(param);
|
|
Eina_Bool had_star = !!strchr(ptype, '*');
|
|
|
|
leg_param_idx++;
|
|
if (eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, ", ");
|
|
eina_strbuf_append_printf(fparam, "%s%s%s%s",
|
|
ptype, had_star?"":" ", _get_add_star(ftype, pdir), pname);
|
|
eina_stringshare_del(ptype);
|
|
if (eolian_parameter_is_nonull((Eolian_Function_Parameter*)data))
|
|
{
|
|
if (!flags)
|
|
{
|
|
flags = eina_strbuf_new();
|
|
eina_strbuf_append_printf(flags, " EINA_ARG_NONNULL(%d", leg_param_idx);
|
|
}
|
|
else
|
|
eina_strbuf_append_printf(flags, ", %d", leg_param_idx);
|
|
}
|
|
}
|
|
eina_iterator_free(itr);
|
|
}
|
|
if (!eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, "void");
|
|
if (flags) eina_strbuf_append_printf(flags, ")");
|
|
|
|
if (rettypet) rettype = eolian_type_c_type_get(rettypet);
|
|
|
|
eina_strbuf_replace_all(fbody, "@#params", eina_strbuf_string_get(fparam));
|
|
eina_strbuf_reset(fparam);
|
|
eina_strbuf_append_printf(fparam, "%s%s",
|
|
rettype ? rettype : "void",
|
|
rettype && strchr(rettype, '*')?"":" ");
|
|
eina_strbuf_replace_all(fbody, "@#type_return", eina_strbuf_string_get(fparam));
|
|
if (eolian_function_return_is_warn_unused(funcid, ftype))
|
|
{
|
|
Eina_Bool no_nonull = !flags;
|
|
if (no_nonull) flags = eina_strbuf_new();
|
|
eina_strbuf_prepend(flags, " EINA_WARN_UNUSED_RESULT");
|
|
}
|
|
if (flags)
|
|
eina_strbuf_replace_all(fbody, "@#flags", eina_strbuf_string_get(flags));
|
|
eina_strbuf_replace_all(fbody, "@#flags", (eolian_function_return_is_warn_unused(funcid, ftype)) ? " EINA_WARN_UNUSED_RESULT" : "");
|
|
eina_strbuf_append(buf, eina_strbuf_string_get(fbody));
|
|
|
|
if (rettype) eina_stringshare_del(rettype);
|
|
|
|
end:
|
|
eina_strbuf_free(flags);
|
|
eina_strbuf_free(fbody);
|
|
eina_strbuf_free(fparam);
|
|
}
|
|
|
|
static void
|
|
_eapi_func_generate(const Eolian_Class *class, const Eolian_Function *funcid, Eolian_Function_Type ftype, Eina_Strbuf *buf)
|
|
{
|
|
_eolian_class_func_vars func_env;
|
|
char tmpstr[0xFF];
|
|
Eina_Bool var_as_ret = EINA_FALSE;
|
|
const Eolian_Type *rettypet = NULL;
|
|
const char *rettype = NULL;
|
|
const char *retname = NULL;
|
|
Eina_Bool ret_is_void = EINA_FALSE;
|
|
Eina_Bool is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET);
|
|
|
|
Eina_Strbuf *fbody = eina_strbuf_new();
|
|
Eina_Strbuf *fparam = eina_strbuf_new();
|
|
Eina_Strbuf *eoparam = eina_strbuf_new();
|
|
|
|
Eina_Iterator *itr;
|
|
void *data, *data2;
|
|
|
|
_class_func_env_create(class, eolian_function_name_get(funcid), ftype, &func_env);
|
|
rettypet = eolian_function_return_type_get(funcid, ftype);
|
|
if (rettypet) rettype = eolian_type_c_type_get(rettypet);
|
|
if (rettype && !strcmp(rettype, "void")) ret_is_void = EINA_TRUE;
|
|
retname = "ret";
|
|
if (ftype == EOLIAN_PROP_GET)
|
|
{
|
|
if (!rettypet)
|
|
{
|
|
itr = eolian_property_values_get(funcid, ftype);
|
|
/* We want to check if there is only one parameter */
|
|
if (eina_iterator_next(itr, &data) && !eina_iterator_next(itr, &data2))
|
|
{
|
|
Eolian_Function_Parameter *param = data;
|
|
rettypet = eolian_parameter_type_get(param);
|
|
retname = eolian_parameter_name_get(param);
|
|
var_as_ret = EINA_TRUE;
|
|
}
|
|
eina_iterator_free(itr);
|
|
}
|
|
}
|
|
|
|
if (func_env.legacy_func[0] == '\0') goto end;
|
|
|
|
if (!rettype && rettypet) rettype = eolian_type_c_type_get(rettypet);
|
|
|
|
if (rettype && (!ret_is_void))
|
|
eina_strbuf_append(fbody, tmpl_eapi_body);
|
|
else
|
|
eina_strbuf_append(fbody, tmpl_eapi_body_void);
|
|
|
|
if (!eolian_function_is_class(funcid))
|
|
{
|
|
if (ftype == EOLIAN_PROP_GET || eolian_function_object_is_const(funcid))
|
|
eina_strbuf_append(fparam, "const ");
|
|
eina_strbuf_append_printf(fparam, "%s *obj", class_env.full_classname);
|
|
char cbuf[256];
|
|
snprintf(cbuf, sizeof(cbuf), "(%s *)obj", class_env.full_classname);
|
|
eina_strbuf_replace_all(fbody, "@#eo_obj", cbuf);
|
|
}
|
|
else
|
|
{
|
|
Eina_Strbuf *class_buf = eina_strbuf_new();
|
|
_template_fill(class_buf, "@#CLASS_@#CLASSTYPE", class, NULL, NULL, EINA_TRUE);
|
|
eina_strbuf_replace_all(fbody, "@#eo_obj", eina_strbuf_string_get(class_buf));
|
|
eina_strbuf_free(class_buf);
|
|
}
|
|
eina_strbuf_replace_all(fbody, "@#eapi_func", func_env.legacy_func);
|
|
eina_strbuf_replace_all(fbody, "@#eo_func", func_env.lower_eo_func);
|
|
|
|
tmpstr[0] = '\0';
|
|
|
|
itr = eolian_property_keys_get(funcid, ftype);
|
|
EINA_ITERATOR_FOREACH(itr, data)
|
|
{
|
|
Eolian_Function_Parameter *param = data;
|
|
const Eolian_Type *ptypet = eolian_parameter_type_get(param);
|
|
const char *pname = eolian_parameter_name_get(param);
|
|
const char *ptype = eolian_type_c_type_get(ptypet);
|
|
if (eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, ", ");
|
|
eina_strbuf_append_printf(fparam, "%s %s", ptype, pname);
|
|
eina_stringshare_del(ptype);
|
|
eina_strbuf_append_printf(eoparam, ", %s", pname);
|
|
}
|
|
eina_iterator_free(itr);
|
|
if (!var_as_ret)
|
|
{
|
|
itr = is_prop ? eolian_property_values_get(funcid, ftype) : eolian_function_parameters_get(funcid);
|
|
EINA_ITERATOR_FOREACH(itr, data)
|
|
{
|
|
Eolian_Function_Parameter *param = data;
|
|
const Eolian_Type *ptypet = eolian_parameter_type_get(param);
|
|
const char *pname = eolian_parameter_name_get(param);
|
|
const char *ptype = eolian_type_c_type_get(ptypet);
|
|
Eolian_Parameter_Dir pdir = eolian_parameter_direction_get(param);
|
|
Eina_Bool had_star = !!strchr(ptype, '*');
|
|
if (eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, ", ");
|
|
eina_strbuf_append_printf(fparam, "%s%s%s%s",
|
|
ptype, had_star?"":" ", _get_add_star(ftype, pdir), pname);
|
|
eina_stringshare_del(ptype);
|
|
eina_strbuf_append_printf(eoparam, ", %s", pname);
|
|
}
|
|
eina_iterator_free(itr);
|
|
}
|
|
if (!eina_strbuf_length_get(fparam)) eina_strbuf_append(fparam, "void");
|
|
|
|
if (rettype && (!ret_is_void))
|
|
{
|
|
char tmp_ret_str[0xFF];
|
|
sprintf (tmp_ret_str, "%s", rettype);
|
|
const Eolian_Expression *default_ret_val =
|
|
eolian_function_return_default_value_get(funcid, ftype);
|
|
const char *val_str = NULL;
|
|
if (default_ret_val)
|
|
{
|
|
Eolian_Value val = eolian_expression_eval_type
|
|
(default_ret_val, rettypet);
|
|
if (val.type)
|
|
val_str = eolian_expression_value_to_literal(&val);
|
|
}
|
|
Eina_Bool had_star = !!strchr(rettype, '*');
|
|
sprintf (tmpstr, " %s%s%s = %s;\n",
|
|
rettype, had_star?"":" ", retname,
|
|
val_str?val_str:"0");
|
|
|
|
eina_strbuf_replace_all(fbody, "@#ret_type", tmp_ret_str);
|
|
eina_strbuf_replace_all(fbody, "@#ret_init_val", tmpstr);
|
|
}
|
|
|
|
eina_strbuf_replace_all(fbody, "@#full_params", eina_strbuf_string_get(fparam));
|
|
eina_strbuf_replace_all(fbody, "@#eo_params", eina_strbuf_string_get(eoparam));
|
|
|
|
eina_strbuf_replace_all(fbody, "@#ret_val", (rettype && !ret_is_void) ? retname : "");
|
|
|
|
eina_strbuf_append(buf, eina_strbuf_string_get(fbody));
|
|
|
|
if (rettype) eina_stringshare_del(rettype);
|
|
|
|
end:
|
|
eina_strbuf_free(fbody);
|
|
eina_strbuf_free(fparam);
|
|
eina_strbuf_free(eoparam);
|
|
}
|
|
|
|
Eina_Bool
|
|
legacy_header_generate(const Eolian_Class *class, Eina_Strbuf *buf)
|
|
{
|
|
_class_env_create(class, NULL, &class_env);
|
|
|
|
const Eolian_Documentation *doc = eolian_class_documentation_get(class);
|
|
if (doc)
|
|
{
|
|
Eina_Strbuf *cdoc = docs_generate_full(doc, eolian_class_full_name_get(class), 0, EINA_TRUE);
|
|
if (cdoc)
|
|
{
|
|
eina_strbuf_append(buf, eina_strbuf_string_get(cdoc));
|
|
eina_strbuf_append_char(buf, '\n');
|
|
eina_strbuf_free(cdoc);
|
|
}
|
|
}
|
|
|
|
Eina_Iterator *itr = eolian_class_implements_get(class);
|
|
if (itr)
|
|
{
|
|
const Eolian_Implement *impl;
|
|
EINA_ITERATOR_FOREACH(itr, impl)
|
|
{
|
|
if (eolian_implement_class_get(impl) != class)
|
|
continue;
|
|
Eolian_Function_Type ftype = EOLIAN_UNRESOLVED;
|
|
const Eolian_Function *fid = eolian_implement_function_get(impl, &ftype);
|
|
if (eolian_function_is_beta(fid))
|
|
continue;
|
|
switch (ftype)
|
|
{
|
|
case EOLIAN_PROP_GET: case EOLIAN_PROP_SET:
|
|
_eapi_decl_func_generate(class, fid, ftype, buf);
|
|
break;
|
|
case EOLIAN_PROPERTY:
|
|
_eapi_decl_func_generate(class, fid, EOLIAN_PROP_SET, buf);
|
|
_eapi_decl_func_generate(class, fid, EOLIAN_PROP_GET, buf);
|
|
break;
|
|
default:
|
|
_eapi_decl_func_generate(class, fid, EOLIAN_METHOD, buf);
|
|
break;
|
|
}
|
|
}
|
|
eina_iterator_free(itr);
|
|
}
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
Eina_Bool
|
|
legacy_source_generate(const Eolian_Class *class, Eina_Strbuf *buf)
|
|
{
|
|
Eina_Bool ret = EINA_FALSE;
|
|
Eina_Iterator *itr;
|
|
|
|
_class_env_create(class, NULL, &class_env);
|
|
|
|
Eina_Strbuf *tmpbuf = eina_strbuf_new();
|
|
Eina_Strbuf *str_bodyf = eina_strbuf_new();
|
|
|
|
if ((itr = eolian_class_implements_get(class)))
|
|
{
|
|
const Eolian_Implement *impl;
|
|
EINA_ITERATOR_FOREACH(itr, impl)
|
|
{
|
|
if (eolian_implement_class_get(impl) != class)
|
|
continue;
|
|
Eolian_Function_Type ftype = EOLIAN_UNRESOLVED;
|
|
const Eolian_Function *fid = eolian_implement_function_get(impl, &ftype);
|
|
if (eolian_function_is_beta(fid))
|
|
continue;
|
|
switch (ftype)
|
|
{
|
|
case EOLIAN_PROP_GET: case EOLIAN_PROP_SET:
|
|
_eapi_func_generate(class, fid, ftype, str_bodyf);
|
|
break;
|
|
case EOLIAN_PROPERTY:
|
|
_eapi_func_generate(class, fid, EOLIAN_PROP_SET, str_bodyf);
|
|
_eapi_func_generate(class, fid, EOLIAN_PROP_GET, str_bodyf);
|
|
break;
|
|
default:
|
|
_eapi_func_generate(class, fid, EOLIAN_METHOD, str_bodyf);
|
|
break;
|
|
}
|
|
}
|
|
eina_iterator_free(itr);
|
|
}
|
|
|
|
eina_strbuf_append(buf, eina_strbuf_string_get(str_bodyf));
|
|
|
|
ret = EINA_TRUE;
|
|
eina_strbuf_free(tmpbuf);
|
|
eina_strbuf_free(str_bodyf);
|
|
|
|
return ret;
|
|
}
|