X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Ftools%2Fvppapigen%2Fvppapigen.py;h=576fa54842483514cb7eda88417298f89a9a5ce2;hb=097fa66b986f06281f603767d321ab13ab6c88c3;hp=5cedfb214e50e6ef64ad29342b4180a35dd0a1fd;hpb=2c2feab7d89239c92df4622c96e853230393deb9;p=vpp.git diff --git a/src/tools/vppapigen/vppapigen.py b/src/tools/vppapigen/vppapigen.py index 5cedfb214e5..576fa548424 100755 --- a/src/tools/vppapigen/vppapigen.py +++ b/src/tools/vppapigen/vppapigen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python3 from __future__ import print_function import ply.lex as lex @@ -18,15 +18,12 @@ sys.dont_write_bytecode = True # Global dictionary of new types (including enums) global_types = {} -global_crc = 0 -def global_type_add(name): +def global_type_add(name, obj): '''Add new type to the dictionary of types ''' type_name = 'vl_api_' + name + '_t' - if type_name in global_types: - raise KeyError('Type is already defined: {}'.format(name)) - global_types[type_name] = True + global_types[type_name] = obj # All your trace are belong to us! @@ -122,22 +119,24 @@ class VPPAPILexer(object): t_ignore = ' \t' +def crc_block_combine(block, crc): + s = str(block).encode() + return binascii.crc32(s, crc) & 0xffffffff + class Service(): - def __init__(self, caller, reply, events=[], stream=False): + def __init__(self, caller, reply, events=None, stream=False): self.caller = caller self.reply = reply self.stream = stream - self.events = events + self.events = [] if events is None else events class Typedef(): def __init__(self, name, flags, block): - global global_crc self.name = name self.flags = flags self.block = block - self.crc = binascii.crc32(str(block)) & 0xffffffff - global_crc = binascii.crc32(str(block), global_crc) + self.crc = str(block).encode() self.manual_print = False self.manual_endian = False for f in flags: @@ -145,23 +144,38 @@ class Typedef(): self.manual_print = True elif f == 'manual_endian': self.manual_endian = True - global_type_add(name) + global_type_add(name, self) def __repr__(self): return self.name + str(self.flags) + str(self.block) +class Using(): + def __init__(self, name, alias): + self.name = name + + if isinstance(alias, Array): + a = { 'type': alias.fieldtype, # noqa: E201 + 'length': alias.length } # noqa: E202 + else: + a = { 'type': alias.fieldtype } # noqa: E201,E202 + self.alias = a + self.crc = str(alias).encode() + global_type_add(name, self) + + def __repr__(self): + return self.name + str(self.alias) + + class Union(): def __init__(self, name, block): self.type = 'Union' self.manual_print = False self.manual_endian = False - global global_crc self.name = name self.block = block - self.crc = binascii.crc32(str(block)) & 0xffffffff - global_crc = binascii.crc32(str(block), global_crc) - global_type_add(name) + self.crc = str(block).encode() + global_type_add(name, self) def __repr__(self): return str(self.block) @@ -169,12 +183,10 @@ class Union(): class Define(): def __init__(self, name, flags, block): - global global_crc self.name = name self.flags = flags self.block = block - self.crc = binascii.crc32(str(block)) & 0xffffffff - global_crc = binascii.crc32(str(block), global_crc) + self.crc = str(block).encode() self.dont_trace = False self.manual_print = False self.manual_endian = False @@ -202,7 +214,6 @@ class Define(): class Enum(): def __init__(self, name, block, enumtype='u32'): - global global_crc self.name = name self.enumtype = enumtype @@ -215,9 +226,8 @@ class Enum(): block[i] = [b, count] self.block = block - self.crc = binascii.crc32(str(block)) & 0xffffffff - global_crc = binascii.crc32(str(block), global_crc) - global_type_add(name) + self.crc = str(block).encode() + global_type_add(name, self) def __repr__(self): return self.name + str(self.block) @@ -235,8 +245,12 @@ class Import(): f = os.path.join(dir, filename) if os.path.exists(f): break - with open(f) as fd: - self.result = parser.parse_file(fd, None) + if sys.version[0] == '2': + with open(f) as fd: + self.result = parser.parse_file(fd, None) + else: + with open(f, encoding='utf-8') as fd: + self.result = parser.parse_file(fd, None) def __repr__(self): return self.filename @@ -244,10 +258,8 @@ class Import(): class Option(): def __init__(self, option): - global global_crc self.option = option - self.crc = binascii.crc32(str(option)) & 0xffffffff - global_crc = binascii.crc32(str(option), global_crc) + self.crc = str(option).encode() def __repr__(self): return str(self.option) @@ -274,10 +286,11 @@ class Array(): class Field(): - def __init__(self, fieldtype, name): + def __init__(self, fieldtype, name, limit=None): self.type = 'Field' self.fieldtype = fieldtype self.fieldname = name + self.limit = limit def __repr__(self): return str([self.fieldtype, self.fieldname]) @@ -457,6 +470,10 @@ class VPPAPIParser(object): '''typedef : TYPEDEF ID '{' block_statements_opt '}' ';' ''' p[0] = Typedef(p[2], [], p[4]) + def p_typedef_alias(self, p): + '''typedef : TYPEDEF declaration ''' + p[0] = Using(p[2].fieldname, p[2]) + def p_block_statements_opt(self, p): '''block_statements_opt : block_statements ''' p[0] = p[1] @@ -476,7 +493,7 @@ class VPPAPIParser(object): def p_enum_statements(self, p): '''enum_statements : enum_statement - | enum_statements enum_statement''' + | enum_statements enum_statement''' if len(p) == 2: p[0] = [p[1]] else: @@ -490,12 +507,30 @@ class VPPAPIParser(object): else: p[0] = p[1] + def p_field_options(self, p): + '''field_options : field_option + | field_options field_option''' + if len(p) == 2: + p[0] = p[1] + else: + p[0] = { **p[1], **p[2] } + + def p_field_option(self, p): + '''field_option : ID '=' assignee ',' + | ID '=' assignee + ''' + p[0] = { p[1]: p[3] } + def p_declaration(self, p): - '''declaration : type_specifier ID ';' ''' - if len(p) != 4: + '''declaration : type_specifier ID ';' + | type_specifier ID '[' field_options ']' ';' ''' + if len(p) == 7: + p[0] = Field(p[1], p[2], p[4]) + elif len(p) == 4: + p[0] = Field(p[1], p[2]) + else: self._parse_error('ERROR') self.fields.append(p[2]) - p[0] = Field(p[1], p[2]) def p_declaration_array(self, p): '''declaration : type_specifier ID '[' NUM ']' ';' @@ -594,8 +629,14 @@ class VPPAPI(object): s['Service'] = [] s['types'] = [] s['Import'] = [] + s['Alias'] = {} + crc = 0 for o in objs: tname = o.__class__.__name__ + try: + crc = binascii.crc32(o.crc, crc) + except AttributeError: + pass if isinstance(o, Define): s[tname].append(o) if o.autoreply: @@ -606,11 +647,16 @@ class VPPAPI(object): for o2 in o: if isinstance(o2, Service): s['Service'].append(o2) - elif isinstance(o, Enum) or isinstance(o, Typedef) or isinstance(o, Union): + elif (isinstance(o, Enum) or + isinstance(o, Typedef) or + isinstance(o, Union)): s['types'].append(o) + elif isinstance(o, Using): + s['Alias'][o.name] = o.alias else: if tname not in s: - raise ValueError('Unknown class type: {} {}'.format(tname, o)) + raise ValueError('Unknown class type: {} {}' + .format(tname, o)) s[tname].append(o) msgs = {d.name: d for d in s['Define']} @@ -618,6 +664,8 @@ class VPPAPI(object): replies = {s.reply: s for s in s['Service']} seen_services = {} + s['file_crc'] = crc + for service in svcs: if service not in msgs: raise ValueError( @@ -656,7 +704,7 @@ class VPPAPI(object): continue if d[:-5]+'_details' in msgs: s['Service'].append(Service(d, d[:-5]+'_details', - stream=True)) + stream=True)) else: raise ValueError('{} missing details message' .format(d)) @@ -685,12 +733,15 @@ class VPPAPI(object): # Only allow the following object types from imported file if in_import and not (isinstance(o, Enum) or isinstance(o, Union) or - isinstance(o, Typedef)): + isinstance(o, Typedef) or + isinstance(o, Import) or + isinstance(o, Using)): continue - result.append(o) - if isinstance(o, Import): self.process_imports(o.result, True, result) + else: + result.append(o) + # Add message ids to each message. def add_msg_id(s): @@ -711,6 +762,23 @@ def dirlist_add(dirs): def dirlist_get(): return dirlist +def foldup_blocks(block, crc): + for b in block: + # Look up CRC in user defined types + if b.fieldtype.startswith('vl_api_'): + # Recursively + t = global_types[b.fieldtype] + try: + crc = crc_block_combine(t.block, crc) + return foldup_blocks(t.block, crc) + except: + pass + return crc + +def foldup_crcs(s): + for f in s: + f.crc = foldup_blocks(f.block, + binascii.crc32(f.crc)) # # Main @@ -719,10 +787,20 @@ def main(): cliparser = argparse.ArgumentParser(description='VPP API generator') cliparser.add_argument('--pluginpath', default=""), cliparser.add_argument('--includedir', action='append'), - cliparser.add_argument('--input', type=argparse.FileType('r'), - default=sys.stdin) - cliparser.add_argument('--output', nargs='?', type=argparse.FileType('w'), - default=sys.stdout) + if sys.version[0] == '2': + cliparser.add_argument('--input', type=argparse.FileType('r'), + default=sys.stdin) + cliparser.add_argument('--output', nargs='?', + type=argparse.FileType('w'), + default=sys.stdout) + + else: + cliparser.add_argument('--input', + type=argparse.FileType('r', encoding='UTF-8'), + default=sys.stdin) + cliparser.add_argument('--output', nargs='?', + type=argparse.FileType('w', encoding='UTF-8'), + default=sys.stdout) cliparser.add_argument('output_module', nargs='?', default='C') cliparser.add_argument('--debug', action='store_true') @@ -758,13 +836,14 @@ def main(): # Add msg_id field s['Define'] = add_msg_id(s['Define']) - file_crc = global_crc & 0xffffffff + # Fold up CRCs + foldup_crcs(s['Define']) # # Debug if args.debug: import pprint - pp = pprint.PrettyPrinter(indent=4) + pp = pprint.PrettyPrinter(indent=4, stream=sys.stderr) for t in s['Define']: pp.pprint([t.name, t.flags, t.block]) for t in s['types']: @@ -773,7 +852,7 @@ def main(): # # Generate representation # - import imp + from importlib.machinery import SourceFileLoader # Default path pluginpath = '' @@ -784,22 +863,25 @@ def main(): '/../share/vpp/') for c in cand: c += '/' - if os.path.isfile(c + args.output_module + '.py'): + if os.path.isfile('{}vppapigen_{}.py' + .format(c, args.output_module.lower())): pluginpath = c break else: pluginpath = args.pluginpath + '/' if pluginpath == '': raise Exception('Output plugin not found') - module_path = pluginpath + args.output_module + '.py' + module_path = '{}vppapigen_{}.py'.format(pluginpath, + args.output_module.lower()) try: - plugin = imp.load_source(args.output_module, module_path) - except Exception, err: + plugin = SourceFileLoader(args.output_module, + module_path).load_module() + except Exception as err: raise Exception('Error importing output plugin: {}, {}' .format(module_path, err)) - result = plugin.run(filename, s, file_crc) + result = plugin.run(filename, s) if result: print(result, file=args.output) else: