eolian: deferred parsing of inherits + better static checks

This change finally introduces deferred parsing of inherits to
Eolian, after a long time and many iterations. That means instead
of parsing inherits directly as part of the main file's parse pass,
they're pushed into a queue and parsed later. The validation engine
was modified to properly fill in the remaining info afterwards.

This may introduce breakages but I haven't noticed any. It also
properly unlocks cyclic dependency support in Eolian.

Additionally, this also introduces checks for duplicates in class
inherits (class Foo(Bar, Bar) is no longer possible) and it adds
stricter name checks, so you can no longer have a class Foo.Bar
and refer to it as Foo_Bar in implements. This was actually never
meant to be supported, but the check was previously broken.

@feature
This commit is contained in:
Daniel Kolesa 2018-01-30 17:03:37 +01:00
parent 7b643f6919
commit 5651b2e586
6 changed files with 88 additions and 23 deletions

View File

@ -1,4 +1,4 @@
interface EFl.Ui.Legacy (Efl.Interface)
interface Efl.Ui.Legacy (Efl.Interface)
{
[[The bg (background) widget is used for setting (solid) background decorations

View File

@ -99,7 +99,7 @@ class Efl.Ui.List (Efl.Ui.Layout, Efl.Ui.View, Efl.Ui.Scrollable.Interactive, Ef
Efl.Layout.Signal.signal_callback_add;
Efl.Layout.Signal.signal_callback_del;
// Elm.Interface.Atspi_Accessible.children { get; }
// Elm.Interface.Atspi_Widget_Action.elm_actions { get; }
// Elm.Interface.Atspi_Widget.Action.elm_actions { get; }
// Efl.Access.Widget.Action.elm_actions { get; }
Efl.Access.Selection.selected_children_count { get; }
Efl.Access.Selection.selected_child { get; }

View File

@ -3,7 +3,7 @@ import elm_list;
import elm_genlist_item;
class Elm.Genlist (Efl.Ui.Layout, Efl.Ui.Focus.Composition, Elm.Interface_Scrollable, Efl.Ui.Clickable,
Efl.Access.Widget_Action, Efl.Access.Selection,
Efl.Access.Widget.Action, Efl.Access.Selection,
Efl.Ui.Selectable, Efl.Ui.Legacy)
{
[[Elementary genlist class]]

View File

@ -644,6 +644,54 @@ end:
return ret;
}
static Eina_Bool
_db_fill_inherits(const Eolian_Unit *src, Eolian_Class *cl, Eina_Hash *fhash)
{
if (eina_hash_find(fhash, cl->full_name))
return EINA_TRUE;
Eina_List *il = cl->inherits;
Eina_Stringshare *inn = NULL;
cl->inherits = NULL;
Eina_Bool succ = EINA_TRUE;
EINA_LIST_FREE(il, inn)
{
if (!succ)
{
eina_stringshare_del(inn);
continue;
}
Eolian_Class *icl = eina_hash_find(src->state->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);
/* recursively fill so the tree is valid */
if (!icl->base.validated && !_db_fill_inherits(src, icl, fhash))
succ = EINA_FALSE;
}
eina_stringshare_del(inn);
}
eina_hash_add(fhash, cl->full_name, cl);
/* make sure impls/ctors are filled first, but do it only once */
if (!_db_fill_implements(cl))
return EINA_FALSE;
if (!_db_fill_ctors(cl))
return EINA_FALSE;
return succ;
}
static Eina_Bool
_validate_implement(const Eolian_Unit *src, Eolian_Implement *impl)
{
@ -661,7 +709,8 @@ _validate_implement(const Eolian_Unit *src, Eolian_Implement *impl)
}
static Eina_Bool
_validate_class(const Eolian_Unit *src, Eolian_Class *cl, Eina_Hash *nhash)
_validate_class(const Eolian_Unit *src, Eolian_Class *cl,
Eina_Hash *nhash, Eina_Bool ipass)
{
Eina_List *l;
Eolian_Function *func;
@ -675,12 +724,17 @@ _validate_class(const Eolian_Unit *src, Eolian_Class *cl, Eina_Hash *nhash)
Eina_Bool valid = cl->base.validated;
/* make sure impls/ctors are filled first, but do it only once */
if (!valid && !_db_fill_implements(cl))
return EINA_FALSE;
if (!valid && !_db_fill_ctors(cl))
return EINA_FALSE;
/* refill inherits in the current inheritance tree first */
if (!valid && !ipass)
{
Eina_Hash *fhash = eina_hash_stringshared_new(NULL);
if (!_db_fill_inherits(src, cl, fhash))
{
eina_hash_free(fhash);
return EINA_FALSE;
}
eina_hash_free(fhash);
}
EINA_LIST_FOREACH(cl->inherits, l, icl)
{
@ -710,7 +764,7 @@ _validate_class(const Eolian_Unit *src, Eolian_Class *cl, Eina_Hash *nhash)
default:
break;
}
if (!_validate_class(src, icl, nhash))
if (!_validate_class(src, icl, nhash, EINA_TRUE))
return EINA_FALSE;
}
@ -786,7 +840,7 @@ database_validate(Eolian *state, const Eolian_Unit *src)
EINA_ITERATOR_FOREACH(iter, cl)
{
eina_hash_free_buckets(nhash);
if (!_validate_class(src, cl, nhash))
if (!_validate_class(src, cl, nhash, EINA_FALSE))
{
eina_iterator_free(iter);
eina_hash_free(nhash);

View File

@ -2038,24 +2038,35 @@ _inherit_dep(Eo_Lexer *ls, Eina_Strbuf *buf)
return; /* unreachable (longjmp above), make static analysis shut up */
}
fname = eina_hash_find(ls->state->filenames_eo, fnm);
free(fnm);
if (!fname)
{
char ebuf[PATH_MAX];
free(fnm);
eo_lexer_context_restore(ls);
snprintf(ebuf, sizeof(ebuf), "unknown inherit '%s'", iname);
eo_lexer_syntax_error(ls, ebuf);
}
Eolian_Class *dep = _parse_dep(ls, fname, iname);
if (!dep)
{
char ebuf[PATH_MAX];
eo_lexer_context_restore(ls);
snprintf(ebuf, sizeof(ebuf), "unknown inherit '%s'. Incorrect case?", iname);
eo_lexer_syntax_error(ls, ebuf);
return;
}
ls->tmp.kls->inherits = eina_list_append(ls->tmp.kls->inherits, dep);
Eina_Stringshare *inames = eina_stringshare_add(iname), *oiname = NULL;
Eina_List *l;
/* never allow duplicate inherits */
EINA_LIST_FOREACH(ls->tmp.kls->inherits, l, oiname)
{
if (inames == 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;
}
}
eina_hash_set(ls->state->defer, fnm, fname);
ls->tmp.kls->inherits = eina_list_append(ls->tmp.kls->inherits, inames);
free(fnm);
eo_lexer_context_pop(ls);
}

View File

@ -1,4 +1,4 @@
class Efl.Input.Key (Efl.Object, Efl.Input.Event, Efl.Input.State, Efl.Input.Event)
class Efl.Input.Key (Efl.Object, Efl.Input.Event, Efl.Input.State)
{
[[Represents a single key event from a keyboard or similar device.