[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 22/29] scripts/qapi/parser.py: improve doc comment indent handlin
From: |
Peter Maydell |
Subject: |
[PATCH 22/29] scripts/qapi/parser.py: improve doc comment indent handling |
Date: |
Thu, 6 Feb 2020 17:30:33 +0000 |
Make the handling of indentation in doc comments more
sophisticated, so that when we see a section like:
Notes: some text
some more text
indented line 3
we save it for the doc-comment processing code as:
some text
some more text
indented line 3
and when we see a section with the heading on its own line:
Notes:
some text
some more text
indented text
we also accept that and save it in the same form.
The exception is that we always retain indentation as-is
for Examples sections, because these are literal text.
If we detect that the comment document text is not indented
as much as we expect it to be, we throw a parse error.
(We don't complain about over-indented sections, because
for rST this can be legitimate markup.)
Signed-off-by: Peter Maydell <address@hidden>
---
scripts/qapi/parser.py | 82 +++++++++++++++++++++++++++++++++---------
1 file changed, 65 insertions(+), 17 deletions(-)
diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py
index 2196ec5de1e..66f802641c9 100644
--- a/scripts/qapi/parser.py
+++ b/scripts/qapi/parser.py
@@ -313,18 +313,32 @@ class QAPIDoc(object):
"""
class Section(object):
- 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
# the list of lines for this section
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:
+ spacecount = len(line) - len(line.lstrip(" "))
+ if spacecount > self._indent:
+ spacecount = self._indent
+ if spacecount < self._indent:
+ raise QAPIParseError(self._parser, "unexpected de-indent")
+ line = line[spacecount:]
+
self.text += line.rstrip() + '\n'
class ArgSection(Section):
- def __init__(self, name):
- QAPIDoc.Section.__init__(self, name)
+ def __init__(self, parser, name, indent=0):
+ QAPIDoc.Section.__init__(self, parser, name, indent)
self.member = None
def connect(self, member):
@@ -338,7 +352,7 @@ class QAPIDoc(object):
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()
@@ -443,7 +457,18 @@ class QAPIDoc(object):
if name.startswith('@') and name.endswith(':'):
line = line[len(name)+1:]
- self._start_args_section(name[1:-1])
+ if not line or line.isspace():
+ # Line was just the "@arg:" header; following lines
+ # are not indented
+ indent = 0
+ line = ''
+ else:
+ # Line is "@arg: first line of description"; following
+ # lines should be indented by len(name) + 1, and we
+ # pad out this first line so it is handled the same way
+ indent = len(name) + 1
+ 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)
@@ -465,7 +490,17 @@ class QAPIDoc(object):
if name.startswith('@') and name.endswith(':'):
line = line[len(name)+1:]
- self._start_features_section(name[1:-1])
+ if not line or line.isspace():
+ # Line is just the "@name:" header, no ident for following
lines
+ indent = 0
+ line = ''
+ else:
+ # Line is "@arg: first line of description"; following
+ # lines should be indented by len(name) + 3, and we
+ # pad out this first line so it is handled the same way
+ indent = len(name) + 1
+ 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)
@@ -498,11 +533,23 @@ class QAPIDoc(object):
% (name, self.sections[0].name))
elif self._is_section_tag(name):
line = line[len(name)+1:]
- self._start_section(name[:-1])
+ if not line or line.isspace():
+ # Line is just "SectionName:", no indent for following lines
+ indent = 0
+ line = ''
+ elif name.startswith("Example"):
+ # The "Examples" section is literal-text, so preserve
+ # all the indentation as-is
+ indent = 0
+ else:
+ # Line is "SectionName: some text", indent required
+ indent = len(name) + 1
+ 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")
@@ -511,21 +558,21 @@ class QAPIDoc(object):
"'%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):
@@ -548,7 +595,7 @@ class QAPIDoc(object):
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):
@@ -556,7 +603,8 @@ class QAPIDoc(object):
raise QAPISemError(feature.info,
"feature '%s' lacks documentation"
% feature.name)
- self.features[feature.name] = QAPIDoc.ArgSection(feature.name)
+ self.features[feature.name] = QAPIDoc.ArgSection(self._parser,
+ feature.name)
self.features[feature.name].connect(feature)
def check_expr(self, expr):
--
2.20.1
- [PATCH 16/29] qapi/{block, misc, tmp}.json: Use explicit bulleted lists, (continued)
[PATCH 09/29] qapi: Fix indent level on doc comments in json files, Peter Maydell, 2020/02/06
[PATCH 27/29] qga/qapi-schema.json: Add some headings, Peter Maydell, 2020/02/06
[PATCH 22/29] scripts/qapi/parser.py: improve doc comment indent handling,
Peter Maydell <=
[PATCH 26/29] qapi: Use rST markup for literal blocks, Peter Maydell, 2020/02/06
[PATCH 24/29] docs/interop: Convert qemu-ga-ref to rST, Peter Maydell, 2020/02/06
[PATCH 23/29] docs/sphinx: Add new qapi-doc Sphinx extension, Peter Maydell, 2020/02/06
[PATCH 25/29] docs/interop: Convert qemu-qmp-ref to rST, Peter Maydell, 2020/02/06
[PATCH 28/29] scripts/qapi: Remove texinfo generation support, Peter Maydell, 2020/02/06
[PATCH 29/29] docs/devel/qapi-code-gen.txt: Update to new rST backend conventions, Peter Maydell, 2020/02/06
Re: [PATCH 00/29] Convert QAPI doc comments to generate rST instead of texinfo, Peter Maydell, 2020/02/06
Re: [PATCH 00/29] Convert QAPI doc comments to generate rST instead of texinfo, no-reply, 2020/02/06
Re: [PATCH 00/29] Convert QAPI doc comments to generate rST instead of texinfo, no-reply, 2020/02/06