summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile_Eolian.am2
-rw-r--r--src/lib/eolian/database_validate.c92
-rw-r--r--src/lib/eolian/eo_lexer.h2
-rw-r--r--src/lib/eolian/eo_parser.c32
-rw-r--r--src/lib/eolian/eolian_database.h1
-rw-r--r--src/tests/eolian/data/class_requires.eo8
-rw-r--r--src/tests/eolian/data/mixins_require.eo13
-rw-r--r--src/tests/eolian/eolian_parsing.c62
8 files changed, 210 insertions, 2 deletions
diff --git a/src/Makefile_Eolian.am b/src/Makefile_Eolian.am
index 6d607ef950..5e1e2d01af 100644
--- a/src/Makefile_Eolian.am
+++ b/src/Makefile_Eolian.am
@@ -103,6 +103,8 @@ tests/eolian/data/typedef.eo \
103tests/eolian/data/var.eo \ 103tests/eolian/data/var.eo \
104tests/eolian/data/function_types.eot \ 104tests/eolian/data/function_types.eot \
105tests/eolian/data/import_types.eot \ 105tests/eolian/data/import_types.eot \
106tests/eolian/data/class_requires.eo \
107tests/eolian/data/mixins_require.eo \
106tests/eolian/data_aux/aux_a.eo \ 108tests/eolian/data_aux/aux_a.eo \
107tests/eolian/data_aux/aux_b.eo \ 109tests/eolian/data_aux/aux_b.eo \
108tests/eolian/data_aux/aux_c.eo 110tests/eolian/data_aux/aux_c.eo
diff --git a/src/lib/eolian/database_validate.c b/src/lib/eolian/database_validate.c
index a96e389010..09004c81c4 100644
--- a/src/lib/eolian/database_validate.c
+++ b/src/lib/eolian/database_validate.c
@@ -508,6 +508,12 @@ _get_impl_class(const Eolian_Class *cl, const char *cln)
508 if (fcl) 508 if (fcl)
509 return fcl; 509 return fcl;
510 } 510 }
511 EINA_LIST_FOREACH(cl->requires, l, icl)
512 {
513 const Eolian_Class *fcl = _get_impl_class(icl, cln);
514 if (fcl)
515 return fcl;
516 }
511 EINA_LIST_FOREACH(cl->extends, l, icl) 517 EINA_LIST_FOREACH(cl->extends, l, icl)
512 { 518 {
513 const Eolian_Class *fcl = _get_impl_class(icl, cln); 519 const Eolian_Class *fcl = _get_impl_class(icl, cln);
@@ -743,9 +749,10 @@ _db_fill_inherits(Eolian_Class *cl, Eina_Hash *fhash)
743 if (eina_hash_find(cl->base.unit->state->main.unit.classes, cl->base.name)) 749 if (eina_hash_find(cl->base.unit->state->main.unit.classes, cl->base.name))
744 return EINA_TRUE; 750 return EINA_TRUE;
745 751
746 Eina_List *il = cl->extends; 752 Eina_List *il = cl->extends, *rl = cl->requires;
747 Eina_Stringshare *inn = NULL; 753 Eina_Stringshare *inn = NULL;
748 cl->extends = NULL; 754 cl->extends = NULL;
755 cl->requires = NULL;
749 Eina_Bool succ = EINA_TRUE; 756 Eina_Bool succ = EINA_TRUE;
750 757
751 if (cl->parent_name) 758 if (cl->parent_name)
@@ -771,6 +778,30 @@ _db_fill_inherits(Eolian_Class *cl, Eina_Hash *fhash)
771 succ = _db_fill_inherits(out_cl, fhash); 778 succ = _db_fill_inherits(out_cl, fhash);
772 } 779 }
773 780
781 if (succ && cl->type == EOLIAN_CLASS_MIXIN)
782 {
783 EINA_LIST_FREE(rl, inn)
784 {
785 Eolian_Class *out_cl = NULL;
786 succ = _db_swap_inherit(cl, succ, inn, &out_cl);
787 if (succ && !(out_cl->type == EOLIAN_CLASS_REGULAR || out_cl->type == EOLIAN_CLASS_ABSTRACT))
788 {
789 char buf[PATH_MAX];
790 snprintf(buf, sizeof(buf), "requires only allows regulars or abstracts");
791 _obj_error(&cl->base, buf);
792 succ = EINA_FALSE;
793 }
794 if (succ)
795 {
796 _db_fill_inherits(out_cl, fhash);
797 }
798 if (!succ)
799 continue;
800 if (!eina_list_data_find(cl->requires, out_cl))
801 cl->requires = eina_list_append(cl->requires, out_cl);
802 }
803 }
804
774 /* failed on the way, no point in filling further 805 /* failed on the way, no point in filling further
775 * the failed stuff will get dropped so it's ok if it's inconsistent 806 * the failed stuff will get dropped so it's ok if it's inconsistent
776 */ 807 */
@@ -805,6 +836,24 @@ _validate_implement(Eolian_Implement *impl)
805 return _validate(&impl->base); 836 return _validate(&impl->base);
806} 837}
807 838
839static Eina_List*
840_required_classes(Eolian_Class *mixin)
841{
842 Eina_List *result = NULL, *n;
843 Eolian_Class *extension;
844
845
846 result = eina_list_clone(mixin->requires);
847
848 if (mixin->parent)
849 result = eina_list_merge(result, _required_classes(mixin->parent));
850
851 EINA_LIST_FOREACH(mixin->extends, n, extension)
852 result = eina_list_merge(result, _required_classes(extension));
853
854 return result;
855}
856
808static Eina_Bool 857static Eina_Bool
809_validate_class(Validate_State *vals, Eolian_Class *cl, 858_validate_class(Validate_State *vals, Eolian_Class *cl,
810 Eina_Hash *nhash, Eina_Hash *ehash, Eina_Hash *chash) 859 Eina_Hash *nhash, Eina_Hash *ehash, Eina_Hash *chash)
@@ -815,6 +864,7 @@ _validate_class(Validate_State *vals, Eolian_Class *cl,
815 Eolian_Part *part; 864 Eolian_Part *part;
816 Eolian_Implement *impl; 865 Eolian_Implement *impl;
817 Eolian_Class *icl; 866 Eolian_Class *icl;
867 Eina_List *required_classes = NULL;
818 868
819 if (!cl) 869 if (!cl)
820 return EINA_FALSE; /* if this happens something is very wrong though */ 870 return EINA_FALSE; /* if this happens something is very wrong though */
@@ -849,6 +899,17 @@ _validate_class(Validate_State *vals, Eolian_Class *cl,
849 899
850 EINA_LIST_FOREACH(cl->extends, l, icl) 900 EINA_LIST_FOREACH(cl->extends, l, icl)
851 { 901 {
902 if (icl->type == EOLIAN_CLASS_MIXIN)
903 {
904 Eina_List *res = _required_classes(icl);
905 Eolian_Class *required_class;
906 Eina_List *n;
907 EINA_LIST_FOREACH(res, n, required_class)
908 {
909 if (!eina_list_data_find(required_classes, required_class))
910 required_classes = eina_list_append(required_classes, required_class);
911 }
912 }
852 if (!valid && vals->ext_regular) switch (icl->type) 913 if (!valid && vals->ext_regular) switch (icl->type)
853 { 914 {
854 case EOLIAN_CLASS_REGULAR: 915 case EOLIAN_CLASS_REGULAR:
@@ -869,6 +930,35 @@ _validate_class(Validate_State *vals, Eolian_Class *cl,
869 if (!_validate_class(vals, icl, nhash, ehash, chash)) 930 if (!_validate_class(vals, icl, nhash, ehash, chash))
870 return EINA_FALSE; 931 return EINA_FALSE;
871 } 932 }
933 if (cl->type == EOLIAN_CLASS_ABSTRACT || cl->type == EOLIAN_CLASS_REGULAR)
934 {
935 //walk up the parent list and remove all classes from there
936 icl = cl;
937 while (icl)
938 {
939 required_classes = eina_list_remove(required_classes, icl);
940 icl = icl->parent;
941 }
942 //if there are a few left, drop, and error
943 if (required_classes)
944 {
945 Eina_Strbuf *classes = eina_strbuf_new();
946 Eolian_Class *required_class;
947 Eina_List *n;
948 EINA_LIST_FOREACH(required_classes, n, required_class)
949 {
950 eina_strbuf_append(classes, required_class->base.name);
951 eina_strbuf_append_char(classes, ' ');
952 }
953 char buf[PATH_MAX];
954 snprintf(buf, sizeof(buf), "required classes %sare not in the inherit chain of %s",
955 eina_strbuf_string_get(classes), cl->base.name);
956 eina_strbuf_free(classes);
957 _obj_error(&cl->base, buf);
958 return EINA_FALSE;
959 }
960 }
961
872 962
873 EINA_LIST_FOREACH(cl->properties, l, func) 963 EINA_LIST_FOREACH(cl->properties, l, func)
874 if (!_validate_function(vals, func, nhash)) 964 if (!_validate_function(vals, func, nhash))
diff --git a/src/lib/eolian/eo_lexer.h b/src/lib/eolian/eo_lexer.h
index d80535723d..522cc41271 100644
--- a/src/lib/eolian/eo_lexer.h
+++ b/src/lib/eolian/eo_lexer.h
@@ -28,7 +28,7 @@ enum Tokens
28 KW(destructor), KW(eo), KW(eo_prefix), KW(event_prefix), KW(events), \ 28 KW(destructor), KW(eo), KW(eo_prefix), KW(event_prefix), KW(events), \
29 KW(extends), KW(free), KW(get), KW(implements), KW(import), KW(interface), \ 29 KW(extends), KW(free), KW(get), KW(implements), KW(import), KW(interface), \
30 KW(keys), KW(legacy), KW(legacy_prefix), KW(methods), KW(mixin), KW(params), \ 30 KW(keys), KW(legacy), KW(legacy_prefix), KW(methods), KW(mixin), KW(params), \
31 KW(parse), KW(parts), KW(ptr), KW(set), KW(type), KW(values), KW(var), \ 31 KW(parse), KW(parts), KW(ptr), KW(set), KW(type), KW(values), KW(var), KW(requires), \
32 \ 32 \
33 KWAT(auto), KWAT(beta), KWAT(class), KWAT(const), KWAT(cref), KWAT(empty), \ 33 KWAT(auto), KWAT(beta), KWAT(class), KWAT(const), KWAT(cref), KWAT(empty), \
34 KWAT(extern), KWAT(free), KWAT(hot), KWAT(in), KWAT(inout), KWAT(nonull), \ 34 KWAT(extern), KWAT(free), KWAT(hot), KWAT(in), KWAT(inout), KWAT(nonull), \
diff --git a/src/lib/eolian/eo_parser.c b/src/lib/eolian/eo_parser.c
index 37bed0ac1f..a06b69b6fb 100644
--- a/src/lib/eolian/eo_parser.c
+++ b/src/lib/eolian/eo_parser.c
@@ -2010,6 +2010,24 @@ inherit_dup:
2010} 2010}
2011 2011
2012static void 2012static void
2013_requires_add(Eo_Lexer *ls, Eina_Strbuf *buf)
2014{
2015 const char *required;
2016 char *fnm;
2017
2018 eo_lexer_context_push(ls);
2019 parse_name(ls, buf);
2020 required = eina_strbuf_string_get(buf);
2021 fnm = database_class_to_filename(required);
2022
2023 ls->klass->requires = eina_list_append(ls->klass->requires, eina_stringshare_add(required));
2024 database_defer(ls->state, fnm, EINA_TRUE);
2025 eo_lexer_context_pop(ls);
2026
2027 free(fnm);
2028}
2029
2030static void
2013parse_class(Eo_Lexer *ls, Eolian_Class_Type type) 2031parse_class(Eo_Lexer *ls, Eolian_Class_Type type)
2014{ 2032{
2015 const char *bnm; 2033 const char *bnm;
@@ -2052,6 +2070,20 @@ parse_class(Eo_Lexer *ls, Eolian_Class_Type type)
2052 Eina_Strbuf *ibuf = eina_strbuf_new(); 2070 Eina_Strbuf *ibuf = eina_strbuf_new();
2053 eo_lexer_dtor_push(ls, EINA_FREE_CB(eina_strbuf_free), ibuf); 2071 eo_lexer_dtor_push(ls, EINA_FREE_CB(eina_strbuf_free), ibuf);
2054 /* new inherits syntax, keep alongside old for now */ 2072 /* new inherits syntax, keep alongside old for now */
2073 if (ls->t.kw == KW_requires)
2074 {
2075 if (type != EOLIAN_CLASS_MIXIN)
2076 {
2077 eo_lexer_syntax_error(ls, "\"requires\" keyword is only needed for mixin classes");
2078 }
2079 eo_lexer_get(ls);
2080 do
2081 _requires_add(ls, ibuf);
2082 while (test_next(ls, ','));
2083 if (ls->t.token == '{')
2084 goto inherit_done;
2085 }
2086
2055 if (ls->t.kw == KW_extends || (is_reg && (ls->t.kw == KW_implements))) 2087 if (ls->t.kw == KW_extends || (is_reg && (ls->t.kw == KW_implements)))
2056 { 2088 {
2057 Eina_Bool ext = (ls->t.kw == KW_extends); 2089 Eina_Bool ext = (ls->t.kw == KW_extends);
diff --git a/src/lib/eolian/eolian_database.h b/src/lib/eolian/eolian_database.h
index 9804449bda..fdaee09d11 100644
--- a/src/lib/eolian/eolian_database.h
+++ b/src/lib/eolian/eolian_database.h
@@ -191,6 +191,7 @@ struct _Eolian_Class
191 Eina_List *constructors; /* Eolian_Constructor */ 191 Eina_List *constructors; /* Eolian_Constructor */
192 Eina_List *events; /* Eolian_Event */ 192 Eina_List *events; /* Eolian_Event */
193 Eina_List *parts; /* Eolian_Part */ 193 Eina_List *parts; /* Eolian_Part */
194 Eina_List *requires; /* a list of required other classes only used internally */
194 Eina_Bool class_ctor_enable:1; 195 Eina_Bool class_ctor_enable:1;
195 Eina_Bool class_dtor_enable:1; 196 Eina_Bool class_dtor_enable:1;
196}; 197};
diff --git a/src/tests/eolian/data/class_requires.eo b/src/tests/eolian/data/class_requires.eo
new file mode 100644
index 0000000000..173c660b39
--- /dev/null
+++ b/src/tests/eolian/data/class_requires.eo
@@ -0,0 +1,8 @@
1import base;
2import mixins_require;
3
4class Class.Requires (Base, Mixins.Require) {
5 methods {
6
7 }
8}
diff --git a/src/tests/eolian/data/mixins_require.eo b/src/tests/eolian/data/mixins_require.eo
new file mode 100644
index 0000000000..474e1a3af1
--- /dev/null
+++ b/src/tests/eolian/data/mixins_require.eo
@@ -0,0 +1,13 @@
1import base;
2import class_simple;
3
4mixin Mixins.Require requires Base {
5 methods {
6 test {
7
8 }
9 }
10 implements {
11 Base.constructor;
12 }
13}
diff --git a/src/tests/eolian/eolian_parsing.c b/src/tests/eolian/eolian_parsing.c
index 6df473f24d..d93906bc56 100644
--- a/src/tests/eolian/eolian_parsing.c
+++ b/src/tests/eolian/eolian_parsing.c
@@ -1552,6 +1552,66 @@ EFL_START_TEST(eolian_parts)
1552} 1552}
1553EFL_END_TEST 1553EFL_END_TEST
1554 1554
1555EFL_START_TEST(eolian_mixins_require)
1556{
1557 const Eolian_Unit *unit;
1558 const Eolian_Class *cl;
1559 const Eolian_Class *base;
1560
1561 Eolian_State *eos = eolian_state_new();
1562
1563 fail_if(!eolian_state_directory_add(eos, TESTS_SRC_DIR"/data"));
1564
1565 fail_if(!(unit = eolian_state_file_parse(eos, TESTS_SRC_DIR"/data/mixins_require.eo")));
1566
1567 fail_if (!(cl = eolian_state_class_by_name_get(eos, "Mixins.Require")));
1568 fail_if (!(base = eolian_state_class_by_name_get(eos, "Base")));
1569
1570 ck_assert_ptr_eq(eolian_class_parent_get(cl), NULL);
1571
1572 //Check that implements is empty
1573 {
1574 Eolian_Class *extc;
1575 Eina_Iterator *ext = eolian_class_extensions_get (cl);
1576
1577 EINA_ITERATOR_FOREACH(ext, extc)
1578 {
1579 ck_abort_msg("Iterator should be empty");
1580 }
1581 eina_iterator_free(ext);
1582 }
1583 //check that implements contains this one class
1584 {
1585 Eolian_Implement *impl;
1586 Eina_Iterator *i = eolian_class_extensions_get (cl);
1587
1588 EINA_ITERATOR_FOREACH(i, impl)
1589 {
1590 ck_assert_ptr_eq(eolian_implement_class_get(impl), base);
1591 }
1592 eina_iterator_free(i);
1593 }
1594 eolian_state_free(eos);
1595}
1596EFL_END_TEST
1597
1598EFL_START_TEST(eolian_class_requires_classes)
1599{
1600 const Eolian_Unit *unit;
1601 const Eolian_Class *cl;
1602
1603 Eolian_State *eos = eolian_state_new();
1604
1605 fail_if(!eolian_state_directory_add(eos, TESTS_SRC_DIR"/data"));
1606
1607 fail_if(!(unit = eolian_state_file_parse(eos, TESTS_SRC_DIR"/data/class_requires.eo")));
1608
1609 fail_if (!(cl = eolian_state_class_by_name_get(eos, "Class.Requires")));
1610
1611 eolian_state_free(eos);
1612}
1613EFL_END_TEST
1614
1555void eolian_parsing_test(TCase *tc) 1615void eolian_parsing_test(TCase *tc)
1556{ 1616{
1557 tcase_add_test(tc, eolian_simple_parsing); 1617 tcase_add_test(tc, eolian_simple_parsing);
@@ -1575,4 +1635,6 @@ void eolian_parsing_test(TCase *tc)
1575 tcase_add_test(tc, eolian_function_types); 1635 tcase_add_test(tc, eolian_function_types);
1576 tcase_add_test(tc, eolian_function_as_arguments); 1636 tcase_add_test(tc, eolian_function_as_arguments);
1577 tcase_add_test(tc, eolian_parts); 1637 tcase_add_test(tc, eolian_parts);
1638 tcase_add_test(tc, eolian_mixins_require);
1639 tcase_add_test(tc, eolian_class_requires_classes);
1578} 1640}