Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20190701' into staging
[qemu/ar7.git] / scripts / qapi / types.py
blob3edd9374aa2ce0381a79e273f149dc1b3d0ea7ea
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 qapi.common import *
19 # variants must be emitted before their container; track what has already
20 # been output
21 objects_seen = set()
24 def gen_fwd_object_or_array(name):
25 return mcgen('''
27 typedef struct %(c_name)s %(c_name)s;
28 ''',
29 c_name=c_name(name))
32 def gen_array(name, element_type):
33 return mcgen('''
35 struct %(c_name)s {
36 %(c_name)s *next;
37 %(c_type)s value;
39 ''',
40 c_name=c_name(name), c_type=element_type.c_type())
43 def gen_struct_members(members):
44 ret = ''
45 for memb in members:
46 ret += gen_if(memb.ifcond)
47 if memb.optional:
48 ret += mcgen('''
49 bool has_%(c_name)s;
50 ''',
51 c_name=c_name(memb.name))
52 ret += mcgen('''
53 %(c_type)s %(c_name)s;
54 ''',
55 c_type=memb.type.c_type(), c_name=c_name(memb.name))
56 ret += gen_endif(memb.ifcond)
57 return ret
60 def gen_object(name, ifcond, base, members, variants):
61 if name in objects_seen:
62 return ''
63 objects_seen.add(name)
65 ret = ''
66 if variants:
67 for v in variants.variants:
68 if isinstance(v.type, QAPISchemaObjectType):
69 ret += gen_object(v.type.name, v.type.ifcond, v.type.base,
70 v.type.local_members, v.type.variants)
72 ret += mcgen('''
74 ''')
75 ret += gen_if(ifcond)
76 ret += mcgen('''
77 struct %(c_name)s {
78 ''',
79 c_name=c_name(name))
81 if base:
82 if not base.is_implicit():
83 ret += mcgen('''
84 /* Members inherited from %(c_name)s: */
85 ''',
86 c_name=base.c_name())
87 ret += gen_struct_members(base.members)
88 if not base.is_implicit():
89 ret += mcgen('''
90 /* Own members: */
91 ''')
92 ret += gen_struct_members(members)
94 if variants:
95 ret += gen_variants(variants)
97 # Make sure that all structs have at least one member; this avoids
98 # potential issues with attempting to malloc space for zero-length
99 # structs in C, and also incompatibility with C++ (where an empty
100 # struct is size 1).
101 if (not base or base.is_empty()) and not members and not variants:
102 ret += mcgen('''
103 char qapi_dummy_for_empty_struct;
104 ''')
106 ret += mcgen('''
108 ''')
109 ret += gen_endif(ifcond)
111 return ret
114 def gen_upcast(name, base):
115 # C makes const-correctness ugly. We have to cast away const to let
116 # this function work for both const and non-const obj.
117 return mcgen('''
119 static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
121 return (%(base)s *)obj;
123 ''',
124 c_name=c_name(name), base=base.c_name())
127 def gen_variants(variants):
128 ret = mcgen('''
129 union { /* union tag is @%(c_name)s */
130 ''',
131 c_name=c_name(variants.tag_member.name))
133 for var in variants.variants:
134 if var.type.name == 'q_empty':
135 continue
136 ret += gen_if(var.ifcond)
137 ret += mcgen('''
138 %(c_type)s %(c_name)s;
139 ''',
140 c_type=var.type.c_unboxed_type(),
141 c_name=c_name(var.name))
142 ret += gen_endif(var.ifcond)
144 ret += mcgen('''
145 } u;
146 ''')
148 return ret
151 def gen_type_cleanup_decl(name):
152 ret = mcgen('''
154 void qapi_free_%(c_name)s(%(c_name)s *obj);
155 ''',
156 c_name=c_name(name))
157 return ret
160 def gen_type_cleanup(name):
161 ret = mcgen('''
163 void qapi_free_%(c_name)s(%(c_name)s *obj)
165 Visitor *v;
167 if (!obj) {
168 return;
171 v = qapi_dealloc_visitor_new();
172 visit_type_%(c_name)s(v, NULL, &obj, NULL);
173 visit_free(v);
175 ''',
176 c_name=c_name(name))
177 return ret
180 class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
182 def __init__(self, prefix):
183 QAPISchemaModularCVisitor.__init__(
184 self, prefix, 'qapi-types', ' * Schema-defined QAPI types',
185 __doc__)
186 self._add_system_module(None, ' * Built-in QAPI types')
187 self._genc.preamble_add(mcgen('''
188 #include "qemu/osdep.h"
189 #include "qapi/dealloc-visitor.h"
190 #include "qapi/qapi-builtin-types.h"
191 #include "qapi/qapi-builtin-visit.h"
192 '''))
193 self._genh.preamble_add(mcgen('''
194 #include "qapi/util.h"
195 '''))
197 def _begin_user_module(self, name):
198 types = self._module_basename('qapi-types', name)
199 visit = self._module_basename('qapi-visit', name)
200 self._genc.preamble_add(mcgen('''
201 #include "qemu/osdep.h"
202 #include "qapi/dealloc-visitor.h"
203 #include "%(types)s.h"
204 #include "%(visit)s.h"
205 ''',
206 types=types, visit=visit))
207 self._genh.preamble_add(mcgen('''
208 #include "qapi/qapi-builtin-types.h"
209 '''))
211 def visit_begin(self, schema):
212 # gen_object() is recursive, ensure it doesn't visit the empty type
213 objects_seen.add(schema.the_empty_object_type.name)
215 def _gen_type_cleanup(self, name):
216 self._genh.add(gen_type_cleanup_decl(name))
217 self._genc.add(gen_type_cleanup(name))
219 def visit_enum_type(self, name, info, ifcond, members, prefix):
220 with ifcontext(ifcond, self._genh, self._genc):
221 self._genh.preamble_add(gen_enum(name, members, prefix))
222 self._genc.add(gen_enum_lookup(name, members, prefix))
224 def visit_array_type(self, name, info, ifcond, element_type):
225 with ifcontext(ifcond, self._genh, self._genc):
226 self._genh.preamble_add(gen_fwd_object_or_array(name))
227 self._genh.add(gen_array(name, element_type))
228 self._gen_type_cleanup(name)
230 def visit_object_type(self, name, info, ifcond, base, members, variants,
231 features):
232 # Nothing to do for the special empty builtin
233 if name == 'q_empty':
234 return
235 with ifcontext(ifcond, self._genh):
236 self._genh.preamble_add(gen_fwd_object_or_array(name))
237 self._genh.add(gen_object(name, ifcond, base, members, variants))
238 with ifcontext(ifcond, self._genh, self._genc):
239 if base and not base.is_implicit():
240 self._genh.add(gen_upcast(name, base))
241 # TODO Worth changing the visitor signature, so we could
242 # directly use rather than repeat type.is_implicit()?
243 if not name.startswith('q_'):
244 # implicit types won't be directly allocated/freed
245 self._gen_type_cleanup(name)
247 def visit_alternate_type(self, name, info, ifcond, variants):
248 with ifcontext(ifcond, self._genh):
249 self._genh.preamble_add(gen_fwd_object_or_array(name))
250 self._genh.add(gen_object(name, ifcond, None,
251 [variants.tag_member], variants))
252 with ifcontext(ifcond, self._genh, self._genc):
253 self._gen_type_cleanup(name)
256 def gen_types(schema, output_dir, prefix, opt_builtins):
257 vis = QAPISchemaGenTypeVisitor(prefix)
258 schema.visit(vis)
259 vis.write(output_dir, opt_builtins)