qapi-visit.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  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. import sys
  18. import os
  19. import getopt
  20. import errno
  21. implicit_structs = []
  22. def generate_visit_implicit_struct(type):
  23. global implicit_structs
  24. if type in implicit_structs:
  25. return ''
  26. implicit_structs.append(type)
  27. return mcgen('''
  28. static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
  29. {
  30. Error *err = NULL;
  31. visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
  32. if (!err) {
  33. visit_type_%(c_type)s_fields(m, obj, errp);
  34. visit_end_implicit_struct(m, &err);
  35. }
  36. error_propagate(errp, err);
  37. }
  38. ''',
  39. c_type=type_name(type))
  40. def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None):
  41. substructs = []
  42. ret = ''
  43. if not fn_prefix:
  44. full_name = name
  45. else:
  46. full_name = "%s_%s" % (name, fn_prefix)
  47. for argname, argentry, optional, structured in parse_args(members):
  48. if structured:
  49. if not fn_prefix:
  50. nested_fn_prefix = argname
  51. else:
  52. nested_fn_prefix = "%s_%s" % (fn_prefix, argname)
  53. nested_field_prefix = "%s%s." % (field_prefix, argname)
  54. ret += generate_visit_struct_fields(name, nested_field_prefix,
  55. nested_fn_prefix, argentry)
  56. ret += mcgen('''
  57. static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj, Error **errp)
  58. {
  59. ''',
  60. name=name, full_name=full_name, c_name=c_var(argname))
  61. ret += generate_visit_struct_body(full_name, argname, argentry)
  62. ret += mcgen('''
  63. }
  64. ''')
  65. if base:
  66. ret += generate_visit_implicit_struct(base)
  67. ret += mcgen('''
  68. static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
  69. {
  70. Error *err = NULL;
  71. ''',
  72. name=name, full_name=full_name)
  73. push_indent()
  74. if base:
  75. ret += mcgen('''
  76. visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err);
  77. if (err) {
  78. goto out;
  79. }
  80. ''',
  81. c_prefix=c_var(field_prefix),
  82. type=type_name(base), c_name=c_var('base'))
  83. for argname, argentry, optional, structured in parse_args(members):
  84. if optional:
  85. ret += mcgen('''
  86. visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err);
  87. if (!err && (*obj)->%(prefix)shas_%(c_name)s) {
  88. ''',
  89. c_prefix=c_var(field_prefix), prefix=field_prefix,
  90. c_name=c_var(argname), name=argname)
  91. push_indent()
  92. if structured:
  93. ret += mcgen('''
  94. visit_type_%(full_name)s_field_%(c_name)s(m, obj, &err);
  95. ''',
  96. full_name=full_name, c_name=c_var(argname))
  97. else:
  98. ret += mcgen('''
  99. visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err);
  100. ''',
  101. c_prefix=c_var(field_prefix), prefix=field_prefix,
  102. type=type_name(argentry), c_name=c_var(argname),
  103. name=argname)
  104. if optional:
  105. pop_indent()
  106. ret += mcgen('''
  107. }
  108. ''')
  109. ret += mcgen('''
  110. if (err) {
  111. goto out;
  112. }
  113. ''')
  114. pop_indent()
  115. if re.search('^ *goto out\\;', ret, re.MULTILINE):
  116. ret += mcgen('''
  117. out:
  118. ''')
  119. ret += mcgen('''
  120. error_propagate(errp, err);
  121. }
  122. ''')
  123. return ret
  124. def generate_visit_struct_body(field_prefix, name, members):
  125. ret = mcgen('''
  126. Error *err = NULL;
  127. ''')
  128. if not field_prefix:
  129. full_name = name
  130. else:
  131. full_name = "%s_%s" % (field_prefix, name)
  132. if len(field_prefix):
  133. ret += mcgen('''
  134. visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
  135. ''',
  136. name=name)
  137. else:
  138. ret += mcgen('''
  139. visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
  140. ''',
  141. name=name)
  142. ret += mcgen('''
  143. if (!err) {
  144. if (*obj) {
  145. visit_type_%(name)s_fields(m, obj, errp);
  146. }
  147. visit_end_struct(m, &err);
  148. }
  149. error_propagate(errp, err);
  150. ''',
  151. name=full_name)
  152. return ret
  153. def generate_visit_struct(expr):
  154. name = expr['struct']
  155. members = expr['data']
  156. base = expr.get('base')
  157. ret = generate_visit_struct_fields(name, "", "", members, base)
  158. ret += mcgen('''
  159. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
  160. {
  161. ''',
  162. name=name)
  163. ret += generate_visit_struct_body("", name, members)
  164. ret += mcgen('''
  165. }
  166. ''')
  167. return ret
  168. def generate_visit_list(name, members):
  169. return mcgen('''
  170. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
  171. {
  172. Error *err = NULL;
  173. GenericList *i, **prev;
  174. visit_start_list(m, name, &err);
  175. if (err) {
  176. goto out;
  177. }
  178. for (prev = (GenericList **)obj;
  179. !err && (i = visit_next_list(m, prev, &err)) != NULL;
  180. prev = &i) {
  181. %(name)sList *native_i = (%(name)sList *)i;
  182. visit_type_%(name)s(m, &native_i->value, NULL, &err);
  183. }
  184. error_propagate(errp, err);
  185. err = NULL;
  186. visit_end_list(m, &err);
  187. out:
  188. error_propagate(errp, err);
  189. }
  190. ''',
  191. name=name)
  192. def generate_visit_enum(name, members):
  193. return mcgen('''
  194. void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
  195. {
  196. visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
  197. }
  198. ''',
  199. name=name)
  200. def generate_visit_alternate(name, members):
  201. ret = mcgen('''
  202. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
  203. {
  204. Error *err = NULL;
  205. visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
  206. if (err) {
  207. goto out;
  208. }
  209. visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
  210. if (err) {
  211. goto out_end;
  212. }
  213. switch ((*obj)->kind) {
  214. ''',
  215. name=name)
  216. # For alternate, always use the default enum type automatically generated
  217. # as "'%sKind' % (name)"
  218. disc_type = '%sKind' % (name)
  219. for key in members:
  220. assert (members[key] in builtin_types.keys()
  221. or find_struct(members[key])
  222. or find_union(members[key])
  223. or find_enum(members[key])), "Invalid alternate member"
  224. enum_full_value = generate_enum_full_value(disc_type, key)
  225. ret += mcgen('''
  226. case %(enum_full_value)s:
  227. visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
  228. break;
  229. ''',
  230. enum_full_value = enum_full_value,
  231. c_type = type_name(members[key]),
  232. c_name = c_fun(key))
  233. ret += mcgen('''
  234. default:
  235. abort();
  236. }
  237. out_end:
  238. error_propagate(errp, err);
  239. err = NULL;
  240. visit_end_implicit_struct(m, &err);
  241. out:
  242. error_propagate(errp, err);
  243. }
  244. ''')
  245. return ret
  246. def generate_visit_union(expr):
  247. name = expr['union']
  248. members = expr['data']
  249. base = expr.get('base')
  250. discriminator = expr.get('discriminator')
  251. enum_define = discriminator_find_enum_define(expr)
  252. if enum_define:
  253. # Use the enum type as discriminator
  254. ret = ""
  255. disc_type = enum_define['enum_name']
  256. else:
  257. # There will always be a discriminator in the C switch code, by default
  258. # it is an enum type generated silently as "'%sKind' % (name)"
  259. ret = generate_visit_enum('%sKind' % name, members.keys())
  260. disc_type = '%sKind' % (name)
  261. if base:
  262. assert discriminator
  263. base_fields = find_struct(base)['data'].copy()
  264. del base_fields[discriminator]
  265. ret += generate_visit_struct_fields(name, "", "", base_fields)
  266. if discriminator:
  267. for key in members:
  268. ret += generate_visit_implicit_struct(members[key])
  269. ret += mcgen('''
  270. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
  271. {
  272. Error *err = NULL;
  273. visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
  274. if (err) {
  275. goto out;
  276. }
  277. if (*obj) {
  278. ''',
  279. name=name)
  280. if base:
  281. ret += mcgen('''
  282. visit_type_%(name)s_fields(m, obj, &err);
  283. if (err) {
  284. goto out_obj;
  285. }
  286. ''',
  287. name=name)
  288. if not discriminator:
  289. disc_key = "type"
  290. else:
  291. disc_key = discriminator
  292. ret += mcgen('''
  293. visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
  294. if (err) {
  295. goto out_obj;
  296. }
  297. if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
  298. goto out_obj;
  299. }
  300. switch ((*obj)->kind) {
  301. ''',
  302. disc_type = disc_type,
  303. disc_key = disc_key)
  304. for key in members:
  305. if not discriminator:
  306. fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
  307. else:
  308. fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
  309. enum_full_value = generate_enum_full_value(disc_type, key)
  310. ret += mcgen('''
  311. case %(enum_full_value)s:
  312. ''' + fmt + '''
  313. break;
  314. ''',
  315. enum_full_value = enum_full_value,
  316. c_type=type_name(members[key]),
  317. c_name=c_fun(key))
  318. ret += mcgen('''
  319. default:
  320. abort();
  321. }
  322. out_obj:
  323. error_propagate(errp, err);
  324. err = NULL;
  325. visit_end_union(m, !!(*obj)->data, &err);
  326. error_propagate(errp, err);
  327. err = NULL;
  328. }
  329. visit_end_struct(m, &err);
  330. out:
  331. error_propagate(errp, err);
  332. }
  333. ''')
  334. return ret
  335. def generate_declaration(name, members, builtin_type=False):
  336. ret = ""
  337. if not builtin_type:
  338. ret += mcgen('''
  339. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
  340. ''',
  341. name=name)
  342. ret += mcgen('''
  343. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
  344. ''',
  345. name=name)
  346. return ret
  347. def generate_enum_declaration(name, members):
  348. ret = mcgen('''
  349. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
  350. ''',
  351. name=name)
  352. return ret
  353. def generate_decl_enum(name, members):
  354. return mcgen('''
  355. void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
  356. ''',
  357. name=name)
  358. try:
  359. opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
  360. ["source", "header", "builtins", "prefix=",
  361. "input-file=", "output-dir="])
  362. except getopt.GetoptError, err:
  363. print str(err)
  364. sys.exit(1)
  365. input_file = ""
  366. output_dir = ""
  367. prefix = ""
  368. c_file = 'qapi-visit.c'
  369. h_file = 'qapi-visit.h'
  370. do_c = False
  371. do_h = False
  372. do_builtins = False
  373. for o, a in opts:
  374. if o in ("-p", "--prefix"):
  375. prefix = a
  376. elif o in ("-i", "--input-file"):
  377. input_file = a
  378. elif o in ("-o", "--output-dir"):
  379. output_dir = a + "/"
  380. elif o in ("-c", "--source"):
  381. do_c = True
  382. elif o in ("-h", "--header"):
  383. do_h = True
  384. elif o in ("-b", "--builtins"):
  385. do_builtins = True
  386. if not do_c and not do_h:
  387. do_c = True
  388. do_h = True
  389. c_file = output_dir + prefix + c_file
  390. h_file = output_dir + prefix + h_file
  391. try:
  392. os.makedirs(output_dir)
  393. except os.error, e:
  394. if e.errno != errno.EEXIST:
  395. raise
  396. def maybe_open(really, name, opt):
  397. if really:
  398. return open(name, opt)
  399. else:
  400. import StringIO
  401. return StringIO.StringIO()
  402. fdef = maybe_open(do_c, c_file, 'w')
  403. fdecl = maybe_open(do_h, h_file, 'w')
  404. fdef.write(mcgen('''
  405. /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
  406. /*
  407. * schema-defined QAPI visitor functions
  408. *
  409. * Copyright IBM, Corp. 2011
  410. *
  411. * Authors:
  412. * Anthony Liguori <aliguori@us.ibm.com>
  413. *
  414. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  415. * See the COPYING.LIB file in the top-level directory.
  416. *
  417. */
  418. #include "qemu-common.h"
  419. #include "%(header)s"
  420. ''',
  421. header=basename(h_file)))
  422. fdecl.write(mcgen('''
  423. /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
  424. /*
  425. * schema-defined QAPI visitor functions
  426. *
  427. * Copyright IBM, Corp. 2011
  428. *
  429. * Authors:
  430. * Anthony Liguori <aliguori@us.ibm.com>
  431. *
  432. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  433. * See the COPYING.LIB file in the top-level directory.
  434. *
  435. */
  436. #ifndef %(guard)s
  437. #define %(guard)s
  438. #include "qapi/visitor.h"
  439. #include "%(prefix)sqapi-types.h"
  440. ''',
  441. prefix=prefix, guard=guardname(h_file)))
  442. exprs = parse_schema(input_file)
  443. # to avoid header dependency hell, we always generate declarations
  444. # for built-in types in our header files and simply guard them
  445. fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
  446. for typename in builtin_types.keys():
  447. fdecl.write(generate_declaration(typename, None, builtin_type=True))
  448. fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
  449. # ...this doesn't work for cases where we link in multiple objects that
  450. # have the functions defined, so we use -b option to provide control
  451. # over these cases
  452. if do_builtins:
  453. for typename in builtin_types.keys():
  454. fdef.write(generate_visit_list(typename, None))
  455. for expr in exprs:
  456. if expr.has_key('struct'):
  457. ret = generate_visit_struct(expr)
  458. ret += generate_visit_list(expr['struct'], expr['data'])
  459. fdef.write(ret)
  460. ret = generate_declaration(expr['struct'], expr['data'])
  461. fdecl.write(ret)
  462. elif expr.has_key('union'):
  463. ret = generate_visit_union(expr)
  464. ret += generate_visit_list(expr['union'], expr['data'])
  465. fdef.write(ret)
  466. enum_define = discriminator_find_enum_define(expr)
  467. ret = ""
  468. if not enum_define:
  469. ret = generate_decl_enum('%sKind' % expr['union'],
  470. expr['data'].keys())
  471. ret += generate_declaration(expr['union'], expr['data'])
  472. fdecl.write(ret)
  473. elif expr.has_key('alternate'):
  474. ret = generate_visit_alternate(expr['alternate'], expr['data'])
  475. ret += generate_visit_list(expr['alternate'], expr['data'])
  476. fdef.write(ret)
  477. ret = generate_decl_enum('%sKind' % expr['alternate'],
  478. expr['data'].keys())
  479. ret += generate_declaration(expr['alternate'], expr['data'])
  480. fdecl.write(ret)
  481. elif expr.has_key('enum'):
  482. ret = generate_visit_list(expr['enum'], expr['data'])
  483. ret += generate_visit_enum(expr['enum'], expr['data'])
  484. fdef.write(ret)
  485. ret = generate_decl_enum(expr['enum'], expr['data'])
  486. ret += generate_enum_declaration(expr['enum'], expr['data'])
  487. fdecl.write(ret)
  488. fdecl.write('''
  489. #endif
  490. ''')
  491. fdecl.flush()
  492. fdecl.close()
  493. fdef.flush()
  494. fdef.close()