qapi-types.py 9.4 KB
Newer Older
1 2 3 4
#
# QAPI types generator
#
# Copyright IBM, Corp. 2011
5
# Copyright (c) 2013-2015 Red Hat Inc.
6 7 8
#
# Authors:
#  Anthony Liguori <aliguori@us.ibm.com>
9
#  Markus Armbruster <armbru@redhat.com>
10
#
11 12
# This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory.
13 14 15

from qapi import *

16

17
def gen_fwd_object_or_array(name):
18
    return mcgen('''
19

20
typedef struct %(c_name)s %(c_name)s;
21
''',
22 23
                 c_name=c_name(name))

24

25
def gen_array(name, element_type):
26
    return mcgen('''
M
Markus Armbruster 已提交
27

28
struct %(c_name)s {
29
    union {
30
        %(c_type)s value;
31 32
        uint64_t padding;
    };
33
    %(c_name)s *next;
34
};
35
''',
36 37
                 c_name=c_name(name), c_type=element_type.c_type())

38

39
def gen_struct_field(name, typ, optional):
40
    ret = ''
41

42 43
    if optional:
        ret += mcgen('''
44 45
    bool has_%(c_name)s;
''',
46 47
                     c_name=c_name(name))
    ret += mcgen('''
48 49
    %(c_type)s %(c_name)s;
''',
50
                 c_type=typ.c_type(), c_name=c_name(name))
51 52
    return ret

53

54
def gen_struct_fields(local_members, base=None):
55
    ret = ''
56

57 58 59 60 61 62 63 64 65 66 67 68
    if base:
        ret += mcgen('''
    /* Members inherited from %(c_name)s: */
''',
                     c_name=base.c_name())
        for memb in base.members:
            ret += gen_struct_field(memb.name, memb.type, memb.optional)
        ret += mcgen('''
    /* Own members: */
''')

    for memb in local_members:
69 70
        ret += gen_struct_field(memb.name, memb.type, memb.optional)
    return ret
71

72

73
def gen_struct(name, base, members):
74
    ret = mcgen('''
M
Markus Armbruster 已提交
75

76
struct %(c_name)s {
77
''',
78
                c_name=c_name(name))
79

E
Eric Blake 已提交
80
    ret += gen_struct_fields(members, base)
81

82
    # Make sure that all structs have at least one field; this avoids
83 84 85
    # potential issues with attempting to malloc space for zero-length
    # structs in C, and also incompatibility with C++ (where an empty
    # struct is size 1).
E
Eric Blake 已提交
86
    if not (base and base.members) and not members:
87
        ret += mcgen('''
88 89 90
    char qapi_dummy_field_for_empty_struct;
''')

91
    ret += mcgen('''
92 93
};
''')
94 95 96

    return ret

97

98 99 100 101 102 103 104 105 106 107 108 109 110
def gen_upcast(name, base):
    # C makes const-correctness ugly.  We have to cast away const to let
    # this function work for both const and non-const obj.
    return mcgen('''

static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
{
    return (%(base)s *)obj;
}
''',
                 c_name=c_name(name), base=base.c_name())


111 112
def gen_alternate_qtypes_decl(name):
    return mcgen('''
K
Kevin Wolf 已提交
113

114 115 116
extern const int %(c_name)s_qtypes[];
''',
                 c_name=c_name(name))
K
Kevin Wolf 已提交
117

118

119
def gen_alternate_qtypes(name, variants):
K
Kevin Wolf 已提交
120
    ret = mcgen('''
M
Markus Armbruster 已提交
121

122
const int %(c_name)s_qtypes[QTYPE_MAX] = {
K
Kevin Wolf 已提交
123
''',
124
                c_name=c_name(name))
K
Kevin Wolf 已提交
125

126 127 128
    for var in variants.variants:
        qtype = var.type.alternate_qtype()
        assert qtype
K
Kevin Wolf 已提交
129 130

        ret += mcgen('''
E
Eric Blake 已提交
131
    [%(qtype)s] = %(enum_const)s,
K
Kevin Wolf 已提交
132
''',
133
                     qtype=qtype,
134 135
                     enum_const=c_enum_const(variants.tag_member.type.name,
                                             var.name))
K
Kevin Wolf 已提交
136 137 138 139 140 141

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

142

143
def gen_union(name, base, variants):
144
    ret = mcgen('''
M
Markus Armbruster 已提交
145

146
struct %(c_name)s {
147
''',
148
                c_name=c_name(name))
149
    if base:
150
        ret += gen_struct_fields([], base)
151 152
    else:
        ret += mcgen('''
153
    %(c_type)s kind;
154
''',
155
                     c_type=c_name(variants.tag_member.type.name))
156

157 158 159 160 161 162 163 164
    # FIXME: What purpose does data serve, besides preventing a union that
    # has a branch named 'data'? We use it in qapi-visit.py to decide
    # whether to bypass the switch statement if visiting the discriminator
    # failed; but since we 0-initialize structs, and cannot tell what
    # branch of the union is in use if the discriminator is invalid, there
    # should not be any data leaks even without a data pointer.  Or, if
    # 'data' is merely added to guarantee we don't have an empty union,
    # shouldn't we enforce that at .json parse time?
