vcl: allow more rx events on peek
[vpp.git] / src / vpp-api / vapi / vapi_cpp_gen.py
1 #!/usr/bin/env python3
2
3 import argparse
4 import os
5 import sys
6 import logging
7 from vapi_c_gen import (
8     CField,
9     CEnum,
10     CStruct,
11     CSimpleType,
12     CStructType,
13     CMessage,
14     json_to_c_header_name,
15     CAlias,
16 )
17 from vapi_json_parser import JsonParser
18
19
20 class CppField(CField):
21     pass
22
23
24 class CppStruct(CStruct):
25     pass
26
27
28 class CppEnum(CEnum):
29     pass
30
31
32 class CppAlias(CAlias):
33     pass
34
35
36 class CppSimpleType(CSimpleType):
37     pass
38
39
40 class CppStructType(CStructType, CppStruct):
41     pass
42
43
44 class CppMessage(CMessage):
45     def get_swap_to_be_template_instantiation(self):
46         return "\n".join(
47             [
48                 "template <> inline void vapi_swap_to_be<%s>(%s *msg)"
49                 % (self.get_c_name(), self.get_c_name()),
50                 "{",
51                 "  %s(msg);" % self.get_swap_to_be_func_name(),
52                 "}",
53             ]
54         )
55
56     def get_swap_to_host_template_instantiation(self):
57         return "\n".join(
58             [
59                 "template <> inline void vapi_swap_to_host<%s>(%s *msg)"
60                 % (self.get_c_name(), self.get_c_name()),
61                 "{",
62                 "  %s(msg);" % self.get_swap_to_host_func_name(),
63                 "}",
64             ]
65         )
66
67     def get_alloc_template_instantiation(self):
68         return "\n".join(
69             [
70                 "template <> inline %s* vapi_alloc<%s%s>"
71                 "(Connection &con%s)"
72                 % (
73                     self.get_c_name(),
74                     self.get_c_name(),
75                     ", size_t" * len(self.get_alloc_vla_param_names()),
76                     "".join(
77                         [", size_t %s" % n for n in self.get_alloc_vla_param_names()]
78                     ),
79                 ),
80                 "{",
81                 "  %s* result = %s(con.vapi_ctx%s);"
82                 % (
83                     self.get_c_name(),
84                     self.get_alloc_func_name(),
85                     "".join([", %s" % n for n in self.get_alloc_vla_param_names()]),
86                 ),
87                 "#if VAPI_CPP_DEBUG_LEAKS",
88                 "  con.on_shm_data_alloc(result);",
89                 "#endif",
90                 "  return result;",
91                 "}",
92             ]
93         )
94
95     def get_cpp_name(self):
96         return "%s%s" % (self.name[0].upper(), self.name[1:])
97
98     def get_req_template_name(self):
99         if self.has_stream_msg:
100             return "Stream<%s, %s, %s>" % (
101                 self.get_c_name(),
102                 self.reply.get_c_name(),
103                 self.stream_msg.get_c_name(),
104             )
105
106         if self.reply_is_stream:
107             template = "Dump"
108         else:
109             template = "Request"
110
111         return "%s<%s, %s%s>" % (
112             template,
113             self.get_c_name(),
114             self.reply.get_c_name(),
115             "".join([", size_t"] * len(self.get_alloc_vla_param_names())),
116         )
117
118     def get_req_template_instantiation(self):
119         return "template class %s;" % self.get_req_template_name()
120
121     def get_type_alias(self):
122         return "using %s = %s;" % (self.get_cpp_name(), self.get_req_template_name())
123
124     def get_reply_template_name(self):
125         return "Msg<%s>" % (self.get_c_name())
126
127     def get_reply_type_alias(self):
128         return "using %s = %s;" % (self.get_cpp_name(), self.get_reply_template_name())
129
130     def get_msg_class_instantiation(self):
131         return "template class Msg<%s>;" % self.get_c_name()
132
133     def get_get_msg_id_t_instantiation(self):
134         return "\n".join(
135             [
136                 (
137                     "template <> inline vapi_msg_id_t vapi_get_msg_id_t<%s>()"
138                     % self.get_c_name()
139                 ),
140                 "{",
141                 "  return ::%s; " % self.get_msg_id_name(),
142                 "}",
143                 "",
144                 (
145                     "template <> inline vapi_msg_id_t "
146                     "vapi_get_msg_id_t<Msg<%s>>()" % self.get_c_name()
147                 ),
148                 "{",
149                 "  return ::%s; " % self.get_msg_id_name(),
150                 "}",
151             ]
152         )
153
154     def get_cpp_constructor(self):
155         return "\n".join(
156             [
157                 (
158                     "static void __attribute__((constructor)) "
159                     "__vapi_cpp_constructor_%s()" % self.name
160                 ),
161                 "{",
162                 (
163                     "  vapi::vapi_msg_set_msg_id<%s>(%s);"
164                     % (self.get_c_name(), self.get_msg_id_name())
165                 ),
166                 "}",
167             ]
168         )
169
170
171 def gen_json_header(parser, logger, j, io, gen_h_prefix, add_debug_comments):
172     logger.info("Generating header `%s'" % io.name)
173     orig_stdout = sys.stdout
174     sys.stdout = io
175     d, f = os.path.split(j)
176     include_guard = "__included_hpp_%s" % (
177         f.replace(".", "_").replace("/", "_").replace("-", "_").replace("@", "_")
178     )
179     print("#ifndef %s" % include_guard)
180     print("#define %s" % include_guard)
181     print("")
182     print("#include <vapi/vapi.hpp>")
183     print("#include <%s%s>" % (gen_h_prefix, json_to_c_header_name(f)))
184     print("")
185     print("namespace vapi {")
186     print("")
187     for m in parser.messages_by_json[j].values():
188         # utility functions need to go first, otherwise internal instantiation
189         # causes headaches ...
190         if add_debug_comments:
191             print("/* m.get_swap_to_be_template_instantiation() */")
192         print("%s" % m.get_swap_to_be_template_instantiation())
193         print("")
194         if add_debug_comments:
195             print("/* m.get_swap_to_host_template_instantiation() */")
196         print("%s" % m.get_swap_to_host_template_instantiation())
197         print("")
198         if add_debug_comments:
199             print("/* m.get_get_msg_id_t_instantiation() */")
200         print("%s" % m.get_get_msg_id_t_instantiation())
201         print("")
202         if add_debug_comments:
203             print("/* m.get_cpp_constructor() */")
204         print("%s" % m.get_cpp_constructor())
205         print("")
206         if not m.is_reply and not m.is_event and not m.is_stream:
207             if add_debug_comments:
208                 print("/* m.get_alloc_template_instantiation() */")
209             print("%s" % m.get_alloc_template_instantiation())
210             print("")
211         if add_debug_comments:
212             print("/* m.get_msg_class_instantiation() */")
213         print("%s" % m.get_msg_class_instantiation())
214         print("")
215         if m.is_reply or m.is_event:
216             if add_debug_comments:
217                 print("/* m.get_reply_type_alias() */")
218             print("%s" % m.get_reply_type_alias())
219             continue
220         if m.is_stream:
221             continue
222         if add_debug_comments:
223             print("/* m.get_req_template_instantiation() */")
224         print("%s" % m.get_req_template_instantiation())
225         print("")
226         if add_debug_comments:
227             print("/* m.get_type_alias() */")
228         print("%s" % m.get_type_alias())
229         print("")
230     print("}")  # namespace vapi
231
232     print("#endif")
233     sys.stdout = orig_stdout
234
235
236 def json_to_cpp_header_name(json_name):
237     if json_name.endswith(".json"):
238         return "%s.vapi.hpp" % os.path.splitext(json_name)[0]
239     raise Exception("Unexpected json name `%s'!" % json_name)
240
241
242 def gen_cpp_headers(
243     parser, logger, prefix, gen_h_prefix, remove_path, add_debug_comments=False
244 ):
245     if prefix == "" or prefix is None:
246         prefix = ""
247     else:
248         prefix = "%s/" % prefix
249     if gen_h_prefix is None:
250         gen_h_prefix = ""
251     else:
252         gen_h_prefix = "%s/" % gen_h_prefix
253     for j in parser.json_files:
254         if remove_path:
255             d, f = os.path.split(j)
256         else:
257             f = j
258         with open("%s%s" % (prefix, json_to_cpp_header_name(f)), "w") as io:
259             gen_json_header(parser, logger, j, io, gen_h_prefix, add_debug_comments)
260
261
262 if __name__ == "__main__":
263     try:
264         verbose = int(os.getenv("V", 0))
265     except:
266         verbose = 0
267
268     if verbose >= 2:
269         log_level = 10
270     elif verbose == 1:
271         log_level = 20
272     else:
273         log_level = 40
274
275     logging.basicConfig(stream=sys.stdout, level=log_level)
276     logger = logging.getLogger("VAPI CPP GEN")
277     logger.setLevel(log_level)
278
279     argparser = argparse.ArgumentParser(description="VPP C++ API generator")
280     argparser.add_argument(
281         "files",
282         metavar="api-file",
283         action="append",
284         type=str,
285         help="json api file" "(may be specified multiple times)",
286     )
287     argparser.add_argument("--prefix", action="store", default=None, help="path prefix")
288     argparser.add_argument(
289         "--gen-h-prefix", action="store", default=None, help="generated C header prefix"
290     )
291     argparser.add_argument(
292         "--remove-path", action="store_true", help="remove path from filename"
293     )
294     args = argparser.parse_args()
295
296     jsonparser = JsonParser(
297         logger,
298         args.files,
299         simple_type_class=CppSimpleType,
300         struct_type_class=CppStructType,
301         field_class=CppField,
302         enum_class=CppEnum,
303         message_class=CppMessage,
304         alias_class=CppAlias,
305     )
306
307     gen_cpp_headers(
308         jsonparser, logger, args.prefix, args.gen_h_prefix, args.remove_path
309     )
310
311     for e in jsonparser.exceptions:
312         logger.warning(e)