#!/usr/bin/env python import sys import os import re import argparse import yaml 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('name') 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]) if __name__ == '__main__': parser = argparse.ArgumentParser( description='Phosphor Inventory Manager (PIM) YAML ' 'scanner and code generator.') parser.add_argument( '-o', '--output', dest='output', default='generated.hpp', help='Output file name.') parser.add_argument( '-d', '--dir', dest='inputdir', default='examples', help='Location of files to process.') args = parser.parse_args() yaml_files = filter( lambda x: x.endswith('.yaml'), os.listdir(args.inputdir)) def get_parsers(x): with open(os.path.join(args.inputdir, x), 'r') as fd: return DictParse(yaml.load(fd.read())) head = """// This file was auto generated. Do not edit. #pragma once const Manager::Events Manager::_events{ """ tail = """}; """ 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)) with open(args.output, 'w') as fd: r(fd) # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4