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