hw/arm: ast2600: Fix address mapping of second SPI controller
[qemu.git] / scripts / qapi / types.py
blob3013329c2482fd7e874f4dec8db681f8782e4511
1 """
2 QAPI types generator
4 Copyright IBM, Corp. 2011
5 Copyright (c) 2013-2018 Red Hat Inc.
7 Authors:
8 Anthony Liguori <aliguori@us.ibm.com>
9 Michael Roth <mdroth@linux.vnet.ibm.com>
10 Markus Armbruster <armbru@redhat.com>
12 This work is licensed under the terms of the GNU GPL, version 2.
13 # See the COPYING file in the top-level directory.
14 """
16 from typing import List, Optional
18 from .common import c_enum_const, c_name, mcgen
19 from .gen import QAPISchemaModularCVisitor, gen_special_features, ifcontext
20 from .schema import (
21 QAPISchema,
22 QAPISchemaEnumMember,
23 QAPISchemaFeature,
24 QAPISchemaIfCond,
25 QAPISchemaObjectType,
26 QAPISchemaObjectTypeMember,
27 QAPISchemaType,
28 QAPISchemaVariants,
30 from .source import QAPISourceInfo
33 # variants must be emitted before their container; track what has already
34 # been output
35 objects_seen = set()
38 def gen_enum_lookup(name: str,
39 members: List[QAPISchemaEnumMember],
40 prefix: Optional[str] = None) -> str:
41 max_index = c_enum_const(name, '_MAX', prefix)
42 feats = ''
43 ret = mcgen('''
45 const QEnumLookup %(c_name)s_lookup = {
46 .array = (const char *const[]) {
47 ''',
48 c_name=c_name(name))
49 for memb in members:
50 ret += memb.ifcond.gen_if()
51 index = c_enum_const(name, memb.name, prefix)
52 ret += mcgen('''
53 [%(index)s] = "%(name)s",
54 ''',
55 index=index, name=memb.name)
56 ret += memb.ifcond.gen_endif()
58 special_features = gen_special_features(memb.features)
59 if special_features != '0':
60 feats += mcgen('''
61 [%(index)s] = %(special_features)s,
62 ''',
63 index=index, special_features=special_features)
65 if feats:
66 ret += mcgen('''
68 .special_features = (const unsigned char[%(max_index)s]) {
69 ''',
70 max_index=max_index)
71 ret += feats
73 ret += mcgen('''
75 .size = %(max_index)s
77 ''',
78 max_index=max_index)
79 return ret
82 def gen_enum(name: str,
83 members: List[QAPISchemaEnumMember],
84 prefix: Optional[str] = None) -> str:
85 # append automatically generated _MAX value
86 enum_members = members + [QAPISchemaEnumMember('_MAX', None)]
88 ret = mcgen('''
90 typedef enum %(c_name)s {
91 ''',
92 c_name=c_name(name))
94 for memb in enum_members:
95 ret += memb.ifcond.gen_if()
96 ret += mcgen('''
97 %(c_enum)s,
98 ''',
99 c_enum=c_enum_const(name, memb.name, prefix))
100 ret += memb.ifcond.gen_endif()
102 ret += mcgen('''
103 } %(c_name)s;
104 ''',
105 c_name=c_name(name))
107 ret += mcgen('''
109 #define %(c_name)s_str(val) \\
110 qapi_enum_lookup(&%(c_name)s_lookup, (val))
112 extern const QEnumLookup %(c_name)s_lookup;
113 ''',
114 c_name=c_name(name))
115 return ret
118 def gen_fwd_object_or_array(name: str) -> str:
119 return mcgen('''
121 typedef struct %(c_name)s %(c_name)s;
122 ''',
123 c_name=c_name(name))
126 def gen_array(name: str, element_type: QAPISchemaType) -> str:
127 return mcgen('''
129 struct %(c_name)s {
130 %(c_name)s *next;
131 %(c_type)s value;
133 ''',
134 c_name=c_name(name), c_type=element_type.c_type())
137 def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str:
138 ret = ''
139 for memb in members:
140 ret += memb.ifcond.gen_if()
141 if memb.optional:
142 ret += mcgen('''
143 bool has_%(c_name)s;
144 ''',
145 c_name=c_name(memb.name))
146 ret += mcgen('''
147 %(c_type)s %(c_name)s;
148 ''',
149 c_type=memb.type.c_type(), c_name=c_name(memb.name))
150 ret += memb.ifcond.gen_endif()
151 return ret
154 def gen_object(name: str, ifcond: QAPISchemaIfCond,
155 base: Optional[QAPISchemaObjectType],
156 members: List[QAPISchemaObjectTypeMember],
157 variants: Optional[QAPISchemaVariants]) -> str:
158 if name in objects_seen:
159 return ''
160 objects_seen.add(name)
162 ret = ''
163 for var in variants.variants if variants else ():
164 obj = var.type
165 if not isinstance(obj, QAPISchemaObjectType):
166 continue
167 ret += gen_object(obj.name, obj.ifcond, obj.base,
168 obj.local_members, obj.variants)
170 ret += mcgen('''
172 ''')
173 ret += ifcond.gen_if()
174 ret += mcgen('''
175 struct %(c_name)s {
176 ''',
177 c_name=c_name(name))
179 if base:
180 if not base.is_implicit():
181 ret += mcgen('''
182 /* Members inherited from %(c_name)s: */
183 ''',
184 c_name=base.c_name())
185 ret += gen_struct_members(base.members)
186 if not base.is_implicit():
187 ret += mcgen('''
188 /* Own members: */
189 ''')
190 ret += gen_struct_members(members)
192 if variants:
193 ret += gen_variants(variants)
195 # Make sure that all structs have at least one member; this avoids
196 # potential issues with attempting to malloc space for zero-length
197 # structs in C, and also incompatibility with C++ (where an empty
198 # struct is size 1).
199 if (not base or base.is_empty()) and not members and not variants:
200 ret += mcgen('''
201 char qapi_dummy_for_empty_struct;
202 ''')
204 ret += mcgen('''
206 ''')
207 ret += ifcond.gen_endif()
209 return ret
212 def gen_upcast(name: str, base: QAPISchemaObjectType) -> str:
213 # C makes const-correctness ugly. We have to cast away const to let
214 # this function work for both const and non-const obj.
215 return mcgen('''
217 static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
219 return (%(base)s *)obj;
221 ''',
222 c_name=c_name(name), base=base.c_name())
225 def gen_variants(variants: QAPISchemaVariants) -> str:
226 ret = mcgen('''
227 union { /* union tag is @%(c_name)s */
228 ''',
229 c_name=c_name(variants.tag_member.name))
231 for var in variants.variants:
232 if var.type.name == 'q_empty':
233 continue
234 ret += var.ifcond.gen_if()
235 ret += mcgen('''
236 %(c_type)s %(c_name)s;
237 ''',
238 c_type=var.type.c_unboxed_type(),
239 c_name=c_name(var.name))
240 ret += var.ifcond.gen_endif()
242 ret += mcgen('''
243 } u;
244 ''')
246 return ret
249 def gen_type_cleanup_decl(name: str) -> str:
250 ret = mcgen('''
252 void qapi_free_%(c_name)s(%(c_name)s *obj);
253 G_DEFINE_AUTOPTR_CLEANUP_FUNC(%(c_name)s, qapi_free_%(c_name)s)
254 ''',
255 c_name=c_name(name))
256 return ret
259 def gen_type_cleanup(name: str) -> str:
260 ret = mcgen('''
262 void qapi_free_%(c_name)s(%(c_name)s *obj)
264 Visitor *v;
266 if (!obj) {
267 return;
270 v = qapi_dealloc_visitor_new();
271 visit_type_%(c_name)s(v, NULL, &obj, NULL);
272 visit_free(v);
274 ''',
275 c_name=c_name(name))
276 return ret
279 class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
281 def __init__(self, prefix: str):
282 super().__init__(
283 prefix, 'qapi-types', ' * Schema-defined QAPI types',
284 ' * Built-in QAPI types', __doc__)
286 def _begin_builtin_module(self) -> None:
287 self._genc.preamble_add(mcgen('''
288 #include "qemu/osdep.h"
289 #include "qapi/dealloc-visitor.h"
290 #include "qapi/qapi-builtin-types.h"
291 #include "qapi/qapi-builtin-visit.h"
292 '''))
293 self._genh.preamble_add(mcgen('''
294 #include "qapi/util.h"
295 '''))
297 def _begin_user_module(self, name: str) -> None:
298 types = self._module_basename('qapi-types', name)
299 visit = self._module_basename('qapi-visit', name)
300 self._genc.preamble_add(mcgen('''
301 #include "qemu/osdep.h"
302 #include "qapi/dealloc-visitor.h"
303 #include "%(types)s.h"
304 #include "%(visit)s.h"
305 ''',
306 types=types, visit=visit))
307 self._genh.preamble_add(mcgen('''
308 #include "qapi/qapi-builtin-types.h"
309 '''))
311 def visit_begin(self, schema: QAPISchema) -> None:
312 # gen_object() is recursive, ensure it doesn't visit the empty type
313 objects_seen.add(schema.the_empty_object_type.name)
315 def _gen_type_cleanup(self, name: str) -> None:
316 self._genh.add(gen_type_cleanup_decl(name))
317 self._genc.add(gen_type_cleanup(name))
319 def visit_enum_type(self,
320 name: str,
321 info: Optional[QAPISourceInfo],
322 ifcond: QAPISchemaIfCond,
323 features: List[QAPISchemaFeature],
324 members: List[QAPISchemaEnumMember],
325 prefix: Optional[str]) -> None:
326 with ifcontext(ifcond, self._genh, self._genc):
327 self._genh.preamble_add(gen_enum(name, members, prefix))
328 self._genc.add(gen_enum_lookup(name, members, prefix))
330 def visit_array_type(self,
331 name: str,
332 info: Optional[QAPISourceInfo],
333 ifcond: QAPISchemaIfCond,
334 element_type: QAPISchemaType) -> None:
335 with ifcontext(ifcond, self._genh, self._genc):
336 self._genh.preamble_add(gen_fwd_object_or_array(name))
337 self._genh.add(gen_array(name, element_type))
338 self._gen_type_cleanup(name)
340 def visit_object_type(self,
341 name: str,
342 info: Optional[QAPISourceInfo],
343 ifcond: QAPISchemaIfCond,
344 features: List[QAPISchemaFeature],
345 base: Optional[QAPISchemaObjectType],
346 members: List[QAPISchemaObjectTypeMember],
347 variants: Optional[QAPISchemaVariants]) -> None:
348 # Nothing to do for the special empty builtin
349 if name == 'q_empty':
350 return
351 with ifcontext(ifcond, self._genh):
352 self._genh.preamble_add(gen_fwd_object_or_array(name))
353 self._genh.add(gen_object(name, ifcond, base, members, variants))
354 with ifcontext(ifcond, self._genh, self._genc):
355 if base and not base.is_implicit():
356 self._genh.add(gen_upcast(name, base))
357 # TODO Worth changing the visitor signature, so we could
358 # directly use rather than repeat type.is_implicit()?
359 if not name.startswith('q_'):
360 # implicit types won't be directly allocated/freed
361 self._gen_type_cleanup(name)
363 def visit_alternate_type(self,
364 name: str,
365 info: Optional[QAPISourceInfo],
366 ifcond: QAPISchemaIfCond,
367 features: List[QAPISchemaFeature],
368 variants: QAPISchemaVariants) -> None:
369 with ifcontext(ifcond, self._genh):
370 self._genh.preamble_add(gen_fwd_object_or_array(name))
371 self._genh.add(gen_object(name, ifcond, None,
372 [variants.tag_member], variants))
373 with ifcontext(ifcond, self._genh, self._genc):
374 self._gen_type_cleanup(name)
377 def gen_types(schema: QAPISchema,
378 output_dir: str,
379 prefix: str,
380 opt_builtins: bool) -> None:
381 vis = QAPISchemaGenTypeVisitor(prefix)
382 schema.visit(vis)
383 vis.write(output_dir, opt_builtins)