Eolian: add support of namespaces.

It is now possible to define a class in a .eo file as e.g:
Elm::Widgets::Button.
Elm and Widgets will be the namespaces of the class Button.

@feature
This commit is contained in:
Daniel Zaoui 2014-05-25 13:53:49 +03:00
parent eb58e70ce9
commit 8e4700ce65
8 changed files with 1372 additions and 1171 deletions

View File

@ -96,5 +96,6 @@ tests/eolian/data/object_impl_add.eo \
tests/eolian/data/object_impl_add_ref.c \
tests/eolian/data/consts.eo \
tests/eolian/data/override.eo \
tests/eolian/data/events.eo
tests/eolian/data/events.eo \
tests/eolian/data/namespace.eo

View File

@ -206,6 +206,18 @@ eolian_class_find_by_file(const char *file_name);
EAPI const char *
eolian_class_file_get(const Eolian_Class klass);
/*
* @brief Returns the full name of the given class.
*
* @param[in] class the class.
* @return the full name of the class on success or NULL otherwise.
*
* The full name and the name of a class will be different if namespaces
* are used.
*/
EAPI const char *
eolian_class_full_name_get(const Eolian_Class klass);
/*
* @brief Returns the name of the given class.
*
@ -215,6 +227,15 @@ eolian_class_file_get(const Eolian_Class klass);
EAPI const char *
eolian_class_name_get(const Eolian_Class klass);
/*
* @brief Returns the namespaces list of the given class.
*
* @param[in] class the class.
* @return the namespaces list of the class on success or NULL otherwise.
*/
EAPI const Eina_List *
eolian_class_namespaces_list_get(const Eolian_Class klass);
/*
* @brief Returns the class type of the given class
*

File diff suppressed because it is too large Load Diff

View File

@ -429,8 +429,9 @@ _eo_tokenizer_implement_get(Eo_Tokenizer *toknz, char *p)
alnum_u = alnum | '_';
alpha_u = alpha | '_';
ident = alpha+ >save_fpc (alnum | '_' )*;
event = alpha+ >save_fpc (alnum | '_' | ',' )*;
event = alpha+ >save_fpc (alnum | '_' | ',' )*;
class_meth = alpha+ >save_fpc (alnum | '_' | '::' )*;
class_name = alpha+ >save_fpc (alnum | '_' | '::' )*;
eo_comment = "/*@" ignore* ('@' | alnum_u) >save_fpc ( any | cr @inc_line )* :>> "*/";
c_comment = "/*" ( any | cr @inc_line )* :>> "*/";
@ -894,7 +895,7 @@ _eo_tokenizer_implement_get(Eo_Tokenizer *toknz, char *p)
data_type = 'data' ignore* colon ignore* ident %end_data_type end_statement ignore*;
class_it = ident %end_str_item ignore*;
class_it = class_name %end_str_item ignore*;
class_it_next = list_separator ignore* class_it;
inherits = begin_list (class_it class_it_next*)? end_list %end_inherits;
@ -962,12 +963,11 @@ _eo_tokenizer_implement_get(Eo_Tokenizer *toknz, char *p)
toknz->tmp.kls->type = toknz->tmp.kls_type;
}
class_name = ident %end_class_name;
begin_class = (
"class" %class_type_set_to_class |
"mixin" %class_type_set_to_mixin |
"abstract" %class_type_set_to_abstract |
"interface" %class_type_set_to_interface) ws+ class_name ws* inherits? ignore* begin_def;
"interface" %class_type_set_to_interface) ws+ class_name %end_class_name ws* inherits? ignore* begin_def;
action end_typedef_alias {
toknz->tmp.typedef_alias = _eo_tokenizer_token_get(toknz, fpc);
@ -1512,44 +1512,44 @@ eo_tokenizer_database_fill(const char *filename)
EINA_LIST_FOREACH(kls->implements, l, impl)
{
const char *impl_class = impl->meth_name;
Eina_Bool virtual_pure = EINA_FALSE;
if (!strcmp(impl_class, "class::constructor"))
const char *impl_name = impl->meth_name;
if (!strcmp(impl_name, "class::constructor"))
{
database_class_ctor_enable_set(class, EINA_TRUE);
continue;
}
if (!strcmp(impl_class, "class::destructor"))
if (!strcmp(impl_name, "class::destructor"))
{
database_class_dtor_enable_set(class, EINA_TRUE);
continue;
}
if (!strncmp(impl_class, "virtual::", 9)) virtual_pure = EINA_TRUE;
char *func = strstr(impl_class, "::");
if (func) *func = '\0';
func += 2;
Eolian_Function_Type ftype = EOLIAN_UNRESOLVED;
char *type_as_str = strstr(func, "::");
if (type_as_str)
{
*type_as_str = '\0';
if (!strcmp(type_as_str+2, "set")) ftype = EOLIAN_PROP_SET;
else if (!strcmp(type_as_str+2, "get")) ftype = EOLIAN_PROP_GET;
}
if (virtual_pure)
if (!strncmp(impl_name, "virtual::", 9))
{
char *virtual_name = strdup(impl_name);
char *func = strstr(virtual_name, "::");
if (func) *func = '\0';
func += 2;
Eolian_Function_Type ftype = EOLIAN_UNRESOLVED;
char *type_as_str = strstr(func, "::");
if (type_as_str)
{
*type_as_str = '\0';
if (!strcmp(type_as_str+2, "set")) ftype = EOLIAN_PROP_SET;
else if (!strcmp(type_as_str+2, "get")) ftype = EOLIAN_PROP_GET;
}
/* Search the function into the existing functions of the current class */
Eolian_Function foo_id = eolian_class_function_find_by_name(
class, func, ftype);
free(virtual_name);
if (!foo_id)
{
ERR("Error - %s not known in class %s", impl_class + 9, eolian_class_name_get(class));
ERR("Error - %s not known in class %s", impl_name + 9, eolian_class_name_get(class));
goto end;
}
database_function_set_as_virtual_pure(foo_id, ftype);
continue;
}
Eolian_Implement impl_desc = database_implement_new(impl_class, func, ftype);
Eolian_Implement impl_desc = database_implement_new(impl_name);
database_class_implement_add(class, impl_desc);
}

View File

@ -21,6 +21,8 @@ static int _database_init_count = 0;
typedef struct
{
Eina_Stringshare *full_name;
Eina_List *namespaces; /* List Eina_Stringshare * */
Eina_Stringshare *name;
Eina_Stringshare *file;
Eolian_Class_Type type;
@ -81,9 +83,7 @@ typedef struct
typedef struct
{
Eina_Stringshare *class_name;
Eina_Stringshare *func_name;
Eolian_Function_Type type;
Eina_Stringshare *full_name;
} _Implement_Desc;
typedef struct
@ -141,8 +141,7 @@ _class_del(_Class_Desc *class)
Eina_List *implements = class->implements;
EINA_LIST_FREE(implements, impl)
{
eina_stringshare_del(impl->class_name);
eina_stringshare_del(impl->func_name);
eina_stringshare_del(impl->full_name);
free(impl);
}
@ -154,6 +153,7 @@ _class_del(_Class_Desc *class)
EINA_LIST_FREE(class->events, ev) database_event_free(ev);
eina_stringshare_del(class->name);
eina_stringshare_del(class->full_name);
eina_stringshare_del(class->file);
eina_stringshare_del(class->description);
eina_stringshare_del(class->legacy_prefix);
@ -229,11 +229,27 @@ eolian_type_find_by_alias(const char *alias)
Eolian_Class
database_class_add(const char *class_name, Eolian_Class_Type type)
{
_Class_Desc *cl = NULL;
cl = calloc(1, sizeof(*cl));
cl->name = eina_stringshare_add(class_name);
char *full_name = strdup(class_name);
char *name = full_name;
char *colon = full_name;
_Class_Desc *cl = calloc(1, sizeof(*cl));
cl->full_name = eina_stringshare_add(class_name);
cl->type = type;
do
{
colon = strstr(colon, "::");
if (colon)
{
*colon = '\0';
cl->namespaces = eina_list_append(cl->namespaces, eina_stringshare_add(name));
colon += 2;
name = colon;
}
}
while(colon);
cl->name = eina_stringshare_add(name);
_classes = eina_list_append(_classes, cl);
free(full_name);
return (Eolian_Class)cl;
}
@ -253,6 +269,13 @@ eolian_class_file_get(const Eolian_Class class)
return cl ? cl->file : NULL;
}
EAPI const char *
eolian_class_full_name_get(const Eolian_Class class)
{
_Class_Desc *cl = (_Class_Desc *)class;
return cl ? cl->full_name : NULL;
}
EAPI const char *
eolian_class_name_get(const Eolian_Class class)
{
@ -260,6 +283,13 @@ eolian_class_name_get(const Eolian_Class class)
return cl ? cl->name : NULL;
}
EAPI const Eina_List *
eolian_class_namespaces_list_get(const Eolian_Class class)
{
_Class_Desc *cl = (_Class_Desc *)class;
return cl ? cl->namespaces : NULL;
}
EAPI Eolian_Class
eolian_class_find_by_name(const char *class_name)
{
@ -267,14 +297,48 @@ eolian_class_find_by_name(const char *class_name)
_Class_Desc *cl;
Eina_Stringshare *shr_name = eina_stringshare_add(class_name);
EINA_LIST_FOREACH(_classes, itr, cl)
if (cl->full_name == shr_name) goto end;
cl = NULL;
end:
eina_stringshare_del(shr_name);
return (Eolian_Class)cl;
}
/*
* ret false -> clash, class = NULL
* ret true && class -> only one class corresponding
* ret true && !class -> no class corresponding
*/
Eina_Bool database_class_name_validate(const char *class_name, Eolian_Class *class)
{
char *name = strdup(class_name);
char *colon = name + 1;
Eolian_Class found_class = NULL;
Eolian_Class candidate;
if (class) *class = NULL;
do
{
if (cl->name == shr_name)
colon = strstr(colon, "::");
if (colon) *colon = '\0';
candidate = eolian_class_find_by_name(name);
if (candidate)
{
eina_stringshare_del(shr_name);
return (Eolian_Class)cl;
if (found_class)
{
ERR("Name clash between class %s and class %s",
((_Class_Desc *)candidate)->full_name,
((_Class_Desc *)found_class)->full_name);
free(name);
return EINA_FALSE; // Names clash
}
found_class = candidate;
}
if (colon) *colon++ = ':';
}
return NULL;
while(colon);
if (class) *class = found_class;
free(name);
return EINA_TRUE;
}
EAPI Eolian_Class
@ -284,15 +348,11 @@ eolian_class_find_by_file(const char *file_name)
_Class_Desc *cl;
Eina_Stringshare *shr_file = eina_stringshare_add(file_name);
EINA_LIST_FOREACH(_classes, itr, cl)
{
if (cl->file == shr_file)
{
eina_stringshare_del(shr_file);
return (Eolian_Class)cl;
}
}
if (cl->file == shr_file) goto end;
cl = NULL;
end:
eina_stringshare_del(shr_file);
return NULL;
return (Eolian_Class)cl;
}
EAPI Eolian_Class_Type
@ -486,14 +546,11 @@ Eina_Bool database_class_function_add(Eolian_Class class, Eolian_Function foo_id
}
Eolian_Implement
database_implement_new(const char *class_name, const char *func_name, Eolian_Function_Type type)
database_implement_new(const char *impl_name)
{
EINA_SAFETY_ON_FALSE_RETURN_VAL(class_name && func_name, NULL);
_Implement_Desc *impl_desc = calloc(1, sizeof(_Implement_Desc));
EINA_SAFETY_ON_NULL_RETURN_VAL(impl_desc, NULL);
impl_desc->class_name = eina_stringshare_add(class_name);
impl_desc->func_name = eina_stringshare_add(func_name);
impl_desc->type = type;
impl_desc->full_name = eina_stringshare_add(impl_name);
return (Eolian_Implement) impl_desc;
}
@ -508,13 +565,30 @@ database_class_implement_add(Eolian_Class class, Eolian_Implement impl_desc)
}
EAPI Eina_Bool
eolian_implement_information_get(Eolian_Implement impl, const char **class_name, const char **func_name, Eolian_Function_Type *type)
eolian_implement_information_get(Eolian_Implement impl, const char **class_name_out, const char **func_name_out, Eolian_Function_Type *type_out)
{
_Implement_Desc *_impl = (_Implement_Desc *)impl;
EINA_SAFETY_ON_NULL_RETURN_VAL(_impl, EINA_FALSE);
if (class_name) *class_name = _impl->class_name;
if (func_name) *func_name = _impl->func_name;
if (type) *type = _impl->type;
Eolian_Class class;
if (!database_class_name_validate(_impl->full_name, &class) || !class) return EINA_FALSE;
const char *class_name = ((_Class_Desc *)class)->full_name;
if (class_name_out) *class_name_out = class_name;
char *func_name = strdup(_impl->full_name + strlen(class_name) + 2);
char *colon = strstr(func_name, "::");
Eolian_Function_Type type = EOLIAN_UNRESOLVED;
if (colon)
{
*colon = '\0';
if (!strcmp(colon+2, "set")) type = EOLIAN_PROP_SET;
else if (!strcmp(colon+2, "get")) type = EOLIAN_PROP_GET;
}
Eolian_Function fid = eolian_class_function_find_by_name(class, func_name, type);
if (func_name_out) *func_name_out = eolian_function_name_get(fid);
if (type == EOLIAN_UNRESOLVED) type = eolian_function_type_get(fid);
if (type_out) *type_out = type;
free(func_name);
return EINA_TRUE;
}
@ -1339,18 +1413,16 @@ EAPI Eina_Bool eolian_eo_file_parse(const char *filepath)
}
EINA_LIST_FOREACH(eolian_class_implements_list_get(class), itr, impl)
{
_Implement_Desc *_impl = (_Implement_Desc *)impl;
Eolian_Class impl_class = eolian_class_find_by_name(_impl->class_name);
Eolian_Function foo = eolian_class_function_find_by_name(impl_class, _impl->func_name, _impl->type);
const char *impl_classname = NULL, *impl_func = NULL;
Eolian_Function_Type impl_type = EOLIAN_UNRESOLVED;
eolian_implement_information_get(impl, &impl_classname, &impl_func, &impl_type);
Eolian_Class impl_class = eolian_class_find_by_name(impl_classname);
Eolian_Function foo = eolian_class_function_find_by_name(impl_class, impl_func, impl_type);
if (!foo)
{
ERR("Unable to find function %s in class %s", _impl->func_name, _impl->class_name);
ERR("Unable to find function %s in class %s", impl_func, impl_classname);
return EINA_FALSE;
}
if (_impl->type == EOLIAN_UNRESOLVED)
{
_impl->type = eolian_function_type_get(foo);
}
}
return EINA_TRUE;
}

