4 Copyright IBM, Corp. 2011
5 Copyright (c) 2013-2018 Red Hat Inc.
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.
16 from qapi
.common
import *
19 # variants must be emitted before their container; track what has already
24 def gen_fwd_object_or_array(name
):
27 typedef struct %(c_name)s %(c_name)s;
32 def gen_array(name
, element_type
):
40 c_name
=c_name(name
), c_type
=element_type
.c_type())
43 def gen_struct_members(members
):
46 ret
+= gen_if(memb
.ifcond
)
51 c_name
=c_name(memb
.name
))
53 %(c_type)s %(c_name)s;
55 c_type
=memb
.type.c_type(), c_name
=c_name(memb
.name
))
56 ret
+= gen_endif(memb
.ifcond
)
60 def gen_object(name
, ifcond
, base
, members
, variants
):
61 if name
in objects_seen
:
63 objects_seen
.add(name
)
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
)
82 if not base
.is_implicit():
84 /* Members inherited from %(c_name)s: */
87 ret
+= gen_struct_members(base
.members
)
88 if not base
.is_implicit():
92 ret
+= gen_struct_members(members
)
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
101 if (not base
or base
.is_empty()) and not members
and not variants
:
103 char qapi_dummy_for_empty_struct;
109 ret
+= gen_endif(ifcond
)
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.
119 static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
121 return (%(base)s *)obj;
124 c_name
=c_name(name
), base
=base
.c_name())
127 def gen_variants(variants
):
129 union { /* union tag is @%(c_name)s */
131 c_name
=c_name(variants
.tag_member
.name
))
133 for var
in variants
.variants
:
134 if var
.type.name
== 'q_empty':
136 ret
+= gen_if(var
.ifcond
)
138 %(c_type)s %(c_name)s;
140 c_type
=var
.type.c_unboxed_type(),
141 c_name
=c_name(var
.name
))
142 ret
+= gen_endif(var
.ifcond
)
151 def gen_type_cleanup_decl(name
):
154 void qapi_free_%(c_name)s(%(c_name)s *obj);
160 def gen_type_cleanup(name
):
163 void qapi_free_%(c_name)s(%(c_name)s *obj)
171 v = qapi_dealloc_visitor_new();
172 visit_type_%(c_name)s(v, NULL, &obj, NULL);
180 class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor
):
182 def __init__(self
, prefix
):
183 QAPISchemaModularCVisitor
.__init
__(
184 self
, prefix
, 'qapi-types', ' * Schema-defined QAPI types',
186 self
._add
_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"
193 self
._genh
.preamble_add(mcgen('''
194 #include "qapi/util.h"
197 def _begin_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"
206 types
=types
, visit
=visit
))
207 self
._genh
.preamble_add(mcgen('''
208 #include "qapi/qapi-builtin-types.h"
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 # Nothing to do for the special empty builtin
232 if name
== 'q_empty':
234 with
ifcontext(ifcond
, self
._genh
):
235 self
._genh
.preamble_add(gen_fwd_object_or_array(name
))
236 self
._genh
.add(gen_object(name
, ifcond
, base
, members
, variants
))
237 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
238 if base
and not base
.is_implicit():
239 self
._genh
.add(gen_upcast(name
, base
))
240 # TODO Worth changing the visitor signature, so we could
241 # directly use rather than repeat type.is_implicit()?
242 if not name
.startswith('q_'):
243 # implicit types won't be directly allocated/freed
244 self
._gen
_type
_cleanup
(name
)
246 def visit_alternate_type(self
, name
, info
, ifcond
, variants
):
247 with
ifcontext(ifcond
, self
._genh
):
248 self
._genh
.preamble_add(gen_fwd_object_or_array(name
))
249 self
._genh
.add(gen_object(name
, ifcond
, None,
250 [variants
.tag_member
], variants
))
251 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
252 self
._gen
_type
_cleanup
(name
)
255 def gen_types(schema
, output_dir
, prefix
, opt_builtins
):
256 vis
= QAPISchemaGenTypeVisitor(prefix
)
258 vis
.write(output_dir
, opt_builtins
)