]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/qapi/commands.py
qapi/commands.py: Don't re-bind to variable of different type
[mirror_qemu.git] / scripts / qapi / commands.py
CommitLineData
5ddeec83
MA
1"""
2QAPI command marshaller generator
3
4Copyright IBM, Corp. 2011
5Copyright (C) 2014-2018 Red Hat, Inc.
6
7Authors:
8 Anthony Liguori <aliguori@us.ibm.com>
9 Michael Roth <mdroth@linux.vnet.ibm.com>
10 Markus Armbruster <armbru@redhat.com>
11
12This work is licensed under the terms of the GNU GPL, version 2.
13See the COPYING file in the top-level directory.
14"""
c17d9908 15
e6a34cd7
JS
16from .common import c_name, mcgen
17from .gen import (
18 QAPIGenCCode,
19 QAPISchemaModularCVisitor,
20 build_params,
21 ifcontext,
22)
c17d9908 23
e98859a9 24
48825ca4 25def gen_command_decl(name, arg_type, boxed, ret_type):
c17d9908 26 return mcgen('''
03b4367a 27%(c_type)s qmp_%(c_name)s(%(params)s);
c17d9908 28''',
e98859a9
MA
29 c_type=(ret_type and ret_type.c_type()) or 'void',
30 c_name=c_name(name),
086ee7a6 31 params=build_params(arg_type, boxed, 'Error **errp'))
e98859a9 32
c17d9908 33
48825ca4 34def gen_call(name, arg_type, boxed, ret_type):
e98859a9
MA
35 ret = ''
36
37 argstr = ''
48825ca4 38 if boxed:
675b214b 39 assert arg_type
c818408e 40 argstr = '&arg, '
48825ca4 41 elif arg_type:
29f6bd15 42 assert not arg_type.variants
e98859a9 43 for memb in arg_type.members:
ee446028 44 if memb.optional:
386230a2
EB
45 argstr += 'arg.has_%s, ' % c_name(memb.name)
46 argstr += 'arg.%s, ' % c_name(memb.name)
e98859a9
MA
47
48 lhs = ''
49 if ret_type:
50 lhs = 'retval = '
51
c17d9908 52 ret = mcgen('''
f1538019 53
05372f70 54 %(lhs)sqmp_%(c_name)s(%(args)s&err);
cdd2b228 55 error_propagate(errp, err);
c17d9908 56''',
e98859a9 57 c_name=c_name(name), args=argstr, lhs=lhs)
c17d9908 58 if ret_type:
e02bca28 59 ret += mcgen('''
fa274ed6
EB
60 if (err) {
61 goto out;
62 }
e02bca28 63
cdd2b228 64 qmp_marshal_output_%(c_name)s(retval, ret, errp);
c17d9908 65''',
56d92b00 66 c_name=ret_type.c_name())
1f9a7a1a 67 return ret
c17d9908 68
e98859a9 69
56d92b00 70def gen_marshal_output(ret_type):
f1538019 71 return mcgen('''
ee446028 72
42c0dd12
JS
73static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in,
74 QObject **ret_out, Error **errp)
c17d9908 75{
c17d9908
MR
76 Visitor *v;
77
7d5e199a 78 v = qobject_output_visitor_new(ret_out);
cdd2b228 79 if (visit_type_%(c_name)s(v, "unused", &ret_in, errp)) {
3b098d56 80 visit_complete(v, ret_out);
c17d9908 81 }
2c0ef9f4
EB
82 visit_free(v);
83 v = qapi_dealloc_visitor_new();
51e72bc1 84 visit_type_%(c_name)s(v, "unused", &ret_in, NULL);
2c0ef9f4 85 visit_free(v);
c17d9908
MR
86}
87''',
56d92b00 88 c_type=ret_type.c_type(), c_name=ret_type.c_name())
c17d9908 89
e98859a9 90
086ee7a6 91def build_marshal_proto(name):
c2613949
MA
92 return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)'
93 % c_name(name))
776574d6 94
e98859a9 95
f1538019
MA
96def gen_marshal_decl(name):
97 return mcgen('''
98%(proto)s;
99''',
086ee7a6 100 proto=build_marshal_proto(name))
f1538019 101
776574d6 102
48825ca4 103def gen_marshal(name, arg_type, boxed, ret_type):
675b214b 104 have_args = boxed or (arg_type and not arg_type.is_empty())
a0067da1 105
c17d9908 106 ret = mcgen('''
ee446028 107
f1538019 108%(proto)s
c17d9908 109{
c1ff0e6c 110 Error *err = NULL;
cdd2b228 111 bool ok = false;
2061487b 112 Visitor *v;
c17d9908 113''',
086ee7a6 114 proto=build_marshal_proto(name))
c17d9908 115
c1ff0e6c
EB
116 if ret_type:
117 ret += mcgen('''
118 %(c_type)s retval;
119''',
120 c_type=ret_type.c_type())
121
a0067da1 122 if have_args:
c1ff0e6c 123 ret += mcgen('''
c1ff0e6c 124 %(c_name)s arg = {0};
a0067da1
MAL
125''',
126 c_name=arg_type.c_name())
a0067da1
MAL
127
128 ret += mcgen('''
2061487b 129
048abb7b 130 v = qobject_input_visitor_new(QOBJECT(args));
cdd2b228 131 if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
ed841535
EB
132 goto out;
133 }
89bf68f9
MA
134''')
135
136 if have_args:
137 ret += mcgen('''
cdd2b228
MA
138 if (visit_type_%(c_arg_type)s_members(v, &arg, errp)) {
139 ok = visit_check_struct(v, errp);
15c2f669 140 }
89bf68f9
MA
141''',
142 c_arg_type=arg_type.c_name())
143 else:
144 ret += mcgen('''
cdd2b228 145 ok = visit_check_struct(v, errp);
89bf68f9
MA
146''')
147
148 ret += mcgen('''
1158bb2a 149 visit_end_struct(v, NULL);
cdd2b228 150 if (!ok) {
c1ff0e6c
EB
151 goto out;
152 }
89bf68f9 153''')
c1ff0e6c 154
48825ca4 155 ret += gen_call(name, arg_type, boxed, ret_type)
1f9a7a1a 156
a0067da1 157 ret += mcgen('''
c17d9908
MR
158
159out:
a0067da1 160 visit_free(v);
1f9a7a1a 161''')
a0067da1 162
a0067da1 163 ret += mcgen('''
2c0ef9f4 164 v = qapi_dealloc_visitor_new();
ed841535 165 visit_start_struct(v, NULL, NULL, 0, NULL);
89bf68f9
MA
166''')
167
168 if have_args:
169 ret += mcgen('''
170 visit_type_%(c_arg_type)s_members(v, &arg, NULL);
171''',
172 c_arg_type=arg_type.c_name())
173
174 ret += mcgen('''
1158bb2a 175 visit_end_struct(v, NULL);
2c0ef9f4 176 visit_free(v);
89bf68f9 177''')
a0067da1 178
1f9a7a1a 179 ret += mcgen('''
485febc6 180}
1f9a7a1a 181''')
c17d9908
MR
182 return ret
183
e98859a9 184
04f22362
KW
185def gen_register_command(name, success_response, allow_oob, allow_preconfig,
186 coroutine):
876c6751
PX
187 options = []
188
ee446028 189 if not success_response:
876c6751
PX
190 options += ['QCO_NO_SUCCESS_RESP']
191 if allow_oob:
192 options += ['QCO_ALLOW_OOB']
d6fe3d02
IM
193 if allow_preconfig:
194 options += ['QCO_ALLOW_PRECONFIG']
04f22362
KW
195 if coroutine:
196 options += ['QCO_COROUTINE']
876c6751
PX
197
198 if not options:
199 options = ['QCO_NO_OPTIONS']
200
ee446028 201 ret = mcgen('''
c2613949 202 qmp_register_command(cmds, "%(name)s",
1527badb 203 qmp_marshal_%(c_name)s, %(opts)s);
c17d9908 204''',
e98859a9 205 name=name, c_name=c_name(name),
ab2d8a75 206 opts=" | ".join(options))
ee446028
MA
207 return ret
208
e98859a9 209
93b564c4 210def gen_registry(registry, prefix):
c17d9908 211 ret = mcgen('''
ee446028 212
1527badb 213void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
c17d9908 214{
1527badb
MA
215 QTAILQ_INIT(cmds);
216
217''',
218 c_prefix=c_name(prefix, protect=False))
1f9a7a1a
MA
219 ret += registry
220 ret += mcgen('''
c17d9908 221}
1f9a7a1a 222''')
c17d9908
MR
223 return ret
224
ee446028 225
252dc310 226class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor):
71b3f045 227
93b564c4 228 def __init__(self, prefix):
2cae67bc
MA
229 super().__init__(
230 prefix, 'qapi-commands',
3bef3aae 231 ' * Schema-defined QAPI/QMP commands', None, __doc__)
dddee4d7 232 self._regy = QAPIGenCCode(None)
252dc310
MA
233 self._visited_ret_types = {}
234
dcac6471 235 def _begin_user_module(self, name):
252dc310 236 self._visited_ret_types[self._genc] = set()
9af23989
MA
237 commands = self._module_basename('qapi-commands', name)
238 types = self._module_basename('qapi-types', name)
239 visit = self._module_basename('qapi-visit', name)
71b3f045 240 self._genc.add(mcgen('''
9167ebd9 241#include "qemu/osdep.h"
4180978c 242#include "qapi/visitor.h"
452fcdbc 243#include "qapi/qmp/qdict.h"
b3db211f
DB
244#include "qapi/qobject-output-visitor.h"
245#include "qapi/qobject-input-visitor.h"
4180978c 246#include "qapi/dealloc-visitor.h"
e688df6b 247#include "qapi/error.h"
9af23989
MA
248#include "%(visit)s.h"
249#include "%(commands)s.h"
4180978c
MA
250
251''',
9af23989 252 commands=commands, visit=visit))
71b3f045 253 self._genh.add(mcgen('''
9af23989 254#include "%(types)s.h"
4180978c
MA
255
256''',
9af23989 257 types=types))
71b3f045
MA
258
259 def visit_end(self):
00ca24ff
MA
260 self._add_system_module('init', ' * QAPI Commands initialization')
261 self._genh.add(mcgen('''
262#include "qapi/qmp/dispatch.h"
263
252dc310
MA
264void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
265''',
8ec0e1a4 266 c_prefix=c_name(self._prefix, protect=False)))
00ca24ff
MA
267 self._genc.preamble_add(mcgen('''
268#include "qemu/osdep.h"
269#include "%(prefix)sqapi-commands.h"
270#include "%(prefix)sqapi-init-commands.h"
271''',
272 prefix=self._prefix))
273 self._genc.add(gen_registry(self._regy.get_content(), self._prefix))
71b3f045 274
7b3bc9e2
MA
275 def visit_command(self, name, info, ifcond, features,
276 arg_type, ret_type, gen, success_response, boxed,
04f22362 277 allow_oob, allow_preconfig, coroutine):
71b3f045
MA
278 if not gen:
279 return
1f7b9f31
MAL
280 # FIXME: If T is a user-defined type, the user is responsible
281 # for making this work, i.e. to make T's condition the
282 # conjunction of the T-returning commands' conditions. If T
283 # is a built-in type, this isn't possible: the
284 # qmp_marshal_output_T() will be generated unconditionally.
252dc310
MA
285 if ret_type and ret_type not in self._visited_ret_types[self._genc]:
286 self._visited_ret_types[self._genc].add(ret_type)
1f7b9f31
MAL
287 with ifcontext(ret_type.ifcond,
288 self._genh, self._genc, self._regy):
289 self._genc.add(gen_marshal_output(ret_type))
290 with ifcontext(ifcond, self._genh, self._genc, self._regy):
291 self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
292 self._genh.add(gen_marshal_decl(name))
293 self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
294 self._regy.add(gen_register_command(name, success_response,
04f22362
KW
295 allow_oob, allow_preconfig,
296 coroutine))
71b3f045 297
26df4e7f 298
71b3f045 299def gen_commands(schema, output_dir, prefix):
26df4e7f
MA
300 vis = QAPISchemaGenCommandVisitor(prefix)
301 schema.visit(vis)
71b3f045 302 vis.write(output_dir)