qapi-visit.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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, %(c_type)sobj, const char *name, 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, &err);
  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, %(c_name)s **obj, const char *name, Error **errp)
  94. {
  95. Error *err = NULL;
  96. visit_start_struct(v, (void **)obj, "%(name)s", name, 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. name=name, 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, %(c_name)s **obj, const char *name, 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, &err)) != NULL;
  130. prev = &i) {
  131. %(c_name)s *native_i = (%(c_name)s *)i;
  132. visit_type_%(c_elt_type)s(v, &native_i->value, NULL, &err);
  133. }
  134. error_propagate(errp, err);
  135. err = NULL;
  136. visit_end_list(v, &err);
  137. out:
  138. error_propagate(errp, err);
  139. }
  140. ''',
  141. c_name=c_name(name), c_elt_type=element_type.c_name())
  142. def gen_visit_enum(name):
  143. # FIXME cast from enum *obj to int * invalidly assumes enum is int
  144. return mcgen('''
  145. void visit_type_%(c_name)s(Visitor *v, %(c_name)s *obj, const char *name, Error **errp)
  146. {
  147. visit_type_enum(v, (int *)obj, %(c_name)s_lookup, "%(name)s", name, errp);
  148. }
  149. ''',
  150. c_name=c_name(name), name=name)
  151. def gen_visit_alternate(name, variants):
  152. promote_int = 'true'
  153. for var in variants.variants:
  154. if var.type.alternate_qtype() == 'QTYPE_QINT':
  155. promote_int = 'false'
  156. ret = mcgen('''
  157. void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
  158. {
  159. Error *err = NULL;
  160. visit_start_implicit_struct(v, (void**) obj, sizeof(%(c_name)s), &err);
  161. if (err) {
  162. goto out;
  163. }
  164. visit_get_next_type(v, &(*obj)->type, %(promote_int)s, name, &err);
  165. if (err) {
  166. goto out_obj;
  167. }
  168. switch ((*obj)->type) {
  169. ''',
  170. c_name=c_name(name), promote_int=promote_int)
  171. for var in variants.variants:
  172. ret += mcgen('''
  173. case %(case)s:
  174. visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, name, &err);
  175. break;
  176. ''',
  177. case=var.type.alternate_qtype(),
  178. c_type=var.type.c_name(),
  179. c_name=c_name(var.name))
  180. ret += mcgen('''
  181. default:
  182. error_setg(&err, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  183. "%(name)s");
  184. }
  185. out_obj:
  186. error_propagate(errp, err);
  187. err = NULL;
  188. visit_end_implicit_struct(v, &err);
  189. out:
  190. error_propagate(errp, err);
  191. }
  192. ''',
  193. name=name)
  194. return ret
  195. def gen_visit_union(name, base, variants):
  196. ret = ''
  197. if base:
  198. ret += gen_visit_fields_decl(base)
  199. for var in variants.variants:
  200. # Ugly special case for simple union TODO get rid of it
  201. if not var.simple_union_type():
  202. ret += gen_visit_implicit_struct(var.type)
  203. ret += mcgen('''
  204. void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
  205. {
  206. Error *err = NULL;
  207. visit_start_struct(v, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
  208. if (err) {
  209. goto out;
  210. }
  211. if (!*obj) {
  212. goto out_obj;
  213. }
  214. ''',
  215. c_name=c_name(name), name=name)
  216. if base:
  217. ret += mcgen('''
  218. visit_type_%(c_name)s_fields(v, (%(c_name)s **)obj, &err);
  219. ''',
  220. c_name=base.c_name())
  221. else:
  222. ret += mcgen('''
  223. visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
  224. ''',
  225. c_type=variants.tag_member.type.c_name(),
  226. c_name=c_name(variants.tag_member.name),
  227. name=variants.tag_member.name)
  228. ret += gen_err_check(label='out_obj')
  229. ret += mcgen('''
  230. if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
  231. goto out_obj;
  232. }
  233. switch ((*obj)->%(c_name)s) {
  234. ''',
  235. c_name=c_name(variants.tag_member.name))
  236. for var in variants.variants:
  237. # TODO ugly special case for simple union
  238. simple_union_type = var.simple_union_type()
  239. ret += mcgen('''
  240. case %(case)s:
  241. ''',
  242. case=c_enum_const(variants.tag_member.type.name,
  243. var.name))
  244. if simple_union_type:
  245. ret += mcgen('''
  246. visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, "data", &err);
  247. ''',
  248. c_type=simple_union_type.c_name(),
  249. c_name=c_name(var.name))
  250. else:
  251. ret += mcgen('''
  252. visit_type_implicit_%(c_type)s(v, &(*obj)->u.%(c_name)s, &err);
  253. ''',
  254. c_type=var.type.c_name(),
  255. c_name=c_name(var.name))
  256. ret += mcgen('''
  257. break;
  258. ''')
  259. ret += mcgen('''
  260. default:
  261. abort();
  262. }
  263. out_obj:
  264. error_propagate(errp, err);
  265. err = NULL;
  266. if (*obj) {
  267. visit_end_union(v, !!(*obj)->u.data, &err);
  268. }
  269. error_propagate(errp, err);
  270. err = NULL;
  271. visit_end_struct(v, &err);
  272. out:
  273. error_propagate(errp, err);
  274. }
  275. ''')
  276. return ret
  277. class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
  278. def __init__(self):
  279. self.decl = None
  280. self.defn = None
  281. self._btin = None
  282. def visit_begin(self, schema):
  283. self.decl = ''
  284. self.defn = ''
  285. self._btin = guardstart('QAPI_VISIT_BUILTIN')
  286. def visit_end(self):
  287. # To avoid header dependency hell, we always generate
  288. # declarations for built-in types in our header files and
  289. # simply guard them. See also do_builtins (command line
  290. # option -b).
  291. self._btin += guardend('QAPI_VISIT_BUILTIN')
  292. self.decl = self._btin + self.decl
  293. self._btin = None
  294. def visit_needed(self, entity):
  295. # Visit everything except implicit objects
  296. return not (entity.is_implicit() and
  297. isinstance(entity, QAPISchemaObjectType))
  298. def visit_enum_type(self, name, info, values, prefix):
  299. # Special case for our lone builtin enum type
  300. # TODO use something cleaner than existence of info
  301. if not info:
  302. self._btin += gen_visit_decl(name, scalar=True)
  303. if do_builtins:
  304. self.defn += gen_visit_enum(name)
  305. else:
  306. self.decl += gen_visit_decl(name, scalar=True)
  307. self.defn += gen_visit_enum(name)
  308. def visit_array_type(self, name, info, element_type):
  309. decl = gen_visit_decl(name)
  310. defn = gen_visit_list(name, element_type)
  311. if isinstance(element_type, QAPISchemaBuiltinType):
  312. self._btin += decl
  313. if do_builtins:
  314. self.defn += defn
  315. else:
  316. self.decl += decl
  317. self.defn += defn
  318. def visit_object_type(self, name, info, base, members, variants):
  319. self.decl += gen_visit_decl(name)
  320. if variants:
  321. if members:
  322. # Members other than variants.tag_member not implemented
  323. assert len(members) == 1
  324. assert members[0] == variants.tag_member
  325. self.defn += gen_visit_union(name, base, variants)
  326. else:
  327. self.defn += gen_visit_struct(name, base, members)
  328. def visit_alternate_type(self, name, info, variants):
  329. self.decl += gen_visit_decl(name)
  330. self.defn += gen_visit_alternate(name, variants)
  331. # If you link code generated from multiple schemata, you want only one
  332. # instance of the code for built-in types. Generate it only when
  333. # do_builtins, enabled by command line option -b. See also
  334. # QAPISchemaGenVisitVisitor.visit_end().
  335. do_builtins = False
  336. (input_file, output_dir, do_c, do_h, prefix, opts) = \
  337. parse_command_line("b", ["builtins"])
  338. for o, a in opts:
  339. if o in ("-b", "--builtins"):
  340. do_builtins = True
  341. c_comment = '''
  342. /*
  343. * schema-defined QAPI visitor functions
  344. *
  345. * Copyright IBM, Corp. 2011
  346. *
  347. * Authors:
  348. * Anthony Liguori <aliguori@us.ibm.com>
  349. *
  350. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  351. * See the COPYING.LIB file in the top-level directory.
  352. *
  353. */
  354. '''
  355. h_comment = '''
  356. /*
  357. * schema-defined QAPI visitor functions
  358. *
  359. * Copyright IBM, Corp. 2011
  360. *
  361. * Authors:
  362. * Anthony Liguori <aliguori@us.ibm.com>
  363. *
  364. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  365. * See the COPYING.LIB file in the top-level directory.
  366. *
  367. */
  368. '''
  369. (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
  370. 'qapi-visit.c', 'qapi-visit.h',
  371. c_comment, h_comment)
  372. fdef.write(mcgen('''
  373. #include "qemu-common.h"
  374. #include "%(prefix)sqapi-visit.h"
  375. ''',
  376. prefix=prefix))
  377. fdecl.write(mcgen('''
  378. #include "qapi/visitor.h"
  379. #include "qapi/qmp/qerror.h"
  380. #include "%(prefix)sqapi-types.h"
  381. ''',
  382. prefix=prefix))
  383. schema = QAPISchema(input_file)
  384. gen = QAPISchemaGenVisitVisitor()
  385. schema.visit(gen)
  386. fdef.write(gen.defn)
  387. fdecl.write(gen.decl)
  388. close_output(fdef, fdecl)