eolian: add support for inlist structs

This adds support for inlist structs, a special type of struct
that can only be used with inlists. This differs from regular
structs in a couple ways:

1) They are stored separately. Just like structs, enums, aliases
   have their own storage, so do inlist structs.
2) They can't be @extern, nor they can be opaque.
3) They are their own type of typedecl.
4) When they contain only one field, this field must be a value
   type always, cannot be a pointer.

Like regular structs, they can have arbitrary fields, and they
can have a pre-set free function via @free().

In C, the inlist structs will be generated exactly like ordinary
ones, except they will have EINA_INLIST before the first field.
Other binding generators can deal with them as they wish, for
example to provide high level interfaces to them.

This does not yet do the plumbing necessary to hook these into
the type system, nor it adds generator support.

@feature
This commit is contained in:
Daniel Kolesa 2019-01-29 15:46:05 +01:00
parent 0e027980f6
commit a9360222b0
8 changed files with 155 additions and 15 deletions

View File

@ -264,7 +264,8 @@ typedef enum
EOLIAN_TYPEDECL_STRUCT_OPAQUE,
EOLIAN_TYPEDECL_ENUM,
EOLIAN_TYPEDECL_ALIAS,
EOLIAN_TYPEDECL_FUNCTION_POINTER
EOLIAN_TYPEDECL_FUNCTION_POINTER,
EOLIAN_TYPEDECL_STRUCT_INLIST
} Eolian_Typedecl_Type;
typedef enum
@ -1050,6 +1051,16 @@ EAPI const Eolian_Typedecl *eolian_unit_struct_by_name_get(const Eolian_Unit *un
*/
EAPI const Eolian_Typedecl *eolian_unit_enum_by_name_get(const Eolian_Unit *unit, const char *name);
/*
* @brief Get an inlist struct declaration within a unit by name.
*
* @param[in] unit The unit.
* @param[in] name The name of the alias.
*
* @ingroup Eolian
*/
EAPI const Eolian_Typedecl *eolian_unit_inlist_struct_by_name_get(const Eolian_Unit *unit, const char *name);
/*
* @brief Get an iterator to all aliases in the Eolian database.
*
@ -1083,6 +1094,17 @@ EAPI Eina_Iterator *eolian_unit_structs_get(const Eolian_Unit *unit);
*/
EAPI Eina_Iterator *eolian_unit_enums_get(const Eolian_Unit *unit);
/*
* @brief Get an iterator to all inlist structs in the Eolian database.
*
* @param[in] unit The unit.
*
* Thanks to internal caching, this is an O(1) operation.
*
* @ingroup Eolian
*/
EAPI Eina_Iterator *eolian_unit_inlist_structs_get(const Eolian_Unit *unit);
/*
* @brief A helper function to get an object in a state by name.
*
@ -1275,6 +1297,19 @@ eolian_state_enum_by_name_get(const Eolian_State *state, const char *name)
return eolian_unit_enum_by_name_get(EOLIAN_UNIT(state), name);
}
/*
* @brief A helper function to get an inlist struct in a state by name.
*
* @see eolian_unit_inlist_struct_by_name_get
*
* @ingroup Eolian
*/
static inline const Eolian_Typedecl *
eolian_state_inlist_struct_by_name_get(const Eolian_State *state, const char *name)
{
return eolian_unit_inlist_struct_by_name_get(EOLIAN_UNIT(state), name);
}
/*
* @brief Get an iterator to all aliases contained in a file.
*
@ -1311,6 +1346,18 @@ EAPI Eina_Iterator *eolian_state_structs_by_file_get(const Eolian_State *state,
*/
EAPI Eina_Iterator *eolian_state_enums_by_file_get(const Eolian_State *state, const char *file_name);
/*
* @brief Get an iterator to all inlist structs contained in a file.
*
* @param[in] state The state.
* @param[in] file_name The file name.
*
* Thanks to internal caching, this is an O(1) operation.
*
* @ingroup Eolian
*/
EAPI Eina_Iterator *eolian_state_inlist_structs_by_file_get(const Eolian_State *state, const char *file_name);
/*
* @brief A helper function to get all aliases in a state.
*
@ -1350,6 +1397,19 @@ eolian_state_enums_get(const Eolian_State *state)
return eolian_unit_enums_get(EOLIAN_UNIT(state));
}
/*
* @brief A helper function to get all inlist structs in a state.
*
* @see eolian_unit_inlist_structs_get
*
* @ingroup Eolian
*/
static inline Eina_Iterator *
eolian_state_inlist_structs_get(const Eolian_State *state)
{
return eolian_unit_inlist_structs_get(EOLIAN_UNIT(state));
}
/*
* @brief A helper function to get the full name of a class.
*

View File

@ -172,6 +172,7 @@ _check_typedecl(const Eolian_Typedecl *tp, Eina_Hash *depset, Eina_Hash *chash)
switch (tp->type)
{
case EOLIAN_TYPEDECL_STRUCT:
case EOLIAN_TYPEDECL_STRUCT_INLIST:
_check_type(((const Eolian_Struct_Type_Field *)data)->type,
depset, chash);
break;

View File

@ -43,11 +43,20 @@ database_type_add(Eolian_Unit *unit, Eolian_Typedecl *tp)
}
void
database_struct_add(Eolian_Unit *unit, Eolian_Typedecl *tp)
database_struct_add(Eolian_Unit *unit, Eolian_Typedecl *tp, Eina_Bool is_inlist)
{
EOLIAN_OBJECT_ADD(unit, tp->base.name, tp, structs);
eina_hash_set(unit->state->staging.structs_f, tp->base.file, eina_list_append
((Eina_List*)eina_hash_find(unit->state->staging.structs_f, tp->base.file), tp));
if (is_inlist)
{
EOLIAN_OBJECT_ADD(unit, tp->base.name, tp, inlists);
}
else
{
EOLIAN_OBJECT_ADD(unit, tp->base.name, tp, structs);
}
Eina_Hash *sh = is_inlist ? unit->state->staging.structs_f
: unit->state->staging.inlists_f;
eina_hash_set(sh, tp->base.file, eina_list_append
((Eina_List*)eina_hash_find(sh, tp->base.file), tp));
database_object_add(unit, &tp->base);
}
@ -160,6 +169,8 @@ _stype_to_str(const Eolian_Typedecl *tp, Eina_Strbuf *buf)
if (tp->type == EOLIAN_TYPEDECL_STRUCT_OPAQUE)
return;
eina_strbuf_append(buf, " { ");
if (tp->type == EOLIAN_TYPEDECL_STRUCT_INLIST)
eina_strbuf_append(buf, "EINA_INLIST; ");
Eina_List *l;
Eolian_Struct_Type_Field *sf;
EINA_LIST_FOREACH(tp->field_list, l, sf)
@ -234,6 +245,7 @@ database_typedecl_to_str(const Eolian_Typedecl *tp, Eina_Strbuf *buf)
break;
case EOLIAN_TYPEDECL_STRUCT:
case EOLIAN_TYPEDECL_STRUCT_OPAQUE:
case EOLIAN_TYPEDECL_STRUCT_INLIST:
_stype_to_str(tp, buf);
break;
default:

View File

@ -31,7 +31,7 @@ EAPI Eina_Iterator *
eolian_typedecl_struct_fields_get(const Eolian_Typedecl *tp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(tp, NULL);
if (tp->type != EOLIAN_TYPEDECL_STRUCT)
if (tp->type != EOLIAN_TYPEDECL_STRUCT && tp->type != EOLIAN_TYPEDECL_STRUCT_INLIST)
return NULL;
return eina_list_iterator_new(tp->field_list);
}
@ -42,7 +42,7 @@ eolian_typedecl_struct_field_get(const Eolian_Typedecl *tp, const char *field)
Eolian_Struct_Type_Field *sf = NULL;
EINA_SAFETY_ON_NULL_RETURN_VAL(tp, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(field, NULL);
if (tp->type != EOLIAN_TYPEDECL_STRUCT)
if (tp->type != EOLIAN_TYPEDECL_STRUCT && tp->type != EOLIAN_TYPEDECL_STRUCT_INLIST)
return NULL;
sf = eina_hash_find(tp->fields, field);
if (!sf) return NULL;

View File

@ -171,6 +171,25 @@ _validate_typedecl(Validate_State *vals, Eolian_Typedecl *tp)
if (!tp->freefunc && tp->base_type->freefunc)
tp->freefunc = eina_stringshare_ref(tp->base_type->freefunc);
return _validate(&tp->base);
case EOLIAN_TYPEDECL_STRUCT_INLIST:
if (eina_hash_population(tp->fields) == 1)
{
Eina_Iterator *itr = eina_hash_iterator_data_new(tp->fields);
const Eolian_Struct_Type_Field *sf;
if (!eina_iterator_next(itr, (void **)&sf))
{
_eo_parser_log(&tp->base, "internal error: failed fetching field");
eina_iterator_free(itr);
return EINA_FALSE;
}
eina_iterator_free(itr);
if (database_type_is_ownable(tp->base.unit, sf->type, EINA_FALSE))
{
_eo_parser_log(&sf->base, "single-field inlist struct must contain a value type");
return EINA_FALSE;
}
}
/* fallthrough */
case EOLIAN_TYPEDECL_STRUCT:
{
Cb_Ret rt = { vals, EINA_TRUE };
@ -1388,6 +1407,10 @@ database_validate(const Eolian_Unit *src)
if (!rt.succ)
return EINA_FALSE;
eina_hash_foreach(src->inlists, (Eina_Hash_Foreach)_typedecl_map_cb, &rt);
if (!rt.succ)
return EINA_FALSE;
eina_hash_foreach(src->globals, (Eina_Hash_Foreach)_var_map_cb, &rt);
if (!rt.succ)
return EINA_FALSE;

View File

@ -133,6 +133,7 @@ _eolian_decl_name_get(Eolian_Object *obj)
return "type alias";
case EOLIAN_TYPEDECL_STRUCT:
case EOLIAN_TYPEDECL_STRUCT_OPAQUE:
case EOLIAN_TYPEDECL_STRUCT_INLIST:
return "struct";
case EOLIAN_TYPEDECL_ENUM:
return "enum";
@ -433,13 +434,13 @@ _struct_field_free(Eolian_Struct_Type_Field *def)
static Eolian_Typedecl *
parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
int line, int column, const char *freefunc)
int line, int column, const char *freefunc, Eina_Bool is_inlist)
{
int bline = ls->line_number, bcolumn = ls->column;
Eolian_Typedecl *def = eo_lexer_typedecl_new(ls);
def->is_extern = is_extern;
def->base.name = name;
def->type = EOLIAN_TYPEDECL_STRUCT;
def->type = is_inlist ? EOLIAN_TYPEDECL_STRUCT_INLIST : EOLIAN_TYPEDECL_STRUCT;
def->fields = eina_hash_string_small_new(EINA_FREE_CB(_struct_field_free));
if (freefunc)
{
@ -475,7 +476,7 @@ parse_struct(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
}
check_match(ls, '}', '{', bline, bcolumn);
FILL_BASE(def->base, ls, line, column, TYPEDECL);
database_struct_add(ls->unit, eo_lexer_typedecl_release(ls, def));
database_struct_add(ls->unit, eo_lexer_typedecl_release(ls, def), is_inlist);
return def;
}
@ -2205,8 +2206,10 @@ parse_unit(Eo_Lexer *ls, Eina_Bool eot)
}
case KW_struct:
case KW_enum:
case KW_inlist:
{
Eina_Bool is_enum = (ls->t.kw == KW_enum);
Eina_Bool is_inlist = (ls->t.kw == KW_inlist);
const char *name;
int line, col;
const char *freefunc = NULL;
@ -2217,6 +2220,8 @@ parse_unit(Eo_Lexer *ls, Eina_Bool eot)
{
case KW_at_extern:
CASE_LOCK(ls, extern, "@extern qualifier")
if (is_inlist)
eo_lexer_syntax_error(ls, "inlist structs cannot be @extern");
eo_lexer_get(ls);
break;
case KW_at_free:
@ -2254,12 +2259,13 @@ postparams:
eo_lexer_context_restore(ls);
Eolian_Typedecl tdecl;
tdecl.base.type = EOLIAN_OBJECT_TYPEDECL;
tdecl.type = is_enum ? EOLIAN_TYPEDECL_ENUM : EOLIAN_TYPEDECL_STRUCT;
tdecl.type = is_inlist ? EOLIAN_TYPEDECL_STRUCT_INLIST :
(is_enum ? EOLIAN_TYPEDECL_ENUM : EOLIAN_TYPEDECL_STRUCT);
redef_error(ls, decl, &tdecl.base);
}
eo_lexer_context_pop(ls);
eo_lexer_dtor_pop(ls);
if (!is_enum && ls->t.token == ';')
if (!is_enum && !is_inlist && ls->t.token == ';')
{
Eolian_Typedecl *def = eo_lexer_typedecl_new(ls);
def->is_extern = has_extern;
@ -2273,13 +2279,13 @@ postparams:
eo_lexer_get(ls);
FILL_DOC(ls, def, doc);
FILL_BASE(def->base, ls, line, col, TYPEDECL);
database_struct_add(ls->unit, eo_lexer_typedecl_release(ls, def));
database_struct_add(ls->unit, eo_lexer_typedecl_release(ls, def), EINA_FALSE);
break;
}
if (is_enum)
parse_enum(ls, name, has_extern, line, col);
else
parse_struct(ls, name, has_extern, line, col, freefunc);
parse_struct(ls, name, has_extern, line, col, freefunc, is_inlist);
break;
}
def:

