qapi-visit.py 12 KB

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