qapi-visit.py 12 KB

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