165 166
    ret += mcgen('''
    union { /* union tag is @%(c_name)s */
167
        void *data;
168
''',
169 170 171 172 173 174 175 176
                 # 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'))

    for var in variants.variants:
        # Ugly special case for simple union TODO get rid of it
        typ = var.simple_union_type() or var.type
177 178 179
        ret += mcgen('''
        %(c_type)s %(c_name)s;
''',
180 181
                     c_type=typ.c_type(),
                     c_name=c_name(var.name))
182 183 184 185 186 187 188 189

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

    return ret

190 191

def gen_type_cleanup_decl(name):
192
    ret = mcgen('''
193

194
void qapi_free_%(c_name)s(%(c_name)s *obj);
195
''',
196
                c_name=c_name(name))
197 198
    return ret

199 200

def gen_type_cleanup(name):
201
    ret = mcgen('''
202

203
void qapi_free_%(c_name)s(%(c_name)s *obj)
204
{
205
    QapiDeallocVisitor *qdv;
206 207 208 209 210 211
    Visitor *v;

    if (!obj) {
        return;
    }

212 213
    qdv = qapi_dealloc_visitor_new();
    v = qapi_dealloc_get_visitor(qdv);
214
    visit_type_%(c_name)s(v, &obj, NULL, NULL);
215
    qapi_dealloc_visitor_cleanup(qdv);
216 217
}
''',
218
                c_name=c_name(name))
219 220
    return ret

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
    def __init__(self):
        self.decl = None
        self.defn = None
        self._fwdecl = None
        self._fwdefn = None
        self._btin = None

    def visit_begin(self, schema):
        self.decl = ''
        self.defn = ''
        self._fwdecl = ''
        self._fwdefn = ''
        self._btin = guardstart('QAPI_TYPES_BUILTIN')

    def visit_end(self):
        self.decl = self._fwdecl + self.decl
        self._fwdecl = None
        self.defn = self._fwdefn + self.defn
        self._fwdefn = None
        # 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_TYPES_BUILTIN')
        self.decl = self._btin + self.decl
        self._btin = None

250 251
    def visit_needed(self, entity):
        # Visit everything except implicit objects
252 253
        return not (entity.is_implicit() and
                    isinstance(entity, QAPISchemaObjectType))
254

255
    def _gen_type_cleanup(self, name):
256 257
        self.decl += gen_type_cleanup_decl(name)
        self.defn += gen_type_cleanup(name)
258 259

    def visit_enum_type(self, name, info, values, prefix):
260 261
        self._fwdecl += gen_enum(name, values, prefix)
        self._fwdefn += gen_enum_lookup(name, values, prefix)
262 263 264 265 266

    def visit_array_type(self, name, info, element_type):
        if isinstance(element_type, QAPISchemaBuiltinType):
            self._btin += gen_fwd_object_or_array(name)
            self._btin += gen_array(name, element_type)
267
            self._btin += gen_type_cleanup_decl(name)
268
            if do_builtins:
269
                self.defn += gen_type_cleanup(name)
270 271 272 273 274 275
        else:
            self._fwdecl += gen_fwd_object_or_array(name)
            self.decl += gen_array(name, element_type)
            self._gen_type_cleanup(name)

    def visit_object_type(self, name, info, base, members, variants):
276 277 278 279 280 281
        self._fwdecl += gen_fwd_object_or_array(name)
        if variants:
            assert not members      # not implemented
            self.decl += gen_union(name, base, variants)
        else:
            self.decl += gen_struct(name, base, members)
E
Eric Blake 已提交
282 283
        if base:
            self.decl += gen_upcast(name, base)
284
        self._gen_type_cleanup(name)
285 286 287 288 289 290 291 292 293 294 295 296

    def visit_alternate_type(self, name, info, variants):
        self._fwdecl += gen_fwd_object_or_array(name)
        self._fwdefn += gen_alternate_qtypes(name, variants)
        self.decl += gen_union(name, None, variants)
        self.decl += gen_alternate_qtypes_decl(name)
        self._gen_type_cleanup(name)

# 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
# QAPISchemaGenTypeVisitor.visit_end().
297
do_builtins = False
298

299 300 301
(input_file, output_dir, do_c, do_h, prefix, opts) = \
    parse_command_line("b", ["builtins"])

302
for o, a in opts:
303
    if o in ("-b", "--builtins"):
304
        do_builtins = True
305

306
c_comment = '''
307 308 309 310 311 312 313 314 315 316 317 318 319
/*
 * deallocation functions for schema-defined QAPI types
 *
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *  Michael Roth      <mdroth@linux.vnet.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.
 *
 */
320 321
'''
h_comment = '''
322 323 324 325 326 327 328 329 330 331 332 333
/*
 * schema-defined QAPI types
 *
 * 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.
 *
 */
334
'''
335

336 337 338
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
                            'qapi-types.c', 'qapi-types.h',
                            c_comment, h_comment)
339

340 341 342 343 344 345 346 347
fdef.write(mcgen('''
#include "qapi/dealloc-visitor.h"
#include "%(prefix)sqapi-types.h"
#include "%(prefix)sqapi-visit.h"
''',
                 prefix=prefix))

fdecl.write(mcgen('''
348 349
#include <stdbool.h>
#include <stdint.h>
350
#include "qapi/qmp/qobject.h"
351
'''))
352

353 354 355 356 357
schema = QAPISchema(input_file)
gen = QAPISchemaGenTypeVisitor()
schema.visit(gen)
fdef.write(gen.defn)
fdecl.write(gen.decl)
358

359
close_output(fdef, fdecl)