Pyolian: implement an utility class: Namspace
authorDave Andreoli <dave@gurumeditation.it>
Tue, 2 Jan 2018 14:43:15 +0000 (15:43 +0100)
committerWonki Kim <wonki_.kim@samsung.com>
Wed, 10 Jan 2018 11:08:13 +0000 (20:08 +0900)
Update tests and generator to use this new feature

src/scripts/pyolian/eolian.py
src/scripts/pyolian/generator.py
src/scripts/pyolian/test_eolian.py
src/scripts/pyolian/test_gen_namespace.template

index 75a98ff..645b463 100644 (file)
@@ -301,6 +301,20 @@ class Eolian_Unit(EolianBaseObject):
         return Iterator(Class, lib.eolian_all_classes_get(self._obj))
 
     @property
+    def all_namespaces(self):
+        # TODO find a better way to find namespaces (maybe inside eolian?)
+        nspaces = []
+        for cls in self.all_classes:
+            ns = Namespace(self, cls.namespace)
+            if not ns in nspaces:
+                nspaces.append(ns)
+        nspaces.sort()
+        return nspaces
+
+    def namespace_get_by_name(self, name):
+        return Namespace(self, name)
+
+    @property
     def typedecl_all_enums(self):
         return Iterator(Typedecl, lib.eolian_typedecl_all_enums_get(self._obj))
 
@@ -416,6 +430,72 @@ class Eolian(Eolian_Unit):
         return bool(lib.eolian_all_eot_files_parse(self._obj))
 
 
+###  Namespace Utility Class  #################################################
+
+class Namespace(object):
+    def __init__(self, unit, namespace_name):
+        self._name = namespace_name
+        self._unit = unit
+
+    def __repr__(self):
+        return "<eolian.Namespace '{0._name}'>".format(self)
+
+    def __eq__(self, other):
+        return self.name == other.name
+
+    def __lt__(self, other):
+        return self.name < other.name
+
+    def __gt__(self, other):
+        return self.name > other.name
+
+    @property
+    def name(self):
+        return self._name
+
+    @property
+    def namespaces(self):
+        return self._name.split('.')
+
+    @property
+    def classes(self):
+        return [ c for c in self._unit.all_classes
+                if c.namespace == self._name ]
+
+    @property
+    def regulars(self):
+        return [ c for c in self._unit.all_classes
+                if c.type == Eolian_Class_Type.REGULAR and
+                   c.namespace == self._name]
+
+    @property
+    def mixins(self):
+        return [ c for c in self._unit.all_classes
+                if c.type == Eolian_Class_Type.MIXIN and
+                   c.namespace == self._name]
+
+    @property
+    def interfaces(self):
+        return [ c for c in self._unit.all_classes
+                if c.type == Eolian_Class_Type.INTERFACE and
+                   c.namespace == self._name]
+
+    @property
+    def aliases(self):
+        return [ td for td in self._unit.typedecl_all_aliases
+                if td.namespace == self._name]
+
+    @property
+    def structs(self):
+        return [ td for td in self._unit.typedecl_all_structs
+                if td.namespace == self._name]
+
+    @property
+    def enums(self):
+        return [ td for td in self._unit.typedecl_all_enums
+                if td.namespace == self._name]
+
+
 ###  Eolian Classes  ##########################################################
 
 class Class(EolianBaseObject):
@@ -1240,6 +1320,7 @@ class _Eolian_Doc_Token_Struct(ctypes.Structure):
                 ("text", c_char_p),
                 ("text_end", c_char_p)]
 
+
 class Documentation(EolianBaseObject):
     # def __repr__(self):
         # return "<eolian.Documentation '{0.name}'>".format(self)
@@ -1345,7 +1426,6 @@ lib.eolian_init()
 atexit.register(lambda: lib.eolian_shutdown())
 
 
-
 ###  API coverage statistics  #################################################
 
 if __name__ == '__main__':
index 2640bfa..140b620 100755 (executable)
@@ -90,9 +90,9 @@ class Template(pyratemp.Template):
 
     Args:
         filename: Template file to load. (REQUIRED)
