qapi: Fix generated code when flat union has member 'kind'
[qemu/ar7.git] / scripts / qapi-visit.py
blob4ec79a6db8df463285f9a56055b69e0c83ec1851
2 # QAPI visitor generator
4 # Copyright IBM, Corp. 2011
5 # Copyright (C) 2014-2015 Red Hat, Inc.
7 # Authors:
8 # Anthony Liguori <aliguori@us.ibm.com>
9 # Michael Roth <mdroth@linux.vnet.ibm.com>
10 # Markus Armbruster <armbru@redhat.com>
12 # This work is licensed under the terms of the GNU GPL, version 2.
13 # See the COPYING file in the top-level directory.
15 from ordereddict import OrderedDict
16 from qapi import *
17 import re
19 implicit_structs = []
21 def 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('''
28 static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
30 Error *err = NULL;
32 visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
33 if (!err) {
34 visit_type_%(c_type)s_fields(m, obj, errp);
35 visit_end_implicit_struct(m, &err);
37 error_propagate(errp, err);
39 ''',
40 c_type=type_name(type))
42 def generate_visit_struct_fields(name, members, base = None):
43 ret = ''
45 if base:
46 ret += generate_visit_implicit_struct(base)
48 ret += mcgen('''
50 static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
52 Error *err = NULL;
53 ''',
54 name=c_name(name))
55 push_indent()
57 if base:
58 ret += mcgen('''
59 visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
60 if (err) {
61 goto out;
63 ''',
64 type=type_name(base), c_name=c_name('base'))
66 for argname, argentry, optional in parse_args(members):
67 if optional:
68 ret += mcgen('''
69 visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
70 if (!err && (*obj)->has_%(c_name)s) {
71 ''',
72 c_name=c_name(argname), name=argname)
73 push_indent()
75 ret += mcgen('''
76 visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
77 ''',
78 type=type_name(argentry), c_name=c_name(argname),
79 name=argname)
81 if optional:
82 pop_indent()
83 ret += mcgen('''
85 ''')
86 ret += mcgen('''
87 if (err) {
88 goto out;
90 ''')
92 pop_indent()
93 if re.search('^ *goto out\\;', ret, re.MULTILINE):
94 ret += mcgen('''
96 out:
97 ''')
98 ret += mcgen('''
99 error_propagate(errp, err);
101 ''')
102 return ret
105 def generate_visit_struct_body(name):
106 ret = mcgen('''
107 Error *err = NULL;
109 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
110 if (!err) {
111 if (*obj) {
112 visit_type_%(c_name)s_fields(m, obj, errp);
114 visit_end_struct(m, &err);
116 error_propagate(errp, err);
117 ''',
118 name=name, c_name=c_name(name))
120 return ret
122 def generate_visit_struct(expr):
124 name = expr['struct']
125 members = expr['data']
126 base = expr.get('base')
128 ret = generate_visit_struct_fields(name, members, base)
130 ret += mcgen('''
132 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
134 ''',
135 name=c_name(name))
137 ret += generate_visit_struct_body(name)
139 ret += mcgen('''
141 ''')
142 return ret
144 def generate_visit_list(name):
145 return mcgen('''
147 void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
149 Error *err = NULL;
150 GenericList *i, **prev;
152 visit_start_list(m, name, &err);
153 if (err) {
154 goto out;
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);
164 error_propagate(errp, err);
165 err = NULL;
166 visit_end_list(m, &err);
167 out:
168 error_propagate(errp, err);
170 ''',
171 name=type_name(name))
173 def generate_visit_enum(name):
174 return mcgen('''
176 void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
178 visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
180 ''',
181 name=c_name(name))
183 def generate_visit_alternate(name, members):
184 ret = mcgen('''
186 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
188 Error *err = NULL;
190 visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
191 if (err) {
192 goto out;
194 visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
195 if (err) {
196 goto out_end;
198 switch ((*obj)->kind) {
199 ''',
200 name=c_name(name))
202 # For alternate, always use the default enum type automatically generated
203 # as name + 'Kind'
204 disc_type = c_name(name) + 'Kind'
206 for key in members:
207 assert (members[key] in builtin_types.keys()
208 or find_struct(members[key])
209 or find_union(members[key])
210 or find_enum(members[key])), "Invalid alternate member"
212 enum_full_value = c_enum_const(disc_type, key)
213 ret += mcgen('''
214 case %(enum_full_value)s:
215 visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
216 break;
217 ''',
218 enum_full_value = enum_full_value,
219 c_type = type_name(members[key]),
220 c_name = c_name(key))
222 ret += mcgen('''
223 default:
224 abort();
226 out_end:
227 error_propagate(errp, err);
228 err = NULL;
229 visit_end_implicit_struct(m, &err);
230 out:
231 error_propagate(errp, err);
233 ''')
235 return ret
238 def generate_visit_union(expr):
240 name = expr['union']
241 members = expr['data']
243 base = expr.get('base')
244 discriminator = expr.get('discriminator')
246 enum_define = discriminator_find_enum_define(expr)
247 if enum_define:
248 # Use the enum type as discriminator
249 ret = ""
250 disc_type = c_name(enum_define['enum_name'])
251 else:
252 # There will always be a discriminator in the C switch code, by default
253 # it is an enum type generated silently
254 ret = generate_visit_enum(name + 'Kind')
255 disc_type = c_name(name) + 'Kind'
257 if base:
258 assert discriminator
259 base_fields = find_struct(base)['data'].copy()
260 del base_fields[discriminator]
261 ret += generate_visit_struct_fields(name, base_fields)
263 if discriminator:
264 for key in members:
265 ret += generate_visit_implicit_struct(members[key])
267 ret += mcgen('''
269 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
271 Error *err = NULL;
273 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
274 if (err) {
275 goto out;
277 if (*obj) {
278 ''',
279 name=c_name(name))
281 if base:
282 ret += mcgen('''
283 visit_type_%(name)s_fields(m, obj, &err);
284 if (err) {
285 goto out_obj;
287 ''',
288 name=c_name(name))
290 if not discriminator:
291 tag = 'kind'
292 disc_key = "type"
293 else:
294 tag = discriminator
295 disc_key = discriminator
296 ret += mcgen('''
297 visit_type_%(disc_type)s(m, &(*obj)->%(c_tag)s, "%(disc_key)s", &err);
298 if (err) {
299 goto out_obj;
301 if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
302 goto out_obj;
304 switch ((*obj)->%(c_tag)s) {
305 ''',
306 disc_type = disc_type,
307 c_tag=c_name(tag),
308 disc_key = disc_key)
310 for key in members:
311 if not discriminator:
312 fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
313 else:
314 fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
316 enum_full_value = c_enum_const(disc_type, key)
317 ret += mcgen('''
318 case %(enum_full_value)s:
319 ''' + fmt + '''
320 break;
321 ''',
322 enum_full_value = enum_full_value,
323 c_type=type_name(members[key]),
324 c_name=c_name(key))
326 ret += mcgen('''
327 default:
328 abort();
330 out_obj:
331 error_propagate(errp, err);
332 err = NULL;
333 visit_end_union(m, !!(*obj)->data, &err);
334 error_propagate(errp, err);
335 err = NULL;
337 visit_end_struct(m, &err);
338 out:
339 error_propagate(errp, err);
341 ''')
343 return ret
345 def generate_declaration(name, builtin_type=False):
346 ret = ""
347 if not builtin_type:
348 name = c_name(name)
349 ret += mcgen('''
351 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
352 ''',
353 name=name)
355 ret += mcgen('''
356 void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
357 ''',
358 name=name)
360 return ret
362 def generate_enum_declaration(name):
363 ret = mcgen('''
364 void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
365 ''',
366 name=c_name(name))
368 return ret
370 def generate_decl_enum(name):
371 return mcgen('''
373 void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
374 ''',
375 name=c_name(name))
377 do_builtins = False
379 (input_file, output_dir, do_c, do_h, prefix, opts) = \
380 parse_command_line("b", ["builtins"])
382 for o, a in opts:
383 if o in ("-b", "--builtins"):
384 do_builtins = True
386 c_comment = '''
388 * schema-defined QAPI visitor functions
390 * Copyright IBM, Corp. 2011
392 * Authors:
393 * Anthony Liguori <aliguori@us.ibm.com>
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.
400 h_comment = '''
402 * schema-defined QAPI visitor functions
404 * Copyright IBM, Corp. 2011
406 * Authors:
407 * Anthony Liguori <aliguori@us.ibm.com>
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.
415 (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
416 'qapi-visit.c', 'qapi-visit.h',
417 c_comment, h_comment)
419 fdef.write(mcgen('''
420 #include "qemu-common.h"
421 #include "%(prefix)sqapi-visit.h"
422 ''',
423 prefix = prefix))
425 fdecl.write(mcgen('''
426 #include "qapi/visitor.h"
427 #include "%(prefix)sqapi-types.h"
429 ''',
430 prefix=prefix))
432 exprs = parse_schema(input_file)
434 # to avoid header dependency hell, we always generate declarations
435 # for built-in types in our header files and simply guard them
436 fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
437 for typename in builtin_types.keys():
438 fdecl.write(generate_declaration(typename, builtin_type=True))
439 fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
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
444 if do_builtins:
445 for typename in builtin_types.keys():
446 fdef.write(generate_visit_list(typename))
448 for expr in exprs:
449 if expr.has_key('struct'):
450 ret = generate_visit_struct(expr)
451 ret += generate_visit_list(expr['struct'])
452 fdef.write(ret)
454 ret = generate_declaration(expr['struct'])
455 fdecl.write(ret)
456 elif expr.has_key('union'):
457 ret = generate_visit_union(expr)
458 ret += generate_visit_list(expr['union'])
459 fdef.write(ret)
461 enum_define = discriminator_find_enum_define(expr)
462 ret = ""
463 if not enum_define:
464 ret = generate_decl_enum('%sKind' % expr['union'])
465 ret += generate_declaration(expr['union'])
466 fdecl.write(ret)
467 elif expr.has_key('alternate'):
468 ret = generate_visit_alternate(expr['alternate'], expr['data'])
469 ret += generate_visit_list(expr['alternate'])
470 fdef.write(ret)
472 ret = generate_decl_enum('%sKind' % expr['alternate'])
473 ret += generate_declaration(expr['alternate'])
474 fdecl.write(ret)
475 elif expr.has_key('enum'):
476 ret = generate_visit_list(expr['enum'])
477 ret += generate_visit_enum(expr['enum'])
478 fdef.write(ret)
480 ret = generate_decl_enum(expr['enum'])
481 ret += generate_enum_declaration(expr['enum'])
482 fdecl.write(ret)
484 close_output(fdef, fdecl)