aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/devel/qapi-code-gen.txt2
-rw-r--r--qapi-schema.json13
-rw-r--r--qmp.c5
-rw-r--r--scripts/qapi.py107
-rwxr-xr-xscripts/qapi2texi.py65
-rw-r--r--tests/Makefile.include3
-rw-r--r--tests/qapi-schema/doc-bad-section.err0
-rw-r--r--tests/qapi-schema/doc-bad-section.exit1
-rw-r--r--tests/qapi-schema/doc-bad-section.json11
-rw-r--r--tests/qapi-schema/doc-bad-section.out13
-rw-r--r--tests/qapi-schema/doc-good.json1
-rw-r--r--tests/qapi-schema/doc-good.out4
-rw-r--r--tests/qapi-schema/doc-good.texi11
-rw-r--r--tests/qapi-schema/test-qapi.py6
14 files changed, 111 insertions, 131 deletions
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index f04c63fe82..06ab699066 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -63,7 +63,7 @@ Comment text starting with '=' is a section title:
Double the '=' for a subsection title:
- # == Subection title
+ # == Subsection title
'|' denotes examples:
diff --git a/qapi-schema.json b/qapi-schema.json
index 18457954a8..5c06745c79 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1046,17 +1046,6 @@
{ 'command': 'system_powerdown' }
##
-# @cpu:
-#
-# This command is a nop that is only provided for the purposes of compatibility.
-#
-# Since: 0.14.0
-#
-# Notes: Do not use this command.
-##
-{ 'command': 'cpu', 'data': {'index': 'int'} }
-
-##
# @cpu-add:
#
# Adds CPU with specified ID
@@ -3188,7 +3177,7 @@
#
# Show Virtual Machine Generation ID
#
-# Since 2.9
+# Since: 2.9
##
{ 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }
diff --git a/qmp.c b/qmp.c
index e8c303116a..52cfd2d81c 100644
--- a/qmp.c
+++ b/qmp.c
@@ -113,11 +113,6 @@ void qmp_system_powerdown(Error **erp)
qemu_system_powerdown_request();
}
-void qmp_cpu(int64_t index, Error **errp)
-{
- /* Just do nothing */
-}
-
void qmp_cpu_add(int64_t id, Error **errp)
{
MachineClass *mc;
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 62dc52ed6e..43a54bf40f 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -106,13 +106,10 @@ class QAPIDoc(object):
# optional section name (argument/member or section name)
self.name = name
# the list of lines for this section
- self.content = []
+ self.text = ''
def append(self, line):
- self.content.append(line)
-
- def __repr__(self):
- return '\n'.join(self.content).strip()
+ self.text += line.rstrip() + '\n'
class ArgSection(Section):
def __init__(self, name):
@@ -123,11 +120,11 @@ class QAPIDoc(object):
self.member = member
def __init__(self, parser, info):
- # 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.
# It happens to be the beginning of the comment. More or less
# servicable, but action at a distance.
- self.parser = parser
+ self._parser = parser
self.info = info
self.symbol = None
self.body = QAPIDoc.Section()
@@ -136,7 +133,7 @@ class QAPIDoc(object):
# a list of Section
self.sections = []
# the current section
- self.section = self.body
+ self._section = self.body
def has_section(self, name):
"""Return True if we have a section with this name."""
@@ -153,20 +150,20 @@ class QAPIDoc(object):
return
if line[0] != ' ':
- raise QAPIParseError(self.parser, "Missing space after #")
+ raise QAPIParseError(self._parser, "Missing space after #")
line = line[1:]
# FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
# recognized, and get silently treated as ordinary text
if self.symbol:
self._append_symbol_line(line)
- elif not self.body.content and line.startswith('@'):
+ elif not self.body.text and line.startswith('@'):
if not line.endswith(':'):
- raise QAPIParseError(self.parser, "Line should end with :")
+ raise QAPIParseError(self._parser, "Line should end with :")
self.symbol = line[1:-1]
# FIXME invalid names other than the empty string aren't flagged
if not self.symbol:
- raise QAPIParseError(self.parser, "Invalid name")
+ raise QAPIParseError(self._parser, "Invalid name")
else:
self._append_freeform(line)
@@ -192,53 +189,48 @@ class QAPIDoc(object):
def _start_args_section(self, name):
# FIXME invalid names other than the empty string aren't flagged
if not name:
- raise QAPIParseError(self.parser, "Invalid parameter name")
+ raise QAPIParseError(self._parser, "Invalid parameter name")
if name in self.args:
- raise QAPIParseError(self.parser,
+ raise QAPIParseError(self._parser,
"'%s' parameter name duplicated" % name)
if self.sections:
- raise QAPIParseError(self.parser,
+ raise QAPIParseError(self._parser,
"'@%s:' can't follow '%s' section"
% (name, self.sections[0].name))
self._end_section()
- self.section = QAPIDoc.ArgSection(name)
- self.args[name] = self.section
+ self._section = QAPIDoc.ArgSection(name)
+ self.args[name] = self._section
- def _start_section(self, name=''):
+ def _start_section(self, name=None):
if name in ('Returns', 'Since') and self.has_section(name):
- raise QAPIParseError(self.parser,
+ raise QAPIParseError(self._parser,
"Duplicated '%s' section" % name)
self._end_section()
- self.section = QAPIDoc.Section(name)
- self.sections.append(self.section)
+ self._section = QAPIDoc.Section(name)
+ self.sections.append(self._section)
def _end_section(self):
- if self.section:
- contents = str(self.section)
- if self.section.name and (not contents or contents.isspace()):
- raise QAPIParseError(self.parser, "Empty doc section '%s'"
- % self.section.name)
- self.section = None
+ if self._section:
+ text = self._section.text = self._section.text.strip()
+ if self._section.name and (not text or text.isspace()):
+ raise QAPIParseError(self._parser, "Empty doc section '%s'"
+ % self._section.name)
+ self._section = None
def _append_freeform(self, line):
- in_arg = isinstance(self.section, QAPIDoc.ArgSection)
- if (in_arg and self.section.content
- and not self.section.content[-1]
+ in_arg = isinstance(self._section, QAPIDoc.ArgSection)
+ if (in_arg and self._section.text.endswith('\n\n')
and line and not line[0].isspace()):
self._start_section()
- if (in_arg or not self.section.name
- or not self.section.name.startswith('Example')):
+ if (in_arg or not self._section.name
+ or not self._section.name.startswith('Example')):
line = line.strip()
match = re.match(r'(@\S+:)', line)
if match:
- raise QAPIParseError(self.parser,
+ raise QAPIParseError(self._parser,
"'%s' not allowed in free-form documentation"
% match.group(1))
- # TODO Drop this once the dust has settled
- if (isinstance(self.section, QAPIDoc.ArgSection)
- and '#optional' in line):
- raise QAPISemError(self.info, "Please drop the #optional tag")
- self.section.append(line)
+ self._section.append(line)
def connect_member(self, member):
if member.name not in self.args:
@@ -265,8 +257,7 @@ class QAPISchemaParser(object):
def __init__(self, fp, previously_included=[], incl_info=None):
abs_fname = os.path.abspath(fp.name)
- fname = fp.name
- self.fname = fname
+ self.fname = fp.name
previously_included.append(abs_fname)
self.incl_info = incl_info
self.src = fp.read()
@@ -277,21 +268,21 @@ class QAPISchemaParser(object):
self.line_pos = 0
self.exprs = []
self.docs = []
- self.cur_doc = None
self.accept()
+ cur_doc = None
while self.tok is not None:
- info = {'file': fname, 'line': self.line,
+ info = {'file': self.fname, 'line': self.line,
'parent': self.incl_info}
if self.tok == '#':
- self.reject_expr_doc()
- self.cur_doc = self.get_doc(info)
- self.docs.append(self.cur_doc)
+ self.reject_expr_doc(cur_doc)
+ cur_doc = self.get_doc(info)
+ self.docs.append(cur_doc)
continue
expr = self.get_expr(False)
if 'include' in expr:
- self.reject_expr_doc()
+ self.reject_expr_doc(cur_doc)
if len(expr) != 1:
raise QAPISemError(info, "Invalid 'include' directive")
include = expr['include']
@@ -301,7 +292,7 @@ class QAPISchemaParser(object):
self._include(include, info, os.path.dirname(abs_fname),
previously_included)
elif "pragma" in expr:
- self.reject_expr_doc()
+ self.reject_expr_doc(cur_doc)
if len(expr) != 1:
raise QAPISemError(info, "Invalid 'pragma' directive")
pragma = expr['pragma']
@@ -313,22 +304,22 @@ class QAPISchemaParser(object):
else:
expr_elem = {'expr': expr,
'info': info}
- if self.cur_doc:
- if not self.cur_doc.symbol:
+ if cur_doc:
+ if not cur_doc.symbol:
raise QAPISemError(
- self.cur_doc.info,
- "Expression documentation required")
- expr_elem['doc'] = self.cur_doc
+ cur_doc.info, "Expression documentation required")
+ expr_elem['doc'] = cur_doc
self.exprs.append(expr_elem)
- self.cur_doc = None
- self.reject_expr_doc()
+ cur_doc = None
+ self.reject_expr_doc(cur_doc)
- def reject_expr_doc(self):
- if self.cur_doc and self.cur_doc.symbol:
+ @staticmethod
+ def reject_expr_doc(doc):
+ if doc and doc.symbol:
raise QAPISemError(
- self.cur_doc.info,
+ doc.info,
"Documentation for '%s' is not followed by the definition"
- % self.cur_doc.symbol)
+ % doc.symbol)
def _include(self, include, info, base_dir, previously_included):
incl_abs_fname = os.path.join(base_dir, include)
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index a317526e51..92e2af2cd6 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -13,7 +13,6 @@ MSG_FMT = """
@deftypefn {type} {{}} {name}
{body}
-
@end deftypefn
""".format
@@ -22,7 +21,6 @@ TYPE_FMT = """
@deftp {{{type}}} {name}
{body}
-
@end deftp
""".format
@@ -74,7 +72,7 @@ def texi_format(doc):
- 1. or 1): generates an @enumerate @item
- */-: generates an @itemize list
"""
- lines = []
+ ret = ''
doc = subst_braces(doc)
doc = subst_vars(doc)
doc = subst_emph(doc)
@@ -100,32 +98,32 @@ def texi_format(doc):
line = '@subsection ' + line[3:]
elif re.match(r'^([0-9]*\.) ', line):
if not inlist:
- lines.append('@enumerate')
+ ret += '@enumerate\n'
inlist = 'enumerate'
+ ret += '@item\n'
line = line[line.find(' ')+1:]
- lines.append('@item')
elif re.match(r'^[*-] ', line):
if not inlist:
- lines.append('@itemize %s' % {'*': '@bullet',
- '-': '@minus'}[line[0]])
+ ret += '@itemize %s\n' % {'*': '@bullet',
+ '-': '@minus'}[line[0]]
inlist = 'itemize'
- lines.append('@item')
+ ret += '@item\n'
line = line[2:]
elif lastempty and inlist:
- lines.append('@end %s\n' % inlist)
+ ret += '@end %s\n\n' % inlist
inlist = ''
lastempty = empty
- lines.append(line)
+ ret += line + '\n'
if inlist:
- lines.append('@end %s\n' % inlist)
- return '\n'.join(lines)
+ ret += '@end %s\n\n' % inlist
+ return ret
def texi_body(doc):
"""Format the main documentation body"""
- return texi_format(str(doc.body)) + '\n'
+ return texi_format(doc.body.text)
def texi_enum_value(value):
@@ -149,15 +147,16 @@ def texi_members(doc, what, base, variants, member_func):
items = ''
for section in doc.args.itervalues():
# TODO Drop fallbacks when undocumented members are outlawed
- if section.content:
- desc = texi_format(str(section))
+ if section.text:
+ desc = texi_format(section.text)
elif (variants and variants.tag_member == section.member
and not section.member.type.doc_type()):
values = section.member.type.member_names()
- desc = 'One of ' + ', '.join(['@t{"%s"}' % v for v in values])
+ members_text = ', '.join(['@t{"%s"}' % v for v in values])
+ desc = 'One of ' + members_text + '\n'
else:
- desc = 'Not documented'
- items += member_func(section.member) + desc + '\n'
+ desc = 'Not documented\n'
+ items += member_func(section.member) + desc
if base:
items += '@item The members of @code{%s}\n' % base.doc_type()
if variants:
@@ -180,16 +179,13 @@ def texi_sections(doc):
"""Format additional sections following arguments"""
body = ''
for section in doc.sections:
- name, doc = (section.name, str(section))
- func = texi_format
- if name.startswith('Example'):
- func = texi_example
-
- if name:
+ if section.name:
# prefer @b over @strong, so txt doesn't translate it to *Foo:*
- body += '\n\n@b{%s:}\n' % name
-
- body += func(doc)
+ body += '\n@b{%s:}\n' % section.name
+ if section.name and section.name.startswith('Example'):
+ body += texi_example(section.text)
+ else:
+ body += texi_format(section.text)
return body
@@ -210,8 +206,6 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
def visit_enum_type(self, name, info, values, prefix):
doc = self.cur_doc
- if self.out:
- self.out += '\n'
self.out += TYPE_FMT(type='Enum',
name=doc.symbol,
body=texi_entity(doc, 'Values',
@@ -221,16 +215,12 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
doc = self.cur_doc
if base and base.is_implicit():
base = None
- if self.out:
- self.out += '\n'
self.out += TYPE_FMT(type='Object',
name=doc.symbol,
body=texi_entity(doc, 'Members', base, variants))
def visit_alternate_type(self, name, info, variants):
doc = self.cur_doc
- if self.out:
- self.out += '\n'
self.out += TYPE_FMT(type='Alternate',
name=doc.symbol,
body=texi_entity(doc, 'Members'))
@@ -238,11 +228,10 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
def visit_command(self, name, info, arg_type, ret_type,
gen, success_response, boxed):
doc = self.cur_doc
- if self.out:
- self.out += '\n'
if boxed:
body = texi_body(doc)
- body += '\n@b{Arguments:} the members of @code{%s}' % arg_type.name
+ body += ('\n@b{Arguments:} the members of @code{%s}\n'
+ % arg_type.name)
body += texi_sections(doc)
else:
body = texi_entity(doc, 'Arguments')
@@ -252,13 +241,13 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
def visit_event(self, name, info, arg_type, boxed):
doc = self.cur_doc
- if self.out:
- self.out += '\n'
self.out += MSG_FMT(type='Event',
name=doc.symbol,
body=texi_entity(doc, 'Arguments'))
def symbol(self, doc, entity):
+ if self.out:
+ self.out += '\n'
self.cur_doc = doc
entity.visit(self)
self.cur_doc = None
diff --git a/tests/Makefile.include b/tests/Makefile.include
index b4bcc872f2..f8e20d9f5d 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -416,6 +416,7 @@ qapi-schema += command-int.json
qapi-schema += comments.json
qapi-schema += doc-bad-alternate-member.json
qapi-schema += doc-bad-command-arg.json
+qapi-schema += doc-bad-section.json
qapi-schema += doc-bad-symbol.json
qapi-schema += doc-bad-union-member.json
qapi-schema += doc-before-include.json
@@ -433,10 +434,10 @@ qapi-schema += doc-invalid-end2.json
qapi-schema += doc-invalid-return.json
qapi-schema += doc-invalid-section.json
qapi-schema += doc-invalid-start.json
-qapi-schema += doc-missing.json
qapi-schema += doc-missing-colon.json
qapi-schema += doc-missing-expr.json
qapi-schema += doc-missing-space.json
+qapi-schema += doc-missing.json
qapi-schema += doc-no-symbol.json
qapi-schema += double-data.json
qapi-schema += double-type.json
diff --git a/tests/qapi-schema/doc-bad-section.err b/tests/qapi-schema/doc-bad-section.err
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-section.err
diff --git a/tests/qapi-schema/doc-bad-section.exit b/tests/qapi-schema/doc-bad-section.exit
new file mode 100644
index 0000000000..573541ac97
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-section.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/doc-bad-section.json b/tests/qapi-schema/doc-bad-section.json
new file mode 100644
index 0000000000..560df4b087
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-section.json
@@ -0,0 +1,11 @@
+# = section within an expression comment
+# BUG: not rejected
+
+##
+# @Enum:
+# == Produces *invalid* texinfo
+# @one: The _one_ {and only}
+#
+# @two is undocumented
+##
+{ 'enum': 'Enum', 'data': [ 'one', 'two' ] }
diff --git a/tests/qapi-schema/doc-bad-section.out b/tests/qapi-schema/doc-bad-section.out
new file mode 100644
index 0000000000..089bde1381
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-section.out
@@ -0,0 +1,13 @@
+enum Enum ['one', 'two']
+enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+ prefix QTYPE
+object q_empty
+doc symbol=Enum
+ body=
+== Produces *invalid* texinfo
+ arg=one
+The _one_ {and only}
+ arg=two
+
+ section=None
+@two is undocumented
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index cfdc0a8a81..97ab4625ff 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -51,7 +51,6 @@
##
# @Enum:
-# == Produces *invalid* texinfo
# @one: The _one_ {and only}
#
# @two is undocumented
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 63ca25a8b9..1d2c250527 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -77,12 +77,12 @@ Examples:
- {braces}
doc symbol=Enum
body=
-== Produces *invalid* texinfo
+
arg=one
The _one_ {and only}
arg=two
- section=
+ section=None
@two is undocumented
doc symbol=Base
body=
diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi
index c410626e4a..1778312581 100644
--- a/tests/qapi-schema/doc-good.texi
+++ b/tests/qapi-schema/doc-good.texi
@@ -76,7 +76,7 @@ Examples:
@deftp {Enum} Enum
-@subsection Produces @strong{invalid} texinfo
+
@b{Values:}
@table @asis
@@ -101,7 +101,6 @@ Not documented
the first member
@end table
-
@end deftp
@@ -118,7 +117,6 @@ Another paragraph (but no @code{var}: line)
Not documented
@end table
-
@end deftp
@@ -127,7 +125,6 @@ Not documented
-
@end deftp
@@ -143,7 +140,6 @@ Not documented
@item The members of @code{Variant2} when @code{base1} is @t{"two"}
@end table
-
@end deftp
@@ -160,7 +156,6 @@ One of @t{"one"}, @t{"two"}
@item @code{data: Variant2} when @code{type} is @t{"two"}
@end table
-
@end deftp
@@ -182,7 +177,6 @@ argument
Not documented
@end table
-
@b{Note:}
@code{arg3} is undocumented
@@ -209,14 +203,12 @@ Duis aute irure dolor
<- out
@end example
-
@b{Examples:}
@example
- *verbatim*
- @{braces@}
@end example
-
@b{Since:}
2.10
@@ -237,7 +229,6 @@ If you're bored enough to read this, go see a video of boxed cats
<- out
@end example
-
@end deftypefn
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index c7724d3437..fe0ca08d78 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -61,8 +61,8 @@ for doc in schema.docs:
print 'doc symbol=%s' % doc.symbol
else:
print 'doc freeform'
- print ' body=\n%s' % doc.body
+ print ' body=\n%s' % doc.body.text
for arg, section in doc.args.iteritems():
- print ' arg=%s\n%s' % (arg, section)
+ print ' arg=%s\n%s' % (arg, section.text)
for section in doc.sections:
- print ' section=%s\n%s' % (section.name, section)
+ print ' section=%s\n%s' % (section.name, section.text)