]> git.proxmox.com Git - qemu.git/blob - scripts/qapi-types.py
qapi-types/visit.py: Pass whole expr dict for structs
[qemu.git] / scripts / qapi-types.py
1 #
2 # QAPI types generator
3 #
4 # Copyright IBM, Corp. 2011
5 #
6 # Authors:
7 # Anthony Liguori <aliguori@us.ibm.com>
8 #
9 # This work is licensed under the terms of the GNU GPLv2.
10 # See the COPYING.LIB file in the top-level directory.
11
12 from ordereddict import OrderedDict
13 from qapi import *
14 import sys
15 import os
16 import getopt
17 import errno
18
19 def generate_fwd_struct(name, members, builtin_type=False):
20 if builtin_type:
21 return mcgen('''
22
23 typedef struct %(name)sList
24 {
25 union {
26 %(type)s value;
27 uint64_t padding;
28 };
29 struct %(name)sList *next;
30 } %(name)sList;
31 ''',
32 type=c_type(name),
33 name=name)
34
35 return mcgen('''
36
37 typedef struct %(name)s %(name)s;
38
39 typedef struct %(name)sList
40 {
41 union {
42 %(name)s *value;
43 uint64_t padding;
44 };
45 struct %(name)sList *next;
46 } %(name)sList;
47 ''',
48 name=name)
49
50 def generate_fwd_enum_struct(name, members):
51 return mcgen('''
52 typedef struct %(name)sList
53 {
54 union {
55 %(name)s value;
56 uint64_t padding;
57 };
58 struct %(name)sList *next;
59 } %(name)sList;
60 ''',
61 name=name)
62
63 def generate_struct_fields(members):
64 ret = ''
65
66 for argname, argentry, optional, structured in parse_args(members):
67 if optional:
68 ret += mcgen('''
69 bool has_%(c_name)s;
70 ''',
71 c_name=c_var(argname))
72 if structured:
73 push_indent()
74 ret += generate_struct({ "field": argname, "data": argentry})
75 pop_indent()
76 else:
77 ret += mcgen('''
78 %(c_type)s %(c_name)s;
79 ''',
80 c_type=c_type(argentry), c_name=c_var(argname))
81
82 return ret
83
84 def generate_struct(expr):
85
86 structname = expr.get('type', "")
87 fieldname = expr.get('field', "")
88 members = expr['data']
89
90 ret = mcgen('''
91 struct %(name)s
92 {
93 ''',
94 name=structname)
95
96 ret += generate_struct_fields(members)
97
98 if len(fieldname):
99 fieldname = " " + fieldname
100 ret += mcgen('''
101 }%(field)s;
102 ''',
103 field=fieldname)
104
105 return ret
106
107 def generate_enum_lookup(name, values):
108 ret = mcgen('''
109 const char *%(name)s_lookup[] = {
110 ''',
111 name=name)
112 i = 0
113 for value in values:
114 ret += mcgen('''
115 "%(value)s",
116 ''',
117 value=value)
118
119 ret += mcgen('''
120 NULL,
121 };
122
123 ''')
124 return ret
125
126 def generate_enum_name(name):
127 if name.isupper():
128 return c_fun(name, False)
129 new_name = ''
130 for c in c_fun(name, False):
131 if c.isupper():
132 new_name += '_'
133 new_name += c
134 return new_name.lstrip('_').upper()
135
136 def generate_enum(name, values):
137 lookup_decl = mcgen('''
138 extern const char *%(name)s_lookup[];
139 ''',
140 name=name)
141
142 enum_decl = mcgen('''
143 typedef enum %(name)s
144 {
145 ''',
146 name=name)
147
148 # append automatically generated _MAX value
149 enum_values = values + [ 'MAX' ]
150
151 i = 0
152 for value in enum_values:
153 enum_decl += mcgen('''
154 %(abbrev)s_%(value)s = %(i)d,
155 ''',
156 abbrev=de_camel_case(name).upper(),
157 value=generate_enum_name(value),
158 i=i)
159 i += 1
160
161 enum_decl += mcgen('''
162 } %(name)s;
163 ''',
164 name=name)
165
166 return lookup_decl + enum_decl
167
168 def generate_anon_union_qtypes(expr):
169
170 name = expr['union']
171 members = expr['data']
172
173 ret = mcgen('''
174 const int %(name)s_qtypes[QTYPE_MAX] = {
175 ''',
176 name=name)
177
178 for key in members:
179 qapi_type = members[key]
180 if builtin_type_qtypes.has_key(qapi_type):
181 qtype = builtin_type_qtypes[qapi_type]
182 elif find_struct(qapi_type):
183 qtype = "QTYPE_QDICT"
184 elif find_union(qapi_type):
185 qtype = "QTYPE_QDICT"
186 else:
187 assert False, "Invalid anonymous union member"
188
189 ret += mcgen('''
190 [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s,
191 ''',
192 qtype = qtype,
193 abbrev = de_camel_case(name).upper(),
194 enum = c_fun(de_camel_case(key),False).upper())
195
196 ret += mcgen('''
197 };
198 ''')
199 return ret
200
201
202 def generate_union(expr):
203
204 name = expr['union']
205 typeinfo = expr['data']
206
207 base = expr.get('base')
208 discriminator = expr.get('discriminator')
209
210 ret = mcgen('''
211 struct %(name)s
212 {
213 %(name)sKind kind;
214 union {
215 void *data;
216 ''',
217 name=name)
218
219 for key in typeinfo:
220 ret += mcgen('''
221 %(c_type)s %(c_name)s;
222 ''',
223 c_type=c_type(typeinfo[key]),
224 c_name=c_fun(key))
225
226 ret += mcgen('''
227 };
228 ''')
229
230 if base:
231 base_fields = find_struct(base)['data']
232 if discriminator:
233 base_fields = base_fields.copy()
234 del base_fields[discriminator]
235 ret += generate_struct_fields(base_fields)
236 else:
237 assert not discriminator
238
239 ret += mcgen('''
240 };
241 ''')
242 if discriminator == {}:
243 ret += mcgen('''
244 extern const int %(name)s_qtypes[];
245 ''',
246 name=name)
247
248
249 return ret
250
251 def generate_type_cleanup_decl(name):
252 ret = mcgen('''
253 void qapi_free_%(type)s(%(c_type)s obj);
254 ''',
255 c_type=c_type(name),type=name)
256 return ret
257
258 def generate_type_cleanup(name):
259 ret = mcgen('''
260
261 void qapi_free_%(type)s(%(c_type)s obj)
262 {
263 QapiDeallocVisitor *md;
264 Visitor *v;
265
266 if (!obj) {
267 return;
268 }
269
270 md = qapi_dealloc_visitor_new();
271 v = qapi_dealloc_get_visitor(md);
272 visit_type_%(type)s(v, &obj, NULL, NULL);
273 qapi_dealloc_visitor_cleanup(md);
274 }
275 ''',
276 c_type=c_type(name),type=name)
277 return ret
278
279
280 try:
281 opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:o:",
282 ["source", "header", "builtins",
283 "prefix=", "output-dir="])
284 except getopt.GetoptError, err:
285 print str(err)
286 sys.exit(1)
287
288 output_dir = ""
289 prefix = ""
290 c_file = 'qapi-types.c'
291 h_file = 'qapi-types.h'
292
293 do_c = False
294 do_h = False
295 do_builtins = False
296
297 for o, a in opts:
298 if o in ("-p", "--prefix"):
299 prefix = a
300 elif o in ("-o", "--output-dir"):
301 output_dir = a + "/"
302 elif o in ("-c", "--source"):
303 do_c = True
304 elif o in ("-h", "--header"):
305 do_h = True
306 elif o in ("-b", "--builtins"):
307 do_builtins = True
308
309 if not do_c and not do_h:
310 do_c = True
311 do_h = True
312
313 c_file = output_dir + prefix + c_file
314 h_file = output_dir + prefix + h_file
315
316 try:
317 os.makedirs(output_dir)
318 except os.error, e:
319 if e.errno != errno.EEXIST:
320 raise
321
322 def maybe_open(really, name, opt):
323 if really:
324 return open(name, opt)
325 else:
326 import StringIO
327 return StringIO.StringIO()
328
329 fdef = maybe_open(do_c, c_file, 'w')
330 fdecl = maybe_open(do_h, h_file, 'w')
331
332 fdef.write(mcgen('''
333 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
334
335 /*
336 * deallocation functions for schema-defined QAPI types
337 *
338 * Copyright IBM, Corp. 2011
339 *
340 * Authors:
341 * Anthony Liguori <aliguori@us.ibm.com>
342 * Michael Roth <mdroth@linux.vnet.ibm.com>
343 *
344 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
345 * See the COPYING.LIB file in the top-level directory.
346 *
347 */
348
349 #include "qapi/dealloc-visitor.h"
350 #include "%(prefix)sqapi-types.h"
351 #include "%(prefix)sqapi-visit.h"
352
353 ''', prefix=prefix))
354
355 fdecl.write(mcgen('''
356 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
357
358 /*
359 * schema-defined QAPI types
360 *
361 * Copyright IBM, Corp. 2011
362 *
363 * Authors:
364 * Anthony Liguori <aliguori@us.ibm.com>
365 *
366 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
367 * See the COPYING.LIB file in the top-level directory.
368 *
369 */
370
371 #ifndef %(guard)s
372 #define %(guard)s
373
374 #include <stdbool.h>
375 #include <stdint.h>
376
377 ''',
378 guard=guardname(h_file)))
379
380 exprs = parse_schema(sys.stdin)
381 exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
382
383 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
384 for typename in builtin_types:
385 fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
386 fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
387
388 for expr in exprs:
389 ret = "\n"
390 if expr.has_key('type'):
391 ret += generate_fwd_struct(expr['type'], expr['data'])
392 elif expr.has_key('enum'):
393 ret += generate_enum(expr['enum'], expr['data']) + "\n"
394 ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
395 fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
396 elif expr.has_key('union'):
397 ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
398 ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
399 fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys()))
400 if expr.get('discriminator') == {}:
401 fdef.write(generate_anon_union_qtypes(expr))
402 else:
403 continue
404 fdecl.write(ret)
405
406 # to avoid header dependency hell, we always generate declarations
407 # for built-in types in our header files and simply guard them
408 fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
409 for typename in builtin_types:
410 fdecl.write(generate_type_cleanup_decl(typename + "List"))
411 fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
412
413 # ...this doesn't work for cases where we link in multiple objects that
414 # have the functions defined, so we use -b option to provide control
415 # over these cases
416 if do_builtins:
417 fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
418 for typename in builtin_types:
419 fdef.write(generate_type_cleanup(typename + "List"))
420 fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
421
422 for expr in exprs:
423 ret = "\n"
424 if expr.has_key('type'):
425 ret += generate_struct(expr) + "\n"
426 ret += generate_type_cleanup_decl(expr['type'] + "List")
427 fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
428 ret += generate_type_cleanup_decl(expr['type'])
429 fdef.write(generate_type_cleanup(expr['type']) + "\n")
430 elif expr.has_key('union'):
431 ret += generate_union(expr)
432 ret += generate_type_cleanup_decl(expr['union'] + "List")
433 fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
434 ret += generate_type_cleanup_decl(expr['union'])
435 fdef.write(generate_type_cleanup(expr['union']) + "\n")
436 elif expr.has_key('enum'):
437 ret += generate_type_cleanup_decl(expr['enum'] + "List")
438 fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
439 else:
440 continue
441 fdecl.write(ret)
442
443 fdecl.write('''
444 #endif
445 ''')
446
447 fdecl.flush()
448 fdecl.close()
449
450 fdef.flush()
451 fdef.close()