]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi/types.py
Merge remote-tracking branch 'remotes/vivier/tags/q800-for-5.0-pull-request' into...
[mirror_qemu.git] / scripts / qapi / types.py
CommitLineData
5ddeec83
MA
1"""
2QAPI types generator
3
4Copyright IBM, Corp. 2011
5Copyright (c) 2013-2018 Red Hat Inc.
6
7Authors:
8 Anthony Liguori <aliguori@us.ibm.com>
9 Michael Roth <mdroth@linux.vnet.ibm.com>
10 Markus Armbruster <armbru@redhat.com>
11
12This work is licensed under the terms of the GNU GPL, version 2.
678e48a2 13# See the COPYING file in the top-level directory.
5ddeec83 14"""
fb3182ce 15
fb0bc835 16from qapi.common import *
e6c42b96
MA
17from qapi.gen import QAPISchemaModularCVisitor, ifcontext
18from qapi.schema import QAPISchemaEnumMember, QAPISchemaObjectType
fb3182ce 19
e98859a9 20
1de5d4ca
EB
21# variants must be emitted before their container; track what has already
22# been output
23objects_seen = set()
24
25
61bfb2e1
MA
26def gen_enum_lookup(name, members, prefix=None):
27 ret = mcgen('''
28
29const QEnumLookup %(c_name)s_lookup = {
30 .array = (const char *const[]) {
31''',
32 c_name=c_name(name))
33 for m in members:
34 ret += gen_if(m.ifcond)
35 index = c_enum_const(name, m.name, prefix)
36 ret += mcgen('''
37 [%(index)s] = "%(name)s",
38''',
39 index=index, name=m.name)
40 ret += gen_endif(m.ifcond)
41
42 ret += mcgen('''
43 },
44 .size = %(max_index)s
45};
46''',
47 max_index=c_enum_const(name, '_MAX', prefix))
48 return ret
49
50
51def gen_enum(name, members, prefix=None):
52 # append automatically generated _MAX value
53 enum_members = members + [QAPISchemaEnumMember('_MAX', None)]
54
55 ret = mcgen('''
56
57typedef enum %(c_name)s {
58''',
59 c_name=c_name(name))
60
61 for m in enum_members:
62 ret += gen_if(m.ifcond)
63 ret += mcgen('''
64 %(c_enum)s,
65''',
66 c_enum=c_enum_const(name, m.name, prefix))
67 ret += gen_endif(m.ifcond)
68
69 ret += mcgen('''
70} %(c_name)s;
71''',
72 c_name=c_name(name))
73
74 ret += mcgen('''
75
76#define %(c_name)s_str(val) \\
77 qapi_enum_lookup(&%(c_name)s_lookup, (val))
78
79extern const QEnumLookup %(c_name)s_lookup;
80''',
81 c_name=c_name(name))
82 return ret
83
84
2b162ccb 85def gen_fwd_object_or_array(name):
fb3182ce 86 return mcgen('''
c0afa9c5 87
e98859a9 88typedef struct %(c_name)s %(c_name)s;
fb3182ce 89''',
e98859a9
MA
90 c_name=c_name(name))
91
fb3182ce 92
2b162ccb 93def gen_array(name, element_type):
b9c4b48d 94 return mcgen('''
3a864e7c 95
e98859a9 96struct %(c_name)s {
e98859a9 97 %(c_name)s *next;
e65d89bf 98 %(c_type)s value;
2b162ccb 99};
b9c4b48d 100''',
e98859a9
MA
101 c_name=c_name(name), c_type=element_type.c_type())
102
b9c4b48d 103
14f00c6c 104def gen_struct_members(members):
01537030 105 ret = ''
7d9586f9 106 for memb in members:
8ee06f61 107 ret += gen_if(memb.ifcond)
7d9586f9
EB
108 if memb.optional:
109 ret += mcgen('''
fb3182ce
MR
110 bool has_%(c_name)s;
111''',
7d9586f9
EB
112 c_name=c_name(memb.name))
113 ret += mcgen('''
fb3182ce
MR
114 %(c_type)s %(c_name)s;
115''',
7d9586f9 116 c_type=memb.type.c_type(), c_name=c_name(memb.name))
8ee06f61 117 ret += gen_endif(memb.ifcond)
01537030
KW
118 return ret
119
e98859a9 120
9f88c662 121def gen_object(name, ifcond, base, members, variants):
1de5d4ca
EB
122 if name in objects_seen:
123 return ''
124 objects_seen.add(name)
125
126 ret = ''
127 if variants:
128 for v in variants.variants:
7ce106a9 129 if isinstance(v.type, QAPISchemaObjectType):
9f88c662 130 ret += gen_object(v.type.name, v.type.ifcond, v.type.base,
1de5d4ca
EB
131 v.type.local_members, v.type.variants)
132
133 ret += mcgen('''
7d9586f9 134
9f88c662
MA
135''')
136 ret += gen_if(ifcond)
137 ret += mcgen('''
7d9586f9
EB
138struct %(c_name)s {
139''',
1de5d4ca 140 c_name=c_name(name))
14d36307 141
f87ab7f9 142 if base:
ac4338f8
EB
143 if not base.is_implicit():
144 ret += mcgen('''
f87ab7f9
EB
145 /* Members inherited from %(c_name)s: */
146''',
ac4338f8 147 c_name=base.c_name())
14f00c6c 148 ret += gen_struct_members(base.members)
ac4338f8
EB
149 if not base.is_implicit():
150 ret += mcgen('''
f87ab7f9
EB
151 /* Own members: */
152''')
14f00c6c 153 ret += gen_struct_members(members)
01537030 154
570cd8d1
EB
155 if variants:
156 ret += gen_variants(variants)
157
14f00c6c 158 # Make sure that all structs have at least one member; this avoids
e98859a9
MA
159 # potential issues with attempting to malloc space for zero-length
160 # structs in C, and also incompatibility with C++ (where an empty
161 # struct is size 1).
b6167706 162 if (not base or base.is_empty()) and not members and not variants:
e98859a9 163 ret += mcgen('''
c81200b0 164 char qapi_dummy_for_empty_struct;
83ecb22b
PM
165''')
166
fb3182ce 167 ret += mcgen('''
e1d4210c
MA
168};
169''')
9f88c662 170 ret += gen_endif(ifcond)
fb3182ce
MR
171
172 return ret
173
e98859a9 174
30594fe1
EB
175def gen_upcast(name, base):
176 # C makes const-correctness ugly. We have to cast away const to let
177 # this function work for both const and non-const obj.
178 return mcgen('''
179
180static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
181{
182 return (%(base)s *)obj;
183}
184''',
185 c_name=c_name(name), base=base.c_name())
186
187
570cd8d1 188def gen_variants(variants):
570cd8d1 189 ret = mcgen('''
1e6c1616 190 union { /* union tag is @%(c_name)s */
fb3182ce 191''',
570cd8d1 192 c_name=c_name(variants.tag_member.name))
2b162ccb
MA
193
194 for var in variants.variants:
800877bb
AN
195 if var.type.name == 'q_empty':
196 continue
8ee06f61 197 ret += gen_if(var.ifcond)
e4ba22b3 198 ret += mcgen('''
fb3182ce
MR
199 %(c_type)s %(c_name)s;
200''',
32bafa8f 201 c_type=var.type.c_unboxed_type(),
2b162ccb 202 c_name=c_name(var.name))
8ee06f61 203 ret += gen_endif(var.ifcond)
fb3182ce
MR
204
205 ret += mcgen('''
f51d8fab 206 } u;
fb3182ce
MR
207''')
208
209 return ret
210
e98859a9
MA
211
212def gen_type_cleanup_decl(name):
fb3182ce 213 ret = mcgen('''
2b162ccb 214
e98859a9 215void qapi_free_%(c_name)s(%(c_name)s *obj);
fb3182ce 216''',
e98859a9 217 c_name=c_name(name))
fb3182ce
MR
218 return ret
219
e98859a9
MA
220
221def gen_type_cleanup(name):
fb3182ce 222 ret = mcgen('''
c0afa9c5 223
e98859a9 224void qapi_free_%(c_name)s(%(c_name)s *obj)
fb3182ce 225{
fb3182ce
MR
226 Visitor *v;
227
228 if (!obj) {
229 return;
230 }
231
2c0ef9f4 232 v = qapi_dealloc_visitor_new();
51e72bc1 233 visit_type_%(c_name)s(v, NULL, &obj, NULL);
2c0ef9f4 234 visit_free(v);
fb3182ce
MR
235}
236''',
e98859a9 237 c_name=c_name(name))
fb3182ce
MR
238 return ret
239
2b162ccb 240
cdb6610a 241class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
71b3f045 242
cdb6610a 243 def __init__(self, prefix):
2cae67bc
MA
244 super().__init__(
245 prefix, 'qapi-types', ' * Schema-defined QAPI types',
3bef3aae
MA
246 ' * Built-in QAPI types', __doc__)
247
248 def _begin_system_module(self, name):
cdb6610a
MA
249 self._genc.preamble_add(mcgen('''
250#include "qemu/osdep.h"
251#include "qapi/dealloc-visitor.h"
eb815e24
MA
252#include "qapi/qapi-builtin-types.h"
253#include "qapi/qapi-builtin-visit.h"
cdb6610a
MA
254'''))
255 self._genh.preamble_add(mcgen('''
256#include "qapi/util.h"
257'''))
258
dcac6471 259 def _begin_user_module(self, name):
9af23989
MA
260 types = self._module_basename('qapi-types', name)
261 visit = self._module_basename('qapi-visit', name)
71b3f045
MA
262 self._genc.preamble_add(mcgen('''
263#include "qemu/osdep.h"
264#include "qapi/dealloc-visitor.h"
9af23989
MA
265#include "%(types)s.h"
266#include "%(visit)s.h"
71b3f045 267''',
9af23989 268 types=types, visit=visit))
71b3f045 269 self._genh.preamble_add(mcgen('''
eb815e24 270#include "qapi/qapi-builtin-types.h"
71b3f045 271'''))
2b162ccb
MA
272
273 def visit_begin(self, schema):
7ce106a9
EB
274 # gen_object() is recursive, ensure it doesn't visit the empty type
275 objects_seen.add(schema.the_empty_object_type.name)
2b162ccb 276
2b162ccb 277 def _gen_type_cleanup(self, name):
71b3f045
MA
278 self._genh.add(gen_type_cleanup_decl(name))
279 self._genc.add(gen_type_cleanup(name))
2b162ccb 280
1962bd39 281 def visit_enum_type(self, name, info, ifcond, members, prefix):
9f88c662 282 with ifcontext(ifcond, self._genh, self._genc):
1962bd39
MAL
283 self._genh.preamble_add(gen_enum(name, members, prefix))
284 self._genc.add(gen_enum_lookup(name, members, prefix))
2b162ccb 285
fbf09a2f 286 def visit_array_type(self, name, info, ifcond, element_type):
9f88c662
MA
287 with ifcontext(ifcond, self._genh, self._genc):
288 self._genh.preamble_add(gen_fwd_object_or_array(name))
289 self._genh.add(gen_array(name, element_type))
290 self._gen_type_cleanup(name)
2b162ccb 291
6a8c0b51
KW
292 def visit_object_type(self, name, info, ifcond, base, members, variants,
293 features):
7ce106a9
EB
294 # Nothing to do for the special empty builtin
295 if name == 'q_empty':
296 return
9f88c662
MA
297 with ifcontext(ifcond, self._genh):
298 self._genh.preamble_add(gen_fwd_object_or_array(name))
299 self._genh.add(gen_object(name, ifcond, base, members, variants))
300 with ifcontext(ifcond, self._genh, self._genc):
301 if base and not base.is_implicit():
302 self._genh.add(gen_upcast(name, base))
303 # TODO Worth changing the visitor signature, so we could
304 # directly use rather than repeat type.is_implicit()?
305 if not name.startswith('q_'):
306 # implicit types won't be directly allocated/freed
307 self._gen_type_cleanup(name)
2b162ccb 308
fbf09a2f 309 def visit_alternate_type(self, name, info, ifcond, variants):
9f88c662
MA
310 with ifcontext(ifcond, self._genh):
311 self._genh.preamble_add(gen_fwd_object_or_array(name))
312 self._genh.add(gen_object(name, ifcond, None,
71b3f045 313 [variants.tag_member], variants))
9f88c662
MA
314 with ifcontext(ifcond, self._genh, self._genc):
315 self._gen_type_cleanup(name)
2b162ccb 316
8d3bc517 317
fb0bc835 318def gen_types(schema, output_dir, prefix, opt_builtins):
cdb6610a 319 vis = QAPISchemaGenTypeVisitor(prefix)
26df4e7f 320 schema.visit(vis)
cdb6610a 321 vis.write(output_dir, opt_builtins)