qapi-visit.py 15 KB

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