blob: 06bfbff238f262a9836edda30c0eb1d4d05115ad [file] [log] [blame]
Nathan Skrzypczak5c2f9642019-09-09 16:45:06 +02001#!/usr/bin/env python3
Ole Troan9d420872017-10-12 13:06:35 +02002
Ole Troan9d420872017-10-12 13:06:35 +02003import ply.lex as lex
4import ply.yacc as yacc
5import sys
6import argparse
Paul Vinciguerraff47fb62019-08-06 19:58:24 -04007import keyword
Ole Troan9d420872017-10-12 13:06:35 +02008import logging
9import binascii
10import os
Ole Troan33a58172019-09-04 09:12:29 +020011import sys
Ole Troan5c318c72020-05-05 12:23:47 +020012from subprocess import Popen, PIPE
Ole Troan9d420872017-10-12 13:06:35 +020013
Ole Troan14a6c0e2020-05-13 11:47:43 +020014assert sys.version_info >= (3, 6), \
15 "Not supported Python version: {}".format(sys.version)
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -040016log = logging.getLogger('vppapigen')
17
Ole Troand6743b12018-03-07 08:40:58 +010018# Ensure we don't leave temporary files around
19sys.dont_write_bytecode = True
20
Ole Troan9d420872017-10-12 13:06:35 +020021#
22# VPP API language
23#
24
25# Global dictionary of new types (including enums)
26global_types = {}
27
Paul Vinciguerra4bf84902019-07-31 00:34:05 -040028seen_imports = {}
29
Ole Troan9d420872017-10-12 13:06:35 +020030
Ole Troan8dbfb432019-04-24 14:31:18 +020031def global_type_add(name, obj):
Ole Troan9d420872017-10-12 13:06:35 +020032 '''Add new type to the dictionary of types '''
33 type_name = 'vl_api_' + name + '_t'
Paul Vinciguerra4bf84902019-07-31 00:34:05 -040034 if type_name in global_types:
35 raise KeyError("Attempted redefinition of {!r} with {!r}.".format(
36 name, obj))
Ole Troan8dbfb432019-04-24 14:31:18 +020037 global_types[type_name] = obj
Ole Troan9d420872017-10-12 13:06:35 +020038
39
40# All your trace are belong to us!
41def exception_handler(exception_type, exception, traceback):
Ole Troan17225df2018-04-11 09:50:03 +020042 print("%s: %s" % (exception_type.__name__, exception))
Ole Troan9d420872017-10-12 13:06:35 +020043
44
45#
46# Lexer
47#
48class VPPAPILexer(object):
49 def __init__(self, filename):
50 self.filename = filename
51
52 reserved = {
53 'service': 'SERVICE',
54 'rpc': 'RPC',
55 'returns': 'RETURNS',
Marek Gradzki51e59682018-03-06 10:05:44 +010056 'null': 'NULL',
Ole Troan9d420872017-10-12 13:06:35 +020057 'stream': 'STREAM',
58 'events': 'EVENTS',
59 'define': 'DEFINE',
60 'typedef': 'TYPEDEF',
61 'enum': 'ENUM',
62 'typeonly': 'TYPEONLY',
63 'manual_print': 'MANUAL_PRINT',
64 'manual_endian': 'MANUAL_ENDIAN',
65 'dont_trace': 'DONT_TRACE',
66 'autoreply': 'AUTOREPLY',
67 'option': 'OPTION',
68 'u8': 'U8',
69 'u16': 'U16',
70 'u32': 'U32',
71 'u64': 'U64',
72 'i8': 'I8',
73 'i16': 'I16',
74 'i32': 'I32',
75 'i64': 'I64',
76 'f64': 'F64',
77 'bool': 'BOOL',
78 'string': 'STRING',
79 'import': 'IMPORT',
80 'true': 'TRUE',
81 'false': 'FALSE',
Ole Troan2c2feab2018-04-24 00:02:37 -040082 'union': 'UNION',
Ole Troan9d420872017-10-12 13:06:35 +020083 }
84
85 tokens = ['STRING_LITERAL',
86 'ID', 'NUM'] + list(reserved.values())
87
88 t_ignore_LINE_COMMENT = '//.*'
89
Ole Troan33a58172019-09-04 09:12:29 +020090 def t_FALSE(self, t):
91 r'false'
92 t.value = False
93 return t
94
95 def t_TRUE(self, t):
96 r'false'
97 t.value = True
98 return t
99
Ole Troan9d420872017-10-12 13:06:35 +0200100 def t_NUM(self, t):
Paul Vinciguerra063f3742019-07-02 13:00:58 -0400101 r'0[xX][0-9a-fA-F]+|-?\d+\.?\d*'
Ole Troan9d420872017-10-12 13:06:35 +0200102 base = 16 if t.value.startswith('0x') else 10
Paul Vinciguerra063f3742019-07-02 13:00:58 -0400103 if '.' in t.value:
104 t.value = float(t.value)
105 else:
106 t.value = int(t.value, base)
Ole Troan9d420872017-10-12 13:06:35 +0200107 return t
108
109 def t_ID(self, t):
110 r'[a-zA-Z_][a-zA-Z_0-9]*'
111 # Check for reserved words
112 t.type = VPPAPILexer.reserved.get(t.value, 'ID')
113 return t
114
115 # C string
116 def t_STRING_LITERAL(self, t):
117 r'\"([^\\\n]|(\\.))*?\"'
118 t.value = str(t.value).replace("\"", "")
119 return t
120
121 # C or C++ comment (ignore)
122 def t_comment(self, t):
123 r'(/\*(.|\n)*?\*/)|(//.*)'
124 t.lexer.lineno += t.value.count('\n')
125
126 # Error handling rule
127 def t_error(self, t):
128 raise ParseError("Illegal character '{}' ({})"
129 "in {}: line {}".format(t.value[0],
130 hex(ord(t.value[0])),
131 self.filename,
132 t.lexer.lineno))
133 t.lexer.skip(1)
134
135 # Define a rule so we can track line numbers
136 def t_newline(self, t):
137 r'\n+'
138 t.lexer.lineno += len(t.value)
139
140 literals = ":{}[];=.,"
141
142 # A string containing ignored characters (spaces and tabs)
143 t_ignore = ' \t'
144
Ole Troan17225df2018-04-11 09:50:03 +0200145
Ole Troan8dbfb432019-04-24 14:31:18 +0200146def crc_block_combine(block, crc):
Ole Troan58914252018-10-23 10:50:07 +0200147 s = str(block).encode()
Ole Troan8dbfb432019-04-24 14:31:18 +0200148 return binascii.crc32(s, crc) & 0xffffffff
Ole Troan58914252018-10-23 10:50:07 +0200149
Paul Vinciguerra063f3742019-07-02 13:00:58 -0400150
Ole Troand5a78a52019-09-18 12:12:47 +0200151def vla_is_last_check(name, block):
152 vla = False
153 for i, b in enumerate(block):
154 if isinstance(b, Array) and b.vla:
155 vla = True
156 if i + 1 < len(block):
157 raise ValueError(
158 'VLA field "{}" must be the last field in message "{}"'
159 .format(b.fieldname, name))
160 elif b.fieldtype.startswith('vl_api_'):
161 if global_types[b.fieldtype].vla:
162 vla = True
163 if i + 1 < len(block):
164 raise ValueError(
165 'VLA field "{}" must be the last '
166 'field in message "{}"'
167 .format(b.fieldname, name))
168 elif b.fieldtype == 'string' and b.length == 0:
169 vla = True
170 if i + 1 < len(block):
171 raise ValueError(
172 'VLA field "{}" must be the last '
173 'field in message "{}"'
174 .format(b.fieldname, name))
175 return vla
176
177
Ole Troan9d420872017-10-12 13:06:35 +0200178class Service():
Paul Vinciguerra7e0c48e2019-02-01 19:37:45 -0800179 def __init__(self, caller, reply, events=None, stream=False):
Ole Troan9d420872017-10-12 13:06:35 +0200180 self.caller = caller
181 self.reply = reply
182 self.stream = stream
Paul Vinciguerra7e0c48e2019-02-01 19:37:45 -0800183 self.events = [] if events is None else events
Ole Troan9d420872017-10-12 13:06:35 +0200184
185
186class Typedef():
187 def __init__(self, name, flags, block):
188 self.name = name
189 self.flags = flags
190 self.block = block
Ole Troan8dbfb432019-04-24 14:31:18 +0200191 self.crc = str(block).encode()
Ole Troan2c2feab2018-04-24 00:02:37 -0400192 self.manual_print = False
193 self.manual_endian = False
194 for f in flags:
195 if f == 'manual_print':
196 self.manual_print = True
197 elif f == 'manual_endian':
198 self.manual_endian = True
Ole Troan33a58172019-09-04 09:12:29 +0200199
Ole Troan8dbfb432019-04-24 14:31:18 +0200200 global_type_add(name, self)
Ole Troan9d420872017-10-12 13:06:35 +0200201
Ole Troand5a78a52019-09-18 12:12:47 +0200202 self.vla = vla_is_last_check(name, block)
Ole Troane5ff5a32019-08-23 22:55:18 +0200203
Ole Troan9d420872017-10-12 13:06:35 +0200204 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200205 return self.name + str(self.flags) + str(self.block)
Ole Troan9d420872017-10-12 13:06:35 +0200206
207
Ole Troan53fffa12018-11-13 12:36:56 +0100208class Using():
Ole Troan33a58172019-09-04 09:12:29 +0200209 def __init__(self, name, flags, alias):
Ole Troan53fffa12018-11-13 12:36:56 +0100210 self.name = name
Ole Troane5ff5a32019-08-23 22:55:18 +0200211 self.vla = False
Ole Troan75761b92019-09-11 17:49:08 +0200212 self.block = []
213 self.manual_print = True
214 self.manual_endian = True
Ole Troan53fffa12018-11-13 12:36:56 +0100215
Ole Troan33a58172019-09-04 09:12:29 +0200216 self.manual_print = False
217 self.manual_endian = False
218 for f in flags:
219 if f == 'manual_print':
220 self.manual_print = True
221 elif f == 'manual_endian':
222 self.manual_endian = True
223
Ole Troan53fffa12018-11-13 12:36:56 +0100224 if isinstance(alias, Array):
Ole Troane5ff5a32019-08-23 22:55:18 +0200225 a = {'type': alias.fieldtype,
226 'length': alias.length}
Ole Troan53fffa12018-11-13 12:36:56 +0100227 else:
Ole Troane5ff5a32019-08-23 22:55:18 +0200228 a = {'type': alias.fieldtype}
Ole Troan53fffa12018-11-13 12:36:56 +0100229 self.alias = a
Ole Troan8dbfb432019-04-24 14:31:18 +0200230 self.crc = str(alias).encode()
231 global_type_add(name, self)
Ole Troan53fffa12018-11-13 12:36:56 +0100232
233 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200234 return self.name + str(self.alias)
Ole Troan53fffa12018-11-13 12:36:56 +0100235
236
Ole Troan2c2feab2018-04-24 00:02:37 -0400237class Union():
Ole Troan33a58172019-09-04 09:12:29 +0200238 def __init__(self, name, flags, block):
Ole Troan2c2feab2018-04-24 00:02:37 -0400239 self.type = 'Union'
240 self.manual_print = False
241 self.manual_endian = False
Ole Troan2c2feab2018-04-24 00:02:37 -0400242 self.name = name
Ole Troan33a58172019-09-04 09:12:29 +0200243
Ole Troan33a58172019-09-04 09:12:29 +0200244 for f in flags:
245 if f == 'manual_print':
246 self.manual_print = True
247 elif f == 'manual_endian':
248 self.manual_endian = True
249
Ole Troan2c2feab2018-04-24 00:02:37 -0400250 self.block = block
Ole Troan8dbfb432019-04-24 14:31:18 +0200251 self.crc = str(block).encode()
Ole Troand5a78a52019-09-18 12:12:47 +0200252 self.vla = vla_is_last_check(name, block)
253
Ole Troan8dbfb432019-04-24 14:31:18 +0200254 global_type_add(name, self)
Ole Troan2c2feab2018-04-24 00:02:37 -0400255
256 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200257 return str(self.block)
Ole Troan2c2feab2018-04-24 00:02:37 -0400258
259
Ole Troan9d420872017-10-12 13:06:35 +0200260class Define():
261 def __init__(self, name, flags, block):
262 self.name = name
263 self.flags = flags
264 self.block = block
Ole Troan9d420872017-10-12 13:06:35 +0200265 self.dont_trace = False
266 self.manual_print = False
267 self.manual_endian = False
268 self.autoreply = False
269 self.singular = False
Ole Troan2a1ca782019-09-19 01:08:30 +0200270 self.options = {}
Ole Troan9d420872017-10-12 13:06:35 +0200271 for f in flags:
Ole Troan2c2feab2018-04-24 00:02:37 -0400272 if f == 'dont_trace':
Ole Troan9d420872017-10-12 13:06:35 +0200273 self.dont_trace = True
274 elif f == 'manual_print':
275 self.manual_print = True
276 elif f == 'manual_endian':
277 self.manual_endian = True
278 elif f == 'autoreply':
279 self.autoreply = True
280
Ole Troan5c318c72020-05-05 12:23:47 +0200281 remove = []
Ole Troand5a78a52019-09-18 12:12:47 +0200282 for b in block:
Ole Troan9d420872017-10-12 13:06:35 +0200283 if isinstance(b, Option):
284 if b[1] == 'singular' and b[2] == 'true':
285 self.singular = True
Ole Troan2a1ca782019-09-19 01:08:30 +0200286 else:
287 self.options[b.option] = b.value
Ole Troan5c318c72020-05-05 12:23:47 +0200288 remove.append(b)
Ole Troan2a1ca782019-09-19 01:08:30 +0200289
Ole Troan14a6c0e2020-05-13 11:47:43 +0200290 block = [x for x in block if x not in remove]
Ole Troan5c318c72020-05-05 12:23:47 +0200291 self.block = block
Ole Troand5a78a52019-09-18 12:12:47 +0200292 self.vla = vla_is_last_check(name, block)
Ole Troan2a1ca782019-09-19 01:08:30 +0200293 self.crc = str(block).encode()
Ole Troane5ff5a32019-08-23 22:55:18 +0200294
Ole Troan9d420872017-10-12 13:06:35 +0200295 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200296 return self.name + str(self.flags) + str(self.block)
Ole Troan9d420872017-10-12 13:06:35 +0200297
298
299class Enum():
300 def __init__(self, name, block, enumtype='u32'):
301 self.name = name
302 self.enumtype = enumtype
Ole Troane5ff5a32019-08-23 22:55:18 +0200303 self.vla = False
Ole Troan2c2feab2018-04-24 00:02:37 -0400304
Ole Troan9d420872017-10-12 13:06:35 +0200305 count = 0
306 for i, b in enumerate(block):
307 if type(b) is list:
308 count = b[1]
309 else:
310 count += 1
311 block[i] = [b, count]
312
313 self.block = block
Ole Troan8dbfb432019-04-24 14:31:18 +0200314 self.crc = str(block).encode()
315 global_type_add(name, self)
Ole Troan9d420872017-10-12 13:06:35 +0200316
317 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200318 return self.name + str(self.block)
Ole Troan9d420872017-10-12 13:06:35 +0200319
320
321class Import():
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400322
323 def __new__(cls, *args, **kwargs):
324 if args[0] not in seen_imports:
325 instance = super().__new__(cls)
326 instance._initialized = False
327 seen_imports[args[0]] = instance
328
329 return seen_imports[args[0]]
330
Ole Troan5c318c72020-05-05 12:23:47 +0200331 def __init__(self, filename, revision):
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400332 if self._initialized:
333 return
334 else:
335 self.filename = filename
336 # Deal with imports
Ole Troan5c318c72020-05-05 12:23:47 +0200337 parser = VPPAPI(filename=filename, revision=revision)
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400338 dirlist = dirlist_get()
339 f = filename
340 for dir in dirlist:
341 f = os.path.join(dir, filename)
342 if os.path.exists(f):
343 break
Ole Troan5c318c72020-05-05 12:23:47 +0200344 self.result = parser.parse_filename(f, None)
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400345 self._initialized = True
Ole Troan9d420872017-10-12 13:06:35 +0200346
347 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200348 return self.filename
Ole Troan9d420872017-10-12 13:06:35 +0200349
350
351class Option():
Ole Troan33a58172019-09-04 09:12:29 +0200352 def __init__(self, option, value):
353 self.type = 'Option'
Ole Troan9d420872017-10-12 13:06:35 +0200354 self.option = option
Ole Troan33a58172019-09-04 09:12:29 +0200355 self.value = value
Ole Troan8dbfb432019-04-24 14:31:18 +0200356 self.crc = str(option).encode()
Ole Troan9d420872017-10-12 13:06:35 +0200357
358 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200359 return str(self.option)
Ole Troan9d420872017-10-12 13:06:35 +0200360
361 def __getitem__(self, index):
362 return self.option[index]
363
364
365class Array():
Ole Troane5ff5a32019-08-23 22:55:18 +0200366 def __init__(self, fieldtype, name, length, modern_vla=False):
Ole Troan9d420872017-10-12 13:06:35 +0200367 self.type = 'Array'
368 self.fieldtype = fieldtype
369 self.fieldname = name
Ole Troane5ff5a32019-08-23 22:55:18 +0200370 self.modern_vla = modern_vla
Ole Troan9d420872017-10-12 13:06:35 +0200371 if type(length) is str:
372 self.lengthfield = length
373 self.length = 0
Ole Troane5ff5a32019-08-23 22:55:18 +0200374 self.vla = True
Ole Troan9d420872017-10-12 13:06:35 +0200375 else:
376 self.length = length
377 self.lengthfield = None
Ole Troane5ff5a32019-08-23 22:55:18 +0200378 self.vla = False
Ole Troan9d420872017-10-12 13:06:35 +0200379
380 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200381 return str([self.fieldtype, self.fieldname, self.length,
382 self.lengthfield])
Ole Troan9d420872017-10-12 13:06:35 +0200383
384
385class Field():
Ole Troan9ac11382019-04-23 17:11:01 +0200386 def __init__(self, fieldtype, name, limit=None):
Ole Troan9d420872017-10-12 13:06:35 +0200387 self.type = 'Field'
388 self.fieldtype = fieldtype
Ole Troane5ff5a32019-08-23 22:55:18 +0200389
390 if self.fieldtype == 'string':
391 raise ValueError("The string type {!r} is an "
392 "array type ".format(name))
393
Paul Vinciguerraff47fb62019-08-06 19:58:24 -0400394 if name in keyword.kwlist:
395 raise ValueError("Fieldname {!r} is a python keyword and is not "
396 "accessible via the python API. ".format(name))
Ole Troan9d420872017-10-12 13:06:35 +0200397 self.fieldname = name
Ole Troan9ac11382019-04-23 17:11:01 +0200398 self.limit = limit
Ole Troan9d420872017-10-12 13:06:35 +0200399
400 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200401 return str([self.fieldtype, self.fieldname])
Ole Troan9d420872017-10-12 13:06:35 +0200402
403
404class Coord(object):
405 """ Coordinates of a syntactic element. Consists of:
406 - File name
407 - Line number
408 - (optional) column number, for the Lexer
409 """
410 __slots__ = ('file', 'line', 'column', '__weakref__')
411
412 def __init__(self, file, line, column=None):
413 self.file = file
414 self.line = line
415 self.column = column
416
417 def __str__(self):
418 str = "%s:%s" % (self.file, self.line)
419 if self.column:
420 str += ":%s" % self.column
421 return str
422
423
424class ParseError(Exception):
425 pass
426
427
428#
429# Grammar rules
430#
431class VPPAPIParser(object):
432 tokens = VPPAPILexer.tokens
433
Ole Troan5c318c72020-05-05 12:23:47 +0200434 def __init__(self, filename, logger, revision=None):
Ole Troan9d420872017-10-12 13:06:35 +0200435 self.filename = filename
436 self.logger = logger
437 self.fields = []
Ole Troan5c318c72020-05-05 12:23:47 +0200438 self.revision = revision
Ole Troan9d420872017-10-12 13:06:35 +0200439
440 def _parse_error(self, msg, coord):
441 raise ParseError("%s: %s" % (coord, msg))
442
443 def _parse_warning(self, msg, coord):
444 if self.logger:
445 self.logger.warning("%s: %s" % (coord, msg))
446
447 def _coord(self, lineno, column=None):
448 return Coord(
449 file=self.filename,
450 line=lineno, column=column)
451
452 def _token_coord(self, p, token_idx):
453 """ Returns the coordinates for the YaccProduction object 'p' indexed
454 with 'token_idx'. The coordinate includes the 'lineno' and
455 'column'. Both follow the lex semantic, starting from 1.
456 """
457 last_cr = p.lexer.lexdata.rfind('\n', 0, p.lexpos(token_idx))
458 if last_cr < 0:
459 last_cr = -1
460 column = (p.lexpos(token_idx) - (last_cr))
461 return self._coord(p.lineno(token_idx), column)
462
463 def p_slist(self, p):
464 '''slist : stmt
465 | slist stmt'''
466 if len(p) == 2:
467 p[0] = [p[1]]
468 else:
469 p[0] = p[1] + [p[2]]
470
471 def p_stmt(self, p):
472 '''stmt : define
473 | typedef
474 | option
475 | import
476 | enum
Ole Troan2c2feab2018-04-24 00:02:37 -0400477 | union
Ole Troan9d420872017-10-12 13:06:35 +0200478 | service'''
479 p[0] = p[1]
480
481 def p_import(self, p):
482 '''import : IMPORT STRING_LITERAL ';' '''
Ole Troan5c318c72020-05-05 12:23:47 +0200483 p[0] = Import(p[2], revision=self.revision)
Ole Troan9d420872017-10-12 13:06:35 +0200484
485 def p_service(self, p):
486 '''service : SERVICE '{' service_statements '}' ';' '''
487 p[0] = p[3]
488
489 def p_service_statements(self, p):
490 '''service_statements : service_statement
491 | service_statements service_statement'''
492 if len(p) == 2:
493 p[0] = [p[1]]
494 else:
495 p[0] = p[1] + [p[2]]
496
497 def p_service_statement(self, p):
Marek Gradzki51e59682018-03-06 10:05:44 +0100498 '''service_statement : RPC ID RETURNS NULL ';'
499 | RPC ID RETURNS ID ';'
Ole Troan9d420872017-10-12 13:06:35 +0200500 | RPC ID RETURNS STREAM ID ';'
501 | RPC ID RETURNS ID EVENTS event_list ';' '''
Marek Gradzkifc70e3a2018-03-06 10:56:26 +0100502 if p[2] == p[4]:
503 # Verify that caller and reply differ
Ole Troan17225df2018-04-11 09:50:03 +0200504 self._parse_error(
505 'Reply ID ({}) should not be equal to Caller ID'.format(p[2]),
506 self._token_coord(p, 1))
Ole Troan9d420872017-10-12 13:06:35 +0200507 if len(p) == 8:
508 p[0] = Service(p[2], p[4], p[6])
509 elif len(p) == 7:
510 p[0] = Service(p[2], p[5], stream=True)
511 else:
512 p[0] = Service(p[2], p[4])
513
514 def p_event_list(self, p):
515 '''event_list : events
516 | event_list events '''
517 if len(p) == 2:
518 p[0] = [p[1]]
519 else:
520 p[0] = p[1] + [p[2]]
521
522 def p_event(self, p):
523 '''events : ID
524 | ID ',' '''
525 p[0] = p[1]
526
527 def p_enum(self, p):
528 '''enum : ENUM ID '{' enum_statements '}' ';' '''
529 p[0] = Enum(p[2], p[4])
530
531 def p_enum_type(self, p):
532 ''' enum : ENUM ID ':' enum_size '{' enum_statements '}' ';' '''
533 if len(p) == 9:
534 p[0] = Enum(p[2], p[6], enumtype=p[4])
535 else:
536 p[0] = Enum(p[2], p[4])
537
538 def p_enum_size(self, p):
539 ''' enum_size : U8
540 | U16
541 | U32 '''
542 p[0] = p[1]
543
544 def p_define(self, p):
545 '''define : DEFINE ID '{' block_statements_opt '}' ';' '''
546 self.fields = []
547 p[0] = Define(p[2], [], p[4])
548
549 def p_define_flist(self, p):
550 '''define : flist DEFINE ID '{' block_statements_opt '}' ';' '''
Ole Troan2c2feab2018-04-24 00:02:37 -0400551 # Legacy typedef
552 if 'typeonly' in p[1]:
Paul Vinciguerrae7174822019-08-07 00:05:59 -0400553 self._parse_error('legacy typedef. use typedef: {} {}[{}];'
554 .format(p[1], p[2], p[4]),
555 self._token_coord(p, 1))
Ole Troan2c2feab2018-04-24 00:02:37 -0400556 else:
557 p[0] = Define(p[3], p[1], p[5])
Ole Troan9d420872017-10-12 13:06:35 +0200558
559 def p_flist(self, p):
560 '''flist : flag
561 | flist flag'''
562 if len(p) == 2:
563 p[0] = [p[1]]
564 else:
565 p[0] = p[1] + [p[2]]
566
567 def p_flag(self, p):
568 '''flag : MANUAL_PRINT
569 | MANUAL_ENDIAN
570 | DONT_TRACE
571 | TYPEONLY
572 | AUTOREPLY'''
573 if len(p) == 1:
574 return
575 p[0] = p[1]
576
577 def p_typedef(self, p):
578 '''typedef : TYPEDEF ID '{' block_statements_opt '}' ';' '''
579 p[0] = Typedef(p[2], [], p[4])
580
Ole Troan33a58172019-09-04 09:12:29 +0200581 def p_typedef_flist(self, p):
582 '''typedef : flist TYPEDEF ID '{' block_statements_opt '}' ';' '''
583 p[0] = Typedef(p[3], p[1], p[5])
584
Ole Troan53fffa12018-11-13 12:36:56 +0100585 def p_typedef_alias(self, p):
586 '''typedef : TYPEDEF declaration '''
Ole Troan33a58172019-09-04 09:12:29 +0200587 p[0] = Using(p[2].fieldname, [], p[2])
588
589 def p_typedef_alias_flist(self, p):
590 '''typedef : flist TYPEDEF declaration '''
591 p[0] = Using(p[3].fieldname, p[1], p[3])
Ole Troan53fffa12018-11-13 12:36:56 +0100592
Ole Troan9d420872017-10-12 13:06:35 +0200593 def p_block_statements_opt(self, p):
Ole Troan2c2feab2018-04-24 00:02:37 -0400594 '''block_statements_opt : block_statements '''
Ole Troan9d420872017-10-12 13:06:35 +0200595 p[0] = p[1]
596
597 def p_block_statements(self, p):
598 '''block_statements : block_statement
599 | block_statements block_statement'''
600 if len(p) == 2:
601 p[0] = [p[1]]
602 else:
603 p[0] = p[1] + [p[2]]
604
605 def p_block_statement(self, p):
606 '''block_statement : declaration
607 | option '''
608 p[0] = p[1]
609
610 def p_enum_statements(self, p):
611 '''enum_statements : enum_statement
Ole Troan9ac11382019-04-23 17:11:01 +0200612 | enum_statements enum_statement'''
Ole Troan9d420872017-10-12 13:06:35 +0200613 if len(p) == 2:
614 p[0] = [p[1]]
615 else:
616 p[0] = p[1] + [p[2]]
617
618 def p_enum_statement(self, p):
619 '''enum_statement : ID '=' NUM ','
620 | ID ',' '''
621 if len(p) == 5:
622 p[0] = [p[1], p[3]]
623 else:
624 p[0] = p[1]
625
Ole Troan85465582019-04-30 10:04:36 +0200626 def p_field_options(self, p):
627 '''field_options : field_option
628 | field_options field_option'''
629 if len(p) == 2:
630 p[0] = p[1]
631 else:
Ole Troane5ff5a32019-08-23 22:55:18 +0200632 p[0] = {**p[1], **p[2]}
Ole Troan85465582019-04-30 10:04:36 +0200633
634 def p_field_option(self, p):
Ole Troane5ff5a32019-08-23 22:55:18 +0200635 '''field_option : ID
636 | ID '=' assignee ','
Ole Troan85465582019-04-30 10:04:36 +0200637 | ID '=' assignee
Ole Troane5ff5a32019-08-23 22:55:18 +0200638
Ole Troan85465582019-04-30 10:04:36 +0200639 '''
Ole Troane5ff5a32019-08-23 22:55:18 +0200640 if len(p) == 2:
641 p[0] = {p[1]: None}
642 else:
643 p[0] = {p[1]: p[3]}
Ole Troan85465582019-04-30 10:04:36 +0200644
Ole Troan9d420872017-10-12 13:06:35 +0200645 def p_declaration(self, p):
Ole Troan9ac11382019-04-23 17:11:01 +0200646 '''declaration : type_specifier ID ';'
Ole Troan85465582019-04-30 10:04:36 +0200647 | type_specifier ID '[' field_options ']' ';' '''
648 if len(p) == 7:
649 p[0] = Field(p[1], p[2], p[4])
Ole Troan9ac11382019-04-23 17:11:01 +0200650 elif len(p) == 4:
651 p[0] = Field(p[1], p[2])
652 else:
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400653 self._parse_error('ERROR', self._token_coord(p, 1))
Ole Troan9d420872017-10-12 13:06:35 +0200654 self.fields.append(p[2])
Ole Troan9ac11382019-04-23 17:11:01 +0200655
Ole Troane5ff5a32019-08-23 22:55:18 +0200656 def p_declaration_array_vla(self, p):
657 '''declaration : type_specifier ID '[' ']' ';' '''
658 p[0] = Array(p[1], p[2], 0, modern_vla=True)
659
Ole Troan9d420872017-10-12 13:06:35 +0200660 def p_declaration_array(self, p):
661 '''declaration : type_specifier ID '[' NUM ']' ';'
662 | type_specifier ID '[' ID ']' ';' '''
Ole Troane5ff5a32019-08-23 22:55:18 +0200663
Ole Troan9d420872017-10-12 13:06:35 +0200664 if len(p) != 7:
665 return self._parse_error(
666 'array: %s' % p.value,
667 self._coord(lineno=p.lineno))
668
669 # Make this error later
670 if type(p[4]) is int and p[4] == 0:
671 # XXX: Line number is wrong
672 self._parse_warning('Old Style VLA: {} {}[{}];'
673 .format(p[1], p[2], p[4]),
674 self._token_coord(p, 1))
675
676 if type(p[4]) is str and p[4] not in self.fields:
677 # Verify that length field exists
678 self._parse_error('Missing length field: {} {}[{}];'
679 .format(p[1], p[2], p[4]),
680 self._token_coord(p, 1))
681 p[0] = Array(p[1], p[2], p[4])
682
683 def p_option(self, p):
684 '''option : OPTION ID '=' assignee ';' '''
Ole Troan33a58172019-09-04 09:12:29 +0200685 p[0] = Option(p[2], p[4])
Ole Troan9d420872017-10-12 13:06:35 +0200686
687 def p_assignee(self, p):
688 '''assignee : NUM
689 | TRUE
690 | FALSE
691 | STRING_LITERAL '''
692 p[0] = p[1]
693
694 def p_type_specifier(self, p):
695 '''type_specifier : U8
696 | U16
697 | U32
698 | U64
699 | I8
700 | I16
701 | I32
702 | I64
703 | F64
704 | BOOL
705 | STRING'''
706 p[0] = p[1]
707
708 # Do a second pass later to verify that user defined types are defined
709 def p_typedef_specifier(self, p):
710 '''type_specifier : ID '''
711 if p[1] not in global_types:
712 self._parse_error('Undefined type: {}'.format(p[1]),
713 self._token_coord(p, 1))
714 p[0] = p[1]
715
Ole Troan2c2feab2018-04-24 00:02:37 -0400716 def p_union(self, p):
717 '''union : UNION ID '{' block_statements_opt '}' ';' '''
Ole Troan33a58172019-09-04 09:12:29 +0200718 p[0] = Union(p[2], [], p[4])
719
720 def p_union_flist(self, p):
721 '''union : flist UNION ID '{' block_statements_opt '}' ';' '''
722 p[0] = Union(p[3], p[1], p[5])
Ole Troan2c2feab2018-04-24 00:02:37 -0400723
Ole Troan9d420872017-10-12 13:06:35 +0200724 # Error rule for syntax errors
725 def p_error(self, p):
726 if p:
727 self._parse_error(
728 'before: %s' % p.value,
729 self._coord(lineno=p.lineno))
730 else:
731 self._parse_error('At end of input', self.filename)
732
733
734class VPPAPI(object):
735
Ole Troan5c318c72020-05-05 12:23:47 +0200736 def __init__(self, debug=False, filename='', logger=None, revision=None):
Ole Troan9d420872017-10-12 13:06:35 +0200737 self.lexer = lex.lex(module=VPPAPILexer(filename), debug=debug)
Ole Troan5c318c72020-05-05 12:23:47 +0200738 self.parser = yacc.yacc(module=VPPAPIParser(filename, logger,
739 revision=revision),
Ole Troand6743b12018-03-07 08:40:58 +0100740 write_tables=False, debug=debug)
Ole Troan9d420872017-10-12 13:06:35 +0200741 self.logger = logger
Ole Troan5c318c72020-05-05 12:23:47 +0200742 self.revision = revision
743 self.filename = filename
Ole Troan9d420872017-10-12 13:06:35 +0200744
745 def parse_string(self, code, debug=0, lineno=1):
746 self.lexer.lineno = lineno
747 return self.parser.parse(code, lexer=self.lexer, debug=debug)
748
Ole Troan5c318c72020-05-05 12:23:47 +0200749 def parse_fd(self, fd, debug=0):
Ole Troan9d420872017-10-12 13:06:35 +0200750 data = fd.read()
751 return self.parse_string(data, debug=debug)
752
Ole Troan5c318c72020-05-05 12:23:47 +0200753 def parse_filename(self, filename, debug=0):
754 if self.revision:
755 git_show = f'git show {self.revision}:{filename}'
Ole Troandeecc932020-05-19 12:33:00 +0200756 proc = Popen(git_show.split(), stdout=PIPE, encoding='utf-8')
757 try:
758 data, errs = proc.communicate()
759 if proc.returncode != 0:
760 print(f'File not found: {self.revision}:{filename}', file=sys.stderr)
761 sys.exit(2)
762 return self.parse_string(data, debug=debug)
763 except Exception as e:
764 sys.exit(3)
Ole Troan5c318c72020-05-05 12:23:47 +0200765 else:
766 try:
767 with open(filename, encoding='utf-8') as fd:
768 return self.parse_fd(fd, None)
769 except FileNotFoundError:
770 print(f'File not found: {filename}', file=sys.stderr)
771 sys.exit(2)
772
773 def autoreply_block(self, name, parent):
Ole Troan9d420872017-10-12 13:06:35 +0200774 block = [Field('u32', 'context'),
775 Field('i32', 'retval')]
Ole Troan5c318c72020-05-05 12:23:47 +0200776 # inherhit the parent's options
Ole Troan14a6c0e2020-05-13 11:47:43 +0200777 for k, v in parent.options.items():
Ole Troan5c318c72020-05-05 12:23:47 +0200778 block.append(Option(k, v))
Ole Troan9d420872017-10-12 13:06:35 +0200779 return Define(name + '_reply', [], block)
780
781 def process(self, objs):
782 s = {}
Ole Troan2c2feab2018-04-24 00:02:37 -0400783 s['Option'] = {}
784 s['Define'] = []
785 s['Service'] = []
786 s['types'] = []
787 s['Import'] = []
Ole Troan8dbfb432019-04-24 14:31:18 +0200788 crc = 0
Ole Troan9d420872017-10-12 13:06:35 +0200789 for o in objs:
Ole Troan2c2feab2018-04-24 00:02:37 -0400790 tname = o.__class__.__name__
Ole Troan8dbfb432019-04-24 14:31:18 +0200791 try:
Mark Nelsonea2abba2020-03-04 15:32:09 -0500792 crc = binascii.crc32(o.crc, crc) & 0xffffffff
Ole Troan8dbfb432019-04-24 14:31:18 +0200793 except AttributeError:
794 pass
Ole Troan9d420872017-10-12 13:06:35 +0200795 if isinstance(o, Define):
Ole Troan2c2feab2018-04-24 00:02:37 -0400796 s[tname].append(o)
797 if o.autoreply:
Ole Troan5c318c72020-05-05 12:23:47 +0200798 s[tname].append(self.autoreply_block(o.name, o))
Ole Troan9d420872017-10-12 13:06:35 +0200799 elif isinstance(o, Option):
Ole Troan59b6c0c2020-02-04 09:12:00 +0100800 s[tname][o.option] = o.value
Ole Troan9d420872017-10-12 13:06:35 +0200801 elif type(o) is list:
802 for o2 in o:
803 if isinstance(o2, Service):
Ole Troan2c2feab2018-04-24 00:02:37 -0400804 s['Service'].append(o2)
Ole Troan58914252018-10-23 10:50:07 +0200805 elif (isinstance(o, Enum) or
806 isinstance(o, Typedef) or
Ole Troan75761b92019-09-11 17:49:08 +0200807 isinstance(o, Using) or
Ole Troan58914252018-10-23 10:50:07 +0200808 isinstance(o, Union)):
Ole Troan2c2feab2018-04-24 00:02:37 -0400809 s['types'].append(o)
810 else:
811 if tname not in s:
Ole Troan58914252018-10-23 10:50:07 +0200812 raise ValueError('Unknown class type: {} {}'
813 .format(tname, o))
Ole Troan2c2feab2018-04-24 00:02:37 -0400814 s[tname].append(o)
Ole Troan9d420872017-10-12 13:06:35 +0200815
Ole Troan2c2feab2018-04-24 00:02:37 -0400816 msgs = {d.name: d for d in s['Define']}
817 svcs = {s.caller: s for s in s['Service']}
818 replies = {s.reply: s for s in s['Service']}
Marek Gradzki51e59682018-03-06 10:05:44 +0100819 seen_services = {}
Ole Troan9d420872017-10-12 13:06:35 +0200820
Ole Troan8dbfb432019-04-24 14:31:18 +0200821 s['file_crc'] = crc
822
Ole Troan9d420872017-10-12 13:06:35 +0200823 for service in svcs:
824 if service not in msgs:
Ole Troan17225df2018-04-11 09:50:03 +0200825 raise ValueError(
826 'Service definition refers to unknown message'
827 ' definition: {}'.format(service))
828 if svcs[service].reply != 'null' and \
829 svcs[service].reply not in msgs:
Ole Troan9d420872017-10-12 13:06:35 +0200830 raise ValueError('Service definition refers to unknown message'
831 ' definition in reply: {}'
832 .format(svcs[service].reply))
Marek Gradzkib533f3f2018-03-06 11:10:56 +0100833 if service in replies:
834 raise ValueError('Service definition refers to message'
835 ' marked as reply: {}'.format(service))
Ole Troan9d420872017-10-12 13:06:35 +0200836 for event in svcs[service].events:
837 if event not in msgs:
838 raise ValueError('Service definition refers to unknown '
839 'event: {} in message: {}'
840 .format(event, service))
Marek Gradzki51e59682018-03-06 10:05:44 +0100841 seen_services[event] = True
Ole Troan9d420872017-10-12 13:06:35 +0200842
Marek Gradzki51e59682018-03-06 10:05:44 +0100843 # Create services implicitly
Ole Troan9d420872017-10-12 13:06:35 +0200844 for d in msgs:
Marek Gradzki51e59682018-03-06 10:05:44 +0100845 if d in seen_services:
846 continue
Ole Troan9d420872017-10-12 13:06:35 +0200847 if msgs[d].singular is True:
848 continue
Ole Troan9d420872017-10-12 13:06:35 +0200849 if d.endswith('_reply'):
850 if d[:-6] in svcs:
851 continue
852 if d[:-6] not in msgs:
Marek Gradzkicc134712018-03-06 12:25:02 +0100853 raise ValueError('{} missing calling message'
854 .format(d))
Ole Troan9d420872017-10-12 13:06:35 +0200855 continue
856 if d.endswith('_dump'):
857 if d in svcs:
858 continue
859 if d[:-5]+'_details' in msgs:
Ole Troan2c2feab2018-04-24 00:02:37 -0400860 s['Service'].append(Service(d, d[:-5]+'_details',
Ole Troan58914252018-10-23 10:50:07 +0200861 stream=True))
Ole Troan9d420872017-10-12 13:06:35 +0200862 else:
Marek Gradzkicc134712018-03-06 12:25:02 +0100863 raise ValueError('{} missing details message'
864 .format(d))
Ole Troan9d420872017-10-12 13:06:35 +0200865 continue
866
867 if d.endswith('_details'):
868 if d[:-8]+'_dump' not in msgs:
Marek Gradzkicc134712018-03-06 12:25:02 +0100869 raise ValueError('{} missing dump message'
870 .format(d))
Ole Troan9d420872017-10-12 13:06:35 +0200871 continue
872
873 if d in svcs:
874 continue
875 if d+'_reply' in msgs:
Ole Troan2c2feab2018-04-24 00:02:37 -0400876 s['Service'].append(Service(d, d+'_reply'))
Ole Troan9d420872017-10-12 13:06:35 +0200877 else:
Ole Troan17225df2018-04-11 09:50:03 +0200878 raise ValueError(
879 '{} missing reply message ({}) or service definition'
880 .format(d, d+'_reply'))
Ole Troan9d420872017-10-12 13:06:35 +0200881
882 return s
883
Ole Troan2c2feab2018-04-24 00:02:37 -0400884 def process_imports(self, objs, in_import, result):
Marek Gradzki51e59682018-03-06 10:05:44 +0100885 imported_objs = []
Ole Troan9d420872017-10-12 13:06:35 +0200886 for o in objs:
Ole Troan2c2feab2018-04-24 00:02:37 -0400887 # Only allow the following object types from imported file
888 if in_import and not (isinstance(o, Enum) or
889 isinstance(o, Union) or
Ole Troan10a09892018-06-29 11:32:33 +0200890 isinstance(o, Typedef) or
Ole Troan53fffa12018-11-13 12:36:56 +0100891 isinstance(o, Import) or
892 isinstance(o, Using)):
Ole Troan2c2feab2018-04-24 00:02:37 -0400893 continue
Ole Troan2c2feab2018-04-24 00:02:37 -0400894 if isinstance(o, Import):
Ole Troan33a58172019-09-04 09:12:29 +0200895 result.append(o)
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400896 result = self.process_imports(o.result, True, result)
Ole Troan10a09892018-06-29 11:32:33 +0200897 else:
898 result.append(o)
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400899 return result
Ole Troan9d420872017-10-12 13:06:35 +0200900
Ole Troan58914252018-10-23 10:50:07 +0200901
Ole Troan9d420872017-10-12 13:06:35 +0200902# Add message ids to each message.
903def add_msg_id(s):
904 for o in s:
905 o.block.insert(0, Field('u16', '_vl_msg_id'))
906 return s
907
908
Ole Troan9d420872017-10-12 13:06:35 +0200909dirlist = []
910
911
912def dirlist_add(dirs):
913 global dirlist
914 if dirs:
915 dirlist = dirlist + dirs
916
917
918def dirlist_get():
919 return dirlist
920
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -0400921
Ole Troan8dbfb432019-04-24 14:31:18 +0200922def foldup_blocks(block, crc):
923 for b in block:
924 # Look up CRC in user defined types
925 if b.fieldtype.startswith('vl_api_'):
926 # Recursively
927 t = global_types[b.fieldtype]
928 try:
929 crc = crc_block_combine(t.block, crc)
930 return foldup_blocks(t.block, crc)
Ole Troane5ff5a32019-08-23 22:55:18 +0200931 except AttributeError:
Ole Troan8dbfb432019-04-24 14:31:18 +0200932 pass
933 return crc
934
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -0400935
Ole Troan8dbfb432019-04-24 14:31:18 +0200936def foldup_crcs(s):
937 for f in s:
938 f.crc = foldup_blocks(f.block,
Mark Nelsonea2abba2020-03-04 15:32:09 -0500939 binascii.crc32(f.crc) & 0xffffffff)
Ole Troan9d420872017-10-12 13:06:35 +0200940
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -0400941
Ole Troan9d420872017-10-12 13:06:35 +0200942#
943# Main
944#
945def main():
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -0400946 if sys.version_info < (3, 5,):
947 log.exception('vppapigen requires a supported version of python. '
948 'Please use version 3.5 or greater. '
949 'Using {}'.format(sys.version))
950 return 1
951
Ole Troan9d420872017-10-12 13:06:35 +0200952 cliparser = argparse.ArgumentParser(description='VPP API generator')
953 cliparser.add_argument('--pluginpath', default=""),
954 cliparser.add_argument('--includedir', action='append'),
Ole Troan2a1ca782019-09-19 01:08:30 +0200955 cliparser.add_argument('--outputdir', action='store'),
Ole Troan5c318c72020-05-05 12:23:47 +0200956 cliparser.add_argument('--input')
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -0400957 cliparser.add_argument('--output', nargs='?',
958 type=argparse.FileType('w', encoding='UTF-8'),
959 default=sys.stdout)
Ole Troan9d420872017-10-12 13:06:35 +0200960
961 cliparser.add_argument('output_module', nargs='?', default='C')
962 cliparser.add_argument('--debug', action='store_true')
963 cliparser.add_argument('--show-name', nargs=1)
Ole Troan5c318c72020-05-05 12:23:47 +0200964 cliparser.add_argument('--git-revision',
965 help="Git revision to use for opening files")
Ole Troan9d420872017-10-12 13:06:35 +0200966 args = cliparser.parse_args()
967
968 dirlist_add(args.includedir)
969 if not args.debug:
970 sys.excepthook = exception_handler
971
972 # Filename
973 if args.show_name:
974 filename = args.show_name[0]
Ole Troan5c318c72020-05-05 12:23:47 +0200975 elif args.input:
976 filename = args.input
Ole Troan9d420872017-10-12 13:06:35 +0200977 else:
978 filename = ''
979
Marek Gradzki51e59682018-03-06 10:05:44 +0100980 if args.debug:
981 logging.basicConfig(stream=sys.stdout, level=logging.WARNING)
982 else:
983 logging.basicConfig()
Marek Gradzki51e59682018-03-06 10:05:44 +0100984
Ole Troan5c318c72020-05-05 12:23:47 +0200985 parser = VPPAPI(debug=args.debug, filename=filename, logger=log,
986 revision=args.git_revision)
987
988 try:
989 if not args.input:
990 parsed_objects = parser.parse_fd(sys.stdin, log)
991 else:
992 parsed_objects = parser.parse_filename(args.input, log)
993 except ParseError as e:
994 print('Parse error: ', e, file=sys.stderr)
995 sys.exit(1)
Ole Troan9d420872017-10-12 13:06:35 +0200996
997 # Build a list of objects. Hash of lists.
Ole Troan2c2feab2018-04-24 00:02:37 -0400998 result = []
Ole Troan33a58172019-09-04 09:12:29 +0200999
1000 if args.output_module == 'C':
1001 s = parser.process(parsed_objects)
1002 else:
Paul Vinciguerra4bf84902019-07-31 00:34:05 -04001003 result = parser.process_imports(parsed_objects, False, result)
Ole Troan33a58172019-09-04 09:12:29 +02001004 s = parser.process(result)
Ole Troan9d420872017-10-12 13:06:35 +02001005
1006 # Add msg_id field
Ole Troan2c2feab2018-04-24 00:02:37 -04001007 s['Define'] = add_msg_id(s['Define'])
Ole Troan9d420872017-10-12 13:06:35 +02001008
Ole Troan8dbfb432019-04-24 14:31:18 +02001009 # Fold up CRCs
1010 foldup_crcs(s['Define'])
Ole Troan9d420872017-10-12 13:06:35 +02001011
1012 #
1013 # Debug
1014 if args.debug:
1015 import pprint
Ole Troan10a09892018-06-29 11:32:33 +02001016 pp = pprint.PrettyPrinter(indent=4, stream=sys.stderr)
Ole Troan2c2feab2018-04-24 00:02:37 -04001017 for t in s['Define']:
Ole Troan9d420872017-10-12 13:06:35 +02001018 pp.pprint([t.name, t.flags, t.block])
Ole Troan2c2feab2018-04-24 00:02:37 -04001019 for t in s['types']:
1020 pp.pprint([t.name, t.block])
Ole Troan9d420872017-10-12 13:06:35 +02001021
1022 #
1023 # Generate representation
1024 #
Paul Vinciguerraf4647ed2019-02-12 12:21:01 -08001025 from importlib.machinery import SourceFileLoader
Ole Troan9d420872017-10-12 13:06:35 +02001026
1027 # Default path
Ole Troan30787372018-03-01 13:33:39 +01001028 pluginpath = ''
Ole Troan9d420872017-10-12 13:06:35 +02001029 if not args.pluginpath:
Ole Troan30787372018-03-01 13:33:39 +01001030 cand = []
1031 cand.append(os.path.dirname(os.path.realpath(__file__)))
Ole Troan17225df2018-04-11 09:50:03 +02001032 cand.append(os.path.dirname(os.path.realpath(__file__)) +
Ole Troan30787372018-03-01 13:33:39 +01001033 '/../share/vpp/')
1034 for c in cand:
1035 c += '/'
Ole Troan58914252018-10-23 10:50:07 +02001036 if os.path.isfile('{}vppapigen_{}.py'
1037 .format(c, args.output_module.lower())):
Ole Troan30787372018-03-01 13:33:39 +01001038 pluginpath = c
1039 break
Ole Troan9d420872017-10-12 13:06:35 +02001040 else:
1041 pluginpath = args.pluginpath + '/'
Ole Troan30787372018-03-01 13:33:39 +01001042 if pluginpath == '':
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001043 log.exception('Output plugin not found')
1044 return 1
Ole Troan58914252018-10-23 10:50:07 +02001045 module_path = '{}vppapigen_{}.py'.format(pluginpath,
1046 args.output_module.lower())
Ole Troan9d420872017-10-12 13:06:35 +02001047
1048 try:
Paul Vinciguerraf4647ed2019-02-12 12:21:01 -08001049 plugin = SourceFileLoader(args.output_module,
1050 module_path).load_module()
Ole Troan58914252018-10-23 10:50:07 +02001051 except Exception as err:
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001052 log.exception('Error importing output plugin: {}, {}'
1053 .format(module_path, err))
1054 return 1
Ole Troan9d420872017-10-12 13:06:35 +02001055
Ole Troan2a1ca782019-09-19 01:08:30 +02001056 result = plugin.run(args, filename, s)
Ole Troan9d420872017-10-12 13:06:35 +02001057 if result:
Ole Troan17225df2018-04-11 09:50:03 +02001058 print(result, file=args.output)
Ole Troan9d420872017-10-12 13:06:35 +02001059 else:
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001060 log.exception('Running plugin failed: {} {}'
1061 .format(filename, result))
1062 return 1
1063 return 0
Ole Troan9d420872017-10-12 13:06:35 +02001064
1065
1066if __name__ == '__main__':
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001067 sys.exit(main())