mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-29 05:13:54 -06:00
qapi/parser: add type hint annotations (QAPIDoc)
Annotations do not change runtime behavior. This commit consists of only annotations. Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210930205716.1148693-10-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
parent
e7ac60fcd0
commit
5f0d9f3bc7
1 changed files with 39 additions and 28 deletions
|
@ -37,6 +37,9 @@ if TYPE_CHECKING:
|
||||||
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]
|
||||||
|
|
||||||
|
@ -454,7 +457,8 @@ class QAPIDoc:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Section:
|
class Section:
|
||||||
def __init__(self, parser, name=None, indent=0):
|
def __init__(self, parser: QAPISchemaParser,
|
||||||
|
name: Optional[str] = None, indent: int = 0):
|
||||||
# parser, for error messages about indentation
|
# parser, for error messages about indentation
|
||||||
self._parser = parser
|
self._parser = parser
|
||||||
# optional section name (argument/member or section name)
|
# optional section name (argument/member or section name)
|
||||||
|
@ -463,7 +467,7 @@ class QAPIDoc:
|
||||||
# the expected indent level of the text of this section
|
# the expected indent level of the text of this section
|
||||||
self._indent = indent
|
self._indent = indent
|
||||||
|
|
||||||
def append(self, line):
|
def append(self, line: str) -> None:
|
||||||
# Strip leading spaces corresponding to the expected indent level
|
# Strip leading spaces corresponding to the expected indent level
|
||||||
# Blank lines are always OK.
|
# Blank lines are always OK.
|
||||||
if line:
|
if line:
|
||||||
|
@ -478,7 +482,8 @@ class QAPIDoc:
|
||||||
self.text += line.rstrip() + '\n'
|
self.text += line.rstrip() + '\n'
|
||||||
|
|
||||||
class ArgSection(Section):
|
class ArgSection(Section):
|
||||||
def __init__(self, parser, name, indent=0):
|
def __init__(self, parser: QAPISchemaParser,
|
||||||
|
name: str, indent: int = 0):
|
||||||
super().__init__(parser, name, indent)
|
super().__init__(parser, name, indent)
|
||||||
self.member: Optional['QAPISchemaMember'] = None
|
self.member: Optional['QAPISchemaMember'] = None
|
||||||
|
|
||||||
|
@ -489,35 +494,34 @@ class QAPIDoc:
|
||||||
"""
|
"""
|
||||||
Immutable dummy section for use at the end of a doc block.
|
Immutable dummy section for use at the end of a doc block.
|
||||||
"""
|
"""
|
||||||
def append(self, line):
|
def append(self, line: str) -> None:
|
||||||
assert False, "Text appended after end_comment() called."
|
assert False, "Text appended after end_comment() called."
|
||||||
|
|
||||||
def __init__(self, parser, info):
|
def __init__(self, parser: QAPISchemaParser, info: QAPISourceInfo):
|
||||||
# self._parser is used to report errors with QAPIParseError. The
|
# self._parser is used to report errors with QAPIParseError. The
|
||||||
# resulting error position depends on the state of the parser.
|
# resulting error position depends on the state of the parser.
|
||||||
# It happens to be the beginning of the comment. More or less
|
# It happens to be the beginning of the comment. More or less
|
||||||
# servicable, but action at a distance.
|
# servicable, but action at a distance.
|
||||||
self._parser = parser
|
self._parser = parser
|
||||||
self.info = info
|
self.info = info
|
||||||
self.symbol = None
|
self.symbol: Optional[str] = None
|
||||||
self.body = QAPIDoc.Section(parser)
|
self.body = QAPIDoc.Section(parser)
|
||||||
# dict mapping parameter name to ArgSection
|
# dicts mapping parameter/feature names to their ArgSection
|
||||||
self.args = OrderedDict()
|
self.args: Dict[str, QAPIDoc.ArgSection] = OrderedDict()
|
||||||
self.features = OrderedDict()
|
self.features: Dict[str, QAPIDoc.ArgSection] = OrderedDict()
|
||||||
# a list of Section
|
self.sections: List[QAPIDoc.Section] = []
|
||||||
self.sections = []
|
|
||||||
# the current section
|
# the current section
|
||||||
self._section = self.body
|
self._section = self.body
|
||||||
self._append_line = self._append_body_line
|
self._append_line = self._append_body_line
|
||||||
|
|
||||||
def has_section(self, name):
|
def has_section(self, name: str) -> bool:
|
||||||
"""Return True if we have a section with this name."""
|
"""Return True if we have a section with this name."""
|
||||||
for i in self.sections:
|
for i in self.sections:
|
||||||
if i.name == name:
|
if i.name == name:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def append(self, line):
|
def append(self, line: str) -> None:
|
||||||
"""
|
"""
|
||||||
Parse a comment line and add it to the documentation.
|
Parse a comment line and add it to the documentation.
|
||||||
|
|
||||||
|
@ -538,18 +542,18 @@ class QAPIDoc:
|
||||||
line = line[1:]
|
line = line[1:]
|
||||||
self._append_line(line)
|
self._append_line(line)
|
||||||
|
|
||||||
def end_comment(self):
|
def end_comment(self) -> None:
|
||||||
self._switch_section(QAPIDoc.NullSection(self._parser))
|
self._switch_section(QAPIDoc.NullSection(self._parser))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _is_section_tag(name):
|
def _is_section_tag(name: str) -> bool:
|
||||||
return name in ('Returns:', 'Since:',
|
return name in ('Returns:', 'Since:',
|
||||||
# those are often singular or plural
|
# those are often singular or plural
|
||||||
'Note:', 'Notes:',
|
'Note:', 'Notes:',
|
||||||
'Example:', 'Examples:',
|
'Example:', 'Examples:',
|
||||||
'TODO:')
|
'TODO:')
|
||||||
|
|
||||||
def _append_body_line(self, line):
|
def _append_body_line(self, line: str) -> None:
|
||||||
"""
|
"""
|
||||||
Process a line of documentation text in the body section.
|
Process a line of documentation text in the body section.
|
||||||
|
|
||||||
|
@ -591,7 +595,7 @@ class QAPIDoc:
|
||||||
# This is a free-form documentation block
|
# This is a free-form documentation block
|
||||||
self._append_freeform(line)
|
self._append_freeform(line)
|
||||||
|
|
||||||
def _append_args_line(self, line):
|
def _append_args_line(self, line: str) -> None:
|
||||||
"""
|
"""
|
||||||
Process a line of documentation text in an argument section.
|
Process a line of documentation text in an argument section.
|
||||||
|
|
||||||
|
@ -637,7 +641,7 @@ class QAPIDoc:
|
||||||
|
|
||||||
self._append_freeform(line)
|
self._append_freeform(line)
|
||||||
|
|
||||||
def _append_features_line(self, line):
|
def _append_features_line(self, line: str) -> None:
|
||||||
name = line.split(' ', 1)[0]
|
name = line.split(' ', 1)[0]
|
||||||
|
|
||||||
if name.startswith('@') and name.endswith(':'):
|
if name.startswith('@') and name.endswith(':'):
|
||||||
|
@ -669,7 +673,7 @@ class QAPIDoc:
|
||||||
|
|
||||||
self._append_freeform(line)
|
self._append_freeform(line)
|
||||||
|
|
||||||
def _append_various_line(self, line):
|
def _append_various_line(self, line: str) -> None:
|
||||||
"""
|
"""
|
||||||
Process a line of documentation text in an additional section.
|
Process a line of documentation text in an additional section.
|
||||||
|
|
||||||
|
@ -705,7 +709,11 @@ class QAPIDoc:
|
||||||
|
|
||||||
self._append_freeform(line)
|
self._append_freeform(line)
|
||||||
|
|
||||||
def _start_symbol_section(self, symbols_dict, name, indent):
|
def _start_symbol_section(
|
||||||
|
self,
|
||||||
|
symbols_dict: Dict[str, 'QAPIDoc.ArgSection'],
|
||||||
|
name: str,
|
||||||
|
indent: int) -> None:
|
||||||
# FIXME invalid names other than the empty string aren't flagged
|
# FIXME invalid names other than the empty string aren't flagged
|
||||||
if not name:
|
if not name:
|
||||||
raise QAPIParseError(self._parser, "invalid parameter name")
|
raise QAPIParseError(self._parser, "invalid parameter name")
|
||||||
|
@ -717,13 +725,14 @@ class QAPIDoc:
|
||||||
self._switch_section(new_section)
|
self._switch_section(new_section)
|
||||||
symbols_dict[name] = new_section
|
symbols_dict[name] = new_section
|
||||||
|
|
||||||
def _start_args_section(self, name, indent):
|
def _start_args_section(self, name: str, indent: int) -> None:
|
||||||
self._start_symbol_section(self.args, name, indent)
|
self._start_symbol_section(self.args, name, indent)
|
||||||
|
|
||||||
def _start_features_section(self, name, indent):
|
def _start_features_section(self, name: str, indent: int) -> None:
|
||||||
self._start_symbol_section(self.features, name, indent)
|
self._start_symbol_section(self.features, name, indent)
|
||||||
|
|
||||||
def _start_section(self, name=None, indent=0):
|
def _start_section(self, name: Optional[str] = None,
|
||||||
|
indent: int = 0) -> None:
|
||||||
if name in ('Returns', 'Since') and self.has_section(name):
|
if name in ('Returns', 'Since') and self.has_section(name):
|
||||||
raise QAPIParseError(self._parser,
|
raise QAPIParseError(self._parser,
|
||||||
"duplicated '%s' section" % name)
|
"duplicated '%s' section" % name)
|
||||||
|
@ -731,7 +740,7 @@ class QAPIDoc:
|
||||||
self._switch_section(new_section)
|
self._switch_section(new_section)
|
||||||
self.sections.append(new_section)
|
self.sections.append(new_section)
|
||||||
|
|
||||||
def _switch_section(self, new_section):
|
def _switch_section(self, new_section: 'QAPIDoc.Section') -> None:
|
||||||
text = self._section.text = self._section.text.strip()
|
text = self._section.text = self._section.text.strip()
|
||||||
|
|
||||||
# Only the 'body' section is allowed to have an empty body.
|
# Only the 'body' section is allowed to have an empty body.
|
||||||
|
@ -746,7 +755,7 @@ class QAPIDoc:
|
||||||
|
|
||||||
self._section = new_section
|
self._section = new_section
|
||||||
|
|
||||||
def _append_freeform(self, line):
|
def _append_freeform(self, line: str) -> None:
|
||||||
match = re.match(r'(@\S+:)', line)
|
match = re.match(r'(@\S+:)', line)
|
||||||
if match:
|
if match:
|
||||||
raise QAPIParseError(self._parser,
|
raise QAPIParseError(self._parser,
|
||||||
|
@ -768,14 +777,16 @@ class QAPIDoc:
|
||||||
% feature.name)
|
% feature.name)
|
||||||
self.features[feature.name].connect(feature)
|
self.features[feature.name].connect(feature)
|
||||||
|
|
||||||
def check_expr(self, expr):
|
def check_expr(self, expr: TopLevelExpr) -> 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")
|
||||||
|
|
||||||
def check(self):
|
def check(self) -> None:
|
||||||
|
|
||||||
def check_args_section(args, what):
|
def check_args_section(
|
||||||
|
args: Dict[str, QAPIDoc.ArgSection], what: str
|
||||||
|
) -> None:
|
||||||
bogus = [name for name, section in args.items()
|
bogus = [name for name, section in args.items()
|
||||||
if not section.member]
|
if not section.member]
|
||||||
if bogus:
|
if bogus:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue