2 QAPI command marshaller generator
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.
24 from .common
import c_name
, mcgen
27 QAPISchemaModularCVisitor
,
37 from .source
import QAPISourceInfo
40 def gen_command_decl(name
: str,
41 arg_type
: Optional
[QAPISchemaObjectType
],
43 ret_type
: Optional
[QAPISchemaType
]) -> str:
45 %(c_type)s qmp_%(c_name)s(%(params)s);
47 c_type
=(ret_type
and ret_type
.c_type()) or 'void',
49 params
=build_params(arg_type
, boxed
, 'Error **errp'))
52 def gen_call(name
: str,
53 arg_type
: Optional
[QAPISchemaObjectType
],
55 ret_type
: Optional
[QAPISchemaType
]) -> str:
63 assert not arg_type
.variants
64 for memb
in arg_type
.members
:
66 argstr
+= 'arg.has_%s, ' % c_name(memb
.name
)
67 argstr
+= 'arg.%s, ' % c_name(memb
.name
)
75 %(lhs)sqmp_%(c_name)s(%(args)s&err);
76 error_propagate(errp, err);
78 c_name
=c_name(name
), args
=argstr
, lhs
=lhs
)
85 qmp_marshal_output_%(c_name)s(retval, ret, errp);
87 c_name
=ret_type
.c_name())
91 def gen_marshal_output(ret_type
: QAPISchemaType
) -> str:
94 static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in,
95 QObject **ret_out, Error **errp)
99 v = qobject_output_visitor_new(ret_out);
100 if (visit_type_%(c_name)s(v, "unused", &ret_in, errp)) {
101 visit_complete(v, ret_out);
104 v = qapi_dealloc_visitor_new();
105 visit_type_%(c_name)s(v, "unused", &ret_in, NULL);
109 c_type
=ret_type
.c_type(), c_name
=ret_type
.c_name())
112 def build_marshal_proto(name
: str) -> str:
113 return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)'
117 def gen_marshal_decl(name
: str) -> str:
121 proto
=build_marshal_proto(name
))
124 def gen_marshal(name
: str,
125 arg_type
: Optional
[QAPISchemaObjectType
],
127 ret_type
: Optional
[QAPISchemaType
]) -> str:
128 have_args
= boxed
or (arg_type
and not arg_type
.is_empty())
130 assert arg_type
is not None
131 arg_type_c_name
= arg_type
.c_name()
141 proto
=build_marshal_proto(name
))
147 c_type
=ret_type
.c_type())
151 %(c_name)s arg = {0};
153 c_name
=arg_type_c_name
)
157 v = qobject_input_visitor_new(QOBJECT(args));
158 if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
165 if (visit_type_%(c_arg_type)s_members(v, &arg, errp)) {
166 ok = visit_check_struct(v, errp);
169 c_arg_type
=arg_type_c_name
)
172 ok = visit_check_struct(v, errp);
176 visit_end_struct(v, NULL);
182 ret
+= gen_call(name
, arg_type
, boxed
, ret_type
)
191 v = qapi_dealloc_visitor_new();
192 visit_start_struct(v, NULL, NULL, 0, NULL);
197 visit_type_%(c_arg_type)s_members(v, &arg, NULL);
199 c_arg_type
=arg_type_c_name
)
202 visit_end_struct(v, NULL);
212 def gen_register_command(name
: str,
213 success_response
: bool,
215 allow_preconfig
: bool,
216 coroutine
: bool) -> str:
219 if not success_response
:
220 options
+= ['QCO_NO_SUCCESS_RESP']
222 options
+= ['QCO_ALLOW_OOB']
224 options
+= ['QCO_ALLOW_PRECONFIG']
226 options
+= ['QCO_COROUTINE']
229 options
= ['QCO_NO_OPTIONS']
232 qmp_register_command(cmds, "%(name)s",
233 qmp_marshal_%(c_name)s, %(opts)s);
235 name
=name
, c_name
=c_name(name
),
236 opts
=" | ".join(options
))
240 class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor
):
241 def __init__(self
, prefix
: str):
243 prefix
, 'qapi-commands',
244 ' * Schema-defined QAPI/QMP commands', None, __doc__
)
245 self
._visited
_ret
_types
: Dict
[QAPIGenC
, Set
[QAPISchemaType
]] = {}
247 def _begin_user_module(self
, name
: str) -> None:
248 self
._visited
_ret
_types
[self
._genc
] = set()
249 commands
= self
._module
_basename
('qapi-commands', name
)
250 types
= self
._module
_basename
('qapi-types', name
)
251 visit
= self
._module
_basename
('qapi-visit', name
)
252 self
._genc
.add(mcgen('''
253 #include "qemu/osdep.h"
254 #include "qapi/visitor.h"
255 #include "qapi/qmp/qdict.h"
256 #include "qapi/qobject-output-visitor.h"
257 #include "qapi/qobject-input-visitor.h"
258 #include "qapi/dealloc-visitor.h"
259 #include "qapi/error.h"
260 #include "%(visit)s.h"
261 #include "%(commands)s.h"
264 commands
=commands
, visit
=visit
))
265 self
._genh
.add(mcgen('''
266 #include "%(types)s.h"
271 def visit_begin(self
, schema
: QAPISchema
) -> None:
272 self
._add
_module
('./init', ' * QAPI Commands initialization')
273 self
._genh
.add(mcgen('''
274 #include "qapi/qmp/dispatch.h"
276 void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
278 c_prefix
=c_name(self
._prefix
, protect
=False)))
279 self
._genc
.add(mcgen('''
280 #include "qemu/osdep.h"
281 #include "%(prefix)sqapi-commands.h"
282 #include "%(prefix)sqapi-init-commands.h"
284 void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
290 c_prefix
=c_name(self
._prefix
, protect
=False)))
292 def visit_end(self
) -> None:
293 with self
._temp
_module
('./init'):
294 self
._genc
.add(mcgen('''
298 def visit_command(self
,
300 info
: Optional
[QAPISourceInfo
],
301 ifcond
: Sequence
[str],
302 features
: List
[QAPISchemaFeature
],
303 arg_type
: Optional
[QAPISchemaObjectType
],
304 ret_type
: Optional
[QAPISchemaType
],
306 success_response
: bool,
309 allow_preconfig
: bool,
310 coroutine
: bool) -> None:
313 # FIXME: If T is a user-defined type, the user is responsible
314 # for making this work, i.e. to make T's condition the
315 # conjunction of the T-returning commands' conditions. If T
316 # is a built-in type, this isn't possible: the
317 # qmp_marshal_output_T() will be generated unconditionally.
318 if ret_type
and ret_type
not in self
._visited
_ret
_types
[self
._genc
]:
319 self
._visited
_ret
_types
[self
._genc
].add(ret_type
)
320 with
ifcontext(ret_type
.ifcond
,
321 self
._genh
, self
._genc
):
322 self
._genc
.add(gen_marshal_output(ret_type
))
323 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
324 self
._genh
.add(gen_command_decl(name
, arg_type
, boxed
, ret_type
))
325 self
._genh
.add(gen_marshal_decl(name
))
326 self
._genc
.add(gen_marshal(name
, arg_type
, boxed
, ret_type
))
327 with self
._temp
_module
('./init'):
328 with
ifcontext(ifcond
, self
._genh
, self
._genc
):
329 self
._genc
.add(gen_register_command(name
, success_response
,
330 allow_oob
, allow_preconfig
,
334 def gen_commands(schema
: QAPISchema
,
336 prefix
: str) -> None:
337 vis
= QAPISchemaGenCommandVisitor(prefix
)
339 vis
.write(output_dir
)