blob: 944bf5e7135c09a5bab4e330ced75d6d3f2a756d [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 sys
4import argparse
Paul Vinciguerraff47fb62019-08-06 19:58:24 -04005import keyword
Ole Troan9d420872017-10-12 13:06:35 +02006import logging
7import binascii
8import os
Ole Troan5c318c72020-05-05 12:23:47 +02009from subprocess import Popen, PIPE
Ole Troandf87f802020-11-18 19:17:48 +010010import ply.lex as lex
11import ply.yacc as yacc
Ole Troan9d420872017-10-12 13:06:35 +020012
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020013assert sys.version_info >= (3, 5), "Not supported Python version: {}".format(
14 sys.version
15)
16log = logging.getLogger("vppapigen")
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -040017
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):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +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:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020035 raise KeyError("Attempted redefinition of {!r} with {!r}.".format(name, obj))
Ole Troan8dbfb432019-04-24 14:31:18 +020036 global_types[type_name] = obj
Ole Troan9d420872017-10-12 13:06:35 +020037
38
39# All your trace are belong to us!
40def exception_handler(exception_type, exception, traceback):
Ole Troan17225df2018-04-11 09:50:03 +020041 print("%s: %s" % (exception_type.__name__, exception))
Ole Troan9d420872017-10-12 13:06:35 +020042
43
44#
45# Lexer
46#
Paul Vinciguerrab00c49c2020-12-04 15:01:53 -050047class VPPAPILexer:
Ole Troan9d420872017-10-12 13:06:35 +020048 def __init__(self, filename):
49 self.filename = filename
50
51 reserved = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020052 "service": "SERVICE",
53 "rpc": "RPC",
54 "returns": "RETURNS",
55 "null": "NULL",
56 "stream": "STREAM",
57 "events": "EVENTS",
58 "define": "DEFINE",
59 "typedef": "TYPEDEF",
60 "enum": "ENUM",
61 "enumflag": "ENUMFLAG",
62 "typeonly": "TYPEONLY",
63 "manual_print": "MANUAL_PRINT",
64 "manual_endian": "MANUAL_ENDIAN",
65 "dont_trace": "DONT_TRACE",
66 "autoreply": "AUTOREPLY",
67 "autoendian": "AUTOENDIAN",
68 "option": "OPTION",
69 "u8": "U8",
70 "u16": "U16",
71 "u32": "U32",
72 "u64": "U64",
73 "i8": "I8",
74 "i16": "I16",
75 "i32": "I32",
76 "i64": "I64",
77 "f64": "F64",
78 "bool": "BOOL",
79 "string": "STRING",
80 "import": "IMPORT",
81 "true": "TRUE",
82 "false": "FALSE",
83 "union": "UNION",
84 "counters": "COUNTERS",
85 "paths": "PATHS",
86 "units": "UNITS",
87 "severity": "SEVERITY",
88 "type": "TYPE",
89 "description": "DESCRIPTION",
Ole Troan9d420872017-10-12 13:06:35 +020090 }
91
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020092 tokens = ["STRING_LITERAL", "ID", "NUM"] + list(reserved.values())
Ole Troan9d420872017-10-12 13:06:35 +020093
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020094 t_ignore_LINE_COMMENT = "//.*"
Ole Troan9d420872017-10-12 13:06:35 +020095
Ole Troan33a58172019-09-04 09:12:29 +020096 def t_FALSE(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020097 r"false"
Ole Troan33a58172019-09-04 09:12:29 +020098 t.value = False
99 return t
100
101 def t_TRUE(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200102 r"false"
Ole Troan33a58172019-09-04 09:12:29 +0200103 t.value = True
104 return t
105
Ole Troan9d420872017-10-12 13:06:35 +0200106 def t_NUM(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200107 r"0[xX][0-9a-fA-F]+|-?\d+\.?\d*"
108 base = 16 if t.value.startswith("0x") else 10
109 if "." in t.value:
Paul Vinciguerra063f3742019-07-02 13:00:58 -0400110 t.value = float(t.value)
111 else:
112 t.value = int(t.value, base)
Ole Troan9d420872017-10-12 13:06:35 +0200113 return t
114
115 def t_ID(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200116 r"[a-zA-Z_][a-zA-Z_0-9]*"
Ole Troan9d420872017-10-12 13:06:35 +0200117 # Check for reserved words
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200118 t.type = VPPAPILexer.reserved.get(t.value, "ID")
Ole Troan9d420872017-10-12 13:06:35 +0200119 return t
120
121 # C string
122 def t_STRING_LITERAL(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200123 r"\"([^\\\n]|(\\.))*?\" "
124 t.value = str(t.value).replace('"', "")
Ole Troan9d420872017-10-12 13:06:35 +0200125 return t
126
127 # C or C++ comment (ignore)
128 def t_comment(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200129 r"(/\*(.|\n)*?\*/)|(//.*)"
130 t.lexer.lineno += t.value.count("\n")
Ole Troan9d420872017-10-12 13:06:35 +0200131
132 # Error handling rule
133 def t_error(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200134 raise ParseError(
135 "Illegal character '{}' ({})"
136 "in {}: line {}".format(
137 t.value[0], hex(ord(t.value[0])), self.filename, t.lexer.lineno
138 )
139 )
Ole Troan9d420872017-10-12 13:06:35 +0200140
141 # Define a rule so we can track line numbers
142 def t_newline(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200143 r"\n+"
Ole Troan9d420872017-10-12 13:06:35 +0200144 t.lexer.lineno += len(t.value)
145
146 literals = ":{}[];=.,"
147
148 # A string containing ignored characters (spaces and tabs)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200149 t_ignore = " \t"
Ole Troan9d420872017-10-12 13:06:35 +0200150
Ole Troan17225df2018-04-11 09:50:03 +0200151
Ole Troandf87f802020-11-18 19:17:48 +0100152def vla_mark_length_field(block):
153 if isinstance(block[-1], Array):
154 lengthfield = block[-1].lengthfield
155 for b in block:
156 if b.fieldname == lengthfield:
157 b.is_lengthfield = True
158
159
Ole Troand5a78a52019-09-18 12:12:47 +0200160def vla_is_last_check(name, block):
161 vla = False
162 for i, b in enumerate(block):
163 if isinstance(b, Array) and b.vla:
164 vla = True
165 if i + 1 < len(block):
166 raise ValueError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200167 'VLA field "{}" must be the last field in message "{}"'.format(
168 b.fieldname, name
169 )
170 )
171 elif b.fieldtype.startswith("vl_api_"):
Ole Troand5a78a52019-09-18 12:12:47 +0200172 if global_types[b.fieldtype].vla:
173 vla = True
174 if i + 1 < len(block):
175 raise ValueError(
176 'VLA field "{}" must be the last '
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200177 'field in message "{}"'.format(b.fieldname, name)
178 )
179 elif b.fieldtype == "string" and b.length == 0:
Ole Troand5a78a52019-09-18 12:12:47 +0200180 vla = True
181 if i + 1 < len(block):
182 raise ValueError(
183 'VLA field "{}" must be the last '
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200184 'field in message "{}"'.format(b.fieldname, name)
185 )
Ole Troand5a78a52019-09-18 12:12:47 +0200186 return vla
187
188
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500189class Processable:
190 type = "<Invalid>"
191
192 def process(self, result): # -> Dict
193 result[self.type].append(self)
194
195
196class Service(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200197 type = "Service"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500198
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200199 def __init__(self, caller, reply, events=None, stream_message=None, stream=False):
Ole Troan9d420872017-10-12 13:06:35 +0200200 self.caller = caller
201 self.reply = reply
202 self.stream = stream
Ole Troanf5db3712020-05-20 15:47:06 +0200203 self.stream_message = stream_message
Paul Vinciguerra7e0c48e2019-02-01 19:37:45 -0800204 self.events = [] if events is None else events
Ole Troan9d420872017-10-12 13:06:35 +0200205
206
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500207class Typedef(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200208 type = "Typedef"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500209
Ole Troan9d420872017-10-12 13:06:35 +0200210 def __init__(self, name, flags, block):
211 self.name = name
212 self.flags = flags
213 self.block = block
Ole Troan8dbfb432019-04-24 14:31:18 +0200214 self.crc = str(block).encode()
Ole Troan2c2feab2018-04-24 00:02:37 -0400215 self.manual_print = False
216 self.manual_endian = False
217 for f in flags:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200218 if f == "manual_print":
Ole Troan2c2feab2018-04-24 00:02:37 -0400219 self.manual_print = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200220 elif f == "manual_endian":
Ole Troan2c2feab2018-04-24 00:02:37 -0400221 self.manual_endian = True
Ole Troan8dbfb432019-04-24 14:31:18 +0200222 global_type_add(name, self)
Ole Troan9d420872017-10-12 13:06:35 +0200223
Ole Troand5a78a52019-09-18 12:12:47 +0200224 self.vla = vla_is_last_check(name, block)
Ole Troandf87f802020-11-18 19:17:48 +0100225 vla_mark_length_field(self.block)
Ole Troane5ff5a32019-08-23 22:55:18 +0200226
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500227 def process(self, result):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200228 result["types"].append(self)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500229
Ole Troan9d420872017-10-12 13:06:35 +0200230 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200231 return self.name + str(self.flags) + str(self.block)
Ole Troan9d420872017-10-12 13:06:35 +0200232
233
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500234class Using(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200235 type = "Using"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500236
Ole Troan33a58172019-09-04 09:12:29 +0200237 def __init__(self, name, flags, alias):
Ole Troan53fffa12018-11-13 12:36:56 +0100238 self.name = name
Ole Troane5ff5a32019-08-23 22:55:18 +0200239 self.vla = False
Ole Troan75761b92019-09-11 17:49:08 +0200240 self.block = []
241 self.manual_print = True
242 self.manual_endian = True
Ole Troan53fffa12018-11-13 12:36:56 +0100243
Ole Troan33a58172019-09-04 09:12:29 +0200244 self.manual_print = False
245 self.manual_endian = False
246 for f in flags:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200247 if f == "manual_print":
Ole Troan33a58172019-09-04 09:12:29 +0200248 self.manual_print = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200249 elif f == "manual_endian":
Ole Troan33a58172019-09-04 09:12:29 +0200250 self.manual_endian = True
251
Ole Troan53fffa12018-11-13 12:36:56 +0100252 if isinstance(alias, Array):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200253 a = {"type": alias.fieldtype, "length": alias.length}
Ole Troan53fffa12018-11-13 12:36:56 +0100254 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200255 a = {"type": alias.fieldtype}
Ole Troan53fffa12018-11-13 12:36:56 +0100256 self.alias = a
Ole Troandf87f802020-11-18 19:17:48 +0100257 self.using = alias
258
Ole Troan6006ca82020-08-31 13:54:47 +0200259 #
260 # Should have been:
261 # self.crc = str(alias).encode()
262 # but to be backwards compatible use the block ([])
263 #
264 self.crc = str(self.block).encode()
Ole Troan8dbfb432019-04-24 14:31:18 +0200265 global_type_add(name, self)
Ole Troan53fffa12018-11-13 12:36:56 +0100266
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500267 def process(self, result): # -> Dict
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200268 result["types"].append(self)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500269
Ole Troan53fffa12018-11-13 12:36:56 +0100270 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200271 return self.name + str(self.alias)
Ole Troan53fffa12018-11-13 12:36:56 +0100272
273
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500274class Union(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200275 type = "Union"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500276
Ole Troan33a58172019-09-04 09:12:29 +0200277 def __init__(self, name, flags, block):
Ole Troan2c2feab2018-04-24 00:02:37 -0400278 self.manual_print = False
279 self.manual_endian = False
Ole Troan2c2feab2018-04-24 00:02:37 -0400280 self.name = name
Ole Troan33a58172019-09-04 09:12:29 +0200281
Ole Troan33a58172019-09-04 09:12:29 +0200282 for f in flags:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200283 if f == "manual_print":
Ole Troan33a58172019-09-04 09:12:29 +0200284 self.manual_print = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200285 elif f == "manual_endian":
Ole Troan33a58172019-09-04 09:12:29 +0200286 self.manual_endian = True
287
Ole Troan2c2feab2018-04-24 00:02:37 -0400288 self.block = block
Ole Troan8dbfb432019-04-24 14:31:18 +0200289 self.crc = str(block).encode()
Ole Troand5a78a52019-09-18 12:12:47 +0200290 self.vla = vla_is_last_check(name, block)
291
Ole Troan8dbfb432019-04-24 14:31:18 +0200292 global_type_add(name, self)
Ole Troan2c2feab2018-04-24 00:02:37 -0400293
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500294 def process(self, result):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200295 result["types"].append(self)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500296
Ole Troan2c2feab2018-04-24 00:02:37 -0400297 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200298 return str(self.block)
Ole Troan2c2feab2018-04-24 00:02:37 -0400299
300
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500301class Define(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200302 type = "Define"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500303
Ole Troan9d420872017-10-12 13:06:35 +0200304 def __init__(self, name, flags, block):
305 self.name = name
306 self.flags = flags
307 self.block = block
Ole Troan9d420872017-10-12 13:06:35 +0200308 self.dont_trace = False
309 self.manual_print = False
310 self.manual_endian = False
311 self.autoreply = False
Neale Ranns9302cfe2021-02-02 09:21:52 +0000312 self.autoendian = 0
Ole Troan2a1ca782019-09-19 01:08:30 +0200313 self.options = {}
Ole Troan9d420872017-10-12 13:06:35 +0200314 for f in flags:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200315 if f == "dont_trace":
Ole Troan9d420872017-10-12 13:06:35 +0200316 self.dont_trace = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200317 elif f == "manual_print":
Ole Troan9d420872017-10-12 13:06:35 +0200318 self.manual_print = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200319 elif f == "manual_endian":
Ole Troan9d420872017-10-12 13:06:35 +0200320 self.manual_endian = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200321 elif f == "autoreply":
Ole Troan9d420872017-10-12 13:06:35 +0200322 self.autoreply = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200323 elif f == "autoendian":
Neale Ranns9302cfe2021-02-02 09:21:52 +0000324 self.autoendian = 1
Ole Troan9d420872017-10-12 13:06:35 +0200325
Ole Troan5c318c72020-05-05 12:23:47 +0200326 remove = []
Ole Troand5a78a52019-09-18 12:12:47 +0200327 for b in block:
Ole Troan9d420872017-10-12 13:06:35 +0200328 if isinstance(b, Option):
Ole Troan791c2062020-12-08 20:35:32 +0100329 self.options[b.option] = b.value
Ole Troan5c318c72020-05-05 12:23:47 +0200330 remove.append(b)
Ole Troan2a1ca782019-09-19 01:08:30 +0200331
Ole Troan14a6c0e2020-05-13 11:47:43 +0200332 block = [x for x in block if x not in remove]
Ole Troan5c318c72020-05-05 12:23:47 +0200333 self.block = block
Ole Troand5a78a52019-09-18 12:12:47 +0200334 self.vla = vla_is_last_check(name, block)
Ole Troandf87f802020-11-18 19:17:48 +0100335 vla_mark_length_field(self.block)
336
Ole Troan2a1ca782019-09-19 01:08:30 +0200337 self.crc = str(block).encode()
Ole Troane5ff5a32019-08-23 22:55:18 +0200338
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500339 def autoreply_block(self, name, parent):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200340 block = [Field("u32", "context"), Field("i32", "retval")]
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500341 # inherit the parent's options
342 for k, v in parent.options.items():
343 block.append(Option(k, v))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200344 return Define(name + "_reply", [], block)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500345
346 def process(self, result): # -> Dict
347 tname = self.__class__.__name__
348 result[tname].append(self)
349 if self.autoreply:
350 result[tname].append(self.autoreply_block(self.name, self))
351
Ole Troan9d420872017-10-12 13:06:35 +0200352 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200353 return self.name + str(self.flags) + str(self.block)
Ole Troan9d420872017-10-12 13:06:35 +0200354
355
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500356class Enum(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200357 type = "Enum"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500358
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200359 def __init__(self, name, block, enumtype="u32"):
Ole Troan9d420872017-10-12 13:06:35 +0200360 self.name = name
361 self.enumtype = enumtype
Ole Troane5ff5a32019-08-23 22:55:18 +0200362 self.vla = False
Ole Troandf87f802020-11-18 19:17:48 +0100363 self.manual_print = False
Ole Troan2c2feab2018-04-24 00:02:37 -0400364
Filip Varga9a8d3d72022-05-23 21:18:38 +0200365 count = -1
Ole Troan6006ca82020-08-31 13:54:47 +0200366 block2 = []
367 block3 = []
368 bc_set = False
369
370 for b in block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200371 if "value" in b:
372 count = b["value"]
Ole Troan9d420872017-10-12 13:06:35 +0200373 else:
374 count += 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200375 block2.append([b["id"], count])
Ole Troan6006ca82020-08-31 13:54:47 +0200376 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200377 if b["option"]["backwards_compatible"]:
Ole Troan6006ca82020-08-31 13:54:47 +0200378 pass
379 bc_set = True
380 except KeyError:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200381 block3.append([b["id"], count])
Ole Troan6006ca82020-08-31 13:54:47 +0200382 if bc_set:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200383 raise ValueError(
384 "Backward compatible enum must "
385 "be last {!r} {!r}".format(name, b["id"])
386 )
Ole Troan6006ca82020-08-31 13:54:47 +0200387 self.block = block2
388 self.crc = str(block3).encode()
Ole Troan8dbfb432019-04-24 14:31:18 +0200389 global_type_add(name, self)
Ole Troan9d420872017-10-12 13:06:35 +0200390
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500391 def process(self, result):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200392 result["types"].append(self)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500393
Ole Troan9d420872017-10-12 13:06:35 +0200394 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200395 return self.name + str(self.block)
Ole Troan9d420872017-10-12 13:06:35 +0200396
397
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500398class EnumFlag(Enum):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200399 type = "EnumFlag"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500400
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200401 def __init__(self, name, block, enumtype="u32"):
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500402 super(EnumFlag, self).__init__(name, block, enumtype)
403
404 for b in self.block:
405 if bin(b[1])[2:].count("1") > 1:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200406 raise TypeError(
407 "%s is not a flag enum. No element in a "
408 "flag enum may have more than a "
409 "single bit set." % self.name
410 )
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500411
412
413class Import(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200414 type = "Import"
Ole Troandf87f802020-11-18 19:17:48 +0100415 _initialized = False
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500416
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400417 def __new__(cls, *args, **kwargs):
418 if args[0] not in seen_imports:
419 instance = super().__new__(cls)
420 instance._initialized = False
421 seen_imports[args[0]] = instance
422
423 return seen_imports[args[0]]
424
Ole Troan5c318c72020-05-05 12:23:47 +0200425 def __init__(self, filename, revision):
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400426 if self._initialized:
427 return
Ole Troandf87f802020-11-18 19:17:48 +0100428 self.filename = filename
429 # Deal with imports
430 parser = VPPAPI(filename=filename, revision=revision)
431 dirlist = dirlist_get()
432 f = filename
433 for dir in dirlist:
434 f = os.path.join(dir, filename)
435 if os.path.exists(f):
436 break
437 self.result = parser.parse_filename(f, None)
438 self._initialized = True
Ole Troan9d420872017-10-12 13:06:35 +0200439
440 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200441 return self.filename
Ole Troan9d420872017-10-12 13:06:35 +0200442
443
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500444class Option(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200445 type = "Option"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500446
Ole Troan68ebcd52020-08-10 17:06:44 +0200447 def __init__(self, option, value=None):
Ole Troan9d420872017-10-12 13:06:35 +0200448 self.option = option
Ole Troan33a58172019-09-04 09:12:29 +0200449 self.value = value
Ole Troan8dbfb432019-04-24 14:31:18 +0200450 self.crc = str(option).encode()
Ole Troan9d420872017-10-12 13:06:35 +0200451
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500452 def process(self, result): # -> Dict
453 result[self.type][self.option] = self.value
454
Ole Troan9d420872017-10-12 13:06:35 +0200455 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200456 return str(self.option)
Ole Troan9d420872017-10-12 13:06:35 +0200457
458 def __getitem__(self, index):
459 return self.option[index]
460
461
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500462class Array(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200463 type = "Array"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500464
Ole Troane5ff5a32019-08-23 22:55:18 +0200465 def __init__(self, fieldtype, name, length, modern_vla=False):
Ole Troan9d420872017-10-12 13:06:35 +0200466 self.fieldtype = fieldtype
467 self.fieldname = name
Ole Troane5ff5a32019-08-23 22:55:18 +0200468 self.modern_vla = modern_vla
Ole Troan9d420872017-10-12 13:06:35 +0200469 if type(length) is str:
470 self.lengthfield = length
471 self.length = 0
Ole Troane5ff5a32019-08-23 22:55:18 +0200472 self.vla = True
Ole Troan9d420872017-10-12 13:06:35 +0200473 else:
474 self.length = length
475 self.lengthfield = None
Ole Troane5ff5a32019-08-23 22:55:18 +0200476 self.vla = False
Ole Troan9d420872017-10-12 13:06:35 +0200477
478 def __repr__(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200479 return str([self.fieldtype, self.fieldname, self.length, self.lengthfield])
Ole Troan9d420872017-10-12 13:06:35 +0200480
481
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500482class Field(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200483 type = "Field"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500484
Ole Troan9ac11382019-04-23 17:11:01 +0200485 def __init__(self, fieldtype, name, limit=None):
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500486 # limit field has been expanded to an options dict.
487
Ole Troan9d420872017-10-12 13:06:35 +0200488 self.fieldtype = fieldtype
Ole Troandf87f802020-11-18 19:17:48 +0100489 self.is_lengthfield = False
Ole Troane5ff5a32019-08-23 22:55:18 +0200490
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200491 if self.fieldtype == "string":
492 raise ValueError("The string type {!r} is an " "array type ".format(name))
Ole Troane5ff5a32019-08-23 22:55:18 +0200493
Paul Vinciguerraff47fb62019-08-06 19:58:24 -0400494 if name in keyword.kwlist:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200495 raise ValueError(
496 "Fieldname {!r} is a python keyword and is not "
497 "accessible via the python API. ".format(name)
498 )
Ole Troan9d420872017-10-12 13:06:35 +0200499 self.fieldname = name
Ole Troan9ac11382019-04-23 17:11:01 +0200500 self.limit = limit
Ole Troan9d420872017-10-12 13:06:35 +0200501
502 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200503 return str([self.fieldtype, self.fieldname])
Ole Troan9d420872017-10-12 13:06:35 +0200504
505
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500506class Counter(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200507 type = "Counter"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500508
Ole Troan148c7b72020-10-07 18:05:37 +0200509 def __init__(self, path, counter):
Ole Troan148c7b72020-10-07 18:05:37 +0200510 self.name = path
511 self.block = counter
512
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500513 def process(self, result): # -> Dict
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200514 result["Counters"].append(self)
Ole Troan148c7b72020-10-07 18:05:37 +0200515
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500516
517class Paths(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200518 type = "Paths"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500519
Ole Troan148c7b72020-10-07 18:05:37 +0200520 def __init__(self, pathset):
Ole Troan148c7b72020-10-07 18:05:37 +0200521 self.paths = pathset
522
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500523 def __repr__(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200524 return "%s(paths=%s)" % (self.__class__.__name__, self.paths)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500525
Ole Troan148c7b72020-10-07 18:05:37 +0200526
Paul Vinciguerrab00c49c2020-12-04 15:01:53 -0500527class Coord:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200528 """Coordinates of a syntactic element. Consists of:
529 - File name
530 - Line number
531 - (optional) column number, for the Lexer
Ole Troan9d420872017-10-12 13:06:35 +0200532 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200533
534 __slots__ = ("file", "line", "column", "__weakref__")
Ole Troan9d420872017-10-12 13:06:35 +0200535
536 def __init__(self, file, line, column=None):
537 self.file = file
538 self.line = line
539 self.column = column
540
541 def __str__(self):
542 str = "%s:%s" % (self.file, self.line)
543 if self.column:
544 str += ":%s" % self.column
545 return str
546
547
548class ParseError(Exception):
549 pass
550
551
552#
553# Grammar rules
554#
Paul Vinciguerrab00c49c2020-12-04 15:01:53 -0500555class VPPAPIParser:
Ole Troan9d420872017-10-12 13:06:35 +0200556 tokens = VPPAPILexer.tokens
557
Ole Troan5c318c72020-05-05 12:23:47 +0200558 def __init__(self, filename, logger, revision=None):
Ole Troan9d420872017-10-12 13:06:35 +0200559 self.filename = filename
560 self.logger = logger
561 self.fields = []
Ole Troan5c318c72020-05-05 12:23:47 +0200562 self.revision = revision
Ole Troan9d420872017-10-12 13:06:35 +0200563
564 def _parse_error(self, msg, coord):
565 raise ParseError("%s: %s" % (coord, msg))
566
567 def _parse_warning(self, msg, coord):
568 if self.logger:
569 self.logger.warning("%s: %s" % (coord, msg))
570
571 def _coord(self, lineno, column=None):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200572 return Coord(file=self.filename, line=lineno, column=column)
Ole Troan9d420872017-10-12 13:06:35 +0200573
574 def _token_coord(self, p, token_idx):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200575 """Returns the coordinates for the YaccProduction object 'p' indexed
576 with 'token_idx'. The coordinate includes the 'lineno' and
577 'column'. Both follow the lex semantic, starting from 1.
Ole Troan9d420872017-10-12 13:06:35 +0200578 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200579 last_cr = p.lexer.lexdata.rfind("\n", 0, p.lexpos(token_idx))
Ole Troan9d420872017-10-12 13:06:35 +0200580 if last_cr < 0:
581 last_cr = -1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200582 column = p.lexpos(token_idx) - (last_cr)
Ole Troan9d420872017-10-12 13:06:35 +0200583 return self._coord(p.lineno(token_idx), column)
584
585 def p_slist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200586 """slist : stmt
587 | slist stmt"""
Ole Troan9d420872017-10-12 13:06:35 +0200588 if len(p) == 2:
589 p[0] = [p[1]]
590 else:
591 p[0] = p[1] + [p[2]]
592
593 def p_stmt(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200594 """stmt : define
595 | typedef
596 | option
597 | import
598 | enum
599 | enumflag
600 | union
601 | service
602 | paths
603 | counters"""
Ole Troan9d420872017-10-12 13:06:35 +0200604 p[0] = p[1]
605
606 def p_import(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200607 """import : IMPORT STRING_LITERAL ';'"""
Ole Troan5c318c72020-05-05 12:23:47 +0200608 p[0] = Import(p[2], revision=self.revision)
Ole Troan9d420872017-10-12 13:06:35 +0200609
Ole Troan148c7b72020-10-07 18:05:37 +0200610 def p_path_elements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200611 """path_elements : path_element
612 | path_elements path_element"""
Ole Troan148c7b72020-10-07 18:05:37 +0200613 if len(p) == 2:
614 p[0] = p[1]
615 else:
616 if type(p[1]) is dict:
617 p[0] = [p[1], p[2]]
618 else:
619 p[0] = p[1] + [p[2]]
620
621 def p_path_element(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200622 """path_element : STRING_LITERAL STRING_LITERAL ';'"""
623 p[0] = {"path": p[1], "counter": p[2]}
Ole Troan148c7b72020-10-07 18:05:37 +0200624
625 def p_paths(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200626 """paths : PATHS '{' path_elements '}' ';'"""
Ole Troan148c7b72020-10-07 18:05:37 +0200627 p[0] = Paths(p[3])
628
629 def p_counters(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200630 """counters : COUNTERS ID '{' counter_elements '}' ';'"""
Ole Troan148c7b72020-10-07 18:05:37 +0200631 p[0] = Counter(p[2], p[4])
632
633 def p_counter_elements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200634 """counter_elements : counter_element
635 | counter_elements counter_element"""
Ole Troan148c7b72020-10-07 18:05:37 +0200636 if len(p) == 2:
Ole Troan18327be2021-01-12 21:49:38 +0100637 p[0] = [p[1]]
Ole Troan148c7b72020-10-07 18:05:37 +0200638 else:
639 if type(p[1]) is dict:
640 p[0] = [p[1], p[2]]
641 else:
642 p[0] = p[1] + [p[2]]
643
644 def p_counter_element(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200645 """counter_element : ID '{' counter_statements '}' ';'"""
646 p[0] = {**{"name": p[1]}, **p[3]}
Ole Troan148c7b72020-10-07 18:05:37 +0200647
648 def p_counter_statements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200649 """counter_statements : counter_statement
650 | counter_statements counter_statement"""
Ole Troan148c7b72020-10-07 18:05:37 +0200651 if len(p) == 2:
652 p[0] = p[1]
653 else:
654 p[0] = {**p[1], **p[2]}
655
656 def p_counter_statement(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200657 """counter_statement : SEVERITY ID ';'
658 | UNITS STRING_LITERAL ';'
659 | DESCRIPTION STRING_LITERAL ';'
660 | TYPE ID ';'"""
Ole Troan148c7b72020-10-07 18:05:37 +0200661 p[0] = {p[1]: p[2]}
662
Ole Troan9d420872017-10-12 13:06:35 +0200663 def p_service(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200664 """service : SERVICE '{' service_statements '}' ';'"""
Ole Troan9d420872017-10-12 13:06:35 +0200665 p[0] = p[3]
666
667 def p_service_statements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200668 """service_statements : service_statement
669 | service_statements service_statement"""
Ole Troan9d420872017-10-12 13:06:35 +0200670 if len(p) == 2:
671 p[0] = [p[1]]
672 else:
673 p[0] = p[1] + [p[2]]
674
675 def p_service_statement(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200676 """service_statement : RPC ID RETURNS NULL ';'
677 | RPC ID RETURNS ID ';'
678 | RPC ID RETURNS STREAM ID ';'
679 | RPC ID RETURNS ID EVENTS event_list ';'"""
Marek Gradzkifc70e3a2018-03-06 10:56:26 +0100680 if p[2] == p[4]:
681 # Verify that caller and reply differ
Ole Troan17225df2018-04-11 09:50:03 +0200682 self._parse_error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200683 "Reply ID ({}) should not be equal to Caller ID".format(p[2]),
684 self._token_coord(p, 1),
685 )
Ole Troan9d420872017-10-12 13:06:35 +0200686 if len(p) == 8:
687 p[0] = Service(p[2], p[4], p[6])
688 elif len(p) == 7:
689 p[0] = Service(p[2], p[5], stream=True)
690 else:
691 p[0] = Service(p[2], p[4])
692
Ole Troanf5db3712020-05-20 15:47:06 +0200693 def p_service_statement2(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200694 """service_statement : RPC ID RETURNS ID STREAM ID ';'"""
Ole Troanf5db3712020-05-20 15:47:06 +0200695 p[0] = Service(p[2], p[4], stream_message=p[6], stream=True)
696
Ole Troan9d420872017-10-12 13:06:35 +0200697 def p_event_list(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200698 """event_list : events
699 | event_list events"""
Ole Troan9d420872017-10-12 13:06:35 +0200700 if len(p) == 2:
701 p[0] = [p[1]]
702 else:
703 p[0] = p[1] + [p[2]]
704
705 def p_event(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200706 """events : ID
707 | ID ','"""
Ole Troan9d420872017-10-12 13:06:35 +0200708 p[0] = p[1]
709
710 def p_enum(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200711 """enum : ENUM ID '{' enum_statements '}' ';'"""
Ole Troan9d420872017-10-12 13:06:35 +0200712 p[0] = Enum(p[2], p[4])
713
714 def p_enum_type(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200715 """enum : ENUM ID ':' enum_size '{' enum_statements '}' ';'"""
Ole Troan9d420872017-10-12 13:06:35 +0200716 if len(p) == 9:
717 p[0] = Enum(p[2], p[6], enumtype=p[4])
718 else:
719 p[0] = Enum(p[2], p[4])
720
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500721 def p_enumflag(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200722 """enumflag : ENUMFLAG ID '{' enum_statements '}' ';'"""
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500723 p[0] = EnumFlag(p[2], p[4])
724
725 def p_enumflag_type(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200726 """enumflag : ENUMFLAG ID ':' enumflag_size '{' enum_statements '}' ';'""" # noqa : E502
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500727 if len(p) == 9:
728 p[0] = EnumFlag(p[2], p[6], enumtype=p[4])
729 else:
730 p[0] = EnumFlag(p[2], p[4])
731
Ole Troan9d420872017-10-12 13:06:35 +0200732 def p_enum_size(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200733 """enum_size : U8
734 | U16
735 | U32
736 | I8
737 | I16
738 | I32"""
Paul Vinciguerra6d467b32020-12-13 04:12:55 +0000739 p[0] = p[1]
740
741 def p_enumflag_size(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200742 """enumflag_size : U8
743 | U16
744 | U32"""
Ole Troan9d420872017-10-12 13:06:35 +0200745 p[0] = p[1]
746
747 def p_define(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200748 """define : DEFINE ID '{' block_statements_opt '}' ';'"""
Ole Troan9d420872017-10-12 13:06:35 +0200749 self.fields = []
750 p[0] = Define(p[2], [], p[4])
751
752 def p_define_flist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200753 """define : flist DEFINE ID '{' block_statements_opt '}' ';'"""
Ole Troan2c2feab2018-04-24 00:02:37 -0400754 # Legacy typedef
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200755 if "typeonly" in p[1]:
756 self._parse_error(
757 "legacy typedef. use typedef: {} {}[{}];".format(p[1], p[2], p[4]),
758 self._token_coord(p, 1),
759 )
Ole Troan2c2feab2018-04-24 00:02:37 -0400760 else:
761 p[0] = Define(p[3], p[1], p[5])
Ole Troan9d420872017-10-12 13:06:35 +0200762
763 def p_flist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200764 """flist : flag
765 | flist flag"""
Ole Troan9d420872017-10-12 13:06:35 +0200766 if len(p) == 2:
767 p[0] = [p[1]]
768 else:
769 p[0] = p[1] + [p[2]]
770
771 def p_flag(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200772 """flag : MANUAL_PRINT
773 | MANUAL_ENDIAN
774 | DONT_TRACE
775 | TYPEONLY
776 | AUTOENDIAN
777 | AUTOREPLY"""
Ole Troan9d420872017-10-12 13:06:35 +0200778 if len(p) == 1:
779 return
780 p[0] = p[1]
781
782 def p_typedef(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200783 """typedef : TYPEDEF ID '{' block_statements_opt '}' ';'"""
Ole Troan9d420872017-10-12 13:06:35 +0200784 p[0] = Typedef(p[2], [], p[4])
785
Ole Troan33a58172019-09-04 09:12:29 +0200786 def p_typedef_flist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200787 """typedef : flist TYPEDEF ID '{' block_statements_opt '}' ';'"""
Ole Troan33a58172019-09-04 09:12:29 +0200788 p[0] = Typedef(p[3], p[1], p[5])
789
Ole Troan53fffa12018-11-13 12:36:56 +0100790 def p_typedef_alias(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200791 """typedef : TYPEDEF declaration"""
Ole Troan33a58172019-09-04 09:12:29 +0200792 p[0] = Using(p[2].fieldname, [], p[2])
793
794 def p_typedef_alias_flist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200795 """typedef : flist TYPEDEF declaration"""
Ole Troan33a58172019-09-04 09:12:29 +0200796 p[0] = Using(p[3].fieldname, p[1], p[3])
Ole Troan53fffa12018-11-13 12:36:56 +0100797
Ole Troan9d420872017-10-12 13:06:35 +0200798 def p_block_statements_opt(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200799 """block_statements_opt : block_statements"""
Ole Troan9d420872017-10-12 13:06:35 +0200800 p[0] = p[1]
801
802 def p_block_statements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200803 """block_statements : block_statement
804 | block_statements block_statement"""
Ole Troan9d420872017-10-12 13:06:35 +0200805 if len(p) == 2:
806 p[0] = [p[1]]
807 else:
808 p[0] = p[1] + [p[2]]
809
810 def p_block_statement(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200811 """block_statement : declaration
812 | option"""
Ole Troan9d420872017-10-12 13:06:35 +0200813 p[0] = p[1]
814
815 def p_enum_statements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200816 """enum_statements : enum_statement
817 | enum_statements enum_statement"""
Ole Troan9d420872017-10-12 13:06:35 +0200818 if len(p) == 2:
819 p[0] = [p[1]]
820 else:
821 p[0] = p[1] + [p[2]]
822
823 def p_enum_statement(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200824 """enum_statement : ID '=' NUM ','
825 | ID ','
826 | ID '[' field_options ']' ','
827 | ID '=' NUM '[' field_options ']' ','"""
Ole Troan6006ca82020-08-31 13:54:47 +0200828 if len(p) == 3:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200829 p[0] = {"id": p[1]}
Ole Troan6006ca82020-08-31 13:54:47 +0200830 elif len(p) == 5:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200831 p[0] = {"id": p[1], "value": p[3]}
Ole Troan6006ca82020-08-31 13:54:47 +0200832 elif len(p) == 6:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200833 p[0] = {"id": p[1], "option": p[3]}
Ole Troan6006ca82020-08-31 13:54:47 +0200834 elif len(p) == 8:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200835 p[0] = {"id": p[1], "value": p[3], "option": p[5]}
Ole Troan9d420872017-10-12 13:06:35 +0200836 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200837 self._parse_error("ERROR", self._token_coord(p, 1))
Ole Troan9d420872017-10-12 13:06:35 +0200838
Ole Troan85465582019-04-30 10:04:36 +0200839 def p_field_options(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200840 """field_options : field_option
841 | field_options field_option"""
Ole Troan85465582019-04-30 10:04:36 +0200842 if len(p) == 2:
843 p[0] = p[1]
844 else:
Ole Troane5ff5a32019-08-23 22:55:18 +0200845 p[0] = {**p[1], **p[2]}
Ole Troan85465582019-04-30 10:04:36 +0200846
847 def p_field_option(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200848 """field_option : ID
849 | ID '=' assignee ','
850 | ID '=' assignee
Ole Troane5ff5a32019-08-23 22:55:18 +0200851
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200852 """
Ole Troane5ff5a32019-08-23 22:55:18 +0200853 if len(p) == 2:
854 p[0] = {p[1]: None}
855 else:
856 p[0] = {p[1]: p[3]}
Ole Troan85465582019-04-30 10:04:36 +0200857
Ole Troan148c7b72020-10-07 18:05:37 +0200858 def p_variable_name(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200859 """variable_name : ID
860 | TYPE
861 | SEVERITY
862 | DESCRIPTION
863 | COUNTERS
864 | PATHS
865 """
Ole Troan148c7b72020-10-07 18:05:37 +0200866 p[0] = p[1]
867
Ole Troan9d420872017-10-12 13:06:35 +0200868 def p_declaration(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200869 """declaration : type_specifier variable_name ';'
870 | type_specifier variable_name '[' field_options ']' ';'
871 """
Ole Troan85465582019-04-30 10:04:36 +0200872 if len(p) == 7:
873 p[0] = Field(p[1], p[2], p[4])
Ole Troan9ac11382019-04-23 17:11:01 +0200874 elif len(p) == 4:
875 p[0] = Field(p[1], p[2])
876 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200877 self._parse_error("ERROR", self._token_coord(p, 1))
Ole Troan9d420872017-10-12 13:06:35 +0200878 self.fields.append(p[2])
Ole Troan9ac11382019-04-23 17:11:01 +0200879
Ole Troane5ff5a32019-08-23 22:55:18 +0200880 def p_declaration_array_vla(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200881 """declaration : type_specifier variable_name '[' ']' ';'"""
Ole Troane5ff5a32019-08-23 22:55:18 +0200882 p[0] = Array(p[1], p[2], 0, modern_vla=True)
883
Ole Troan9d420872017-10-12 13:06:35 +0200884 def p_declaration_array(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200885 """declaration : type_specifier variable_name '[' NUM ']' ';'
886 | type_specifier variable_name '[' ID ']' ';'"""
Ole Troane5ff5a32019-08-23 22:55:18 +0200887
Ole Troan9d420872017-10-12 13:06:35 +0200888 if len(p) != 7:
889 return self._parse_error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200890 "array: %s" % p.value, self._coord(lineno=p.lineno)
891 )
Ole Troan9d420872017-10-12 13:06:35 +0200892
893 # Make this error later
894 if type(p[4]) is int and p[4] == 0:
895 # XXX: Line number is wrong
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200896 self._parse_warning(
897 "Old Style VLA: {} {}[{}];".format(p[1], p[2], p[4]),
898 self._token_coord(p, 1),
899 )
Ole Troan9d420872017-10-12 13:06:35 +0200900
901 if type(p[4]) is str and p[4] not in self.fields:
902 # Verify that length field exists
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200903 self._parse_error(
904 "Missing length field: {} {}[{}];".format(p[1], p[2], p[4]),
905 self._token_coord(p, 1),
906 )
Ole Troan9d420872017-10-12 13:06:35 +0200907 p[0] = Array(p[1], p[2], p[4])
908
909 def p_option(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200910 """option : OPTION ID '=' assignee ';'
911 | OPTION ID ';'"""
Ole Troan68ebcd52020-08-10 17:06:44 +0200912 if len(p) == 4:
913 p[0] = Option(p[2])
914 else:
915 p[0] = Option(p[2], p[4])
Ole Troan9d420872017-10-12 13:06:35 +0200916
917 def p_assignee(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200918 """assignee : NUM
919 | TRUE
920 | FALSE
921 | STRING_LITERAL"""
Ole Troan9d420872017-10-12 13:06:35 +0200922 p[0] = p[1]
923
924 def p_type_specifier(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200925 """type_specifier : U8
926 | U16
927 | U32
928 | U64
929 | I8
930 | I16
931 | I32
932 | I64
933 | F64
934 | BOOL
935 | STRING"""
Ole Troan9d420872017-10-12 13:06:35 +0200936 p[0] = p[1]
937
938 # Do a second pass later to verify that user defined types are defined
939 def p_typedef_specifier(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200940 """type_specifier : ID"""
Ole Troan9d420872017-10-12 13:06:35 +0200941 if p[1] not in global_types:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200942 self._parse_error(
943 "Undefined type: {}".format(p[1]), self._token_coord(p, 1)
944 )
Ole Troan9d420872017-10-12 13:06:35 +0200945 p[0] = p[1]
946
Ole Troan2c2feab2018-04-24 00:02:37 -0400947 def p_union(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200948 """union : UNION ID '{' block_statements_opt '}' ';'"""
Ole Troan33a58172019-09-04 09:12:29 +0200949 p[0] = Union(p[2], [], p[4])
950
951 def p_union_flist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200952 """union : flist UNION ID '{' block_statements_opt '}' ';'"""
Ole Troan33a58172019-09-04 09:12:29 +0200953 p[0] = Union(p[3], p[1], p[5])
Ole Troan2c2feab2018-04-24 00:02:37 -0400954
Ole Troan9d420872017-10-12 13:06:35 +0200955 # Error rule for syntax errors
956 def p_error(self, p):
957 if p:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200958 self._parse_error("before: %s" % p.value, self._coord(lineno=p.lineno))
Ole Troan9d420872017-10-12 13:06:35 +0200959 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200960 self._parse_error("At end of input", self.filename)
Ole Troan9d420872017-10-12 13:06:35 +0200961
962
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200963class VPPAPI:
964 def __init__(self, debug=False, filename="", logger=None, revision=None):
Ole Troan9d420872017-10-12 13:06:35 +0200965 self.lexer = lex.lex(module=VPPAPILexer(filename), debug=debug)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200966 self.parser = yacc.yacc(
967 module=VPPAPIParser(filename, logger, revision=revision),
968 write_tables=False,
969 debug=debug,
970 )
Ole Troan9d420872017-10-12 13:06:35 +0200971 self.logger = logger
Ole Troan5c318c72020-05-05 12:23:47 +0200972 self.revision = revision
973 self.filename = filename
Ole Troan9d420872017-10-12 13:06:35 +0200974
975 def parse_string(self, code, debug=0, lineno=1):
976 self.lexer.lineno = lineno
977 return self.parser.parse(code, lexer=self.lexer, debug=debug)
978
Ole Troan5c318c72020-05-05 12:23:47 +0200979 def parse_fd(self, fd, debug=0):
Ole Troan9d420872017-10-12 13:06:35 +0200980 data = fd.read()
981 return self.parse_string(data, debug=debug)
982
Ole Troan5c318c72020-05-05 12:23:47 +0200983 def parse_filename(self, filename, debug=0):
984 if self.revision:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200985 git_show = "git show {}:{}".format(self.revision, filename)
986 proc = Popen(git_show.split(), stdout=PIPE, encoding="utf-8")
Ole Troandeecc932020-05-19 12:33:00 +0200987 try:
988 data, errs = proc.communicate()
989 if proc.returncode != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200990 print(
991 "File not found: {}:{}".format(self.revision, filename),
992 file=sys.stderr,
993 )
Ole Troandeecc932020-05-19 12:33:00 +0200994 sys.exit(2)
995 return self.parse_string(data, debug=debug)
Ole Troandf87f802020-11-18 19:17:48 +0100996 except Exception:
Ole Troandeecc932020-05-19 12:33:00 +0200997 sys.exit(3)
Ole Troan5c318c72020-05-05 12:23:47 +0200998 else:
999 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001000 with open(filename, encoding="utf-8") as fd:
Ole Troan5c318c72020-05-05 12:23:47 +02001001 return self.parse_fd(fd, None)
1002 except FileNotFoundError:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001003 print("File not found: {}".format(filename), file=sys.stderr)
Ole Troan5c318c72020-05-05 12:23:47 +02001004 sys.exit(2)
1005
Ole Troan9d420872017-10-12 13:06:35 +02001006 def process(self, objs):
1007 s = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001008 s["Option"] = {}
1009 s["Define"] = []
1010 s["Service"] = []
1011 s["types"] = []
1012 s["Import"] = []
1013 s["Counters"] = []
1014 s["Paths"] = []
Ole Troan8dbfb432019-04-24 14:31:18 +02001015 crc = 0
Ole Troan9d420872017-10-12 13:06:35 +02001016 for o in objs:
Ole Troan8dbfb432019-04-24 14:31:18 +02001017 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001018 crc = binascii.crc32(o.crc, crc) & 0xFFFFFFFF
Ole Troan8dbfb432019-04-24 14:31:18 +02001019 except AttributeError:
1020 pass
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05001021
1022 if type(o) is list:
Ole Troan9d420872017-10-12 13:06:35 +02001023 for o2 in o:
1024 if isinstance(o2, Service):
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05001025 o2.process(s)
Ole Troan2c2feab2018-04-24 00:02:37 -04001026 else:
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05001027 o.process(s)
Ole Troan9d420872017-10-12 13:06:35 +02001028
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001029 msgs = {d.name: d for d in s["Define"]}
1030 svcs = {s.caller: s for s in s["Service"]}
1031 replies = {s.reply: s for s in s["Service"]}
Marek Gradzki51e59682018-03-06 10:05:44 +01001032 seen_services = {}
Ole Troan9d420872017-10-12 13:06:35 +02001033
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001034 s["file_crc"] = crc
Ole Troan8dbfb432019-04-24 14:31:18 +02001035
Ole Troan9d420872017-10-12 13:06:35 +02001036 for service in svcs:
1037 if service not in msgs:
Ole Troan17225df2018-04-11 09:50:03 +02001038 raise ValueError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001039 "Service definition refers to unknown message"
1040 " definition: {}".format(service)
1041 )
1042 if svcs[service].reply != "null" and svcs[service].reply not in msgs:
1043 raise ValueError(
1044 "Service definition refers to unknown message"
1045 " definition in reply: {}".format(svcs[service].reply)
1046 )
Marek Gradzkib533f3f2018-03-06 11:10:56 +01001047 if service in replies:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001048 raise ValueError(
1049 "Service definition refers to message"
1050 " marked as reply: {}".format(service)
1051 )
Ole Troan9d420872017-10-12 13:06:35 +02001052 for event in svcs[service].events:
1053 if event not in msgs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001054 raise ValueError(
1055 "Service definition refers to unknown "
1056 "event: {} in message: {}".format(event, service)
1057 )
Marek Gradzki51e59682018-03-06 10:05:44 +01001058 seen_services[event] = True
Ole Troan9d420872017-10-12 13:06:35 +02001059
Marek Gradzki51e59682018-03-06 10:05:44 +01001060 # Create services implicitly
Ole Troan9d420872017-10-12 13:06:35 +02001061 for d in msgs:
Marek Gradzki51e59682018-03-06 10:05:44 +01001062 if d in seen_services:
1063 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001064 if d.endswith("_reply"):
Ole Troan9d420872017-10-12 13:06:35 +02001065 if d[:-6] in svcs:
1066 continue
1067 if d[:-6] not in msgs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001068 raise ValueError("{} missing calling message".format(d))
Ole Troan9d420872017-10-12 13:06:35 +02001069 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001070 if d.endswith("_dump"):
Ole Troan9d420872017-10-12 13:06:35 +02001071 if d in svcs:
1072 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001073 if d[:-5] + "_details" in msgs:
1074 s["Service"].append(Service(d, d[:-5] + "_details", stream=True))
Ole Troan9d420872017-10-12 13:06:35 +02001075 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001076 raise ValueError("{} missing details message".format(d))
Ole Troan9d420872017-10-12 13:06:35 +02001077 continue
1078
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001079 if d.endswith("_details"):
1080 if d[:-8] + "_get" in msgs:
1081 if d[:-8] + "_get" in svcs:
Jon Loeligerc0b19542020-05-11 08:43:51 -05001082 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001083 raise ValueError(
1084 "{} should be in a stream service".format(d[:-8] + "_get")
1085 )
1086 if d[:-8] + "_dump" in msgs:
Jon Loeligerc0b19542020-05-11 08:43:51 -05001087 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001088 raise ValueError("{} missing dump or get message".format(d))
Ole Troan9d420872017-10-12 13:06:35 +02001089
1090 if d in svcs:
1091 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001092 if d + "_reply" in msgs:
1093 s["Service"].append(Service(d, d + "_reply"))
Ole Troan9d420872017-10-12 13:06:35 +02001094 else:
Ole Troan17225df2018-04-11 09:50:03 +02001095 raise ValueError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001096 "{} missing reply message ({}) or service definition".format(
1097 d, d + "_reply"
1098 )
1099 )
Ole Troan9d420872017-10-12 13:06:35 +02001100
1101 return s
1102
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05001103 def process_imports(self, objs, in_import, result): # -> List
Ole Troan9d420872017-10-12 13:06:35 +02001104 for o in objs:
Ole Troan2c2feab2018-04-24 00:02:37 -04001105 # Only allow the following object types from imported file
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001106 if in_import and not isinstance(o, (Enum, Import, Typedef, Union, Using)):
Ole Troan2c2feab2018-04-24 00:02:37 -04001107 continue
Ole Troan2c2feab2018-04-24 00:02:37 -04001108 if isinstance(o, Import):
Ole Troan33a58172019-09-04 09:12:29 +02001109 result.append(o)
Paul Vinciguerra4bf84902019-07-31 00:34:05 -04001110 result = self.process_imports(o.result, True, result)
Ole Troan10a09892018-06-29 11:32:33 +02001111 else:
1112 result.append(o)
Paul Vinciguerra4bf84902019-07-31 00:34:05 -04001113 return result
Ole Troan9d420872017-10-12 13:06:35 +02001114
Ole Troan58914252018-10-23 10:50:07 +02001115
Ole Troan9d420872017-10-12 13:06:35 +02001116# Add message ids to each message.
1117def add_msg_id(s):
1118 for o in s:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001119 o.block.insert(0, Field("u16", "_vl_msg_id"))
Ole Troan9d420872017-10-12 13:06:35 +02001120 return s
1121
1122
Ole Troan9d420872017-10-12 13:06:35 +02001123dirlist = []
1124
1125
1126def dirlist_add(dirs):
1127 global dirlist
1128 if dirs:
1129 dirlist = dirlist + dirs
1130
1131
1132def dirlist_get():
1133 return dirlist
1134
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001135
Ole Troan8dbfb432019-04-24 14:31:18 +02001136def foldup_blocks(block, crc):
1137 for b in block:
1138 # Look up CRC in user defined types
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001139 if b.fieldtype.startswith("vl_api_"):
Ole Troan8dbfb432019-04-24 14:31:18 +02001140 # Recursively
1141 t = global_types[b.fieldtype]
1142 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001143 crc = binascii.crc32(t.crc, crc) & 0xFFFFFFFF
Ole Troan9f84e702020-06-25 14:27:46 +02001144 crc = foldup_blocks(t.block, crc)
Ole Troane5ff5a32019-08-23 22:55:18 +02001145 except AttributeError:
Ole Troan8dbfb432019-04-24 14:31:18 +02001146 pass
1147 return crc
1148
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001149
Ole Troan8dbfb432019-04-24 14:31:18 +02001150def foldup_crcs(s):
1151 for f in s:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001152 f.crc = foldup_blocks(f.block, binascii.crc32(f.crc) & 0xFFFFFFFF)
Ole Troan9d420872017-10-12 13:06:35 +02001153
Ole Troandf87f802020-11-18 19:17:48 +01001154
Ole Troan9d420872017-10-12 13:06:35 +02001155#
1156# Main
1157#
1158def main():
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001159 if sys.version_info < (
1160 3,
1161 5,
1162 ):
1163 log.exception(
1164 "vppapigen requires a supported version of python. "
1165 "Please use version 3.5 or greater. "
1166 "Using %s",
1167 sys.version,
1168 )
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001169 return 1
1170
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001171 cliparser = argparse.ArgumentParser(description="VPP API generator")
1172 cliparser.add_argument("--pluginpath", default="")
1173 cliparser.add_argument("--includedir", action="append")
1174 cliparser.add_argument("--outputdir", action="store")
1175 cliparser.add_argument("--input")
1176 cliparser.add_argument(
1177 "--output",
1178 nargs="?",
1179 type=argparse.FileType("w", encoding="UTF-8"),
1180 default=sys.stdout,
1181 )
Ole Troan9d420872017-10-12 13:06:35 +02001182
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001183 cliparser.add_argument("output_module", nargs="?", default="C")
1184 cliparser.add_argument("--debug", action="store_true")
1185 cliparser.add_argument("--show-name", nargs=1)
1186 cliparser.add_argument(
1187 "--git-revision", help="Git revision to use for opening files"
1188 )
Ole Troan9d420872017-10-12 13:06:35 +02001189 args = cliparser.parse_args()
1190
1191 dirlist_add(args.includedir)
1192 if not args.debug:
1193 sys.excepthook = exception_handler
1194
1195 # Filename
1196 if args.show_name:
1197 filename = args.show_name[0]
Ole Troan5c318c72020-05-05 12:23:47 +02001198 elif args.input:
1199 filename = args.input
Ole Troan9d420872017-10-12 13:06:35 +02001200 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001201 filename = ""
Ole Troan9d420872017-10-12 13:06:35 +02001202
Marek Gradzki51e59682018-03-06 10:05:44 +01001203 if args.debug:
1204 logging.basicConfig(stream=sys.stdout, level=logging.WARNING)
1205 else:
1206 logging.basicConfig()
Marek Gradzki51e59682018-03-06 10:05:44 +01001207
Ole Troan9d420872017-10-12 13:06:35 +02001208 #
1209 # Generate representation
1210 #
Paul Vinciguerraf4647ed2019-02-12 12:21:01 -08001211 from importlib.machinery import SourceFileLoader
Ole Troan9d420872017-10-12 13:06:35 +02001212
1213 # Default path
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001214 pluginpath = ""
Ole Troan9d420872017-10-12 13:06:35 +02001215 if not args.pluginpath:
Ole Troan30787372018-03-01 13:33:39 +01001216 cand = []
1217 cand.append(os.path.dirname(os.path.realpath(__file__)))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001218 cand.append(os.path.dirname(os.path.realpath(__file__)) + "/../share/vpp/")
Ole Troan30787372018-03-01 13:33:39 +01001219 for c in cand:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001220 c += "/"
1221 if os.path.isfile(
1222 "{}vppapigen_{}.py".format(c, args.output_module.lower())
1223 ):
Ole Troan30787372018-03-01 13:33:39 +01001224 pluginpath = c
1225 break
Ole Troan9d420872017-10-12 13:06:35 +02001226 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001227 pluginpath = args.pluginpath + "/"
1228 if pluginpath == "":
1229 log.exception("Output plugin not found")
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001230 return 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001231 module_path = "{}vppapigen_{}.py".format(pluginpath, args.output_module.lower())
Ole Troan9d420872017-10-12 13:06:35 +02001232
1233 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001234 plugin = SourceFileLoader(args.output_module, module_path).load_module()
Ole Troan58914252018-10-23 10:50:07 +02001235 except Exception as err:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001236 log.exception("Error importing output plugin: %s, %s", module_path, err)
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001237 return 1
Ole Troan9d420872017-10-12 13:06:35 +02001238
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001239 parser = VPPAPI(
1240 debug=args.debug, filename=filename, logger=log, revision=args.git_revision
1241 )
Paul Vinciguerra9046e442020-11-20 23:10:09 -05001242
1243 try:
1244 if not args.input:
1245 parsed_objects = parser.parse_fd(sys.stdin, log)
1246 else:
1247 parsed_objects = parser.parse_filename(args.input, log)
1248 except ParseError as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001249 print("Parse error: ", e, file=sys.stderr)
Paul Vinciguerra9046e442020-11-20 23:10:09 -05001250 sys.exit(1)
1251
1252 # Build a list of objects. Hash of lists.
1253 result = []
1254
1255 # if the variable is not set in the plugin, assume it to be false.
1256 try:
1257 plugin.process_imports
1258 except AttributeError:
1259 plugin.process_imports = False
1260
1261 if plugin.process_imports:
1262 result = parser.process_imports(parsed_objects, False, result)
1263 s = parser.process(result)
1264 else:
1265 s = parser.process(parsed_objects)
Ole Troandf87f802020-11-18 19:17:48 +01001266 imports = parser.process_imports(parsed_objects, False, result)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001267 s["imported"] = parser.process(imports)
Paul Vinciguerra9046e442020-11-20 23:10:09 -05001268
1269 # Add msg_id field
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001270 s["Define"] = add_msg_id(s["Define"])
Paul Vinciguerra9046e442020-11-20 23:10:09 -05001271
1272 # Fold up CRCs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001273 foldup_crcs(s["Define"])
Paul Vinciguerra9046e442020-11-20 23:10:09 -05001274
1275 #
1276 # Debug
1277 if args.debug:
1278 import pprint
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001279
Paul Vinciguerra9046e442020-11-20 23:10:09 -05001280 pp = pprint.PrettyPrinter(indent=4, stream=sys.stderr)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001281 for t in s["Define"]:
Paul Vinciguerra9046e442020-11-20 23:10:09 -05001282 pp.pprint([t.name, t.flags, t.block])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001283 for t in s["types"]:
Paul Vinciguerra9046e442020-11-20 23:10:09 -05001284 pp.pprint([t.name, t.block])
1285
Ole Troan2a1ca782019-09-19 01:08:30 +02001286 result = plugin.run(args, filename, s)
Ole Troan9d420872017-10-12 13:06:35 +02001287 if result:
Ole Troan17225df2018-04-11 09:50:03 +02001288 print(result, file=args.output)
Ole Troan9d420872017-10-12 13:06:35 +02001289 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001290 log.exception("Running plugin failed: %s %s", filename, result)
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001291 return 1
1292 return 0
Ole Troan9d420872017-10-12 13:06:35 +02001293
1294
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001295if __name__ == "__main__":
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001296 sys.exit(main())