blob: 2b0ce9999d742df6c8a524be102920f66cc1f558 [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
Ole Troan5d234682021-05-05 23:00:58 +020092 tokens = ["STRING_LITERAL", "COMMENT", "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)
Ole Troan5d234682021-05-05 23:00:58 +0200128 def t_COMMENT(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200129 r"(/\*(.|\n)*?\*/)|(//.*)"
130 t.lexer.lineno += t.value.count("\n")
Ole Troan5d234682021-05-05 23:00:58 +0200131 return t
Ole Troan9d420872017-10-12 13:06:35 +0200132
133 # Error handling rule
134 def t_error(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200135 raise ParseError(
136 "Illegal character '{}' ({})"
137 "in {}: line {}".format(
138 t.value[0], hex(ord(t.value[0])), self.filename, t.lexer.lineno
139 )
140 )
Ole Troan9d420872017-10-12 13:06:35 +0200141
142 # Define a rule so we can track line numbers
143 def t_newline(self, t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200144 r"\n+"
Ole Troan9d420872017-10-12 13:06:35 +0200145 t.lexer.lineno += len(t.value)
146
147 literals = ":{}[];=.,"
148
149 # A string containing ignored characters (spaces and tabs)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200150 t_ignore = " \t"
Ole Troan9d420872017-10-12 13:06:35 +0200151
Ole Troan17225df2018-04-11 09:50:03 +0200152
Ole Troandf87f802020-11-18 19:17:48 +0100153def vla_mark_length_field(block):
154 if isinstance(block[-1], Array):
155 lengthfield = block[-1].lengthfield
156 for b in block:
157 if b.fieldname == lengthfield:
158 b.is_lengthfield = True
159
160
Ole Troand5a78a52019-09-18 12:12:47 +0200161def vla_is_last_check(name, block):
162 vla = False
163 for i, b in enumerate(block):
164 if isinstance(b, Array) and b.vla:
165 vla = True
166 if i + 1 < len(block):
167 raise ValueError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200168 'VLA field "{}" must be the last field in message "{}"'.format(
169 b.fieldname, name
170 )
171 )
172 elif b.fieldtype.startswith("vl_api_"):
Ole Troand5a78a52019-09-18 12:12:47 +0200173 if global_types[b.fieldtype].vla:
174 vla = True
175 if i + 1 < len(block):
176 raise ValueError(
177 'VLA field "{}" must be the last '
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200178 'field in message "{}"'.format(b.fieldname, name)
179 )
180 elif b.fieldtype == "string" and b.length == 0:
Ole Troand5a78a52019-09-18 12:12:47 +0200181 vla = True
182 if i + 1 < len(block):
183 raise ValueError(
184 'VLA field "{}" must be the last '
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200185 'field in message "{}"'.format(b.fieldname, name)
186 )
Ole Troand5a78a52019-09-18 12:12:47 +0200187 return vla
188
189
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500190class Processable:
191 type = "<Invalid>"
192
193 def process(self, result): # -> Dict
194 result[self.type].append(self)
195
196
197class Service(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200198 type = "Service"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500199
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200200 def __init__(self, caller, reply, events=None, stream_message=None, stream=False):
Ole Troan9d420872017-10-12 13:06:35 +0200201 self.caller = caller
202 self.reply = reply
203 self.stream = stream
Ole Troanf5db3712020-05-20 15:47:06 +0200204 self.stream_message = stream_message
Paul Vinciguerra7e0c48e2019-02-01 19:37:45 -0800205 self.events = [] if events is None else events
Ole Troan9d420872017-10-12 13:06:35 +0200206
207
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500208class Typedef(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200209 type = "Typedef"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500210
Ole Troan9d420872017-10-12 13:06:35 +0200211 def __init__(self, name, flags, block):
212 self.name = name
213 self.flags = flags
214 self.block = block
Ole Troan8dbfb432019-04-24 14:31:18 +0200215 self.crc = str(block).encode()
Ole Troan2c2feab2018-04-24 00:02:37 -0400216 self.manual_print = False
217 self.manual_endian = False
218 for f in flags:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200219 if f == "manual_print":
Ole Troan2c2feab2018-04-24 00:02:37 -0400220 self.manual_print = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200221 elif f == "manual_endian":
Ole Troan2c2feab2018-04-24 00:02:37 -0400222 self.manual_endian = True
Ole Troan8dbfb432019-04-24 14:31:18 +0200223 global_type_add(name, self)
Ole Troan9d420872017-10-12 13:06:35 +0200224
Ole Troand5a78a52019-09-18 12:12:47 +0200225 self.vla = vla_is_last_check(name, block)
Ole Troandf87f802020-11-18 19:17:48 +0100226 vla_mark_length_field(self.block)
Ole Troane5ff5a32019-08-23 22:55:18 +0200227
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500228 def process(self, result):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200229 result["types"].append(self)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500230
Ole Troan9d420872017-10-12 13:06:35 +0200231 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200232 return self.name + str(self.flags) + str(self.block)
Ole Troan9d420872017-10-12 13:06:35 +0200233
234
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500235class Using(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200236 type = "Using"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500237
Ole Troan33a58172019-09-04 09:12:29 +0200238 def __init__(self, name, flags, alias):
Ole Troan53fffa12018-11-13 12:36:56 +0100239 self.name = name
Ole Troane5ff5a32019-08-23 22:55:18 +0200240 self.vla = False
Ole Troan75761b92019-09-11 17:49:08 +0200241 self.block = []
242 self.manual_print = True
243 self.manual_endian = True
Ole Troan53fffa12018-11-13 12:36:56 +0100244
Ole Troan33a58172019-09-04 09:12:29 +0200245 self.manual_print = False
246 self.manual_endian = False
247 for f in flags:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200248 if f == "manual_print":
Ole Troan33a58172019-09-04 09:12:29 +0200249 self.manual_print = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200250 elif f == "manual_endian":
Ole Troan33a58172019-09-04 09:12:29 +0200251 self.manual_endian = True
252
Ole Troan53fffa12018-11-13 12:36:56 +0100253 if isinstance(alias, Array):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200254 a = {"type": alias.fieldtype, "length": alias.length}
Ole Troan53fffa12018-11-13 12:36:56 +0100255 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200256 a = {"type": alias.fieldtype}
Ole Troan53fffa12018-11-13 12:36:56 +0100257 self.alias = a
Ole Troandf87f802020-11-18 19:17:48 +0100258 self.using = alias
259
Ole Troan6006ca82020-08-31 13:54:47 +0200260 #
261 # Should have been:
262 # self.crc = str(alias).encode()
263 # but to be backwards compatible use the block ([])
264 #
265 self.crc = str(self.block).encode()
Ole Troan8dbfb432019-04-24 14:31:18 +0200266 global_type_add(name, self)
Ole Troan53fffa12018-11-13 12:36:56 +0100267
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500268 def process(self, result): # -> Dict
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200269 result["types"].append(self)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500270
Ole Troan53fffa12018-11-13 12:36:56 +0100271 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200272 return self.name + str(self.alias)
Ole Troan53fffa12018-11-13 12:36:56 +0100273
274
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500275class Union(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200276 type = "Union"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500277
Ole Troan33a58172019-09-04 09:12:29 +0200278 def __init__(self, name, flags, block):
Ole Troan2c2feab2018-04-24 00:02:37 -0400279 self.manual_print = False
280 self.manual_endian = False
Ole Troan2c2feab2018-04-24 00:02:37 -0400281 self.name = name
Ole Troan33a58172019-09-04 09:12:29 +0200282
Ole Troan33a58172019-09-04 09:12:29 +0200283 for f in flags:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200284 if f == "manual_print":
Ole Troan33a58172019-09-04 09:12:29 +0200285 self.manual_print = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200286 elif f == "manual_endian":
Ole Troan33a58172019-09-04 09:12:29 +0200287 self.manual_endian = True
288
Ole Troan2c2feab2018-04-24 00:02:37 -0400289 self.block = block
Ole Troan8dbfb432019-04-24 14:31:18 +0200290 self.crc = str(block).encode()
Ole Troand5a78a52019-09-18 12:12:47 +0200291 self.vla = vla_is_last_check(name, block)
292
Ole Troan8dbfb432019-04-24 14:31:18 +0200293 global_type_add(name, self)
Ole Troan2c2feab2018-04-24 00:02:37 -0400294
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500295 def process(self, result):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200296 result["types"].append(self)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500297
Ole Troan2c2feab2018-04-24 00:02:37 -0400298 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200299 return str(self.block)
Ole Troan2c2feab2018-04-24 00:02:37 -0400300
301
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500302class Define(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200303 type = "Define"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500304
Ole Troan5d234682021-05-05 23:00:58 +0200305 def __init__(self, name, flags, block, comment=None):
Ole Troan9d420872017-10-12 13:06:35 +0200306 self.name = name
307 self.flags = flags
308 self.block = block
Ole Troan9d420872017-10-12 13:06:35 +0200309 self.dont_trace = False
310 self.manual_print = False
311 self.manual_endian = False
312 self.autoreply = False
Neale Ranns9302cfe2021-02-02 09:21:52 +0000313 self.autoendian = 0
Ole Troan2a1ca782019-09-19 01:08:30 +0200314 self.options = {}
Ole Troan5d234682021-05-05 23:00:58 +0200315 self.comment = comment
Ole Troan9d420872017-10-12 13:06:35 +0200316 for f in flags:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200317 if f == "dont_trace":
Ole Troan9d420872017-10-12 13:06:35 +0200318 self.dont_trace = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200319 elif f == "manual_print":
Ole Troan9d420872017-10-12 13:06:35 +0200320 self.manual_print = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200321 elif f == "manual_endian":
Ole Troan9d420872017-10-12 13:06:35 +0200322 self.manual_endian = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200323 elif f == "autoreply":
Ole Troan9d420872017-10-12 13:06:35 +0200324 self.autoreply = True
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200325 elif f == "autoendian":
Neale Ranns9302cfe2021-02-02 09:21:52 +0000326 self.autoendian = 1
Ole Troan9d420872017-10-12 13:06:35 +0200327
Ole Troan5c318c72020-05-05 12:23:47 +0200328 remove = []
Ole Troand5a78a52019-09-18 12:12:47 +0200329 for b in block:
Ole Troan9d420872017-10-12 13:06:35 +0200330 if isinstance(b, Option):
Ole Troan791c2062020-12-08 20:35:32 +0100331 self.options[b.option] = b.value
Ole Troan5c318c72020-05-05 12:23:47 +0200332 remove.append(b)
Ole Troan2a1ca782019-09-19 01:08:30 +0200333
Ole Troan14a6c0e2020-05-13 11:47:43 +0200334 block = [x for x in block if x not in remove]
Ole Troan5c318c72020-05-05 12:23:47 +0200335 self.block = block
Ole Troand5a78a52019-09-18 12:12:47 +0200336 self.vla = vla_is_last_check(name, block)
Ole Troandf87f802020-11-18 19:17:48 +0100337 vla_mark_length_field(self.block)
338
Ole Troan2a1ca782019-09-19 01:08:30 +0200339 self.crc = str(block).encode()
Ole Troane5ff5a32019-08-23 22:55:18 +0200340
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500341 def autoreply_block(self, name, parent):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200342 block = [Field("u32", "context"), Field("i32", "retval")]
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500343 # inherit the parent's options
344 for k, v in parent.options.items():
345 block.append(Option(k, v))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200346 return Define(name + "_reply", [], block)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500347
348 def process(self, result): # -> Dict
349 tname = self.__class__.__name__
350 result[tname].append(self)
351 if self.autoreply:
352 result[tname].append(self.autoreply_block(self.name, self))
353
Ole Troan9d420872017-10-12 13:06:35 +0200354 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200355 return self.name + str(self.flags) + str(self.block)
Ole Troan9d420872017-10-12 13:06:35 +0200356
357
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500358class Enum(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200359 type = "Enum"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500360
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200361 def __init__(self, name, block, enumtype="u32"):
Ole Troan9d420872017-10-12 13:06:35 +0200362 self.name = name
363 self.enumtype = enumtype
Ole Troane5ff5a32019-08-23 22:55:18 +0200364 self.vla = False
Ole Troandf87f802020-11-18 19:17:48 +0100365 self.manual_print = False
Ole Troan2c2feab2018-04-24 00:02:37 -0400366
Filip Varga9a8d3d72022-05-23 21:18:38 +0200367 count = -1
Ole Troan6006ca82020-08-31 13:54:47 +0200368 block2 = []
369 block3 = []
370 bc_set = False
371
372 for b in block:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200373 if "value" in b:
374 count = b["value"]
Ole Troan9d420872017-10-12 13:06:35 +0200375 else:
376 count += 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200377 block2.append([b["id"], count])
Ole Troan6006ca82020-08-31 13:54:47 +0200378 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200379 if b["option"]["backwards_compatible"]:
Ole Troan6006ca82020-08-31 13:54:47 +0200380 pass
381 bc_set = True
382 except KeyError:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200383 block3.append([b["id"], count])
Ole Troan6006ca82020-08-31 13:54:47 +0200384 if bc_set:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200385 raise ValueError(
386 "Backward compatible enum must "
387 "be last {!r} {!r}".format(name, b["id"])
388 )
Ole Troan6006ca82020-08-31 13:54:47 +0200389 self.block = block2
390 self.crc = str(block3).encode()
Ole Troan8dbfb432019-04-24 14:31:18 +0200391 global_type_add(name, self)
Ole Troan9d420872017-10-12 13:06:35 +0200392
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500393 def process(self, result):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200394 result["types"].append(self)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500395
Ole Troan9d420872017-10-12 13:06:35 +0200396 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200397 return self.name + str(self.block)
Ole Troan9d420872017-10-12 13:06:35 +0200398
399
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500400class EnumFlag(Enum):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200401 type = "EnumFlag"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500402
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200403 def __init__(self, name, block, enumtype="u32"):
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500404 super(EnumFlag, self).__init__(name, block, enumtype)
405
406 for b in self.block:
407 if bin(b[1])[2:].count("1") > 1:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200408 raise TypeError(
409 "%s is not a flag enum. No element in a "
410 "flag enum may have more than a "
411 "single bit set." % self.name
412 )
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500413
414
415class Import(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200416 type = "Import"
Ole Troandf87f802020-11-18 19:17:48 +0100417 _initialized = False
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500418
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400419 def __new__(cls, *args, **kwargs):
420 if args[0] not in seen_imports:
421 instance = super().__new__(cls)
422 instance._initialized = False
423 seen_imports[args[0]] = instance
424
425 return seen_imports[args[0]]
426
Ole Troan5c318c72020-05-05 12:23:47 +0200427 def __init__(self, filename, revision):
Paul Vinciguerra4bf84902019-07-31 00:34:05 -0400428 if self._initialized:
429 return
Ole Troandf87f802020-11-18 19:17:48 +0100430 self.filename = filename
431 # Deal with imports
432 parser = VPPAPI(filename=filename, revision=revision)
433 dirlist = dirlist_get()
434 f = filename
435 for dir in dirlist:
436 f = os.path.join(dir, filename)
437 if os.path.exists(f):
438 break
439 self.result = parser.parse_filename(f, None)
440 self._initialized = True
Ole Troan9d420872017-10-12 13:06:35 +0200441
442 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200443 return self.filename
Ole Troan9d420872017-10-12 13:06:35 +0200444
445
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500446class Option(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200447 type = "Option"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500448
Ole Troan68ebcd52020-08-10 17:06:44 +0200449 def __init__(self, option, value=None):
Ole Troan9d420872017-10-12 13:06:35 +0200450 self.option = option
Ole Troan33a58172019-09-04 09:12:29 +0200451 self.value = value
Ole Troan8dbfb432019-04-24 14:31:18 +0200452 self.crc = str(option).encode()
Ole Troan9d420872017-10-12 13:06:35 +0200453
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500454 def process(self, result): # -> Dict
455 result[self.type][self.option] = self.value
456
Ole Troan9d420872017-10-12 13:06:35 +0200457 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200458 return str(self.option)
Ole Troan9d420872017-10-12 13:06:35 +0200459
460 def __getitem__(self, index):
461 return self.option[index]
462
463
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500464class Array(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200465 type = "Array"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500466
Ole Troane5ff5a32019-08-23 22:55:18 +0200467 def __init__(self, fieldtype, name, length, modern_vla=False):
Ole Troan9d420872017-10-12 13:06:35 +0200468 self.fieldtype = fieldtype
469 self.fieldname = name
Ole Troane5ff5a32019-08-23 22:55:18 +0200470 self.modern_vla = modern_vla
Ole Troan9d420872017-10-12 13:06:35 +0200471 if type(length) is str:
472 self.lengthfield = length
473 self.length = 0
Ole Troane5ff5a32019-08-23 22:55:18 +0200474 self.vla = True
Ole Troan9d420872017-10-12 13:06:35 +0200475 else:
476 self.length = length
477 self.lengthfield = None
Ole Troane5ff5a32019-08-23 22:55:18 +0200478 self.vla = False
Ole Troan9d420872017-10-12 13:06:35 +0200479
480 def __repr__(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200481 return str([self.fieldtype, self.fieldname, self.length, self.lengthfield])
Ole Troan9d420872017-10-12 13:06:35 +0200482
483
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500484class Field(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200485 type = "Field"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500486
Ole Troan9ac11382019-04-23 17:11:01 +0200487 def __init__(self, fieldtype, name, limit=None):
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500488 # limit field has been expanded to an options dict.
489
Ole Troan9d420872017-10-12 13:06:35 +0200490 self.fieldtype = fieldtype
Ole Troandf87f802020-11-18 19:17:48 +0100491 self.is_lengthfield = False
Ole Troane5ff5a32019-08-23 22:55:18 +0200492
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200493 if self.fieldtype == "string":
494 raise ValueError("The string type {!r} is an " "array type ".format(name))
Ole Troane5ff5a32019-08-23 22:55:18 +0200495
Paul Vinciguerraff47fb62019-08-06 19:58:24 -0400496 if name in keyword.kwlist:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200497 raise ValueError(
498 "Fieldname {!r} is a python keyword and is not "
499 "accessible via the python API. ".format(name)
500 )
Ole Troan9d420872017-10-12 13:06:35 +0200501 self.fieldname = name
Ole Troan9ac11382019-04-23 17:11:01 +0200502 self.limit = limit
Ole Troan9d420872017-10-12 13:06:35 +0200503
504 def __repr__(self):
Vratko Polak7520e172019-08-01 10:31:49 +0200505 return str([self.fieldtype, self.fieldname])
Ole Troan9d420872017-10-12 13:06:35 +0200506
507
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500508class Counter(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200509 type = "Counter"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500510
Ole Troan148c7b72020-10-07 18:05:37 +0200511 def __init__(self, path, counter):
Ole Troan148c7b72020-10-07 18:05:37 +0200512 self.name = path
513 self.block = counter
514
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500515 def process(self, result): # -> Dict
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200516 result["Counters"].append(self)
Ole Troan148c7b72020-10-07 18:05:37 +0200517
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500518
519class Paths(Processable):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200520 type = "Paths"
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500521
Ole Troan148c7b72020-10-07 18:05:37 +0200522 def __init__(self, pathset):
Ole Troan148c7b72020-10-07 18:05:37 +0200523 self.paths = pathset
524
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500525 def __repr__(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200526 return "%s(paths=%s)" % (self.__class__.__name__, self.paths)
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500527
Ole Troan148c7b72020-10-07 18:05:37 +0200528
Paul Vinciguerrab00c49c2020-12-04 15:01:53 -0500529class Coord:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200530 """Coordinates of a syntactic element. Consists of:
531 - File name
532 - Line number
533 - (optional) column number, for the Lexer
Ole Troan9d420872017-10-12 13:06:35 +0200534 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200535
536 __slots__ = ("file", "line", "column", "__weakref__")
Ole Troan9d420872017-10-12 13:06:35 +0200537
538 def __init__(self, file, line, column=None):
539 self.file = file
540 self.line = line
541 self.column = column
542
543 def __str__(self):
544 str = "%s:%s" % (self.file, self.line)
545 if self.column:
546 str += ":%s" % self.column
547 return str
548
549
550class ParseError(Exception):
551 pass
552
553
554#
555# Grammar rules
556#
Paul Vinciguerrab00c49c2020-12-04 15:01:53 -0500557class VPPAPIParser:
Ole Troan9d420872017-10-12 13:06:35 +0200558 tokens = VPPAPILexer.tokens
559
Ole Troan5c318c72020-05-05 12:23:47 +0200560 def __init__(self, filename, logger, revision=None):
Ole Troan9d420872017-10-12 13:06:35 +0200561 self.filename = filename
562 self.logger = logger
563 self.fields = []
Ole Troan5c318c72020-05-05 12:23:47 +0200564 self.revision = revision
Ole Troan5d234682021-05-05 23:00:58 +0200565 self.last_comment = None
Ole Troan9d420872017-10-12 13:06:35 +0200566
567 def _parse_error(self, msg, coord):
568 raise ParseError("%s: %s" % (coord, msg))
569
570 def _parse_warning(self, msg, coord):
571 if self.logger:
572 self.logger.warning("%s: %s" % (coord, msg))
573
574 def _coord(self, lineno, column=None):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200575 return Coord(file=self.filename, line=lineno, column=column)
Ole Troan9d420872017-10-12 13:06:35 +0200576
577 def _token_coord(self, p, token_idx):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200578 """Returns the coordinates for the YaccProduction object 'p' indexed
579 with 'token_idx'. The coordinate includes the 'lineno' and
580 'column'. Both follow the lex semantic, starting from 1.
Ole Troan9d420872017-10-12 13:06:35 +0200581 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200582 last_cr = p.lexer.lexdata.rfind("\n", 0, p.lexpos(token_idx))
Ole Troan9d420872017-10-12 13:06:35 +0200583 if last_cr < 0:
584 last_cr = -1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200585 column = p.lexpos(token_idx) - (last_cr)
Ole Troan9d420872017-10-12 13:06:35 +0200586 return self._coord(p.lineno(token_idx), column)
587
588 def p_slist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200589 """slist : stmt
590 | slist stmt"""
Ole Troan9d420872017-10-12 13:06:35 +0200591 if len(p) == 2:
592 p[0] = [p[1]]
593 else:
594 p[0] = p[1] + [p[2]]
595
596 def p_stmt(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200597 """stmt : define
598 | typedef
599 | option
600 | import
601 | enum
602 | enumflag
603 | union
604 | service
605 | paths
Ole Troan5d234682021-05-05 23:00:58 +0200606 | comment
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200607 | counters"""
Ole Troan9d420872017-10-12 13:06:35 +0200608 p[0] = p[1]
609
610 def p_import(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200611 """import : IMPORT STRING_LITERAL ';'"""
Ole Troan5c318c72020-05-05 12:23:47 +0200612 p[0] = Import(p[2], revision=self.revision)
Ole Troan9d420872017-10-12 13:06:35 +0200613
Ole Troan148c7b72020-10-07 18:05:37 +0200614 def p_path_elements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200615 """path_elements : path_element
616 | path_elements path_element"""
Ole Troan148c7b72020-10-07 18:05:37 +0200617 if len(p) == 2:
618 p[0] = p[1]
619 else:
620 if type(p[1]) is dict:
621 p[0] = [p[1], p[2]]
622 else:
623 p[0] = p[1] + [p[2]]
624
625 def p_path_element(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200626 """path_element : STRING_LITERAL STRING_LITERAL ';'"""
627 p[0] = {"path": p[1], "counter": p[2]}
Ole Troan148c7b72020-10-07 18:05:37 +0200628
629 def p_paths(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200630 """paths : PATHS '{' path_elements '}' ';'"""
Ole Troan148c7b72020-10-07 18:05:37 +0200631 p[0] = Paths(p[3])
632
633 def p_counters(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200634 """counters : COUNTERS ID '{' counter_elements '}' ';'"""
Ole Troan148c7b72020-10-07 18:05:37 +0200635 p[0] = Counter(p[2], p[4])
636
637 def p_counter_elements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200638 """counter_elements : counter_element
639 | counter_elements counter_element"""
Ole Troan148c7b72020-10-07 18:05:37 +0200640 if len(p) == 2:
Ole Troan18327be2021-01-12 21:49:38 +0100641 p[0] = [p[1]]
Ole Troan148c7b72020-10-07 18:05:37 +0200642 else:
643 if type(p[1]) is dict:
644 p[0] = [p[1], p[2]]
645 else:
646 p[0] = p[1] + [p[2]]
647
648 def p_counter_element(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200649 """counter_element : ID '{' counter_statements '}' ';'"""
650 p[0] = {**{"name": p[1]}, **p[3]}
Ole Troan148c7b72020-10-07 18:05:37 +0200651
652 def p_counter_statements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200653 """counter_statements : counter_statement
654 | counter_statements counter_statement"""
Ole Troan148c7b72020-10-07 18:05:37 +0200655 if len(p) == 2:
656 p[0] = p[1]
657 else:
658 p[0] = {**p[1], **p[2]}
659
660 def p_counter_statement(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200661 """counter_statement : SEVERITY ID ';'
662 | UNITS STRING_LITERAL ';'
663 | DESCRIPTION STRING_LITERAL ';'
664 | TYPE ID ';'"""
Ole Troan148c7b72020-10-07 18:05:37 +0200665 p[0] = {p[1]: p[2]}
666
Ole Troan9d420872017-10-12 13:06:35 +0200667 def p_service(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200668 """service : SERVICE '{' service_statements '}' ';'"""
Ole Troan9d420872017-10-12 13:06:35 +0200669 p[0] = p[3]
670
671 def p_service_statements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200672 """service_statements : service_statement
673 | service_statements service_statement"""
Ole Troan9d420872017-10-12 13:06:35 +0200674 if len(p) == 2:
675 p[0] = [p[1]]
676 else:
677 p[0] = p[1] + [p[2]]
678
679 def p_service_statement(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200680 """service_statement : RPC ID RETURNS NULL ';'
681 | RPC ID RETURNS ID ';'
682 | RPC ID RETURNS STREAM ID ';'
683 | RPC ID RETURNS ID EVENTS event_list ';'"""
Marek Gradzkifc70e3a2018-03-06 10:56:26 +0100684 if p[2] == p[4]:
685 # Verify that caller and reply differ
Ole Troan17225df2018-04-11 09:50:03 +0200686 self._parse_error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200687 "Reply ID ({}) should not be equal to Caller ID".format(p[2]),
688 self._token_coord(p, 1),
689 )
Ole Troan9d420872017-10-12 13:06:35 +0200690 if len(p) == 8:
691 p[0] = Service(p[2], p[4], p[6])
692 elif len(p) == 7:
693 p[0] = Service(p[2], p[5], stream=True)
694 else:
695 p[0] = Service(p[2], p[4])
696
Ole Troanf5db3712020-05-20 15:47:06 +0200697 def p_service_statement2(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200698 """service_statement : RPC ID RETURNS ID STREAM ID ';'"""
Ole Troanf5db3712020-05-20 15:47:06 +0200699 p[0] = Service(p[2], p[4], stream_message=p[6], stream=True)
700
Ole Troan9d420872017-10-12 13:06:35 +0200701 def p_event_list(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200702 """event_list : events
703 | event_list events"""
Ole Troan9d420872017-10-12 13:06:35 +0200704 if len(p) == 2:
705 p[0] = [p[1]]
706 else:
707 p[0] = p[1] + [p[2]]
708
709 def p_event(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200710 """events : ID
711 | ID ','"""
Ole Troan9d420872017-10-12 13:06:35 +0200712 p[0] = p[1]
713
714 def p_enum(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200715 """enum : ENUM ID '{' enum_statements '}' ';'"""
Ole Troan9d420872017-10-12 13:06:35 +0200716 p[0] = Enum(p[2], p[4])
717
718 def p_enum_type(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200719 """enum : ENUM ID ':' enum_size '{' enum_statements '}' ';'"""
Ole Troan9d420872017-10-12 13:06:35 +0200720 if len(p) == 9:
721 p[0] = Enum(p[2], p[6], enumtype=p[4])
722 else:
723 p[0] = Enum(p[2], p[4])
724
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500725 def p_enumflag(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200726 """enumflag : ENUMFLAG ID '{' enum_statements '}' ';'"""
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500727 p[0] = EnumFlag(p[2], p[4])
728
729 def p_enumflag_type(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200730 """enumflag : ENUMFLAG ID ':' enumflag_size '{' enum_statements '}' ';'""" # noqa : E502
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -0500731 if len(p) == 9:
732 p[0] = EnumFlag(p[2], p[6], enumtype=p[4])
733 else:
734 p[0] = EnumFlag(p[2], p[4])
735
Ole Troan9d420872017-10-12 13:06:35 +0200736 def p_enum_size(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200737 """enum_size : U8
738 | U16
739 | U32
740 | I8
741 | I16
742 | I32"""
Paul Vinciguerra6d467b32020-12-13 04:12:55 +0000743 p[0] = p[1]
744
745 def p_enumflag_size(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200746 """enumflag_size : U8
747 | U16
748 | U32"""
Ole Troan9d420872017-10-12 13:06:35 +0200749 p[0] = p[1]
750
751 def p_define(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200752 """define : DEFINE ID '{' block_statements_opt '}' ';'"""
Ole Troan9d420872017-10-12 13:06:35 +0200753 self.fields = []
Ole Troan5d234682021-05-05 23:00:58 +0200754 p[0] = Define(p[2], [], p[4], self.last_comment)
Ondrej Fabrya4f994f2023-02-03 11:33:39 +0100755 self.last_comment = None
Ole Troan9d420872017-10-12 13:06:35 +0200756
757 def p_define_flist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200758 """define : flist DEFINE ID '{' block_statements_opt '}' ';'"""
Ole Troan2c2feab2018-04-24 00:02:37 -0400759 # Legacy typedef
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200760 if "typeonly" in p[1]:
761 self._parse_error(
762 "legacy typedef. use typedef: {} {}[{}];".format(p[1], p[2], p[4]),
763 self._token_coord(p, 1),
764 )
Ole Troan2c2feab2018-04-24 00:02:37 -0400765 else:
Ole Troan5d234682021-05-05 23:00:58 +0200766 p[0] = Define(p[3], p[1], p[5], self.last_comment)
Ondrej Fabrya4f994f2023-02-03 11:33:39 +0100767 self.last_comment = None
Ole Troan9d420872017-10-12 13:06:35 +0200768
769 def p_flist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200770 """flist : flag
771 | flist flag"""
Ole Troan9d420872017-10-12 13:06:35 +0200772 if len(p) == 2:
773 p[0] = [p[1]]
774 else:
775 p[0] = p[1] + [p[2]]
776
777 def p_flag(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200778 """flag : MANUAL_PRINT
779 | MANUAL_ENDIAN
780 | DONT_TRACE
781 | TYPEONLY
782 | AUTOENDIAN
783 | AUTOREPLY"""
Ole Troan9d420872017-10-12 13:06:35 +0200784 if len(p) == 1:
785 return
786 p[0] = p[1]
787
788 def p_typedef(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200789 """typedef : TYPEDEF ID '{' block_statements_opt '}' ';'"""
Ole Troan9d420872017-10-12 13:06:35 +0200790 p[0] = Typedef(p[2], [], p[4])
791
Ole Troan33a58172019-09-04 09:12:29 +0200792 def p_typedef_flist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200793 """typedef : flist TYPEDEF ID '{' block_statements_opt '}' ';'"""
Ole Troan33a58172019-09-04 09:12:29 +0200794 p[0] = Typedef(p[3], p[1], p[5])
795
Ole Troan53fffa12018-11-13 12:36:56 +0100796 def p_typedef_alias(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200797 """typedef : TYPEDEF declaration"""
Ole Troan33a58172019-09-04 09:12:29 +0200798 p[0] = Using(p[2].fieldname, [], p[2])
799
800 def p_typedef_alias_flist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200801 """typedef : flist TYPEDEF declaration"""
Ole Troan33a58172019-09-04 09:12:29 +0200802 p[0] = Using(p[3].fieldname, p[1], p[3])
Ole Troan53fffa12018-11-13 12:36:56 +0100803
Ole Troan9d420872017-10-12 13:06:35 +0200804 def p_block_statements_opt(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200805 """block_statements_opt : block_statements"""
Ole Troan9d420872017-10-12 13:06:35 +0200806 p[0] = p[1]
807
808 def p_block_statements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200809 """block_statements : block_statement
810 | block_statements block_statement"""
Ole Troan9d420872017-10-12 13:06:35 +0200811 if len(p) == 2:
812 p[0] = [p[1]]
813 else:
814 p[0] = p[1] + [p[2]]
815
816 def p_block_statement(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200817 """block_statement : declaration
818 | option"""
Ole Troan9d420872017-10-12 13:06:35 +0200819 p[0] = p[1]
820
821 def p_enum_statements(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200822 """enum_statements : enum_statement
823 | enum_statements enum_statement"""
Ole Troan9d420872017-10-12 13:06:35 +0200824 if len(p) == 2:
825 p[0] = [p[1]]
826 else:
827 p[0] = p[1] + [p[2]]
828
829 def p_enum_statement(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200830 """enum_statement : ID '=' NUM ','
831 | ID ','
832 | ID '[' field_options ']' ','
833 | ID '=' NUM '[' field_options ']' ','"""
Ole Troan6006ca82020-08-31 13:54:47 +0200834 if len(p) == 3:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200835 p[0] = {"id": p[1]}
Ole Troan6006ca82020-08-31 13:54:47 +0200836 elif len(p) == 5:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200837 p[0] = {"id": p[1], "value": p[3]}
Ole Troan6006ca82020-08-31 13:54:47 +0200838 elif len(p) == 6:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200839 p[0] = {"id": p[1], "option": p[3]}
Ole Troan6006ca82020-08-31 13:54:47 +0200840 elif len(p) == 8:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200841 p[0] = {"id": p[1], "value": p[3], "option": p[5]}
Ole Troan9d420872017-10-12 13:06:35 +0200842 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200843 self._parse_error("ERROR", self._token_coord(p, 1))
Ole Troan9d420872017-10-12 13:06:35 +0200844
Ole Troan85465582019-04-30 10:04:36 +0200845 def p_field_options(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200846 """field_options : field_option
847 | field_options field_option"""
Ole Troan85465582019-04-30 10:04:36 +0200848 if len(p) == 2:
849 p[0] = p[1]
850 else:
Ole Troane5ff5a32019-08-23 22:55:18 +0200851 p[0] = {**p[1], **p[2]}
Ole Troan85465582019-04-30 10:04:36 +0200852
853 def p_field_option(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200854 """field_option : ID
855 | ID '=' assignee ','
856 | ID '=' assignee
Ole Troane5ff5a32019-08-23 22:55:18 +0200857
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200858 """
Ole Troane5ff5a32019-08-23 22:55:18 +0200859 if len(p) == 2:
860 p[0] = {p[1]: None}
861 else:
862 p[0] = {p[1]: p[3]}
Ole Troan85465582019-04-30 10:04:36 +0200863
Ole Troan148c7b72020-10-07 18:05:37 +0200864 def p_variable_name(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200865 """variable_name : ID
866 | TYPE
867 | SEVERITY
868 | DESCRIPTION
869 | COUNTERS
870 | PATHS
871 """
Ole Troan148c7b72020-10-07 18:05:37 +0200872 p[0] = p[1]
873
Ole Troan5d234682021-05-05 23:00:58 +0200874 def p_comment(self, p):
875 """comment : COMMENT"""
876 self.last_comment = p[1]
877 p[0] = []
878
Ole Troan9d420872017-10-12 13:06:35 +0200879 def p_declaration(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200880 """declaration : type_specifier variable_name ';'
881 | type_specifier variable_name '[' field_options ']' ';'
882 """
Ole Troan85465582019-04-30 10:04:36 +0200883 if len(p) == 7:
884 p[0] = Field(p[1], p[2], p[4])
Ole Troan9ac11382019-04-23 17:11:01 +0200885 elif len(p) == 4:
886 p[0] = Field(p[1], p[2])
887 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200888 self._parse_error("ERROR", self._token_coord(p, 1))
Ole Troan9d420872017-10-12 13:06:35 +0200889 self.fields.append(p[2])
Ole Troan9ac11382019-04-23 17:11:01 +0200890
Ole Troane5ff5a32019-08-23 22:55:18 +0200891 def p_declaration_array_vla(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200892 """declaration : type_specifier variable_name '[' ']' ';'"""
Ole Troane5ff5a32019-08-23 22:55:18 +0200893 p[0] = Array(p[1], p[2], 0, modern_vla=True)
894
Ole Troan9d420872017-10-12 13:06:35 +0200895 def p_declaration_array(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200896 """declaration : type_specifier variable_name '[' NUM ']' ';'
897 | type_specifier variable_name '[' ID ']' ';'"""
Ole Troane5ff5a32019-08-23 22:55:18 +0200898
Ole Troan9d420872017-10-12 13:06:35 +0200899 if len(p) != 7:
900 return self._parse_error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200901 "array: %s" % p.value, self._coord(lineno=p.lineno)
902 )
Ole Troan9d420872017-10-12 13:06:35 +0200903
904 # Make this error later
905 if type(p[4]) is int and p[4] == 0:
906 # XXX: Line number is wrong
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200907 self._parse_warning(
908 "Old Style VLA: {} {}[{}];".format(p[1], p[2], p[4]),
909 self._token_coord(p, 1),
910 )
Ole Troan9d420872017-10-12 13:06:35 +0200911
912 if type(p[4]) is str and p[4] not in self.fields:
913 # Verify that length field exists
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200914 self._parse_error(
915 "Missing length field: {} {}[{}];".format(p[1], p[2], p[4]),
916 self._token_coord(p, 1),
917 )
Ole Troan9d420872017-10-12 13:06:35 +0200918 p[0] = Array(p[1], p[2], p[4])
919
920 def p_option(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200921 """option : OPTION ID '=' assignee ';'
922 | OPTION ID ';'"""
Ole Troan68ebcd52020-08-10 17:06:44 +0200923 if len(p) == 4:
924 p[0] = Option(p[2])
925 else:
926 p[0] = Option(p[2], p[4])
Ole Troan9d420872017-10-12 13:06:35 +0200927
928 def p_assignee(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200929 """assignee : NUM
930 | TRUE
931 | FALSE
932 | STRING_LITERAL"""
Ole Troan9d420872017-10-12 13:06:35 +0200933 p[0] = p[1]
934
935 def p_type_specifier(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200936 """type_specifier : U8
937 | U16
938 | U32
939 | U64
940 | I8
941 | I16
942 | I32
943 | I64
944 | F64
945 | BOOL
946 | STRING"""
Ole Troan9d420872017-10-12 13:06:35 +0200947 p[0] = p[1]
948
949 # Do a second pass later to verify that user defined types are defined
950 def p_typedef_specifier(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200951 """type_specifier : ID"""
Ole Troan9d420872017-10-12 13:06:35 +0200952 if p[1] not in global_types:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200953 self._parse_error(
954 "Undefined type: {}".format(p[1]), self._token_coord(p, 1)
955 )
Ole Troan9d420872017-10-12 13:06:35 +0200956 p[0] = p[1]
957
Ole Troan2c2feab2018-04-24 00:02:37 -0400958 def p_union(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200959 """union : UNION ID '{' block_statements_opt '}' ';'"""
Ole Troan33a58172019-09-04 09:12:29 +0200960 p[0] = Union(p[2], [], p[4])
961
962 def p_union_flist(self, p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200963 """union : flist UNION ID '{' block_statements_opt '}' ';'"""
Ole Troan33a58172019-09-04 09:12:29 +0200964 p[0] = Union(p[3], p[1], p[5])
Ole Troan2c2feab2018-04-24 00:02:37 -0400965
Ole Troan9d420872017-10-12 13:06:35 +0200966 # Error rule for syntax errors
967 def p_error(self, p):
968 if p:
Ole Troan5d234682021-05-05 23:00:58 +0200969 if p.type == "COMMENT":
970 self.parser.errok()
971 return
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200972 self._parse_error("before: %s" % p.value, self._coord(lineno=p.lineno))
Ole Troan9d420872017-10-12 13:06:35 +0200973 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200974 self._parse_error("At end of input", self.filename)
Ole Troan9d420872017-10-12 13:06:35 +0200975
Ole Troan5d234682021-05-05 23:00:58 +0200976 def build(self, **kwargs):
977 self.parser = yacc.yacc(module=self, **kwargs)
978
Ole Troan9d420872017-10-12 13:06:35 +0200979
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200980class VPPAPI:
981 def __init__(self, debug=False, filename="", logger=None, revision=None):
Ole Troan9d420872017-10-12 13:06:35 +0200982 self.lexer = lex.lex(module=VPPAPILexer(filename), debug=debug)
Ole Troan5d234682021-05-05 23:00:58 +0200983 self.parser = VPPAPIParser(filename, logger, revision=revision)
984 self.parser.build(write_tables=False, debug=debug)
Ole Troan9d420872017-10-12 13:06:35 +0200985 self.logger = logger
Ole Troan5c318c72020-05-05 12:23:47 +0200986 self.revision = revision
987 self.filename = filename
Ole Troan9d420872017-10-12 13:06:35 +0200988
989 def parse_string(self, code, debug=0, lineno=1):
990 self.lexer.lineno = lineno
Ole Troan5d234682021-05-05 23:00:58 +0200991 return self.parser.parser.parse(code, lexer=self.lexer, debug=debug)
Ole Troan9d420872017-10-12 13:06:35 +0200992
Ole Troan5c318c72020-05-05 12:23:47 +0200993 def parse_fd(self, fd, debug=0):
Ole Troan9d420872017-10-12 13:06:35 +0200994 data = fd.read()
995 return self.parse_string(data, debug=debug)
996
Ole Troan5c318c72020-05-05 12:23:47 +0200997 def parse_filename(self, filename, debug=0):
998 if self.revision:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200999 git_show = "git show {}:{}".format(self.revision, filename)
1000 proc = Popen(git_show.split(), stdout=PIPE, encoding="utf-8")
Ole Troandeecc932020-05-19 12:33:00 +02001001 try:
1002 data, errs = proc.communicate()
1003 if proc.returncode != 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001004 print(
1005 "File not found: {}:{}".format(self.revision, filename),
1006 file=sys.stderr,
1007 )
Ole Troandeecc932020-05-19 12:33:00 +02001008 sys.exit(2)
1009 return self.parse_string(data, debug=debug)
Ole Troandf87f802020-11-18 19:17:48 +01001010 except Exception:
Ole Troandeecc932020-05-19 12:33:00 +02001011 sys.exit(3)
Ole Troan5c318c72020-05-05 12:23:47 +02001012 else:
1013 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001014 with open(filename, encoding="utf-8") as fd:
Ole Troan5c318c72020-05-05 12:23:47 +02001015 return self.parse_fd(fd, None)
1016 except FileNotFoundError:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001017 print("File not found: {}".format(filename), file=sys.stderr)
Ole Troan5c318c72020-05-05 12:23:47 +02001018 sys.exit(2)
1019
Ole Troan9d420872017-10-12 13:06:35 +02001020 def process(self, objs):
1021 s = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001022 s["Option"] = {}
1023 s["Define"] = []
1024 s["Service"] = []
1025 s["types"] = []
1026 s["Import"] = []
1027 s["Counters"] = []
1028 s["Paths"] = []
Ole Troan8dbfb432019-04-24 14:31:18 +02001029 crc = 0
Ole Troan9d420872017-10-12 13:06:35 +02001030 for o in objs:
Ole Troan8dbfb432019-04-24 14:31:18 +02001031 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001032 crc = binascii.crc32(o.crc, crc) & 0xFFFFFFFF
Ole Troan8dbfb432019-04-24 14:31:18 +02001033 except AttributeError:
1034 pass
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05001035
1036 if type(o) is list:
Ole Troan9d420872017-10-12 13:06:35 +02001037 for o2 in o:
1038 if isinstance(o2, Service):
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05001039 o2.process(s)
Ole Troan2c2feab2018-04-24 00:02:37 -04001040 else:
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05001041 o.process(s)
Ole Troan9d420872017-10-12 13:06:35 +02001042
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001043 msgs = {d.name: d for d in s["Define"]}
1044 svcs = {s.caller: s for s in s["Service"]}
1045 replies = {s.reply: s for s in s["Service"]}
Marek Gradzki51e59682018-03-06 10:05:44 +01001046 seen_services = {}
Ole Troan9d420872017-10-12 13:06:35 +02001047
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001048 s["file_crc"] = crc
Ole Troan8dbfb432019-04-24 14:31:18 +02001049
Ole Troan9d420872017-10-12 13:06:35 +02001050 for service in svcs:
1051 if service not in msgs:
Ole Troan17225df2018-04-11 09:50:03 +02001052 raise ValueError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001053 "Service definition refers to unknown message"
1054 " definition: {}".format(service)
1055 )
1056 if svcs[service].reply != "null" and svcs[service].reply not in msgs:
1057 raise ValueError(
1058 "Service definition refers to unknown message"
1059 " definition in reply: {}".format(svcs[service].reply)
1060 )
Marek Gradzkib533f3f2018-03-06 11:10:56 +01001061 if service in replies:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001062 raise ValueError(
1063 "Service definition refers to message"
1064 " marked as reply: {}".format(service)
1065 )
Ole Troan9d420872017-10-12 13:06:35 +02001066 for event in svcs[service].events:
1067 if event not in msgs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001068 raise ValueError(
1069 "Service definition refers to unknown "
1070 "event: {} in message: {}".format(event, service)
1071 )
Marek Gradzki51e59682018-03-06 10:05:44 +01001072 seen_services[event] = True
Ole Troan9d420872017-10-12 13:06:35 +02001073
Marek Gradzki51e59682018-03-06 10:05:44 +01001074 # Create services implicitly
Ole Troan9d420872017-10-12 13:06:35 +02001075 for d in msgs:
Marek Gradzki51e59682018-03-06 10:05:44 +01001076 if d in seen_services:
1077 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001078 if d.endswith("_reply"):
Ole Troan9d420872017-10-12 13:06:35 +02001079 if d[:-6] in svcs:
1080 continue
1081 if d[:-6] not in msgs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001082 raise ValueError("{} missing calling message".format(d))
Ole Troan9d420872017-10-12 13:06:35 +02001083 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001084 if d.endswith("_dump"):
Ole Troan9d420872017-10-12 13:06:35 +02001085 if d in svcs:
1086 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001087 if d[:-5] + "_details" in msgs:
1088 s["Service"].append(Service(d, d[:-5] + "_details", stream=True))
Ole Troan9d420872017-10-12 13:06:35 +02001089 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001090 raise ValueError("{} missing details message".format(d))
Ole Troan9d420872017-10-12 13:06:35 +02001091 continue
1092
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001093 if d.endswith("_details"):
1094 if d[:-8] + "_get" in msgs:
1095 if d[:-8] + "_get" in svcs:
Jon Loeligerc0b19542020-05-11 08:43:51 -05001096 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001097 raise ValueError(
1098 "{} should be in a stream service".format(d[:-8] + "_get")
1099 )
1100 if d[:-8] + "_dump" in msgs:
Jon Loeligerc0b19542020-05-11 08:43:51 -05001101 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001102 raise ValueError("{} missing dump or get message".format(d))
Ole Troan9d420872017-10-12 13:06:35 +02001103
1104 if d in svcs:
1105 continue
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001106 if d + "_reply" in msgs:
1107 s["Service"].append(Service(d, d + "_reply"))
Ole Troan9d420872017-10-12 13:06:35 +02001108 else:
Ole Troan17225df2018-04-11 09:50:03 +02001109 raise ValueError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001110 "{} missing reply message ({}) or service definition".format(
1111 d, d + "_reply"
1112 )
1113 )
Ole Troan9d420872017-10-12 13:06:35 +02001114
1115 return s
1116
Paul Vinciguerraa51f9b32020-11-24 23:26:06 -05001117 def process_imports(self, objs, in_import, result): # -> List
Ole Troan9d420872017-10-12 13:06:35 +02001118 for o in objs:
Ole Troan2c2feab2018-04-24 00:02:37 -04001119 # Only allow the following object types from imported file
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001120 if in_import and not isinstance(o, (Enum, Import, Typedef, Union, Using)):
Ole Troan2c2feab2018-04-24 00:02:37 -04001121 continue
Ole Troan2c2feab2018-04-24 00:02:37 -04001122 if isinstance(o, Import):
Ole Troan33a58172019-09-04 09:12:29 +02001123 result.append(o)
Paul Vinciguerra4bf84902019-07-31 00:34:05 -04001124 result = self.process_imports(o.result, True, result)
Ole Troan10a09892018-06-29 11:32:33 +02001125 else:
1126 result.append(o)
Paul Vinciguerra4bf84902019-07-31 00:34:05 -04001127 return result
Ole Troan9d420872017-10-12 13:06:35 +02001128
Ole Troan58914252018-10-23 10:50:07 +02001129
Ole Troan9d420872017-10-12 13:06:35 +02001130# Add message ids to each message.
1131def add_msg_id(s):
1132 for o in s:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001133 o.block.insert(0, Field("u16", "_vl_msg_id"))
Ole Troan9d420872017-10-12 13:06:35 +02001134 return s
1135
1136
Ole Troan9d420872017-10-12 13:06:35 +02001137dirlist = []
1138
1139
1140def dirlist_add(dirs):
1141 global dirlist
1142 if dirs:
1143 dirlist = dirlist + dirs
1144
1145
1146def dirlist_get():
1147 return dirlist
1148
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001149
Ole Troan8dbfb432019-04-24 14:31:18 +02001150def foldup_blocks(block, crc):
1151 for b in block:
1152 # Look up CRC in user defined types
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001153 if b.fieldtype.startswith("vl_api_"):
Ole Troan8dbfb432019-04-24 14:31:18 +02001154 # Recursively
1155 t = global_types[b.fieldtype]
1156 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001157 crc = binascii.crc32(t.crc, crc) & 0xFFFFFFFF
Ole Troan9f84e702020-06-25 14:27:46 +02001158 crc = foldup_blocks(t.block, crc)
Ole Troane5ff5a32019-08-23 22:55:18 +02001159 except AttributeError:
Ole Troan8dbfb432019-04-24 14:31:18 +02001160 pass
1161 return crc
1162
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001163
Ole Troan8dbfb432019-04-24 14:31:18 +02001164def foldup_crcs(s):
1165 for f in s:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001166 f.crc = foldup_blocks(f.block, binascii.crc32(f.crc) & 0xFFFFFFFF)
Ole Troan9d420872017-10-12 13:06:35 +02001167
Ole Troandf87f802020-11-18 19:17:48 +01001168
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02001169def run_vppapigen(
1170 input_file=None,
1171 output=sys.stdout,
1172 includedir=None,
1173 debug=False,
1174 show_name=None,
1175 output_module="C",
1176 outputdir=None,
1177 pluginpath="",
1178 git_revision=None,
1179):
1180 # reset globals
1181 dirlist.clear()
1182 global_types.clear()
1183 seen_imports.clear()
1184
1185 dirlist_add(includedir)
1186 if not debug:
1187 sys.excepthook = exception_handler
1188
1189 # Filename
1190 if show_name:
1191 filename = show_name[0]
1192 elif input_file:
1193 filename = input_file
1194 else:
1195 filename = ""
1196
1197 if debug:
1198 logging.basicConfig(stream=sys.stdout, level=logging.WARNING)
1199 else:
1200 logging.basicConfig()
1201
1202 #
1203 # Generate representation
1204 #
1205 from importlib.machinery import SourceFileLoader
1206
1207 # Default path
1208 pluginpath = ""
1209 if not pluginpath:
1210 cand = []
1211 cand.append(os.path.dirname(os.path.realpath(__file__)))
1212 cand.append(os.path.dirname(os.path.realpath(__file__)) + "/../share/vpp/")
1213 for c in cand:
1214 c += "/"
1215 if os.path.isfile("{}vppapigen_{}.py".format(c, output_module.lower())):
1216 pluginpath = c
1217 break
1218 else:
1219 pluginpath = pluginpath + "/"
1220 if pluginpath == "":
1221 log.exception("Output plugin not found")
1222 return 1
1223 module_path = "{}vppapigen_{}.py".format(pluginpath, output_module.lower())
1224
1225 try:
1226 plugin = SourceFileLoader(output_module, module_path).load_module()
1227 except Exception as err:
1228 log.exception("Error importing output plugin: %s, %s", module_path, err)
1229 return 1
1230
1231 parser = VPPAPI(debug=debug, filename=filename, logger=log, revision=git_revision)
1232
1233 try:
1234 if not input_file:
1235 parsed_objects = parser.parse_fd(sys.stdin, log)
1236 else:
1237 parsed_objects = parser.parse_filename(input_file, log)
1238 except ParseError as e:
1239 print("Parse error: ", e, file=sys.stderr)
1240 sys.exit(1)
1241
1242 # Build a list of objects. Hash of lists.
1243 result = []
1244
1245 # if the variable is not set in the plugin, assume it to be false.
1246 try:
1247 plugin.process_imports
1248 except AttributeError:
1249 plugin.process_imports = False
1250
1251 if plugin.process_imports:
1252 result = parser.process_imports(parsed_objects, False, result)
1253 s = parser.process(result)
1254 else:
1255 s = parser.process(parsed_objects)
1256 imports = parser.process_imports(parsed_objects, False, result)
1257 s["imported"] = parser.process(imports)
1258
1259 # Add msg_id field
1260 s["Define"] = add_msg_id(s["Define"])
1261
1262 # Fold up CRCs
1263 foldup_crcs(s["Define"])
1264
1265 #
1266 # Debug
1267 if debug:
1268 import pprint
1269
1270 pp = pprint.PrettyPrinter(indent=4, stream=sys.stderr)
1271 for t in s["Define"]:
1272 pp.pprint([t.name, t.flags, t.block])
1273 for t in s["types"]:
1274 pp.pprint([t.name, t.block])
1275
1276 result = plugin.run(outputdir, filename, s)
1277 if result:
1278 if isinstance(output, str):
1279 with open(output, "w", encoding="UTF-8") as f:
1280 print(result, file=f)
1281 else:
1282 print(result, file=output)
1283 else:
1284 log.exception("Running plugin failed: %s %s", filename, result)
1285 return 1
1286 return 0
1287
1288
1289def run_kw_vppapigen(kwargs):
1290 return run_vppapigen(**kwargs)
1291
1292
Ole Troan9d420872017-10-12 13:06:35 +02001293#
1294# Main
1295#
1296def main():
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001297 if sys.version_info < (
1298 3,
1299 5,
1300 ):
1301 log.exception(
1302 "vppapigen requires a supported version of python. "
1303 "Please use version 3.5 or greater. "
1304 "Using %s",
1305 sys.version,
1306 )
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001307 return 1
1308
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001309 cliparser = argparse.ArgumentParser(description="VPP API generator")
1310 cliparser.add_argument("--pluginpath", default="")
1311 cliparser.add_argument("--includedir", action="append")
1312 cliparser.add_argument("--outputdir", action="store")
1313 cliparser.add_argument("--input")
1314 cliparser.add_argument(
1315 "--output",
1316 nargs="?",
1317 type=argparse.FileType("w", encoding="UTF-8"),
1318 default=sys.stdout,
1319 )
Ole Troan9d420872017-10-12 13:06:35 +02001320
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001321 cliparser.add_argument("output_module", nargs="?", default="C")
1322 cliparser.add_argument("--debug", action="store_true")
1323 cliparser.add_argument("--show-name", nargs=1)
1324 cliparser.add_argument(
1325 "--git-revision", help="Git revision to use for opening files"
1326 )
Ole Troan9d420872017-10-12 13:06:35 +02001327 args = cliparser.parse_args()
1328
Nathan Skrzypczak1b299fa2022-06-16 17:00:02 +02001329 return run_vppapigen(
1330 includedir=args.includedir,
1331 debug=args.debug,
1332 outputdir=args.outputdir,
1333 show_name=args.show_name,
1334 input_file=args.input,
1335 output_module=args.output_module,
1336 pluginpath=args.pluginpath,
1337 git_revision=args.git_revision,
1338 output=args.output,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001339 )
Paul Vinciguerra9046e442020-11-20 23:10:09 -05001340
Ole Troan9d420872017-10-12 13:06:35 +02001341
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001342if __name__ == "__main__":
Paul Vinciguerra2cd3cc82019-08-06 22:02:45 -04001343 sys.exit(main())