qapi-visit.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. #
  2. # QAPI visitor generator
  3. #
  4. # Copyright IBM, Corp. 2011
  5. # Copyright (C) 2014-2016 Red Hat, Inc.
  6. #
  7. # Authors:
  8. # Anthony Liguori <aliguori@us.ibm.com>
  9. # Michael Roth <mdroth@linux.vnet.ibm.com>
  10. # Markus Armbruster <armbru@redhat.com>
  11. #
  12. # This work is licensed under the terms of the GNU GPL, version 2.
  13. # See the COPYING file in the top-level directory.
  14. from qapi import *
  15. import re
  16. # visit_type_FOO_implicit() is emitted as needed; track if it has already
  17. # been output.
  18. implicit_structs_seen = set()
  19. # visit_type_FOO_fields() is always emitted; track if a forward declaration
  20. # or implementation has already been output.
  21. struct_fields_seen = set()
  22. def gen_visit_decl(name, scalar=False):
  23. c_type = c_name(name) + ' *'
  24. if not scalar:
  25. c_type += '*'
  26. return mcgen('''
  27. void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_type)sobj, Error **errp);
  28. ''',
  29. c_name=c_name(name), c_type=c_type)
  30. def gen_visit_fields_decl(typ):
  31. ret = ''
  32. if typ.name not in struct_fields_seen:
  33. ret += mcgen('''
  34. static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp);
  35. ''',
  36. c_type=typ.c_name())
  37. struct_fields_seen.add(typ.name)
  38. return ret
  39. def gen_visit_implicit_struct(typ):
  40. if typ in implicit_structs_seen:
  41. return ''
  42. implicit_structs_seen.add(typ)
  43. ret = gen_visit_fields_decl(typ)
  44. ret += mcgen('''
  45. static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error **errp)
  46. {
  47. Error *err = NULL;
  48. visit_start_implicit_struct(v, (void **)obj, sizeof(%(c_type)s), &err);
  49. if (!err) {
  50. visit_type_%(c_type)s_fields(v, obj, errp);
  51. visit_end_implicit_struct(v);
  52. }
  53. error_propagate(errp, err);
  54. }
  55. ''',
  56. c_type=typ.c_name())
  57. return ret
  58. def gen_visit_struct_fields(name, base, members):
  59. ret = ''
  60. if base:
  61. ret += gen_visit_fields_decl(base)
  62. struct_fields_seen.add(name)
  63. ret += mcgen('''
  64. static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **errp)
  65. {
  66. Error *err = NULL;
  67. ''',
  68. c_name=c_name(name))
  69. if base:
  70. ret += mcgen('''
  71. visit_type_%(c_type)s_fields(v, (%(c_type)s **)obj, &err);
  72. ''',
  73. c_type=base.c_name())
  74. ret += gen_err_check()
  75. ret += gen_visit_fields(members, prefix='(*obj)->')
  76. # 'goto out' produced for base, and by gen_visit_fields() for each member
  77. if base or members:
  78. ret += mcgen('''
  79. out:
  80. ''')
  81. ret += mcgen('''
  82. error_propagate(errp, err);
  83. }
  84. ''')
  85. return ret
  86. def gen_visit_struct(name, base, members):
  87. ret = gen_visit_struct_fields(name, base, members)
  88. # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
  89. # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
  90. # rather than leaving it non-NULL. As currently written, the caller must
  91. # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
  92. ret += mcgen('''
  93. void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
  94. {
  95. Error *err = NULL;
  96. visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), &err);
  97. if (err) {
  98. goto out;
  99. }
  100. if (!*obj) {
  101. goto out_obj;
  102. }
  103. visit_type_%(c_name)s_fields(v, obj, &err);
  104. error_propagate(errp, err);
  105. err = NULL;
  106. out_obj:
  107. visit_end_struct(v, &err);
  108. out:
  109. error_propagate(errp, err);
  110. }
  111. ''',
  112. c_name=c_name(name))
  113. return ret
  114. def gen_visit_list(name, element_type):
  115. # FIXME: if *obj is NULL on entry, and the first visit_next_list()
  116. # assigns to *obj, while a later one fails, we should clean up *obj
  117. # rather than leaving it non-NULL. As currently written, the caller must
  118. # call qapi_free_FOOList() to avoid a memory leak of the partial FOOList.
  119. return mcgen('''
  120. void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
  121. {
  122. Error *err = NULL;
  123. GenericList *i, **prev;
  124. visit_start_list(v, name, &err);
  125. if (err) {
  126. goto out;
  127. }
  128. for (prev = (GenericList **)obj;
  129. !err && (i = visit_next_list(v, prev)) != NULL;
  130. prev = &i) {
  131. %(c_name)s *native_i = (%(c_name)s *)i;
  132. visit_type_%(c_elt_type)s(v, NULL, &native_i->value, &err);
  133. }
  134. visit_end_list(v);
  135. out:
  136. error_propagate(errp, err);
  137. }
  138. ''',
  139. c_name=c_name(name), c_elt_type=element_type.c_name())
  140. def gen_visit_enum(name):
  141. return mcgen('''
  142. void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s *obj, Error **errp)
  143. {
  144. int value = *obj;
  145. visit_type_enum(v, name, &value, %(c_name)s_lookup, errp);
  146. *obj = value;
  147. }
  148. ''',
  149. c_name=c_name(name))
  150. def gen_visit_alternate(name, variants):
  151. promote_int = 'true'
  152. for var in variants.variants:
  153. if var.type.alternate_qtype() == 'QTYPE_QINT':
  154. promote_int = 'false'
  155. ret = mcgen('''
  156. void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
  157. {
  158. Error *err = NULL;
  159. visit_start_implicit_struct(v, (void**) obj, sizeof(%(c_name)s), &err);
  160. if (err) {
  161. goto out;
  162. }
  163. visit_get_next_type(v, name, &(*obj)->type, %(promote_int)s, &err);
  164. if (err) {
  165. goto out_obj;
  166. }
  167. switch ((*obj)->type) {
  168. ''',
  169. c_name=c_name(name), promote_int=promote_int)
  170. for var in variants.variants:
  171. ret += mcgen('''
  172. case %(case)s:
  173. visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, &err);
  174. break;
  175. ''',
  176. case=var.type.alternate_qtype(),
  177. c_type=var.type.c_name(),
  178. c_name=c_name(var.name))
  179. ret += mcgen('''
  180. default:
  181. error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  182. "%(name)s");
  183. }
  184. out_obj:
  185. visit_end_implicit_struct(v);
  186. out:
  187. error_propagate(errp, err);
  188. }
  189. ''',
  190. name=name)
  191. return ret
  192. def gen_visit_union(name, base, members, variants):
  193. ret = gen_visit_struct_fields(name, base, members)
  194. for var in variants.variants:
  195. # Ugly special case for simple union TODO get rid of it
  196. if not var.simple_union_type():
  197. ret += gen_visit_implicit_struct(var.type)
  198. ret += mcgen('''
  199. void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp)
  200. {
  201. Error *err = NULL;
  202. visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), &err);
  203. if (err) {
  204. goto out;
  205. }
  206. if (!*obj) {
  207. goto out_obj;
  208. }
  209. visit_type_%(c_name)s_fields(v, obj, &err);
  210. ''',
  211. c_name=c_name(name))
  212. ret += gen_err_check(label='out_obj')
  213. ret += mcgen('''
  214. if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
  215. goto out_obj;
  216. }
  217. switch ((*obj)->%(c_name)s) {
  218. ''',
  219. c_name=c_name(variants.tag_member.name))
  220. for var in variants.variants:
  221. # TODO ugly special case for simple union
  222. simple_union_type = var.simple_union_type()
  223. ret += mcgen('''
  224. case %(case)s:
  225. ''',
  226. case=c_enum_const(variants.tag_member.type.name,
  227. var.name,
  228. variants.tag_member.type.prefix))
  229. if simple_union_type:
  230. ret += mcgen('''
  231. visit_type_%(c_type)s(v, "data", &(*obj)->u.%(c_name)s, &err);
  232. ''',
  233. c_type=simple_union_type.c_name(),
  234. c_name=c_name(var.name))
  235. else:
  236. ret += mcgen('''
  237. visit_type_implicit_%(c_type)s(v, &(*obj)->u.%(c_name)s, &err);
  238. ''',
  239. c_type=var.type.c_name(),
  240. c_name=c_name(var.name))
  241. ret += mcgen('''
  242. break;
  243. ''')
  244. ret += mcgen('''
  245. default:
  246. abort();
  247. }
  248. out_obj:
  249. error_propagate(errp, err);
  250. err = NULL;
  251. visit_end_struct(v, &err);
  252. out:
  253. error_propagate(errp, err);
  254. }
  255. ''')
  256. return ret
  257. class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
  258. def __init__(self):
  259. self.decl = None
  260. self.defn = None
  261. self._btin = None
  262. def visit_begin(self, schema):
  263. self.decl = ''
  264. self.defn = ''
  265. self._btin = guardstart('QAPI_VISIT_BUILTIN')
  266. def visit_end(self):
  267. # To avoid header dependency hell, we always generate
  268. # declarations for built-in types in our header files and
  269. # simply guard them. See also do_builtins (command line
  270. # option -b).
  271. self._btin += guardend('QAPI_VISIT_BUILTIN')
  272. self.decl = self._btin + self.decl
  273. self._btin = None
  274. def visit_needed(self, entity):
  275. # Visit everything except implicit objects
  276. return not (entity.is_implicit() and
  277. isinstance(entity, QAPISchemaObjectType))
  278. def visit_enum_type(self, name, info, values, prefix):
  279. # Special case for our lone builtin enum type
  280. # TODO use something cleaner than existence of info
  281. if not info:
  282. self._btin += gen_visit_decl(name, scalar=True)
  283. if do_builtins:
  284. self.defn += gen_visit_enum(name)
  285. else:
  286. self.decl += gen_visit_decl(name, scalar=True)
  287. self.defn += gen_visit_enum(name)
  288. def visit_array_type(self, name, info, element_type):
  289. decl = gen_visit_decl(name)
  290. defn = gen_visit_list(name, element_type)
  291. if isinstance(element_type, QAPISchemaBuiltinType):
  292. self._btin += decl
  293. if do_builtins:
  294. self.defn += defn
  295. else:
  296. self.decl += decl
  297. self.defn += defn
  298. def visit_object_type(self, name, info, base, members, variants):
  299. self.decl += gen_visit_decl(name)
  300. if variants:
  301. self.defn += gen_visit_union(name, base, members, variants)
  302. else:
  303. self.defn += gen_visit_struct(name, base, members)
  304. def visit_alternate_type(self, name, info, variants):
  305. self.decl += gen_visit_decl(name)
  306. self.defn += gen_visit_alternate(name, variants)
  307. # If you link code generated from multiple schemata, you want only one
  308. # instance of the code for built-in types. Generate it only when
  309. # do_builtins, enabled by command line option -b. See also
  310. # QAPISchemaGenVisitVisitor.visit_end().
  311. do_builtins = False
  312. (input_file, output_dir, do_c, do_h, prefix, opts) = \
  313. parse_command_line("b", ["builtins"])
  314. for o, a in opts:
  315. if o in ("-b", "--builtins"):
  316. do_builtins = True
  317. c_comment = '''
  318. /*
  319. * schema-defined QAPI visitor functions
  320. *
  321. * Copyright IBM, Corp. 2011
  322. *
  323. * Authors:
  324. * Anthony Liguori <aliguori@us.ibm.com>
  325. *
  326. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  327. * See the COPYING.LIB file in the top-level directory.
  328. *
  329. */
  330. '''
  331. h_comment = '''
  332. /*
  333. * schema-defined QAPI visitor functions
  334. *
  335. * Copyright IBM, Corp. 2011
  336. *
  337. * Authors:
  338. * Anthony Liguori <aliguori@us.ibm.com>
  339. *
  340. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  341. * See the COPYING.LIB file in the top-level directory.
  342. *
  343. */
  344. '''
  345. (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
  346. 'qapi-visit.c', 'qapi-visit.h',
  347. c_comment, h_comment)
  348. fdef.write(mcgen('''
  349. #include "qemu/osdep.h"
  350. #include "qemu-common.h"
  351. #include "%(prefix)sqapi-visit.h"
  352. ''',
  353. prefix=prefix))
  354. fdecl.write(mcgen('''
  355. #include "qapi/visitor.h"
  356. #include "qapi/qmp/qerror.h"
  357. #include "%(prefix)sqapi-types.h"
  358. ''',
  359. prefix=prefix))
  360. schema = QAPISchema(input_file)
  361. gen = QAPISchemaGenVisitVisitor()
  362. schema.visit(gen)
  363. fdef.write(gen.defn)
  364. fdecl.write(gen.decl)
  365. close_output(fdef, fdecl)