aboutsummaryrefslogtreecommitdiff
path: root/scripts/qapi
diff options
context:
space:
mode:
authorMarkus Armbruster <armbru@redhat.com>2019-06-06 17:38:03 +0200
committerMarkus Armbruster <armbru@redhat.com>2019-06-12 18:37:17 +0200
commit157dd363955b961ef378eb1f7817c31a7fa94d10 (patch)
treed20940570e0014a06068bda8cce5c0752dc80004 /scripts/qapi
parentc9d4070991ee504bd674c77c3790ef7028b258bd (diff)
qapi: Simplify how QAPIDoc implements its state machine
QAPIDoc uses a state machine to for processing of documentation lines. Its state is encoded as an enum QAPIDoc._state (well, as enum-like class actually, thanks to our infatuation with Python 2). All we ever do with the state is calling the state's function to process a line of documentation. The enum values effectively serve as handles for the functions. Eliminate the rather wordy indirection: store the function to call in QAPIDoc._append_line. Update and improve comments. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20190606153803.5278-8-armbru@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> [Commit message typo fixed]
Diffstat (limited to 'scripts/qapi')
-rw-r--r--scripts/qapi/common.py125
1 files changed, 68 insertions, 57 deletions
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 1164301edf..d61bfdc526 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -102,6 +102,24 @@ class QAPISemError(QAPIError):
class QAPIDoc(object):
+ """
+ A documentation comment block, either expression or free-form
+
+ Expression documentation blocks consist of
+
+ * a body section: one line naming the expression, followed by an
+ overview (any number of lines)
+
+ * argument sections: a description of each argument (for commands
+ and events) or member (for structs, unions and alternates)
+
+ * features sections: a description of each feature flag
+
+ * additional (non-argument) sections, possibly tagged
+
+ Free-form documentation blocks consist only of a body section.
+ """
+
class Section(object):
def __init__(self, name=None):
# optional section name (argument/member or section name)
@@ -120,26 +138,6 @@ class QAPIDoc(object):
def connect(self, member):
self.member = member
- class DocPart:
- """
- Describes which part of the documentation we're parsing right now.
-
- Expression documentation blocks consist of
- * a BODY part: first line naming the expression, plus an
- optional overview
- * an ARGS part: description of each argument (for commands and
- events) or member (for structs, unions and alternates),
- * a FEATURES part: description of each feature,
- * a VARIOUS part: optional tagged sections.
-
- Free-form documentation blocks consist only of a BODY part.
- """
- # TODO Make it a subclass of Enum when Python 2 support is removed
- BODY = 1
- ARGS = 2
- FEATURES = 3
- VARIOUS = 4
-
def __init__(self, parser, info):
# self._parser is used to report errors with QAPIParseError. The
# resulting error position depends on the state of the parser.
@@ -156,7 +154,7 @@ class QAPIDoc(object):
self.sections = []
# the current section
self._section = self.body
- self._part = QAPIDoc.DocPart.BODY
+ self._append_line = self._append_body_line
def has_section(self, name):
"""Return True if we have a section with this name."""
@@ -171,21 +169,10 @@ class QAPIDoc(object):
The way that the line is dealt with depends on which part of
the documentation we're parsing right now:
-
- BODY means that we're ready to process free-form text into
- self.body. A symbol name is only allowed if no other text was
- parsed yet. It is interpreted as the symbol name that
- describes the currently documented object. On getting the
- second symbol name, we proceed to ARGS.
-
- ARGS means that we're parsing the arguments section. Any
- symbol name is interpreted as an argument and an ArgSection is
- created for it.
-
- VARIOUS is the final part where free-form sections may appear.
- This includes named sections such as "Return:" as well as
- unnamed paragraphs. Symbols are not allowed any more in this
- part.
+ * The body section: ._append_line is ._append_body_line
+ * An argument section: ._append_line is ._append_args_line
+ * A features section: ._append_line is ._append_features_line
+ * An additional section: ._append_line is ._append_various_line
"""
line = line[1:]
if not line:
@@ -195,17 +182,7 @@ class QAPIDoc(object):
if line[0] != ' ':
raise QAPIParseError(self._parser, "Missing space after #")
line = line[1:]
-
- if self._part == QAPIDoc.DocPart.BODY:
- self._append_body_line(line)
- elif self._part == QAPIDoc.DocPart.ARGS:
- self._append_args_line(line)
- elif self._part == QAPIDoc.DocPart.FEATURES:
- self._append_features_line(line)
- elif self._part == QAPIDoc.DocPart.VARIOUS:
- self._append_various_line(line)
- else:
- assert False
+ self._append_line(line)
def end_comment(self):
self._end_section()
@@ -219,6 +196,19 @@ class QAPIDoc(object):
'TODO:')
def _append_body_line(self, line):
+ """
+ Process a line of documentation text in the body section.
+
+ If this a symbol line and it is the section's first line, this
+ is an expression documentation block for that symbol.
+
+ If it's an expression documentation block, another symbol line
+ begins the argument section for the argument named by it, and
+ a section tag begins an additional section. Start that
+ section and append the line to it.
+
+ Else, append the line to the current section.
+ """
name = line.split(' ', 1)[0]
# FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
# recognized, and get silently treated as ordinary text
@@ -230,38 +220,49 @@ class QAPIDoc(object):
if not self.symbol:
raise QAPIParseError(self._parser, "Invalid name")
elif self.symbol:
- # We already know that we document some symbol
+ # This is an expression documentation block
if name.startswith('@') and name.endswith(':'):
- self._part = QAPIDoc.DocPart.ARGS
+ self._append_line = self._append_args_line
self._append_args_line(line)
elif line == 'Features:':
- self._part = QAPIDoc.DocPart.FEATURES
+ self._append_line = self._append_features_line
elif self._is_section_tag(name):
- self._part = QAPIDoc.DocPart.VARIOUS
+ self._append_line = self._append_various_line
self._append_various_line(line)
else:
self._append_freeform(line.strip())
else:
- # This is free-form documentation without a symbol
+ # This is a free-form documentation block
self._append_freeform(line.strip())
def _append_args_line(self, line):
+ """
+ Process a line of documentation text in an argument section.
+
+ A symbol line begins the next argument section, a section tag
+ section or a non-indented line after a blank line begins an
+ additional section. Start that section and append the line to
+ it.
+
+ Else, append the line to the current section.
+
+ """
name = line.split(' ', 1)[0]
if name.startswith('@') and name.endswith(':'):
line = line[len(name)+1:]
self._start_args_section(name[1:-1])
elif self._is_section_tag(name):
- self._part = QAPIDoc.DocPart.VARIOUS
+ self._append_line = self._append_various_line
self._append_various_line(line)
return
elif (self._section.text.endswith('\n\n')
and line and not line[0].isspace()):
if line == 'Features:':
- self._part = QAPIDoc.DocPart.FEATURES
+ self._append_line = self._append_features_line
else:
self._start_section()
- self._part = QAPIDoc.DocPart.VARIOUS
+ self._append_line = self._append_various_line
self._append_various_line(line)
return
@@ -274,19 +275,29 @@ class QAPIDoc(object):
line = line[len(name)+1:]
self._start_features_section(name[1:-1])
elif self._is_section_tag(name):
- self._part = QAPIDoc.DocPart.VARIOUS
+ self._append_line = self._append_various_line
self._append_various_line(line)
return
elif (self._section.text.endswith('\n\n')
and line and not line[0].isspace()):
self._start_section()
- self._part = QAPIDoc.DocPart.VARIOUS
+ self._append_line = self._append_various_line
self._append_various_line(line)
return
self._append_freeform(line.strip())
def _append_various_line(self, line):
+ """
+ Process a line of documentation text in an additional section.
+
+ A symbol line is an error.
+
+ A section tag begins an additional section. Start that
+ section and append the line to it.
+
+ Else, append the line to the current section.
+ """
name = line.split(' ', 1)[0]
if name.startswith('@') and name.endswith(':'):