diff options
| author | Peter Maydell | 2020-09-30 00:19:39 +0200 |
|---|---|---|
| committer | Peter Maydell | 2020-09-30 00:19:39 +0200 |
| commit | e344ffe73bd77e7067099155cfd8bf42b07ed631 (patch) | |
| tree | cf85f68f00ec2c004fccb574ce35d7aec7afdbdf /scripts/qapi/parser.py | |
| parent | Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging (diff) | |
| parent | Remove texinfo dependency from docker and CI configs (diff) | |
| download | qemu-e344ffe73bd77e7067099155cfd8bf42b07ed631.tar.gz qemu-e344ffe73bd77e7067099155cfd8bf42b07ed631.tar.xz qemu-e344ffe73bd77e7067099155cfd8bf42b07ed631.zip | |
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2020-09-29' into staging
QAPI patches patches for 2020-09-29
# gpg: Signature made Tue 29 Sep 2020 20:54:51 BST
# gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653
# gpg: issuer "armbru@redhat.com"
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full]
# gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full]
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653
* remotes/armbru/tags/pull-qapi-2020-09-29: (29 commits)
Remove texinfo dependency from docker and CI configs
configure: Drop texinfo requirement
Remove Texinfo related line from git.orderfile
scripts/texi2pod: Delete unused script
docs/devel/qapi-code-gen.txt: Update to new rST backend conventions
scripts/qapi: Remove texinfo generation support
tests/qapi-schema: Add test of the rST QAPI doc-comment output
meson.build: Make manuals depend on source to Sphinx extensions
meson.build: Move SPHINX_ARGS to top level meson.build file
tests/qapi-schema: Convert doc-good.json to rST-style strong/emphasis
qga/qapi-schema.json: Add some headings
qapi: Use rST markup for literal blocks
docs/interop: Convert qemu-qmp-ref to rST
docs/interop: Convert qemu-ga-ref to rST
docs/sphinx: Add new qapi-doc Sphinx extension
qapi/machine.json: Escape a literal '*' in doc comment
scripts/qapi/parser.py: improve doc comment indent handling
scripts/qapi: Move doc-comment whitespace stripping to doc.py
tests/qapi/doc-good.json: Prepare for qapi-doc Sphinx extension
qapi/block.json: Add newline after "Example:" for block-latency-histogram-set
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'scripts/qapi/parser.py')
| -rw-r--r-- | scripts/qapi/parser.py | 105 |
1 files changed, 78 insertions, 27 deletions
diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index 165925ca72..9d1a3e2eea 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -319,17 +319,32 @@ class QAPIDoc: """ class Section: - def __init__(self, name=None): + def __init__(self, parser, name=None, indent=0): + # parser, for error messages about indentation + self._parser = parser # optional section name (argument/member or section name) self.name = name self.text = '' + # the expected indent level of the text of this section + self._indent = indent def append(self, line): + # Strip leading spaces corresponding to the expected indent level + # Blank lines are always OK. + if line: + indent = re.match(r'\s*', line).end() + if indent < self._indent: + raise QAPIParseError( + self._parser, + "unexpected de-indent (expected at least %d spaces)" % + self._indent) + line = line[self._indent:] + self.text += line.rstrip() + '\n' class ArgSection(Section): - def __init__(self, name): - super().__init__(name) + def __init__(self, parser, name, indent=0): + super().__init__(parser, name, indent) self.member = None def connect(self, member): @@ -343,7 +358,7 @@ class QAPIDoc: self._parser = parser self.info = info self.symbol = None - self.body = QAPIDoc.Section() + self.body = QAPIDoc.Section(parser) # dict mapping parameter name to ArgSection self.args = OrderedDict() self.features = OrderedDict() @@ -427,10 +442,10 @@ class QAPIDoc: self._append_line = self._append_various_line self._append_various_line(line) else: - self._append_freeform(line.strip()) + self._append_freeform(line) else: # This is a free-form documentation block - self._append_freeform(line.strip()) + self._append_freeform(line) def _append_args_line(self, line): """ @@ -447,8 +462,21 @@ class QAPIDoc: name = line.split(' ', 1)[0] if name.startswith('@') and name.endswith(':'): - line = line[len(name)+1:] - self._start_args_section(name[1:-1]) + # If line is "@arg: first line of description", find + # the index of 'f', which is the indent we expect for any + # following lines. We then remove the leading "@arg:" + # from line and replace it with spaces so that 'f' has the + # same index as it did in the original line and can be + # handled the same way we will handle following lines. + indent = re.match(r'@\S*:\s*', line).end() + line = line[indent:] + if not line: + # Line was just the "@arg:" header; following lines + # are not indented + indent = 0 + else: + line = ' ' * indent + line + self._start_args_section(name[1:-1], indent) elif self._is_section_tag(name): self._append_line = self._append_various_line self._append_various_line(line) @@ -463,14 +491,27 @@ class QAPIDoc: self._append_various_line(line) return - self._append_freeform(line.strip()) + self._append_freeform(line) def _append_features_line(self, line): name = line.split(' ', 1)[0] if name.startswith('@') and name.endswith(':'): - line = line[len(name)+1:] - self._start_features_section(name[1:-1]) + # If line is "@arg: first line of description", find + # the index of 'f', which is the indent we expect for any + # following lines. We then remove the leading "@arg:" + # from line and replace it with spaces so that 'f' has the + # same index as it did in the original line and can be + # handled the same way we will handle following lines. + indent = re.match(r'@\S*:\s*', line).end() + line = line[indent:] + if not line: + # Line was just the "@arg:" header; following lines + # are not indented + indent = 0 + else: + line = ' ' * indent + line + self._start_features_section(name[1:-1], indent) elif self._is_section_tag(name): self._append_line = self._append_various_line self._append_various_line(line) @@ -482,7 +523,7 @@ class QAPIDoc: self._append_various_line(line) return - self._append_freeform(line.strip()) + self._append_freeform(line) def _append_various_line(self, line): """ @@ -502,16 +543,25 @@ class QAPIDoc: "'%s' can't follow '%s' section" % (name, self.sections[0].name)) if self._is_section_tag(name): - line = line[len(name)+1:] - self._start_section(name[:-1]) - - if (not self._section.name or - not self._section.name.startswith('Example')): - line = line.strip() + # If line is "Section: first line of description", find + # the index of 'f', which is the indent we expect for any + # following lines. We then remove the leading "Section:" + # from line and replace it with spaces so that 'f' has the + # same index as it did in the original line and can be + # handled the same way we will handle following lines. + indent = re.match(r'\S*:\s*', line).end() + line = line[indent:] + if not line: + # Line was just the "Section:" header; following lines + # are not indented + indent = 0 + else: + line = ' ' * indent + line + self._start_section(name[:-1], indent) self._append_freeform(line) - def _start_symbol_section(self, symbols_dict, name): + def _start_symbol_section(self, symbols_dict, name, indent): # FIXME invalid names other than the empty string aren't flagged if not name: raise QAPIParseError(self._parser, "invalid parameter name") @@ -520,21 +570,21 @@ class QAPIDoc: "'%s' parameter name duplicated" % name) assert not self.sections self._end_section() - self._section = QAPIDoc.ArgSection(name) + self._section = QAPIDoc.ArgSection(self._parser, name, indent) symbols_dict[name] = self._section - def _start_args_section(self, name): - self._start_symbol_section(self.args, name) + def _start_args_section(self, name, indent): + self._start_symbol_section(self.args, name, indent) - def _start_features_section(self, name): - self._start_symbol_section(self.features, name) + def _start_features_section(self, name, indent): + self._start_symbol_section(self.features, name, indent) - def _start_section(self, name=None): + def _start_section(self, name=None, indent=0): if name in ('Returns', 'Since') and self.has_section(name): raise QAPIParseError(self._parser, "duplicated '%s' section" % name) self._end_section() - self._section = QAPIDoc.Section(name) + self._section = QAPIDoc.Section(self._parser, name, indent) self.sections.append(self._section) def _end_section(self): @@ -557,7 +607,8 @@ class QAPIDoc: def connect_member(self, member): if member.name not in self.args: # Undocumented TODO outlaw - self.args[member.name] = QAPIDoc.ArgSection(member.name) + self.args[member.name] = QAPIDoc.ArgSection(self._parser, + member.name) self.args[member.name].connect(member) def connect_feature(self, feature): |
