]> git.proxmox.com Git - mirror_qemu.git/blob - scripts/qapi-visit.py
qapi-visit: Fix two name arguments passed to visitors
[mirror_qemu.git] / scripts / qapi-visit.py
1 #
2 # QAPI visitor generator
3 #
4 # Copyright IBM, Corp. 2011
5 # Copyright (C) 2014-2015 Red Hat, Inc.
6 #
7 # Authors:
8 # Anthony Liguori <aliguori@us.ibm.com>
9 # Michael Roth <mdroth@linux.vnet.ibm.com>
10 # Markus Armbruster <armbru@redhat.com>
11 #
12 # This work is licensed under the terms of the GNU GPL, version 2.
13 # See the COPYING file in the top-level directory.
14
15 from ordereddict import OrderedDict
16 from qapi import *
17 import re
18
19 implicit_structs_seen = set()
20 struct_fields_seen = set()
21
22 def generate_visit_implicit_struct(type):
23 if type in implicit_structs_seen:
24 return ''
25 implicit_structs_seen.add(type)
26 ret = ''
27 if type not in struct_fields_seen:
28 # Need a forward declaration
29 ret += mcgen('''
30
31 static void visit_type_%(c_type)s_fields(Visitor *m, %(c_type)s **obj, Error **errp);
32 ''',
33 c_type=type_name(type))
34
35 ret += mcgen('''
36
37 static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
38 {
39 Error *err = NULL;
40
41 visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
42 if (!err) {
43 visit_type_%(c_type)s_fields(m, obj, errp);
44 visit_end_implicit_struct(m, &err);
45 }
46 error_propagate(errp, err);
47 }
48 ''',
49 c_type=type_name(type))
50 return ret
51
52 def generate_visit_struct_fields(name, members, base = None):
53 struct_fields_seen.add(name)
54
55 ret = ''
56
57 if base:
58 ret += generate_visit_implicit_struct(base)
59
60 ret += mcgen('''
61
62 static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
63 {
64 Error *err = NULL;
65 ''',
66 name=c_name(name))
67 push_indent()
68
69 if base:
70 ret += mcgen('''
71 visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
72 if (err) {
73 goto out;
74 }
75 ''',
76 type=type_name(base), c_name=c_name('base'))
77
78 for argname, argentry, optional in parse_args(members):
79 if optional:
80 ret += mcgen('''
81 visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
82 if (!err && (*obj)->has_%(c_name)s) {
83 ''',
84 c_name=c_name(argname), name=argname)
85 push_indent()
86
87 ret += mcgen('''
88 visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
89 ''',
90 type=type_name(argentry), c_name=c_name(argname),
91 name=argname)
92
93 if optional:
94 pop_indent()
95 ret += mcgen('''
96 }
97 ''')
98 ret += mcgen('''
99 if (err) {
100 goto out;
101 }
102 ''')
103
104 pop_indent()
105 if re.search('^ *goto out\\;', ret, re.MULTILINE):
106 ret += mcgen('''
107
108 out:
109 ''')
110 ret += mcgen('''
111 error_propagate(errp, err);
112 }
113 ''')
114 return ret
115
116
117 def generate_visit_struct_body(name):
118 ret = mcgen('''
119 Error *err = NULL;
120
121 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
122 if (!err) {
123 if (*obj) {
124 visit_type_%(c_name)s_fields(m, obj, errp);
125 }
126 visit_end_struct(m, &err);
127 }
128 error_propagate(errp, err);
129 ''',
130 name=name, c_name=c_name(name))
131
132 return ret
133
134 def generate_visit_struct(expr):
135
136 name = expr['struct']
137 members = expr['data']
138 base = expr.get('base')
139
140 ret = generate_visit_struct_fields(name, members, base)
141
142 ret += mcgen('''
143
144 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
145 {
146 ''',
147 name=c_name(name))
148
149 ret += generate_visit_struct_body(name)
150
151 ret += mcgen('''
152 }
153 ''')
154 return ret
155
156 def generate_visit_list(name):
157 return mcgen('''
158
159 void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
160 {
161 Error *err = NULL;
162 GenericList *i, **prev;
163
164 visit_start_list(m, name, &err);
165 if (err) {
166 goto out;
167 }
168
169 for (prev = (GenericList **)obj;
170 !err && (i = visit_next_list(m, prev, &err)) != NULL;
171 prev = &i) {
172 %(name)sList *native_i = (%(name)sList *)i;
173 visit_type_%(name)s(m, &native_i->value, NULL, &err);
174 }
175
176 error_propagate(errp, err);
177 err = NULL;
178 visit_end_list(m, &err);
179 out:
180 error_propagate(errp, err);
181 }
182 ''',
183 name=type_name(name))
184
185 def generate_visit_enum(name):
186 return mcgen('''
187
188 void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error **errp)
189 {
190 visit_type_enum(m, (int *)obj, %(c_name)s_lookup, "%(name)s", name, errp);
191 }
192 ''',
193 c_name=c_name(name), name=name)
194
195 def generate_visit_alternate(name, members):
196 ret = mcgen('''
197
198 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
199 {
200 Error *err = NULL;
201
202 visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
203 if (err) {
204 goto out;
205 }
206 visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
207 if (err) {
208 goto out_end;
209 }
210 switch ((*obj)->kind) {
211 ''',
212 name=c_name(name))
213
214 # For alternate, always use the default enum type automatically generated
215 # as name + 'Kind'
216 disc_type = c_name(name) + 'Kind'
217
218 for key in members:
219 assert (members[key] in builtin_types.keys()
220 or find_struct(members[key])
221 or find_union(members[key])
222 or find_enum(members[key])), "Invalid alternate member"
223
224 enum_full_value = c_enum_const(disc_type, key)
225 ret += mcgen('''
226 case %(enum_full_value)s:
227 visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
228 break;
229 ''',
230 enum_full_value = enum_full_value,
231 c_type = type_name(members[key]),
232 c_name = c_name(key))
233
234 ret += mcgen('''
235 default:
236 abort();
237 }
238 out_end:
239 error_propagate(errp, err);
240 err = NULL;
241 visit_end_implicit_struct(m, &err);
242 out:
243 error_propagate(errp, err);
244 }
245 ''')
246
247 return ret
248
249
250 def generate_visit_union(expr):
251
252 name = expr['union']
253 members = expr['data']
254
255 base = expr.get('base')
256 discriminator = expr.get('discriminator')
257
258 enum_define = discriminator_find_enum_define(expr)
259 if enum_define:
260 # Use the enum type as discriminator
261 ret = ""
262 disc_type = c_name(enum_define['enum_name'])
263 else:
264 # There will always be a discriminator in the C switch code, by default
265 # it is an enum type generated silently
266 ret = generate_visit_enum(name + 'Kind')
267 disc_type = c_name(name) + 'Kind'
268
269 if base:
270 assert discriminator
271 base_fields = find_struct(base)['data'].copy()
272 del base_fields[discriminator]
273 ret += generate_visit_struct_fields(name, base_fields)
274
275 if discriminator:
276 for key in members:
277 ret += generate_visit_implicit_struct(members[key])
278
279 ret += mcgen('''
280
281 void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
282 {
283 Error *err = NULL;
284
285 visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
286 if (err) {
287 goto out;
288 }
289 if (*obj) {
290 ''',
291 c_name=c_name(name), name=name)
292
293 if base:
294 ret += mcgen('''
295 visit_type_%(name)s_fields(m, obj, &err);
296 if (err) {
297 goto out_obj;
298 }
299 ''',
300 name=c_name(name))
301
302 if not discriminator:
303 tag = 'kind'
304 disc_key = "type"
305 else:
306 tag = discriminator
307 disc_key = discriminator
308 ret += mcgen('''
309 visit_type_%(disc_type)s(m, &(*obj)->%(c_tag)s, "%(disc_key)s", &err);
310 if (err) {
311 goto out_obj;
312 }
313 if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
314 goto out_obj;
315 }
316 switch ((*obj)->%(c_tag)s) {
317 ''',
318 disc_type = disc_type,
319 c_tag=c_name(tag),
320 disc_key = disc_key)
321
322 for key in members:
323 if not discriminator:
324 fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
325 else:
326 fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
327
328 enum_full_value = c_enum_const(disc_type, key)
329 ret += mcgen('''
330 case %(enum_full_value)s:
331 ''' + fmt + '''
332 break;
333 ''',
334 enum_full_value = enum_full_value,
335 c_type=type_name(members[key]),
336 c_name=c_name(key))
337
338 ret += mcgen('''
339 default:
340 abort();
341 }
342 out_obj:
343 error_propagate(errp, err);
344 err = NULL;
345 visit_end_union(m, !!(*obj)->data, &err);
346 error_propagate(errp, err);
347 err = NULL;
348 }
349 visit_end_struct(m, &err);
350 out:
351 error_propagate(errp, err);
352 }
353 ''')
354
355 return ret
356
357 def generate_declaration(name, builtin_type=False):
358 ret = ""
359 if not builtin_type:
360 name = c_name(name)
361 ret += mcgen('''
362
363 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
364 ''',
365 name=name)
366
367 ret += mcgen('''
368 void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
369 ''',
370 name=name)
371
372 return ret
373
374 def generate_enum_declaration(name):
375 ret = mcgen('''
376 void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
377 ''',
378 name=c_name(name))
379
380 return ret
381
382 def generate_decl_enum(name):
383 return mcgen('''
384
385 void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
386 ''',
387 name=c_name(name))
388
389 do_builtins = False
390
391 (input_file, output_dir, do_c, do_h, prefix, opts) = \
392 parse_command_line("b", ["builtins"])
393
394 for o, a in opts:
395 if o in ("-b", "--builtins"):
396 do_builtins = True
397
398 c_comment = '''
399 /*
400 * schema-defined QAPI visitor functions
401 *
402 * Copyright IBM, Corp. 2011
403 *
404 * Authors:
405 * Anthony Liguori <aliguori@us.ibm.com>
406 *
407 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
408 * See the COPYING.LIB file in the top-level directory.
409 *
410 */
411 '''
412 h_comment = '''
413 /*
414 * schema-defined QAPI visitor functions
415 *
416 * Copyright IBM, Corp. 2011
417 *
418 * Authors:
419 * Anthony Liguori <aliguori@us.ibm.com>
420 *
421 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
422 * See the COPYING.LIB file in the top-level directory.
423 *
424 */
425 '''
426
427 (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
428 'qapi-visit.c', 'qapi-visit.h',
429 c_comment, h_comment)
430
431 fdef.write(mcgen('''
432 #include "qemu-common.h"
433 #include "%(prefix)sqapi-visit.h"
434 ''',
435 prefix = prefix))
436
437 fdecl.write(mcgen('''
438 #include "qapi/visitor.h"
439 #include "%(prefix)sqapi-types.h"
440
441 ''',
442 prefix=prefix))
443
444 exprs = parse_schema(input_file)
445
446 # to avoid header dependency hell, we always generate declarations
447 # for built-in types in our header files and simply guard them
448 fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
449 for typename in builtin_types.keys():
450 fdecl.write(generate_declaration(typename, builtin_type=True))
451 fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
452
453 # ...this doesn't work for cases where we link in multiple objects that
454 # have the functions defined, so we use -b option to provide control
455 # over these cases
456 if do_builtins:
457 for typename in builtin_types.keys():
458 fdef.write(generate_visit_list(typename))
459
460 for expr in exprs:
461 if expr.has_key('struct'):
462 ret = generate_visit_struct(expr)
463 ret += generate_visit_list(expr['struct'])
464 fdef.write(ret)
465
466 ret = generate_declaration(expr['struct'])
467 fdecl.write(ret)
468 elif expr.has_key('union'):
469 ret = generate_visit_union(expr)
470 ret += generate_visit_list(expr['union'])
471 fdef.write(ret)
472
473 enum_define = discriminator_find_enum_define(expr)
474 ret = ""
475 if not enum_define:
476 ret = generate_decl_enum('%sKind' % expr['union'])
477 ret += generate_declaration(expr['union'])
478 fdecl.write(ret)
479 elif expr.has_key('alternate'):
480 ret = generate_visit_alternate(expr['alternate'], expr['data'])
481 ret += generate_visit_list(expr['alternate'])
482 fdef.write(ret)
483
484 ret = generate_decl_enum('%sKind' % expr['alternate'])
485 ret += generate_declaration(expr['alternate'])
486 fdecl.write(ret)
487 elif expr.has_key('enum'):
488 ret = generate_visit_list(expr['enum'])
489 ret += generate_visit_enum(expr['enum'])
490 fdef.write(ret)
491
492 ret = generate_decl_enum(expr['enum'])
493 ret += generate_enum_declaration(expr['enum'])
494 fdecl.write(ret)
495
496 close_output(fdef, fdecl)