]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi-visit.py
qapi: Generate a nicer struct for flat unions
[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 18
be3c7717
MA
19implicit_structs = []
20
21def generate_visit_implicit_struct(type):
22 global implicit_structs
23 if type in implicit_structs:
24 return ''
25 implicit_structs.append(type)
26 return mcgen('''
27
28static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
29{
30 Error *err = NULL;
31
32 visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
33 if (!err) {
297a3646 34 visit_type_%(c_type)s_fields(m, obj, errp);
be3c7717
MA
35 visit_end_implicit_struct(m, &err);
36 }
37 error_propagate(errp, err);
38}
39''',
40 c_type=type_name(type))
41
a82b982e 42def generate_visit_struct_fields(name, members, base = None):
d131c897 43 ret = ''
50f2bdc7 44
be3c7717
MA
45 if base:
46 ret += generate_visit_implicit_struct(base)
47
50f2bdc7
KW
48 ret += mcgen('''
49
a82b982e 50static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
50f2bdc7
KW
51{
52 Error *err = NULL;
53''',
83a02706 54 name=c_name(name))
50f2bdc7 55 push_indent()
d195325b 56
622f557f
KW
57 if base:
58 ret += mcgen('''
a82b982e 59visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
297a3646
MA
60if (err) {
61 goto out;
62}
622f557f 63''',
18df515e 64 type=type_name(base), c_name=c_name('base'))
622f557f 65
6b5abc7d 66 for argname, argentry, optional in parse_args(members):
06d64c62
MR
67 if optional:
68 ret += mcgen('''
a82b982e
EB
69visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
70if (!err && (*obj)->has_%(c_name)s) {
06d64c62 71''',
18df515e 72 c_name=c_name(argname), name=argname)
06d64c62
MR
73 push_indent()
74
6b5abc7d 75 ret += mcgen('''
a82b982e 76visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
06d64c62 77''',
18df515e 78 type=type_name(argentry), c_name=c_name(argname),
6b5abc7d 79 name=argname)
06d64c62
MR
80
81 if optional:
82 pop_indent()
83 ret += mcgen('''
84}
297a3646
MA
85''')
86 ret += mcgen('''
87if (err) {
88 goto out;
89}
d195325b
PB
90''')
91
50f2bdc7 92 pop_indent()
297a3646
MA
93 if re.search('^ *goto out\\;', ret, re.MULTILINE):
94 ret += mcgen('''
50f2bdc7 95
297a3646
MA
96out:
97''')
98 ret += mcgen('''
50f2bdc7
KW
99 error_propagate(errp, err);
100}
101''')
d131c897
KW
102 return ret
103
104
5aa05d3f 105def generate_visit_struct_body(name):
d131c897 106 ret = mcgen('''
297a3646
MA
107 Error *err = NULL;
108
83a02706 109 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
297a3646
MA
110 if (!err) {
111 if (*obj) {
83a02706 112 visit_type_%(c_name)s_fields(m, obj, errp);
297a3646
MA
113 }
114 visit_end_struct(m, &err);
50f2bdc7 115 }
297a3646 116 error_propagate(errp, err);
50f2bdc7 117''',
83a02706 118 name=name, c_name=c_name(name))
d195325b 119
06d64c62
MR
120 return ret
121
14d36307
KW
122def generate_visit_struct(expr):
123
fd41dd4e 124 name = expr['struct']
14d36307 125 members = expr['data']
622f557f 126 base = expr.get('base')
14d36307 127
a82b982e 128 ret = generate_visit_struct_fields(name, members, base)
50f2bdc7
KW
129
130 ret += mcgen('''
06d64c62 131
638ca8ad 132void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
06d64c62 133{
06d64c62 134''',
83a02706 135 name=c_name(name))
d195325b 136
5aa05d3f 137 ret += generate_visit_struct_body(name)
06d64c62
MR
138
139 ret += mcgen('''
06d64c62
MR
140}
141''')
142 return ret
143
5aa05d3f 144def generate_visit_list(name):
06d64c62
MR
145 return mcgen('''
146
638ca8ad 147void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
06d64c62 148{
d195325b 149 Error *err = NULL;
297a3646 150 GenericList *i, **prev;
06d64c62 151
297a3646
MA
152 visit_start_list(m, name, &err);
153 if (err) {
154 goto out;
155 }
156
157 for (prev = (GenericList **)obj;
158 !err && (i = visit_next_list(m, prev, &err)) != NULL;
159 prev = &i) {
160 %(name)sList *native_i = (%(name)sList *)i;
161 visit_type_%(name)s(m, &native_i->value, NULL, &err);
06d64c62 162 }
297a3646
MA
163
164 error_propagate(errp, err);
165 err = NULL;
166 visit_end_list(m, &err);
167out:
168 error_propagate(errp, err);
06d64c62
MR
169}
170''',
fce384b8 171 name=type_name(name))
06d64c62 172
5aa05d3f 173def generate_visit_enum(name):
06d64c62
MR
174 return mcgen('''
175
638ca8ad 176void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
06d64c62
MR
177{
178 visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
179}
180''',
fce384b8 181 name=c_name(name))
06d64c62 182
811d04fd 183def generate_visit_alternate(name, members):
69dd62df
KW
184 ret = mcgen('''
185
638ca8ad 186void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
69dd62df
KW
187{
188 Error *err = NULL;
189
297a3646
MA
190 visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
191 if (err) {
192 goto out;
193 }
194 visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
195 if (err) {
196 goto out_end;
197 }
198 switch ((*obj)->kind) {
69dd62df 199''',
d1f07c86 200 name=c_name(name))
69dd62df 201
ab916fad 202 # For alternate, always use the default enum type automatically generated
d1f07c86
EB
203 # as name + 'Kind'
204 disc_type = c_name(name) + 'Kind'
b0b58195 205
69dd62df 206 for key in members:
b52c4b9c 207 assert (members[key] in builtin_types.keys()
69dd62df 208 or find_struct(members[key])
e775ba77 209 or find_union(members[key])
ab916fad 210 or find_enum(members[key])), "Invalid alternate member"
69dd62df 211
7c81c61f 212 enum_full_value = c_enum_const(disc_type, key)
69dd62df 213 ret += mcgen('''
297a3646
MA
214 case %(enum_full_value)s:
215 visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
216 break;
69dd62df 217''',
b0b58195 218 enum_full_value = enum_full_value,
69dd62df 219 c_type = type_name(members[key]),
18df515e 220 c_name = c_name(key))
69dd62df
KW
221
222 ret += mcgen('''
297a3646
MA
223 default:
224 abort();
69dd62df 225 }
297a3646
MA
226out_end:
227 error_propagate(errp, err);
228 err = NULL;
229 visit_end_implicit_struct(m, &err);
230out:
231 error_propagate(errp, err);
69dd62df
KW
232}
233''')
234
235 return ret
236
237
0aef92b9
KW
238def generate_visit_union(expr):
239
240 name = expr['union']
241 members = expr['data']
242
243 base = expr.get('base')
50f2bdc7 244 discriminator = expr.get('discriminator')
0aef92b9 245
bceae769
WX
246 enum_define = discriminator_find_enum_define(expr)
247 if enum_define:
248 # Use the enum type as discriminator
249 ret = ""
857af5f0 250 disc_type = c_name(enum_define['enum_name'])
bceae769 251 else:
a8d4a2e4 252 # There will always be a discriminator in the C switch code, by default
bb337290 253 # it is an enum type generated silently
5aa05d3f 254 ret = generate_visit_enum(name + 'Kind')
bb337290 255 disc_type = c_name(name) + 'Kind'
06d64c62 256
50f2bdc7 257 if base:
a8d4a2e4
EB
258 assert discriminator
259 base_fields = find_struct(base)['data'].copy()
260 del base_fields[discriminator]
a82b982e 261 ret += generate_visit_struct_fields(name, base_fields)
50f2bdc7 262
be3c7717
MA
263 if discriminator:
264 for key in members:
265 ret += generate_visit_implicit_struct(members[key])
266
06d64c62
MR
267 ret += mcgen('''
268
638ca8ad 269void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
06d64c62 270{
dc8fb6df
PB
271 Error *err = NULL;
272
297a3646
MA
273 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
274 if (err) {
275 goto out;
276 }
277 if (*obj) {
06d64c62 278''',
bb337290 279 name=c_name(name))
06d64c62 280
0aef92b9 281 if base:
50f2bdc7 282 ret += mcgen('''
468866b8 283 visit_type_%(name)s_fields(m, obj, &err);
297a3646
MA
284 if (err) {
285 goto out_obj;
286 }
50f2bdc7 287''',
857af5f0 288 name=c_name(name))
0aef92b9 289
7b75d9d6 290 if not discriminator:
0f61af3e 291 tag = 'kind'
bceae769 292 disc_key = "type"
7b75d9d6 293 else:
0f61af3e 294 tag = discriminator
bceae769 295 disc_key = discriminator
0aef92b9 296 ret += mcgen('''
0f61af3e 297 visit_type_%(disc_type)s(m, &(*obj)->%(c_tag)s, "%(disc_key)s", &err);
297a3646
MA
298 if (err) {
299 goto out_obj;
300 }
cee2dedb
MR
301 if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
302 goto out_obj;
303 }
0f61af3e 304 switch ((*obj)->%(c_tag)s) {
0aef92b9 305''',
bceae769 306 disc_type = disc_type,
0f61af3e 307 c_tag=c_name(tag),
bceae769 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
5aa05d3f 345def generate_declaration(name, 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
5aa05d3f 362def generate_enum_declaration(name):
6540e9f3 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
5aa05d3f 370def generate_decl_enum(name):
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
7c946bc4 377do_builtins = False
8d3bc517 378
2114f5a9
MA
379(input_file, output_dir, do_c, do_h, prefix, opts) = \
380 parse_command_line("b", ["builtins"])
381
06d64c62 382for o, a in opts:
2114f5a9 383 if o in ("-b", "--builtins"):
7c946bc4 384 do_builtins = True
8d3bc517 385
12f8e1b9 386c_comment = '''
06d64c62
MR
387/*
388 * schema-defined QAPI visitor functions
389 *
390 * Copyright IBM, Corp. 2011
391 *
392 * Authors:
393 * Anthony Liguori <aliguori@us.ibm.com>
394 *
395 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
396 * See the COPYING.LIB file in the top-level directory.
397 *
398 */
12f8e1b9
MA
399'''
400h_comment = '''
06d64c62 401/*
297a3646 402 * schema-defined QAPI visitor functions
06d64c62
MR
403 *
404 * Copyright IBM, Corp. 2011
405 *
406 * Authors:
407 * Anthony Liguori <aliguori@us.ibm.com>
408 *
409 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
410 * See the COPYING.LIB file in the top-level directory.
411 *
412 */
12f8e1b9
MA
413'''
414
415(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
416 'qapi-visit.c', 'qapi-visit.h',
417 c_comment, h_comment)
06d64c62 418
12f8e1b9
MA
419fdef.write(mcgen('''
420#include "qemu-common.h"
421#include "%(prefix)sqapi-visit.h"
422''',
423 prefix = prefix))
06d64c62 424
12f8e1b9 425fdecl.write(mcgen('''
7b1b5d19 426#include "qapi/visitor.h"
06d64c62 427#include "%(prefix)sqapi-types.h"
7c946bc4 428
06d64c62 429''',
12f8e1b9 430 prefix=prefix))
06d64c62 431
33aaad52 432exprs = parse_schema(input_file)
06d64c62 433
7c946bc4
MR
434# to avoid header dependency hell, we always generate declarations
435# for built-in types in our header files and simply guard them
436fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
b52c4b9c 437for typename in builtin_types.keys():
5aa05d3f 438 fdecl.write(generate_declaration(typename, builtin_type=True))
7c946bc4
MR
439fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
440
441# ...this doesn't work for cases where we link in multiple objects that
442# have the functions defined, so we use -b option to provide control
443# over these cases
444if do_builtins:
b52c4b9c 445 for typename in builtin_types.keys():
5aa05d3f 446 fdef.write(generate_visit_list(typename))
7c946bc4 447
06d64c62 448for expr in exprs:
fd41dd4e 449 if expr.has_key('struct'):
14d36307 450 ret = generate_visit_struct(expr)
5aa05d3f 451 ret += generate_visit_list(expr['struct'])
06d64c62
MR
452 fdef.write(ret)
453
5aa05d3f 454 ret = generate_declaration(expr['struct'])
06d64c62
MR
455 fdecl.write(ret)
456 elif expr.has_key('union'):
0aef92b9 457 ret = generate_visit_union(expr)
5aa05d3f 458 ret += generate_visit_list(expr['union'])
06d64c62
MR
459 fdef.write(ret)
460
bceae769
WX
461 enum_define = discriminator_find_enum_define(expr)
462 ret = ""
463 if not enum_define:
5aa05d3f
MA
464 ret = generate_decl_enum('%sKind' % expr['union'])
465 ret += generate_declaration(expr['union'])
06d64c62 466 fdecl.write(ret)
ab916fad
EB
467 elif expr.has_key('alternate'):
468 ret = generate_visit_alternate(expr['alternate'], expr['data'])
5aa05d3f 469 ret += generate_visit_list(expr['alternate'])
ab916fad
EB
470 fdef.write(ret)
471
5aa05d3f
MA
472 ret = generate_decl_enum('%sKind' % expr['alternate'])
473 ret += generate_declaration(expr['alternate'])
ab916fad 474 fdecl.write(ret)
06d64c62 475 elif expr.has_key('enum'):
5aa05d3f
MA
476 ret = generate_visit_list(expr['enum'])
477 ret += generate_visit_enum(expr['enum'])
06d64c62
MR
478 fdef.write(ret)
479
5aa05d3f
MA
480 ret = generate_decl_enum(expr['enum'])
481 ret += generate_enum_declaration(expr['enum'])
06d64c62
MR
482 fdecl.write(ret)
483
12f8e1b9 484close_output(fdef, fdecl)