View File

@ -117,7 +117,7 @@ database_function_scope_set(Eolian_Function function_id, Eolian_Function_Scope s
/* Need to add API for callbacks and implements */
Eolian_Implement
database_implement_new(const char *class_name, const char *func_name, Eolian_Function_Type type);
database_implement_new(const char *impl_name);
Eina_Bool
database_class_implement_add(Eolian_Class class, Eolian_Implement impl_id);

View File

@ -0,0 +1,33 @@
class nmsp1::nmsp11::class2
{
properties {
a {
set {
}
}
}
implements {
virtual::a::set;
}
}
class nmsp2::class1
{
}
class no_nmsp
{
methods {
foo {
}
}
}
class nmsp1::class1 (nmsp1::nmsp11::class2, nmsp2::class1, no_nmsp)
{
implements {
nmsp1::nmsp11::class2::a::set;
nmsp1::bad_class::a::set;
no_nmsp::foo;
}
}

View File

@ -9,6 +9,78 @@
#include "Eolian.h"
#include "eolian_suite.h"
START_TEST(eolian_namespaces)
{
Eolian_Class class11, class112, class21, class_no;
Eolian_Function fid;
const Eina_List *list = NULL;
const char *class_name, *func_name;
Eolian_Function_Type func_type;
eolian_init();
/* Parsing */
fail_if(!eolian_eo_file_parse(PACKAGE_DATA_DIR"/data/namespace.eo"));
/* Classes existence */
fail_if(!(class11 = eolian_class_find_by_name("nmsp1::class1")));
fail_if(!(class112 = eolian_class_find_by_name("nmsp1::nmsp11::class2")));
fail_if(!(class21 = eolian_class_find_by_name("nmsp2::class1")));
fail_if(!(class_no = eolian_class_find_by_name("no_nmsp")));
/* Check names and namespaces*/
fail_if(strcmp(eolian_class_name_get(class11), "class1"));
fail_if(!(list = eolian_class_namespaces_list_get(class11)));
fail_if(eina_list_count(list) != 1);
fail_if(strcmp(eina_list_nth(list, 0), "nmsp1"));
fail_if(strcmp(eolian_class_name_get(class112), "class2"));
fail_if(!(list = eolian_class_namespaces_list_get(class112)));
fail_if(eina_list_count(list) != 2);
fail_if(strcmp(eina_list_nth(list, 0), "nmsp1"));
fail_if(strcmp(eina_list_nth(list, 1), "nmsp11"));
fail_if(strcmp(eolian_class_name_get(class21), "class1"));
fail_if(!(list = eolian_class_namespaces_list_get(class21)));
fail_if(eina_list_count(list) != 1);
fail_if(strcmp(eina_list_nth(list, 0), "nmsp2"));
fail_if(strcmp(eolian_class_name_get(class_no), "no_nmsp"));
fail_if(eolian_class_namespaces_list_get(class_no));
/* Inherits */
fail_if(!(list = eolian_class_inherits_list_get(class11)));
fail_if(eina_list_count(list) != 3);
class_name = eina_list_nth(list, 0);
fail_if(eolian_class_find_by_name(class_name) != class112);
class_name = eina_list_nth(list, 1);
fail_if(eolian_class_find_by_name(class_name) != class21);
class_name = eina_list_nth(list, 2);
fail_if(eolian_class_find_by_name(class_name) != class_no);
/* Implements */
fail_if(!(list = eolian_class_implements_list_get(class11)));
fail_if(eina_list_count(list) != 3);
fail_if(!eolian_implement_information_get(eina_list_nth(list, 0),
&class_name, &func_name, &func_type));
fail_if(eolian_class_find_by_name(class_name) != class112);
fail_if(strcmp(func_name, "a"));
fail_if(func_type != EOLIAN_PROP_SET);
fail_if(eolian_implement_information_get(eina_list_nth(list, 1),
&class_name, &func_name, &func_type));
fail_if(!eolian_implement_information_get(eina_list_nth(list, 2),
&class_name, &func_name, &func_type));
fail_if(eolian_class_find_by_name(class_name) != class_no);
fail_if(strcmp(func_name, "foo"));
fail_if(func_type != EOLIAN_METHOD);
/* Virtual regression */
fail_if(!(fid = eolian_class_function_find_by_name(class112, "a", EOLIAN_UNRESOLVED)));
fail_if(!eolian_function_is_virtual_pure(fid, EOLIAN_PROP_SET));
eolian_shutdown();
}
END_TEST
START_TEST(eolian_events)
{
Eolian_Class class;
@ -378,5 +450,6 @@ void eolian_parsing_test(TCase *tc)
tcase_add_test(tc, eolian_consts);
tcase_add_test(tc, eolian_override);
tcase_add_test(tc, eolian_events);
tcase_add_test(tc, eolian_namespaces);
}