Use a Mako template for generated code.

Change-Id: I8901e7719da57f13eff7ba49d50113b01fec88aa
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/generated.mako.cpp b/generated.mako.cpp
new file mode 100644
index 0000000..a92daf1
--- /dev/null
+++ b/generated.mako.cpp
@@ -0,0 +1,60 @@
+## This file is a template.  The comment below is emitted
+## into the rendered file; feel free to edit this file.
+// This file was auto generated.  Do not edit.
+
+#include "manager.hpp"
+
+namespace phosphor
+{
+namespace inventory
+{
+namespace manager
+{
+
+const Manager::Events Manager::_events{
+% for e in events:
+    {
+    % if e.get('description'):
+        // ${e['description']}
+    % endif
+        "${e['name']}",
+        std::make_tuple(
+        % for i, s in enumerate(e['signature'].items()):
+            % if i + 1 == len(e['signature']):
+            ${'"{0}=\'{1}\'"'.format(*s)},
+            % else:
+            ${'"{0}=\'{1}\',"'.format(*s)}
+            % endif
+        % endfor
+            % if e['filter'].get('args'):
+            filters::${e['filter']['type']}(
+                % for i, a in enumerate(e['filter']['args']):
+                    % if i + 1 == len(e['filter']['args']):
+                "${a['value']}"),
+                    % else:
+                "${a['value']}",
+                    % endif
+                % endfor
+            % else:
+            filters::${e['filter']['type']},
+            % endif
+            % if e['action'].get('args'):
+            actions::${e['action']['type']}(
+                % for i, a in enumerate(e['action']['args']):
+                    % if i + 1 == len(e['action']['args']):
+                "${a['value']}")
+                    % else:
+                "${a['value']}",
+                    % endif
+                % endfor
+            % else:
+            actions::${e['action']['type']}
+            % endif
+        ),
+    },
+% endfor
+};
+
+} // namespace manager
+} // namespace inventory
+} // namespace phosphor
diff --git a/pimgen.py b/pimgen.py
index c21c418..7c32594 100755
--- a/pimgen.py
+++ b/pimgen.py
@@ -5,140 +5,18 @@
 import re
 import argparse
 import yaml
+from mako.template import Template
 
 valid_c_name_pattern = re.compile('[\W_]+')
