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
,
36 QAPISchemaObjectTypeMember
,
40 from .source
import QAPISourceInfo
43 def gen_visit_decl(name
: str, scalar
: bool = False) -> str:
44 c_type
= c_name(name
) + ' *'
49 bool visit_type_%(c_name)s(Visitor *v, const char *name,
50 %(c_type)sobj, Error **errp);
52 c_name
=c_name(name
), c_type
=c_type
)
55 def gen_visit_members_decl(name
: str) -> str:
58 bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp);
63 def gen_visit_object_members(name
: str,
64 base
: Optional
[QAPISchemaObjectType
],
65 members
: List
[QAPISchemaObjectTypeMember
],
66 variants
: Optional
[QAPISchemaVariants
]) -> str:
69 bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
76 if memb
.optional
and not memb
.need_has():
77 ret
+= memb
.ifcond
.gen_if()
79 bool has_%(c_name)s = !!obj->%(c_name)s;
81 c_name
=c_name(memb
.name
))
83 ret
+= memb
.ifcond
.gen_endif()
88 if (!visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, errp)) {
95 ret
+= memb
.ifcond
.gen_if()
97 has
= 'has_' + c_name(memb
.name
)
101 if (visit_optional(v, "%(name)s", &%(has)s)) {
103 name
=memb
.name
, has
=has
)
105 special_features
= gen_special_features(memb
.features
)
106 if special_features
!= '0':
108 if (visit_policy_reject(v, "%(name)s", %(special_features)s, errp)) {
111 if (!visit_policy_skip(v, "%(name)s", %(special_features)s)) {
113 name
=memb
.name
, special_features
=special_features
)
116 if (!visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, errp)) {
120 c_type
=memb
.type.c_name(), name
=memb
.name
,
121 c_name
=c_name(memb
.name
))
122 if special_features
!= '0':
132 ret
+= memb
.ifcond
.gen_endif()
135 tag_member
= variants
.tag_member
136 assert isinstance(tag_member
.type, QAPISchemaEnumType
)
139 switch (obj->%(c_name)s) {
141 c_name
=c_name(tag_member
.name
))
143 for var
in variants
.variants
:
144 case_str
= c_enum_const(tag_member
.type.name
, var
.name
,
145 tag_member
.type.prefix
)
146 ret
+= var
.ifcond
.gen_if()
147 if var
.type.name
== 'q_empty':
148 # valid variant and nothing to do
157 return visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, errp);
160 c_type
=var
.type.c_name(), c_name
=c_name(var
.name
))
162 ret
+= var
.ifcond
.gen_endif()
176 def gen_visit_list(name
: str, element_type
: QAPISchemaType
) -> str:
179 bool visit_type_%(c_name)s(Visitor *v, const char *name,
180 %(c_name)s **obj, Error **errp)
184 size_t size = sizeof(**obj);
186 if (!visit_start_list(v, name, (GenericList **)obj, size, errp)) {
190 for (tail = *obj; tail;
191 tail = (%(c_name)s *)visit_next_list(v, (GenericList *)tail, size)) {
192 if (!visit_type_%(c_elt_type)s(v, NULL, &tail->value, errp)) {
197 ok = visit_check_list(v, errp);
199 visit_end_list(v, (void **)obj);
200 if (!ok && visit_is_input(v)) {
201 qapi_free_%(c_name)s(*obj);
207 c_name
=c_name(name
), c_elt_type
=element_type
.c_name())
210 def gen_visit_enum(name
: str) -> str:
213 bool visit_type_%(c_name)s(Visitor *v, const char *name,
214 %(c_name)s *obj, Error **errp)
217 bool ok = visit_type_enum(v, name, &value, &%(c_name)s_lookup, errp);
225 def gen_visit_alternate(name
: str, variants
: QAPISchemaVariants
) -> str:
228 bool visit_type_%(c_name)s(Visitor *v, const char *name,
229 %(c_name)s **obj, Error **errp)
233 if (!visit_start_alternate(v, name, (GenericAlternate **)obj,
234 sizeof(**obj), errp)) {
239 assert(visit_is_dealloc(v));
243 switch ((*obj)->type) {
247 for var
in variants
.variants
:
248 ret
+= var
.ifcond
.gen_if()
252 case
=var
.type.alternate_qtype())
253 if isinstance(var
.type, QAPISchemaObjectType
):
255 if (!visit_start_struct(v, name, NULL, 0, errp)) {
258 if (visit_type_%(c_type)s_members(v, &(*obj)->u.%(c_name)s, errp)) {
259 ok = visit_check_struct(v, errp);
261 visit_end_struct(v, NULL);
263 c_type
=var
.type.c_name(),
264 c_name
=c_name(var
.name
))
267 ok = visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, errp);
269 c_type
=var
.type.c_name(),
270 c_name
=c_name(var
.name
))
274 ret
+= var
.ifcond
.gen_endif()
280 assert(visit_is_input(v));
281 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
283 /* Avoid passing invalid *obj to qapi_free_%(c_name)s() */
288 visit_end_alternate(v, (void **)obj);
289 if (!ok && visit_is_input(v)) {
290 qapi_free_%(c_name)s(*obj);
296 name
=name
, c_name
=c_name(name
))
301 def gen_visit_object(name
: str) -> str:
304 bool visit_type_%(c_name)s(Visitor *v, const char *name,
305 %(c_name)s **obj, Error **errp)
309 if (!visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), errp)) {
314 assert(visit_is_dealloc(v));
318 if (!visit_type_%(c_name)s_members(v, *obj, errp)) {
321 ok = visit_check_struct(v, errp);
323 visit_end_struct(v, (void **)obj);
324 if (!ok && visit_is_input(v)) {
325 qapi_free_%(c_name)s(*obj);
334 class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor
):
336 def __init__(self
, prefix
: str):
338 prefix
, 'qapi-visit', ' * Schema-defined QAPI visitors',
339 ' * Built-in QAPI visitors', __doc__
)
341 def _begin_builtin_module(self
) -> None:
342 self
._genc
.preamble_add(mcgen('''
343 #include "qemu/osdep.h"
344 #include "qapi/error.h"
345 #include "qapi/qapi-builtin-visit.h"
347 self
._genh
.preamble_add(mcgen('''
348 #include "qapi/visitor.h"
349 #include "qapi/qapi-builtin-types.h"
353 def _begin_user_module(self
, name
: str) -> None:
354 types
= self
._module
_basename
('qapi-types', name
)
355 visit
= self
._module
_basename
('qapi-visit', name
)
356 self
._genc
.preamble_add(mcgen('''
357 #include "qemu/osdep.h"
358 #include "qapi/error.h"
359 #include "qapi/qmp/qerror.h"
360 #include "%(visit)s.h"
363 self
._genh
.preamble_add(mcgen('''
364 #include "qapi/qapi-builtin-visit.h"
365 #include "%(types)s.h"
370 def visit_enum_type(self
,
372 info
: Optional
[QAPISourceInfo
],
373 ifcond
: QAPISchemaIfCond
,
374 features
: List
[QAPISchemaFeature
],
375 members
: List
[QAPISchemaEnumMember
],
376 prefix
: Optional
[str]) -> None:
377 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
378 self
._genh
.add(gen_visit_decl(name
, scalar
=True))
379 self
._genc
.add(gen_visit_enum(name
))
381 def visit_array_type(self
,
383 info
: Optional
[QAPISourceInfo
],
384 ifcond
: QAPISchemaIfCond
,
385 element_type
: QAPISchemaType
) -> None:
386 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
387 self
._genh
.add(gen_visit_decl(name
))
388 self
._genc
.add(gen_visit_list(name
, element_type
))
390 def visit_object_type(self
,
392 info
: Optional
[QAPISourceInfo
],
393 ifcond
: QAPISchemaIfCond
,
394 features
: List
[QAPISchemaFeature
],
395 base
: Optional
[QAPISchemaObjectType
],
396 members
: List
[QAPISchemaObjectTypeMember
],
397 variants
: Optional
[QAPISchemaVariants
]) -> None:
398 # Nothing to do for the special empty builtin
399 if name
== 'q_empty':
401 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
402 self
._genh
.add(gen_visit_members_decl(name
))
403 self
._genc
.add(gen_visit_object_members(name
, base
,
405 # TODO Worth changing the visitor signature, so we could
406 # directly use rather than repeat type.is_implicit()?
407 if not name
.startswith('q_'):
408 # only explicit types need an allocating visit
409 self
._genh
.add(gen_visit_decl(name
))
410 self
._genc
.add(gen_visit_object(name
))
412 def visit_alternate_type(self
,
414 info
: Optional
[QAPISourceInfo
],
415 ifcond
: QAPISchemaIfCond
,
416 features
: List
[QAPISchemaFeature
],
417 variants
: QAPISchemaVariants
) -> None:
418 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
419 self
._genh
.add(gen_visit_decl(name
))
420 self
._genc
.add(gen_visit_alternate(name
, variants
))
423 def gen_visit(schema
: QAPISchema
,
426 opt_builtins
: bool) -> None:
427 vis
= QAPISchemaGenVisitVisitor(prefix
)
429 vis
.write(output_dir
, opt_builtins
)