ide: Account for failed and invalid operations
[qemu.git] / scripts / qapi-visit.py
blob3ef5c16a662c688e29c069f1ea33cf2f1cb10532
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 qapi import *
16 import re
18 # visit_type_FOO_implicit() is emitted as needed; track if it has already
19 # been output.
20 implicit_structs_seen = set()
22 # visit_type_FOO_fields() is always emitted; track if a forward declaration
23 # or implementation has already been output.
24 struct_fields_seen = set()
27 def gen_visit_decl(name, scalar=False):
28 c_type = c_name(name) + ' *'
29 if not scalar:
30 c_type += '*'
31 return mcgen('''
32 void visit_type_%(c_name)s(Visitor *v, %(c_type)sobj, const char *name, Error **errp);
33 ''',
34 c_name=c_name(name), c_type=c_type)
37 def gen_visit_fields_decl(typ):
38 ret = ''
39 if typ.name not in struct_fields_seen:
40 ret += mcgen('''
42 static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp);
43 ''',
44 c_type=typ.c_name())
45 struct_fields_seen.add(typ.name)
46 return ret
49 def gen_visit_implicit_struct(typ):
50 if typ in implicit_structs_seen:
51 return ''
52 implicit_structs_seen.add(typ)
54 ret = gen_visit_fields_decl(typ)
56 ret += mcgen('''
58 static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error **errp)
60 Error *err = NULL;
62 visit_start_implicit_struct(v, (void **)obj, sizeof(%(c_type)s), &err);
63 if (!err) {
64 visit_type_%(c_type)s_fields(v, obj, errp);
65 visit_end_implicit_struct(v, &err);
67 error_propagate(errp, err);
69 ''',
70 c_type=typ.c_name())
71 return ret
74 def gen_visit_struct_fields(name, base, members):
75 ret = ''
77 if base:
78 ret += gen_visit_fields_decl(base)
80 struct_fields_seen.add(name)
81 ret += mcgen('''
83 static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **errp)
85 Error *err = NULL;
87 ''',
88 c_name=c_name(name))
90 if base:
91 ret += mcgen('''
92 visit_type_%(c_type)s_fields(v, (%(c_type)s **)obj, &err);
93 ''',
94 c_type=base.c_name())
95 ret += gen_err_check()
97 ret += gen_visit_fields(members, prefix='(*obj)->')
99 # 'goto out' produced for base, and by gen_visit_fields() for each member
100 if base or members:
101 ret += mcgen('''
103 out:
104 ''')
105 ret += mcgen('''
106 error_propagate(errp, err);
108 ''')
109 return ret
112 def gen_visit_struct(name, base, members):
113 ret = gen_visit_struct_fields(name, base, members)
115 # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
116 # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
117 # rather than leaving it non-NULL. As currently written, the caller must
118 # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
119 ret += mcgen('''
121 void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
123 Error *err = NULL;
125 visit_start_struct(v, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
126 if (!err) {
127 if (*obj) {
128 visit_type_%(c_name)s_fields(v, obj, errp);
130 visit_end_struct(v, &err);
132 error_propagate(errp, err);
134 ''',
135 name=name, c_name=c_name(name))
137 return ret
140 def gen_visit_list(name, element_type):
141 # FIXME: if *obj is NULL on entry, and the first visit_next_list()
142 # assigns to *obj, while a later one fails, we should clean up *obj
143 # rather than leaving it non-NULL. As currently written, the caller must
144 # call qapi_free_FOOList() to avoid a memory leak of the partial FOOList.
145 return mcgen('''
147 void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
149 Error *err = NULL;
150 GenericList *i, **prev;
152 visit_start_list(v, name, &err);
153 if (err) {
154 goto out;
157 for (prev = (GenericList **)obj;
158 !err && (i = visit_next_list(v, prev, &err)) != NULL;
159 prev = &i) {
160 %(c_name)s *native_i = (%(c_name)s *)i;
161 visit_type_%(c_elt_type)s(v, &native_i->value, NULL, &err);
164 error_propagate(errp, err);
165 err = NULL;
166 visit_end_list(v, &err);
167 out:
168 error_propagate(errp, err);
170 ''',
171 c_name=c_name(name), c_elt_type=element_type.c_name())
174 def gen_visit_enum(name):
175 return mcgen('''
177 void visit_type_%(c_name)s(Visitor *v, %(c_name)s *obj, const char *name, Error **errp)
179 visit_type_enum(v, (int *)obj, %(c_name)s_lookup, "%(name)s", name, errp);
181 ''',
182 c_name=c_name(name), name=name)
185 def gen_visit_alternate(name, variants):
186 ret = mcgen('''
188 void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
190 Error *err = NULL;
192 visit_start_implicit_struct(v, (void**) obj, sizeof(%(c_name)s), &err);
193 if (err) {
194 goto out;
196 visit_get_next_type(v, (int*) &(*obj)->type, %(c_name)s_qtypes, name, &err);
197 if (err) {
198 goto out_obj;
200 switch ((*obj)->type) {
201 ''',
202 c_name=c_name(name))
204 for var in variants.variants:
205 ret += mcgen('''
206 case %(case)s:
207 visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, name, &err);
208 break;
209 ''',
210 case=c_enum_const(variants.tag_member.type.name,
211 var.name),
212 c_type=var.type.c_name(),
213 c_name=c_name(var.name))
215 ret += mcgen('''
216 default:
217 abort();
219 out_obj:
220 error_propagate(errp, err);
221 err = NULL;
222 visit_end_implicit_struct(v, &err);
223 out:
224 error_propagate(errp, err);
226 ''')
228 return ret
231 def gen_visit_union(name, base, variants):
232 ret = ''
234 if base:
235 ret += gen_visit_fields_decl(base)
237 for var in variants.variants:
238 # Ugly special case for simple union TODO get rid of it
239 if not var.simple_union_type():
240 ret += gen_visit_implicit_struct(var.type)
242 ret += mcgen('''
244 void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
246 Error *err = NULL;
248 visit_start_struct(v, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
249 if (err) {
250 goto out;
252 if (!*obj) {
253 goto out_obj;
255 ''',
256 c_name=c_name(name), name=name)
258 if base:
259 ret += mcgen('''
260 visit_type_%(c_name)s_fields(v, (%(c_name)s **)obj, &err);
261 ''',
262 c_name=base.c_name())
263 else:
264 ret += mcgen('''
265 visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
266 ''',
267 c_type=variants.tag_member.type.c_name(),
268 c_name=c_name(variants.tag_member.name),
269 name=variants.tag_member.name)
270 ret += gen_err_check(label='out_obj')
271 ret += mcgen('''
272 if (!visit_start_union(v, !!(*obj)->u.data, &err) || err) {
273 goto out_obj;
275 switch ((*obj)->%(c_name)s) {
276 ''',
277 c_name=c_name(variants.tag_member.name))
279 for var in variants.variants:
280 # TODO ugly special case for simple union
281 simple_union_type = var.simple_union_type()
282 ret += mcgen('''
283 case %(case)s:
284 ''',
285 case=c_enum_const(variants.tag_member.type.name,
286 var.name))
287 if simple_union_type:
288 ret += mcgen('''
289 visit_type_%(c_type)s(v, &(*obj)->u.%(c_name)s, "data", &err);
290 ''',
291 c_type=simple_union_type.c_name(),
292 c_name=c_name(var.name))
293 else:
294 ret += mcgen('''
295 visit_type_implicit_%(c_type)s(v, &(*obj)->u.%(c_name)s, &err);
296 ''',
297 c_type=var.type.c_name(),
298 c_name=c_name(var.name))
299 ret += mcgen('''
300 break;
301 ''')
303 ret += mcgen('''
304 default:
305 abort();
307 out_obj:
308 error_propagate(errp, err);
309 err = NULL;
310 if (*obj) {
311 visit_end_union(v, !!(*obj)->u.data, &err);
313 error_propagate(errp, err);
314 err = NULL;
315 visit_end_struct(v, &err);
316 out:
317 error_propagate(errp, err);
319 ''')
321 return ret
324 class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
325 def __init__(self):
326 self.decl = None
327 self.defn = None
328 self._btin = None
330 def visit_begin(self, schema):
331 self.decl = ''
332 self.defn = ''
333 self._btin = guardstart('QAPI_VISIT_BUILTIN')
335 def visit_end(self):
336 # To avoid header dependency hell, we always generate
337 # declarations for built-in types in our header files and
338 # simply guard them. See also do_builtins (command line
339 # option -b).
340 self._btin += guardend('QAPI_VISIT_BUILTIN')
341 self.decl = self._btin + self.decl
342 self._btin = None
344 def visit_needed(self, entity):
345 # Visit everything except implicit objects
346 return not (entity.is_implicit() and
347 isinstance(entity, QAPISchemaObjectType))
349 def visit_enum_type(self, name, info, values, prefix):
350 self.decl += gen_visit_decl(name, scalar=True)
351 self.defn += gen_visit_enum(name)
353 def visit_array_type(self, name, info, element_type):
354 decl = gen_visit_decl(name)
355 defn = gen_visit_list(name, element_type)
356 if isinstance(element_type, QAPISchemaBuiltinType):
357 self._btin += decl
358 if do_builtins:
359 self.defn += defn
360 else:
361 self.decl += decl
362 self.defn += defn
364 def visit_object_type(self, name, info, base, members, variants):
365 self.decl += gen_visit_decl(name)
366 if variants:
367 assert not members # not implemented
368 self.defn += gen_visit_union(name, base, variants)
369 else:
370 self.defn += gen_visit_struct(name, base, members)
372 def visit_alternate_type(self, name, info, variants):
373 self.decl += gen_visit_decl(name)
374 self.defn += gen_visit_alternate(name, variants)
376 # If you link code generated from multiple schemata, you want only one
377 # instance of the code for built-in types. Generate it only when
378 # do_builtins, enabled by command line option -b. See also
379 # QAPISchemaGenVisitVisitor.visit_end().
380 do_builtins = False
382 (input_file, output_dir, do_c, do_h, prefix, opts) = \
383 parse_command_line("b", ["builtins"])
385 for o, a in opts:
386 if o in ("-b", "--builtins"):
387 do_builtins = True
389 c_comment = '''
391 * schema-defined QAPI visitor functions
393 * Copyright IBM, Corp. 2011
395 * Authors:
396 * Anthony Liguori <aliguori@us.ibm.com>
398 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
399 * See the COPYING.LIB file in the top-level directory.
403 h_comment = '''
405 * schema-defined QAPI visitor functions
407 * Copyright IBM, Corp. 2011
409 * Authors:
410 * Anthony Liguori <aliguori@us.ibm.com>
412 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
413 * See the COPYING.LIB file in the top-level directory.
418 (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
419 'qapi-visit.c', 'qapi-visit.h',
420 c_comment, h_comment)
422 fdef.write(mcgen('''
423 #include "qemu-common.h"
424 #include "%(prefix)sqapi-visit.h"
425 ''',
426 prefix=prefix))
428 fdecl.write(mcgen('''
429 #include "qapi/visitor.h"
430 #include "%(prefix)sqapi-types.h"
432 ''',
433 prefix=prefix))
435 schema = QAPISchema(input_file)
436 gen = QAPISchemaGenVisitVisitor()
437 schema.visit(gen)
438 fdef.write(gen.defn)
439 fdecl.write(gen.decl)
441 close_output(fdef, fdecl)