]> Git Repo - qemu.git/blob - scripts/qapi-visit.py
qapi-event: Eliminate global variable event_enum_value
[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 <[email protected]>
9 #  Michael Roth    <[email protected]>
10 #  Markus Armbruster <[email protected]>
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 qapi import *
16 import re
17
18 implicit_structs_seen = set()
19 struct_fields_seen = set()
20
21 def generate_visit_implicit_struct(type):
22     if type in implicit_structs_seen:
23         return ''
24     implicit_structs_seen.add(type)
25     ret = ''
26     if type.name not in struct_fields_seen:
27         # Need a forward declaration
28         ret += mcgen('''
29
30 static void visit_type_%(c_type)s_fields(Visitor *m, %(c_type)s **obj, Error **errp);
31 ''',
32                      c_type=type.c_name())
33
34     ret += mcgen('''
35
36 static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
37 {
38     Error *err = NULL;
39
40     visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
41     if (!err) {
42         visit_type_%(c_type)s_fields(m, obj, errp);
43         visit_end_implicit_struct(m, &err);
44     }
45     error_propagate(errp, err);
46 }
47 ''',
48                  c_type=type.c_name())
49     return ret
50
51 def generate_visit_struct_fields(name, members, base = None):
52     struct_fields_seen.add(name)
53
54     ret = ''
55
56     if base:
57         ret += generate_visit_implicit_struct(base)
58
59     ret += mcgen('''
60
61 static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
62 {
63     Error *err = NULL;
64
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=base.c_name(), c_name=c_name('base'))
77
78     for memb in members:
79         if memb.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(memb.name), name=memb.name)
85             push_indent()
86
87         ret += mcgen('''
88 visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
89 ''',
90                      type=memb.type.c_name(), c_name=c_name(memb.name),
91                      name=memb.name)
92
93         if memb.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     # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
119     # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
120     # rather than leaving it non-NULL. As currently written, the caller must
121     # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
122     ret = mcgen('''
123     Error *err = NULL;
124
125     visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
126     if (!err) {
127         if (*obj) {
128             visit_type_%(c_name)s_fields(m, obj, errp);
129         }
130         visit_end_struct(m, &err);
131     }
132     error_propagate(errp, err);
133 ''',
134                 name=name, c_name=c_name(name))
135
136     return ret
137
138 def gen_visit_struct(name, base, members):
139     ret = generate_visit_struct_fields(name, members, base)
140
141     ret += mcgen('''
142
143 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
144 {
145 ''',
146                  name=c_name(name))
147
148     ret += generate_visit_struct_body(name)
149
150     ret += mcgen('''
151 }
152 ''')
153     return ret
154
155 def gen_visit_list(name, element_type):
156     return mcgen('''
157
158 void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
159 {
160     Error *err = NULL;
161     GenericList *i, **prev;
162
163     visit_start_list(m, name, &err);
164     if (err) {
165         goto out;
166     }
167
168     for (prev = (GenericList **)obj;
169          !err && (i = visit_next_list(m, prev, &err)) != NULL;
170          prev = &i) {
171         %(name)s *native_i = (%(name)s *)i;
172         visit_type_%(c_elt_type)s(m, &native_i->value, NULL, &err);
173     }
174
175     error_propagate(errp, err);
176     err = NULL;
177     visit_end_list(m, &err);
178 out:
179     error_propagate(errp, err);
180 }
181 ''',
182                  name=c_name(name),
183                  c_elt_type=element_type.c_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 gen_visit_alternate(name, variants):
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 var in variants.variants:
215         enum_full_value = c_enum_const(variants.tag_member.type.name,
216                                        var.name)
217         ret += mcgen('''
218     case %(enum_full_value)s:
219         visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
220         break;
221 ''',
222                 enum_full_value = enum_full_value,
223                 c_type=var.type.c_name(),
224                 c_name=c_name(var.name))
225
226     ret += mcgen('''
227     default:
228         abort();
229     }
230 out_end:
231     error_propagate(errp, err);
232     err = NULL;
233     visit_end_implicit_struct(m, &err);
234 out:
235     error_propagate(errp, err);
236 }
237 ''')
238
239     return ret
240
241 def gen_visit_union(name, base, variants):
242     ret = ''
243
244     if base:
245         members = [m for m in base.members if m != variants.tag_member]
246         ret += generate_visit_struct_fields(name, members)
247
248     for var in variants.variants:
249         # Ugly special case for simple union TODO get rid of it
250         if not var.simple_union_type():
251             ret += generate_visit_implicit_struct(var.type)
252
253     ret += mcgen('''
254
255 void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
256 {
257     Error *err = NULL;
258
259     visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
260     if (err) {
261         goto out;
262     }
263     if (*obj) {
264 ''',
265                  c_name=c_name(name), name=name)
266
267     if base:
268         ret += mcgen('''
269         visit_type_%(name)s_fields(m, obj, &err);
270         if (err) {
271             goto out_obj;
272         }
273 ''',
274                      name=c_name(name))
275
276     disc_key = variants.tag_member.name
277     if not variants.tag_name:
278         # we pointlessly use a different key for simple unions
279         disc_key = 'type'
280     ret += mcgen('''
281         visit_type_%(disc_type)s(m, &(*obj)->%(c_name)s, "%(disc_key)s", &err);
282         if (err) {
283             goto out_obj;
284         }
285         if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
286             goto out_obj;
287         }
288         switch ((*obj)->%(c_name)s) {
289 ''',
290                  disc_type=variants.tag_member.type.c_name(),
291                  # TODO ugly special case for simple union
292                  # Use same tag name in C as on the wire to get rid of
293                  # it, then: c_name=c_name(variants.tag_member.name)
294                  c_name=c_name(variants.tag_name or 'kind'),
295                  disc_key = disc_key)
296
297     for var in variants.variants:
298         # TODO ugly special case for simple union
299         simple_union_type = var.simple_union_type()
300         if simple_union_type:
301             fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
302         else:
303             fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
304
305         enum_full_value = c_enum_const(variants.tag_member.type.name, var.name)
306         ret += mcgen('''
307         case %(enum_full_value)s:
308             ''' + fmt + '''
309             break;
310 ''',
311                 enum_full_value = enum_full_value,
312                 c_type=(simple_union_type or var.type).c_name(),
313                 c_name=c_name(var.name))
314
315     ret += mcgen('''
316         default:
317             abort();
318         }
319 out_obj:
320         error_propagate(errp, err);
321         err = NULL;
322         visit_end_union(m, !!(*obj)->data, &err);
323         error_propagate(errp, err);
324         err = NULL;
325     }
326     visit_end_struct(m, &err);
327 out:
328     error_propagate(errp, err);
329 }
330 ''')
331
332     return ret
333
334 def gen_visit_decl(name, scalar=False):
335     c_type = c_name(name) + ' *'
336     if not scalar:
337         c_type += '*'
338     return mcgen('''
339 void visit_type_%(c_name)s(Visitor *m, %(c_type)sobj, const char *name, Error **errp);
340 ''',
341                  c_name=c_name(name), c_type=c_type)
342
343
344 class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
345     def __init__(self):
346         self.decl = None
347         self.defn = None
348         self._btin = None
349
350     def visit_begin(self, schema):
351         self.decl = ''
352         self.defn = ''
353         self._btin = guardstart('QAPI_VISIT_BUILTIN')
354
355     def visit_end(self):
356         # To avoid header dependency hell, we always generate
357         # declarations for built-in types in our header files and
358         # simply guard them.  See also do_builtins (command line
359         # option -b).
360         self._btin += guardend('QAPI_VISIT_BUILTIN')
361         self.decl = self._btin + self.decl
362         self._btin = None
363
364     def visit_enum_type(self, name, info, values, prefix):
365         self.decl += gen_visit_decl(name, scalar=True)
366         self.defn += generate_visit_enum(name)
367
368     def visit_array_type(self, name, info, element_type):
369         decl = gen_visit_decl(name)
370         defn = gen_visit_list(name, element_type)
371         if isinstance(element_type, QAPISchemaBuiltinType):
372             self._btin += decl
373             if do_builtins:
374                 self.defn += defn
375         else:
376             self.decl += decl
377             self.defn += defn
378
379     def visit_object_type(self, name, info, base, members, variants):
380         if info:
381             self.decl += gen_visit_decl(name)
382             if variants:
383                 assert not members      # not implemented
384                 self.defn += gen_visit_union(name, base, variants)
385             else:
386                 self.defn += gen_visit_struct(name, base, members)
387
388     def visit_alternate_type(self, name, info, variants):
389         self.decl += gen_visit_decl(name)
390         self.defn += gen_visit_alternate(name, variants)
391
392 # If you link code generated from multiple schemata, you want only one
393 # instance of the code for built-in types.  Generate it only when
394 # do_builtins, enabled by command line option -b.  See also
395 # QAPISchemaGenVisitVisitor.visit_end().
396 do_builtins = False
397
398 (input_file, output_dir, do_c, do_h, prefix, opts) = \
399     parse_command_line("b", ["builtins"])
400
401 for o, a in opts:
402     if o in ("-b", "--builtins"):
403         do_builtins = True
404
405 c_comment = '''
406 /*
407  * schema-defined QAPI visitor functions
408  *
409  * Copyright IBM, Corp. 2011
410  *
411  * Authors:
412  *  Anthony Liguori   <[email protected]>
413  *
414  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
415  * See the COPYING.LIB file in the top-level directory.
416  *
417  */
418 '''
419 h_comment = '''
420 /*
421  * schema-defined QAPI visitor functions
422  *
423  * Copyright IBM, Corp. 2011
424  *
425  * Authors:
426  *  Anthony Liguori   <[email protected]>
427  *
428  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
429  * See the COPYING.LIB file in the top-level directory.
430  *
431  */
432 '''
433
434 (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
435                             'qapi-visit.c', 'qapi-visit.h',
436                             c_comment, h_comment)
437
438 fdef.write(mcgen('''
439 #include "qemu-common.h"
440 #include "%(prefix)sqapi-visit.h"
441 ''',
442                  prefix = prefix))
443
444 fdecl.write(mcgen('''
445 #include "qapi/visitor.h"
446 #include "%(prefix)sqapi-types.h"
447
448 ''',
449                   prefix=prefix))
450
451 schema = QAPISchema(input_file)
452 gen = QAPISchemaGenVisitVisitor()
453 schema.visit(gen)
454 fdef.write(gen.defn)
455 fdecl.write(gen.decl)
456
457 close_output(fdef, fdecl)
This page took 0.05222 seconds and 4 git commands to generate.