# # Copyright 2018 Free Software Foundation, Inc. # # This file is part of GNU Radio # # GNU Radio is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3, or (at your option) # any later version. # # GNU Radio is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Radio; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. # """ A tool for generating YAML bindings """ from __future__ import print_function from __future__ import absolute_import from __future__ import unicode_literals from collections import OrderedDict import yaml try: from yaml import CLoader as Loader, CDumper as Dumper except: from yaml import Loader, Dumper from .util_functions import is_number ## setup dumper for dumping OrderedDict ## _mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG def dict_representer(dumper, data): """ Representer to represent special OrderedDict """ return dumper.represent_dict(data.items()) def dict_constructor(loader, node): """ Construct an OrderedDict for dumping """ return OrderedDict(loader.construct_pairs(node)) Dumper.add_representer(OrderedDict, dict_representer) Loader.add_constructor(_mapping_tag, dict_constructor) class GRCYAMLGenerator(object): """ Create and write the YAML bindings for a GRC block. """ def __init__(self, modname=None, blockname=None, doc=None, params=None, iosig=None): """docstring for __init__""" params_list = ['${'+s['key']+'}' for s in params if s['in_constructor']] # Can't make a dict 'cause order matters self._header = (('id', '{}_{}'.format(modname, blockname)), ('label', blockname.replace('_', ' ')), ('category', '[{}]'.format(modname.capitalize())) ) self._templates = (('imports', 'import {}'.format(modname)), ('make', '{}.{}({})'.format(modname, blockname, ', '.join(params_list))) ) self.params = params self.iosig = iosig self.doc = doc self.data = None def make_yaml(self): """ Create the actual tag tree """ data = OrderedDict() for tag, value in self._header: data[tag] = value templates = OrderedDict() for tag, value in self._templates: templates[tag] = value data['templates'] = templates parameters = [] for param in self.params: parameter = OrderedDict() parameter['id'] = param['key'] parameter['label'] = param['key'].capitalize() if param['default']: parameter['default'] = param['default'] parameter['dtype'] = param['type'] parameters.append(parameter) if parameters: data['parameters'] = parameters inputs = [] outputs = [] iosig = self.iosig for inout in sorted(iosig.keys()): if iosig[inout]['max_ports'] == '0': continue for i in range(len(iosig[inout]['type'])): s_type = {'in': 'input', 'out': 'output'}[inout] s_obj = OrderedDict() s_obj['label'] = inout s_obj['domain'] = 'stream' s_obj['dtype'] = iosig[inout]['type'][i] if iosig[inout]['vlen'][i] != '1': vlen = iosig[inout]['vlen'][i] if is_number(vlen): s_obj['vlen'] = vlen else: s_obj['vlen'] = '${ '+vlen+' }' if i == len(iosig[inout]['type'])-1: if not is_number(iosig[inout]['max_ports']): s_obj['multiplicity'] = iosig[inout]['max_ports'] elif len(iosig[inout]['type']) < int(iosig[inout]['max_ports']): s_obj['multiplicity'] = str(int(iosig[inout]['max_ports']) - len(iosig[inout]['type'])+1) if s_type == 'input': inputs.append(s_obj) elif s_type == 'output': outputs.append(s_obj) if inputs: data['inputs'] = inputs if outputs: data['outputs'] = outputs if self.doc is not None: data['documentation'] = self.doc self.data = data data['file_format'] = 1 def save(self, filename): """ Write the YAML file """ self.make_yaml() with open(filename, 'w') as f: yaml.dump(self.data, f, Dumper=Dumper, default_flow_style=False)