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