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, 291d067e39SMarkus Armbruster QAPISchemaAlternatives, 301d067e39SMarkus Armbruster QAPISchemaBranches, 3167fea575SJohn Snow QAPISchemaArrayType, 3267fea575SJohn Snow QAPISchemaBuiltinType, 3382b52f6bSJohn Snow QAPISchemaEntity, 3482b52f6bSJohn Snow QAPISchemaEnumMember, 3582b52f6bSJohn Snow QAPISchemaFeature, 36f17539c8SMarc-André Lureau QAPISchemaIfCond, 3782b52f6bSJohn Snow QAPISchemaObjectType, 3882b52f6bSJohn Snow QAPISchemaObjectTypeMember, 3967fea575SJohn Snow QAPISchemaType, 4082b52f6bSJohn Snow QAPISchemaVariant, 4167fea575SJohn Snow) 4282b52f6bSJohn Snowfrom .source import QAPISourceInfo 43fb0bc835SMarkus Armbruster 44fb0bc835SMarkus Armbruster 459db27346SJohn Snow# This module constructs a tree data structure that is used to 469db27346SJohn Snow# generate the introspection information for QEMU. It is shaped 479db27346SJohn Snow# like a JSON value. 489db27346SJohn Snow# 499db27346SJohn Snow# A complexity over JSON is that our values may or may not be annotated. 509db27346SJohn Snow# 519db27346SJohn Snow# Un-annotated values may be: 529db27346SJohn Snow# Scalar: str, bool, None. 539db27346SJohn Snow# Non-scalar: List, Dict 549db27346SJohn Snow# _value = Union[str, bool, None, Dict[str, JSONValue], List[JSONValue]] 559db27346SJohn Snow# 569db27346SJohn Snow# With optional annotations, the type of all values is: 579db27346SJohn Snow# JSONValue = Union[_Value, Annotated[_Value]] 589db27346SJohn Snow# 599db27346SJohn Snow# Sadly, mypy does not support recursive types; so the _Stub alias is used to 609db27346SJohn Snow# mark the imprecision in the type model where we'd otherwise use JSONValue. 619db27346SJohn Snow_Stub = Any 629db27346SJohn Snow_Scalar = Union[str, bool, None] 639db27346SJohn Snow_NonScalar = Union[Dict[str, _Stub], List[_Stub]] 649db27346SJohn Snow_Value = Union[_Scalar, _NonScalar] 654f7f97a7SJohn SnowJSONValue = Union[_Value, 'Annotated[_Value]'] 669db27346SJohn Snow 6782b52f6bSJohn Snow# These types are based on structures defined in QEMU's schema, so we 6882b52f6bSJohn Snow# lack precise types for them here. Python 3.6 does not offer 6982b52f6bSJohn Snow# TypedDict constructs, so they are broadly typed here as simple 7082b52f6bSJohn Snow# Python Dicts. 7182b52f6bSJohn SnowSchemaInfo = Dict[str, object] 7275ecee72SMarkus ArmbrusterSchemaInfoEnumMember = Dict[str, object] 7382b52f6bSJohn SnowSchemaInfoObject = Dict[str, object] 7482b52f6bSJohn SnowSchemaInfoObjectVariant = Dict[str, object] 7582b52f6bSJohn SnowSchemaInfoObjectMember = Dict[str, object] 7682b52f6bSJohn SnowSchemaInfoCommand = Dict[str, object] 7782b52f6bSJohn Snow 789db27346SJohn Snow 794f7f97a7SJohn Snow_ValueT = TypeVar('_ValueT', bound=_Value) 804f7f97a7SJohn Snow 814f7f97a7SJohn Snow 824f7f97a7SJohn Snowclass Annotated(Generic[_ValueT]): 834f7f97a7SJohn Snow """ 844f7f97a7SJohn Snow Annotated generally contains a SchemaInfo-like type (as a dict), 854f7f97a7SJohn Snow But it also used to wrap comments/ifconds around scalar leaf values, 864f7f97a7SJohn Snow for the benefit of features and enums. 874f7f97a7SJohn Snow """ 884f7f97a7SJohn Snow # TODO: Remove after Python 3.7 adds @dataclass: 894f7f97a7SJohn Snow # pylint: disable=too-few-public-methods 90f17539c8SMarc-André Lureau def __init__(self, value: _ValueT, ifcond: QAPISchemaIfCond, 914f7f97a7SJohn Snow comment: Optional[str] = None): 924f7f97a7SJohn Snow self.value = value 934f7f97a7SJohn Snow self.comment: Optional[str] = comment 94f17539c8SMarc-André Lureau self.ifcond = ifcond 9524cfd6adSMarkus Armbruster 9624cfd6adSMarkus Armbruster 9782b52f6bSJohn Snowdef _tree_to_qlit(obj: JSONValue, 9882b52f6bSJohn Snow level: int = 0, 9982b52f6bSJohn Snow dict_value: bool = False) -> str: 1005444dedfSJohn Snow """ 1015444dedfSJohn Snow Convert the type tree into a QLIT C string, recursively. 1025444dedfSJohn Snow 1035444dedfSJohn Snow :param obj: The value to convert. 1045444dedfSJohn Snow This value may not be Annotated when dict_value is True. 1055444dedfSJohn Snow :param level: The indentation level for this particular value. 1065444dedfSJohn Snow :param dict_value: True when the value being processed belongs to a 1075444dedfSJohn Snow dict key; which suppresses the output indent. 1085444dedfSJohn Snow """ 1097d0f982bSMarc-André Lureau 11082b52f6bSJohn Snow def indent(level: int) -> str: 1117d0f982bSMarc-André Lureau return level * 4 * ' ' 1127d0f982bSMarc-André Lureau 1134f7f97a7SJohn Snow if isinstance(obj, Annotated): 11405556960SJohn Snow # NB: _tree_to_qlit is called recursively on the values of a 11505556960SJohn Snow # key:value pair; those values can't be decorated with 11605556960SJohn Snow # comments or conditionals. 11705556960SJohn Snow msg = "dict values cannot have attached comments or if-conditionals." 11805556960SJohn Snow assert not dict_value, msg 11905556960SJohn Snow 1208c643361SEric Blake ret = '' 1214f7f97a7SJohn Snow if obj.comment: 122c0e8d9f3SJohn Snow ret += indent(level) + f"/* {obj.comment} */\n" 12333aa3267SMarc-André Lureau if obj.ifcond.is_present(): 1241889e57aSMarkus Armbruster ret += obj.ifcond.gen_if() 1254f7f97a7SJohn Snow ret += _tree_to_qlit(obj.value, level) 12633aa3267SMarc-André Lureau if obj.ifcond.is_present(): 1271889e57aSMarkus Armbruster ret += '\n' + obj.ifcond.gen_endif() 128d626b6c1SMarc-André Lureau return ret 129d626b6c1SMarc-André Lureau 1307d0f982bSMarc-André Lureau ret = '' 13105556960SJohn Snow if not dict_value: 1327d0f982bSMarc-André Lureau ret += indent(level) 133c0e8d9f3SJohn Snow 134c0e8d9f3SJohn Snow # Scalars: 135fb0bc835SMarkus Armbruster if obj is None: 1367d0f982bSMarc-André Lureau ret += 'QLIT_QNULL' 137fb0bc835SMarkus Armbruster elif isinstance(obj, str): 138c0e8d9f3SJohn Snow ret += f"QLIT_QSTR({to_c_string(obj)})" 139c0e8d9f3SJohn Snow elif isinstance(obj, bool): 140c0e8d9f3SJohn Snow ret += f"QLIT_QBOOL({str(obj).lower()})" 141c0e8d9f3SJohn Snow 142c0e8d9f3SJohn Snow # Non-scalars: 143fb0bc835SMarkus Armbruster elif isinstance(obj, list): 1447d0f982bSMarc-André Lureau ret += 'QLIT_QLIST(((QLitObject[]) {\n' 145c0e8d9f3SJohn Snow for value in obj: 146c0e8d9f3SJohn Snow ret += _tree_to_qlit(value, level + 1).strip('\n') + '\n' 147c0e8d9f3SJohn Snow ret += indent(level + 1) + '{}\n' 1487d0f982bSMarc-André Lureau ret += indent(level) + '}))' 149fb0bc835SMarkus Armbruster elif isinstance(obj, dict): 1507d0f982bSMarc-André Lureau ret += 'QLIT_QDICT(((QLitDictEntry[]) {\n' 151c0e8d9f3SJohn Snow for key, value in sorted(obj.items()): 152c0e8d9f3SJohn Snow ret += indent(level + 1) + "{{ {:s}, {:s} }},\n".format( 153c0e8d9f3SJohn Snow to_c_string(key), 154c0e8d9f3SJohn Snow _tree_to_qlit(value, level + 1, dict_value=True) 155c0e8d9f3SJohn Snow ) 156c0e8d9f3SJohn Snow ret += indent(level + 1) + '{}\n' 1577d0f982bSMarc-André Lureau ret += indent(level) + '}))' 158fb0bc835SMarkus Armbruster else: 1592a6c161bSJohn Snow raise NotImplementedError( 1602a6c161bSJohn Snow f"type '{type(obj).__name__}' not implemented" 1612a6c161bSJohn Snow ) 162c0e8d9f3SJohn Snow 16340bb1376SMarc-André Lureau if level > 0: 16440bb1376SMarc-André Lureau ret += ',' 165fb0bc835SMarkus Armbruster return ret 166fb0bc835SMarkus Armbruster 167fb0bc835SMarkus Armbruster 16882b52f6bSJohn Snowdef to_c_string(string: str) -> str: 169fb0bc835SMarkus Armbruster return '"' + string.replace('\\', r'\\').replace('"', r'\"') + '"' 170fb0bc835SMarkus Armbruster 171fb0bc835SMarkus Armbruster 17271b3f045SMarkus Armbrusterclass QAPISchemaGenIntrospectVisitor(QAPISchemaMonolithicCVisitor): 173fb0bc835SMarkus Armbruster 17482b52f6bSJohn Snow def __init__(self, prefix: str, unmask: bool): 1752cae67bcSMarkus Armbruster super().__init__( 1762cae67bcSMarkus Armbruster prefix, 'qapi-introspect', 17771b3f045SMarkus Armbruster ' * QAPI/QMP schema introspection', __doc__) 17871b3f045SMarkus Armbruster self._unmask = unmask 17982b52f6bSJohn Snow self._schema: Optional[QAPISchema] = None 18082b52f6bSJohn Snow self._trees: List[Annotated[SchemaInfo]] = [] 18182b52f6bSJohn Snow self._used_types: List[QAPISchemaType] = [] 18282b52f6bSJohn Snow self._name_map: Dict[str, str] = {} 18371b3f045SMarkus Armbruster self._genc.add(mcgen(''' 18471b3f045SMarkus Armbruster#include "qemu/osdep.h" 185eb815e24SMarkus Armbruster#include "%(prefix)sqapi-introspect.h" 18671b3f045SMarkus Armbruster 18771b3f045SMarkus Armbruster''', 18871b3f045SMarkus Armbruster prefix=prefix)) 18971b3f045SMarkus Armbruster 19082b52f6bSJohn Snow def visit_begin(self, schema: QAPISchema) -> None: 19171b3f045SMarkus Armbruster self._schema = schema 192fb0bc835SMarkus Armbruster 19382b52f6bSJohn Snow def visit_end(self) -> None: 194fb0bc835SMarkus Armbruster # visit the types that are actually used 195fb0bc835SMarkus Armbruster for typ in self._used_types: 196fb0bc835SMarkus Armbruster typ.visit(self) 197fb0bc835SMarkus Armbruster # generate C 1987d0f982bSMarc-André Lureau name = c_name(self._prefix, protect=False) + 'qmp_schema_qlit' 19971b3f045SMarkus Armbruster self._genh.add(mcgen(''' 2007d0f982bSMarc-André Lureau#include "qapi/qmp/qlit.h" 2017d0f982bSMarc-André Lureau 2027d0f982bSMarc-André Lureauextern const QLitObject %(c_name)s; 203fb0bc835SMarkus Armbruster''', 20471b3f045SMarkus Armbruster c_name=c_name(name))) 20571b3f045SMarkus Armbruster self._genc.add(mcgen(''' 2067d0f982bSMarc-André Lureauconst QLitObject %(c_name)s = %(c_string)s; 207fb0bc835SMarkus Armbruster''', 208fb0bc835SMarkus Armbruster c_name=c_name(name), 2092e8a843dSMarkus Armbruster c_string=_tree_to_qlit(self._trees))) 210fb0bc835SMarkus Armbruster self._schema = None 2112e8a843dSMarkus Armbruster self._trees = [] 21271b3f045SMarkus Armbruster self._used_types = [] 21371b3f045SMarkus Armbruster self._name_map = {} 214fb0bc835SMarkus Armbruster 21582b52f6bSJohn Snow def visit_needed(self, entity: QAPISchemaEntity) -> bool: 216fb0bc835SMarkus Armbruster # Ignore types on first pass; visit_end() will pick up used types 217fb0bc835SMarkus Armbruster return not isinstance(entity, QAPISchemaType) 218fb0bc835SMarkus Armbruster 21982b52f6bSJohn Snow def _name(self, name: str) -> str: 220fb0bc835SMarkus Armbruster if self._unmask: 221fb0bc835SMarkus Armbruster return name 222fb0bc835SMarkus Armbruster if name not in self._name_map: 223fb0bc835SMarkus Armbruster self._name_map[name] = '%d' % len(self._name_map) 224fb0bc835SMarkus Armbruster return self._name_map[name] 225fb0bc835SMarkus Armbruster 22682b52f6bSJohn Snow def _use_type(self, typ: QAPISchemaType) -> str: 2276b67bcacSJohn Snow assert self._schema is not None 2286b67bcacSJohn Snow 229fb0bc835SMarkus Armbruster # Map the various integer types to plain int 230fb0bc835SMarkus Armbruster if typ.json_type() == 'int': 2317191400aSMarkus Armbruster type_int = self._schema.lookup_type('int') 2327191400aSMarkus Armbruster assert type_int 2337191400aSMarkus Armbruster typ = type_int 234fb0bc835SMarkus Armbruster elif (isinstance(typ, QAPISchemaArrayType) and 235fb0bc835SMarkus Armbruster typ.element_type.json_type() == 'int'): 2367191400aSMarkus Armbruster type_intList = self._schema.lookup_type('intList') 2377191400aSMarkus Armbruster assert type_intList 2387191400aSMarkus Armbruster typ = type_intList 239fb0bc835SMarkus Armbruster # Add type to work queue if new 240fb0bc835SMarkus Armbruster if typ not in self._used_types: 241fb0bc835SMarkus Armbruster self._used_types.append(typ) 242fb0bc835SMarkus Armbruster # Clients should examine commands and events, not types. Hide 2431aa806ccSEric Blake # type names as integers to reduce the temptation. Also, it 2441aa806ccSEric Blake # saves a few characters on the wire. 245fb0bc835SMarkus Armbruster if isinstance(typ, QAPISchemaBuiltinType): 246fb0bc835SMarkus Armbruster return typ.name 247fb0bc835SMarkus Armbruster if isinstance(typ, QAPISchemaArrayType): 248fb0bc835SMarkus Armbruster return '[' + self._use_type(typ.element_type) + ']' 249fb0bc835SMarkus Armbruster return self._name(typ.name) 250fb0bc835SMarkus Armbruster 25184bece7dSJohn Snow @staticmethod 252cea53c31SJohn Snow def _gen_features(features: Sequence[QAPISchemaFeature] 25382b52f6bSJohn Snow ) -> List[Annotated[str]]: 2544f7f97a7SJohn Snow return [Annotated(f.name, f.ifcond) for f in features] 25584bece7dSJohn Snow 25682b52f6bSJohn Snow def _gen_tree(self, name: str, mtype: str, obj: Dict[str, object], 257f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond = QAPISchemaIfCond(), 258cea53c31SJohn Snow features: Sequence[QAPISchemaFeature] = ()) -> None: 2595444dedfSJohn Snow """ 2605444dedfSJohn Snow Build and append a SchemaInfo object to self._trees. 2615444dedfSJohn Snow 2625444dedfSJohn Snow :param name: The SchemaInfo's name. 2635444dedfSJohn Snow :param mtype: The SchemaInfo's meta-type. 2645444dedfSJohn Snow :param obj: Additional SchemaInfo members, as appropriate for 2655444dedfSJohn Snow the meta-type. 2665444dedfSJohn Snow :param ifcond: Conditionals to apply to the SchemaInfo. 2675444dedfSJohn Snow :param features: The SchemaInfo's features. 2685444dedfSJohn Snow Will be omitted from the output if empty. 2695444dedfSJohn Snow """ 2705f50cedeSJohn Snow comment: Optional[str] = None 271fb0bc835SMarkus Armbruster if mtype not in ('command', 'event', 'builtin', 'array'): 2728c643361SEric Blake if not self._unmask: 2738c643361SEric Blake # Output a comment to make it easy to map masked names 2748c643361SEric Blake # back to the source when reading the generated output. 2755f50cedeSJohn Snow comment = f'"{self._name(name)}" = {name}' 276fb0bc835SMarkus Armbruster name = self._name(name) 277fb0bc835SMarkus Armbruster obj['name'] = name 278fb0bc835SMarkus Armbruster obj['meta-type'] = mtype 27984bece7dSJohn Snow if features: 28084bece7dSJohn Snow obj['features'] = self._gen_features(features) 2814f7f97a7SJohn Snow self._trees.append(Annotated(obj, ifcond, comment)) 282fb0bc835SMarkus Armbruster 283b6c18755SMarkus Armbruster def _gen_enum_member(self, member: QAPISchemaEnumMember 28475ecee72SMarkus Armbruster ) -> Annotated[SchemaInfoEnumMember]: 28575ecee72SMarkus Armbruster obj: SchemaInfoEnumMember = { 28675ecee72SMarkus Armbruster 'name': member.name, 28775ecee72SMarkus Armbruster } 288b6c18755SMarkus Armbruster if member.features: 289b6c18755SMarkus Armbruster obj['features'] = self._gen_features(member.features) 29075ecee72SMarkus Armbruster return Annotated(obj, member.ifcond) 29175ecee72SMarkus Armbruster 29275ecee72SMarkus Armbruster def _gen_object_member(self, member: QAPISchemaObjectTypeMember 29382b52f6bSJohn Snow ) -> Annotated[SchemaInfoObjectMember]: 29482b52f6bSJohn Snow obj: SchemaInfoObjectMember = { 29582b52f6bSJohn Snow 'name': member.name, 29682b52f6bSJohn Snow 'type': self._use_type(member.type) 29782b52f6bSJohn Snow } 298fb0bc835SMarkus Armbruster if member.optional: 29924cfd6adSMarkus Armbruster obj['default'] = None 30084bece7dSJohn Snow if member.features: 30184bece7dSJohn Snow obj['features'] = self._gen_features(member.features) 3024f7f97a7SJohn Snow return Annotated(obj, member.ifcond) 303fb0bc835SMarkus Armbruster 30482b52f6bSJohn Snow def _gen_variant(self, variant: QAPISchemaVariant 30582b52f6bSJohn Snow ) -> Annotated[SchemaInfoObjectVariant]: 30682b52f6bSJohn Snow obj: SchemaInfoObjectVariant = { 30782b52f6bSJohn Snow 'case': variant.name, 30882b52f6bSJohn Snow 'type': self._use_type(variant.type) 30982b52f6bSJohn Snow } 3104f7f97a7SJohn Snow return Annotated(obj, variant.ifcond) 311fb0bc835SMarkus Armbruster 31282b52f6bSJohn Snow def visit_builtin_type(self, name: str, info: Optional[QAPISourceInfo], 31382b52f6bSJohn Snow json_type: str) -> None: 3149b77d946SJohn Snow self._gen_tree(name, 'builtin', {'json-type': json_type}) 315fb0bc835SMarkus Armbruster 31682b52f6bSJohn Snow def visit_enum_type(self, name: str, info: Optional[QAPISourceInfo], 317f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 31882b52f6bSJohn Snow features: List[QAPISchemaFeature], 31982b52f6bSJohn Snow members: List[QAPISchemaEnumMember], 32082b52f6bSJohn Snow prefix: Optional[str]) -> None: 3214f7f97a7SJohn Snow self._gen_tree( 3224f7f97a7SJohn Snow name, 'enum', 32375ecee72SMarkus Armbruster {'members': [self._gen_enum_member(m) for m in members], 32475ecee72SMarkus Armbruster 'values': [Annotated(m.name, m.ifcond) for m in members]}, 3254f7f97a7SJohn Snow ifcond, features 3264f7f97a7SJohn Snow ) 327fb0bc835SMarkus Armbruster 32882b52f6bSJohn Snow def visit_array_type(self, name: str, info: Optional[QAPISourceInfo], 329f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 33082b52f6bSJohn Snow element_type: QAPISchemaType) -> None: 331fb0bc835SMarkus Armbruster element = self._use_type(element_type) 3322e8a843dSMarkus Armbruster self._gen_tree('[' + element + ']', 'array', {'element-type': element}, 333cea53c31SJohn Snow ifcond) 334fb0bc835SMarkus Armbruster 33582b52f6bSJohn Snow def visit_object_type_flat(self, name: str, info: Optional[QAPISourceInfo], 336f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 33782b52f6bSJohn Snow features: List[QAPISchemaFeature], 33882b52f6bSJohn Snow members: List[QAPISchemaObjectTypeMember], 339d1da8af8SMarkus Armbruster branches: Optional[QAPISchemaBranches]) -> None: 34082b52f6bSJohn Snow obj: SchemaInfoObject = { 34175ecee72SMarkus Armbruster 'members': [self._gen_object_member(m) for m in members] 34282b52f6bSJohn Snow } 343d1da8af8SMarkus Armbruster if branches: 344d1da8af8SMarkus Armbruster obj['tag'] = branches.tag_member.name 345d1da8af8SMarkus Armbruster obj['variants'] = [self._gen_variant(v) for v in branches.variants] 3462e8a843dSMarkus Armbruster self._gen_tree(name, 'object', obj, ifcond, features) 347fb0bc835SMarkus Armbruster 34882b52f6bSJohn Snow def visit_alternate_type(self, name: str, info: Optional[QAPISourceInfo], 349f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 35082b52f6bSJohn Snow features: List[QAPISchemaFeature], 35141d0ad1dSMarkus Armbruster alternatives: QAPISchemaAlternatives) -> None: 3524f7f97a7SJohn Snow self._gen_tree( 3534f7f97a7SJohn Snow name, 'alternate', 3544f7f97a7SJohn Snow {'members': [Annotated({'type': self._use_type(m.type)}, 3554f7f97a7SJohn Snow m.ifcond) 35641d0ad1dSMarkus Armbruster for m in alternatives.variants]}, 3574f7f97a7SJohn Snow ifcond, features 3584f7f97a7SJohn Snow ) 359fb0bc835SMarkus Armbruster 36082b52f6bSJohn Snow def visit_command(self, name: str, info: Optional[QAPISourceInfo], 361f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 36282b52f6bSJohn Snow features: List[QAPISchemaFeature], 36382b52f6bSJohn Snow arg_type: Optional[QAPISchemaObjectType], 36482b52f6bSJohn Snow ret_type: Optional[QAPISchemaType], gen: bool, 36582b52f6bSJohn Snow success_response: bool, boxed: bool, allow_oob: bool, 36682b52f6bSJohn Snow allow_preconfig: bool, coroutine: bool) -> None: 3676b67bcacSJohn Snow assert self._schema is not None 3686b67bcacSJohn Snow 369fb0bc835SMarkus Armbruster arg_type = arg_type or self._schema.the_empty_object_type 370fb0bc835SMarkus Armbruster ret_type = ret_type or self._schema.the_empty_object_type 37182b52f6bSJohn Snow obj: SchemaInfoCommand = { 37282b52f6bSJohn Snow 'arg-type': self._use_type(arg_type), 37382b52f6bSJohn Snow 'ret-type': self._use_type(ret_type) 37482b52f6bSJohn Snow } 37525b1ef31SMarkus Armbruster if allow_oob: 37625b1ef31SMarkus Armbruster obj['allow-oob'] = allow_oob 3772e8a843dSMarkus Armbruster self._gen_tree(name, 'command', obj, ifcond, features) 37823394b4cSPeter Krempa 37982b52f6bSJohn Snow def visit_event(self, name: str, info: Optional[QAPISourceInfo], 380f17539c8SMarc-André Lureau ifcond: QAPISchemaIfCond, 381f17539c8SMarc-André Lureau features: List[QAPISchemaFeature], 38282b52f6bSJohn Snow arg_type: Optional[QAPISchemaObjectType], 38382b52f6bSJohn Snow boxed: bool) -> None: 3846b67bcacSJohn Snow assert self._schema is not None 38582b52f6bSJohn Snow 386fb0bc835SMarkus Armbruster arg_type = arg_type or self._schema.the_empty_object_type 3872e8a843dSMarkus Armbruster self._gen_tree(name, 'event', {'arg-type': self._use_type(arg_type)}, 388013b4efcSMarkus Armbruster ifcond, features) 389fb0bc835SMarkus Armbruster 390fb0bc835SMarkus Armbruster 39182b52f6bSJohn Snowdef gen_introspect(schema: QAPISchema, output_dir: str, prefix: str, 39282b52f6bSJohn Snow opt_unmask: bool) -> None: 393fb0bc835SMarkus Armbruster vis = QAPISchemaGenIntrospectVisitor(prefix, opt_unmask) 394fb0bc835SMarkus Armbruster schema.visit(vis) 39571b3f045SMarkus Armbruster vis.write(output_dir) 396