qapi-visit.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. #
  2. # QAPI visitor generator
  3. #
  4. # Copyright IBM, Corp. 2011
  5. # Copyright (C) 2014 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['type']
  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_anon_union(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 anon union, 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
  221. or find_struct(members[key])
  222. or find_union(members[key])), "Invalid anonymous union member"
  223. enum_full_value = generate_enum_full_value(disc_type, key)
  224. ret += mcgen('''
  225. case %(enum_full_value)s:
  226. visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
  227. break;
  228. ''',
  229. enum_full_value = enum_full_value,
  230. c_type = type_name(members[key]),
  231. c_name = c_fun(key))
  232. ret += mcgen('''
  233. default:
  234. abort();
  235. }
  236. out_end:
  237. error_propagate(errp, err);
  238. err = NULL;
  239. visit_end_implicit_struct(m, &err);
  240. out:
  241. error_propagate(errp, err);
  242. }
  243. ''')
  244. return ret
  245. def generate_visit_union(expr):
  246. name = expr['union']
  247. members = expr['data']
  248. base = expr.get('base')
  249. discriminator = expr.get('discriminator')
  250. if discriminator == {}:
  251. assert not base
  252. return generate_visit_anon_union(name, members)
  253. enum_define = discriminator_find_enum_define(expr)
  254. if enum_define:
  255. # Use the enum type as discriminator
  256. ret = ""
  257. disc_type = enum_define['enum_name']
  258. else:
  259. # There will always be a discriminator in the C switch code, by default it
  260. # is an enum type generated silently as "'%sKind' % (name)"
  261. ret = generate_visit_enum('%sKind' % name, members.keys())
  262. disc_type = '%sKind' % (name)
  263. if base:
  264. base_fields = find_struct(base)['data']
  265. if discriminator:
  266. base_fields = base_fields.copy()
  267. del base_fields[discriminator]
  268. ret += generate_visit_struct_fields(name, "", "", base_fields)
  269. if discriminator:
  270. for key in members:
  271. ret += generate_visit_implicit_struct(members[key])
  272. ret += mcgen('''
  273. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
  274. {
  275. Error *err = NULL;
  276. visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
  277. if (err) {
  278. goto out;
  279. }
  280. if (*obj) {
  281. ''',
  282. name=name)
  283. if base:
  284. ret += mcgen('''
  285. visit_type_%(name)s_fields(m, obj, &err);
  286. if (err) {
  287. goto out_obj;
  288. }
  289. ''',
  290. name=name)
  291. if not discriminator:
  292. disc_key = "type"
  293. else:
  294. disc_key = discriminator
  295. ret += mcgen('''
  296. visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
  297. if (err) {
  298. goto out_obj;
  299. }
  300. if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
  301. goto out_obj;
  302. }
  303. switch ((*obj)->kind) {
  304. ''',
  305. disc_type = disc_type,
  306. disc_key = disc_key)
  307. for key in members:
  308. if not discriminator:
  309. fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
  310. else:
  311. fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
  312. enum_full_value = generate_enum_full_value(disc_type, key)
  313. ret += mcgen('''
  314. case %(enum_full_value)s:
  315. ''' + fmt + '''
  316. break;
  317. ''',
  318. enum_full_value = enum_full_value,
  319. c_type=type_name(members[key]),
  320. c_name=c_fun(key))
  321. ret += mcgen('''
  322. default:
  323. abort();
  324. }
  325. out_obj:
  326. error_propagate(errp, err);
  327. err = NULL;
  328. visit_end_union(m, !!(*obj)->data, &err);
  329. error_propagate(errp, err);
  330. err = NULL;
  331. }
  332. visit_end_struct(m, &err);
  333. out:
  334. error_propagate(errp, err);
  335. }
  336. ''')
  337. return ret
  338. def generate_declaration(name, members, genlist=True, builtin_type=False):
  339. ret = ""
  340. if not builtin_type:
  341. ret += mcgen('''
  342. void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
  343. ''',
  344. name=name)
  345. if genlist:
  346. ret += mcgen('''
  347. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
  348. ''',
  349. name=name)
  350. return ret
  351. def generate_enum_declaration(name, members, genlist=True):
  352. ret = ""
  353. if genlist:
  354. ret += mcgen('''
  355. void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
  356. ''',
  357. name=name)
  358. return ret
  359. def generate_decl_enum(name, members, genlist=True):
  360. return mcgen('''
  361. void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
  362. ''',
  363. name=name)
  364. try:
  365. opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
  366. ["source", "header", "builtins", "prefix=",
  367. "input-file=", "output-dir="])
  368. except getopt.GetoptError, err:
  369. print str(err)
  370. sys.exit(1)
  371. input_file = ""
  372. output_dir = ""
  373. prefix = ""
  374. c_file = 'qapi-visit.c'
  375. h_file = 'qapi-visit.h'
  376. do_c = False
  377. do_h = False
  378. do_builtins = False
  379. for o, a in opts:
  380. if o in ("-p", "--prefix"):
  381. prefix = a
  382. elif o in ("-i", "--input-file"):
  383. input_file = a
  384. elif o in ("-o", "--output-dir"):
  385. output_dir = a + "/"
  386. elif o in ("-c", "--source"):
  387. do_c = True
  388. elif o in ("-h", "--header"):
  389. do_h = True
  390. elif o in ("-b", "--builtins"):
  391. do_builtins = True
  392. if not do_c and not do_h:
  393. do_c = True
  394. do_h = True
  395. c_file = output_dir + prefix + c_file
  396. h_file = output_dir + prefix + h_file
  397. try:
  398. os.makedirs(output_dir)
  399. except os.error, e:
  400. if e.errno != errno.EEXIST:
  401. raise
  402. def maybe_open(really, name, opt):
  403. if really:
  404. return open(name, opt)
  405. else:
  406. import StringIO
  407. return StringIO.StringIO()
  408. fdef = maybe_open(do_c, c_file, 'w')
  409. fdecl = maybe_open(do_h, h_file, 'w')
  410. fdef.write(mcgen('''
  411. /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
  412. /*
  413. * schema-defined QAPI visitor functions
  414. *
  415. * Copyright IBM, Corp. 2011
  416. *
  417. * Authors:
  418. * Anthony Liguori <aliguori@us.ibm.com>
  419. *
  420. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  421. * See the COPYING.LIB file in the top-level directory.
  422. *
  423. */
  424. #include "qemu-common.h"
  425. #include "%(header)s"
  426. ''',
  427. header=basename(h_file)))
  428. fdecl.write(mcgen('''
  429. /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
  430. /*
  431. * schema-defined QAPI visitor functions
  432. *
  433. * Copyright IBM, Corp. 2011
  434. *
  435. * Authors:
  436. * Anthony Liguori <aliguori@us.ibm.com>
  437. *
  438. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  439. * See the COPYING.LIB file in the top-level directory.
  440. *
  441. */
  442. #ifndef %(guard)s
  443. #define %(guard)s
  444. #include "qapi/visitor.h"
  445. #include "%(prefix)sqapi-types.h"
  446. ''',
  447. prefix=prefix, guard=guardname(h_file)))
  448. exprs = parse_schema(input_file)
  449. # to avoid header dependency hell, we always generate declarations
  450. # for built-in types in our header files and simply guard them
  451. fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
  452. for typename in builtin_types:
  453. fdecl.write(generate_declaration(typename, None, genlist=True,
  454. builtin_type=True))
  455. fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
  456. # ...this doesn't work for cases where we link in multiple objects that
  457. # have the functions defined, so we use -b option to provide control
  458. # over these cases
  459. if do_builtins:
  460. for typename in builtin_types:
  461. fdef.write(generate_visit_list(typename, None))
  462. for expr in exprs:
  463. if expr.has_key('type'):
  464. ret = generate_visit_struct(expr)
  465. ret += generate_visit_list(expr['type'], expr['data'])
  466. fdef.write(ret)
  467. ret = generate_declaration(expr['type'], expr['data'])
  468. fdecl.write(ret)
  469. elif expr.has_key('union'):
  470. ret = generate_visit_union(expr)
  471. ret += generate_visit_list(expr['union'], expr['data'])
  472. fdef.write(ret)
  473. enum_define = discriminator_find_enum_define(expr)
  474. ret = ""
  475. if not enum_define:
  476. ret = generate_decl_enum('%sKind' % expr['union'],
  477. expr['data'].keys())
  478. ret += generate_declaration(expr['union'], expr['data'])
  479. fdecl.write(ret)
  480. elif expr.has_key('enum'):
  481. ret = generate_visit_list(expr['enum'], expr['data'])
  482. ret += generate_visit_enum(expr['enum'], expr['data'])
  483. fdef.write(ret)
  484. ret = generate_decl_enum(expr['enum'], expr['data'])
  485. ret += generate_enum_declaration(expr['enum'], expr['data'])
  486. fdecl.write(ret)
  487. fdecl.write('''
  488. #endif
  489. ''')
  490. fdecl.flush()
  491. fdecl.close()
  492. fdef.flush()
  493. fdef.close()