Merge remote-tracking branch 'qemu/master'
[qemu/ar7.git] / scripts / qapi-visit.py
blob65f1a54ee7489f8bfa5ae2ec7a0fef6e6f6a04ca
2 # QAPI visitor generator
4 # Copyright IBM, Corp. 2011
6 # Authors:
7 # Anthony Liguori <aliguori@us.ibm.com>
8 # Michael Roth <mdroth@linux.vnet.ibm.com>
10 # This work is licensed under the terms of the GNU GPLv2.
11 # See the COPYING.LIB file in the top-level directory.
13 from ordereddict import OrderedDict
14 from qapi import *
15 import sys
16 import os
17 import getopt
18 import errno
20 def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None):
21 substructs = []
22 ret = ''
23 if not fn_prefix:
24 full_name = name
25 else:
26 full_name = "%s_%s" % (name, fn_prefix)
28 for argname, argentry, optional, structured in parse_args(members):
29 if structured:
30 if not fn_prefix:
31 nested_fn_prefix = argname
32 else:
33 nested_fn_prefix = "%s_%s" % (fn_prefix, argname)
35 nested_field_prefix = "%s%s." % (field_prefix, argname)
36 ret += generate_visit_struct_fields(name, nested_field_prefix,
37 nested_fn_prefix, argentry)
39 ret += mcgen('''
41 static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s ** obj, Error **errp)
43 Error *err = NULL;
44 ''',
45 name=name, full_name=full_name)
46 push_indent()
48 if base:
49 ret += mcgen('''
50 visit_start_implicit_struct(m, obj ? (void**) &(*obj)->%(c_name)s : NULL, sizeof(%(type)s), &err);
51 if (!err) {
52 visit_type_%(type)s_fields(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, &err);
53 error_propagate(errp, err);
54 err = NULL;
55 visit_end_implicit_struct(m, &err);
57 ''',
58 c_prefix=c_var(field_prefix),
59 type=type_name(base), c_name=c_var('base'))
61 for argname, argentry, optional, structured in parse_args(members):
62 if optional:
63 ret += mcgen('''
64 visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err);
65 if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
66 ''',
67 c_prefix=c_var(field_prefix), prefix=field_prefix,
68 c_name=c_var(argname), name=argname)
69 push_indent()
71 if structured:
72 ret += generate_visit_struct_body(full_name, argname, argentry)
73 else:
74 ret += mcgen('''
75 visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err);
76 ''',
77 c_prefix=c_var(field_prefix), prefix=field_prefix,
78 type=type_name(argentry), c_name=c_var(argname),
79 name=argname)
81 if optional:
82 pop_indent()
83 ret += mcgen('''
85 visit_end_optional(m, &err);
86 ''')
88 pop_indent()
89 ret += mcgen('''
91 error_propagate(errp, err);
93 ''')
94 return ret
97 def generate_visit_struct_body(field_prefix, name, members):
98 ret = mcgen('''
99 if (!error_is_set(errp)) {
100 ''')
101 push_indent()
103 if not field_prefix:
104 full_name = name
105 else:
106 full_name = "%s_%s" % (field_prefix, name)
108 if len(field_prefix):
109 ret += mcgen('''
110 Error **errp = &err; /* from outer scope */
111 Error *err = NULL;
112 visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
113 ''',
114 name=name)
115 else:
116 ret += mcgen('''
117 Error *err = NULL;
118 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
119 ''',
120 name=name)
122 ret += mcgen('''
123 if (!err) {
124 if (!obj || *obj) {
125 visit_type_%(name)s_fields(m, obj, &err);
126 error_propagate(errp, err);
127 err = NULL;
129 ''',
130 name=full_name)
132 pop_indent()
133 ret += mcgen('''
134 /* Always call end_struct if start_struct succeeded. */
135 visit_end_struct(m, &err);
137 error_propagate(errp, err);
139 ''')
140 return ret
142 def generate_visit_struct(expr):
144 name = expr['type']
145 members = expr['data']
146 base = expr.get('base')
148 ret = generate_visit_struct_fields(name, "", "", members, base)
150 ret += mcgen('''
152 void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
154 ''',
155 name=name)
157 push_indent()
158 ret += generate_visit_struct_body("", name, members)
159 pop_indent()
161 ret += mcgen('''
163 ''')
164 return ret
166 def generate_visit_list(name, members):
167 return mcgen('''
169 void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
171 GenericList *i, **prev = (GenericList **)obj;
172 Error *err = NULL;
174 if (!error_is_set(errp)) {
175 visit_start_list(m, name, &err);
176 if (!err) {
177 for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) {
178 %(name)sList *native_i = (%(name)sList *)i;
179 visit_type_%(name)s(m, &native_i->value, NULL, &err);
181 error_propagate(errp, err);
182 err = NULL;
184 /* Always call end_list if start_list succeeded. */
185 visit_end_list(m, &err);
187 error_propagate(errp, err);
190 ''',
191 name=name)
193 def generate_visit_enum(name, members):
194 return mcgen('''
196 void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
198 visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
200 ''',
201 name=name)
203 def generate_visit_anon_union(name, members):
204 ret = mcgen('''
206 void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
208 Error *err = NULL;
210 if (!error_is_set(errp)) {
211 visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
212 visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
213 switch ((*obj)->kind) {
214 ''',
215 name=name)
217 for key in members:
218 assert (members[key] in builtin_types
219 or find_struct(members[key])
220 or find_union(members[key])), "Invalid anonymous union member"
222 ret += mcgen('''
223 case %(abbrev)s_KIND_%(enum)s:
224 visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
225 break;
226 ''',
227 abbrev = de_camel_case(name).upper(),
228 enum = c_fun(de_camel_case(key),False).upper(),
229 c_type = type_name(members[key]),
230 c_name = c_fun(key))
232 ret += mcgen('''
233 default:
234 abort();
236 error_propagate(errp, err);
237 err = NULL;
238 visit_end_implicit_struct(m, &err);
241 ''')
243 return ret
246 def generate_visit_union(expr):
248 name = expr['union']
249 members = expr['data']
251 base = expr.get('base')
252 discriminator = expr.get('discriminator')
254 if discriminator == {}:
255 assert not base
256 return generate_visit_anon_union(name, members)
258 ret = generate_visit_enum('%sKind' % name, members.keys())
260 if base:
261 base_fields = find_struct(base)['data']
262 if discriminator:
263 base_fields = base_fields.copy()
264 del base_fields[discriminator]
265 ret += generate_visit_struct_fields(name, "", "", base_fields)
267 ret += mcgen('''
269 void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
271 Error *err = NULL;
273 if (!error_is_set(errp)) {
274 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
275 if (!err) {
276 if (obj && *obj) {
277 ''',
278 name=name)
281 push_indent()
282 push_indent()
283 push_indent()
285 if base:
286 ret += mcgen('''
287 visit_type_%(name)s_fields(m, obj, &err);
288 ''',
289 name=name)
291 pop_indent()
293 if not discriminator:
294 desc_type = "type"
295 else:
296 desc_type = discriminator
297 ret += mcgen('''
298 visit_type_%(name)sKind(m, &(*obj)->kind, "%(type)s", &err);
299 if (!err) {
300 switch ((*obj)->kind) {
301 ''',
302 name=name, type=desc_type)
304 for key in members:
305 if not discriminator:
306 fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
307 else:
308 fmt = '''visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(c_type)s), &err);
309 if (!err) {
310 visit_type_%(c_type)s_fields(m, &(*obj)->%(c_name)s, &err);
311 error_propagate(errp, err);
312 err = NULL;
313 visit_end_implicit_struct(m, &err);
314 }'''
316 ret += mcgen('''
317 case %(abbrev)s_KIND_%(enum)s:
318 ''' + fmt + '''
319 break;
320 ''',
321 abbrev = de_camel_case(name).upper(),
322 enum = c_fun(de_camel_case(key),False).upper(),
323 c_type=type_name(members[key]),
324 c_name=c_fun(key))
326 ret += mcgen('''
327 default:
328 abort();
331 error_propagate(errp, err);
332 err = NULL;
334 ''')
335 pop_indent()
336 ret += mcgen('''
337 /* Always call end_struct if start_struct succeeded. */
338 visit_end_struct(m, &err);
340 error_propagate(errp, err);
342 ''')
344 pop_indent();
345 ret += mcgen('''
347 ''')
349 return ret
351 def generate_declaration(name, members, genlist=True, builtin_type=False):
352 ret = ""
353 if not builtin_type:
354 ret += mcgen('''
356 void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
357 ''',
358 name=name)
360 if genlist:
361 ret += mcgen('''
362 void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
363 ''',
364 name=name)
366 return ret
368 def generate_enum_declaration(name, members, genlist=True):
369 ret = ""
370 if genlist:
371 ret += mcgen('''
372 void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
373 ''',
374 name=name)
376 return ret
378 def generate_decl_enum(name, members, genlist=True):
379 return mcgen('''
381 void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
382 ''',
383 name=name)
385 try:
386 opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:",
387 ["source", "header", "builtins", "prefix=",
388 "output-dir="])
389 except getopt.GetoptError, err:
390 print str(err)
391 sys.exit(1)
393 output_dir = ""
394 prefix = ""
395 c_file = 'qapi-visit.c'
396 h_file = 'qapi-visit.h'
398 do_c = False
399 do_h = False
400 do_builtins = False
402 for o, a in opts:
403 if o in ("-p", "--prefix"):
404 prefix = a
405 elif o in ("-o", "--output-dir"):
406 output_dir = a + "/"
407 elif o in ("-c", "--source"):
408 do_c = True
409 elif o in ("-h", "--header"):
410 do_h = True
411 elif o in ("-b", "--builtins"):
412 do_builtins = True
414 if not do_c and not do_h:
415 do_c = True
416 do_h = True
418 c_file = output_dir + prefix + c_file
419 h_file = output_dir + prefix + h_file
421 try:
422 os.makedirs(output_dir)
423 except os.error, e:
424 if e.errno != errno.EEXIST:
425 raise
427 def maybe_open(really, name, opt):
428 if really:
429 return open(name, opt)
430 else:
431 import StringIO
432 return StringIO.StringIO()
434 fdef = maybe_open(do_c, c_file, 'w')
435 fdecl = maybe_open(do_h, h_file, 'w')
437 fdef.write(mcgen('''
438 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
441 * schema-defined QAPI visitor functions
443 * Copyright IBM, Corp. 2011
445 * Authors:
446 * Anthony Liguori <aliguori@us.ibm.com>
448 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
449 * See the COPYING.LIB file in the top-level directory.
453 #include "qemu-common.h"
454 #include "%(header)s"
455 ''',
456 header=basename(h_file)))
458 fdecl.write(mcgen('''
459 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
462 * schema-defined QAPI visitor function
464 * Copyright IBM, Corp. 2011
466 * Authors:
467 * Anthony Liguori <aliguori@us.ibm.com>
469 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
470 * See the COPYING.LIB file in the top-level directory.
474 #ifndef %(guard)s
475 #define %(guard)s
477 #include "qapi/visitor.h"
478 #include "%(prefix)sqapi-types.h"
480 ''',
481 prefix=prefix, guard=guardname(h_file)))
483 exprs = parse_schema(sys.stdin)
485 # to avoid header dependency hell, we always generate declarations
486 # for built-in types in our header files and simply guard them
487 fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
488 for typename in builtin_types:
489 fdecl.write(generate_declaration(typename, None, genlist=True,
490 builtin_type=True))
491 fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
493 # ...this doesn't work for cases where we link in multiple objects that
494 # have the functions defined, so we use -b option to provide control
495 # over these cases
496 if do_builtins:
497 fdef.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DEF"))
498 for typename in builtin_types:
499 fdef.write(generate_visit_list(typename, None))
500 fdef.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DEF"))
502 for expr in exprs:
503 if expr.has_key('type'):
504 ret = generate_visit_struct(expr)
505 ret += generate_visit_list(expr['type'], expr['data'])
506 fdef.write(ret)
508 ret = generate_declaration(expr['type'], expr['data'])
509 fdecl.write(ret)
510 elif expr.has_key('union'):
511 ret = generate_visit_union(expr)
512 ret += generate_visit_list(expr['union'], expr['data'])
513 fdef.write(ret)
515 ret = generate_decl_enum('%sKind' % expr['union'], expr['data'].keys())
516 ret += generate_declaration(expr['union'], expr['data'])
517 fdecl.write(ret)
518 elif expr.has_key('enum'):
519 ret = generate_visit_list(expr['enum'], expr['data'])
520 ret += generate_visit_enum(expr['enum'], expr['data'])
521 fdef.write(ret)
523 ret = generate_decl_enum(expr['enum'], expr['data'])
524 ret += generate_enum_declaration(expr['enum'], expr['data'])
525 fdecl.write(ret)
527 fdecl.write('''
528 #endif
529 ''')
531 fdecl.flush()
532 fdecl.close()
534 fdef.flush()
535 fdef.close()