Pyolian: implement an utility class: Namspace

Update tests and generator to use this new feature
This commit is contained in:
Davide Andreoli 2018-01-02 15:43:15 +01:00
parent b8f4dc296f
commit b9ed84f4ed
4 changed files with 179 additions and 28 deletions

View File

@ -300,6 +300,20 @@ class Eolian_Unit(EolianBaseObject):
def all_classes(self):
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__':

View File

@ -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,

View File

@ -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')

View 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