eolian: implement new inherit behavior

Eolian now separates 'parent' and 'extensions'. For regular
classes, parent is the first item in the inherits list and
extesions is the rest. For interfaces and mixins, parent is
NULL and extends is the inherits list.

The reason for this is the separation of them in syntax in near
future. It also slightly changes the behavior; since for interfaces
and mixins, parent is always NULL now, you can freely inherit from
all types of classes without needing to manually put an interface
type as the first item of the inherits list.
This commit is contained in:
Daniel Kolesa 2018-11-22 16:21:52 +01:00
parent f3eb8d6441
commit 14ce54c303
13 changed files with 182 additions and 78 deletions

View File

@ -981,11 +981,17 @@ eo_gen_source_gen(const Eolian_Class *cl, Eina_Strbuf *buf)
/* inherits in EFL_DEFINE_CLASS */
{
const Eolian_Class *icl;
Eina_Iterator *itr = eolian_class_inherits_get(cl);
const Eolian_Class *icl = eolian_class_parent_get(cl);
/* no inherits, NULL parent */
if (!itr)
if (!icl)
eina_strbuf_append(buf, ", NULL");
else
{
Eina_Stringshare *mname = eolian_class_c_name_get(icl);
eina_strbuf_append_printf(buf, ", %s", mname);
eina_stringshare_del(mname);
}
Eina_Iterator *itr = eolian_class_extensions_get(cl);
EINA_ITERATOR_FOREACH(itr, icl)
{
Eina_Stringshare *mname = eolian_class_c_name_get(icl);

View File

@ -120,7 +120,17 @@ generate(const Eolian_Class* klass, eolian_cxx::options_type const& opts,
std::function<void(Eolian_Class const*)> klass_function
= [&] (Eolian_Class const* klass2)
{
for(efl::eina::iterator<Eolian_Class const> inherit_iterator ( ::eolian_class_inherits_get(klass2))
if(::eolian_class_parent_get(klass2))
{
Eolian_Class const* inherit = ::eolian_class_parent_get(klass2);
c_headers.insert(eolian_object_file_get((const Eolian_Object *)inherit) + std::string(".h"));
cpp_headers.insert(eolian_object_file_get((const Eolian_Object *)inherit) + std::string(".hh"));
efl::eolian::grammar::attributes::klass_def klass3{inherit, opts.unit};
forward_klasses.insert(klass3);
klass_function(inherit);
}
for(efl::eina::iterator<Eolian_Class const> inherit_iterator ( ::eolian_class_extensions_get(klass2))
, inherit_last; inherit_iterator != inherit_last; ++inherit_iterator)
{
Eolian_Class const* inherit = &*inherit_iterator;

View File

@ -334,7 +334,8 @@ ffi.cdef [[
const char *eolian_class_legacy_prefix_get(const Eolian_Class *klass);
const char *eolian_class_eo_prefix_get(const Eolian_Class *klass);
const char *eolian_class_data_type_get(const Eolian_Class *klass);
Eina_Iterator *eolian_class_inherits_get(const Eolian_Class *klass);
const Eolian_Class *eolian_class_parent_get(const Eolian_Class *klass);
Eina_Iterator *eolian_class_extensions_get(const Eolian_Class *klass);
Eina_Iterator *eolian_class_functions_get(const Eolian_Class *klass, Eolian_Function_Type func_type);
Eolian_Function_Type eolian_function_type_get(const Eolian_Function *function_id);
Eolian_Object_Scope eolian_function_scope_get(const Eolian_Function *function_id, Eolian_Function_Type ftype);
@ -1338,9 +1339,15 @@ M.Class = ffi.metatype("Eolian_Class", {
return ffi.string(v)
end,
inherits_get = function(self)
parent_get = function(self)
local v = eolian.eolian_class_parent_get(self)
if v == nil then return nil end
return v
end,
extensions_get = function(self)
return Ptr_Iterator("const Eolian_Class*",
eolian.eolian_class_inherits_get(self))
eolian.eolian_class_extensions_get(self))
end,
functions_get = function(self, func_type)

View File

@ -1446,14 +1446,36 @@ EAPI Eina_Stringshare* eolian_class_event_prefix_get(const Eolian_Class *klass);
EAPI Eina_Stringshare *eolian_class_data_type_get(const Eolian_Class *klass);
/*
* @brief Returns an iterator to the inherited classes.
* @brief Get the parent class of a class
*
* This is the class the class inherits from. It only applies to classes,
* as Eo follows a single-inheritance model with interfaces. This will be
* NULL for any non-class (i.e. interface or mixin).
*
* @param[in] klass the class
* @return the parent
*
* @see eolian_class_extensions_get
*
* @ingroup Eolian
*/
EAPI const Eolian_Class *eolian_class_parent_get(const Eolian_Class *klass);
/*
* @brief Returns an iterator to the class extensions
*
* For regular classes, extensions are interfaces/mixins for the class, i.e.
* everything past the parent class. For interfaces/mixins, this is everything
* in the inherits list.
*
* @param[in] klass the class
* @return the iterator
*
* @see eolian_class_parent_get
*
* @ingroup Eolian
*/
EAPI Eina_Iterator *eolian_class_inherits_get(const Eolian_Class *klass);
EAPI Eina_Iterator *eolian_class_extensions_get(const Eolian_Class *klass);
/*
* @brief Returns an iterator to functions of a class.

View File

@ -116,8 +116,11 @@ _check_class(const Eolian_Class *cl, Eina_Hash *depset, Eina_Hash *chash)
_add_dep(depset, cl->base.unit);
Eina_Iterator *itr = eina_list_iterator_new(cl->inherits);
const Eolian_Class *icl;
const Eolian_Class *icl = cl->parent;
if (icl)
_add_dep(depset, icl->base.unit);
Eina_Iterator *itr = eina_list_iterator_new(cl->extends);
EINA_ITERATOR_FOREACH(itr, icl)
_add_dep(depset, icl->base.unit);
eina_iterator_free(itr);

View File

@ -48,11 +48,18 @@ eolian_class_data_type_get(const Eolian_Class *cl)
return cl->data_type;
}
EAPI const Eolian_Class *
eolian_class_parent_get(const Eolian_Class *cl)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cl, NULL);
return cl->parent;
}
EAPI Eina_Iterator *
eolian_class_inherits_get(const Eolian_Class *cl)
eolian_class_extensions_get(const Eolian_Class *cl)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(cl, NULL);
return (cl->inherits ? eina_list_iterator_new(cl->inherits) : NULL);
return (cl->extends ? eina_list_iterator_new(cl->extends) : NULL);
}
EAPI Eina_Iterator *

View File

@ -497,8 +497,8 @@ _get_impl_class(const Eolian_Class *cl, const char *cln)
if (!cl || !strcmp(cl->base.name, cln))
return cl;
Eina_List *l;
Eolian_Class *icl;
EINA_LIST_FOREACH(cl->inherits, l, icl)
Eolian_Class *icl = cl->parent;
if (icl)
{
/* we can do a depth first search, it's easier and doesn't matter
* which part of the inheritance tree we find the class in
@ -507,6 +507,12 @@ _get_impl_class(const Eolian_Class *cl, const char *cln)
if (fcl)
return fcl;
}
EINA_LIST_FOREACH(cl->extends, l, icl)
{
const Eolian_Class *fcl = _get_impl_class(icl, cln);
if (fcl)
return fcl;
}
return NULL;
}
@ -703,6 +709,29 @@ end:
return ret;
}
static Eina_Bool
_db_swap_inherit(Eolian_Class *cl, Eina_Bool succ, Eina_Stringshare *in_cl,
Eolian_Class **out_cl)
{
if (!succ)
{
eina_stringshare_del(in_cl);
return EINA_FALSE;
}
Eolian_Class *icl = eina_hash_find(cl->base.unit->classes, in_cl);
if (!icl)
{
succ = EINA_FALSE;
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "unknown inherit '%s' (incorrect case?)", in_cl);
_obj_error(&cl->base, buf);
}
else
*out_cl = icl;
eina_stringshare_del(in_cl);
return succ;
}
static Eina_Bool
_db_fill_inherits(Eolian_Class *cl, Eina_Hash *fhash)
{
@ -713,37 +742,32 @@ _db_fill_inherits(Eolian_Class *cl, Eina_Hash *fhash)
if (eina_hash_find(cl->base.unit->state->main.unit.classes, cl->base.name))
return EINA_TRUE;
Eina_List *il = cl->inherits;
Eina_List *il = cl->extends;
Eina_Stringshare *inn = NULL;
cl->inherits = NULL;
cl->extends = NULL;
Eina_Bool succ = EINA_TRUE;
EINA_LIST_FREE(il, inn)
if (cl->parent_name)
{
if (!succ)
succ = _db_swap_inherit(cl, succ, cl->parent_name, &cl->parent);
if (succ)
{
eina_stringshare_del(inn);
continue;
}
Eolian_Class *icl = eina_hash_find(cl->base.unit->classes, inn);
if (!icl)
{
succ = EINA_FALSE;
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "unknown inherit '%s' (incorrect case?)", inn);
_obj_error(&cl->base, buf);
}
else
{
cl->inherits = eina_list_append(cl->inherits, icl);
/* fill if not found, but do not return right away because
* the rest of the list needs to be freed in order not to
* leak any memory
*/
if (!_db_fill_inherits(icl, fhash))
succ = EINA_FALSE;
succ = _db_fill_inherits(cl->parent, fhash);
}
eina_stringshare_del(inn);
}
EINA_LIST_FREE(il, inn)
{
Eolian_Class *out_cl = NULL;
succ = _db_swap_inherit(cl, succ, inn, &out_cl);
if (!succ)
continue;
cl->extends = eina_list_append(cl->extends, out_cl);
succ = _db_fill_inherits(out_cl, fhash);
}
/* failed on the way, no point in filling further
@ -800,34 +824,30 @@ _validate_class(Validate_State *vals, Eolian_Class *cl,
Eina_Bool valid = cl->base.validated;
EINA_LIST_FOREACH(cl->inherits, l, icl)
if (cl->parent)
{
/* first inherit needs some checking done on it */
if (!valid && (l == cl->inherits)) switch (cl->type)
if (!valid) switch (cl->type)
{
case EOLIAN_CLASS_REGULAR:
case EOLIAN_CLASS_ABSTRACT:
if (icl->type != EOLIAN_CLASS_REGULAR && icl->type != EOLIAN_CLASS_ABSTRACT)
if (cl->parent->type != EOLIAN_CLASS_REGULAR && cl->parent->type != EOLIAN_CLASS_ABSTRACT)
{
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "regular classes ('%s') cannot inherit from non-regular classes ('%s')",
cl->base.name, icl->base.name);
return _obj_error(&cl->base, buf);
}
break;
case EOLIAN_CLASS_MIXIN:
case EOLIAN_CLASS_INTERFACE:
if (icl->type != EOLIAN_CLASS_MIXIN && icl->type != EOLIAN_CLASS_INTERFACE)
{
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "non-regular classes ('%s') cannot inherit from regular classes ('%s')",
cl->base.name, icl->base.name);
cl->base.name, cl->parent->base.name);
return _obj_error(&cl->base, buf);
}
break;
default:
break;
}
if (!_validate_class(vals, cl->parent, nhash, ehash, chash))
return EINA_FALSE;
}
EINA_LIST_FOREACH(cl->extends, l, icl)
{
if (!_validate_class(vals, icl, nhash, ehash, chash))
return EINA_FALSE;
}

View File

@ -1951,8 +1951,9 @@ parse_class_body(Eo_Lexer *ls, Eolian_Class_Type type)
}
static void
_inherit_dep(Eo_Lexer *ls, Eina_Strbuf *buf)
_inherit_dep(Eo_Lexer *ls, Eina_Strbuf *buf, Eina_Bool parent)
{
char ebuf[PATH_MAX];
const char *iname;
char *fnm;
eina_strbuf_reset(buf);
@ -1962,7 +1963,6 @@ _inherit_dep(Eo_Lexer *ls, Eina_Strbuf *buf)
fnm = database_class_to_filename(iname);
if (compare_class_file(fnm, ls->filename))
{
char ebuf[PATH_MAX];
free(fnm);
eo_lexer_context_restore(ls);
snprintf(ebuf, sizeof(ebuf), "class '%s' cannot inherit from itself",
@ -1972,7 +1972,6 @@ _inherit_dep(Eo_Lexer *ls, Eina_Strbuf *buf)
}
if (!eina_hash_find(ls->state->filenames_eo, fnm))
{
char ebuf[PATH_MAX];
free(fnm);
eo_lexer_context_restore(ls);
snprintf(ebuf, sizeof(ebuf), "unknown inherit '%s'", iname);
@ -1981,25 +1980,33 @@ _inherit_dep(Eo_Lexer *ls, Eina_Strbuf *buf)
}
Eina_Stringshare *inames = eina_stringshare_add(iname), *oiname = NULL;
Eina_List *l;
/* never allow duplicate inherits */
EINA_LIST_FOREACH(ls->klass->inherits, l, oiname)
if (!parent)
{
if (inames == oiname)
Eina_List *l;
if (inames == ls->klass->parent_name)
goto inherit_dup;
EINA_LIST_FOREACH(ls->klass->extends, l, oiname)
{
char ebuf[PATH_MAX];
free(fnm);
eina_stringshare_del(inames);
eo_lexer_context_restore(ls);
snprintf(ebuf, sizeof(ebuf), "duplicate inherit '%s'", iname);
eo_lexer_syntax_error(ls, ebuf);
return;
if (inames == oiname)
goto inherit_dup;
}
}
database_defer(ls->state, fnm, EINA_TRUE);
ls->klass->inherits = eina_list_append(ls->klass->inherits, inames);
if (parent)
ls->klass->parent_name = inames;
else
ls->klass->extends = eina_list_append(ls->klass->extends, inames);
free(fnm);
eo_lexer_context_pop(ls);
return;
inherit_dup:
free(fnm);
eina_stringshare_del(inames);
eo_lexer_context_restore(ls);
snprintf(ebuf, sizeof(ebuf), "duplicate inherit '%s'", iname);
eo_lexer_syntax_error(ls, ebuf);
}
static void
@ -2045,9 +2052,10 @@ parse_class(Eo_Lexer *ls, Eolian_Class_Type type)
{
Eina_Strbuf *ibuf = eina_strbuf_new();
eo_lexer_dtor_push(ls, EINA_FREE_CB(eina_strbuf_free), ibuf);
_inherit_dep(ls, ibuf);
_inherit_dep(ls, ibuf,
(type == EOLIAN_CLASS_REGULAR) || (type == EOLIAN_CLASS_ABSTRACT));
while (test_next(ls, ','))
_inherit_dep(ls, ibuf);
_inherit_dep(ls, ibuf, EINA_FALSE);
eo_lexer_dtor_pop(ls);
}
check_match(ls, ')', '(', line, col);

View File

@ -180,7 +180,11 @@ struct _Eolian_Class
Eina_Stringshare *eo_prefix;
Eina_Stringshare *ev_prefix;
Eina_Stringshare *data_type;
Eina_List *inherits; /* Eolian_Class */
union {
Eolian_Class *parent;
Eina_Stringshare *parent_name;
};
Eina_List *extends; /* Eolian_Class */
Eina_List *properties; /* Eolian_Function */
Eina_List *methods; /* Eolian_Function */
Eina_List *implements; /* Eolian_Implement */

View File

@ -1036,7 +1036,9 @@ struct klass_def
functions.push_back({function, EOLIAN_METHOD, NULL, unit});
} catch(std::exception const&) {}
}
for(efl::eina::iterator<Eolian_Class const> inherit_iterator ( ::eolian_class_inherits_get(klass))
if(::eolian_class_parent_get(klass))
immediate_inherits.insert({::eolian_class_parent_get(klass), {}});
for(efl::eina::iterator<Eolian_Class const> inherit_iterator ( ::eolian_class_extensions_get(klass))
, inherit_last; inherit_iterator != inherit_last; ++inherit_iterator)
{
Eolian_Class const* inherit = &*inherit_iterator;
@ -1045,7 +1047,13 @@ struct klass_def
std::function<void(Eolian_Class const*)> inherit_algo =
[&] (Eolian_Class const* inherit_klass)
{
for(efl::eina::iterator<Eolian_Class const> inherit_iterator ( ::eolian_class_inherits_get(inherit_klass))
if(::eolian_class_parent_get(inherit_klass))
{
Eolian_Class const* inherit = ::eolian_class_parent_get(inherit_klass);
inherits.insert({inherit, {}});
inherit_algo(inherit);
}
for(efl::eina::iterator<Eolian_Class const> inherit_iterator ( ::eolian_class_extensions_get(inherit_klass))
, inherit_last; inherit_iterator != inherit_last; ++inherit_iterator)
{
Eolian_Class const* inherit = &*inherit_iterator;

View File

@ -686,9 +686,14 @@ class Class(Object):
_str_to_bytes(event_name))
return Event(c_event) if c_event else None
@cached_property
def parent(self):
c_class = lib.eolian_class_parent_get(self)
return Class(c_class) if c_class else None
@property
def inherits(self):
return Iterator(Class, lib.eolian_class_inherits_get(self))
def extensions(self):
return Iterator(Class, lib.eolian_class_extensions_get(self))
@cached_property
def inherits_full(self):

View File

@ -254,9 +254,13 @@ lib.eolian_class_event_prefix_get.restype = c_char_p
lib.eolian_class_data_type_get.argtypes = (c_void_p,)
lib.eolian_class_data_type_get.restype = c_char_p
# EAPI Eina_Iterator *eolian_class_inherits_get(const Eolian_Class *klass);
lib.eolian_class_inherits_get.argtypes = (c_void_p,)
lib.eolian_class_inherits_get.restype = c_void_p
# EAPI const Eolian_Class *eolian_class_parent_get(const Eolian_Class *klass);
lib.eolian_class_parent_get.argtypes = (c_void_p,)
lib.eolian_class_parent_get.restype = c_void_p
# EAPI Eina_Iterator *eolian_class_extensions_get(const Eolian_Class *klass);
lib.eolian_class_extensions_get.argtypes = (c_void_p,)
lib.eolian_class_extensions_get.restype = c_void_p
# EAPI Eina_Iterator *eolian_class_functions_get(const Eolian_Class *klass, Eolian_Function_Type func_type);
lib.eolian_class_functions_get.argtypes = (c_void_p, c_int)

View File

@ -61,9 +61,8 @@ EFL_START_TEST(eolian_namespaces)
fail_if(eolian_class_namespaces_get(class_no));
/* Inherits */
fail_if(!(iter = eolian_class_inherits_get(class11)));
fail_if(!(eina_iterator_next(iter, (void**)&iclass)));
fail_if(iclass != class112);
fail_if(eolian_class_parent_get(class11) != class112);
fail_if(!(iter = eolian_class_extensions_get(class11)));
fail_if(!(eina_iterator_next(iter, (void**)&iclass)));
fail_if(iclass != class21);
fail_if(!(eina_iterator_next(iter, (void**)&iclass)));
@ -551,7 +550,8 @@ EFL_START_TEST(eolian_simple_parsing)
/* Class */
fail_if(eolian_class_type_get(class) != EOLIAN_CLASS_REGULAR);
fail_if(eolian_class_inherits_get(class) != NULL);
fail_if(eolian_class_parent_get(class) != NULL);
fail_if(eolian_class_extensions_get(class) != NULL);
fail_if(strcmp(eolian_class_legacy_prefix_get(class), "evas_object_simple"));
fail_if(strcmp(eolian_class_eo_prefix_get(class), "efl_canvas_object_simple"));
fail_if(strcmp(eolian_class_data_type_get(class), "Evas_Simple_Data"));