qapi-visit.py 11 KB

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