target/riscv: Add DisasExtend to gen_arith*
[qemu/ar7.git] / scripts / qapi / visit.py
blob56ea516399b0deff2094c26f8a1cbd951340b82e
1 """
2 QAPI visitor generator
4 Copyright IBM, Corp. 2011
5 Copyright (C) 2014-2018 Red Hat, Inc.
7 Authors:
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.
14 """
16 from typing import List, Optional
18 from .common import (
19 c_enum_const,
20 c_name,
21 gen_endif,
22 gen_if,
23 indent,
24 mcgen,
26 from .gen import QAPISchemaModularCVisitor, ifcontext
27 from .schema import (
28 QAPISchema,
29 QAPISchemaEnumMember,
30 QAPISchemaEnumType,
31 QAPISchemaFeature,
32 QAPISchemaIfCond,
33 QAPISchemaObjectType,
34 QAPISchemaObjectTypeMember,
35 QAPISchemaType,
36 QAPISchemaVariants,
38 from .source import QAPISourceInfo
41 def gen_visit_decl(name: str, scalar: bool = False) -> str:
42 c_type = c_name(name) + ' *'
43 if not scalar:
44 c_type += '*'
45 return mcgen('''
47 bool visit_type_%(c_name)s(Visitor *v, const char *name,
48 %(c_type)sobj, Error **errp);
49 ''',
50 c_name=c_name(name), c_type=c_type)
53 def gen_visit_members_decl(name: str) -> str:
54 return mcgen('''
56 bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp);
57 ''',
58 c_name=c_name(name))
61 def gen_visit_object_members(name: str,
62 base: Optional[QAPISchemaObjectType],
63 members: List[QAPISchemaObjectTypeMember],
64 variants: Optional[QAPISchemaVariants]) -> str:
65 ret = mcgen('''
67 bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
69 ''',
70 c_name=c_name(name))
72 if base:
73 ret += mcgen('''
74 if (!visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, errp)) {
75 return false;
77 ''',
78 c_type=base.c_name())
80 for memb in members:
81 deprecated = 'deprecated' in [f.name for f in memb.features]
82 ret += gen_if(memb.ifcond.cgen())
83 if memb.optional:
84 ret += mcgen('''
85 if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
86 ''',
87 name=memb.name, c_name=c_name(memb.name))
88 indent.increase()
89 if deprecated:
90 ret += mcgen('''
91 if (!visit_deprecated_accept(v, "%(name)s", errp)) {
92 return false;
94 if (visit_deprecated(v, "%(name)s")) {
95 ''',
96 name=memb.name)
97 indent.increase()
98 ret += mcgen('''
99 if (!visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, errp)) {
100 return false;
102 ''',
103 c_type=memb.type.c_name(), name=memb.name,
104 c_name=c_name(memb.name))
105 if deprecated:
106 indent.decrease()
107 ret += mcgen('''
109 ''')
110 if memb.optional:
111 indent.decrease()
112 ret += mcgen('''
114 ''')
115 ret += gen_endif(memb.ifcond.cgen())
117 if variants:
118 tag_member = variants.tag_member
119 assert isinstance(tag_member.type, QAPISchemaEnumType)
121 ret += mcgen('''
122 switch (obj->%(c_name)s) {
123 ''',
124 c_name=c_name(tag_member.name))
126 for var in variants.variants:
127 case_str = c_enum_const(tag_member.type.name, var.name,
128 tag_member.type.prefix)
129 ret += gen_if(var.ifcond.cgen())
130 if var.type.name == 'q_empty':
131 # valid variant and nothing to do
132 ret += mcgen('''
133 case %(case)s:
134 break;
135 ''',
136 case=case_str)
137 else:
138 ret += mcgen('''
139 case %(case)s:
140 return visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, errp);
141 ''',
142 case=case_str,
143 c_type=var.type.c_name(), c_name=c_name(var.name))
145 ret += gen_endif(var.ifcond.cgen())
146 ret += mcgen('''
147 default:
148 abort();
150 ''')
152 ret += mcgen('''
153 return true;
155 ''')
156 return ret
159 def gen_visit_list(name: str, element_type: QAPISchemaType) -> str:
160 return mcgen('''
162 bool visit_type_%(c_name)s(Visitor *v, const char *name,
163 %(c_name)s **obj, Error **errp)
165 bool ok = false;
166 %(c_name)s *tail;
167 size_t size = sizeof(**obj);
169 if (!visit_start_list(v, name, (GenericList **)obj, size, errp)) {
170 return false;
173 for (tail = *obj; tail;
174 tail = (%(c_name)s *)visit_next_list(v, (GenericList *)tail, size)) {
175 if (!visit_type_%(c_elt_type)s(v, NULL, &tail->value, errp)) {
176 goto out_obj;
180 ok = visit_check_list(v, errp);
181 out_obj:
182 visit_end_list(v, (void **)obj);
183 if (!ok && visit_is_input(v)) {
184 qapi_free_%(c_name)s(*obj);
185 *obj = NULL;
187 return ok;
189 ''',
190 c_name=c_name(name), c_elt_type=element_type.c_name())
193 def gen_visit_enum(name: str) -> str:
194 return mcgen('''
196 bool visit_type_%(c_name)s(Visitor *v, const char *name,
197 %(c_name)s *obj, Error **errp)
199 int value = *obj;
200 bool ok = visit_type_enum(v, name, &value, &%(c_name)s_lookup, errp);
201 *obj = value;
202 return ok;
204 ''',
205 c_name=c_name(name))
208 def gen_visit_alternate(name: str, variants: QAPISchemaVariants) -> str:
209 ret = mcgen('''
211 bool visit_type_%(c_name)s(Visitor *v, const char *name,
212 %(c_name)s **obj, Error **errp)
214 bool ok = false;
216 if (!visit_start_alternate(v, name, (GenericAlternate **)obj,
217 sizeof(**obj), errp)) {
218 return false;
220 if (!*obj) {
221 /* incomplete */
222 assert(visit_is_dealloc(v));
223 ok = true;
224 goto out_obj;
226 switch ((*obj)->type) {
227 ''',
228 c_name=c_name(name))
230 for var in variants.variants:
231 ret += gen_if(var.ifcond.cgen())
232 ret += mcgen('''
233 case %(case)s:
234 ''',
235 case=var.type.alternate_qtype())
236 if isinstance(var.type, QAPISchemaObjectType):
237 ret += mcgen('''
238 if (!visit_start_struct(v, name, NULL, 0, errp)) {
239 break;
241 if (visit_type_%(c_type)s_members(v, &(*obj)->u.%(c_name)s, errp)) {
242 ok = visit_check_struct(v, errp);
244 visit_end_struct(v, NULL);
245 ''',
246 c_type=var.type.c_name(),
247 c_name=c_name(var.name))
248 else:
249 ret += mcgen('''
250 ok = visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, errp);
251 ''',
252 c_type=var.type.c_name(),
253 c_name=c_name(var.name))
254 ret += mcgen('''
255 break;
256 ''')
257 ret += gen_endif(var.ifcond.cgen())
259 ret += mcgen('''
260 case QTYPE_NONE:
261 abort();
262 default:
263 assert(visit_is_input(v));
264 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
265 "%(name)s");
266 /* Avoid passing invalid *obj to qapi_free_%(c_name)s() */
267 g_free(*obj);
268 *obj = NULL;
270 out_obj:
271 visit_end_alternate(v, (void **)obj);
272 if (!ok && visit_is_input(v)) {
273 qapi_free_%(c_name)s(*obj);
274 *obj = NULL;
276 return ok;
278 ''',
279 name=name, c_name=c_name(name))
281 return ret
284 def gen_visit_object(name: str) -> str:
285 return mcgen('''
287 bool visit_type_%(c_name)s(Visitor *v, const char *name,
288 %(c_name)s **obj, Error **errp)
290 bool ok = false;
292 if (!visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), errp)) {
293 return false;
295 if (!*obj) {
296 /* incomplete */
297 assert(visit_is_dealloc(v));
298 ok = true;
299 goto out_obj;
301 if (!visit_type_%(c_name)s_members(v, *obj, errp)) {
302 goto out_obj;
304 ok = visit_check_struct(v, errp);
305 out_obj:
306 visit_end_struct(v, (void **)obj);
307 if (!ok && visit_is_input(v)) {
308 qapi_free_%(c_name)s(*obj);
309 *obj = NULL;
311 return ok;
313 ''',
314 c_name=c_name(name))
317 class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
319 def __init__(self, prefix: str):
320 super().__init__(
321 prefix, 'qapi-visit', ' * Schema-defined QAPI visitors',
322 ' * Built-in QAPI visitors', __doc__)
324 def _begin_builtin_module(self) -> None:
325 self._genc.preamble_add(mcgen('''
326 #include "qemu/osdep.h"
327 #include "qapi/error.h"
328 #include "qapi/qapi-builtin-visit.h"
329 '''))
330 self._genh.preamble_add(mcgen('''
331 #include "qapi/visitor.h"
332 #include "qapi/qapi-builtin-types.h"
334 '''))
336 def _begin_user_module(self, name: str) -> None:
337 types = self._module_basename('qapi-types', name)
338 visit = self._module_basename('qapi-visit', name)
339 self._genc.preamble_add(mcgen('''
340 #include "qemu/osdep.h"
341 #include "qapi/error.h"
342 #include "qapi/qmp/qerror.h"
343 #include "%(visit)s.h"
344 ''',
345 visit=visit))
346 self._genh.preamble_add(mcgen('''
347 #include "qapi/qapi-builtin-visit.h"
348 #include "%(types)s.h"
350 ''',
351 types=types))
353 def visit_enum_type(self,
354 name: str,
355 info: Optional[QAPISourceInfo],
356 ifcond: QAPISchemaIfCond,
357 features: List[QAPISchemaFeature],
358 members: List[QAPISchemaEnumMember],
359 prefix: Optional[str]) -> None:
360 with ifcontext(ifcond, self._genh, self._genc):
361 self._genh.add(gen_visit_decl(name, scalar=True))
362 self._genc.add(gen_visit_enum(name))
364 def visit_array_type(self,
365 name: str,
366 info: Optional[QAPISourceInfo],
367 ifcond: QAPISchemaIfCond,
368 element_type: QAPISchemaType) -> None:
369 with ifcontext(ifcond, self._genh, self._genc):
370 self._genh.add(gen_visit_decl(name))
371 self._genc.add(gen_visit_list(name, element_type))
373 def visit_object_type(self,
374 name: str,
375 info: Optional[QAPISourceInfo],
376 ifcond: QAPISchemaIfCond,
377 features: List[QAPISchemaFeature],
378 base: Optional[QAPISchemaObjectType],
379 members: List[QAPISchemaObjectTypeMember],
380 variants: Optional[QAPISchemaVariants]) -> None:
381 # Nothing to do for the special empty builtin
382 if name == 'q_empty':
383 return
384 with ifcontext(ifcond, self._genh, self._genc):
385 self._genh.add(gen_visit_members_decl(name))
386 self._genc.add(gen_visit_object_members(name, base,
387 members, variants))
388 # TODO Worth changing the visitor signature, so we could
389 # directly use rather than repeat type.is_implicit()?
390 if not name.startswith('q_'):
391 # only explicit types need an allocating visit
392 self._genh.add(gen_visit_decl(name))
393 self._genc.add(gen_visit_object(name))
395 def visit_alternate_type(self,
396 name: str,
397 info: Optional[QAPISourceInfo],
398 ifcond: QAPISchemaIfCond,
399 features: List[QAPISchemaFeature],
400 variants: QAPISchemaVariants) -> None:
401 with ifcontext(ifcond, self._genh, self._genc):
402 self._genh.add(gen_visit_decl(name))
403 self._genc.add(gen_visit_alternate(name, variants))
406 def gen_visit(schema: QAPISchema,
407 output_dir: str,
408 prefix: str,
409 opt_builtins: bool) -> None:
410 vis = QAPISchemaGenVisitVisitor(prefix)
411 schema.visit(vis)
412 vis.write(output_dir, opt_builtins)