linux-user: Support f_flags in statfs64 when available.
[qemu/ar7.git] / scripts / qapi / visit.py
blob339f1521524c89ed29008c435fa1a60c77660a1f
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 QAPISchemaObjectType,
33 QAPISchemaObjectTypeMember,
34 QAPISchemaType,
35 QAPISchemaVariants,
37 from .source import QAPISourceInfo
40 def gen_visit_decl(name: str, scalar: bool = False) -> str:
41 c_type = c_name(name) + ' *'
42 if not scalar:
43 c_type += '*'
44 return mcgen('''
46 bool visit_type_%(c_name)s(Visitor *v, const char *name,
47 %(c_type)sobj, Error **errp);
48 ''',
49 c_name=c_name(name), c_type=c_type)
52 def gen_visit_members_decl(name: str) -> str:
53 return mcgen('''
55 bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp);
56 ''',
57 c_name=c_name(name))
60 def gen_visit_object_members(name: str,
61 base: Optional[QAPISchemaObjectType],
62 members: List[QAPISchemaObjectTypeMember],
63 variants: Optional[QAPISchemaVariants]) -> str:
64 ret = mcgen('''
66 bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
68 ''',
69 c_name=c_name(name))
71 if base:
72 ret += mcgen('''
73 if (!visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, errp)) {
74 return false;
76 ''',
77 c_type=base.c_name())
79 for memb in members:
80 ret += gen_if(memb.ifcond)
81 if memb.optional:
82 ret += mcgen('''
83 if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
84 ''',
85 name=memb.name, c_name=c_name(memb.name))
86 indent.increase()
87 ret += mcgen('''
88 if (!visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, errp)) {
89 return false;
91 ''',
92 c_type=memb.type.c_name(), name=memb.name,
93 c_name=c_name(memb.name))
94 if memb.optional:
95 indent.decrease()
96 ret += mcgen('''
98 ''')
99 ret += gen_endif(memb.ifcond)
101 if variants:
102 tag_member = variants.tag_member
103 assert isinstance(tag_member.type, QAPISchemaEnumType)
105 ret += mcgen('''
106 switch (obj->%(c_name)s) {
107 ''',
108 c_name=c_name(tag_member.name))
110 for var in variants.variants:
111 case_str = c_enum_const(tag_member.type.name, var.name,
112 tag_member.type.prefix)
113 ret += gen_if(var.ifcond)
114 if var.type.name == 'q_empty':
115 # valid variant and nothing to do
116 ret += mcgen('''
117 case %(case)s:
118 break;
119 ''',
120 case=case_str)
121 else:
122 ret += mcgen('''
123 case %(case)s:
124 return visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, errp);
125 ''',
126 case=case_str,
127 c_type=var.type.c_name(), c_name=c_name(var.name))
129 ret += gen_endif(var.ifcond)
130 ret += mcgen('''
131 default:
132 abort();
134 ''')
136 ret += mcgen('''
137 return true;
139 ''')
140 return ret
143 def gen_visit_list(name: str, element_type: QAPISchemaType) -> str:
144 return mcgen('''
146 bool visit_type_%(c_name)s(Visitor *v, const char *name,
147 %(c_name)s **obj, Error **errp)
149 bool ok = false;
150 %(c_name)s *tail;
151 size_t size = sizeof(**obj);
153 if (!visit_start_list(v, name, (GenericList **)obj, size, errp)) {
154 return false;
157 for (tail = *obj; tail;
158 tail = (%(c_name)s *)visit_next_list(v, (GenericList *)tail, size)) {
159 if (!visit_type_%(c_elt_type)s(v, NULL, &tail->value, errp)) {
160 goto out_obj;
164 ok = visit_check_list(v, errp);
165 out_obj:
166 visit_end_list(v, (void **)obj);
167 if (!ok && visit_is_input(v)) {
168 qapi_free_%(c_name)s(*obj);
169 *obj = NULL;
171 return ok;
173 ''',
174 c_name=c_name(name), c_elt_type=element_type.c_name())
177 def gen_visit_enum(name: str) -> str:
178 return mcgen('''
180 bool visit_type_%(c_name)s(Visitor *v, const char *name,
181 %(c_name)s *obj, Error **errp)
183 int value = *obj;
184 bool ok = visit_type_enum(v, name, &value, &%(c_name)s_lookup, errp);
185 *obj = value;
186 return ok;
188 ''',
189 c_name=c_name(name))
192 def gen_visit_alternate(name: str, variants: QAPISchemaVariants) -> str:
193 ret = mcgen('''
195 bool visit_type_%(c_name)s(Visitor *v, const char *name,
196 %(c_name)s **obj, Error **errp)
198 bool ok = false;
200 if (!visit_start_alternate(v, name, (GenericAlternate **)obj,
201 sizeof(**obj), errp)) {
202 return false;
204 if (!*obj) {
205 /* incomplete */
206 assert(visit_is_dealloc(v));
207 ok = true;
208 goto out_obj;
210 switch ((*obj)->type) {
211 ''',
212 c_name=c_name(name))
214 for var in variants.variants:
215 ret += gen_if(var.ifcond)
216 ret += mcgen('''
217 case %(case)s:
218 ''',
219 case=var.type.alternate_qtype())
220 if isinstance(var.type, QAPISchemaObjectType):
221 ret += mcgen('''
222 if (!visit_start_struct(v, name, NULL, 0, errp)) {
223 break;
225 if (visit_type_%(c_type)s_members(v, &(*obj)->u.%(c_name)s, errp)) {
226 ok = visit_check_struct(v, errp);
228 visit_end_struct(v, NULL);
229 ''',
230 c_type=var.type.c_name(),
231 c_name=c_name(var.name))
232 else:
233 ret += mcgen('''
234 ok = visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, errp);
235 ''',
236 c_type=var.type.c_name(),
237 c_name=c_name(var.name))
238 ret += mcgen('''
239 break;
240 ''')
241 ret += gen_endif(var.ifcond)
243 ret += mcgen('''
244 case QTYPE_NONE:
245 abort();
246 default:
247 assert(visit_is_input(v));
248 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
249 "%(name)s");
250 /* Avoid passing invalid *obj to qapi_free_%(c_name)s() */
251 g_free(*obj);
252 *obj = NULL;
254 out_obj:
255 visit_end_alternate(v, (void **)obj);
256 if (!ok && visit_is_input(v)) {
257 qapi_free_%(c_name)s(*obj);
258 *obj = NULL;
260 return ok;
262 ''',
263 name=name, c_name=c_name(name))
265 return ret
268 def gen_visit_object(name: str) -> str:
269 return mcgen('''
271 bool visit_type_%(c_name)s(Visitor *v, const char *name,
272 %(c_name)s **obj, Error **errp)
274 bool ok = false;
276 if (!visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), errp)) {
277 return false;
279 if (!*obj) {
280 /* incomplete */
281 assert(visit_is_dealloc(v));
282 ok = true;
283 goto out_obj;
285 if (!visit_type_%(c_name)s_members(v, *obj, errp)) {
286 goto out_obj;
288 ok = visit_check_struct(v, errp);
289 out_obj:
290 visit_end_struct(v, (void **)obj);
291 if (!ok && visit_is_input(v)) {
292 qapi_free_%(c_name)s(*obj);
293 *obj = NULL;
295 return ok;
297 ''',
298 c_name=c_name(name))
301 class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
303 def __init__(self, prefix: str):
304 super().__init__(
305 prefix, 'qapi-visit', ' * Schema-defined QAPI visitors',
306 ' * Built-in QAPI visitors', __doc__)
308 def _begin_system_module(self, name: None) -> None:
309 self._genc.preamble_add(mcgen('''
310 #include "qemu/osdep.h"
311 #include "qapi/error.h"
312 #include "qapi/qapi-builtin-visit.h"
313 '''))
314 self._genh.preamble_add(mcgen('''
315 #include "qapi/visitor.h"
316 #include "qapi/qapi-builtin-types.h"
318 '''))
320 def _begin_user_module(self, name: str) -> None:
321 types = self._module_basename('qapi-types', name)
322 visit = self._module_basename('qapi-visit', name)
323 self._genc.preamble_add(mcgen('''
324 #include "qemu/osdep.h"
325 #include "qapi/error.h"
326 #include "qapi/qmp/qerror.h"
327 #include "%(visit)s.h"
328 ''',
329 visit=visit))
330 self._genh.preamble_add(mcgen('''
331 #include "qapi/qapi-builtin-visit.h"
332 #include "%(types)s.h"
334 ''',
335 types=types))
337 def visit_enum_type(self,
338 name: str,
339 info: QAPISourceInfo,
340 ifcond: List[str],
341 features: List[QAPISchemaFeature],
342 members: List[QAPISchemaEnumMember],
343 prefix: Optional[str]) -> None:
344 with ifcontext(ifcond, self._genh, self._genc):
345 self._genh.add(gen_visit_decl(name, scalar=True))
346 self._genc.add(gen_visit_enum(name))
348 def visit_array_type(self,
349 name: str,
350 info: Optional[QAPISourceInfo],
351 ifcond: List[str],
352 element_type: QAPISchemaType) -> None:
353 with ifcontext(ifcond, self._genh, self._genc):
354 self._genh.add(gen_visit_decl(name))
355 self._genc.add(gen_visit_list(name, element_type))
357 def visit_object_type(self,
358 name: str,
359 info: Optional[QAPISourceInfo],
360 ifcond: List[str],
361 features: List[QAPISchemaFeature],
362 base: Optional[QAPISchemaObjectType],
363 members: List[QAPISchemaObjectTypeMember],
364 variants: Optional[QAPISchemaVariants]) -> None:
365 # Nothing to do for the special empty builtin
366 if name == 'q_empty':
367 return
368 with ifcontext(ifcond, self._genh, self._genc):
369 self._genh.add(gen_visit_members_decl(name))
370 self._genc.add(gen_visit_object_members(name, base,
371 members, variants))
372 # TODO Worth changing the visitor signature, so we could
373 # directly use rather than repeat type.is_implicit()?
374 if not name.startswith('q_'):
375 # only explicit types need an allocating visit
376 self._genh.add(gen_visit_decl(name))
377 self._genc.add(gen_visit_object(name))
379 def visit_alternate_type(self,
380 name: str,
381 info: QAPISourceInfo,
382 ifcond: List[str],
383 features: List[QAPISchemaFeature],
384 variants: QAPISchemaVariants) -> None:
385 with ifcontext(ifcond, self._genh, self._genc):
386 self._genh.add(gen_visit_decl(name))
387 self._genc.add(gen_visit_alternate(name, variants))
390 def gen_visit(schema: QAPISchema,
391 output_dir: str,
392 prefix: str,
393 opt_builtins: bool) -> None:
394 vis = QAPISchemaGenVisitVisitor(prefix)
395 schema.visit(vis)
396 vis.write(output_dir, opt_builtins)