blob: 67c7d89aae00cba7eade35abd21129c41038b3f6 [file] [log] [blame]
Markus Armbruster5ddeec82018-02-11 10:35:41 +01001"""
2QAPI introspection generator
3
John Snowcf269062021-02-15 21:18:06 -05004Copyright (C) 2015-2021 Red Hat, Inc.
Markus Armbruster5ddeec82018-02-11 10:35:41 +01005
6Authors:
7 Markus Armbruster <armbru@redhat.com>
John Snowcf269062021-02-15 21:18:06 -05008 John Snow <jsnow@redhat.com>
Markus Armbruster5ddeec82018-02-11 10:35:41 +01009
10This work is licensed under the terms of the GNU GPL, version 2.
11See the COPYING file in the top-level directory.
12"""
Markus Armbruster39a18152015-09-16 13:06:28 +020013
John Snow9db27342021-02-15 21:17:59 -050014from typing import (
15 Any,
16 Dict,
John Snow4f7f97a2021-02-15 21:18:00 -050017 Generic,
John Snow9db27342021-02-15 21:17:59 -050018 List,
19 Optional,
John Snow82b52f62021-02-15 21:18:04 -050020 Sequence,
John Snow4f7f97a2021-02-15 21:18:00 -050021 TypeVar,
John Snow9db27342021-02-15 21:17:59 -050022 Union,
23)
John Snow5f50ced2021-02-15 21:17:57 -050024
Markus Armbruster1889e572021-08-31 14:37:58 +020025from .common import c_name, mcgen
John Snow7137a962020-10-09 12:15:27 -040026from .gen import QAPISchemaMonolithicCVisitor
John Snow67fea572020-10-09 12:15:29 -040027from .schema import (
John Snow82b52f62021-02-15 21:18:04 -050028 QAPISchema,
John Snow67fea572020-10-09 12:15:29 -040029 QAPISchemaArrayType,
30 QAPISchemaBuiltinType,
John Snow82b52f62021-02-15 21:18:04 -050031 QAPISchemaEntity,
32 QAPISchemaEnumMember,
33 QAPISchemaFeature,
Marc-André Lureauf17539c2021-08-04 12:30:57 +040034 QAPISchemaIfCond,
John Snow82b52f62021-02-15 21:18:04 -050035 QAPISchemaObjectType,
36 QAPISchemaObjectTypeMember,
John Snow67fea572020-10-09 12:15:29 -040037 QAPISchemaType,
John Snow82b52f62021-02-15 21:18:04 -050038 QAPISchemaVariant,
39 QAPISchemaVariants,
John Snow67fea572020-10-09 12:15:29 -040040)
John Snow82b52f62021-02-15 21:18:04 -050041from .source import QAPISourceInfo
Markus Armbruster39a18152015-09-16 13:06:28 +020042
43
John Snow9db27342021-02-15 21:17:59 -050044# This module constructs a tree data structure that is used to
45# generate the introspection information for QEMU. It is shaped
46# like a JSON value.
47#
48# A complexity over JSON is that our values may or may not be annotated.
49#
50# Un-annotated values may be:
51# Scalar: str, bool, None.
52# Non-scalar: List, Dict
53# _value = Union[str, bool, None, Dict[str, JSONValue], List[JSONValue]]
54#
55# With optional annotations, the type of all values is:
56# JSONValue = Union[_Value, Annotated[_Value]]
57#
58# Sadly, mypy does not support recursive types; so the _Stub alias is used to
59# mark the imprecision in the type model where we'd otherwise use JSONValue.
60_Stub = Any
61_Scalar = Union[str, bool, None]
62_NonScalar = Union[Dict[str, _Stub], List[_Stub]]
63_Value = Union[_Scalar, _NonScalar]
John Snow4f7f97a2021-02-15 21:18:00 -050064JSONValue = Union[_Value, 'Annotated[_Value]']
John Snow9db27342021-02-15 21:17:59 -050065
John Snow82b52f62021-02-15 21:18:04 -050066# These types are based on structures defined in QEMU's schema, so we
67# lack precise types for them here. Python 3.6 does not offer
68# TypedDict constructs, so they are broadly typed here as simple
69# Python Dicts.
70SchemaInfo = Dict[str, object]
Markus Armbruster75ecee72021-10-25 06:24:01 +020071SchemaInfoEnumMember = Dict[str, object]
John Snow82b52f62021-02-15 21:18:04 -050072SchemaInfoObject = Dict[str, object]
73SchemaInfoObjectVariant = Dict[str, object]
74SchemaInfoObjectMember = Dict[str, object]
75SchemaInfoCommand = Dict[str, object]
76
John Snow9db27342021-02-15 21:17:59 -050077
John Snow4f7f97a2021-02-15 21:18:00 -050078_ValueT = TypeVar('_ValueT', bound=_Value)
79
80
81class Annotated(Generic[_ValueT]):
82 """
83 Annotated generally contains a SchemaInfo-like type (as a dict),
84 But it also used to wrap comments/ifconds around scalar leaf values,
85 for the benefit of features and enums.
86 """
87 # TODO: Remove after Python 3.7 adds @dataclass:
88 # pylint: disable=too-few-public-methods
Marc-André Lureauf17539c2021-08-04 12:30:57 +040089 def __init__(self, value: _ValueT, ifcond: QAPISchemaIfCond,
John Snow4f7f97a2021-02-15 21:18:00 -050090 comment: Optional[str] = None):
91 self.value = value
92 self.comment: Optional[str] = comment
Marc-André Lureauf17539c2021-08-04 12:30:57 +040093 self.ifcond = ifcond
Markus Armbruster24cfd6a2020-03-17 12:54:40 +010094
95
John Snow82b52f62021-02-15 21:18:04 -050096def _tree_to_qlit(obj: JSONValue,
97 level: int = 0,
98 dict_value: bool = False) -> str:
John Snow5444ded2021-02-15 21:18:05 -050099 """
100 Convert the type tree into a QLIT C string, recursively.
101
102 :param obj: The value to convert.
103 This value may not be Annotated when dict_value is True.
104 :param level: The indentation level for this particular value.
105 :param dict_value: True when the value being processed belongs to a
106 dict key; which suppresses the output indent.
107 """
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100108
John Snow82b52f62021-02-15 21:18:04 -0500109 def indent(level: int) -> str:
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100110 return level * 4 * ' '
111
John Snow4f7f97a2021-02-15 21:18:00 -0500112 if isinstance(obj, Annotated):
John Snow05556962021-02-15 21:17:55 -0500113 # NB: _tree_to_qlit is called recursively on the values of a
114 # key:value pair; those values can't be decorated with
115 # comments or conditionals.
116 msg = "dict values cannot have attached comments or if-conditionals."
117 assert not dict_value, msg
118
Eric Blake8c643362018-08-27 16:39:43 -0500119 ret = ''
John Snow4f7f97a2021-02-15 21:18:00 -0500120 if obj.comment:
John Snowc0e8d9f2021-02-15 21:18:02 -0500121 ret += indent(level) + f"/* {obj.comment} */\n"
Marc-André Lureau33aa3262021-08-04 12:30:58 +0400122 if obj.ifcond.is_present():
Markus Armbruster1889e572021-08-31 14:37:58 +0200123 ret += obj.ifcond.gen_if()
John Snow4f7f97a2021-02-15 21:18:00 -0500124 ret += _tree_to_qlit(obj.value, level)
Marc-André Lureau33aa3262021-08-04 12:30:58 +0400125 if obj.ifcond.is_present():
Markus Armbruster1889e572021-08-31 14:37:58 +0200126 ret += '\n' + obj.ifcond.gen_endif()
Marc-André Lureaud626b6c2018-07-03 17:56:42 +0200127 return ret
128
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100129 ret = ''
John Snow05556962021-02-15 21:17:55 -0500130 if not dict_value:
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100131 ret += indent(level)
John Snowc0e8d9f2021-02-15 21:18:02 -0500132
133 # Scalars:
Markus Armbruster39a18152015-09-16 13:06:28 +0200134 if obj is None:
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100135 ret += 'QLIT_QNULL'
Markus Armbruster39a18152015-09-16 13:06:28 +0200136 elif isinstance(obj, str):
John Snowc0e8d9f2021-02-15 21:18:02 -0500137 ret += f"QLIT_QSTR({to_c_string(obj)})"
138 elif isinstance(obj, bool):
139 ret += f"QLIT_QBOOL({str(obj).lower()})"
140
141 # Non-scalars:
Markus Armbruster39a18152015-09-16 13:06:28 +0200142 elif isinstance(obj, list):
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100143 ret += 'QLIT_QLIST(((QLitObject[]) {\n'
John Snowc0e8d9f2021-02-15 21:18:02 -0500144 for value in obj:
145 ret += _tree_to_qlit(value, level + 1).strip('\n') + '\n'
146 ret += indent(level + 1) + '{}\n'
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100147 ret += indent(level) + '}))'
Markus Armbruster39a18152015-09-16 13:06:28 +0200148 elif isinstance(obj, dict):
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100149 ret += 'QLIT_QDICT(((QLitDictEntry[]) {\n'
John Snowc0e8d9f2021-02-15 21:18:02 -0500150 for key, value in sorted(obj.items()):
151 ret += indent(level + 1) + "{{ {:s}, {:s} }},\n".format(
152 to_c_string(key),
153 _tree_to_qlit(value, level + 1, dict_value=True)
154 )
155 ret += indent(level + 1) + '{}\n'
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100156 ret += indent(level) + '}))'
Markus Armbruster39a18152015-09-16 13:06:28 +0200157 else:
John Snow2a6c1612021-02-15 21:18:01 -0500158 raise NotImplementedError(
159 f"type '{type(obj).__name__}' not implemented"
160 )
John Snowc0e8d9f2021-02-15 21:18:02 -0500161
Marc-André Lureau40bb1372018-07-03 17:56:41 +0200162 if level > 0:
163 ret += ','
Markus Armbruster39a18152015-09-16 13:06:28 +0200164 return ret
165
166
John Snow82b52f62021-02-15 21:18:04 -0500167def to_c_string(string: str) -> str:
Markus Armbruster39a18152015-09-16 13:06:28 +0200168 return '"' + string.replace('\\', r'\\').replace('"', r'\"') + '"'
169
170
Markus Armbruster71b3f042018-02-26 13:50:08 -0600171class QAPISchemaGenIntrospectVisitor(QAPISchemaMonolithicCVisitor):
Markus Armbruster39a18152015-09-16 13:06:28 +0200172
John Snow82b52f62021-02-15 21:18:04 -0500173 def __init__(self, prefix: str, unmask: bool):
Markus Armbruster2cae67b2020-03-04 16:59:31 +0100174 super().__init__(
175 prefix, 'qapi-introspect',
Markus Armbruster71b3f042018-02-26 13:50:08 -0600176 ' * QAPI/QMP schema introspection', __doc__)
177 self._unmask = unmask
John Snow82b52f62021-02-15 21:18:04 -0500178 self._schema: Optional[QAPISchema] = None
179 self._trees: List[Annotated[SchemaInfo]] = []
180 self._used_types: List[QAPISchemaType] = []
181 self._name_map: Dict[str, str] = {}
Markus Armbruster71b3f042018-02-26 13:50:08 -0600182 self._genc.add(mcgen('''
183#include "qemu/osdep.h"
Markus Armbrustereb815e22018-02-11 10:36:05 +0100184#include "%(prefix)sqapi-introspect.h"
Markus Armbruster71b3f042018-02-26 13:50:08 -0600185
186''',
187 prefix=prefix))
188
John Snow82b52f62021-02-15 21:18:04 -0500189 def visit_begin(self, schema: QAPISchema) -> None:
Markus Armbruster71b3f042018-02-26 13:50:08 -0600190 self._schema = schema
Markus Armbruster39a18152015-09-16 13:06:28 +0200191
John Snow82b52f62021-02-15 21:18:04 -0500192 def visit_end(self) -> None:
Markus Armbruster39a18152015-09-16 13:06:28 +0200193 # visit the types that are actually used
194 for typ in self._used_types:
195 typ.visit(self)
Markus Armbruster39a18152015-09-16 13:06:28 +0200196 # generate C
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100197 name = c_name(self._prefix, protect=False) + 'qmp_schema_qlit'
Markus Armbruster71b3f042018-02-26 13:50:08 -0600198 self._genh.add(mcgen('''
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100199#include "qapi/qmp/qlit.h"
200
201extern const QLitObject %(c_name)s;
Markus Armbruster39a18152015-09-16 13:06:28 +0200202''',
Markus Armbruster71b3f042018-02-26 13:50:08 -0600203 c_name=c_name(name)))
Markus Armbruster71b3f042018-02-26 13:50:08 -0600204 self._genc.add(mcgen('''
Marc-André Lureau7d0f9822018-03-05 18:29:51 +0100205const QLitObject %(c_name)s = %(c_string)s;
Markus Armbruster39a18152015-09-16 13:06:28 +0200206''',
Markus Armbruster71b3f042018-02-26 13:50:08 -0600207 c_name=c_name(name),
Markus Armbruster2e8a8432020-03-17 12:54:39 +0100208 c_string=_tree_to_qlit(self._trees)))
Markus Armbruster39a18152015-09-16 13:06:28 +0200209 self._schema = None
Markus Armbruster2e8a8432020-03-17 12:54:39 +0100210 self._trees = []
Markus Armbruster71b3f042018-02-26 13:50:08 -0600211 self._used_types = []
212 self._name_map = {}
Markus Armbruster1a9a5072015-09-16 13:06:29 +0200213
John Snow82b52f62021-02-15 21:18:04 -0500214 def visit_needed(self, entity: QAPISchemaEntity) -> bool:
Eric Blake25a0d9c2015-10-12 22:22:21 -0600215 # Ignore types on first pass; visit_end() will pick up used types
216 return not isinstance(entity, QAPISchemaType)
217
John Snow82b52f62021-02-15 21:18:04 -0500218 def _name(self, name: str) -> str:
Markus Armbruster1a9a5072015-09-16 13:06:29 +0200219 if self._unmask:
220 return name
221 if name not in self._name_map:
222 self._name_map[name] = '%d' % len(self._name_map)
223 return self._name_map[name]
Markus Armbruster39a18152015-09-16 13:06:28 +0200224
John Snow82b52f62021-02-15 21:18:04 -0500225 def _use_type(self, typ: QAPISchemaType) -> str:
John Snow6b67bca2021-02-15 21:17:52 -0500226 assert self._schema is not None
227
Markus Armbruster39a18152015-09-16 13:06:28 +0200228 # Map the various integer types to plain int
229 if typ.json_type() == 'int':
230 typ = self._schema.lookup_type('int')
231 elif (isinstance(typ, QAPISchemaArrayType) and
232 typ.element_type.json_type() == 'int'):
233 typ = self._schema.lookup_type('intList')
234 # Add type to work queue if new
235 if typ not in self._used_types:
236 self._used_types.append(typ)
Markus Armbruster1a9a5072015-09-16 13:06:29 +0200237 # Clients should examine commands and events, not types. Hide
Eric Blake1aa806c2018-08-27 16:39:42 -0500238 # type names as integers to reduce the temptation. Also, it
239 # saves a few characters on the wire.
Markus Armbruster1a9a5072015-09-16 13:06:29 +0200240 if isinstance(typ, QAPISchemaBuiltinType):
241 return typ.name
Eric Blakece5fcb42015-11-05 23:35:35 -0700242 if isinstance(typ, QAPISchemaArrayType):
243 return '[' + self._use_type(typ.element_type) + ']'
Markus Armbruster1a9a5072015-09-16 13:06:29 +0200244 return self._name(typ.name)
Markus Armbruster39a18152015-09-16 13:06:28 +0200245
John Snow84bece72021-02-15 21:17:54 -0500246 @staticmethod
John Snowcea53c32021-02-15 21:18:07 -0500247 def _gen_features(features: Sequence[QAPISchemaFeature]
John Snow82b52f62021-02-15 21:18:04 -0500248 ) -> List[Annotated[str]]:
John Snow4f7f97a2021-02-15 21:18:00 -0500249 return [Annotated(f.name, f.ifcond) for f in features]
John Snow84bece72021-02-15 21:17:54 -0500250
John Snow82b52f62021-02-15 21:18:04 -0500251 def _gen_tree(self, name: str, mtype: str, obj: Dict[str, object],
Marc-André Lureauf17539c2021-08-04 12:30:57 +0400252 ifcond: QAPISchemaIfCond = QAPISchemaIfCond(),
John Snowcea53c32021-02-15 21:18:07 -0500253 features: Sequence[QAPISchemaFeature] = ()) -> None:
John Snow5444ded2021-02-15 21:18:05 -0500254 """
255 Build and append a SchemaInfo object to self._trees.
256
257 :param name: The SchemaInfo's name.
258 :param mtype: The SchemaInfo's meta-type.
259 :param obj: Additional SchemaInfo members, as appropriate for
260 the meta-type.
261 :param ifcond: Conditionals to apply to the SchemaInfo.
262 :param features: The SchemaInfo's features.
263 Will be omitted from the output if empty.
264 """
John Snow5f50ced2021-02-15 21:17:57 -0500265 comment: Optional[str] = None
Eric Blakece5fcb42015-11-05 23:35:35 -0700266 if mtype not in ('command', 'event', 'builtin', 'array'):
Eric Blake8c643362018-08-27 16:39:43 -0500267 if not self._unmask:
268 # Output a comment to make it easy to map masked names
269 # back to the source when reading the generated output.
John Snow5f50ced2021-02-15 21:17:57 -0500270 comment = f'"{self._name(name)}" = {name}'
Markus Armbruster1a9a5072015-09-16 13:06:29 +0200271 name = self._name(name)
Markus Armbruster39a18152015-09-16 13:06:28 +0200272 obj['name'] = name
273 obj['meta-type'] = mtype
John Snow84bece72021-02-15 21:17:54 -0500274 if features:
275 obj['features'] = self._gen_features(features)
John Snow4f7f97a2021-02-15 21:18:00 -0500276 self._trees.append(Annotated(obj, ifcond, comment))
Markus Armbruster39a18152015-09-16 13:06:28 +0200277
Markus Armbrusterb6c18752021-10-25 06:24:02 +0200278 def _gen_enum_member(self, member: QAPISchemaEnumMember
Markus Armbruster75ecee72021-10-25 06:24:01 +0200279 ) -> Annotated[SchemaInfoEnumMember]:
280 obj: SchemaInfoEnumMember = {
281 'name': member.name,
282 }
Markus Armbrusterb6c18752021-10-25 06:24:02 +0200283 if member.features:
284 obj['features'] = self._gen_features(member.features)
Markus Armbruster75ecee72021-10-25 06:24:01 +0200285 return Annotated(obj, member.ifcond)
286
287 def _gen_object_member(self, member: QAPISchemaObjectTypeMember
288 ) -> Annotated[SchemaInfoObjectMember]:
John Snow82b52f62021-02-15 21:18:04 -0500289 obj: SchemaInfoObjectMember = {
290 'name': member.name,
291 'type': self._use_type(member.type)
292 }
Markus Armbruster39a18152015-09-16 13:06:28 +0200293 if member.optional:
Markus Armbruster24cfd6a2020-03-17 12:54:40 +0100294 obj['default'] = None
John Snow84bece72021-02-15 21:17:54 -0500295 if member.features:
296 obj['features'] = self._gen_features(member.features)
John Snow4f7f97a2021-02-15 21:18:00 -0500297 return Annotated(obj, member.ifcond)
Markus Armbruster39a18152015-09-16 13:06:28 +0200298
John Snow82b52f62021-02-15 21:18:04 -0500299 def _gen_variant(self, variant: QAPISchemaVariant
300 ) -> Annotated[SchemaInfoObjectVariant]:
301 obj: SchemaInfoObjectVariant = {
302 'case': variant.name,
303 'type': self._use_type(variant.type)
304 }
John Snow4f7f97a2021-02-15 21:18:00 -0500305 return Annotated(obj, variant.ifcond)
Markus Armbruster39a18152015-09-16 13:06:28 +0200306
John Snow82b52f62021-02-15 21:18:04 -0500307 def visit_builtin_type(self, name: str, info: Optional[QAPISourceInfo],
308 json_type: str) -> None:
John Snow9b77d942021-02-15 21:18:08 -0500309 self._gen_tree(name, 'builtin', {'json-type': json_type})
Markus Armbruster39a18152015-09-16 13:06:28 +0200310
John Snow82b52f62021-02-15 21:18:04 -0500311 def visit_enum_type(self, name: str, info: Optional[QAPISourceInfo],
Marc-André Lureauf17539c2021-08-04 12:30:57 +0400312 ifcond: QAPISchemaIfCond,
John Snow82b52f62021-02-15 21:18:04 -0500313 features: List[QAPISchemaFeature],
314 members: List[QAPISchemaEnumMember],
315 prefix: Optional[str]) -> None:
John Snow4f7f97a2021-02-15 21:18:00 -0500316 self._gen_tree(
317 name, 'enum',
Markus Armbruster75ecee72021-10-25 06:24:01 +0200318 {'members': [self._gen_enum_member(m) for m in members],
319 'values': [Annotated(m.name, m.ifcond) for m in members]},
John Snow4f7f97a2021-02-15 21:18:00 -0500320 ifcond, features
321 )
Markus Armbruster39a18152015-09-16 13:06:28 +0200322
John Snow82b52f62021-02-15 21:18:04 -0500323 def visit_array_type(self, name: str, info: Optional[QAPISourceInfo],
Marc-André Lureauf17539c2021-08-04 12:30:57 +0400324 ifcond: QAPISchemaIfCond,
John Snow82b52f62021-02-15 21:18:04 -0500325 element_type: QAPISchemaType) -> None:
Eric Blakece5fcb42015-11-05 23:35:35 -0700326 element = self._use_type(element_type)
Markus Armbruster2e8a8432020-03-17 12:54:39 +0100327 self._gen_tree('[' + element + ']', 'array', {'element-type': element},
John Snowcea53c32021-02-15 21:18:07 -0500328 ifcond)
Markus Armbruster39a18152015-09-16 13:06:28 +0200329
John Snow82b52f62021-02-15 21:18:04 -0500330 def visit_object_type_flat(self, name: str, info: Optional[QAPISourceInfo],
Marc-André Lureauf17539c2021-08-04 12:30:57 +0400331 ifcond: QAPISchemaIfCond,
John Snow82b52f62021-02-15 21:18:04 -0500332 features: List[QAPISchemaFeature],
333 members: List[QAPISchemaObjectTypeMember],
334 variants: Optional[QAPISchemaVariants]) -> None:
335 obj: SchemaInfoObject = {
Markus Armbruster75ecee72021-10-25 06:24:01 +0200336 'members': [self._gen_object_member(m) for m in members]
John Snow82b52f62021-02-15 21:18:04 -0500337 }
Markus Armbruster39a18152015-09-16 13:06:28 +0200338 if variants:
John Snowcf5db212021-02-15 21:18:03 -0500339 obj['tag'] = variants.tag_member.name
340 obj['variants'] = [self._gen_variant(v) for v in variants.variants]
Markus Armbruster2e8a8432020-03-17 12:54:39 +0100341 self._gen_tree(name, 'object', obj, ifcond, features)
Markus Armbruster39a18152015-09-16 13:06:28 +0200342
John Snow82b52f62021-02-15 21:18:04 -0500343 def visit_alternate_type(self, name: str, info: Optional[QAPISourceInfo],
Marc-André Lureauf17539c2021-08-04 12:30:57 +0400344 ifcond: QAPISchemaIfCond,
John Snow82b52f62021-02-15 21:18:04 -0500345 features: List[QAPISchemaFeature],
346 variants: QAPISchemaVariants) -> None:
John Snow4f7f97a2021-02-15 21:18:00 -0500347 self._gen_tree(
348 name, 'alternate',
349 {'members': [Annotated({'type': self._use_type(m.type)},
350 m.ifcond)
351 for m in variants.variants]},
352 ifcond, features
353 )
Markus Armbruster39a18152015-09-16 13:06:28 +0200354
John Snow82b52f62021-02-15 21:18:04 -0500355 def visit_command(self, name: str, info: Optional[QAPISourceInfo],
Marc-André Lureauf17539c2021-08-04 12:30:57 +0400356 ifcond: QAPISchemaIfCond,
John Snow82b52f62021-02-15 21:18:04 -0500357 features: List[QAPISchemaFeature],
358 arg_type: Optional[QAPISchemaObjectType],
359 ret_type: Optional[QAPISchemaType], gen: bool,
360 success_response: bool, boxed: bool, allow_oob: bool,
361 allow_preconfig: bool, coroutine: bool) -> None:
John Snow6b67bca2021-02-15 21:17:52 -0500362 assert self._schema is not None
363
Markus Armbruster39a18152015-09-16 13:06:28 +0200364 arg_type = arg_type or self._schema.the_empty_object_type
365 ret_type = ret_type or self._schema.the_empty_object_type
John Snow82b52f62021-02-15 21:18:04 -0500366 obj: SchemaInfoCommand = {
367 'arg-type': self._use_type(arg_type),
368 'ret-type': self._use_type(ret_type)
369 }
Markus Armbruster25b1ef32018-07-18 11:05:57 +0200370 if allow_oob:
371 obj['allow-oob'] = allow_oob
Markus Armbruster2e8a8432020-03-17 12:54:39 +0100372 self._gen_tree(name, 'command', obj, ifcond, features)
Peter Krempa23394b42019-10-18 10:14:51 +0200373
John Snow82b52f62021-02-15 21:18:04 -0500374 def visit_event(self, name: str, info: Optional[QAPISourceInfo],
Marc-André Lureauf17539c2021-08-04 12:30:57 +0400375 ifcond: QAPISchemaIfCond,
376 features: List[QAPISchemaFeature],
John Snow82b52f62021-02-15 21:18:04 -0500377 arg_type: Optional[QAPISchemaObjectType],
378 boxed: bool) -> None:
John Snow6b67bca2021-02-15 21:17:52 -0500379 assert self._schema is not None
John Snow82b52f62021-02-15 21:18:04 -0500380
Markus Armbruster39a18152015-09-16 13:06:28 +0200381 arg_type = arg_type or self._schema.the_empty_object_type
Markus Armbruster2e8a8432020-03-17 12:54:39 +0100382 self._gen_tree(name, 'event', {'arg-type': self._use_type(arg_type)},
Markus Armbruster013b4ef2020-03-17 12:54:37 +0100383 ifcond, features)
Markus Armbruster39a18152015-09-16 13:06:28 +0200384
Markus Armbruster1a9a5072015-09-16 13:06:29 +0200385
John Snow82b52f62021-02-15 21:18:04 -0500386def gen_introspect(schema: QAPISchema, output_dir: str, prefix: str,
387 opt_unmask: bool) -> None:
Markus Armbruster26df4e72018-02-26 13:39:37 -0600388 vis = QAPISchemaGenIntrospectVisitor(prefix, opt_unmask)
389 schema.visit(vis)
Markus Armbruster71b3f042018-02-26 13:50:08 -0600390 vis.write(output_dir)