]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi-types.py
qapi-types: Split generate_fwd_builtin() off generate_fwd_struct()
[mirror_qemu.git] / scripts / qapi-types.py
CommitLineData
fb3182ce
MR
1#
2# QAPI types generator
3#
4# Copyright IBM, Corp. 2011
5#
6# Authors:
7# Anthony Liguori <aliguori@us.ibm.com>
8#
678e48a2
MA
9# This work is licensed under the terms of the GNU GPL, version 2.
10# See the COPYING file in the top-level directory.
fb3182ce
MR
11
12from ordereddict import OrderedDict
13from qapi import *
fb3182ce 14
c5ecd7e1
MA
15def generate_fwd_builtin(name):
16 return mcgen('''
c0afa9c5
MR
17
18typedef struct %(name)sList
19{
a678e26c
MR
20 union {
21 %(type)s value;
22 uint64_t padding;
23 };
c0afa9c5
MR
24 struct %(name)sList *next;
25} %(name)sList;
26''',
c5ecd7e1
MA
27 type=c_type(name),
28 name=name)
c0afa9c5 29
c5ecd7e1 30def generate_fwd_struct(name):
fb3182ce 31 return mcgen('''
c0afa9c5 32
fb3182ce
MR
33typedef struct %(name)s %(name)s;
34
35typedef struct %(name)sList
36{
a678e26c
MR
37 union {
38 %(name)s *value;
39 uint64_t padding;
40 };
fb3182ce
MR
41 struct %(name)sList *next;
42} %(name)sList;
43''',
83a02706 44 name=c_name(name))
fb3182ce 45
ae0a7a10 46def generate_fwd_enum_struct(name):
b9c4b48d
AK
47 return mcgen('''
48typedef struct %(name)sList
49{
02dc4bf5
CR
50 union {
51 %(name)s value;
52 uint64_t padding;
53 };
b9c4b48d
AK
54 struct %(name)sList *next;
55} %(name)sList;
56''',
fce384b8 57 name=c_name(name))
b9c4b48d 58
01537030
KW
59def generate_struct_fields(members):
60 ret = ''
fb3182ce 61
6b5abc7d 62 for argname, argentry, optional in parse_args(members):
fb3182ce
MR
63 if optional:
64 ret += mcgen('''
65 bool has_%(c_name)s;
66''',
18df515e 67 c_name=c_name(argname))
6b5abc7d 68 ret += mcgen('''
fb3182ce
MR
69 %(c_type)s %(c_name)s;
70''',
18df515e 71 c_type=c_type(argentry), c_name=c_name(argname))
fb3182ce 72
01537030
KW
73 return ret
74
14d36307
KW
75def generate_struct(expr):
76
fd41dd4e 77 structname = expr.get('struct', "")
14d36307
KW
78 fieldname = expr.get('field', "")
79 members = expr['data']
622f557f 80 base = expr.get('base')
14d36307 81
01537030
KW
82 ret = mcgen('''
83struct %(name)s
84{
85''',
83a02706 86 name=c_name(structname))
01537030 87
622f557f
KW
88 if base:
89 ret += generate_struct_fields({'base': base})
90
01537030
KW
91 ret += generate_struct_fields(members)
92
83ecb22b
PM
93 # Make sure that all structs have at least one field; this avoids
94 # potential issues with attempting to malloc space for zero-length structs
95 # in C, and also incompatibility with C++ (where an empty struct is size 1).
96 if not base and not members:
97 ret += mcgen('''
98 char qapi_dummy_field_for_empty_struct;
99''')
100
fb3182ce
MR
101 if len(fieldname):
102 fieldname = " " + fieldname
103 ret += mcgen('''
104}%(field)s;
105''',
106 field=fieldname)
107
108 return ret
109
110def generate_enum_lookup(name, values):
111 ret = mcgen('''
112const char *%(name)s_lookup[] = {
113''',
fce384b8 114 name=c_name(name))
fb3182ce
MR
115 i = 0
116 for value in values:
7c81c61f 117 index = c_enum_const(name, value)
fb3182ce 118 ret += mcgen('''
912ae9c8 119 [%(index)s] = "%(value)s",
fb3182ce 120''',
912ae9c8 121 index = index, value = value)
fb3182ce 122
7c81c61f 123 max_index = c_enum_const(name, 'MAX')
fb3182ce 124 ret += mcgen('''
912ae9c8 125 [%(max_index)s] = NULL,
fb3182ce
MR
126};
127
912ae9c8
MT
128''',
129 max_index=max_index)
fb3182ce
MR
130 return ret
131
132def generate_enum(name, values):
fce384b8 133 name = c_name(name)
fb3182ce
MR
134 lookup_decl = mcgen('''
135extern const char *%(name)s_lookup[];
136''',
137 name=name)
138
139 enum_decl = mcgen('''
140typedef enum %(name)s
141{
142''',
143 name=name)
144
303b54b1
LC
145 # append automatically generated _MAX value
146 enum_values = values + [ 'MAX' ]
147
fb3182ce 148 i = 0
303b54b1 149 for value in enum_values:
7c81c61f 150 enum_full_value = c_enum_const(name, value)
fb3182ce 151 enum_decl += mcgen('''
b0b58195 152 %(enum_full_value)s = %(i)d,
fb3182ce 153''',
b0b58195 154 enum_full_value = enum_full_value,
fb3182ce
MR
155 i=i)
156 i += 1
157
158 enum_decl += mcgen('''
159} %(name)s;
160''',
161 name=name)
162
163 return lookup_decl + enum_decl
164
811d04fd 165def generate_alternate_qtypes(expr):
69dd62df 166
ab916fad 167 name = expr['alternate']
69dd62df
KW
168 members = expr['data']
169
170 ret = mcgen('''
171const int %(name)s_qtypes[QTYPE_MAX] = {
172''',
d1f07c86 173 name=c_name(name))
69dd62df
KW
174
175 for key in members:
811d04fd 176 qtype = find_alternate_member_qtype(members[key])
ab916fad 177 assert qtype, "Invalid alternate member"
69dd62df
KW
178
179 ret += mcgen('''
d1f07c86 180 [%(qtype)s] = %(enum_const)s,
69dd62df 181''',
d1f07c86
EB
182 qtype = qtype,
183 enum_const = c_enum_const(name + 'Kind', key))
69dd62df
KW
184
185 ret += mcgen('''
186};
187''')
188 return ret
189
190
ab916fad 191def generate_union(expr, meta):
e2503f5e 192
bb337290 193 name = c_name(expr[meta])
e2503f5e 194 typeinfo = expr['data']
50f2bdc7 195
e2503f5e 196 base = expr.get('base')
50f2bdc7 197 discriminator = expr.get('discriminator')
e2503f5e 198
bceae769
WX
199 enum_define = discriminator_find_enum_define(expr)
200 if enum_define:
201 discriminator_type_name = enum_define['enum_name']
202 else:
203 discriminator_type_name = '%sKind' % (name)
204
fb3182ce
MR
205 ret = mcgen('''
206struct %(name)s
207{
bceae769 208 %(discriminator_type_name)s kind;
fb3182ce 209 union {
dc8fb6df 210 void *data;
fb3182ce 211''',
bceae769 212 name=name,
857af5f0 213 discriminator_type_name=c_name(discriminator_type_name))
fb3182ce
MR
214
215 for key in typeinfo:
216 ret += mcgen('''
217 %(c_type)s %(c_name)s;
218''',
219 c_type=c_type(typeinfo[key]),
18df515e 220 c_name=c_name(key))
fb3182ce
MR
221
222 ret += mcgen('''
223 };
e2503f5e
KW
224''')
225
226 if base:
a8d4a2e4
EB
227 assert discriminator
228 base_fields = find_struct(base)['data'].copy()
229 del base_fields[discriminator]
50f2bdc7
KW
230 ret += generate_struct_fields(base_fields)
231 else:
232 assert not discriminator
e2503f5e
KW
233
234 ret += mcgen('''
fb3182ce
MR
235};
236''')
ab916fad 237 if meta == 'alternate':
69dd62df
KW
238 ret += mcgen('''
239extern const int %(name)s_qtypes[];
240''',
241 name=name)
242
fb3182ce
MR
243
244 return ret
245
246def generate_type_cleanup_decl(name):
247 ret = mcgen('''
fce384b8 248void qapi_free_%(name)s(%(c_type)s obj);
fb3182ce 249''',
fce384b8 250 c_type=c_type(name), name=c_name(name))
fb3182ce
MR
251 return ret
252
253def generate_type_cleanup(name):
254 ret = mcgen('''
c0afa9c5 255
fce384b8 256void qapi_free_%(name)s(%(c_type)s obj)
fb3182ce
MR
257{
258 QapiDeallocVisitor *md;
259 Visitor *v;
260
261 if (!obj) {
262 return;
263 }
264
265 md = qapi_dealloc_visitor_new();
266 v = qapi_dealloc_get_visitor(md);
fce384b8 267 visit_type_%(name)s(v, &obj, NULL, NULL);
fb3182ce
MR
268 qapi_dealloc_visitor_cleanup(md);
269}
270''',
fce384b8 271 c_type=c_type(name), name=c_name(name))
fb3182ce
MR
272 return ret
273
c0afa9c5 274do_builtins = False
8d3bc517 275
2114f5a9
MA
276(input_file, output_dir, do_c, do_h, prefix, opts) = \
277 parse_command_line("b", ["builtins"])
278
fb3182ce 279for o, a in opts:
2114f5a9 280 if o in ("-b", "--builtins"):
c0afa9c5 281 do_builtins = True
8d3bc517 282
12f8e1b9 283c_comment = '''
fb3182ce
MR
284/*
285 * deallocation functions for schema-defined QAPI types
286 *
287 * Copyright IBM, Corp. 2011
288 *
289 * Authors:
290 * Anthony Liguori <aliguori@us.ibm.com>
291 * Michael Roth <mdroth@linux.vnet.ibm.com>
292 *
293 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
294 * See the COPYING.LIB file in the top-level directory.
295 *
296 */
12f8e1b9
MA
297'''
298h_comment = '''
fb3182ce
MR
299/*
300 * schema-defined QAPI types
301 *
302 * Copyright IBM, Corp. 2011
303 *
304 * Authors:
305 * Anthony Liguori <aliguori@us.ibm.com>
306 *
307 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
308 * See the COPYING.LIB file in the top-level directory.
309 *
310 */
12f8e1b9 311'''
fb3182ce 312
12f8e1b9
MA
313(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
314 'qapi-types.c', 'qapi-types.h',
315 c_comment, h_comment)
fb3182ce 316
12f8e1b9
MA
317fdef.write(mcgen('''
318#include "qapi/dealloc-visitor.h"
319#include "%(prefix)sqapi-types.h"
320#include "%(prefix)sqapi-visit.h"
321
322''',
323 prefix=prefix))
324
325fdecl.write(mcgen('''
da4fea06
IM
326#include <stdbool.h>
327#include <stdint.h>
b68a8472 328
12f8e1b9 329'''))
fb3182ce 330
33aaad52 331exprs = parse_schema(input_file)
fb3182ce 332
c0afa9c5 333fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
b52c4b9c 334for typename in builtin_types.keys():
c5ecd7e1 335 fdecl.write(generate_fwd_builtin(typename))
c0afa9c5
MR
336fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
337
fb3182ce
MR
338for expr in exprs:
339 ret = "\n"
fd41dd4e 340 if expr.has_key('struct'):
ae0a7a10 341 ret += generate_fwd_struct(expr['struct'])
fb3182ce 342 elif expr.has_key('enum'):
b9c4b48d 343 ret += generate_enum(expr['enum'], expr['data']) + "\n"
ae0a7a10 344 ret += generate_fwd_enum_struct(expr['enum'])
fb3182ce
MR
345 fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
346 elif expr.has_key('union'):
ae0a7a10 347 ret += generate_fwd_struct(expr['union']) + "\n"
bceae769
WX
348 enum_define = discriminator_find_enum_define(expr)
349 if not enum_define:
350 ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
351 fdef.write(generate_enum_lookup('%sKind' % expr['union'],
352 expr['data'].keys()))
ab916fad 353 elif expr.has_key('alternate'):
ae0a7a10 354 ret += generate_fwd_struct(expr['alternate']) + "\n"
ab916fad
EB
355 ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
356 fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
357 expr['data'].keys()))
358 fdef.write(generate_alternate_qtypes(expr))
fb3182ce
MR
359 else:
360 continue
361 fdecl.write(ret)
362
c0afa9c5
MR
363# to avoid header dependency hell, we always generate declarations
364# for built-in types in our header files and simply guard them
365fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
b52c4b9c 366for typename in builtin_types.keys():
c0afa9c5
MR
367 fdecl.write(generate_type_cleanup_decl(typename + "List"))
368fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
369
370# ...this doesn't work for cases where we link in multiple objects that
371# have the functions defined, so we use -b option to provide control
372# over these cases
373if do_builtins:
374 fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
b52c4b9c 375 for typename in builtin_types.keys():
c0afa9c5
MR
376 fdef.write(generate_type_cleanup(typename + "List"))
377 fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
378
fb3182ce
MR
379for expr in exprs:
380 ret = "\n"
fd41dd4e 381 if expr.has_key('struct'):
14d36307 382 ret += generate_struct(expr) + "\n"
fd41dd4e
EB
383 ret += generate_type_cleanup_decl(expr['struct'] + "List")
384 fdef.write(generate_type_cleanup(expr['struct'] + "List") + "\n")
385 ret += generate_type_cleanup_decl(expr['struct'])
386 fdef.write(generate_type_cleanup(expr['struct']) + "\n")
fb3182ce 387 elif expr.has_key('union'):
ab916fad 388 ret += generate_union(expr, 'union')
dc8fb6df
PB
389 ret += generate_type_cleanup_decl(expr['union'] + "List")
390 fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
391 ret += generate_type_cleanup_decl(expr['union'])
392 fdef.write(generate_type_cleanup(expr['union']) + "\n")
ab916fad
EB
393 elif expr.has_key('alternate'):
394 ret += generate_union(expr, 'alternate')
395 ret += generate_type_cleanup_decl(expr['alternate'] + "List")
396 fdef.write(generate_type_cleanup(expr['alternate'] + "List") + "\n")
397 ret += generate_type_cleanup_decl(expr['alternate'])
398 fdef.write(generate_type_cleanup(expr['alternate']) + "\n")
b9c4b48d
AK
399 elif expr.has_key('enum'):
400 ret += generate_type_cleanup_decl(expr['enum'] + "List")
401 fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
fb3182ce
MR
402 else:
403 continue
404 fdecl.write(ret)
405
12f8e1b9 406close_output(fdef, fdecl)