]> Git Repo - qemu.git/blame - scripts/qapi-visit.py
target-i386: fix pcmpxstrx equal-ordered (strstr) mode
[qemu.git] / scripts / qapi-visit.py
CommitLineData
06d64c62
MR
1#
2# QAPI visitor generator
3#
4# Copyright IBM, Corp. 2011
6540e9f3 5# Copyright (C) 2014-2015 Red Hat, Inc.
06d64c62
MR
6#
7# Authors:
8# Anthony Liguori <[email protected]>
9# Michael Roth <[email protected]>
297a3646 10# Markus Armbruster <[email protected]>
06d64c62 11#
678e48a2
MA
12# This work is licensed under the terms of the GNU GPL, version 2.
13# See the COPYING file in the top-level directory.
06d64c62 14
06d64c62 15from qapi import *
297a3646 16import re
06d64c62 17
8c07eddc 18implicit_structs_seen = set()
8c3f8e77 19struct_fields_seen = set()
be3c7717 20
e98859a9 21
60f8546a
MA
22def gen_visit_decl(name, scalar=False):
23 c_type = c_name(name) + ' *'
24 if not scalar:
25 c_type += '*'
26 return mcgen('''
f8b7f1a8 27void visit_type_%(c_name)s(Visitor *v, %(c_type)sobj, const char *name, Error **errp);
60f8546a
MA
28''',
29 c_name=c_name(name), c_type=c_type)
30
31
e98859a9
MA
32def gen_visit_implicit_struct(typ):
33 if typ in implicit_structs_seen:
be3c7717 34 return ''
e98859a9
MA
35 implicit_structs_seen.add(typ)
36
8c3f8e77 37 ret = ''
e98859a9 38 if typ.name not in struct_fields_seen:
8c3f8e77
MA
39 # Need a forward declaration
40 ret += mcgen('''
41
f8b7f1a8 42static void visit_type_%(c_type)s_fields(Visitor *v, %(c_type)s **obj, Error **errp);
8c3f8e77 43''',
e98859a9 44 c_type=typ.c_name())
8c3f8e77
MA
45
46 ret += mcgen('''
be3c7717 47
f8b7f1a8 48static void visit_type_implicit_%(c_type)s(Visitor *v, %(c_type)s **obj, Error **errp)
be3c7717
MA
49{
50 Error *err = NULL;
51
f8b7f1a8 52 visit_start_implicit_struct(v, (void **)obj, sizeof(%(c_type)s), &err);
be3c7717 53 if (!err) {
f8b7f1a8
EB
54 visit_type_%(c_type)s_fields(v, obj, errp);
55 visit_end_implicit_struct(v, &err);
be3c7717
MA
56 }
57 error_propagate(errp, err);
58}
59''',
e98859a9 60 c_type=typ.c_name())
8c3f8e77 61 return ret
be3c7717 62
e98859a9
MA
63
64def gen_visit_struct_fields(name, base, members):
8c3f8e77
MA
65 struct_fields_seen.add(name)
66
d131c897 67 ret = ''
50f2bdc7 68
be3c7717 69 if base:
e98859a9 70 ret += gen_visit_implicit_struct(base)
be3c7717 71
50f2bdc7
KW
72 ret += mcgen('''
73
f8b7f1a8 74static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **errp)
50f2bdc7
KW
75{
76 Error *err = NULL;
3a864e7c 77
50f2bdc7 78''',
e98859a9 79 c_name=c_name(name))
d195325b 80
622f557f
KW
81 if base:
82 ret += mcgen('''
05372f70 83 visit_type_implicit_%(c_type)s(v, &(*obj)->%(c_name)s, &err);
622f557f 84''',
e98859a9 85 c_type=base.c_name(), c_name=c_name('base'))
1f353344 86 ret += gen_err_check()
622f557f 87
82ca8e46 88 ret += gen_visit_fields(members, prefix='(*obj)->')
d195325b 89
e98859a9 90 if re.search('^ *goto out;', ret, re.MULTILINE):
297a3646 91 ret += mcgen('''
50f2bdc7 92
297a3646
MA
93out:
94''')
95 ret += mcgen('''
50f2bdc7
KW
96 error_propagate(errp, err);
97}
98''')
d131c897
KW
99 return ret
100
101
60f8546a
MA
102def gen_visit_struct(name, base, members):
103 ret = gen_visit_struct_fields(name, base, members)
104
2f52e205
EB
105 # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
106 # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
107 # rather than leaving it non-NULL. As currently written, the caller must
108 # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
60f8546a
MA
109 ret += mcgen('''
110
f8b7f1a8 111void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
60f8546a 112{
297a3646
MA
113 Error *err = NULL;
114
f8b7f1a8 115 visit_start_struct(v, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
297a3646
MA
116 if (!err) {
117 if (*obj) {
f8b7f1a8 118 visit_type_%(c_name)s_fields(v, obj, errp);
297a3646 119 }
f8b7f1a8 120 visit_end_struct(v, &err);
50f2bdc7 121 }
297a3646 122 error_propagate(errp, err);
60f8546a 123}
50f2bdc7 124''',
60f8546a 125 name=name, c_name=c_name(name))
06d64c62 126
06d64c62
MR
127 return ret
128
e98859a9 129
441cbac0 130def gen_visit_list(name, element_type):
06d64c62
MR
131 return mcgen('''
132
f8b7f1a8 133void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
06d64c62 134{
d195325b 135 Error *err = NULL;
297a3646 136 GenericList *i, **prev;
06d64c62 137
f8b7f1a8 138 visit_start_list(v, name, &err);
297a3646
MA
139 if (err) {
140 goto out;
141 }
142
143 for (prev = (GenericList **)obj;
f8b7f1a8 144 !err && (i = visit_next_list(v, prev, &err)) != NULL;
297a3646 145 prev = &i) {
e98859a9 146 %(c_name)s *native_i = (%(c_name)s *)i;
f8b7f1a8 147 visit_type_%(c_elt_type)s(v, &native_i->value, NULL, &err);
06d64c62 148 }
297a3646
MA
149
150 error_propagate(errp, err);
151 err = NULL;
f8b7f1a8 152 visit_end_list(v, &err);
297a3646
MA
153out:
154 error_propagate(errp, err);
06d64c62
MR
155}
156''',
e98859a9 157 c_name=c_name(name), c_elt_type=element_type.c_name())
06d64c62 158
e98859a9
MA
159
160def gen_visit_enum(name):
06d64c62
MR
161 return mcgen('''
162
f8b7f1a8 163void visit_type_%(c_name)s(Visitor *v, %(c_name)s *obj, const char *name, Error **errp)
06d64c62 164{
f8b7f1a8 165 visit_type_enum(v, (int *)obj, %(c_name)s_lookup, "%(name)s", name, errp);
06d64c62
MR
166}
167''',
40b3adec 168 c_name=c_name(name), name=name)
06d64c62 169
e98859a9 170
441cbac0 171def gen_visit_alternate(name, variants):
69dd62df
KW
172 ret = mcgen('''
173
f8b7f1a8 174void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
69dd62df
KW
175{
176 Error *err = NULL;
177
f8b7f1a8 178 visit_start_implicit_struct(v, (void**) obj, sizeof(%(c_name)s), &err);
297a3646
MA
179 if (err) {
180 goto out;
181 }
f8b7f1a8 182 visit_get_next_type(v, (int*) &(*obj)->kind, %(c_name)s_qtypes, name, &err);
297a3646 183 if (err) {
f782399c 184 goto out_obj;
297a3646
MA
185 }
186 switch ((*obj)->kind) {
69dd62df 187''',
e98859a9 188 c_name=c_name(name))
69dd62df 189
441cbac0 190 for var in variants.variants:
69dd62df 191 ret += mcgen('''
e98859a9 192 case %(case)s:
f8b7f1a8 193 visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, name, &err);
297a3646 194 break;
69dd62df 195''',
e98859a9
MA
196 case=c_enum_const(variants.tag_member.type.name,
197 var.name),
198 c_type=var.type.c_name(),
199 c_name=c_name(var.name))
69dd62df
KW
200
201 ret += mcgen('''
297a3646
MA
202 default:
203 abort();
69dd62df 204 }
f782399c 205out_obj:
297a3646
MA
206 error_propagate(errp, err);
207 err = NULL;
f8b7f1a8 208 visit_end_implicit_struct(v, &err);
297a3646
MA
209out:
210 error_propagate(errp, err);
69dd62df
KW
211}
212''')
213
214 return ret
215
e98859a9 216
441cbac0
MA
217def gen_visit_union(name, base, variants):
218 ret = ''
06d64c62 219
50f2bdc7 220 if base:
441cbac0 221 members = [m for m in base.members if m != variants.tag_member]
e98859a9 222 ret += gen_visit_struct_fields(name, None, members)
50f2bdc7 223
441cbac0
MA
224 for var in variants.variants:
225 # Ugly special case for simple union TODO get rid of it
226 if not var.simple_union_type():
e98859a9 227 ret += gen_visit_implicit_struct(var.type)
be3c7717 228
06d64c62
MR
229 ret += mcgen('''
230
f8b7f1a8 231void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error **errp)
06d64c62 232{
dc8fb6df
PB
233 Error *err = NULL;
234
f8b7f1a8 235 visit_start_struct(v, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
297a3646
MA
236 if (err) {
237 goto out;
238 }
e36c714e
EB
239 if (!*obj) {
240 goto out_obj;
241 }
06d64c62 242''',
40b3adec 243 c_name=c_name(name), name=name)
06d64c62 244
0aef92b9 245 if base:
50f2bdc7 246 ret += mcgen('''
e36c714e 247 visit_type_%(c_name)s_fields(v, obj, &err);
50f2bdc7 248''',
e98859a9 249 c_name=c_name(name))
1f353344 250 ret += gen_err_check(label='out_obj')
0aef92b9 251
e98859a9 252 tag_key = variants.tag_member.name
441cbac0
MA
253 if not variants.tag_name:
254 # we pointlessly use a different key for simple unions
e98859a9 255 tag_key = 'type'
0aef92b9 256 ret += mcgen('''
e36c714e
EB
257 visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
258 if (err) {
259 goto out_obj;
260 }
261 if (!visit_start_union(v, !!(*obj)->data, &err) || err) {
262 goto out_obj;
263 }
264 switch ((*obj)->%(c_name)s) {
0aef92b9 265''',
e98859a9 266 c_type=variants.tag_member.type.c_name(),
441cbac0
MA
267 # TODO ugly special case for simple union
268 # Use same tag name in C as on the wire to get rid of
269 # it, then: c_name=c_name(variants.tag_member.name)
270 c_name=c_name(variants.tag_name or 'kind'),
e98859a9 271 name=tag_key)
0aef92b9 272
441cbac0
MA
273 for var in variants.variants:
274 # TODO ugly special case for simple union
275 simple_union_type = var.simple_union_type()
e98859a9 276 ret += mcgen('''
e36c714e 277 case %(case)s:
e98859a9
MA
278''',
279 case=c_enum_const(variants.tag_member.type.name,
280 var.name))
441cbac0 281 if simple_union_type:
e98859a9 282 ret += mcgen('''
e36c714e 283 visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "data", &err);
e98859a9
MA
284''',
285 c_type=simple_union_type.c_name(),
286 c_name=c_name(var.name))
50f2bdc7 287 else:
e98859a9 288 ret += mcgen('''
e36c714e 289 visit_type_implicit_%(c_type)s(v, &(*obj)->%(c_name)s, &err);
e98859a9
MA
290''',
291 c_type=var.type.c_name(),
292 c_name=c_name(var.name))
dc8fb6df 293 ret += mcgen('''
e36c714e 294 break;
e98859a9 295''')
dc8fb6df
PB
296
297 ret += mcgen('''
e36c714e
EB
298 default:
299 abort();
468866b8 300 }
e36c714e
EB
301out_obj:
302 error_propagate(errp, err);
303 err = NULL;
d08ac81a
EB
304 if (*obj) {
305 visit_end_union(v, !!(*obj)->data, &err);
306 }
e36c714e
EB
307 error_propagate(errp, err);
308 err = NULL;
f8b7f1a8 309 visit_end_struct(v, &err);
297a3646
MA
310out:
311 error_propagate(errp, err);
dc8fb6df
PB
312}
313''')
314
06d64c62
MR
315 return ret
316
e98859a9 317
441cbac0
MA
318class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
319 def __init__(self):
320 self.decl = None
321 self.defn = None
322 self._btin = None
323
324 def visit_begin(self, schema):
325 self.decl = ''
326 self.defn = ''
327 self._btin = guardstart('QAPI_VISIT_BUILTIN')
328
329 def visit_end(self):
330 # To avoid header dependency hell, we always generate
331 # declarations for built-in types in our header files and
332 # simply guard them. See also do_builtins (command line
333 # option -b).
334 self._btin += guardend('QAPI_VISIT_BUILTIN')
335 self.decl = self._btin + self.decl
336 self._btin = None
337
25a0d9c9
EB
338 def visit_needed(self, entity):
339 # Visit everything except implicit objects
49823c4b
EB
340 return not (entity.is_implicit() and
341 isinstance(entity, QAPISchemaObjectType))
25a0d9c9 342
441cbac0
MA
343 def visit_enum_type(self, name, info, values, prefix):
344 self.decl += gen_visit_decl(name, scalar=True)
e98859a9 345 self.defn += gen_visit_enum(name)
441cbac0
MA
346
347 def visit_array_type(self, name, info, element_type):
348 decl = gen_visit_decl(name)
349 defn = gen_visit_list(name, element_type)
350 if isinstance(element_type, QAPISchemaBuiltinType):
351 self._btin += decl
352 if do_builtins:
353 self.defn += defn
354 else:
355 self.decl += decl
356 self.defn += defn
357
358 def visit_object_type(self, name, info, base, members, variants):
25a0d9c9
EB
359 self.decl += gen_visit_decl(name)
360 if variants:
361 assert not members # not implemented
362 self.defn += gen_visit_union(name, base, variants)
363 else:
364 self.defn += gen_visit_struct(name, base, members)
441cbac0
MA
365
366 def visit_alternate_type(self, name, info, variants):
367 self.decl += gen_visit_decl(name)
368 self.defn += gen_visit_alternate(name, variants)
369
370# If you link code generated from multiple schemata, you want only one
371# instance of the code for built-in types. Generate it only when
372# do_builtins, enabled by command line option -b. See also
373# QAPISchemaGenVisitVisitor.visit_end().
7c946bc4 374do_builtins = False
8d3bc517 375
2114f5a9
MA
376(input_file, output_dir, do_c, do_h, prefix, opts) = \
377 parse_command_line("b", ["builtins"])
378
06d64c62 379for o, a in opts:
2114f5a9 380 if o in ("-b", "--builtins"):
7c946bc4 381 do_builtins = True
8d3bc517 382
12f8e1b9 383c_comment = '''
06d64c62
MR
384/*
385 * schema-defined QAPI visitor functions
386 *
387 * Copyright IBM, Corp. 2011
388 *
389 * Authors:
390 * Anthony Liguori <[email protected]>
391 *
392 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
393 * See the COPYING.LIB file in the top-level directory.
394 *
395 */
12f8e1b9
MA
396'''
397h_comment = '''
06d64c62 398/*
297a3646 399 * schema-defined QAPI visitor functions
06d64c62
MR
400 *
401 * Copyright IBM, Corp. 2011
402 *
403 * Authors:
404 * Anthony Liguori <[email protected]>
405 *
406 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
407 * See the COPYING.LIB file in the top-level directory.
408 *
409 */
12f8e1b9
MA
410'''
411
412(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
413 'qapi-visit.c', 'qapi-visit.h',
414 c_comment, h_comment)
06d64c62 415
12f8e1b9
MA
416fdef.write(mcgen('''
417#include "qemu-common.h"
418#include "%(prefix)sqapi-visit.h"
419''',
e98859a9 420 prefix=prefix))
06d64c62 421
12f8e1b9 422fdecl.write(mcgen('''
7b1b5d19 423#include "qapi/visitor.h"
06d64c62 424#include "%(prefix)sqapi-types.h"
7c946bc4 425
06d64c62 426''',
12f8e1b9 427 prefix=prefix))
06d64c62 428
441cbac0
MA
429schema = QAPISchema(input_file)
430gen = QAPISchemaGenVisitVisitor()
431schema.visit(gen)
432fdef.write(gen.defn)
433fdecl.write(gen.decl)
06d64c62 434
12f8e1b9 435close_output(fdef, fdecl)
This page took 0.413605 seconds and 4 git commands to generate.