mirror of
https://github.com/qemu/qemu.git
synced 2025-08-15 05:06:56 +00:00
qapi/parser: add QAPIExpression type
This patch creates a new type, QAPIExpression, which represents a parsed expression complete with QAPIDoc and QAPISourceInfo. This patch turns parser.exprs into a list of QAPIExpression instead, and adjusts expr.py to match. This allows the types we specify in parser.py to be "remembered" all the way through expr.py and into schema.py. Several assertions around packing and unpacking this data can be removed as a result. It also corrects a harmless typing error. Before the patch, check_exprs() allegedly takes a List[_JSONObject]. It actually takes a list of dicts of the form {'expr': E, 'info': I, 'doc': D} where E is of type _ExprValue, I is of type QAPISourceInfo, and D is of type QAPIDoc. Key 'doc' is optional. This is not a _JSONObject! Passes type checking anyway, because _JSONObject is Dict[str, object]. Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20230215000011.1725012-5-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> [Commit message amended to point out the typing fix]
This commit is contained in:
parent
c60caf8086
commit
420110591c
@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
from .common import c_name
|
from .common import c_name
|
||||||
from .error import QAPISemError
|
from .error import QAPISemError
|
||||||
from .parser import QAPIDoc
|
from .parser import QAPIExpression
|
||||||
from .source import QAPISourceInfo
|
from .source import QAPISourceInfo
|
||||||
|
|
||||||
|
|
||||||
@ -228,12 +228,11 @@ def pprint(elems: Iterable[str]) -> str:
|
|||||||
pprint(unknown), pprint(allowed)))
|
pprint(unknown), pprint(allowed)))
|
||||||
|
|
||||||
|
|
||||||
def check_flags(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
def check_flags(expr: QAPIExpression) -> None:
|
||||||
"""
|
"""
|
||||||
Ensure flag members (if present) have valid values.
|
Ensure flag members (if present) have valid values.
|
||||||
|
|
||||||
:param expr: The expression to validate.
|
:param expr: The expression to validate.
|
||||||
:param info: QAPI schema source file information.
|
|
||||||
|
|
||||||
:raise QAPISemError:
|
:raise QAPISemError:
|
||||||
When certain flags have an invalid value, or when
|
When certain flags have an invalid value, or when
|
||||||
@ -242,18 +241,18 @@ def check_flags(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
|||||||
for key in ('gen', 'success-response'):
|
for key in ('gen', 'success-response'):
|
||||||
if key in expr and expr[key] is not False:
|
if key in expr and expr[key] is not False:
|
||||||
raise QAPISemError(
|
raise QAPISemError(
|
||||||
info, "flag '%s' may only use false value" % key)
|
expr.info, "flag '%s' may only use false value" % key)
|
||||||
for key in ('boxed', 'allow-oob', 'allow-preconfig', 'coroutine'):
|
for key in ('boxed', 'allow-oob', 'allow-preconfig', 'coroutine'):
|
||||||
if key in expr and expr[key] is not True:
|
if key in expr and expr[key] is not True:
|
||||||
raise QAPISemError(
|
raise QAPISemError(
|
||||||
info, "flag '%s' may only use true value" % key)
|
expr.info, "flag '%s' may only use true value" % key)
|
||||||
if 'allow-oob' in expr and 'coroutine' in expr:
|
if 'allow-oob' in expr and 'coroutine' in expr:
|
||||||
# This is not necessarily a fundamental incompatibility, but
|
# This is not necessarily a fundamental incompatibility, but
|
||||||
# we don't have a use case and the desired semantics isn't
|
# we don't have a use case and the desired semantics isn't
|
||||||
# obvious. The simplest solution is to forbid it until we get
|
# obvious. The simplest solution is to forbid it until we get
|
||||||
# a use case for it.
|
# a use case for it.
|
||||||
raise QAPISemError(info, "flags 'allow-oob' and 'coroutine' "
|
raise QAPISemError(
|
||||||
"are incompatible")
|
expr.info, "flags 'allow-oob' and 'coroutine' are incompatible")
|
||||||
|
|
||||||
|
|
||||||
def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None:
|
def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None:
|
||||||
@ -446,12 +445,11 @@ def check_features(features: Optional[object],
|
|||||||
check_if(feat, info, source)
|
check_if(feat, info, source)
|
||||||
|
|
||||||
|
|
||||||
def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
def check_enum(expr: QAPIExpression) -> None:
|
||||||
"""
|
"""
|
||||||
Normalize and validate this expression as an ``enum`` definition.
|
Normalize and validate this expression as an ``enum`` definition.
|
||||||
|
|
||||||
:param expr: The expression to validate.
|
:param expr: The expression to validate.
|
||||||
:param info: QAPI schema source file information.
|
|
||||||
|
|
||||||
:raise QAPISemError: When ``expr`` is not a valid ``enum``.
|
:raise QAPISemError: When ``expr`` is not a valid ``enum``.
|
||||||
:return: None, ``expr`` is normalized in-place as needed.
|
:return: None, ``expr`` is normalized in-place as needed.
|
||||||
@ -459,6 +457,7 @@ def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
|||||||
name = expr['enum']
|
name = expr['enum']
|
||||||
members = expr['data']
|
members = expr['data']
|
||||||
prefix = expr.get('prefix')
|
prefix = expr.get('prefix')
|
||||||
|
info = expr.info
|
||||||
|
|
||||||
if not isinstance(members, list):
|
if not isinstance(members, list):
|
||||||
raise QAPISemError(info, "'data' must be an array")
|
raise QAPISemError(info, "'data' must be an array")
|
||||||
@ -485,12 +484,11 @@ def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
|||||||
check_features(member.get('features'), info)
|
check_features(member.get('features'), info)
|
||||||
|
|
||||||
|
|
||||||
def check_struct(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
def check_struct(expr: QAPIExpression) -> None:
|
||||||
"""
|
"""
|
||||||
Normalize and validate this expression as a ``struct`` definition.
|
Normalize and validate this expression as a ``struct`` definition.
|
||||||
|
|
||||||
:param expr: The expression to validate.
|
:param expr: The expression to validate.
|
||||||
:param info: QAPI schema source file information.
|
|
||||||
|
|
||||||
:raise QAPISemError: When ``expr`` is not a valid ``struct``.
|
:raise QAPISemError: When ``expr`` is not a valid ``struct``.
|
||||||
:return: None, ``expr`` is normalized in-place as needed.
|
:return: None, ``expr`` is normalized in-place as needed.
|
||||||
@ -498,16 +496,15 @@ def check_struct(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
|||||||
name = cast(str, expr['struct']) # Checked in check_exprs
|
name = cast(str, expr['struct']) # Checked in check_exprs
|
||||||
members = expr['data']
|
members = expr['data']
|
||||||
|
|
||||||
check_type(members, info, "'data'", allow_dict=name)
|
check_type(members, expr.info, "'data'", allow_dict=name)
|
||||||
check_type(expr.get('base'), info, "'base'")
|
check_type(expr.get('base'), expr.info, "'base'")
|
||||||
|
|
||||||
|
|
||||||
def check_union(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
def check_union(expr: QAPIExpression) -> None:
|
||||||
"""
|
"""
|
||||||
Normalize and validate this expression as a ``union`` definition.
|
Normalize and validate this expression as a ``union`` definition.
|
||||||
|
|
||||||
:param expr: The expression to validate.
|
:param expr: The expression to validate.
|
||||||
:param info: QAPI schema source file information.
|
|
||||||
|
|
||||||
:raise QAPISemError: when ``expr`` is not a valid ``union``.
|
:raise QAPISemError: when ``expr`` is not a valid ``union``.
|
||||||
:return: None, ``expr`` is normalized in-place as needed.
|
:return: None, ``expr`` is normalized in-place as needed.
|
||||||
@ -516,6 +513,7 @@ def check_union(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
|||||||
base = expr['base']
|
base = expr['base']
|
||||||
discriminator = expr['discriminator']
|
discriminator = expr['discriminator']
|
||||||
members = expr['data']
|
members = expr['data']
|
||||||
|
info = expr.info
|
||||||
|
|
||||||
check_type(base, info, "'base'", allow_dict=name)
|
check_type(base, info, "'base'", allow_dict=name)
|
||||||
check_name_is_str(discriminator, info, "'discriminator'")
|
check_name_is_str(discriminator, info, "'discriminator'")
|
||||||
@ -530,17 +528,17 @@ def check_union(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
|||||||
check_type(value['type'], info, source, allow_array=not base)
|
check_type(value['type'], info, source, allow_array=not base)
|
||||||
|
|
||||||
|
|
||||||
def check_alternate(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
def check_alternate(expr: QAPIExpression) -> None:
|
||||||
"""
|
"""
|
||||||
Normalize and validate this expression as an ``alternate`` definition.
|
Normalize and validate this expression as an ``alternate`` definition.
|
||||||
|
|
||||||
:param expr: The expression to validate.
|
:param expr: The expression to validate.
|
||||||
:param info: QAPI schema source file information.
|
|
||||||
|
|
||||||
:raise QAPISemError: When ``expr`` is not a valid ``alternate``.
|
:raise QAPISemError: When ``expr`` is not a valid ``alternate``.
|
||||||
:return: None, ``expr`` is normalized in-place as needed.
|
:return: None, ``expr`` is normalized in-place as needed.
|
||||||
"""
|
"""
|
||||||
members = expr['data']
|
members = expr['data']
|
||||||
|
info = expr.info
|
||||||
|
|
||||||
if not members:
|
if not members:
|
||||||
raise QAPISemError(info, "'data' must not be empty")
|
raise QAPISemError(info, "'data' must not be empty")
|
||||||
@ -556,12 +554,11 @@ def check_alternate(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
|||||||
check_type(value['type'], info, source, allow_array=True)
|
check_type(value['type'], info, source, allow_array=True)
|
||||||
|
|
||||||
|
|
||||||
def check_command(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
def check_command(expr: QAPIExpression) -> None:
|
||||||
"""
|
"""
|
||||||
Normalize and validate this expression as a ``command`` definition.
|
Normalize and validate this expression as a ``command`` definition.
|
||||||
|
|
||||||
:param expr: The expression to validate.
|
:param expr: The expression to validate.
|
||||||
:param info: QAPI schema source file information.
|
|
||||||
|
|
||||||
:raise QAPISemError: When ``expr`` is not a valid ``command``.
|
:raise QAPISemError: When ``expr`` is not a valid ``command``.
|
||||||
:return: None, ``expr`` is normalized in-place as needed.
|
:return: None, ``expr`` is normalized in-place as needed.
|
||||||
@ -571,17 +568,16 @@ def check_command(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
|||||||
boxed = expr.get('boxed', False)
|
boxed = expr.get('boxed', False)
|
||||||
|
|
||||||
if boxed and args is None:
|
if boxed and args is None:
|
||||||
raise QAPISemError(info, "'boxed': true requires 'data'")
|
raise QAPISemError(expr.info, "'boxed': true requires 'data'")
|
||||||
check_type(args, info, "'data'", allow_dict=not boxed)
|
check_type(args, expr.info, "'data'", allow_dict=not boxed)
|
||||||
check_type(rets, info, "'returns'", allow_array=True)
|
check_type(rets, expr.info, "'returns'", allow_array=True)
|
||||||
|
|
||||||
|
|
||||||
def check_event(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
def check_event(expr: QAPIExpression) -> None:
|
||||||
"""
|
"""
|
||||||
Normalize and validate this expression as an ``event`` definition.
|
Normalize and validate this expression as an ``event`` definition.
|
||||||
|
|
||||||
:param expr: The expression to validate.
|
:param expr: The expression to validate.
|
||||||
:param info: QAPI schema source file information.
|
|
||||||
|
|
||||||
:raise QAPISemError: When ``expr`` is not a valid ``event``.
|
:raise QAPISemError: When ``expr`` is not a valid ``event``.
|
||||||
:return: None, ``expr`` is normalized in-place as needed.
|
:return: None, ``expr`` is normalized in-place as needed.
|
||||||
@ -590,11 +586,11 @@ def check_event(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
|||||||
boxed = expr.get('boxed', False)
|
boxed = expr.get('boxed', False)
|
||||||
|
|
||||||
if boxed and args is None:
|
if boxed and args is None:
|
||||||
raise QAPISemError(info, "'boxed': true requires 'data'")
|
raise QAPISemError(expr.info, "'boxed': true requires 'data'")
|
||||||
check_type(args, info, "'data'", allow_dict=not boxed)
|
check_type(args, expr.info, "'data'", allow_dict=not boxed)
|
||||||
|
|
||||||
|
|
||||||
def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]:
|
def check_exprs(exprs: List[QAPIExpression]) -> List[QAPIExpression]:
|
||||||
"""
|
"""
|
||||||
Validate and normalize a list of parsed QAPI schema expressions.
|
Validate and normalize a list of parsed QAPI schema expressions.
|
||||||
|
|
||||||
@ -606,21 +602,9 @@ def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]:
|
|||||||
:raise QAPISemError: When any expression fails validation.
|
:raise QAPISemError: When any expression fails validation.
|
||||||
:return: The same list of expressions (now modified).
|
:return: The same list of expressions (now modified).
|
||||||
"""
|
"""
|
||||||
for expr_elem in exprs:
|
for expr in exprs:
|
||||||
# Expression
|
info = expr.info
|
||||||
assert isinstance(expr_elem['expr'], dict)
|
doc = expr.doc
|
||||||
for key in expr_elem['expr'].keys():
|
|
||||||
assert isinstance(key, str)
|
|
||||||
expr: _JSONObject = expr_elem['expr']
|
|
||||||
|
|
||||||
# QAPISourceInfo
|
|
||||||
assert isinstance(expr_elem['info'], QAPISourceInfo)
|
|
||||||
info: QAPISourceInfo = expr_elem['info']
|
|
||||||
|
|
||||||
# Optional[QAPIDoc]
|
|
||||||
tmp = expr_elem.get('doc')
|
|
||||||
assert tmp is None or isinstance(tmp, QAPIDoc)
|
|
||||||
doc: Optional[QAPIDoc] = tmp
|
|
||||||
|
|
||||||
if 'include' in expr:
|
if 'include' in expr:
|
||||||
continue
|
continue
|
||||||
@ -652,24 +636,24 @@ def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]:
|
|||||||
if meta == 'enum':
|
if meta == 'enum':
|
||||||
check_keys(expr, info, meta,
|
check_keys(expr, info, meta,
|
||||||
['enum', 'data'], ['if', 'features', 'prefix'])
|
['enum', 'data'], ['if', 'features', 'prefix'])
|
||||||
check_enum(expr, info)
|
check_enum(expr)
|
||||||
elif meta == 'union':
|
elif meta == 'union':
|
||||||
check_keys(expr, info, meta,
|
check_keys(expr, info, meta,
|
||||||
['union', 'base', 'discriminator', 'data'],
|
['union', 'base', 'discriminator', 'data'],
|
||||||
['if', 'features'])
|
['if', 'features'])
|
||||||
normalize_members(expr.get('base'))
|
normalize_members(expr.get('base'))
|
||||||
normalize_members(expr['data'])
|
normalize_members(expr['data'])
|
||||||
check_union(expr, info)
|
check_union(expr)
|
||||||
elif meta == 'alternate':
|
elif meta == 'alternate':
|
||||||
check_keys(expr, info, meta,
|
check_keys(expr, info, meta,
|
||||||
['alternate', 'data'], ['if', 'features'])
|
['alternate', 'data'], ['if', 'features'])
|
||||||
normalize_members(expr['data'])
|
normalize_members(expr['data'])
|
||||||
check_alternate(expr, info)
|
check_alternate(expr)
|
||||||
elif meta == 'struct':
|
elif meta == 'struct':
|
||||||
check_keys(expr, info, meta,
|
check_keys(expr, info, meta,
|
||||||
['struct', 'data'], ['base', 'if', 'features'])
|
['struct', 'data'], ['base', 'if', 'features'])
|
||||||
normalize_members(expr['data'])
|
normalize_members(expr['data'])
|
||||||
check_struct(expr, info)
|
check_struct(expr)
|
||||||
elif meta == 'command':
|
elif meta == 'command':
|
||||||
check_keys(expr, info, meta,
|
check_keys(expr, info, meta,
|
||||||
['command'],
|
['command'],
|
||||||
@ -677,17 +661,17 @@ def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]:
|
|||||||
'gen', 'success-response', 'allow-oob',
|
'gen', 'success-response', 'allow-oob',
|
||||||
'allow-preconfig', 'coroutine'])
|
'allow-preconfig', 'coroutine'])
|
||||||
normalize_members(expr.get('data'))
|
normalize_members(expr.get('data'))
|
||||||
check_command(expr, info)
|
check_command(expr)
|
||||||
elif meta == 'event':
|
elif meta == 'event':
|
||||||
check_keys(expr, info, meta,
|
check_keys(expr, info, meta,
|
||||||
['event'], ['data', 'boxed', 'if', 'features'])
|
['event'], ['data', 'boxed', 'if', 'features'])
|
||||||
normalize_members(expr.get('data'))
|
normalize_members(expr.get('data'))
|
||||||
check_event(expr, info)
|
check_event(expr)
|
||||||
else:
|
else:
|
||||||
assert False, 'unexpected meta type'
|
assert False, 'unexpected meta type'
|
||||||
|
|
||||||
check_if(expr, info, meta)
|
check_if(expr, info, meta)
|
||||||
check_features(expr.get('features'), info)
|
check_features(expr.get('features'), info)
|
||||||
check_flags(expr, info)
|
check_flags(expr)
|
||||||
|
|
||||||
return exprs
|
return exprs
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Dict,
|
Dict,
|
||||||
List,
|
List,
|
||||||
|
Mapping,
|
||||||
Optional,
|
Optional,
|
||||||
Set,
|
Set,
|
||||||
Union,
|
Union,
|
||||||
@ -37,15 +38,24 @@
|
|||||||
from .schema import QAPISchemaFeature, QAPISchemaMember
|
from .schema import QAPISchemaFeature, QAPISchemaMember
|
||||||
|
|
||||||
|
|
||||||
#: Represents a single Top Level QAPI schema expression.
|
|
||||||
TopLevelExpr = Dict[str, object]
|
|
||||||
|
|
||||||
# Return value alias for get_expr().
|
# Return value alias for get_expr().
|
||||||
_ExprValue = Union[List[object], Dict[str, object], str, bool]
|
_ExprValue = Union[List[object], Dict[str, object], str, bool]
|
||||||
|
|
||||||
# FIXME: Consolidate and centralize definitions for TopLevelExpr,
|
|
||||||
# _ExprValue, _JSONValue, and _JSONObject; currently scattered across
|
# FIXME: Consolidate and centralize definitions for _ExprValue,
|
||||||
# several modules.
|
# JSONValue, and _JSONObject; currently scattered across several
|
||||||
|
# modules.
|
||||||
|
|
||||||
|
|
||||||
|
class QAPIExpression(Dict[str, object]):
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
def __init__(self,
|
||||||
|
data: Mapping[str, object],
|
||||||
|
info: QAPISourceInfo,
|
||||||
|
doc: Optional['QAPIDoc'] = None):
|
||||||
|
super().__init__(data)
|
||||||
|
self.info = info
|
||||||
|
self.doc: Optional['QAPIDoc'] = doc
|
||||||
|
|
||||||
|
|
||||||
class QAPIParseError(QAPISourceError):
|
class QAPIParseError(QAPISourceError):
|
||||||
@ -100,7 +110,7 @@ def __init__(self,
|
|||||||
self.line_pos = 0
|
self.line_pos = 0
|
||||||
|
|
||||||
# Parser output:
|
# Parser output:
|
||||||
self.exprs: List[Dict[str, object]] = []
|
self.exprs: List[QAPIExpression] = []
|
||||||
self.docs: List[QAPIDoc] = []
|
self.docs: List[QAPIDoc] = []
|
||||||
|
|
||||||
# Showtime!
|
# Showtime!
|
||||||
@ -147,8 +157,7 @@ def _parse(self) -> None:
|
|||||||
"value of 'include' must be a string")
|
"value of 'include' must be a string")
|
||||||
incl_fname = os.path.join(os.path.dirname(self._fname),
|
incl_fname = os.path.join(os.path.dirname(self._fname),
|
||||||
include)
|
include)
|
||||||
self.exprs.append({'expr': {'include': incl_fname},
|
self._add_expr(OrderedDict({'include': incl_fname}), info)
|
||||||
'info': info})
|
|
||||||
exprs_include = self._include(include, info, incl_fname,
|
exprs_include = self._include(include, info, incl_fname,
|
||||||
self._included)
|
self._included)
|
||||||
if exprs_include:
|
if exprs_include:
|
||||||
@ -165,17 +174,18 @@ def _parse(self) -> None:
|
|||||||
for name, value in pragma.items():
|
for name, value in pragma.items():
|
||||||
self._pragma(name, value, info)
|
self._pragma(name, value, info)
|
||||||
else:
|
else:
|
||||||
expr_elem = {'expr': expr,
|
if cur_doc and not cur_doc.symbol:
|
||||||
'info': info}
|
raise QAPISemError(
|
||||||
if cur_doc:
|
cur_doc.info, "definition documentation required")
|
||||||
if not cur_doc.symbol:
|
self._add_expr(expr, info, cur_doc)
|
||||||
raise QAPISemError(
|
|
||||||
cur_doc.info, "definition documentation required")
|
|
||||||
expr_elem['doc'] = cur_doc
|
|
||||||
self.exprs.append(expr_elem)
|
|
||||||
cur_doc = None
|
cur_doc = None
|
||||||
self.reject_expr_doc(cur_doc)
|
self.reject_expr_doc(cur_doc)
|
||||||
|
|
||||||
|
def _add_expr(self, expr: Mapping[str, object],
|
||||||
|
info: QAPISourceInfo,
|
||||||
|
doc: Optional['QAPIDoc'] = None) -> None:
|
||||||
|
self.exprs.append(QAPIExpression(expr, info, doc))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def reject_expr_doc(doc: Optional['QAPIDoc']) -> None:
|
def reject_expr_doc(doc: Optional['QAPIDoc']) -> None:
|
||||||
if doc and doc.symbol:
|
if doc and doc.symbol:
|
||||||
@ -784,7 +794,7 @@ def connect_feature(self, feature: 'QAPISchemaFeature') -> None:
|
|||||||
% feature.name)
|
% feature.name)
|
||||||
self.features[feature.name].connect(feature)
|
self.features[feature.name].connect(feature)
|
||||||
|
|
||||||
def check_expr(self, expr: TopLevelExpr) -> None:
|
def check_expr(self, expr: QAPIExpression) -> None:
|
||||||
if self.has_section('Returns') and 'command' not in expr:
|
if self.has_section('Returns') and 'command' not in expr:
|
||||||
raise QAPISemError(self.info,
|
raise QAPISemError(self.info,
|
||||||
"'Returns:' is only valid for commands")
|
"'Returns:' is only valid for commands")
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from typing import Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from .common import (
|
from .common import (
|
||||||
POINTER_SUFFIX,
|
POINTER_SUFFIX,
|
||||||
@ -29,7 +29,7 @@
|
|||||||
)
|
)
|
||||||
from .error import QAPIError, QAPISemError, QAPISourceError
|
from .error import QAPIError, QAPISemError, QAPISourceError
|
||||||
from .expr import check_exprs
|
from .expr import check_exprs
|
||||||
from .parser import QAPISchemaParser
|
from .parser import QAPIExpression, QAPISchemaParser
|
||||||
|
|
||||||
|
|
||||||
class QAPISchemaIfCond:
|
class QAPISchemaIfCond:
|
||||||
@ -964,10 +964,11 @@ def module_by_fname(self, fname):
|
|||||||
name = self._module_name(fname)
|
name = self._module_name(fname)
|
||||||
return self._module_dict[name]
|
return self._module_dict[name]
|
||||||
|
|
||||||
def _def_include(self, expr, info, doc):
|
def _def_include(self, expr: QAPIExpression):
|
||||||
include = expr['include']
|
include = expr['include']
|
||||||
assert doc is None
|
assert expr.doc is None
|
||||||
self._def_entity(QAPISchemaInclude(self._make_module(include), info))
|
self._def_entity(
|
||||||
|
QAPISchemaInclude(self._make_module(include), expr.info))
|
||||||
|
|
||||||
def _def_builtin_type(self, name, json_type, c_type):
|
def _def_builtin_type(self, name, json_type, c_type):
|
||||||
self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
|
self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
|
||||||
@ -1045,14 +1046,15 @@ def _make_implicit_object_type(self, name, info, ifcond, role, members):
|
|||||||
name, info, None, ifcond, None, None, members, None))
|
name, info, None, ifcond, None, None, members, None))
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def _def_enum_type(self, expr, info, doc):
|
def _def_enum_type(self, expr: QAPIExpression):
|
||||||
name = expr['enum']
|
name = expr['enum']
|
||||||
data = expr['data']
|
data = expr['data']
|
||||||
prefix = expr.get('prefix')
|
prefix = expr.get('prefix')
|
||||||
ifcond = QAPISchemaIfCond(expr.get('if'))
|
ifcond = QAPISchemaIfCond(expr.get('if'))
|
||||||
|
info = expr.info
|
||||||
features = self._make_features(expr.get('features'), info)
|
features = self._make_features(expr.get('features'), info)
|
||||||
self._def_entity(QAPISchemaEnumType(
|
self._def_entity(QAPISchemaEnumType(
|
||||||
name, info, doc, ifcond, features,
|
name, info, expr.doc, ifcond, features,
|
||||||
self._make_enum_members(data, info), prefix))
|
self._make_enum_members(data, info), prefix))
|
||||||
|
|
||||||
def _make_member(self, name, typ, ifcond, features, info):
|
def _make_member(self, name, typ, ifcond, features, info):
|
||||||
@ -1072,14 +1074,15 @@ def _make_members(self, data, info):
|
|||||||
value.get('features'), info)
|
value.get('features'), info)
|
||||||
for (key, value) in data.items()]
|
for (key, value) in data.items()]
|
||||||
|
|
||||||
def _def_struct_type(self, expr, info, doc):
|
def _def_struct_type(self, expr: QAPIExpression):
|
||||||
name = expr['struct']
|
name = expr['struct']
|
||||||
base = expr.get('base')
|
base = expr.get('base')
|
||||||
data = expr['data']
|
data = expr['data']
|
||||||
|
info = expr.info
|
||||||
ifcond = QAPISchemaIfCond(expr.get('if'))
|
ifcond = QAPISchemaIfCond(expr.get('if'))
|
||||||
features = self._make_features(expr.get('features'), info)
|
features = self._make_features(expr.get('features'), info)
|
||||||
self._def_entity(QAPISchemaObjectType(
|
self._def_entity(QAPISchemaObjectType(
|
||||||
name, info, doc, ifcond, features, base,
|
name, info, expr.doc, ifcond, features, base,
|
||||||
self._make_members(data, info),
|
self._make_members(data, info),
|
||||||
None))
|
None))
|
||||||
|
|
||||||
@ -1089,11 +1092,13 @@ def _make_variant(self, case, typ, ifcond, info):
|
|||||||
typ = self._make_array_type(typ[0], info)
|
typ = self._make_array_type(typ[0], info)
|
||||||
return QAPISchemaVariant(case, info, typ, ifcond)
|
return QAPISchemaVariant(case, info, typ, ifcond)
|
||||||
|
|
||||||
def _def_union_type(self, expr, info, doc):
|
def _def_union_type(self, expr: QAPIExpression):
|
||||||
name = expr['union']
|
name = expr['union']
|
||||||
base = expr['base']
|
base = expr['base']
|
||||||
tag_name = expr['discriminator']
|
tag_name = expr['discriminator']
|
||||||
data = expr['data']
|
data = expr['data']
|
||||||
|
assert isinstance(data, dict)
|
||||||
|
info = expr.info
|
||||||
ifcond = QAPISchemaIfCond(expr.get('if'))
|
ifcond = QAPISchemaIfCond(expr.get('if'))
|
||||||
features = self._make_features(expr.get('features'), info)
|
features = self._make_features(expr.get('features'), info)
|
||||||
if isinstance(base, dict):
|
if isinstance(base, dict):
|
||||||
@ -1105,17 +1110,19 @@ def _def_union_type(self, expr, info, doc):
|
|||||||
QAPISchemaIfCond(value.get('if')),
|
QAPISchemaIfCond(value.get('if')),
|
||||||
info)
|
info)
|
||||||
for (key, value) in data.items()]
|
for (key, value) in data.items()]
|
||||||
members = []
|
members: List[QAPISchemaObjectTypeMember] = []
|
||||||
self._def_entity(
|
self._def_entity(
|
||||||
QAPISchemaObjectType(name, info, doc, ifcond, features,
|
QAPISchemaObjectType(name, info, expr.doc, ifcond, features,
|
||||||
base, members,
|
base, members,
|
||||||
QAPISchemaVariants(
|
QAPISchemaVariants(
|
||||||
tag_name, info, None, variants)))
|
tag_name, info, None, variants)))
|
||||||
|
|
||||||
def _def_alternate_type(self, expr, info, doc):
|
def _def_alternate_type(self, expr: QAPIExpression):
|
||||||
name = expr['alternate']
|
name = expr['alternate']
|
||||||
data = expr['data']
|
data = expr['data']
|
||||||
|
assert isinstance(data, dict)
|
||||||
ifcond = QAPISchemaIfCond(expr.get('if'))
|
ifcond = QAPISchemaIfCond(expr.get('if'))
|
||||||
|
info = expr.info
|
||||||
features = self._make_features(expr.get('features'), info)
|
features = self._make_features(expr.get('features'), info)
|
||||||
variants = [
|
variants = [
|
||||||
self._make_variant(key, value['type'],
|
self._make_variant(key, value['type'],
|
||||||
@ -1124,11 +1131,11 @@ def _def_alternate_type(self, expr, info, doc):
|
|||||||
for (key, value) in data.items()]
|
for (key, value) in data.items()]
|
||||||
tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
|
tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
|
||||||
self._def_entity(
|
self._def_entity(
|
||||||
QAPISchemaAlternateType(name, info, doc, ifcond, features,
|
QAPISchemaAlternateType(
|
||||||
QAPISchemaVariants(
|
name, info, expr.doc, ifcond, features,
|
||||||
None, info, tag_member, variants)))
|
QAPISchemaVariants(None, info, tag_member, variants)))
|
||||||
|
|
||||||
def _def_command(self, expr, info, doc):
|
def _def_command(self, expr: QAPIExpression):
|
||||||
name = expr['command']
|
name = expr['command']
|
||||||
data = expr.get('data')
|
data = expr.get('data')
|
||||||
rets = expr.get('returns')
|
rets = expr.get('returns')
|
||||||
@ -1139,6 +1146,7 @@ def _def_command(self, expr, info, doc):
|
|||||||
allow_preconfig = expr.get('allow-preconfig', False)
|
allow_preconfig = expr.get('allow-preconfig', False)
|
||||||
coroutine = expr.get('coroutine', False)
|
coroutine = expr.get('coroutine', False)
|
||||||
ifcond = QAPISchemaIfCond(expr.get('if'))
|
ifcond = QAPISchemaIfCond(expr.get('if'))
|
||||||
|
info = expr.info
|
||||||
features = self._make_features(expr.get('features'), info)
|
features = self._make_features(expr.get('features'), info)
|
||||||
if isinstance(data, OrderedDict):
|
if isinstance(data, OrderedDict):
|
||||||
data = self._make_implicit_object_type(
|
data = self._make_implicit_object_type(
|
||||||
@ -1147,44 +1155,42 @@ def _def_command(self, expr, info, doc):
|
|||||||
if isinstance(rets, list):
|
if isinstance(rets, list):
|
||||||
assert len(rets) == 1
|
assert len(rets) == 1
|
||||||
rets = self._make_array_type(rets[0], info)
|
rets = self._make_array_type(rets[0], info)
|
||||||
self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, features,
|
self._def_entity(QAPISchemaCommand(name, info, expr.doc, ifcond,
|
||||||
data, rets,
|
features, data, rets,
|
||||||
gen, success_response,
|
gen, success_response,
|
||||||
boxed, allow_oob, allow_preconfig,
|
boxed, allow_oob, allow_preconfig,
|
||||||
coroutine))
|
coroutine))
|
||||||
|
|
||||||
def _def_event(self, expr, info, doc):
|
def _def_event(self, expr: QAPIExpression):
|
||||||
name = expr['event']
|
name = expr['event']
|
||||||
data = expr.get('data')
|
data = expr.get('data')
|
||||||
boxed = expr.get('boxed', False)
|
boxed = expr.get('boxed', False)
|
||||||
ifcond = QAPISchemaIfCond(expr.get('if'))
|
ifcond = QAPISchemaIfCond(expr.get('if'))
|
||||||
|
info = expr.info
|
||||||
features = self._make_features(expr.get('features'), info)
|
features = self._make_features(expr.get('features'), info)
|
||||||
if isinstance(data, OrderedDict):
|
if isinstance(data, OrderedDict):
|
||||||
data = self._make_implicit_object_type(
|
data = self._make_implicit_object_type(
|
||||||
name, info, ifcond,
|
name, info, ifcond,
|
||||||
'arg', self._make_members(data, info))
|
'arg', self._make_members(data, info))
|
||||||
self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, features,
|
self._def_entity(QAPISchemaEvent(name, info, expr.doc, ifcond,
|
||||||
data, boxed))
|
features, data, boxed))
|
||||||
|
|
||||||
def _def_exprs(self, exprs):
|
def _def_exprs(self, exprs):
|
||||||
for expr_elem in exprs:
|
for expr in exprs:
|
||||||
expr = expr_elem['expr']
|
|
||||||
info = expr_elem['info']
|
|
||||||
doc = expr_elem.get('doc')
|
|
||||||
if 'enum' in expr:
|
if 'enum' in expr:
|
||||||
self._def_enum_type(expr, info, doc)
|
self._def_enum_type(expr)
|
||||||
elif 'struct' in expr:
|
elif 'struct' in expr:
|
||||||
self._def_struct_type(expr, info, doc)
|
self._def_struct_type(expr)
|
||||||
elif 'union' in expr:
|
elif 'union' in expr:
|
||||||
self._def_union_type(expr, info, doc)
|
self._def_union_type(expr)
|
||||||
elif 'alternate' in expr:
|
elif 'alternate' in expr:
|
||||||
self._def_alternate_type(expr, info, doc)
|
self._def_alternate_type(expr)
|
||||||
elif 'command' in expr:
|
elif 'command' in expr:
|
||||||
self._def_command(expr, info, doc)
|
self._def_command(expr)
|
||||||
elif 'event' in expr:
|
elif 'event' in expr:
|
||||||
self._def_event(expr, info, doc)
|
self._def_event(expr)
|
||||||
elif 'include' in expr:
|
elif 'include' in expr:
|
||||||
self._def_include(expr, info, doc)
|
self._def_include(expr)
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user