forked from enlightenment/efl
eolian: support for setting a free function to values in eo files
This commit is contained in:
parent
d788986fd8
commit
ef380c56b6
|
@ -111,6 +111,8 @@ tests/eolian/data/extern.eo \
|
|||
tests/eolian/data/struct.eo \
|
||||
tests/eolian/data/var.eo \
|
||||
tests/eolian/data/class_funcs.eo \
|
||||
tests/eolian/data/enum.eo \
|
||||
tests/eolian/data/free_func.eo \
|
||||
tests/eolian/data/typedef_ref.c \
|
||||
tests/eolian/data/struct_ref.c
|
||||
|
||||
|
|
|
@ -1322,6 +1322,20 @@ EAPI Eina_Stringshare *eolian_type_full_name_get(const Eolian_Type *tp);
|
|||
*/
|
||||
EAPI Eina_Iterator *eolian_type_namespaces_get(const Eolian_Type *tp);
|
||||
|
||||
/*
|
||||
* @brief Get the name of the function used to free this type.
|
||||
*
|
||||
* @param[in] tp the type.
|
||||
* @return the free func name.
|
||||
*
|
||||
* For pointer types, this returns name of the func used to free the pointer.
|
||||
* For struct and alias types, this returns name of the func used to free a
|
||||
* pointer to that type. For other types, this returns NULL.
|
||||
*
|
||||
* @ingroup Eolian
|
||||
*/
|
||||
EAPI Eina_Stringshare *eolian_type_free_func_get(const Eolian_Type *tp);
|
||||
|
||||
/*
|
||||
* @brief Evaluate an Eolian expression.
|
||||
*
|
||||
|
|
|
@ -21,6 +21,7 @@ database_type_del(Eolian_Type *tp)
|
|||
eina_stringshare_del(sp);
|
||||
if (tp->comment) eina_stringshare_del(tp->comment);
|
||||
if (tp->legacy) eina_stringshare_del(tp->legacy);
|
||||
if (tp->freefunc) eina_stringshare_del(tp->freefunc);
|
||||
free(tp);
|
||||
}
|
||||
|
||||
|
|
|
@ -306,3 +306,10 @@ eolian_type_namespaces_get(const Eolian_Type *tp)
|
|||
if (!tp->namespaces) return NULL;
|
||||
return eina_list_iterator_new(tp->namespaces);
|
||||
}
|
||||
|
||||
EAPI Eina_Stringshare *
|
||||
eolian_type_free_func_get(const Eolian_Type *tp)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(tp, NULL);
|
||||
return tp->freefunc;
|
||||
}
|
||||
|
|
|
@ -25,12 +25,13 @@ enum Tokens
|
|||
KW(virtual), \
|
||||
\
|
||||
KW(abstract), KW(constructor), KW(constructors), KW(data), \
|
||||
KW(destructor), KW(eo), KW(eo_prefix), KW(events), KW(func), KW(get), \
|
||||
KW(implements), KW(interface), KW(keys), KW(legacy), KW(legacy_prefix), \
|
||||
KW(methods), KW(mixin), KW(own), KW(params), KW(properties), KW(set), \
|
||||
KW(type), KW(values), KW(var), KWAT(class), KWAT(const), \
|
||||
KWAT(constructor), KWAT(extern), KWAT(in), KWAT(inout), KWAT(nonull), \
|
||||
KWAT(out), KWAT(private), KWAT(protected), KWAT(warn_unused), \
|
||||
KW(destructor), KW(eo), KW(eo_prefix), KW(events), KW(free), KW(func), \
|
||||
KW(get), KW(implements), KW(interface), KW(keys), KW(legacy), \
|
||||
KW(legacy_prefix), KW(methods), KW(mixin), KW(own), KW(params), \
|
||||
KW(properties), KW(set), KW(type), KW(values), KW(var), KWAT(class), \
|
||||
KWAT(const), KWAT(constructor), KWAT(extern), KWAT(free), KWAT(in), \
|
||||
KWAT(inout), KWAT(nonull), KWAT(out), KWAT(private), KWAT(protected), \
|
||||
KWAT(warn_unused), \
|
||||
\
|
||||
KW(byte), KW(ubyte), KW(char), KW(short), KW(ushort), KW(int), KW(uint), \
|
||||
KW(long), KW(ulong), KW(llong), KW(ullong), \
|
||||
|
|
|
@ -563,7 +563,7 @@ _struct_field_free(Eolian_Struct_Field *def)
|
|||
|
||||
static Eolian_Type *
|
||||
parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
|
||||
int line, int column)
|
||||
int line, int column, const char *freefunc)
|
||||
{
|
||||
int bline = ls->line_number, bcolumn = ls->column;
|
||||
Eolian_Type *def = push_type(ls);
|
||||
|
@ -571,6 +571,7 @@ parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
|
|||
if (name) _fill_type_name(def, name);
|
||||
def->type = EOLIAN_TYPE_STRUCT;
|
||||
def->fields = eina_hash_string_small_new(EINA_FREE_CB(_struct_field_free));
|
||||
def->freefunc = freefunc;
|
||||
check_next(ls, '{');
|
||||
if (ls->t.token == TOK_COMMENT)
|
||||
{
|
||||
|
@ -712,6 +713,49 @@ parse_enum(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
|
|||
return def;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_struct_attrs(Eo_Lexer *ls, Eina_Bool is_enum, Eina_Bool allow_named,
|
||||
Eina_Bool *is_extern, const char **freefunc)
|
||||
{
|
||||
/* TODO: handle freefunc deref on error */
|
||||
Eina_Bool has_extern = EINA_FALSE, has_free = EINA_FALSE;
|
||||
*freefunc = NULL;
|
||||
*is_extern = EINA_FALSE;
|
||||
for (;;) switch (ls->t.kw)
|
||||
{
|
||||
case KW_at_extern:
|
||||
CASE_LOCK(ls, extern, "@extern qualifier")
|
||||
if (!allow_named)
|
||||
{
|
||||
if (is_enum)
|
||||
eo_lexer_syntax_error(ls,
|
||||
"only enum declarations can be extern");
|
||||
else
|
||||
eo_lexer_syntax_error(ls,
|
||||
"only named structs can be extern");
|
||||
}
|
||||
eo_lexer_get(ls);
|
||||
*is_extern = EINA_TRUE;
|
||||
break;
|
||||
case KW_at_free:
|
||||
{
|
||||
CASE_LOCK(ls, free, "@free qualifier")
|
||||
if (is_enum)
|
||||
eo_lexer_syntax_error(ls, "enums cannot have @free");
|
||||
eo_lexer_get(ls);
|
||||
int pline = ls->line_number, pcol = ls->column;
|
||||
check_next(ls, '(');
|
||||
check(ls, TOK_VALUE);
|
||||
*freefunc = eina_stringshare_ref(ls->t.value.s);
|
||||
eo_lexer_get(ls);
|
||||
check_match(ls, ')', '(', pline, pcol);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static Eolian_Type *
|
||||
parse_type_named_void(Eo_Lexer *ls, Eina_Bool allow_named)
|
||||
{
|
||||
|
@ -759,31 +803,46 @@ parse_type_named_void(Eo_Lexer *ls, Eina_Bool allow_named)
|
|||
check_match(ls, ')', '(', pline, pcolumn);
|
||||
goto parse_ptr;
|
||||
}
|
||||
case KW_free:
|
||||
{
|
||||
int pline, pcolumn;
|
||||
eo_lexer_get(ls);
|
||||
pline = ls->line_number;
|
||||
pcolumn = ls->column;
|
||||
check_next(ls, '(');
|
||||
eo_lexer_context_push(ls);
|
||||
def = parse_type_void(ls);
|
||||
if (def->type != EOLIAN_TYPE_POINTER)
|
||||
{
|
||||
eo_lexer_context_restore(ls);
|
||||
eo_lexer_syntax_error(ls, "pointer type expected");
|
||||
}
|
||||
eo_lexer_context_pop(ls);
|
||||
check_next(ls, ',');
|
||||
check(ls, TOK_VALUE);
|
||||
def->freefunc = eina_stringshare_ref(ls->t.value.s);
|
||||
eo_lexer_get(ls);
|
||||
def->base.file = eina_stringshare_ref(ls->filename);
|
||||
def->base.line = line;
|
||||
def->base.column = col;
|
||||
check_match(ls, ')', '(', pline, pcolumn);
|
||||
goto parse_ptr;
|
||||
}
|
||||
case KW_struct:
|
||||
case KW_enum:
|
||||
{
|
||||
const char *freefunc;
|
||||
Eina_Bool has_extern;
|
||||
Eina_Bool is_enum = (ls->t.kw == KW_enum);
|
||||
Eina_Bool is_extern = EINA_FALSE;
|
||||
eo_lexer_get(ls);
|
||||
if (ls->t.kw == KW_at_extern)
|
||||
{
|
||||
if (!allow_named)
|
||||
{
|
||||
if (is_enum)
|
||||
eo_lexer_syntax_error(ls,
|
||||
"only enum declarations can be extern");
|
||||
else
|
||||
eo_lexer_syntax_error(ls,
|
||||
"only named structs can be extern");
|
||||
}
|
||||
is_extern = EINA_TRUE;
|
||||
eo_lexer_get(ls);
|
||||
}
|
||||
parse_struct_attrs(ls, is_enum, allow_named, &has_extern, &freefunc);
|
||||
if (freefunc && !allow_named)
|
||||
check(ls, '{');
|
||||
if (!is_enum && (ls->t.token == '{'))
|
||||
{
|
||||
if (is_extern)
|
||||
if (has_extern)
|
||||
eo_lexer_syntax_error(ls, "extern anonymous struct");
|
||||
return parse_struct(ls, NULL, EINA_FALSE, line, col);
|
||||
return parse_struct(ls, NULL, EINA_FALSE, line, col, freefunc);
|
||||
}
|
||||
buf = push_strbuf(ls);
|
||||
eo_lexer_context_push(ls);
|
||||
|
@ -793,7 +852,7 @@ parse_type_named_void(Eo_Lexer *ls, Eina_Bool allow_named)
|
|||
sname = eina_stringshare_add(eina_strbuf_string_get(buf));
|
||||
pop_strbuf(ls);
|
||||
/* if we're extern and allow structs, gotta enforce it */
|
||||
if (allow_named && is_extern)
|
||||
if (allow_named && (has_extern || freefunc))
|
||||
check(ls, '{');
|
||||
if (allow_named && ls->t.token == '{')
|
||||
{
|
||||
|
@ -808,8 +867,8 @@ parse_type_named_void(Eo_Lexer *ls, Eina_Bool allow_named)
|
|||
}
|
||||
eo_lexer_context_pop(ls);
|
||||
if (is_enum)
|
||||
return parse_enum(ls, sname, is_extern, line, col);
|
||||
return parse_struct(ls, sname, is_extern, line, col);
|
||||
return parse_enum(ls, sname, has_extern, line, col);
|
||||
return parse_struct(ls, sname, has_extern, line, col, freefunc);
|
||||
}
|
||||
eo_lexer_context_pop(ls);
|
||||
def = push_type(ls);
|
||||
|
@ -920,16 +979,14 @@ static Eolian_Type *
|
|||
parse_typedef(Eo_Lexer *ls)
|
||||
{
|
||||
Eolian_Type *def = push_type(ls);
|
||||
Eina_Bool is_extern = EINA_FALSE;
|
||||
Eina_Bool has_extern;
|
||||
const char *freefunc;
|
||||
Eina_Strbuf *buf;
|
||||
eo_lexer_get(ls);
|
||||
if (ls->t.kw == KW_at_extern)
|
||||
{
|
||||
is_extern = EINA_TRUE;
|
||||
eo_lexer_get(ls);
|
||||
}
|
||||
parse_struct_attrs(ls, EINA_FALSE, EINA_TRUE, &has_extern, &freefunc);
|
||||
def->freefunc = freefunc;
|
||||
def->type = EOLIAN_TYPE_ALIAS;
|
||||
def->is_extern = is_extern;
|
||||
def->is_extern = has_extern;
|
||||
buf = push_strbuf(ls);
|
||||
eo_lexer_context_push(ls);
|
||||
def->base.file = eina_stringshare_ref(ls->filename);
|
||||
|
@ -960,18 +1017,18 @@ static Eolian_Variable *
|
|||
parse_variable(Eo_Lexer *ls, Eina_Bool global)
|
||||
{
|
||||
Eolian_Variable *def = push_var(ls);
|
||||
Eina_Bool is_extern = EINA_FALSE;
|
||||
Eina_Bool has_extern = EINA_FALSE;
|
||||
Eina_Strbuf *buf;
|
||||
eo_lexer_get(ls);
|
||||
if (ls->t.kw == KW_at_extern)
|
||||
{
|
||||
if (!global)
|
||||
eo_lexer_syntax_error(ls, "extern constant");
|
||||
is_extern = EINA_TRUE;
|
||||
has_extern = EINA_TRUE;
|
||||
eo_lexer_get(ls);
|
||||
}
|
||||
def->type = global ? EOLIAN_VAR_GLOBAL : EOLIAN_VAR_CONSTANT;
|
||||
def->is_extern = is_extern;
|
||||
def->is_extern = has_extern;
|
||||
buf = push_strbuf(ls);
|
||||
eo_lexer_context_push(ls);
|
||||
def->base.file = eina_stringshare_ref(ls->filename);
|
||||
|
@ -982,7 +1039,7 @@ parse_variable(Eo_Lexer *ls, Eina_Bool global)
|
|||
check_next(ls, ':');
|
||||
def->base_type = parse_type(ls);
|
||||
pop_type(ls);
|
||||
if ((ls->t.token == '=') && !is_extern)
|
||||
if ((ls->t.token == '=') && !has_extern)
|
||||
{
|
||||
ls->expr_mode = EINA_TRUE;
|
||||
eo_lexer_get(ls);
|
||||
|
@ -1766,14 +1823,11 @@ parse_unit(Eo_Lexer *ls, Eina_Bool eot)
|
|||
const char *name;
|
||||
int line, col;
|
||||
Eolian_Type *tp;
|
||||
Eina_Bool is_extern = EINA_FALSE;
|
||||
Eina_Bool has_extern;
|
||||
const char *freefunc;
|
||||
Eina_Strbuf *buf;
|
||||
eo_lexer_get(ls);
|
||||
if (ls->t.kw == KW_at_extern)
|
||||
{
|
||||
is_extern = EINA_TRUE;
|
||||
eo_lexer_get(ls);
|
||||
}
|
||||
parse_struct_attrs(ls, is_enum, EINA_TRUE, &has_extern, &freefunc);
|
||||
buf = push_strbuf(ls);
|
||||
eo_lexer_context_push(ls);
|
||||
line = ls->line_number;
|
||||
|
@ -1794,8 +1848,9 @@ parse_unit(Eo_Lexer *ls, Eina_Bool eot)
|
|||
if (ls->t.token == ';')
|
||||
{
|
||||
Eolian_Type *def = push_type(ls);
|
||||
def->is_extern = is_extern;
|
||||
def->is_extern = has_extern;
|
||||
def->type = EOLIAN_TYPE_STRUCT_OPAQUE;
|
||||
def->freefunc = freefunc;
|
||||
_fill_type_name(def, name);
|
||||
eo_lexer_get(ls);
|
||||
if (ls->t.token == TOK_COMMENT)
|
||||
|
@ -1811,9 +1866,9 @@ parse_unit(Eo_Lexer *ls, Eina_Bool eot)
|
|||
break;
|
||||
}
|
||||
if (is_enum)
|
||||
parse_enum(ls, name, is_extern, line, col);
|
||||
parse_enum(ls, name, has_extern, line, col);
|
||||
else
|
||||
parse_struct(ls, name, is_extern, line, col);
|
||||
parse_struct(ls, name, has_extern, line, col, freefunc);
|
||||
pop_type(ls);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -136,6 +136,7 @@ struct _Eolian_Type
|
|||
Eina_List *field_names;
|
||||
Eina_Stringshare *comment;
|
||||
Eina_Stringshare *legacy;
|
||||
Eina_Stringshare *freefunc;
|
||||
};
|
||||
};
|
||||
Eina_Bool is_const :1;
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/* regular struct */
|
||||
struct Named1 {
|
||||
field: int;
|
||||
}
|
||||
struct @free(test_free) Named2 {
|
||||
field: int;
|
||||
}
|
||||
|
||||
/* typedef */
|
||||
type Typedef1: int;
|
||||
type @free(def_free) Typedef2: int;
|
||||
|
||||
/* anon struct */
|
||||
type Anon1: struct {
|
||||
field: int;
|
||||
};
|
||||
type Anon2: struct @free(anon_free) {
|
||||
field: int;
|
||||
};
|
||||
|
||||
/* opaque */
|
||||
struct Opaque1;
|
||||
struct @free(opaque_free) Opaque2;
|
||||
|
||||
/* pointers */
|
||||
type Pointer1: char *;
|
||||
type Pointer2: free(char *, ptr_free);
|
||||
|
||||
class Free_Func {
|
||||
methods {
|
||||
foo {
|
||||
params {
|
||||
int idx;
|
||||
}
|
||||
return: own(char*);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -823,6 +823,58 @@ START_TEST(eolian_class_funcs)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(eolian_free_func)
|
||||
{
|
||||
const Eolian_Class *class;
|
||||
const Eolian_Type *type;
|
||||
|
||||
eolian_init();
|
||||
|
||||
/* Parsing */
|
||||
fail_if(!eolian_eo_file_parse(PACKAGE_DATA_DIR"/data/free_func.eo"));
|
||||
|
||||
/* Check that the class Dummy is still readable */
|
||||
fail_if(!(class = eolian_class_get_by_name("Free_Func")));
|
||||
fail_if(!eolian_class_function_get_by_name(class, "foo", EOLIAN_METHOD));
|
||||
|
||||
/* regular struct */
|
||||
fail_if(!(type = eolian_type_struct_get_by_name("Named1")));
|
||||
fail_if(eolian_type_free_func_get(type));
|
||||
fail_if(!(type = eolian_type_struct_get_by_name("Named2")));
|
||||
fail_if(strcmp(eolian_type_free_func_get(type), "test_free"));
|
||||
|
||||
/* typedef */
|
||||
fail_if(!(type = eolian_type_alias_get_by_name("Typedef1")));
|
||||
fail_if(eolian_type_free_func_get(type));
|
||||
fail_if(!(type = eolian_type_alias_get_by_name("Typedef2")));
|
||||
fail_if(strcmp(eolian_type_free_func_get(type), "def_free"));
|
||||
|
||||
/* anon struct */
|
||||
fail_if(!(type = eolian_type_alias_get_by_name("Anon1")));
|
||||
fail_if(!(type = eolian_type_base_type_get(type)));
|
||||
fail_if(eolian_type_free_func_get(type));
|
||||
fail_if(!(type = eolian_type_alias_get_by_name("Anon2")));
|
||||
fail_if(!(type = eolian_type_base_type_get(type)));
|
||||
fail_if(strcmp(eolian_type_free_func_get(type), "anon_free"));
|
||||
|
||||
/* opaque struct */
|
||||
fail_if(!(type = eolian_type_struct_get_by_name("Opaque1")));
|
||||
fail_if(eolian_type_free_func_get(type));
|
||||
fail_if(!(type = eolian_type_struct_get_by_name("Opaque2")));
|
||||
fail_if(strcmp(eolian_type_free_func_get(type), "opaque_free"));
|
||||
|
||||
/* pointer */
|
||||
fail_if(!(type = eolian_type_alias_get_by_name("Pointer1")));
|
||||
fail_if(!(type = eolian_type_base_type_get(type)));
|
||||
fail_if(eolian_type_free_func_get(type));
|
||||
fail_if(!(type = eolian_type_alias_get_by_name("Pointer2")));
|
||||
fail_if(!(type = eolian_type_base_type_get(type)));
|
||||
fail_if(strcmp(eolian_type_free_func_get(type), "ptr_free"));
|
||||
|
||||
eolian_shutdown();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void eolian_parsing_test(TCase *tc)
|
||||
{
|
||||
tcase_add_test(tc, eolian_simple_parsing);
|
||||
|
@ -839,5 +891,6 @@ void eolian_parsing_test(TCase *tc)
|
|||
tcase_add_test(tc, eolian_var);
|
||||
tcase_add_test(tc, eolian_enum);
|
||||
tcase_add_test(tc, eolian_class_funcs);
|
||||
tcase_add_test(tc, eolian_free_func);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue