qapi-visit.py 11.9 KB
Newer Older
1 2 3 4
#
# QAPI visitor generator
#
# Copyright IBM, Corp. 2011
E
Eric Blake 已提交
5
# Copyright (C) 2014-2015 Red Hat, Inc.
6 7 8 9
#
# Authors:
#  Anthony Liguori <aliguori@us.ibm.com>
#  Michael Roth    <mdroth@linux.vnet.ibm.com>
10
#  Markus Armbruster <armbru@redhat.com>
11
#
12 13
# This work is licensed under the terms of the GNU GPL, version 2.
# 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 28 29 30 31
        # Need a forward declaration
        ret += mcgen('''

static void visit_type_%(c_type)s_fields(Visitor *m, %(c_type)s **obj, Error **errp);
''',
32
                     c_type=type.c_name())
33 34

    ret += mcgen('''
35 36 37 38 39 40 41

static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
{
    Error *err = NULL;

    visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
    if (!err) {
42
        visit_type_%(c_type)s_fields(m, obj, errp);
43 44 45 46 47
        visit_end_implicit_struct(m, &err);
    }
    error_propagate(errp, err);
}
''',
48
                 c_type=type.c_name())
49
    return ret
50

51
def generate_visit_struct_fields(name, members, base = None):
52 53
    struct_fields_seen.add(name)

54
    ret = ''
55

56 57 58
    if base:
        ret += generate_visit_implicit_struct(base)

59 60
    ret += mcgen('''

61
static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
62 63
{
    Error *err = NULL;
M
Markus Armbruster 已提交
64

65
''',
E
Eric Blake 已提交
66
                 name=c_name(name))
67
    push_indent()
P
Paolo Bonzini 已提交
68

69 70
    if base:
        ret += mcgen('''
71
visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
72 73 74
if (err) {
    goto out;
}
75
''',
76
                     type=base.c_name(), c_name=c_name('base'))
77

78 79
    for memb in members:
        if memb.optional:
80
            ret += mcgen('''
81 82
visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
if (!err && (*obj)->has_%(c_name)s) {
83
''',
84
                         c_name=c_name(memb.name), name=memb.name)
85 86
            push_indent()

87
        ret += mcgen('''
88
visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
89
''',
90 91
                     type=memb.type.c_name(), c_name=c_name(memb.name),
                     name=memb.name)
92

93
        if memb.optional:
94 95 96
            pop_indent()
            ret += mcgen('''
}
97 98 99 100 101
''')
        ret += mcgen('''
if (err) {
    goto out;
}
P
Paolo Bonzini 已提交
102 103
''')

104
    pop_indent()
105 106
    if re.search('^ *goto out\\;', ret, re.MULTILINE):
        ret += mcgen('''
107

108 109 110
out:
''')
    ret += mcgen('''
111 112 113
    error_propagate(errp, err);
}
''')
114 115 116
    return ret


117
def generate_visit_struct_body(name):
118 119 120 121
    # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
    # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
    # rather than leaving it non-NULL. As currently written, the caller must
    # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
122
    ret = mcgen('''
123 124
    Error *err = NULL;

E
Eric Blake 已提交
125
    visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
126 127
    if (!err) {
        if (*obj) {
E
Eric Blake 已提交
128
            visit_type_%(c_name)s_fields(m, obj, errp);
129 130
        }
        visit_end_struct(m, &err);
131
    }
132
    error_propagate(errp, err);
133
''',
E
Eric Blake 已提交
134
                name=name, c_name=c_name(name))
P
Paolo Bonzini 已提交
135

136 137
    return ret

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
{
''',
E
Eric Blake 已提交
146
                 name=c_name(name))
P
Paolo Bonzini 已提交
147

148
    ret += generate_visit_struct_body(name)
149 150 151 152 153 154

    ret += mcgen('''
}
''')
    return ret

155
def gen_visit_list(name, element_type):
156 157
    return mcgen('''

158
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
159
{
P
Paolo Bonzini 已提交
160
    Error *err = NULL;
161
    GenericList *i, **prev;
162

163 164 165 166 167 168 169 170
    visit_start_list(m, name, &err);
    if (err) {
        goto out;
    }

    for (prev = (GenericList **)obj;
         !err && (i = visit_next_list(m, prev, &err)) != NULL;
         prev = &i) {
171 172
        %(name)s *native_i = (%(name)s *)i;
        visit_type_%(c_elt_type)s(m, &native_i->value, NULL, &err);
173
    }
174 175 176 177 178 179

    error_propagate(errp, err);
    err = NULL;
    visit_end_list(m, &err);
out:
    error_propagate(errp, err);
180 181
}
''',
182 183
                 name=c_name(name),
                 c_elt_type=element_type.c_name())
184

185
def generate_visit_enum(name):
186 187
    return mcgen('''

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):
K
Kevin Wolf 已提交
196 197
    ret = mcgen('''

198
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
K
Kevin Wolf 已提交
199 200 201
{
    Error *err = NULL;

202 203 204 205 206 207 208 209 210
    visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
    if (err) {
        goto out;
    }
    visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
    if (err) {
        goto out_end;
    }
    switch ((*obj)->kind) {
K
Kevin Wolf 已提交
211
''',
E
Eric Blake 已提交
212
                name=c_name(name))
K
Kevin Wolf 已提交
213

214 215 216
    for var in variants.variants:
        enum_full_value = c_enum_const(variants.tag_member.type.name,
                                       var.name)
K
Kevin Wolf 已提交
217
        ret += mcgen('''
218 219 220
    case %(enum_full_value)s:
        visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
        break;
K
Kevin Wolf 已提交
221
''',
222
                enum_full_value = enum_full_value,
223 224
                c_type=var.type.c_name(),
                c_name=c_name(var.name))
K
Kevin Wolf 已提交
225 226

    ret += mcgen('''
227 228
    default:
        abort();
K
Kevin Wolf 已提交
229
    }
230 231 232 233 234 235
out_end:
    error_propagate(errp, err);
    err = NULL;
    visit_end_implicit_struct(m, &err);
out:
    error_propagate(errp, err);
K
Kevin Wolf 已提交
236 237 238 239 240
}
''')

    return ret

241 242
def gen_visit_union(name, base, variants):
    ret = ''
243

244
    if base:
245 246
        members = [m for m in base.members if m != variants.tag_member]
        ret += generate_visit_struct_fields(name, members)
247

248 249 250 251
    for var in variants.variants:
        # Ugly special case for simple union TODO get rid of it
        if not var.simple_union_type():
            ret += generate_visit_implicit_struct(var.type)
252

253 254
    ret += mcgen('''

255
void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
256
{
257 258
    Error *err = NULL;

259
    visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
260 261 262 263
    if (err) {
        goto out;
    }
    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 271 272
        if (err) {
            goto out_obj;
        }
273
''',
274
                     name=c_name(name))
275

276 277 278 279
    disc_key = variants.tag_member.name
    if not variants.tag_name:
        # we pointlessly use a different key for simple unions
        disc_key = 'type'
280
    ret += mcgen('''
281
        visit_type_%(disc_type)s(m, &(*obj)->%(c_name)s, "%(disc_key)s", &err);
282 283 284
        if (err) {
            goto out_obj;
        }
285 286 287
        if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
            goto out_obj;
        }
288
        switch ((*obj)->%(c_name)s) {
289
''',
290 291 292 293 294
                 disc_type=variants.tag_member.type.c_name(),
                 # TODO ugly special case for simple union
                 # Use same tag name in C as on the wire to get rid of
                 # it, then: c_name=c_name(variants.tag_member.name)
                 c_name=c_name(variants.tag_name or 'kind'),
295
                 disc_key = disc_key)
296

297 298 299 300
    for var in variants.variants:
        # TODO ugly special case for simple union
        simple_union_type = var.simple_union_type()
        if simple_union_type:
301 302
            fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
        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 308 309
        case %(enum_full_value)s:
            ''' + fmt + '''
            break;
310
''',
311
                enum_full_value = enum_full_value,
312 313
                c_type=(simple_union_type or var.type).c_name(),
                c_name=c_name(var.name))
314 315

    ret += mcgen('''
316 317
        default:
            abort();
P
Paolo Bonzini 已提交
318
        }
319
out_obj:
P
Paolo Bonzini 已提交
320 321
        error_propagate(errp, err);
        err = NULL;
322 323 324
        visit_end_union(m, !!(*obj)->data, &err);
        error_propagate(errp, err);
        err = NULL;
325
    }
326 327 328
    visit_end_struct(m, &err);
out:
    error_propagate(errp, err);
329 330 331
}
''')

332 333
    return ret

334 335 336 337
def gen_visit_decl(name, scalar=False):
    c_type = c_name(name) + ' *'
    if not scalar:
        c_type += '*'
338
    return mcgen('''
339
void visit_type_%(c_name)s(Visitor *m, %(c_type)sobj, const char *name, Error **errp);
340
''',
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
                 c_name=c_name(name), c_type=c_type)


class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
    def __init__(self):
        self.decl = None
        self.defn = None
        self._btin = None

    def visit_begin(self, schema):
        self.decl = ''
        self.defn = ''
        self._btin = guardstart('QAPI_VISIT_BUILTIN')

    def visit_end(self):
        # To avoid header dependency hell, we always generate
        # declarations for built-in types in our header files and
        # simply guard them.  See also do_builtins (command line
        # option -b).
        self._btin += guardend('QAPI_VISIT_BUILTIN')
        self.decl = self._btin + self.decl
        self._btin = None

    def visit_enum_type(self, name, info, values, prefix):
        self.decl += gen_visit_decl(name, scalar=True)
        self.defn += generate_visit_enum(name)

    def visit_array_type(self, name, info, element_type):
        decl = gen_visit_decl(name)
        defn = gen_visit_list(name, element_type)
        if isinstance(element_type, QAPISchemaBuiltinType):
            self._btin += decl
            if do_builtins:
                self.defn += defn
        else:
            self.decl += decl
            self.defn += defn

    def visit_object_type(self, name, info, base, members, variants):
        if info:
            self.decl += gen_visit_decl(name)
            if variants:
                assert not members      # not implemented
                self.defn += gen_visit_union(name, base, variants)
            else:
                self.defn += gen_visit_struct(name, base, members)

    def visit_alternate_type(self, name, info, variants):
        self.decl += gen_visit_decl(name)
        self.defn += gen_visit_alternate(name, variants)

# If you link code generated from multiple schemata, you want only one
# instance of the code for built-in types.  Generate it only when
# do_builtins, enabled by command line option -b.  See also
# QAPISchemaGenVisitVisitor.visit_end().
396
do_builtins = False
397

398 399 400
(input_file, output_dir, do_c, do_h, prefix, opts) = \
    parse_command_line("b", ["builtins"])

401
for o, a in opts:
402
    if o in ("-b", "--builtins"):
403
        do_builtins = True
404

405
c_comment = '''
406 407 408 409 410 411 412 413 414 415 416 417
/*
 * schema-defined QAPI visitor functions
 *
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 * See the COPYING.LIB file in the top-level directory.
 *
 */
418 419
'''
h_comment = '''
420
/*
421
 * schema-defined QAPI visitor functions
422 423 424 425 426 427 428 429 430 431
 *
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 * See the COPYING.LIB file in the top-level directory.
 *
 */
432 433 434 435 436
'''

(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
                            'qapi-visit.c', 'qapi-visit.h',
                            c_comment, h_comment)
437

438 439 440 441 442
fdef.write(mcgen('''
#include "qemu-common.h"
#include "%(prefix)sqapi-visit.h"
''',
                 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 452 453 454 455
schema = QAPISchema(input_file)
gen = QAPISchemaGenVisitVisitor()
schema.visit(gen)
fdef.write(gen.defn)
fdecl.write(gen.decl)
456

457
close_output(fdef, fdecl)