-        data: User provided context for the template.
+        context: User provided context for the template (dict).
     """
-    def __init__(self, filename, encoding='utf-8', data=None, escape=None,
+    def __init__(self, filename, encoding='utf-8', context=None, escape=None,
                        loader_class=pyratemp.LoaderFile,
                        parser_class=pyratemp.Parser,
                        renderer_class=pyratemp.Renderer,
@@ -101,8 +101,8 @@ class Template(pyratemp.Template):
         # Build the global context for the template
         global_ctx = {}
         # user provided context (low pri)
-        if data:
-            global_ctx.update(data)
+        if context:
+            global_ctx.update(context)
         # standard names (not overwritables)
         global_ctx.update({
             # Template info
@@ -164,23 +164,14 @@ class Template(pyratemp.Template):
             ctx.update(kargs)
         if cls:
             ctx['cls'] = eolian_db.class_get_by_name(cls)
+        if ns:
+            ctx['namespace'] = eolian_db.namespace_get_by_name(ns)
         if struct:
             ctx['struct'] = eolian_db.typedecl_struct_get_by_name(struct)
         if enum:
             ctx['enum'] = eolian_db.typedecl_enum_get_by_name(enum)
         if alias:
             ctx['alias'] = eolian_db.typedecl_alias_get_by_name(alias)
-        if ns:
-            ctx['namespace'] = ns
-            ctx['namespaces'] = ns.split('.')
-            ctx['classes'] = [ c for c in eolian_db.all_classes
-                                    if c.full_name.startswith(ns + '.') ]
-            ctx['aliases'] = [ a for a in eolian_db.typedecl_all_aliases
-                                    if a.full_name.startswith(ns + '.') ]
-            ctx['structs'] = [ s for s in eolian_db.typedecl_all_structs
-                                    if s.full_name.startswith(ns + '.') ]
-            ctx['enums']   = [ e for e in eolian_db.typedecl_all_enums
-                                    if e.full_name.startswith(ns + '.') ]
 
         if verbose and filename:
             print('generating "{}" from template "{}"'.format(
@@ -205,7 +196,7 @@ class Template(pyratemp.Template):
 if __name__ == '__main__':
     import argparse
 
-    parser = argparse.ArgumentParser(description='Pyolian generator.')
+    parser = argparse.ArgumentParser(description='Pyolian template based generator.')
     parser.add_argument('template',
                         help='The template file to use. (REQUIRED)')
     parser.add_argument('--output', '-o', metavar='FILE', default=None,
index 76baf88..c7b9769 100755 (executable)
@@ -50,7 +50,6 @@ class TestBaseObject(unittest.TestCase):
         self.assertNotEqual(enum1, 0)
 
         self.assertNotEqual(cls1, enum1)
-        
 
 
 class TestEolianUnit(unittest.TestCase):
@@ -149,6 +148,71 @@ class TestEolianUnit(unittest.TestCase):
         self.assertGreater(all_count, 400)
 
 
+class TestEolianNamespace(unittest.TestCase):
+    def test_all_namespace(self):
+        count = 0
+        for ns in state.all_namespaces:
+            self.assertIsInstance(ns, eolian.Namespace)
+            count += 1
+        self.assertGreater(count, 100)
+
+    def test_namespace_equality(self):
+        ns1 = eolian.Namespace(state, 'Efl.Io')
+        ns2 = eolian.Namespace(state, 'Efl.Net')
+        self.assertIsInstance(ns1, eolian.Namespace)
+        self.assertIsInstance(ns2, eolian.Namespace)
+        self.assertNotEqual(ns1, ns2)
+        self.assertEqual(ns1, eolian.Namespace(state, 'Efl.Io'))
+        self.assertEqual(ns2, eolian.Namespace(state, 'Efl.Net'))
+
+    def test_namespace_sorting(self):
+        nspaces = state.all_namespaces
+        nspaces.sort(reverse=True)
+        self.assertGreater(nspaces[0], nspaces[-1])
+        self.assertLess(nspaces[1], nspaces[0])
+
+    def test_namespace_by_name(self):
+        ns = eolian.Namespace(state, 'Efl.Net')
+        self.assertIsInstance(ns, eolian.Namespace)
+        self.assertEqual(ns.name, 'Efl.Net')
+        self.assertEqual(ns.namespaces, ['Efl', 'Net'])
+
+        ns = state.namespace_get_by_name('Efl')
+        self.assertIsInstance(ns, eolian.Namespace)
+        self.assertEqual(ns.name, 'Efl')
+
+        self.assertGreater(len(ns.classes), 30)
+        for cls in ns.classes:
+            self.assertIsInstance(cls, eolian.Class)
+        self.assertGreater(len(ns.regulars), 4)
+        for cls in ns.regulars:
+            self.assertIsInstance(cls, eolian.Class)
+            self.assertEqual(cls.type, eolian.Eolian_Class_Type.REGULAR)
+        self.assertGreater(len(ns.mixins), 0)
+        for cls in ns.mixins:
+            self.assertIsInstance(cls, eolian.Class)
+            self.assertEqual(cls.type, eolian.Eolian_Class_Type.MIXIN)
+        self.assertGreater(len(ns.interfaces), 15)
+        for cls in ns.interfaces:
+            self.assertIsInstance(cls, eolian.Class)
+            self.assertEqual(cls.type, eolian.Eolian_Class_Type.INTERFACE)
+
+        self.assertGreater(len(ns.enums), 1)
+        for td in ns.enums:
+            self.assertIsInstance(td, eolian.Typedecl)
+            self.assertEqual(td.type, eolian.Eolian_Typedecl_Type.ENUM)
+        self.assertGreater(len(ns.aliases), 0)
+        for td in ns.aliases:
+            self.assertIsInstance(td, eolian.Typedecl)
+            # TODO eolian_typedecl_all_aliases_get also return FUNCTION_POINTER
+            # is this correct? or an eolian bug ?
+            #  self.assertEqual(td.type, eolian.Eolian_Typedecl_Type.ALIAS)
+        self.assertGreater(len(ns.structs), 2)
+        for td in ns.structs:
+            self.assertIsInstance(td, eolian.Typedecl)
+            self.assertEqual(td.type, eolian.Eolian_Typedecl_Type.STRUCT)
+
+
 class TestEolianClass(unittest.TestCase):
     def test_class(self):
         cls = state.class_get_by_file('efl_loop_timer.eo')
index 09b7763..87557c6 100644 (file)
@@ -1,19 +1,35 @@
 
 ================================================================================
-Namespace:    ${namespace}$  ${namespaces}$
+Namespace:    ${namespace.name}$  ${namespace.namespaces}$
 ================================================================================
 
-Classes:
-========
-<!--(for cls in classes)-->
- * ${cls.full_name}$   (${cls.type}$)
+Regular Classes:
+================
+<!--(for cls in namespace.regulars)-->
+ * ${cls.full_name}$ (${cls.type.name.lower()}$)
+<!--(else)-->
+ no classes available
+<!--(end)-->
+
+Interfaces:
+===========
+<!--(for cls in namespace.interfaces)-->
+ * ${cls.full_name}$ (${cls.type.name.lower()}$)
+<!--(else)-->
+ no classes available
+<!--(end)-->
+
+Mixins:
+=======
+<!--(for cls in namespace.mixins)-->
+ * ${cls.full_name}$ (${cls.type.name.lower()}$)
 <!--(else)-->
  no classes available
 <!--(end)-->
 
 Aliases:
 ========
-<!--(for typedecl in aliases)-->
+<!--(for typedecl in namespace.aliases)-->
  * ${typedecl.full_name}$
 <!--(else)-->
  no alias available
@@ -21,10 +37,10 @@ Aliases:
 
 Structs:
 ========
-<!--(for typedecl in structs)-->
+<!--(for typedecl in namespace.structs)-->
  * ${typedecl.full_name}$
     <!--(for field in typedecl.struct_fields)-->
-    ${field}$
+    ${field.type.name}$ ${field.name}$
     <!--(end)-->
 <!--(else)-->
  no structs available
@@ -32,10 +48,10 @@ Structs:
 
 Enums:
 ======
-<!--(for typedecl in enums)-->
+<!--(for typedecl in namespace.enums)-->
  * ${typedecl.full_name}$
     <!--(for field in typedecl.enum_fields)-->
-    ${field}$
+    ${field.c_name}$ = ${field.value.serialize}$
     <!--(end)-->
 <!--(else)-->
  no enums available