-ignore_list = ['description']
-all_names = []
 
 
-def get_parser(x, fmt, lmbda=lambda x: x.capitalize()):
-    try:
-        return getattr(
-            sys.modules[__name__],
-            '%s' % (fmt.format(lmbda(x))))
-    except AttributeError:
-        raise NotImplementedError("Don't know how to parse '%s'" % x)
-
-
-class RenderList(list):
-    def __init__(self, renderers):
-        self.extend(renderers)
-
-    def __call__(self, fd):
-        for x in self:
-            x(fd)
-
-
-class ParseList(list):
-    def __init__(self, parsers):
-        self.extend(parsers)
-
-    def __call__(self):
-        return RenderList([x() for x in self])
-
-
-class MatchRender(object):
-    def __init__(self, name, signature, fltr, action):
-        self.name = valid_c_name_pattern.sub('_', name).lower()
-        self.signature = signature
-        self.fltr = fltr
-        self.action = action
-
-        if self.name in all_names:
-            raise RuntimeError('The name "%s" is not unique.' % name)
-        else:
-            all_names.append(self.name)
-
-    def __call__(self, fd):
-        sig = ['%s=\'%s\'' % (k, v) for k, v in self.signature.iteritems()]
-        sig = ['%s,' % x for x in sig[:-1]] + [sig[-1]]
-        sig = ['"%s"' % x for x in sig]
-        sig = ['%s\n' % x for x in sig[:-1]] + [sig[-1]]
-
-        fd.write('    {\n')
-        fd.write('        "%s",\n' % self.name)
-        fd.write('        std::make_tuple(\n')
-        for s in sig:
-            fd.write('            %s' % s)
-        fd.write(',\n')
-        self.fltr(fd)
-        fd.write(',\n')
-        self.action(fd)
-        fd.write('\n')
-        fd.write('        ),\n')
-        fd.write('    },\n')
-
-
-class FilterRender(object):
-    namespace = 'filters'
-    default = 'none'
-
-    def __init__(self, fltr):
-        self.args = None
-        if fltr is None:
-            self.name = self.default
-        else:
-            self.name = fltr.get('type')
-            self.args = fltr.get('args')
-
-    def __call__(self, fd):
-        def fmt(x):
-            if x.get('type') is None:
-                return '"%s"' % x['value']
-            return str(x['value'])
-
-        fd.write('            %s::%s' % (self.namespace, self.name))
-        if self.args:
-            fd.write('(')
-            buf = ','.join(([fmt(x) for x in self.args]))
-            fd.write(buf)
-            fd.write(')')
-
-
-class ActionRender(FilterRender):
-    namespace = 'actions'
-    default = 'noop'
-
-    def __init__(self, action):
-        FilterRender.__init__(self, action)
-
-
-class MatchEventParse(object):
-    def __init__(self, match):
-        self.name = match['name']
-        self.signature = match['signature']
-        self.fltr = match.get('filter')
-        self.action = match.get('action')
-
-    def __call__(self):
-        return MatchRender(
-            self.name,
-            self.signature,
-            FilterRender(self.fltr),
-            ActionRender(self.action))
-
-
-class EventsParse(object):
-    def __init__(self, event):
-        self.delegate = None
-        cls = event['type']
-        if cls not in ignore_list:
-            fmt = '{0}EventParse'
-            self.delegate = get_parser(cls, fmt)(event)
-
-    def __call__(self):
-        if self.delegate:
-            return self.delegate()
-        return lambda x: None
-
-
-class DictParse(ParseList):
-    def __init__(self, data):
-        fmt = '{0}Parse'
-        parse = set(data.iterkeys()).difference(ignore_list)
-        ParseList.__init__(
-            self, [get_parser(x, fmt)(*data[x]) for x in parse])
-
+def parse_event(e):
+    e['name'] = valid_c_name_pattern.sub('_', e['name']).lower()
+    if e.get('filter') is None:
+        e.setdefault('filter', {}).setdefault('type', 'none')
+    if e.get('action') is None:
+        e.setdefault('action', {}).setdefault('type', 'noop')
+    return e
 
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(
@@ -151,6 +29,10 @@
         '-d', '--dir', dest='inputdir',
         default=os.path.join('example', 'events'),
         help='Location of files to process.')
+    parser.add_argument(
+        '-t', '--templatedir', dest='template',
+        default='generated.mako.cpp',
+        help='Location of mako template.')
 
     args = parser.parse_args()
 
@@ -158,36 +40,17 @@
         lambda x: x.endswith('.yaml'),
         os.listdir(args.inputdir))
 
-    def get_parsers(x):
+    events = []
+    for x in yaml_files:
         with open(os.path.join(args.inputdir, x), 'r') as fd:
-            return DictParse(yaml.load(fd.read()))
+            for e in yaml.load(fd.read()).get('events', {}):
+                events.append(parse_event(e))
 
-    head = """// This file was auto generated.  Do not edit.
-
-#include "manager.hpp"
-
-namespace phosphor
-{
-namespace inventory
-{
-namespace manager
-{
-
-const Manager::Events Manager::_events{
-"""
-
-    tail = """};
-
-} // namespace manager
-} // namespace inventory
-} // namespace phosphor
-"""
-
-    r = ParseList([get_parsers(x) for x in yaml_files])()
-    r.insert(0, lambda x: x.write(head))
-    r.append(lambda x: x.write(tail))
-
+    t = Template(filename=args.template)
     with open(args.output, 'w') as fd:
-        r(fd)
+        fd.write(
+            t.render(
+                events=events))
+
 
 # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4