View File

@ -557,6 +557,7 @@ database_unit_init(Eolian_State *state, Eolian_Unit *unit, const char *file)
unit->aliases = eina_hash_stringshared_new(EINA_FREE_CB(database_typedecl_del));
unit->structs = eina_hash_stringshared_new(EINA_FREE_CB(database_typedecl_del));
unit->enums = eina_hash_stringshared_new(EINA_FREE_CB(database_typedecl_del));
unit->inlists = eina_hash_stringshared_new(EINA_FREE_CB(database_typedecl_del));
unit->objects = eina_hash_stringshared_new(NULL);
}
@ -571,6 +572,7 @@ _unit_contents_del(Eolian_Unit *unit)
eina_hash_free(unit->aliases);
eina_hash_free(unit->structs);
eina_hash_free(unit->enums);
eina_hash_free(unit->inlists);
eina_hash_free(unit->objects);
}
@ -618,6 +620,7 @@ _state_area_init(Eolian_State *state, Eolian_State_Area *a)
a->aliases_f = eina_hash_stringshared_new(NULL);
a->structs_f = eina_hash_stringshared_new(NULL);
a->enums_f = eina_hash_stringshared_new(NULL);
a->inlists_f = eina_hash_stringshared_new(NULL);
a->globals_f = eina_hash_stringshared_new(NULL);
a->constants_f = eina_hash_stringshared_new(NULL);
a->objects_f = eina_hash_stringshared_new(NULL);
@ -644,6 +647,7 @@ _state_area_contents_del(Eolian_State_Area *a)
_hashlist_free(a->aliases_f);
_hashlist_free(a->structs_f);
_hashlist_free(a->enums_f);
_hashlist_free(a->inlists_f);
_hashlist_free(a->globals_f);
_hashlist_free(a->constants_f);
_hashlist_free(a->objects_f);
@ -848,6 +852,7 @@ _state_clean(Eolian_State *state)
eina_hash_free_buckets(stu->aliases);
eina_hash_free_buckets(stu->structs);
eina_hash_free_buckets(stu->enums);
eina_hash_free_buckets(stu->inlists);
eina_hash_free_buckets(stu->objects);
eina_hash_foreach(st->units, _ulist_free_cb, NULL);
@ -858,6 +863,7 @@ _state_clean(Eolian_State *state)
_hashlist_free_buckets(st->aliases_f);
_hashlist_free_buckets(st->structs_f);
_hashlist_free_buckets(st->enums_f);
_hashlist_free_buckets(st->inlists_f);
_hashlist_free_buckets(st->globals_f);
_hashlist_free_buckets(st->constants_f);
_hashlist_free_buckets(st->objects_f);
@ -952,6 +958,7 @@ _merge_unit(Eolian_Unit *dest, Eolian_Unit *src)
eina_hash_foreach(src->aliases, _merge_unit_cb, dest->aliases);
eina_hash_foreach(src->structs, _merge_unit_cb, dest->structs);
eina_hash_foreach(src->enums, _merge_unit_cb, dest->enums);
eina_hash_foreach(src->inlists, _merge_unit_cb, dest->inlists);
eina_hash_foreach(src->objects, _merge_unit_cb_noref, dest->objects);
}
@ -1010,6 +1017,7 @@ _merge_staging(Eolian_State *state)
EOLIAN_STAGING_MERGE_LIST(aliases);
EOLIAN_STAGING_MERGE_LIST(structs);
EOLIAN_STAGING_MERGE_LIST(enums);
EOLIAN_STAGING_MERGE_LIST(inlists);
EOLIAN_STAGING_MERGE_LIST(globals);
EOLIAN_STAGING_MERGE_LIST(constants);
EOLIAN_STAGING_MERGE_LIST(objects);
@ -1205,6 +1213,17 @@ eolian_state_enums_by_file_get(const Eolian_State *state, const char *file_name)
return eina_list_iterator_new(l);
}
EAPI Eina_Iterator *
eolian_state_inlist_structs_by_file_get(const Eolian_State *state, const char *file_name)
{
if (!state) return NULL;
Eina_Stringshare *shr = eina_stringshare_add(file_name);
Eina_List *l = eina_hash_find(state->main.inlists_f, shr);
eina_stringshare_del(shr);
if (!l) return NULL;
return eina_list_iterator_new(l);
}
EAPI const Eolian_State *
eolian_unit_state_get(const Eolian_Unit *unit)
{
@ -1332,6 +1351,17 @@ eolian_unit_enum_by_name_get(const Eolian_Unit *unit, const char *name)
return tp;
}
EAPI const Eolian_Typedecl *
eolian_unit_inlist_struct_by_name_get(const Eolian_Unit *unit, const char *name)
{
if (!unit) return NULL;
Eina_Stringshare *shr = eina_stringshare_add(name);
Eolian_Typedecl *tp = eina_hash_find(unit->inlists, shr);
eina_stringshare_del(shr);
if (!tp) return NULL;
return tp;
}
EAPI Eina_Iterator *
eolian_unit_aliases_get(const Eolian_Unit *unit)
{
@ -1350,6 +1380,12 @@ eolian_unit_enums_get(const Eolian_Unit *unit)
return (unit ? eina_hash_iterator_data_new(unit->enums) : NULL);
}
EAPI Eina_Iterator *
eolian_unit_inlist_structs_get(const Eolian_Unit *unit)
{
return (unit ? eina_hash_iterator_data_new(unit->inlists) : NULL);
}
char *
database_class_to_filename(const char *cname)
{

View File

@ -44,6 +44,7 @@ struct _Eolian_Unit
Eina_Hash *aliases;
Eina_Hash *structs;
Eina_Hash *enums;
Eina_Hash *inlists;
Eina_Hash *objects;
};
@ -57,6 +58,7 @@ typedef struct _Eolian_State_Area
Eina_Hash *aliases_f;
Eina_Hash *structs_f;
Eina_Hash *enums_f;
Eina_Hash *inlists_f;
Eina_Hash *globals_f;
Eina_Hash *constants_f;
Eina_Hash *objects_f;
@ -407,7 +409,7 @@ Eolian_Object_Type database_doc_token_ref_resolve(const Eolian_Doc_Token *tok,
/* types */
void database_type_add(Eolian_Unit *unit, Eolian_Typedecl *tp);
void database_struct_add(Eolian_Unit *unit, Eolian_Typedecl *tp);
void database_struct_add(Eolian_Unit *unit, Eolian_Typedecl *tp, Eina_Bool is_inlist);
void database_enum_add(Eolian_Unit *unit, Eolian_Typedecl *tp);
void database_type_del(Eolian_Type *tp);
void database_typedecl_del(Eolian_Typedecl *tp);