eolian: add library support for declaring and using errors

You can now declare errors like this:

error Foo = "message"; [[documentation]]

Then you can use them as types like this:

foo {
    return: error(Error1, Error2, ...);
}

They have a separate type category and storage. They are checked
for redefinitions the same as anything else though. This does
not add any generator support nor it adds any advanced checking.

Ref T6890
This commit is contained in:
Daniel Kolesa 2019-06-21 15:05:50 +02:00
parent 61235a6e5c
commit 1bbf4380ab
9 changed files with 467 additions and 4 deletions

View File

@ -170,6 +170,12 @@ typedef struct _Eolian_Expression Eolian_Expression;
*/
typedef struct _Eolian_Variable Eolian_Variable;
/* Error information
*
* @ingroup Eolian
*/
typedef struct _Eolian_Error Eolian_Error;
/* Struct field information
*
* @ingroup Eolian
@ -222,7 +228,8 @@ typedef enum
EOLIAN_OBJECT_PART,
EOLIAN_OBJECT_IMPLEMENT,
EOLIAN_OBJECT_CONSTRUCTOR,
EOLIAN_OBJECT_DOCUMENTATION
EOLIAN_OBJECT_DOCUMENTATION,
EOLIAN_OBJECT_ERROR
} Eolian_Object_Type;
typedef enum
@ -276,6 +283,7 @@ typedef enum
EOLIAN_TYPE_VOID,
EOLIAN_TYPE_REGULAR,
EOLIAN_TYPE_CLASS,
EOLIAN_TYPE_ERROR,
EOLIAN_TYPE_UNDEFINED
} Eolian_Type_Type;
@ -1078,6 +1086,16 @@ EAPI const Eolian_Variable *eolian_unit_global_by_name_get(const Eolian_Unit *un
*/
EAPI const Eolian_Variable *eolian_unit_constant_by_name_get(const Eolian_Unit *unit, const char *name);
/*
* @brief Get an error declaration in a unit by name.
*
* @param[in] unit The unit.
* @param[in] name the name of the error
*
* @ingroup Eolian
*/
EAPI const Eolian_Error *eolian_unit_error_by_name_get(const Eolian_Unit *unit, const char *name);
/*
* @brief Get an iterator to all constant variables in the Eolian database.
*
@ -1100,6 +1118,17 @@ EAPI Eina_Iterator *eolian_unit_constants_get(const Eolian_Unit *unit);
*/
EAPI Eina_Iterator *eolian_unit_globals_get(const Eolian_Unit *unit);
/*
* @brief Get an iterator to all error declarations in the Eolian database.
*
* @return the iterator or NULL
*
* Thanks to internal caching, this is an O(1) operation.
*
* @ingroup Eolian
*/
EAPI Eina_Iterator *eolian_unit_errors_get(const Eolian_Unit *unit);
/*
* @brief Get an alias type declaration within a unit by name.
*
@ -1265,6 +1294,19 @@ eolian_state_constant_by_name_get(const Eolian_State *state, const char *name)
return eolian_unit_constant_by_name_get(EOLIAN_UNIT(state), name);
}
/*
* @brief A helper function to get an error declaration in a state by name.
*
* @see eolian_unit_error_by_name_get
*
* @ingroup Eolian
*/
static inline const Eolian_Error *
eolian_state_error_by_name_get(const Eolian_State *state, const char *name)
{
return eolian_unit_error_by_name_get(EOLIAN_UNIT(state), name);
}
/*
* @brief Get an iterator to all global variables contained in a file.
*
@ -1290,6 +1332,19 @@ EAPI Eina_Iterator *eolian_state_globals_by_file_get(const Eolian_State *state,
*/
EAPI Eina_Iterator *eolian_state_constants_by_file_get(const Eolian_State *state, const char *file_name);
/*
* @brief Get an iterator to all error declarations contained in a file.
*
* @param[in] state The state.
* @param[in] file_name The file name.
* @return the iterator or NULL
*
* Thanks to internal caching, this is an O(1) operation.
*
* @ingroup Eolian
*/
EAPI Eina_Iterator *eolian_state_errors_by_file_get(const Eolian_State *state, const char *file_name);
/*
* @brief A helper function to get all globals in a state.
*
@ -1316,6 +1371,19 @@ eolian_state_constants_get(const Eolian_State *state)
return eolian_unit_constants_get(EOLIAN_UNIT(state));
}
/*
* @brief A helper function to get all error declarations in a state.
*
* @see eolian_unit_errors_get
*
* @ingroup Eolian
*/
static inline Eina_Iterator *
eolian_state_errors_get(const Eolian_State *state)
{
return eolian_unit_errors_get(EOLIAN_UNIT(state));
}
/*
* @brief A helper function to get an alias in a state by name.
*
@ -2704,7 +2772,8 @@ EAPI const Eolian_Type *eolian_type_base_type_get(const Eolian_Type *tp);
*
* The inner types of a complex type form a chain. Therefore, you first retrieve
* the first one via eolian_type_base_type_get and then get the next one via
* this API function called on the first inner type if necessary.
* this API function called on the first inner type if necessary. Another use
* for this is with errors, specifying error(Foo, Bar, ...) makes a chain.
*
* @param[in] tp the type.
* @return the next type or NULL.
@ -2752,6 +2821,16 @@ EAPI const Eolian_Type *eolian_type_aliased_base_get(const Eolian_Type *tp);
*/
EAPI const Eolian_Class *eolian_type_class_get(const Eolian_Type *tp);
/*
* @brief Get the error declaration associated with an EOLIAN_TYPE_ERROR type.
*
* @param[in] tp the type.
* @return the error or NULL.
*
* @ingroup Eolian
*/
EAPI const Eolian_Error *eolian_type_error_get(const Eolian_Type *tp);
/*
* @brief Get whether the given type is owned.
*
@ -3130,6 +3209,101 @@ eolian_variable_is_beta(const Eolian_Variable *var)
return eolian_object_is_beta(EOLIAN_OBJECT(var));
}
/*
* @brief Get the message of an error declaration.
*
* @param[in] err the error.
* @return the message or NULL.
*
* @ingroup Eolian
*/
EAPI const char *eolian_error_message_get(const Eolian_Error *err);
/*
* @brief Get the documentation of an error declaration.
*
* @param[in] err the error declaration.
* @return the documentation or NULL.
*
* @ingroup Eolian
*/
EAPI const Eolian_Documentation *eolian_error_documentation_get(const Eolian_Error *err);
/*
* @brief A helper function to get the full name of an error declaration.
*
* @see eolian_object_name_get
*
* @ingroup Eolian
*/
static inline const char *
eolian_error_name_get(const Eolian_Error *err)
{
return eolian_object_name_get(EOLIAN_OBJECT(err));
}
/*
* @brief A helper function to get the C name of an error declaration.
*
* @see eolian_object_c_name_get
*
* @ingroup Eolian
*/
static inline const char *
eolian_error_c_name_get(const Eolian_Error *err)
{
return eolian_object_c_name_get(EOLIAN_OBJECT(err));
}
/*
* @brief A helper function to get the short name of an error declaration.
*
* @see eolian_object_short_name_get
*
* @ingroup Eolian
*/
static inline const char *
eolian_error_short_name_get(const Eolian_Error *err)
{
return eolian_object_short_name_get(EOLIAN_OBJECT(err));
}
/*
* @brief A helper function to get the namespaces of an error declaration.
*
* @see eolian_object_namespaces_get
*
* @ingroup Eolian
*/
static inline Eina_Iterator *
eolian_error_namespaces_get(const Eolian_Error *err)
{
return eolian_object_namespaces_get(EOLIAN_OBJECT(err));
}
/*
* @brief Get whether an error declaration is beta.
*
* @see eolian_object_is_beta
*
* @ingroup Eolian
*/
static inline Eina_Bool
eolian_error_is_beta(const Eolian_Error *err)
{
return eolian_object_is_beta(EOLIAN_OBJECT(err));
}
/*
* @brief Check if an error declaration is extern.
*
* @param[in] err the errpr decůaratopm.
* @return EINA_TRUE if it's extern, EINA_FALSE otherwise.
*
* @ingroup Eolian
*/
EAPI Eina_Bool eolian_error_is_extern(const Eolian_Error *err);
/*
* @brief Get the summary of the documentation.
*

View File

@ -197,6 +197,15 @@ eolian_type_class_get(const Eolian_Type *tp)
return tp->klass;
}
EAPI const Eolian_Error *
eolian_type_error_get(const Eolian_Type *tp)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(tp, NULL);
if (eolian_type_type_get(tp) != EOLIAN_TYPE_ERROR)
return NULL;
return tp->error;
}
EAPI Eina_Bool
eolian_type_is_owned(const Eolian_Type *tp)
{

View File

@ -351,9 +351,29 @@ _validate_type(Validate_State *vals, Eolian_Type *tp)
}
if (!tp->freefunc)
tp->freefunc = eina_stringshare_add(eo_obj_free);
tp->base.c_name = eina_stringshare_ref(tp->tdecl->base.c_name);
tp->base.c_name = eina_stringshare_ref(tp->klass->base.c_name);
return _validate_ownable(tp);
}
case EOLIAN_TYPE_ERROR:
{
tp->error = (Eolian_Error *)eolian_unit_error_by_name_get(src, tp->base.name);
if (!tp->error)
{
_eo_parser_log(&tp->base, "undefined error %s "
"(likely wrong namespacing)", tp->base.name);
return EINA_FALSE;
}
else if (vals->stable && tp->error->base.is_beta)
{
_eo_parser_log(&tp->base, "beta error '%s' used in stable context",
tp->error->base.name);
return EINA_FALSE;
}
tp->base.c_name = eina_stringshare_ref(tp->error->base.c_name);
if (tp->next_type && !_validate_type(vals, tp->next_type))
return EINA_FALSE;
return _validate(&tp->base);
}
default:
return EINA_FALSE;
}

View File

@ -28,7 +28,7 @@ enum Tokens
#define KEYWORDS KW(class), KW(const), KW(enum), KW(return), KW(struct), \
\
KW(abstract), KW(c_prefix), KW(composite), KW(constructor), KW(constructors), \
KW(data), KW(destructor), KW(event_prefix), KW(events), KW(extends), \
KW(data), KW(destructor), KW(error), KW(event_prefix), KW(events), KW(extends), \
KW(free), KW(get), KW(implements), KW(import), KW(interface), \
KW(keys), KW(legacy), KW(methods), KW(mixin), KW(params), \
KW(parse), KW(parts), KW(ptr), KW(set), KW(type), KW(values), KW(var), KW(requires), \
@ -296,6 +296,18 @@ eo_lexer_expr_release_ref(Eo_Lexer *ls, Eolian_Expression *expr)
return eo_lexer_expr_release(ls, expr);
}
static inline Eolian_Error *
eo_lexer_error_new(Eo_Lexer *ls)
{
return (Eolian_Error *)eo_lexer_node_new(ls, sizeof(Eolian_Error));
}
static inline Eolian_Error *
eo_lexer_error_release(Eo_Lexer *ls, Eolian_Error *err)
{
return (Eolian_Error *)eo_lexer_node_release(ls, (Eolian_Object *)err);
}
/* "stack" management, only to protect against errors (jumps) in parsing */
void eo_lexer_dtor_push(Eo_Lexer *ls, Eina_Free_Cb free_cb, void *data);
void eo_lexer_dtor_pop(Eo_Lexer *ls);

