qapi: Rename identical c_fun()/c_var() into c_name()
[qemu.git] / scripts / qapi-visit.py
blobba623b10b8a424a7b84e7024d7631f2cb56c588f
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
18 import sys
19 import os
20 import getopt
21 import errno
23 implicit_structs = []
25 def generate_visit_implicit_struct(type):
26 global implicit_structs
27 if type in implicit_structs:
28 return ''
29 implicit_structs.append(type)
30 return mcgen('''
32 static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
34 Error *err = NULL;
36 visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
37 if (!err) {
38 visit_type_%(c_type)s_fields(m, obj, errp);
39 visit_end_implicit_struct(m, &err);
41 error_propagate(errp, err);
43 ''',
44 c_type=type_name(type))
46 def generate_visit_struct_fields(name, members, base = None):
47 substructs = []
48 ret = ''
50 if base:
51 ret += generate_visit_implicit_struct(base)
53 ret += mcgen('''
55 static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
57 Error *err = NULL;
58 ''',
59 name=name)
60 push_indent()
62 if base:
63 ret += mcgen('''
64 visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
65 if (err) {
66 goto out;
68 ''',
69 type=type_name(base), c_name=c_name('base'))
71 for argname, argentry, optional in parse_args(members):
72 if optional:
73 ret += mcgen('''
74 visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
75 if (!err && (*obj)->has_%(c_name)s) {
76 ''',
77 c_name=c_name(argname), name=argname)
78 push_indent()
80 ret += mcgen('''
81 visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
82 ''',
83 type=type_name(argentry), c_name=c_name(argname),
84 name=argname)
86 if optional:
87 pop_indent()
88 ret += mcgen('''
90 ''')
91 ret += mcgen('''
92 if (err) {
93 goto out;
95 ''')
97 pop_indent()
98 if re.search('^ *goto out\\;', ret, re.MULTILINE):
99 ret += mcgen('''
101 out:
102 ''')
103 ret += mcgen('''
104 error_propagate(errp, err);
106 ''')
107 return ret
110 def generate_visit_struct_body(name, members):
111 ret = mcgen('''
112 Error *err = NULL;
114 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
115 if (!err) {
116 if (*obj) {
117 visit_type_%(name)s_fields(m, obj, errp);
119 visit_end_struct(m, &err);
121 error_propagate(errp, err);
122 ''',
123 name=name)
125 return ret
127 def generate_visit_struct(expr):
129 name = expr['struct']
130 members = expr['data']
131 base = expr.get('base')
133 ret = generate_visit_struct_fields(name, members, base)
135 ret += mcgen('''
137 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
139 ''',
140 name=name)
142 ret += generate_visit_struct_body(name, members)
144 ret += mcgen('''
146 ''')
147 return ret
149 def generate_visit_list(name, members):
150 return mcgen('''
152 void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
154 Error *err = NULL;
155 GenericList *i, **prev;
157 visit_start_list(m, name, &err);
158 if (err) {
159 goto out;
162 for (prev = (GenericList **)obj;
163 !err && (i = visit_next_list(m, prev, &err)) != NULL;
164 prev = &i) {
165 %(name)sList *native_i = (%(name)sList *)i;
166 visit_type_%(name)s(m, &native_i->value, NULL, &err);
169 error_propagate(errp, err);
170 err = NULL;
171 visit_end_list(m, &err);
172 out:
173 error_propagate(errp, err);
175 ''',
176 name=name)
178 def generate_visit_enum(name, members):
179 return mcgen('''
181 void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
183 visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
185 ''',
186 name=name)
188 def generate_visit_alternate(name, members):
189 ret = mcgen('''
191 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
193 Error *err = NULL;
195 visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
196 if (err) {
197 goto out;
199 visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
200 if (err) {
201 goto out_end;
203 switch ((*obj)->kind) {
204 ''',
205 name=name)
207 # For alternate, always use the default enum type automatically generated
208 # as "'%sKind' % (name)"
209 disc_type = '%sKind' % (name)
211 for key in members:
212 assert (members[key] in builtin_types.keys()
213 or find_struct(members[key])
214 or find_union(members[key])
215 or find_enum(members[key])), "Invalid alternate member"
217 enum_full_value = generate_enum_full_value(disc_type, key)
218 ret += mcgen('''
219 case %(enum_full_value)s:
220 visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
221 break;
222 ''',
223 enum_full_value = enum_full_value,
224 c_type = type_name(members[key]),
225 c_name = c_name(key))
227 ret += mcgen('''
228 default:
229 abort();
231 out_end:
232 error_propagate(errp, err);
233 err = NULL;
234 visit_end_implicit_struct(m, &err);
235 out:
236 error_propagate(errp, err);
238 ''')
240 return ret
243 def generate_visit_union(expr):
245 name = expr['union']
246 members = expr['data']
248 base = expr.get('base')
249 discriminator = expr.get('discriminator')
251 enum_define = discriminator_find_enum_define(expr)
252 if enum_define:
253 # Use the enum type as discriminator
254 ret = ""
255 disc_type = enum_define['enum_name']
256 else:
257 # There will always be a discriminator in the C switch code, by default
258 # it is an enum type generated silently as "'%sKind' % (name)"
259 ret = generate_visit_enum('%sKind' % name, members.keys())
260 disc_type = '%sKind' % (name)
262 if base:
263 assert discriminator
264 base_fields = find_struct(base)['data'].copy()
265 del base_fields[discriminator]
266 ret += generate_visit_struct_fields(name, base_fields)
268 if discriminator:
269 for key in members:
270 ret += generate_visit_implicit_struct(members[key])
272 ret += mcgen('''
274 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
276 Error *err = NULL;
278 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
279 if (err) {
280 goto out;
282 if (*obj) {
283 ''',
284 name=name)
286 if base:
287 ret += mcgen('''
288 visit_type_%(name)s_fields(m, obj, &err);
289 if (err) {
290 goto out_obj;
292 ''',
293 name=name)
295 if not discriminator:
296 disc_key = "type"
297 else:
298 disc_key = discriminator
299 ret += mcgen('''
300 visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
301 if (err) {
302 goto out_obj;
304 if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
305 goto out_obj;
307 switch ((*obj)->kind) {
308 ''',
309 disc_type = disc_type,
310 disc_key = disc_key)
312 for key in members:
313 if not discriminator:
314 fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
315 else:
316 fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
318 enum_full_value = generate_enum_full_value(disc_type, key)
319 ret += mcgen('''
320 case %(enum_full_value)s:
321 ''' + fmt + '''
322 break;
323 ''',
324 enum_full_value = enum_full_value,
325 c_type=type_name(members[key]),
326 c_name=c_name(key))
328 ret += mcgen('''
329 default:
330 abort();
332 out_obj:
333 error_propagate(errp, err);
334 err = NULL;
335 visit_end_union(m, !!(*obj)->data, &err);
336 error_propagate(errp, err);
337 err = NULL;
339 visit_end_struct(m, &err);
340 out:
341 error_propagate(errp, err);
343 ''')
345 return ret
347 def generate_declaration(name, members, builtin_type=False):
348 ret = ""
349 if not builtin_type:
350 ret += mcgen('''
352 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
353 ''',
354 name=name)
356 ret += mcgen('''
357 void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
358 ''',
359 name=name)
361 return ret
363 def generate_enum_declaration(name, members):
364 ret = mcgen('''
365 void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
366 ''',
367 name=name)
369 return ret
371 def generate_decl_enum(name, members):
372 return mcgen('''
374 void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
375 ''',
376 name=name)
378 try:
379 opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
380 ["source", "header", "builtins", "prefix=",
381 "input-file=", "output-dir="])
382 except getopt.GetoptError, err:
383 print str(err)
384 sys.exit(1)
386 input_file = ""
387 output_dir = ""
388 prefix = ""
389 c_file = 'qapi-visit.c'
390 h_file = 'qapi-visit.h'
392 do_c = False
393 do_h = False
394 do_builtins = False
396 for o, a in opts:
397 if o in ("-p", "--prefix"):
398 prefix = a
399 elif o in ("-i", "--input-file"):
400 input_file = a
401 elif o in ("-o", "--output-dir"):
402 output_dir = a + "/"
403 elif o in ("-c", "--source"):
404 do_c = True
405 elif o in ("-h", "--header"):
406 do_h = True
407 elif o in ("-b", "--builtins"):
408 do_builtins = True
410 if not do_c and not do_h:
411 do_c = True
412 do_h = True
414 c_file = output_dir + prefix + c_file
415 h_file = output_dir + prefix + h_file
417 try:
418 os.makedirs(output_dir)
419 except os.error, e:
420 if e.errno != errno.EEXIST:
421 raise
423 def maybe_open(really, name, opt):
424 if really:
425 return open(name, opt)
426 else:
427 import StringIO
428 return StringIO.StringIO()
430 fdef = maybe_open(do_c, c_file, 'w')
431 fdecl = maybe_open(do_h, h_file, 'w')
433 fdef.write(mcgen('''
434 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
437 * schema-defined QAPI visitor functions
439 * Copyright IBM, Corp. 2011
441 * Authors:
442 * Anthony Liguori <aliguori@us.ibm.com>
444 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
445 * See the COPYING.LIB file in the top-level directory.
449 #include "qemu-common.h"
450 #include "%(header)s"
451 ''',
452 header=basename(h_file)))
454 fdecl.write(mcgen('''
455 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
458 * schema-defined QAPI visitor functions
460 * Copyright IBM, Corp. 2011
462 * Authors:
463 * Anthony Liguori <aliguori@us.ibm.com>
465 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
466 * See the COPYING.LIB file in the top-level directory.
470 #ifndef %(guard)s
471 #define %(guard)s
473 #include "qapi/visitor.h"
474 #include "%(prefix)sqapi-types.h"
476 ''',
477 prefix=prefix, guard=guardname(h_file)))
479 exprs = parse_schema(input_file)
481 # to avoid header dependency hell, we always generate declarations
482 # for built-in types in our header files and simply guard them
483 fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
484 for typename in builtin_types.keys():
485 fdecl.write(generate_declaration(typename, None, builtin_type=True))
486 fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
488 # ...this doesn't work for cases where we link in multiple objects that
489 # have the functions defined, so we use -b option to provide control
490 # over these cases
491 if do_builtins:
492 for typename in builtin_types.keys():
493 fdef.write(generate_visit_list(typename, None))
495 for expr in exprs:
496 if expr.has_key('struct'):
497 ret = generate_visit_struct(expr)
498 ret += generate_visit_list(expr['struct'], expr['data'])
499 fdef.write(ret)
501 ret = generate_declaration(expr['struct'], expr['data'])
502 fdecl.write(ret)
503 elif expr.has_key('union'):
504 ret = generate_visit_union(expr)
505 ret += generate_visit_list(expr['union'], expr['data'])
506 fdef.write(ret)
508 enum_define = discriminator_find_enum_define(expr)
509 ret = ""
510 if not enum_define:
511 ret = generate_decl_enum('%sKind' % expr['union'],
512 expr['data'].keys())
513 ret += generate_declaration(expr['union'], expr['data'])
514 fdecl.write(ret)
515 elif expr.has_key('alternate'):
516 ret = generate_visit_alternate(expr['alternate'], expr['data'])
517 ret += generate_visit_list(expr['alternate'], expr['data'])
518 fdef.write(ret)
520 ret = generate_decl_enum('%sKind' % expr['alternate'],
521 expr['data'].keys())
522 ret += generate_declaration(expr['alternate'], expr['data'])
523 fdecl.write(ret)
524 elif expr.has_key('enum'):
525 ret = generate_visit_list(expr['enum'], expr['data'])
526 ret += generate_visit_enum(expr['enum'], expr['data'])
527 fdef.write(ret)
529 ret = generate_decl_enum(expr['enum'], expr['data'])
530 ret += generate_enum_declaration(expr['enum'], expr['data'])
531 fdecl.write(ret)
533 fdecl.write('''
534 #endif
535 ''')
537 fdecl.flush()
538 fdecl.close()
540 fdef.flush()
541 fdef.close()