Merge remote-tracking branch 'remotes/armbru/tags/pull-error-2015-06-09' into staging
[qemu.git] / scripts / qapi-types.py
blob6bd0b13759f45e1cc1673e047d053782a32d059f
2 # QAPI types generator
4 # Copyright IBM, Corp. 2011
6 # Authors:
7 # Anthony Liguori <aliguori@us.ibm.com>
9 # This work is licensed under the terms of the GNU GPL, version 2.
10 # See the COPYING file in the top-level directory.
12 from ordereddict import OrderedDict
13 from qapi import *
15 def generate_fwd_struct(name, members, builtin_type=False):
16 if builtin_type:
17 return mcgen('''
19 typedef struct %(name)sList
21 union {
22 %(type)s value;
23 uint64_t padding;
25 struct %(name)sList *next;
26 } %(name)sList;
27 ''',
28 type=c_type(name),
29 name=name)
31 return mcgen('''
33 typedef struct %(name)s %(name)s;
35 typedef struct %(name)sList
37 union {
38 %(name)s *value;
39 uint64_t padding;
41 struct %(name)sList *next;
42 } %(name)sList;
43 ''',
44 name=c_name(name))
46 def generate_fwd_enum_struct(name, members):
47 return mcgen('''
48 typedef struct %(name)sList
50 union {
51 %(name)s value;
52 uint64_t padding;
54 struct %(name)sList *next;
55 } %(name)sList;
56 ''',
57 name=c_name(name))
59 def generate_struct_fields(members):
60 ret = ''
62 for argname, argentry, optional in parse_args(members):
63 if optional:
64 ret += mcgen('''
65 bool has_%(c_name)s;
66 ''',
67 c_name=c_name(argname))
68 ret += mcgen('''
69 %(c_type)s %(c_name)s;
70 ''',
71 c_type=c_type(argentry), c_name=c_name(argname))
73 return ret
75 def generate_struct(expr):
77 structname = expr.get('struct', "")
78 fieldname = expr.get('field', "")
79 members = expr['data']
80 base = expr.get('base')
82 ret = mcgen('''
83 struct %(name)s
85 ''',
86 name=c_name(structname))
88 if base:
89 ret += generate_struct_fields({'base': base})
91 ret += generate_struct_fields(members)
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 ''')
101 if len(fieldname):
102 fieldname = " " + fieldname
103 ret += mcgen('''
104 }%(field)s;
105 ''',
106 field=fieldname)
108 return ret
110 def generate_enum_lookup(name, values):
111 ret = mcgen('''
112 const char *%(name)s_lookup[] = {
113 ''',
114 name=c_name(name))
115 i = 0
116 for value in values:
117 index = c_enum_const(name, value)
118 ret += mcgen('''
119 [%(index)s] = "%(value)s",
120 ''',
121 index = index, value = value)
123 max_index = c_enum_const(name, 'MAX')
124 ret += mcgen('''
125 [%(max_index)s] = NULL,
128 ''',
129 max_index=max_index)
130 return ret
132 def generate_enum(name, values):
133 name = c_name(name)
134 lookup_decl = mcgen('''
135 extern const char *%(name)s_lookup[];
136 ''',
137 name=name)
139 enum_decl = mcgen('''
140 typedef enum %(name)s
142 ''',
143 name=name)
145 # append automatically generated _MAX value
146 enum_values = values + [ 'MAX' ]
148 i = 0
149 for value in enum_values:
150 enum_full_value = c_enum_const(name, value)
151 enum_decl += mcgen('''
152 %(enum_full_value)s = %(i)d,
153 ''',
154 enum_full_value = enum_full_value,
155 i=i)
156 i += 1
158 enum_decl += mcgen('''
159 } %(name)s;
160 ''',
161 name=name)
163 return lookup_decl + enum_decl
165 def generate_alternate_qtypes(expr):
167 name = expr['alternate']
168 members = expr['data']
170 ret = mcgen('''
171 const int %(name)s_qtypes[QTYPE_MAX] = {
172 ''',
173 name=c_name(name))
175 for key in members:
176 qtype = find_alternate_member_qtype(members[key])
177 assert qtype, "Invalid alternate member"
179 ret += mcgen('''
180 [%(qtype)s] = %(enum_const)s,
181 ''',
182 qtype = qtype,
183 enum_const = c_enum_const(name + 'Kind', key))
185 ret += mcgen('''
187 ''')
188 return ret
191 def generate_union(expr, meta):
193 name = c_name(expr[meta])
194 typeinfo = expr['data']
196 base = expr.get('base')
197 discriminator = expr.get('discriminator')
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)
205 ret = mcgen('''
206 struct %(name)s
208 %(discriminator_type_name)s kind;
209 union {
210 void *data;
211 ''',
212 name=name,
213 discriminator_type_name=c_name(discriminator_type_name))
215 for key in typeinfo:
216 ret += mcgen('''
217 %(c_type)s %(c_name)s;
218 ''',
219 c_type=c_type(typeinfo[key]),
220 c_name=c_name(key))
222 ret += mcgen('''
224 ''')
226 if base:
227 assert discriminator
228 base_fields = find_struct(base)['data'].copy()
229 del base_fields[discriminator]
230 ret += generate_struct_fields(base_fields)
231 else:
232 assert not discriminator
234 ret += mcgen('''
236 ''')
237 if meta == 'alternate':
238 ret += mcgen('''
239 extern const int %(name)s_qtypes[];
240 ''',
241 name=name)
244 return ret
246 def generate_type_cleanup_decl(name):
247 ret = mcgen('''
248 void qapi_free_%(name)s(%(c_type)s obj);
249 ''',
250 c_type=c_type(name), name=c_name(name))
251 return ret
253 def generate_type_cleanup(name):
254 ret = mcgen('''
256 void qapi_free_%(name)s(%(c_type)s obj)
258 QapiDeallocVisitor *md;
259 Visitor *v;
261 if (!obj) {
262 return;
265 md = qapi_dealloc_visitor_new();
266 v = qapi_dealloc_get_visitor(md);
267 visit_type_%(name)s(v, &obj, NULL, NULL);
268 qapi_dealloc_visitor_cleanup(md);
270 ''',
271 c_type=c_type(name), name=c_name(name))
272 return ret
274 do_builtins = False
276 (input_file, output_dir, do_c, do_h, prefix, opts) = \
277 parse_command_line("b", ["builtins"])
279 for o, a in opts:
280 if o in ("-b", "--builtins"):
281 do_builtins = True
283 c_comment = '''
285 * deallocation functions for schema-defined QAPI types
287 * Copyright IBM, Corp. 2011
289 * Authors:
290 * Anthony Liguori <aliguori@us.ibm.com>
291 * Michael Roth <mdroth@linux.vnet.ibm.com>
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.
298 h_comment = '''
300 * schema-defined QAPI types
302 * Copyright IBM, Corp. 2011
304 * Authors:
305 * Anthony Liguori <aliguori@us.ibm.com>
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.
313 (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
314 'qapi-types.c', 'qapi-types.h',
315 c_comment, h_comment)
317 fdef.write(mcgen('''
318 #include "qapi/dealloc-visitor.h"
319 #include "%(prefix)sqapi-types.h"
320 #include "%(prefix)sqapi-visit.h"
322 ''',
323 prefix=prefix))
325 fdecl.write(mcgen('''
326 #include <stdbool.h>
327 #include <stdint.h>
329 '''))
331 exprs = parse_schema(input_file)
332 exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
334 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
335 for typename in builtin_types.keys():
336 fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
337 fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
339 for expr in exprs:
340 ret = "\n"
341 if expr.has_key('struct'):
342 ret += generate_fwd_struct(expr['struct'], expr['data'])
343 elif expr.has_key('enum'):
344 ret += generate_enum(expr['enum'], expr['data']) + "\n"
345 ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
346 fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
347 elif expr.has_key('union'):
348 ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
349 enum_define = discriminator_find_enum_define(expr)
350 if not enum_define:
351 ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
352 fdef.write(generate_enum_lookup('%sKind' % expr['union'],
353 expr['data'].keys()))
354 elif expr.has_key('alternate'):
355 ret += generate_fwd_struct(expr['alternate'], expr['data']) + "\n"
356 ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
357 fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
358 expr['data'].keys()))
359 fdef.write(generate_alternate_qtypes(expr))
360 else:
361 continue
362 fdecl.write(ret)
364 # to avoid header dependency hell, we always generate declarations
365 # for built-in types in our header files and simply guard them
366 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
367 for typename in builtin_types.keys():
368 fdecl.write(generate_type_cleanup_decl(typename + "List"))
369 fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
371 # ...this doesn't work for cases where we link in multiple objects that
372 # have the functions defined, so we use -b option to provide control
373 # over these cases
374 if do_builtins:
375 fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
376 for typename in builtin_types.keys():
377 fdef.write(generate_type_cleanup(typename + "List"))
378 fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
380 for expr in exprs:
381 ret = "\n"
382 if expr.has_key('struct'):
383 ret += generate_struct(expr) + "\n"
384 ret += generate_type_cleanup_decl(expr['struct'] + "List")
385 fdef.write(generate_type_cleanup(expr['struct'] + "List") + "\n")
386 ret += generate_type_cleanup_decl(expr['struct'])
387 fdef.write(generate_type_cleanup(expr['struct']) + "\n")
388 elif expr.has_key('union'):
389 ret += generate_union(expr, 'union')
390 ret += generate_type_cleanup_decl(expr['union'] + "List")
391 fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
392 ret += generate_type_cleanup_decl(expr['union'])
393 fdef.write(generate_type_cleanup(expr['union']) + "\n")
394 elif expr.has_key('alternate'):
395 ret += generate_union(expr, 'alternate')
396 ret += generate_type_cleanup_decl(expr['alternate'] + "List")
397 fdef.write(generate_type_cleanup(expr['alternate'] + "List") + "\n")
398 ret += generate_type_cleanup_decl(expr['alternate'])
399 fdef.write(generate_type_cleanup(expr['alternate']) + "\n")
400 elif expr.has_key('enum'):
401 ret += generate_type_cleanup_decl(expr['enum'] + "List")
402 fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
403 else:
404 continue
405 fdecl.write(ret)
407 close_output(fdef, fdecl)