1fb0bc835SMarkus Armbruster""" 2fb0bc835SMarkus ArmbrusterQAPI introspection generator 3fb0bc835SMarkus Armbruster 4cf26906cSJohn SnowCopyright (C) 2015-2021 Red Hat, Inc. 5fb0bc835SMarkus Armbruster 6fb0bc835SMarkus ArmbrusterAuthors: 7fb0bc835SMarkus Armbruster Markus Armbruster <armbru@redhat.com> 8cf26906cSJohn Snow John Snow <jsnow@redhat.com> 9fb0bc835SMarkus Armbruster 10fb0bc835SMarkus ArmbrusterThis work is licensed under the terms of the GNU GPL, version 2. 11fb0bc835SMarkus ArmbrusterSee the COPYING file in the top-level directory. 12fb0bc835SMarkus Armbruster""" 13fb0bc835SMarkus Armbruster 149db27346SJohn Snowfrom typing import ( 159db27346SJohn Snow Any, 169db27346SJohn Snow Dict, 174f7f97a7SJohn Snow Generic, 189db27346SJohn Snow List, 199db27346SJohn Snow Optional, 2082b52f6bSJohn Snow Sequence, 214f7f97a7SJohn Snow TypeVar, 229db27346SJohn Snow Union, 239db27346SJohn Snow) 245f50cedeSJohn Snow 251889e57aSMarkus Armbrusterfrom .common import c_name, mcgen 267137a960SJohn Snowfrom .gen import QAPISchemaMonolithicCVisitor 2767fea575SJohn Snowfrom .schema import ( 2882b52f6bSJohn Snow QAPISchema, 2967fea575SJohn Snow QAPISchemaArrayType, 3067fea575SJohn Snow QAPISchemaBuiltinType, 3182b52f6bSJohn Snow QAPISchemaEntity, 3282b52f6bSJohn Snow QAPISchemaEnumMember, 3382b52f6bSJohn Snow QAPISchemaFeature, 34f17539c8SMarc-André Lureau QAPISchemaIfCond, 3582b52f6bSJohn Snow QAPISchemaObjectType, 3682b52f6bSJohn Snow QAPISchemaObjectTypeMember, 3767fea575SJohn Snow QAPISchemaType, 3882b52f6bSJohn Snow QAPISchemaVariant, 3982b52f6bSJohn Snow QAPISchemaVariants, 4067fea575SJohn Snow) 4182b52f6bSJohn Snowfrom .source import QAPISourceInfo 42fb0bc835SMarkus Armbruster 43fb0bc835SMarkus Armbruster 449db27346SJohn Snow# This module constructs a tree data structure that is used to 459db27346SJohn Snow# generate the introspection information for QEMU. It is shaped 469db27346SJohn Snow# like a JSON value. 479db27346SJohn Snow# 489db27346SJohn Snow# A complexity over JSON is that our values may or may not be annotated. 499db27346SJohn Snow# 509db27346SJohn Snow# Un-annotated values may be: 519db27346SJohn Snow# Scalar: str, bool, None. 529db27346SJohn Snow# Non-scalar: List, Dict 539db27346SJohn Snow# _value = Union[str, bool, None, Dict[str, JSONValue], List[JSONValue]] 549db27346SJohn Snow# 559db27346SJohn Snow# With optional annotations, the type of all values is: 569db27346SJohn Snow# JSONValue = Union[_Value, Annotated[_Value]] 579db27346SJohn Snow# 589db27346SJohn Snow# Sadly, mypy does not support recursive types; so the _Stub alias is used to 599db27346SJohn Snow# mark the imprecision in the type model where we'd otherwise use JSONValue. 609db27346SJohn Snow_Stub = Any 619db27346SJohn Snow_Scalar = Union[str, bool, None] 629db27346SJohn Snow_NonScalar = Union[Dict[str, _Stub], List[_Stub]] 639db27346SJohn Snow_Value = Union[_Scalar, _NonScalar] 644f7f97a7SJohn SnowJSONValue = Union[_Value, 'Annotated[_Value]'] 659db27346SJohn Snow 6682b52f6bSJohn Snow# These types are based on structures defined in QEMU's schema, so we 6782b52f6bSJohn Snow# lack precise types for them here. Python 3.6 does not offer 6882b52f6bSJohn Snow# TypedDict constructs, so they are broadly typed here as simple 6982b52f6bSJohn Snow# Python Dicts. 7082b52f6bSJohn SnowSchemaInfo = Dict[str, object] 7175ecee72SMarkus ArmbrusterSchemaInfoEnumMember = Dict[str, object] 7282b52f6bSJohn SnowSchemaInfoObject = Dict[str, object] 7382b52f6bSJohn SnowSchemaInfoObjectVariant = Dict[str, object] 7482b52f6bSJohn SnowSchemaInfoObjectMember = Dict[str, object] 7582b52f6bSJohn SnowSchemaInfoCommand = Dict[str, object] 7682b52f6bSJohn Snow 779db27346SJohn Snow 784f7f97a7SJohn Snow_ValueT = TypeVar('_ValueT', bound=_Value) 794f7f97a7SJohn Snow 804f7f97a7SJohn Snow 814f7f97a7SJohn Snowclass Annotated(Generic[_ValueT]): 824f7f97a7SJohn Snow """ 834f7f97a7SJohn Snow Annotated generally contains a SchemaInfo-like type (as a dict), 844f7f97a7SJohn Snow But it also used to wrap comments/ifconds around scalar leaf values, 854f7f97a7SJohn Snow for the benefit of features and enums. 864f7f97a7SJohn Snow """ 874f7f97a7SJohn Snow # TODO: Remove after Python 3.7 adds @dataclass: 884f7f97a7SJohn Snow # pylint: disable=too-few-public-methods 89f17539c8SMarc-André Lureau def __init__(self, value: _ValueT, ifcond: QAPISchemaIfCond, 904f7f97a7SJohn Snow comment: Optional[str] = None): 914f7f97a7SJohn Snow self.value = value 924f7f97a7SJohn Snow self.comment: Optional[str] = comment 93f17539c8SMarc-André Lureau self.ifcond = ifcond 9424cfd6adSMarkus Armbruster 9524cfd6adSMarkus Armbruster 9682b52f6bSJohn Snowdef _tree_to_qlit(obj: JSONValue, 9782b52f6bSJohn Snow level: int = 0, 9882b52f6bSJohn Snow dict_value: bool = False) -> str: 995444dedfSJohn Snow """ 1005444dedfSJohn Snow Convert the type tree into a QLIT C string, recursively. 1015444dedfSJohn Snow 1025444dedfSJohn Snow :param obj: The value to convert. 1035444dedfSJohn Snow This value may not be Annotated when dict_value is True. 1045444dedfSJohn Snow :param level: The indentation level for this particular value. 1055444dedfSJohn Snow :param dict_value: True when the value being processed belongs to a 1065444dedfSJohn Snow dict key; which suppresses the output indent. 1075444dedfSJohn Snow """ 1087d0f982bSMarc-André Lureau 10982b52f6bSJohn Snow def indent(level: int) -> str: 1107d0f982bSMarc-André Lureau return level * 4 * ' ' 1117d0f982bSMarc-André Lureau 1124f7f97a7SJohn Snow if isinstance(obj, Annotated): 11305556960SJohn Snow # NB: _tree_to_qlit is called recursively on the values of a 11405556960SJohn Snow # key:value pair; those values can't be decorated with 11505556960SJohn Snow # comments or conditionals. 11605556960SJohn Snow msg = "dict values cannot have attached comments or if-conditionals." 11705556960SJohn Snow assert not dict_value, msg 11805556960SJohn Snow 1198c643361SEric Blake ret = '' 1204f7f97a7SJohn Snow if obj.comment: 121c0e8d9f3SJohn Snow ret += indent(level) + f"/* {obj.comment} */\n" 12233aa3267SMarc-André Lureau if obj.ifcond.is_present(): 1231889e57aSMarkus Armbruster ret += obj.ifcond.gen_if() 1244f7f97a7SJohn Snow ret += _tree_to_qlit(obj.value, level) 12533aa3267SMarc-André Lureau if obj.ifcond.is_present(): 1261889e57aSMarkus Armbruster ret += '\n' + obj.ifcond.gen_endif() 127d626b6c1SMarc-André Lureau return ret 128d626b6c1SMarc-André Lureau 1297d0f982bSMarc-André Lureau ret = '' 13005556960SJohn Snow if not dict_value: 1317d0f982bSMarc-André Lureau ret += indent(level) 132c0e8d9f3SJohn Snow 133c0e8d9f3SJohn Snow # Scalars: 134fb0bc835SMarkus Armbruster if obj is None: 1357d0f982bSMarc-André Lureau ret += 'QLIT_QNULL' 136fb0bc835SMarkus Armbruster elif isinstance(obj, str): 137c0e8d9f3SJohn Snow ret += f"QLIT_QSTR({to_c_string(obj)})" 138c0e8d9f3SJohn Snow elif isinstance(obj, bool): 139c0e8d9f3SJohn Snow ret += f"QLIT_QBOOL({str(obj).lower()})" 140c0e8d9f3SJohn Snow 141c0e8d9f3SJohn Snow # Non-scalars: 142fb0bc835SMarkus Armbruster elif isinstance(obj, list): 1437d0f982bSMarc-André Lureau ret += 'QLIT_QLIST(((QLitObject[]) {\n' 144c0e8d9f3SJohn Snow for value in obj: 145c0e8d9f3SJohn Snow ret += _tree_to_qlit(value, level + 1).strip('\n') + '\n' 146c0e8d9f3SJohn Snow ret += indent(level + 1) + '{}\n' 1477d0f982bSMarc-André Lureau ret += indent(level) + '}))' 148fb0bc835SMarkus Armbruster elif isinstance(obj, dict): 1497d0f982bSMarc-André Lureau ret += 'QLIT_QDICT(((QLitDictEntry[]) {\n' 150c0e8d9f3SJohn Snow for key, value in sorted(obj.items()): 151c0e8d9f3SJohn Snow ret += indent(level + 1) + "{{ {:s}, {:s} }},\n".format( 152c0e8d9f3SJohn Snow to_c_string(key), 153c0e8d9f3SJohn Snow _tree_to_qlit(value, level + 1, dict_value=True) 154c0e8d9f3SJohn Snow ) 155c0e8d9f3SJohn Snow ret += indent(level + 1) + '{}\n' 1567d0f982bSMarc-André Lureau ret += indent(level) + '}))' 157fb0bc835SMarkus Armbruster else: 1582a6c161bSJohn Snow raise NotImplementedError( 1592a6c161bSJohn Snow f"type '{type(obj).__name__}' not implemented" 1602a6c161bSJohn Snow ) 161c0e8d9f3SJohn Snow 16240bb1376SMarc-André Lureau if level > 0: 16340bb1376SMarc-André Lureau ret += ',' 164fb0bc835SMarkus Armbruster return ret 165fb0bc835SMarkus Armbruster 166fb0bc835SMarkus Armbruster 16782b52f6bSJohn Snowdef to_c_string(string: str) -> str: 168fb0bc835SMarkus Armbruster return '"' + string.replace('\\', r'\\').replace('"', r'\"') + '"' 169fb0bc835SMarkus Armbruster 170fb0bc835SMarkus Armbruster 17171b3f045SMarkus Armbrusterclass QAPISchemaGenIntrospectVisitor(QAPISchemaMonolithicCVisitor): 172fb0bc835SMarkus Armbruster 17382b52f6bSJohn Snow def __init__(self, prefix: str, unmask: bool): 1742cae67bcSMarkus Armbruster super().__init__( 1752cae67bcSMarkus Armbruster prefix, 'qapi-introspect', 17671b3f045SMarkus Armbruster ' * QAPI/QMP schema introspection', __doc__) 17771b3f045SMarkus Armbruster self._unmask = unmask 17882b52f6bSJohn Snow self._schema: Optional[QAPISchema] = None 17982b52f6bSJohn Snow self._trees: List[Annotated[SchemaInfo]] = [] 18082b52f6bSJohn Snow self._used_types: List[QAPISchemaType] = [] 18182b52f6bSJohn Snow self._name_map: Dict[str, str] = {} 18271b3f045SMarkus Armbruster self._genc.add(mcgen(''' 18371b3f045SMarkus Armbruster#include "qemu/osdep.h" 184eb815e24SMarkus Armbruster#include "%(prefix)sqapi-introspect.h" 18571b3f045SMarkus Armbruster 18671b3f045SMarkus Armbruster''', 18771b3f045SMarkus Armbruster prefix=prefix)) 18871b3f045SMarkus Armbruster 18982b52f6bSJohn Snow def visit_begin(self, schema: QAPISchema) -> None: 19071b3f045SMarkus Armbruster self._schema = schema 191fb0bc835SMarkus Armbruster 19282b52f6bSJohn Snow def visit_end(self) -> None: 193fb0bc835SMarkus Armbruster # visit the types that are actually used 194fb0bc835SMarkus Armbruster for typ in self._used_types: 195fb0bc835SMarkus Armbruster typ.visit(self) 196fb0bc835SMarkus Armbruster # generate C 1977d0f982bSMarc-André Lureau name = c_name(self._prefix, protect=False) + 'qmp_schema_qlit' 19871b3f045SMarkus Armbruster self._genh.add(mcgen(''' 1997d0f982bSMarc-André Lureau#include "qapi/qmp/qlit.h" 2007d0f982bSMarc-André Lureau 2017d0f982bSMarc-André Lureauextern const QLitObject %(c_name)s; 202fb0bc835SMarkus Armbruster''', 20371b3f045SMarkus Armbruster c_name=c_name(name))) 20471b3f045SMarkus Armbruster self._genc.add(mcgen(''' 2057d0f982bSMarc-André Lureauconst QLitObject %(c_name)s = %(c_string)s; 206fb0bc835SMarkus Armbruster''', 207fb0bc835SMarkus Armbruster c_name=c_name(name), 2082e8a843dSMarkus Armbruster c_string=_tree_to_qlit(self._trees))) 209fb0bc835SMarkus Armbruster self._schema = None 2102e8a843dSMarkus Armbruster self._trees = [] 21171b3f045SMarkus Armbruster self._used_types = [] 21271b3f045SMarkus Armbruster self._name_map = {} 213fb0bc835SMarkus Armbruster 21482b52f6bSJohn Snow def visit_needed(self, entity: QAPISchemaEntity) -> bool: 215fb0bc835SMarkus Armbruster # Ignore types on first pass; visit_end() will pick up used types 216fb0bc835SMarkus Armbruster return not isinstance(entity, QAPISchemaType) 217fb0bc835SMarkus Armbruster 21882b52f6bSJohn Snow def _name(self, name: str) -> str: 219fb0bc835SMarkus Armbruster if self._unmask: 220fb0bc835SMarkus Armbruster return name 221fb0bc835SMarkus Armbruster if name not in self._name_map: 222fb0bc835SMarkus Armbruster self._name_map[name] = '%d' % len(self._name_map) 223fb0bc835SMarkus Armbruster return self._name_map[name] 224fb0bc835SMarkus Armbruster 22582b52f6bSJohn Snow def _use_type(self, typ: QAPISchemaType) -> str: 2266b67bcacSJohn Snow assert self._schema is not None 2276b67bcacSJohn Snow 228fb0bc835SMarkus Armbruster # Map the various integer types to plain int 229fb0bc835SMarkus Armbruster if typ.json_type() == 'int': 230*7191400aSMarkus Armbruster type_int = self._schema.lookup_type('int') 231*7191400aSMarkus Armbruster assert type_int 232*7191400aSMarkus Armbruster typ = type_int 233fb0bc835SMarkus Armbruster elif (isinstance(typ, QAPISchemaArrayType) and 234fb0bc835SMarkus Armbruster typ.element_type.json_type() == 'int'): 235*7191400aSMarkus Armbruster type_intList = self._schema.lookup_type('intList') 236*7191400aSMarkus Armbruster assert type_intList 237*7191400aSMarkus Armbruster typ = type_intList 238fb0bc835SMarkus Armbruster # Add type to work queue if new 239fb0bc835SMarkus Armbruster if typ not in self._used_types: 240fb0bc835SMarkus Armbruster self._used_types.append(typ) 241fb0bc835SMarkus Armbruster # Clients should examine commands and events, not types. Hide 2421aa806ccSEric Blake # type names as integers to reduce the temptation. Also, it 2431aa806ccSEric Blake # saves a few characters on the wire. 244fb0bc835SMarkus Armbruster if isinstance(typ, QAPISchemaBuiltinType): 245fb0bc835SMarkus Armbruster return typ.name 246fb0bc835SMarkus Armbruster if isinstance(typ, QAPISchemaArrayType): 247fb0bc835SMarkus Armbruster return '[' + self._use_type(typ.element_type) + ']' 248fb0bc835SMarkus Armbruster return self._name(typ.name) 249fb0bc835SMarkus Armbruster 25084bece7dSJohn Snow @staticmethod 251cea53c31SJohn Snow def _gen_features(features: Sequence[QAPISchemaFeature] 25282b52f6bSJohn Snow ) -> List[Annotated[str]]: 2534f7f97a7SJohn Snow return [Annotated(f.name, f.ifcond) for f in features] 25484bece7dSJohn Snow 25582b52f6bSJohn Snow def _gen_tree(self, name: str, mtype: str, obj: Dict[str, object], 256f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond = QAPISchemaIfCond(), 257cea53c31SJohn Snow features: Sequence[QAPISchemaFeature] = ()) -> None: 2585444dedfSJohn Snow """ 2595444dedfSJohn Snow Build and append a SchemaInfo object to self._trees. 2605444dedfSJohn Snow 2615444dedfSJohn Snow :param name: The SchemaInfo's name. 2625444dedfSJohn Snow :param mtype: The SchemaInfo's meta-type. 2635444dedfSJohn Snow :param obj: Additional SchemaInfo members, as appropriate for 2645444dedfSJohn Snow the meta-type. 2655444dedfSJohn Snow :param ifcond: Conditionals to apply to the SchemaInfo. 2665444dedfSJohn Snow :param features: The SchemaInfo's features. 2675444dedfSJohn Snow Will be omitted from the output if empty. 2685444dedfSJohn Snow """ 2695f50cedeSJohn Snow comment: Optional[str] = None 270fb0bc835SMarkus Armbruster if mtype not in ('command', 'event', 'builtin', 'array'): 2718c643361SEric Blake if not self._unmask: 2728c643361SEric Blake # Output a comment to make it easy to map masked names 2738c643361SEric Blake # back to the source when reading the generated output. 2745f50cedeSJohn Snow comment = f'"{self._name(name)}" = {name}' 275fb0bc835SMarkus Armbruster name = self._name(name) 276fb0bc835SMarkus Armbruster obj['name'] = name 277fb0bc835SMarkus Armbruster obj['meta-type'] = mtype 27884bece7dSJohn Snow if features: 27984bece7dSJohn Snow obj['features'] = self._gen_features(features) 2804f7f97a7SJohn Snow self._trees.append(Annotated(obj, ifcond, comment)) 281fb0bc835SMarkus Armbruster 282b6c18755SMarkus Armbruster def _gen_enum_member(self, member: QAPISchemaEnumMember 28375ecee72SMarkus Armbruster ) -> Annotated[SchemaInfoEnumMember]: 28475ecee72SMarkus Armbruster obj: SchemaInfoEnumMember = { 28575ecee72SMarkus Armbruster 'name': member.name, 28675ecee72SMarkus Armbruster } 287b6c18755SMarkus Armbruster if member.features: 288b6c18755SMarkus Armbruster obj['features'] = self._gen_features(member.features) 28975ecee72SMarkus Armbruster return Annotated(obj, member.ifcond) 29075ecee72SMarkus Armbruster 29175ecee72SMarkus Armbruster def _gen_object_member(self, member: QAPISchemaObjectTypeMember 29282b52f6bSJohn Snow ) -> Annotated[SchemaInfoObjectMember]: 29382b52f6bSJohn Snow obj: SchemaInfoObjectMember = { 29482b52f6bSJohn Snow 'name': member.name, 29582b52f6bSJohn Snow 'type': self._use_type(member.type) 29682b52f6bSJohn Snow } 297fb0bc835SMarkus Armbruster if member.optional: 29824cfd6adSMarkus Armbruster obj['default'] = None 29984bece7dSJohn Snow if member.features: 30084bece7dSJohn Snow obj['features'] = self._gen_features(member.features) 3014f7f97a7SJohn Snow return Annotated(obj, member.ifcond) 302fb0bc835SMarkus Armbruster 30382b52f6bSJohn Snow def _gen_variant(self, variant: QAPISchemaVariant 30482b52f6bSJohn Snow ) -> Annotated[SchemaInfoObjectVariant]: 30582b52f6bSJohn Snow obj: SchemaInfoObjectVariant = { 30682b52f6bSJohn Snow 'case': variant.name, 30782b52f6bSJohn Snow 'type': self._use_type(variant.type) 30882b52f6bSJohn Snow } 3094f7f97a7SJohn Snow return Annotated(obj, variant.ifcond) 310fb0bc835SMarkus Armbruster 31182b52f6bSJohn Snow def visit_builtin_type(self, name: str, info: Optional[QAPISourceInfo], 31282b52f6bSJohn Snow json_type: str) -> None: 3139b77d946SJohn Snow self._gen_tree(name, 'builtin', {'json-type': json_type}) 314fb0bc835SMarkus Armbruster 31582b52f6bSJohn Snow def visit_enum_type(self, name: str, info: Optional[QAPISourceInfo], 316f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 31782b52f6bSJohn Snow features: List[QAPISchemaFeature], 31882b52f6bSJohn Snow members: List[QAPISchemaEnumMember], 31982b52f6bSJohn Snow prefix: Optional[str]) -> None: 3204f7f97a7SJohn Snow self._gen_tree( 3214f7f97a7SJohn Snow name, 'enum', 32275ecee72SMarkus Armbruster {'members': [self._gen_enum_member(m) for m in members], 32375ecee72SMarkus Armbruster 'values': [Annotated(m.name, m.ifcond) for m in members]}, 3244f7f97a7SJohn Snow ifcond, features 3254f7f97a7SJohn Snow ) 326fb0bc835SMarkus Armbruster 32782b52f6bSJohn Snow def visit_array_type(self, name: str, info: Optional[QAPISourceInfo], 328f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 32982b52f6bSJohn Snow element_type: QAPISchemaType) -> None: 330fb0bc835SMarkus Armbruster element = self._use_type(element_type) 3312e8a843dSMarkus Armbruster self._gen_tree('[' + element + ']', 'array', {'element-type': element}, 332cea53c31SJohn Snow ifcond) 333fb0bc835SMarkus Armbruster 33482b52f6bSJohn Snow def visit_object_type_flat(self, name: str, info: Optional[QAPISourceInfo], 335f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 33682b52f6bSJohn Snow features: List[QAPISchemaFeature], 33782b52f6bSJohn Snow members: List[QAPISchemaObjectTypeMember], 33882b52f6bSJohn Snow variants: Optional[QAPISchemaVariants]) -> None: 33982b52f6bSJohn Snow obj: SchemaInfoObject = { 34075ecee72SMarkus Armbruster 'members': [self._gen_object_member(m) for m in members] 34182b52f6bSJohn Snow } 342fb0bc835SMarkus Armbruster if variants: 343cf5db214SJohn Snow obj['tag'] = variants.tag_member.name 344cf5db214SJohn Snow obj['variants'] = [self._gen_variant(v) for v in variants.variants] 3452e8a843dSMarkus Armbruster self._gen_tree(name, 'object', obj, ifcond, features) 346fb0bc835SMarkus Armbruster 34782b52f6bSJohn Snow def visit_alternate_type(self, name: str, info: Optional[QAPISourceInfo], 348f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 34982b52f6bSJohn Snow features: List[QAPISchemaFeature], 35082b52f6bSJohn Snow variants: QAPISchemaVariants) -> None: 3514f7f97a7SJohn Snow self._gen_tree( 3524f7f97a7SJohn Snow name, 'alternate', 3534f7f97a7SJohn Snow {'members': [Annotated({'type': self._use_type(m.type)}, 3544f7f97a7SJohn Snow m.ifcond) 355013b4efcSMarkus Armbruster for m in variants.variants]}, 3564f7f97a7SJohn Snow ifcond, features 3574f7f97a7SJohn Snow ) 358fb0bc835SMarkus Armbruster 35982b52f6bSJohn Snow def visit_command(self, name: str, info: Optional[QAPISourceInfo], 360f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 36182b52f6bSJohn Snow features: List[QAPISchemaFeature], 36282b52f6bSJohn Snow arg_type: Optional[QAPISchemaObjectType], 36382b52f6bSJohn Snow ret_type: Optional[QAPISchemaType], gen: bool, 36482b52f6bSJohn Snow success_response: bool, boxed: bool, allow_oob: bool, 36582b52f6bSJohn Snow allow_preconfig: bool, coroutine: bool) -> None: 3666b67bcacSJohn Snow assert self._schema is not None 3676b67bcacSJohn Snow 368fb0bc835SMarkus Armbruster arg_type = arg_type or self._schema.the_empty_object_type 369fb0bc835SMarkus Armbruster ret_type = ret_type or self._schema.the_empty_object_type 37082b52f6bSJohn Snow obj: SchemaInfoCommand = { 37182b52f6bSJohn Snow 'arg-type': self._use_type(arg_type), 37282b52f6bSJohn Snow 'ret-type': self._use_type(ret_type) 37382b52f6bSJohn Snow } 37425b1ef31SMarkus Armbruster if allow_oob: 37525b1ef31SMarkus Armbruster obj['allow-oob'] = allow_oob 3762e8a843dSMarkus Armbruster self._gen_tree(name, 'command', obj, ifcond, features) 37723394b4cSPeter Krempa 37882b52f6bSJohn Snow def visit_event(self, name: str, info: Optional[QAPISourceInfo], 379f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 380f17539c8SMarc-André Lureau features: List[QAPISchemaFeature], 38182b52f6bSJohn Snow arg_type: Optional[QAPISchemaObjectType], 38282b52f6bSJohn Snow boxed: bool) -> None: 3836b67bcacSJohn Snow assert self._schema is not None 38482b52f6bSJohn Snow 385fb0bc835SMarkus Armbruster arg_type = arg_type or self._schema.the_empty_object_type 3862e8a843dSMarkus Armbruster self._gen_tree(name, 'event', {'arg-type': self._use_type(arg_type)}, 387013b4efcSMarkus Armbruster ifcond, features) 388fb0bc835SMarkus Armbruster 389fb0bc835SMarkus Armbruster 39082b52f6bSJohn Snowdef gen_introspect(schema: QAPISchema, output_dir: str, prefix: str, 39182b52f6bSJohn Snow opt_unmask: bool) -> None: 392fb0bc835SMarkus Armbruster vis = QAPISchemaGenIntrospectVisitor(prefix, opt_unmask) 393fb0bc835SMarkus Armbruster schema.visit(vis) 39471b3f045SMarkus Armbruster vis.write(output_dir) 395