4 Copyright IBM, Corp. 2011
5 Copyright (C) 2014-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 typing
import List
, Optional
25 QAPISchemaModularCVisitor
,
31 QAPISchemaAlternatives
,
38 QAPISchemaObjectTypeMember
,
41 from .source
import QAPISourceInfo
44 def gen_visit_decl(name
: str, scalar
: bool = False) -> str:
45 c_type
= c_name(name
) + ' *'
50 bool visit_type_%(c_name)s(Visitor *v, const char *name,
51 %(c_type)sobj, Error **errp);
53 c_name
=c_name(name
), c_type
=c_type
)
56 def gen_visit_members_decl(name
: str) -> str:
59 bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp);
64 def gen_visit_object_members(name
: str,
65 base
: Optional
[QAPISchemaObjectType
],
66 members
: List
[QAPISchemaObjectTypeMember
],
67 branches
: Optional
[QAPISchemaBranches
]) -> str:
70 bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
77 if memb
.optional
and not memb
.need_has():
78 ret
+= memb
.ifcond
.gen_if()
80 bool has_%(c_name)s = !!obj->%(c_name)s;
82 c_name
=c_name(memb
.name
))
84 ret
+= memb
.ifcond
.gen_endif()
89 if (!visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, errp)) {
96 ret
+= memb
.ifcond
.gen_if()
98 has
= 'has_' + c_name(memb
.name
)
102 if (visit_optional(v, "%(name)s", &%(has)s)) {
104 name
=memb
.name
, has
=has
)
106 special_features
= gen_special_features(memb
.features
)
107 if special_features
!= '0':
109 if (visit_policy_reject(v, "%(name)s", %(special_features)s, errp)) {
112 if (!visit_policy_skip(v, "%(name)s", %(special_features)s)) {
114 name
=memb
.name
, special_features
=special_features
)
117 if (!visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, errp)) {
121 c_type
=memb
.type.c_name(), name
=memb
.name
,
122 c_name
=c_name(memb
.name
))
123 if special_features
!= '0':
133 ret
+= memb
.ifcond
.gen_endif()
136 tag_member
= branches
.tag_member
137 assert isinstance(tag_member
.type, QAPISchemaEnumType
)
140 switch (obj->%(c_name)s) {
142 c_name
=c_name(tag_member
.name
))
144 for var
in branches
.variants
:
145 case_str
= c_enum_const(tag_member
.type.name
, var
.name
,
146 tag_member
.type.prefix
)
147 ret
+= var
.ifcond
.gen_if()
148 if var
.type.name
== 'q_empty':
149 # valid variant and nothing to do
158 return visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, errp);
161 c_type
=var
.type.c_name(), c_name
=c_name(var
.name
))
163 ret
+= var
.ifcond
.gen_endif()
177 def gen_visit_list(name
: str, element_type
: QAPISchemaType
) -> str:
180 bool visit_type_%(c_name)s(Visitor *v, const char *name,
181 %(c_name)s **obj, Error **errp)
185 size_t size = sizeof(**obj);
187 if (!visit_start_list(v, name, (GenericList **)obj, size, errp)) {
191 for (tail = *obj; tail;
192 tail = (%(c_name)s *)visit_next_list(v, (GenericList *)tail, size)) {
193 if (!visit_type_%(c_elt_type)s(v, NULL, &tail->value, errp)) {
198 ok = visit_check_list(v, errp);
200 visit_end_list(v, (void **)obj);
201 if (!ok && visit_is_input(v)) {
202 qapi_free_%(c_name)s(*obj);
208 c_name
=c_name(name
), c_elt_type
=element_type
.c_name())
211 def gen_visit_enum(name
: str) -> str:
214 bool visit_type_%(c_name)s(Visitor *v, const char *name,
215 %(c_name)s *obj, Error **errp)
218 bool ok = visit_type_enum(v, name, &value, &%(c_name)s_lookup, errp);
226 def gen_visit_alternate(name
: str,
227 alternatives
: QAPISchemaAlternatives
) -> str:
230 bool visit_type_%(c_name)s(Visitor *v, const char *name,
231 %(c_name)s **obj, Error **errp)
235 if (!visit_start_alternate(v, name, (GenericAlternate **)obj,
236 sizeof(**obj), errp)) {
241 assert(visit_is_dealloc(v));
245 switch ((*obj)->type) {
249 for var
in alternatives
.variants
:
250 ret
+= var
.ifcond
.gen_if()
254 case
=var
.type.alternate_qtype())
255 if isinstance(var
.type, QAPISchemaObjectType
):
257 if (!visit_start_struct(v, name, NULL, 0, errp)) {
260 if (visit_type_%(c_type)s_members(v, &(*obj)->u.%(c_name)s, errp)) {
261 ok = visit_check_struct(v, errp);
263 visit_end_struct(v, NULL);
265 c_type
=var
.type.c_name(),
266 c_name
=c_name(var
.name
))
269 ok = visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, errp);
271 c_type
=var
.type.c_name(),
272 c_name
=c_name(var
.name
))
276 ret
+= var
.ifcond
.gen_endif()
282 assert(visit_is_input(v));
284 "Invalid parameter type for '%%s', expected: %(name)s",
285 name ? name : "null");
286 /* Avoid passing invalid *obj to qapi_free_%(c_name)s() */
291 visit_end_alternate(v, (void **)obj);
292 if (!ok && visit_is_input(v)) {
293 qapi_free_%(c_name)s(*obj);
299 name
=name
, c_name
=c_name(name
))
304 def gen_visit_object(name
: str) -> str:
307 bool visit_type_%(c_name)s(Visitor *v, const char *name,
308 %(c_name)s **obj, Error **errp)
312 if (!visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), errp)) {
317 assert(visit_is_dealloc(v));
321 if (!visit_type_%(c_name)s_members(v, *obj, errp)) {
324 ok = visit_check_struct(v, errp);
326 visit_end_struct(v, (void **)obj);
327 if (!ok && visit_is_input(v)) {
328 qapi_free_%(c_name)s(*obj);
337 class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor
):
339 def __init__(self
, prefix
: str):
341 prefix
, 'qapi-visit', ' * Schema-defined QAPI visitors',
342 ' * Built-in QAPI visitors', __doc__
)
344 def _begin_builtin_module(self
) -> None:
345 self
._genc
.preamble_add(mcgen('''
346 #include "qemu/osdep.h"
347 #include "qapi/error.h"
348 #include "qapi/qapi-builtin-visit.h"
350 self
._genh
.preamble_add(mcgen('''
351 #include "qapi/visitor.h"
352 #include "qapi/qapi-builtin-types.h"
356 def _begin_user_module(self
, name
: str) -> None:
357 types
= self
._module
_basename
('qapi-types', name
)
358 visit
= self
._module
_basename
('qapi-visit', name
)
359 self
._genc
.preamble_add(mcgen('''
360 #include "qemu/osdep.h"
361 #include "qapi/error.h"
362 #include "%(visit)s.h"
365 self
._genh
.preamble_add(mcgen('''
366 #include "qapi/qapi-builtin-visit.h"
367 #include "%(types)s.h"
372 def visit_enum_type(self
,
374 info
: Optional
[QAPISourceInfo
],
375 ifcond
: QAPISchemaIfCond
,
376 features
: List
[QAPISchemaFeature
],
377 members
: List
[QAPISchemaEnumMember
],
378 prefix
: Optional
[str]) -> None:
379 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
380 self
._genh
.add(gen_visit_decl(name
, scalar
=True))
381 self
._genc
.add(gen_visit_enum(name
))
383 def visit_array_type(self
,
385 info
: Optional
[QAPISourceInfo
],
386 ifcond
: QAPISchemaIfCond
,
387 element_type
: QAPISchemaType
) -> None:
388 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
389 self
._genh
.add(gen_visit_decl(name
))
390 self
._genc
.add(gen_visit_list(name
, element_type
))
392 def visit_object_type(self
,
394 info
: Optional
[QAPISourceInfo
],
395 ifcond
: QAPISchemaIfCond
,
396 features
: List
[QAPISchemaFeature
],
397 base
: Optional
[QAPISchemaObjectType
],
398 members
: List
[QAPISchemaObjectTypeMember
],
399 branches
: Optional
[QAPISchemaBranches
]) -> None:
400 # Nothing to do for the special empty builtin
401 if name
== 'q_empty':
403 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
404 self
._genh
.add(gen_visit_members_decl(name
))
405 self
._genc
.add(gen_visit_object_members(name
, base
,
407 # TODO Worth changing the visitor signature, so we could
408 # directly use rather than repeat type.is_implicit()?
409 if not name
.startswith('q_'):
410 # only explicit types need an allocating visit
411 self
._genh
.add(gen_visit_decl(name
))
412 self
._genc
.add(gen_visit_object(name
))
414 def visit_alternate_type(self
,
416 info
: Optional
[QAPISourceInfo
],
417 ifcond
: QAPISchemaIfCond
,
418 features
: List
[QAPISchemaFeature
],
419 alternatives
: QAPISchemaAlternatives
) -> None:
420 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
421 self
._genh
.add(gen_visit_decl(name
))
422 self
._genc
.add(gen_visit_alternate(name
, alternatives
))
425 def gen_visit(schema
: QAPISchema
,
428 opt_builtins
: bool) -> None:
429 vis
= QAPISchemaGenVisitVisitor(prefix
)
431 vis
.write(output_dir
, opt_builtins
)