]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi-visit.py
qapi: Consistent generated code: prefer common labels
[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 14
06d64c62 15from qapi import *
297a3646 16import re
06d64c62 17
8c07eddc 18implicit_structs_seen = set()
8c3f8e77 19struct_fields_seen = set()
be3c7717 20
e98859a9 21
60f8546a
MA
22def gen_visit_decl(name, scalar=False):
23 c_type = c_name(name) + ' *'
24 if not scalar:
25 c_type += '*'
26 return mcgen('''
f8b7f1a8 27void visit_type_%(c_name)s(Visitor *v, %(c_type)sobj, const char *name, Error **errp);
60f8546a
MA
28''',
29 c_name=c_name(name), c_type=c_type)
30
31
e98859a9
MA
32def gen_visit_implicit_struct(typ):
33 if typ in implicit_structs_seen:
be3c7717 34 return ''
e98859a9
MA
35 implicit_structs_seen.add(typ)
36
8c3f8e77 37 ret = ''
e98859a9 38 if typ.name not in struct_fields_seen:
8c3f8e77
MA
39 # Need a forward declaration
40 ret += mcgen('''
41
f8b7f1a8 42static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp);
8c3f8e77 43''',
e98859a9 44 c_type=typ.c_name())
8c3f8e77
MA
45
46 ret += mcgen('''
be3c7717 47
f8b7f1a8 48static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error **errp)
be3c7717
MA
49{
50 Error *err = NULL;
51
f8b7f1a8 52 visit_start_implicit_struct(v, (void **)obj, sizeof(%(c_type)s), &err);
be3c7717 53 if (!err) {
f8b7f1a8
EB
54 visit_type_%(c_type)s_fields(v, obj, errp);
55 visit_end_implicit_struct(v, &err);
be3c7717
MA
56 }
57 error_propagate(errp, err);
58}
59''',
e98859a9 60 c_type=typ.c_name())
8c3f8e77 61 return ret
be3c7717 62
e98859a9
MA
63
64def gen_visit_struct_fields(name, base, members):
8c3f8e77
MA
65 struct_fields_seen.add(name)
66
d131c897 67 ret = ''
50f2bdc7 68
be3c7717 69 if base:
e98859a9 70 ret += gen_visit_implicit_struct(base)
be3c7717 71
50f2bdc7
KW
72 ret += mcgen('''
73
f8b7f1a8 74static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **errp)
50f2bdc7
KW
75{
76 Error *err = NULL;
3a864e7c 77
50f2bdc7 78''',
e98859a9 79 c_name=c_name(name))
50f2bdc7 80 push_indent()
d195325b 81
622f557f
KW
82 if base:
83 ret += mcgen('''
f8b7f1a8 84visit_type_implicit_%(c_type)s(v, &(*obj)->%(c_name)s, &err);
297a3646
MA
85if (err) {
86 goto out;
87}
622f557f 88''',
e98859a9 89 c_type=base.c_name(), c_name=c_name('base'))
622f557f 90
441cbac0
MA
91 for memb in members:
92 if memb.optional:
06d64c62 93 ret += mcgen('''
f8b7f1a8 94visit_optional(v, &(*obj)->has_%(c_name)s, "%(name)s", &err);
a82b982e 95if (!err && (*obj)->has_%(c_name)s) {
06d64c62 96''',
441cbac0 97 c_name=c_name(memb.name), name=memb.name)
06d64c62
MR
98 push_indent()
99
6b5abc7d 100 ret += mcgen('''
f8b7f1a8 101visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
06d64c62 102''',
e98859a9 103 c_type=memb.type.c_name(), c_name=c_name(memb.name),
441cbac0 104 name=memb.name)
06d64c62 105
441cbac0 106 if memb.optional:
06d64c62
MR
107 pop_indent()
108 ret += mcgen('''
109}
297a3646
MA
110''')
111 ret += mcgen('''
112if (err) {
113 goto out;
114}
d195325b
PB
115''')
116
50f2bdc7 117 pop_indent()
e98859a9 118 if re.search('^ *goto out;', ret, re.MULTILINE):
297a3646 119 ret += mcgen('''
50f2bdc7 120
297a3646
MA
121out:
122''')
123 ret += mcgen('''
50f2bdc7
KW
124 error_propagate(errp, err);
125}
126''')
d131c897
KW
127 return ret
128
129
60f8546a
MA
130def gen_visit_struct(name, base, members):
131 ret = gen_visit_struct_fields(name, base, members)
132
2f52e205
EB
133 # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
134 # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
135 # rather than leaving it non-NULL. As currently written, the caller must
136 # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
60f8546a
MA
137 ret += mcgen('''
138
f8b7f1a8 139void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
60f8546a 140{
297a3646
MA
141 Error *err = NULL;
142
f8b7f1a8 143 visit_start_struct(v, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
297a3646
MA
144 if (!err) {
145 if (*obj) {
f8b7f1a8 146 visit_type_%(c_name)s_fields(v, obj, errp);
297a3646 147 }
f8b7f1a8 148 visit_end_struct(v, &err);
50f2bdc7 149 }
297a3646 150 error_propagate(errp, err);
60f8546a 151}
50f2bdc7 152''',
60f8546a 153 name=name, c_name=c_name(name))
06d64c62 154
06d64c62
MR
155 return ret
156
e98859a9 157
441cbac0 158def gen_visit_list(name, element_type):
06d64c62
MR
159 return mcgen('''
160
f8b7f1a8 161void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
06d64c62 162{
d195325b 163 Error *err = NULL;
297a3646 164 GenericList *i, **prev;
06d64c62 165
f8b7f1a8 166 visit_start_list(v, name, &err);
297a3646
MA
167 if (err) {
168 goto out;
169 }
170
171 for (prev = (GenericList **)obj;
f8b7f1a8 172 !err && (i = visit_next_list(v, prev, &err)) != NULL;
297a3646 173 prev = &i) {
e98859a9 174 %(c_name)s *native_i = (%(c_name)s *)i;
f8b7f1a8 175 visit_type_%(c_elt_type)s(v, &native_i->value, NULL, &err);
06d64c62 176 }
297a3646
MA
177
178 error_propagate(errp, err);
179 err = NULL;
f8b7f1a8 180 visit_end_list(v, &err);
297a3646
MA
181out:
182 error_propagate(errp, err);
06d64c62
MR
183}
184''',
e98859a9 185 c_name=c_name(name), c_elt_type=element_type.c_name())
06d64c62 186
e98859a9
MA
187
188def gen_visit_enum(name):
06d64c62
MR
189 return mcgen('''
190
f8b7f1a8 191void visit_type_%(c_name)s(Visitor *v, %(c_name)s *obj, const char *name, Error **errp)
06d64c62 192{
f8b7f1a8 193 visit_type_enum(v, (int *)obj, %(c_name)s_lookup, "%(name)s", name, errp);
06d64c62
MR
194}
195''',
40b3adec 196 c_name=c_name(name), name=name)
06d64c62 197
e98859a9 198
441cbac0 199def gen_visit_alternate(name, variants):
69dd62df
KW
200 ret = mcgen('''
201
f8b7f1a8 202void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
69dd62df
KW
203{
204 Error *err = NULL;
205
f8b7f1a8 206 visit_start_implicit_struct(v, (void**) obj, sizeof(%(c_name)s), &err);
297a3646
MA
207 if (err) {
208 goto out;
209 }
f8b7f1a8 210 visit_get_next_type(v, (int*) &(*obj)->kind, %(c_name)s_qtypes, name, &err);
297a3646 211 if (err) {
f782399c 212 goto out_obj;
297a3646
MA
213 }
214 switch ((*obj)->kind) {
69dd62df 215''',
e98859a9 216 c_name=c_name(name))
69dd62df 217
441cbac0 218 for var in variants.variants:
69dd62df 219 ret += mcgen('''
e98859a9 220 case %(case)s:
f8b7f1a8 221 visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, name, &err);
297a3646 222 break;
69dd62df 223''',
e98859a9
MA
224 case=c_enum_const(variants.tag_member.type.name,
225 var.name),
226 c_type=var.type.c_name(),
227 c_name=c_name(var.name))
69dd62df
KW
228
229 ret += mcgen('''
297a3646
MA
230 default:
231 abort();
69dd62df 232 }
f782399c 233out_obj:
297a3646
MA
234 error_propagate(errp, err);
235 err = NULL;
f8b7f1a8 236 visit_end_implicit_struct(v, &err);
297a3646
MA
237out:
238 error_propagate(errp, err);
69dd62df
KW
239}
240''')
241
242 return ret
243
e98859a9 244
441cbac0
MA
245def gen_visit_union(name, base, variants):
246 ret = ''
06d64c62 247
50f2bdc7 248 if base:
441cbac0 249 members = [m for m in base.members if m != variants.tag_member]
e98859a9 250 ret += gen_visit_struct_fields(name, None, members)
50f2bdc7 251
441cbac0
MA
252 for var in variants.variants:
253 # Ugly special case for simple union TODO get rid of it
254 if not var.simple_union_type():
e98859a9 255 ret += gen_visit_implicit_struct(var.type)
be3c7717 256
06d64c62
MR
257 ret += mcgen('''
258
f8b7f1a8 259void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
06d64c62 260{
dc8fb6df
PB
261 Error *err = NULL;
262
f8b7f1a8 263 visit_start_struct(v, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
297a3646
MA
264 if (err) {
265 goto out;
266 }
267 if (*obj) {
06d64c62 268''',
40b3adec 269 c_name=c_name(name), name=name)
06d64c62 270
0aef92b9 271 if base:
50f2bdc7 272 ret += mcgen('''
f8b7f1a8 273 visit_type_%(c_name)s_fields(v, obj, &err);
297a3646
MA
274 if (err) {
275 goto out_obj;
276 }
50f2bdc7 277''',
e98859a9 278 c_name=c_name(name))
0aef92b9 279
e98859a9 280 tag_key = variants.tag_member.name
441cbac0
MA
281 if not variants.tag_name:
282 # we pointlessly use a different key for simple unions
e98859a9 283 tag_key = 'type'
0aef92b9 284 ret += mcgen('''
f8b7f1a8 285 visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
297a3646
MA
286 if (err) {
287 goto out_obj;
288 }
f8b7f1a8 289 if (!visit_start_union(v, !!(*obj)->data, &err) || err) {
cee2dedb
MR
290 goto out_obj;
291 }
441cbac0 292 switch ((*obj)->%(c_name)s) {
0aef92b9 293''',
e98859a9 294 c_type=variants.tag_member.type.c_name(),
441cbac0
MA
295 # TODO ugly special case for simple union
296 # Use same tag name in C as on the wire to get rid of
297 # it, then: c_name=c_name(variants.tag_member.name)
298 c_name=c_name(variants.tag_name or 'kind'),
e98859a9 299 name=tag_key)
0aef92b9 300
441cbac0
MA
301 for var in variants.variants:
302 # TODO ugly special case for simple union
303 simple_union_type = var.simple_union_type()
e98859a9
MA
304 ret += mcgen('''
305 case %(case)s:
306''',
307 case=c_enum_const(variants.tag_member.type.name,
308 var.name))
441cbac0 309 if simple_union_type:
e98859a9 310 ret += mcgen('''
f8b7f1a8 311 visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "data", &err);
e98859a9
MA
312''',
313 c_type=simple_union_type.c_name(),
314 c_name=c_name(var.name))
50f2bdc7 315 else:
e98859a9 316 ret += mcgen('''
f8b7f1a8 317 visit_type_implicit_%(c_type)s(v, &(*obj)->%(c_name)s, &err);
e98859a9
MA
318''',
319 c_type=var.type.c_name(),
320 c_name=c_name(var.name))
dc8fb6df 321 ret += mcgen('''
297a3646 322 break;
e98859a9 323''')
dc8fb6df
PB
324
325 ret += mcgen('''
297a3646
MA
326 default:
327 abort();
d195325b 328 }
297a3646 329out_obj:
d195325b
PB
330 error_propagate(errp, err);
331 err = NULL;
f8b7f1a8 332 visit_end_union(v, !!(*obj)->data, &err);
cee2dedb
MR
333 error_propagate(errp, err);
334 err = NULL;
468866b8 335 }
f8b7f1a8 336 visit_end_struct(v, &err);
297a3646
MA
337out:
338 error_propagate(errp, err);
dc8fb6df
PB
339}
340''')
341
06d64c62
MR
342 return ret
343
e98859a9 344
441cbac0
MA
345class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
346 def __init__(self):
347 self.decl = None
348 self.defn = None
349 self._btin = None
350
351 def visit_begin(self, schema):
352 self.decl = ''
353 self.defn = ''
354 self._btin = guardstart('QAPI_VISIT_BUILTIN')
355
356 def visit_end(self):
357 # To avoid header dependency hell, we always generate
358 # declarations for built-in types in our header files and
359 # simply guard them. See also do_builtins (command line
360 # option -b).
361 self._btin += guardend('QAPI_VISIT_BUILTIN')
362 self.decl = self._btin + self.decl
363 self._btin = None
364
365 def visit_enum_type(self, name, info, values, prefix):
366 self.decl += gen_visit_decl(name, scalar=True)
e98859a9 367 self.defn += gen_visit_enum(name)
441cbac0
MA
368
369 def visit_array_type(self, name, info, element_type):
370 decl = gen_visit_decl(name)
371 defn = gen_visit_list(name, element_type)
372 if isinstance(element_type, QAPISchemaBuiltinType):
373 self._btin += decl
374 if do_builtins:
375 self.defn += defn
376 else:
377 self.decl += decl
378 self.defn += defn
379
380 def visit_object_type(self, name, info, base, members, variants):
381 if info:
382 self.decl += gen_visit_decl(name)
383 if variants:
384 assert not members # not implemented
385 self.defn += gen_visit_union(name, base, variants)
386 else:
387 self.defn += gen_visit_struct(name, base, members)
388
389 def visit_alternate_type(self, name, info, variants):
390 self.decl += gen_visit_decl(name)
391 self.defn += gen_visit_alternate(name, variants)
392
393# If you link code generated from multiple schemata, you want only one
394# instance of the code for built-in types. Generate it only when
395# do_builtins, enabled by command line option -b. See also
396# QAPISchemaGenVisitVisitor.visit_end().
7c946bc4 397do_builtins = False
8d3bc517 398
2114f5a9
MA
399(input_file, output_dir, do_c, do_h, prefix, opts) = \
400 parse_command_line("b", ["builtins"])
401
06d64c62 402for o, a in opts:
2114f5a9 403 if o in ("-b", "--builtins"):
7c946bc4 404 do_builtins = True
8d3bc517 405
12f8e1b9 406c_comment = '''
06d64c62
MR
407/*
408 * schema-defined QAPI visitor functions
409 *
410 * Copyright IBM, Corp. 2011
411 *
412 * Authors:
413 * Anthony Liguori <aliguori@us.ibm.com>
414 *
415 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
416 * See the COPYING.LIB file in the top-level directory.
417 *
418 */
12f8e1b9
MA
419'''
420h_comment = '''
06d64c62 421/*
297a3646 422 * schema-defined QAPI visitor functions
06d64c62
MR
423 *
424 * Copyright IBM, Corp. 2011
425 *
426 * Authors:
427 * Anthony Liguori <aliguori@us.ibm.com>
428 *
429 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
430 * See the COPYING.LIB file in the top-level directory.
431 *
432 */
12f8e1b9
MA
433'''
434
435(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
436 'qapi-visit.c', 'qapi-visit.h',
437 c_comment, h_comment)
06d64c62 438
12f8e1b9
MA
439fdef.write(mcgen('''
440#include "qemu-common.h"
441#include "%(prefix)sqapi-visit.h"
442''',
e98859a9 443 prefix=prefix))
06d64c62 444
12f8e1b9 445fdecl.write(mcgen('''
7b1b5d19 446#include "qapi/visitor.h"
06d64c62 447#include "%(prefix)sqapi-types.h"
7c946bc4 448
06d64c62 449''',
12f8e1b9 450 prefix=prefix))
06d64c62 451
441cbac0
MA
452schema = QAPISchema(input_file)
453gen = QAPISchemaGenVisitVisitor()
454schema.visit(gen)
455fdef.write(gen.defn)
456fdecl.write(gen.decl)
06d64c62 457
12f8e1b9 458close_output(fdef, fdecl)