qapi-visit.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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 ordereddict import OrderedDict
  15. from qapi import *
  16. import re
  17. implicit_structs = []
  18. def generate_visit_implicit_struct(type):
  19. global implicit_structs
  20. if type in implicit_structs:
  21. return ''
  22. implicit_structs.append(type)
  23. return mcgen('''
  24. static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
  25. {
  26. Error *err = NULL;
  27. visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
  28. if (!err) {
  29. visit_type_%(c_type)s_fields(m, obj, errp);
  30. visit_end_implicit_struct(m, &err);
  31. }
  32. error_propagate(errp, err);
  33. }
  34. ''',
  35. c_type=type_name(type))
  36. def generate_visit_struct_fields(name, members, base = None):
  37. substructs = []
  38. ret = ''
  39. if base:
  40. ret += generate_visit_implicit_struct(base)
  41. ret += mcgen('''
  42. static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
  43. {
  44. Error *err = NULL;
  45. ''',
  46. name=c_name(name))
  47. push_indent()
  48. if base:
  49. ret += mcgen('''
  50. visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
  51. if (err) {
  52. goto out;
  53. }
  54. ''',
  55. type=type_name(base), c_name=c_name('base'))
  56. for argname, argentry, optional in parse_args(members):
  57. if optional:
  58. ret += mcgen('''
  59. visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
  60. if (!err && (*obj)->has_%(c_name)s) {
  61. ''',
  62. c_name=c_name(argname), name=argname)
  63. push_indent()
  64. ret += mcgen('''
  65. visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
  66. ''',
  67. type=type_name(argentry), c_name=c_name(argname),
  68. name=argname)
  69. if optional:
  70. pop_indent()
  71. ret += mcgen('''
  72. }
  73. ''')
  74. ret += mcgen('''
  75. if (err) {
  76. goto out;
  77. }
  78. ''')
  79. pop_indent()
  80. if re.search('^ *goto out\\;', ret, re.MULTILINE):
  81. ret += mcgen('''
  82. out:
  83. ''')
  84. ret += mcgen('''
  85. error_propagate(errp, err);
  86. }
  87. ''')
  88. return ret
  89. def generate_visit_struct_body(name, members):
  90. ret = mcgen('''
  91. Error *err = NULL;
  92. visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
  93. if (!err) {
  94. if (*obj) {
  95. visit_type_%(c_name)s_fields(m, obj, errp);
  96. }
  97. visit_end_struct(m, &err);
  98. }
  99. error_propagate(errp, err);
  100. ''',
  101. name=name, c_name=c_name(name))
  102. return ret
  103. def generate_visit_struct(expr):
  104. name = expr['struct']
  105. members = expr['data']
  106. base = expr.get('base')
  107. ret = generate_visit_struct_fields(name, members, base)
  108. ret += mcgen('''
  109. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
  110. {
  111. ''',
  112. name=c_name(name))
  113. ret += generate_visit_struct_body(name, members)
  114. ret += mcgen('''
  115. }
  116. ''')
  117. return ret
  118. def generate_visit_list(name, members):
  119. return mcgen('''
  120. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
  121. {
  122. Error *err = NULL;
  123. GenericList *i, **prev;
  124. visit_start_list(m, name, &err);
  125. if (err) {
  126. goto out;
  127. }
  128. for (prev = (GenericList **)obj;
  129. !err && (i = visit_next_list(m, prev, &err)) != NULL;
  130. prev = &i) {
  131. %(name)sList *native_i = (%(name)sList *)i;
  132. visit_type_%(name)s(m, &native_i->value, NULL, &err);
  133. }
  134. error_propagate(errp, err);
  135. err = NULL;
  136. visit_end_list(m, &err);
  137. out:
  138. error_propagate(errp, err);
  139. }
  140. ''',
  141. name=type_name(name))
  142. def generate_visit_enum(name, members):
  143. return mcgen('''
  144. void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
  145. {
  146. visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
  147. }
  148. ''',
  149. name=c_name(name))
  150. def generate_visit_alternate(name, members):
  151. ret = mcgen('''
  152. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
  153. {
  154. Error *err = NULL;
  155. visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
  156. if (err) {
  157. goto out;
  158. }
  159. visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
  160. if (err) {
  161. goto out_end;
  162. }
  163. switch ((*obj)->kind) {
  164. ''',
  165. name=c_name(name))
  166. # For alternate, always use the default enum type automatically generated
  167. # as name + 'Kind'
  168. disc_type = c_name(name) + 'Kind'
  169. for key in members:
  170. assert (members[key] in builtin_types.keys()
  171. or find_struct(members[key])
  172. or find_union(members[key])
  173. or find_enum(members[key])), "Invalid alternate member"
  174. enum_full_value = c_enum_const(disc_type, key)
  175. ret += mcgen('''
  176. case %(enum_full_value)s:
  177. visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
  178. break;
  179. ''',
  180. enum_full_value = enum_full_value,
  181. c_type = type_name(members[key]),
  182. c_name = c_name(key))
  183. ret += mcgen('''
  184. default:
  185. abort();
  186. }
  187. out_end:
  188. error_propagate(errp, err);
  189. err = NULL;
  190. visit_end_implicit_struct(m, &err);
  191. out:
  192. error_propagate(errp, err);
  193. }
  194. ''')
  195. return ret
  196. def generate_visit_union(expr):
  197. name = expr['union']
  198. members = expr['data']
  199. base = expr.get('base')
  200. discriminator = expr.get('discriminator')
  201. enum_define = discriminator_find_enum_define(expr)
  202. if enum_define:
  203. # Use the enum type as discriminator
  204. ret = ""
  205. disc_type = c_name(enum_define['enum_name'])
  206. else:
  207. # There will always be a discriminator in the C switch code, by default
  208. # it is an enum type generated silently
  209. ret = generate_visit_enum(name + 'Kind', members.keys())
  210. disc_type = c_name(name) + 'Kind'
  211. if base:
  212. assert discriminator
  213. base_fields = find_struct(base)['data'].copy()
  214. del base_fields[discriminator]
  215. ret += generate_visit_struct_fields(name, base_fields)
  216. if discriminator:
  217. for key in members:
  218. ret += generate_visit_implicit_struct(members[key])
  219. ret += mcgen('''
  220. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
  221. {
  222. Error *err = NULL;
  223. visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
  224. if (err) {
  225. goto out;
  226. }
  227. if (*obj) {
  228. ''',
  229. name=c_name(name))
  230. if base:
  231. ret += mcgen('''
  232. visit_type_%(name)s_fields(m, obj, &err);
  233. if (err) {
  234. goto out_obj;
  235. }
  236. ''',
  237. name=c_name(name))
  238. if not discriminator:
  239. disc_key = "type"
  240. else:
  241. disc_key = discriminator
  242. ret += mcgen('''
  243. visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
  244. if (err) {
  245. goto out_obj;
  246. }
  247. if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
  248. goto out_obj;
  249. }
  250. switch ((*obj)->kind) {
  251. ''',
  252. disc_type = disc_type,
  253. disc_key = disc_key)
  254. for key in members:
  255. if not discriminator:
  256. fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
  257. else:
  258. fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
  259. enum_full_value = c_enum_const(disc_type, key)
  260. ret += mcgen('''
  261. case %(enum_full_value)s:
  262. ''' + fmt + '''
  263. break;
  264. ''',
  265. enum_full_value = enum_full_value,
  266. c_type=type_name(members[key]),
  267. c_name=c_name(key))
  268. ret += mcgen('''
  269. default:
  270. abort();
  271. }
  272. out_obj:
  273. error_propagate(errp, err);
  274. err = NULL;
  275. visit_end_union(m, !!(*obj)->data, &err);
  276. error_propagate(errp, err);
  277. err = NULL;
  278. }
  279. visit_end_struct(m, &err);
  280. out:
  281. error_propagate(errp, err);
  282. }
  283. ''')
  284. return ret
  285. def generate_declaration(name, members, builtin_type=False):
  286. ret = ""
  287. if not builtin_type:
  288. name = c_name(name)
  289. ret += mcgen('''
  290. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
  291. ''',
  292. name=name)
  293. ret += mcgen('''
  294. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
  295. ''',
  296. name=name)
  297. return ret
  298. def generate_enum_declaration(name, members):
  299. ret = mcgen('''
  300. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
  301. ''',
  302. name=c_name(name))
  303. return ret
  304. def generate_decl_enum(name, members):
  305. return mcgen('''
  306. void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
  307. ''',
  308. name=c_name(name))
  309. do_builtins = False
  310. (input_file, output_dir, do_c, do_h, prefix, opts) = \
  311. parse_command_line("b", ["builtins"])
  312. for o, a in opts:
  313. if o in ("-b", "--builtins"):
  314. do_builtins = True
  315. c_comment = '''
  316. /*
  317. * schema-defined QAPI visitor functions
  318. *
  319. * Copyright IBM, Corp. 2011
  320. *
  321. * Authors:
  322. * Anthony Liguori <aliguori@us.ibm.com>
  323. *
  324. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  325. * See the COPYING.LIB file in the top-level directory.
  326. *
  327. */
  328. '''
  329. h_comment = '''
  330. /*
  331. * schema-defined QAPI visitor functions
  332. *
  333. * Copyright IBM, Corp. 2011
  334. *
  335. * Authors:
  336. * Anthony Liguori <aliguori@us.ibm.com>
  337. *
  338. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  339. * See the COPYING.LIB file in the top-level directory.
  340. *
  341. */
  342. '''
  343. (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
  344. 'qapi-visit.c', 'qapi-visit.h',
  345. c_comment, h_comment)
  346. fdef.write(mcgen('''
  347. #include "qemu-common.h"
  348. #include "%(prefix)sqapi-visit.h"
  349. ''',
  350. prefix = prefix))
  351. fdecl.write(mcgen('''
  352. #include "qapi/visitor.h"
  353. #include "%(prefix)sqapi-types.h"
  354. ''',
  355. prefix=prefix))
  356. exprs = parse_schema(input_file)
  357. # to avoid header dependency hell, we always generate declarations
  358. # for built-in types in our header files and simply guard them
  359. fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
  360. for typename in builtin_types.keys():
  361. fdecl.write(generate_declaration(typename, None, builtin_type=True))
  362. fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
  363. # ...this doesn't work for cases where we link in multiple objects that
  364. # have the functions defined, so we use -b option to provide control
  365. # over these cases
  366. if do_builtins:
  367. for typename in builtin_types.keys():
  368. fdef.write(generate_visit_list(typename, None))
  369. for expr in exprs:
  370. if expr.has_key('struct'):
  371. ret = generate_visit_struct(expr)
  372. ret += generate_visit_list(expr['struct'], expr['data'])
  373. fdef.write(ret)
  374. ret = generate_declaration(expr['struct'], expr['data'])
  375. fdecl.write(ret)
  376. elif expr.has_key('union'):
  377. ret = generate_visit_union(expr)
  378. ret += generate_visit_list(expr['union'], expr['data'])
  379. fdef.write(ret)
  380. enum_define = discriminator_find_enum_define(expr)
  381. ret = ""
  382. if not enum_define:
  383. ret = generate_decl_enum('%sKind' % expr['union'],
  384. expr['data'].keys())
  385. ret += generate_declaration(expr['union'], expr['data'])
  386. fdecl.write(ret)
  387. elif expr.has_key('alternate'):
  388. ret = generate_visit_alternate(expr['alternate'], expr['data'])
  389. ret += generate_visit_list(expr['alternate'], expr['data'])
  390. fdef.write(ret)
  391. ret = generate_decl_enum('%sKind' % expr['alternate'],
  392. expr['data'].keys())
  393. ret += generate_declaration(expr['alternate'], expr['data'])
  394. fdecl.write(ret)
  395. elif expr.has_key('enum'):
  396. ret = generate_visit_list(expr['enum'], expr['data'])
  397. ret += generate_visit_enum(expr['enum'], expr['data'])
  398. fdef.write(ret)
  399. ret = generate_decl_enum(expr['enum'], expr['data'])
  400. ret += generate_enum_declaration(expr['enum'], expr['data'])
  401. fdecl.write(ret)
  402. close_output(fdef, fdecl)