View File

@ -646,6 +646,29 @@ parse_enum(Eo_Lexer *ls, const char *name, Eina_Bool is_extern,
return def;
}
/* error(Error1, Error2, Error3, ...) */
static Eolian_Type *
parse_type_error(Eo_Lexer *ls)
{
Eolian_Type *def = eo_lexer_type_new(ls);
Eina_Strbuf *buf = eina_strbuf_new();
eo_lexer_dtor_push(ls, EINA_FREE_CB(eina_strbuf_free), buf);
for (Eolian_Type *cdef = def;; cdef = cdef->next_type)
{
FILL_BASE(cdef->base, ls, ls->line_number, ls->column, TYPE);
parse_name(ls, buf);
cdef->type = EOLIAN_TYPE_ERROR;
cdef->base.name = eina_stringshare_add(eina_strbuf_string_get(buf));
eina_strbuf_reset(buf);
if (ls->t.token != ',')
break;
eo_lexer_get(ls);
cdef->next_type = eo_lexer_type_release(ls, eo_lexer_type_new(ls));
}
eo_lexer_dtor_pop(ls);
return def;
}
static Eolian_Type *
parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ptr)
{
@ -698,6 +721,17 @@ parse_type_void(Eo_Lexer *ls, Eina_Bool allow_ptr)
check_match(ls, ')', '(', pline, pcolumn);
return def;
}
case KW_error:
{
int pline, pcolumn;
eo_lexer_get(ls);
pline = ls->line_number;
pcolumn = ls->column;
check_next(ls, '(');
def = parse_type_error(ls);
check_match(ls, ')', '(', pline, pcolumn);
return def;
}
default:
break;
}
@ -910,6 +944,71 @@ tags_done:
return def;
}
static Eolian_Error *
parse_error(Eo_Lexer *ls)
{
Eolian_Error *def = eo_lexer_error_new(ls);
Eina_Strbuf *buf;
eo_lexer_get(ls);
Eina_Stringshare *cname = NULL;
Eina_Bool has_extern = EINA_FALSE, has_beta = EINA_FALSE, has_c_name = EINA_FALSE;
for (;;) switch (ls->t.kw)
{
case KW_at_extern:
CASE_LOCK(ls, extern, "extern qualifier");
def->is_extern = EINA_TRUE;
eo_lexer_get(ls);
break;
case KW_at_beta:
CASE_LOCK(ls, beta, "beta qualifier");
def->base.is_beta = EINA_TRUE;
eo_lexer_get(ls);
break;
case KW_at_c_name:
CASE_LOCK(ls, c_name, "@c_name specifier");
cname = parse_c_name(ls);
eo_lexer_dtor_push(ls, EINA_FREE_CB(eina_stringshare_del), (void *)cname);
break;
default:
goto tags_done;
}
tags_done:
buf = eina_strbuf_new();
eo_lexer_dtor_push(ls, EINA_FREE_CB(eina_strbuf_free), buf);
eo_lexer_context_push(ls);
FILL_BASE(def->base, ls, ls->line_number, ls->column, ERROR);
parse_name(ls, buf);
def->base.name = eina_stringshare_add(eina_strbuf_string_get(buf));
if (cname)
{
def->base.c_name = cname;
eo_lexer_dtor_pop(ls);
}
else
def->base.c_name = make_c_name(def->base.name);
Eolian_Object *decl = _eolian_decl_get(ls, def->base.name);
if (decl)
{
eo_lexer_context_restore(ls);
redef_error(ls, decl, &def->base);
}
eo_lexer_context_pop(ls);
check(ls, '=');
/* we need to parse a string so switch to exprmode */
ls->expr_mode = EINA_TRUE;
/* consume = to get string */
eo_lexer_get(ls);
/* verify and switch back to plain syntax mode */
check(ls, TOK_STRING);
ls->expr_mode = EINA_FALSE;
def->msg = eina_stringshare_ref(ls->t.value.s);
eo_lexer_get(ls);
check_next(ls, ';');
FILL_DOC(ls, def, doc);
eo_lexer_dtor_pop(ls);
return def;
}
typedef struct _Eo_Ret_Def
{
Eolian_Type *type;
@ -2273,6 +2372,9 @@ parse_unit(Eo_Lexer *ls, Eina_Bool eot)
parse_variable(ls, ls->t.kw == KW_var)));
break;
}
case KW_error:
database_error_add(ls->unit, eo_lexer_error_release(ls, parse_error(ls)));
break;
case KW_struct:
case KW_enum:
{

View File

@ -568,6 +568,7 @@ database_unit_init(Eolian_State *state, Eolian_Unit *unit, const char *file)
unit->classes = eina_hash_stringshared_new(EINA_FREE_CB(database_class_del));
unit->globals = eina_hash_stringshared_new(EINA_FREE_CB(database_var_del));
unit->constants = eina_hash_stringshared_new(EINA_FREE_CB(database_var_del));
unit->errors = eina_hash_stringshared_new(EINA_FREE_CB(database_error_del));
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));
@ -585,6 +586,7 @@ _unit_contents_del(Eolian_Unit *unit)
eina_hash_free(unit->classes);
eina_hash_free(unit->globals);
eina_hash_free(unit->constants);
eina_hash_free(unit->errors);
eina_hash_free(unit->aliases);
eina_hash_free(unit->structs);
eina_hash_free(unit->enums);
@ -637,6 +639,7 @@ _state_area_init(Eolian_State *state, Eolian_State_Area *a)
a->enums_f = eina_hash_stringshared_new(NULL);
a->globals_f = eina_hash_stringshared_new(NULL);
a->constants_f = eina_hash_stringshared_new(NULL);
a->errors_f = eina_hash_stringshared_new(NULL);
a->objects_f = eina_hash_stringshared_new(NULL);
}
@ -663,6 +666,7 @@ _state_area_contents_del(Eolian_State_Area *a)
_hashlist_free(a->enums_f);
_hashlist_free(a->globals_f);
_hashlist_free(a->constants_f);
_hashlist_free(a->errors_f);
_hashlist_free(a->objects_f);
}
@ -1239,6 +1243,17 @@ eolian_state_constants_by_file_get(const Eolian_State *state, const char *file_n
return eina_list_iterator_new(l);
}
EAPI Eina_Iterator *
eolian_state_errors_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.errors_f, shr);
eina_stringshare_del(shr);
if (!l) return NULL;
return eina_list_iterator_new(l);
}
EAPI Eina_Iterator *
eolian_state_aliases_by_file_get(const Eolian_State *state, const char *file_name)
{
@ -1361,6 +1376,16 @@ eolian_unit_constant_by_name_get(const Eolian_Unit *unit, const char *name)
return v;
}
EAPI const Eolian_Error *
eolian_unit_error_by_name_get(const Eolian_Unit *unit, const char *name)
{
if (!unit) return NULL;
Eina_Stringshare *shr = eina_stringshare_add(name);
Eolian_Error *v = eina_hash_find(unit->errors, shr);
eina_stringshare_del(shr);
return v;
}
EAPI Eina_Iterator *
eolian_unit_constants_get(const Eolian_Unit *unit)
{
@ -1373,6 +1398,12 @@ eolian_unit_globals_get(const Eolian_Unit *unit)
return (unit ? eina_hash_iterator_data_new(unit->globals) : NULL);
}
EAPI Eina_Iterator *
eolian_unit_errors_get(const Eolian_Unit *unit)
{
return (unit ? eina_hash_iterator_data_new(unit->errors) : NULL);
}
EAPI const Eolian_Typedecl *
eolian_unit_alias_by_name_get(const Eolian_Unit *unit, const char *name)
{
@ -1424,6 +1455,45 @@ eolian_unit_enums_get(const Eolian_Unit *unit)
return (unit ? eina_hash_iterator_data_new(unit->enums) : NULL);
}
EAPI const char *
eolian_error_message_get(const Eolian_Error *err)
{
if (!err) return NULL;
return err->msg;
}
EAPI Eina_Bool
eolian_error_is_extern(const Eolian_Error *err)
{
if (!err) return EINA_FALSE;
return err->is_extern;
}
EAPI const Eolian_Documentation *
eolian_error_documentation_get(const Eolian_Error *err)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(err, NULL);
return err->doc;
}
void
database_error_del(Eolian_Error *err)
{
if (!err || eolian_object_unref(&err->base)) return;
eina_stringshare_del(err->msg);
free(err);
}
void
database_error_add(Eolian_Unit *unit, Eolian_Error *err)
{
EOLIAN_OBJECT_ADD(unit, err->base.name, err, errors);
eina_hash_set(unit->state->staging.errors_f, err->base.file, eina_list_append
((Eina_List*)eina_hash_find(unit->state->staging.errors_f, err->base.file),
err));
database_object_add(unit, &err->base);
}
char *
database_class_to_filename(const char *cname)
{

View File

@ -41,6 +41,7 @@ struct _Eolian_Unit
Eina_Hash *classes;
Eina_Hash *globals;
Eina_Hash *constants;
Eina_Hash *errors;
Eina_Hash *aliases;
Eina_Hash *structs;
Eina_Hash *enums;
@ -60,6 +61,7 @@ typedef struct _Eolian_State_Area
Eina_Hash *enums_f;
Eina_Hash *globals_f;
Eina_Hash *constants_f;
Eina_Hash *errors_f;
Eina_Hash *objects_f;
} Eolian_State_Area;
@ -267,6 +269,7 @@ struct _Eolian_Type
{
Eolian_Class *klass;
Eolian_Typedecl *tdecl;
Eolian_Error *error;
};
Eina_Bool is_const :1;
Eina_Bool is_ptr :1;
@ -325,6 +328,14 @@ struct _Eolian_Event
Eina_Bool is_restart :1;
};
struct _Eolian_Error
{
Eolian_Object base;
Eina_Stringshare *msg;
Eolian_Documentation *doc;
Eina_Bool is_extern :1;
};
struct _Eolian_Struct_Type_Field
{
Eolian_Object base;
@ -448,4 +459,8 @@ void database_event_del(Eolian_Event *event);
/* parts */
void database_part_del(Eolian_Part *part);
/* errors */
void database_error_del(Eolian_Error *err);
void database_error_add(Eolian_Unit *unit, Eolian_Error *err);
#endif

View File

@ -0,0 +1,13 @@
error Foo = "something bad happened"; [[Error doc]]
error @beta Bar = "another bad thing happened"; [[Another error doc]]
class @beta Error {
methods {
foo {
return: error(Foo);
}
bar {
return: error(Foo, Bar);
}
}
}

View File

@ -843,6 +843,53 @@ EFL_START_TEST(eolian_var)
}
EFL_END_TEST
EFL_START_TEST(eolian_error)
{
const Eolian_Unit *unit;
const Eolian_Class *class;
const Eolian_Function *f1, *f2;
const Eolian_Type *rtp1, *rtp2;
const Eolian_Error *err1, *err2;
Eolian_State *eos = eolian_state_new();
fail_if(!eolian_state_directory_add(eos, TESTS_SRC_DIR"/data"));
fail_if(!(unit = eolian_state_file_parse(eos, "error.eo")));
fail_if(!(class = eolian_unit_class_by_name_get(unit, "Error")));
fail_if(!(f1 = eolian_class_function_by_name_get(class, "foo", EOLIAN_METHOD)));
fail_if(!(f2 = eolian_class_function_by_name_get(class, "bar", EOLIAN_METHOD)));
fail_if(!(rtp1 = eolian_function_return_type_get(f1, EOLIAN_METHOD)));
fail_if(!(rtp2 = eolian_function_return_type_get(f2, EOLIAN_METHOD)));
/* single error */
fail_if(eolian_type_type_get(rtp1) != EOLIAN_TYPE_ERROR);
fail_if(eolian_type_next_type_get(rtp1) != NULL);
fail_if(strcmp(eolian_type_name_get(rtp1), "Foo"));
fail_if(!(err1 = eolian_type_error_get(rtp1)));
fail_if(strcmp(eolian_error_message_get(err1), "something bad happened"));
/* error range */
fail_if(eolian_type_type_get(rtp2) != EOLIAN_TYPE_ERROR);
fail_if(!(rtp1 = eolian_type_next_type_get(rtp2)));
fail_if(strcmp(eolian_type_name_get(rtp2), "Foo"));
fail_if(strcmp(eolian_type_name_get(rtp1), "Bar"));
/* it's the same Foo here */
fail_if(eolian_type_error_get(rtp2) != err1);
fail_if(!(err2 = eolian_type_error_get(rtp1)));
fail_if(strcmp(eolian_error_message_get(err1), "something bad happened"));
fail_if(strcmp(eolian_error_message_get(err2), "another bad thing happened"));
fail_if(!eolian_error_documentation_get(err1));
fail_if(!eolian_error_documentation_get(err2));
fail_if(eolian_error_is_beta(err1));
fail_if(!eolian_error_is_beta(err2));
eolian_state_free(eos);
}
EFL_END_TEST
EFL_START_TEST(eolian_enum)
{
const Eolian_Enum_Type_Field *field = NULL;
@ -1621,6 +1668,7 @@ void eolian_parsing_test(TCase *tc)
tcase_add_test(tc, eolian_struct);
tcase_add_test(tc, eolian_extern);
tcase_add_test(tc, eolian_var);
tcase_add_test(tc, eolian_error);
tcase_add_test(tc, eolian_enum);
tcase_add_test(tc, eolian_class_funcs);
tcase_add_test(tc, eolian_free_func);