pimgen: Add new types

Add a number of new types in preparation for another round of
refactoring.

Indent - An object that facilitates indent agnostic templates.
Template - An association of a template with its parent namespace.
Quote - A decorator for quoting strings.
Cast - A decorator for casting arguments.
Literal - A decorator for using literal operators.
InitializerList - An initializer list argument.
Vector/Wrapper - Convenience types.

Change-Id: I92cb6179716f6a04f2fecd3c7c59af5f9ec8d26c
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/pimgen.py b/pimgen.py
index 9c177c1..140ca54 100755
--- a/pimgen.py
+++ b/pimgen.py
@@ -26,6 +26,11 @@
 from sdbusplus.renderer import Renderer
 
 
+def cppTypeName(yaml_type):
+    ''' Convert yaml types to cpp types.'''
+    return sdbusplus.property.Property(type=yaml_type).cppTypeName
+
+
 class Interface(list):
     '''Provide various interface transformations.'''
 
@@ -44,6 +49,72 @@
         return '.'.join(self)
 
 
+class Indent(object):
+    '''Help templates be depth agnostic.'''
+
+    def __init__(self, depth=0):
+        self.depth = depth
+
+    def __add__(self, depth):
+        return Indent(self.depth + depth)
+
+    def __call__(self, depth):
+        '''Render an indent at the current depth plus depth.'''
+        return 4*' '*(depth + self.depth)
+
+
+class Template(NamedElement):
+    '''Associate a template name with its namespace.'''
+
+    def __init__(self, **kw):
+        self.namespace = kw.pop('namespace')
+        super(Template, self).__init__(**kw)
+
+    def qualified(self):
+        return '::'.join(self.namespace + [self.name])
+
+
+class Quote(object):
+    '''Decorate an argument by quoting it.'''
+
+    def __call__(self, arg):
+        return '"{0}"'.format(arg)
+
+
+class Cast(object):
+    '''Decorate an argument by casting it.'''
+
+    def __init__(self, cast, target):
+        '''cast is the cast type (static, const, etc...).
+           target is the cast target type.'''
+        self.cast = cast
+        self.target = target
+
+    def __call__(self, arg):
+        return '{0}_cast<{1}>({2})'.format(self.cast, self.target, arg)
+
+
+class Literal(object):
+    '''Decorate an argument with a literal operator.'''
+
+    literals = {
+        'string': 's',
+        'int64': 'll',
+        'uint64': 'ull'
+    }
+
+    def __init__(self, type):
+        self.type = type
+
+    def __call__(self, arg):
+        literal = self.literals.get(self.type)
+
+        if literal:
+            return '{0}{1}'.format(arg, literal)
+
+        return arg
+
+
 class Argument(sdbusplus.property.Property):
     '''Bridge sdbusplus property typenames to syntatically correct c++.'''
 
@@ -65,6 +136,21 @@
         return a
 
 
+class InitializerList(Argument):
+    '''Initializer list arguments.'''
+
+    def __init__(self, **kw):
+        self.values = kw.pop('values')
+        super(InitializerList, self).__init__(**kw)
+
+    def argument(self, loader, indent):
+        return self.render(
+            loader,
+            'argument.mako.cpp',
+            arg=self,
+            indent=indent)
+
+
 class MethodCall(NamedElement, Renderer):
     '''Render syntatically correct c++ method calls.'''
 
@@ -97,6 +183,32 @@
         return self.call(loader, indent)
 
 
+class Vector(MethodCall):
+    '''Convenience type for vectors.'''
+
+    def __init__(self, **kw):
+        kw['name'] = 'vector'
+        kw['namespace'] = ['std']
+        kw['args'] = [InitializerList(values=kw.pop('args'))]
+        super(Vector, self).__init__(**kw)
+
+
+class Wrapper(MethodCall):
+    '''Convenience type for functions that wrap other functions.'''
+
+    def __init__(self, **kw):
+        m = MethodCall(
+            name=kw.pop('name'),
+            namespace=kw.pop('namespace', []),
+            templates=kw.pop('templates', []),
+            args=kw.pop('args', []))
+
+        kw['name'] = kw.pop('wrapper_name')
+        kw['namespace'] = kw.pop('wrapper_namespace', [])
+        kw['args'] = [m]
+        super(Wrapper, self).__init__(**kw)
+
+
 class Filter(MethodCall):
     '''Provide common attributes for any filter.'''
 
@@ -335,7 +447,8 @@
                     loader,
                     'generated.mako.cpp',
                     events=self.events,
-                    interfaces=self.interfaces))
+                    interfaces=self.interfaces,
+                    indent=Indent()))
 
 
 if __name__ == '__main__':