QAPI patches for 2017-12-20

-----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJaOrGoAAoJEDhwtADrkYZTjBsQALHz4uDvjrTVrocmuNiflPmi
 7WjRbasaaRN9xYb41Aju3O5+019fMhQf1WX9g99ZAdnFd+mFoSIfOhL/wKm4ZQtE
 8pcxycdoEV7qeOECmAL8z0Gfnxog/eLzuSULsarppqY9Iu69VnvZJS6vpaRMqmpU
 7spgnxfKTc+a1VphMt9h3mQUHzIo0MY99/AKorneeRODM4SpogfJaQLnFZlztShj
 REudJXCiLbjYvo0voCvntdzQEK5EoH174n+iZlN4hFaJmTQd42KyTGzixastmMuN
 HVPU2dVPCes2DUJy+xZzQ0JmFTDYWqrsZbzED9zeneabuTonbdcg67TzAF99jFpv
 qP2n78sKBU0cM5AdQ5sy/xPGdZYjwB3a+9mKlM7S7xa+ypKS1goC21oRa98S9ceh
 VA2Y2xdLOFhpptdcKfJd5DRjzPflEGmzKkmwNFeTTmhaVN5bo3NR/VEt0gXjaHbQ
 0GNviXf3w0xW2q77usn6PSf7jD5TUV7vTXuFlVBxLPMsA8r2NJ7hfcgjXN4vre+a
 tn4n5SrG0ZghJFjkaYOaiXM39W8x8szKfJm3wZjs8LaqwzL1hw4iFAjdCNOZ6sX+
 Dpa3DC6ohdofknoWO8Z6VMpvHCiJU2vF92ESf3xqMjQixIVeCK3xjaLXAhwhVBtA
 7WpAujw2PBFbeJwl/NL8
 =Y0n9
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2017-12-20' into staging

QAPI patches for 2017-12-20

# gpg: Signature made Wed 20 Dec 2017 18:53:28 GMT
# gpg:                using RSA key 0x3870B400EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867  4E5F 3870 B400 EB91 8653

* remotes/armbru/tags/pull-qapi-2017-12-20:
  qmp: remove qmp_cpu
  qapi-docs: fix a comment typo
  qapi2texi: De-duplicate code to add blank line before symbol
  qapi: Rename QAPIDoc.parser, .section to ._parser, ._section
  qapi2texi: Simplify representation of section text
  qapi: Simplify representation of QAPIDoc section text
  qapi: Unify representation of doc section without name
  qapi2texi: Clean up texi_sections()
  tests/qapi-schema/doc-bad-section: New, factored out of doc-good
  qapi: Make cur_doc local to QAPISchemaParser.__init__()
  qapi: Eliminate QAPISchemaParser.__init__()'s local fname
  qapi: Stop rejecting #optional
  qapi-schema: Fix query-vm-generation-id's doc comment markup

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-12-20 20:38:36 +00:00
commit 4da5c51cac
14 changed files with 111 additions and 131 deletions

View File

@ -63,7 +63,7 @@ Comment text starting with '=' is a section title:
Double the '=' for a subsection title: Double the '=' for a subsection title:
# == Subection title # == Subsection title
'|' denotes examples: '|' denotes examples:

View File

@ -1045,17 +1045,6 @@
## ##
{ 'command': 'system_powerdown' } { '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: # @cpu-add:
# #
@ -3188,7 +3177,7 @@
# #
# Show Virtual Machine Generation ID # Show Virtual Machine Generation ID
# #
# Since 2.9 # Since: 2.9
## ##
{ 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' } { 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' }

5
qmp.c
View File

@ -113,11 +113,6 @@ void qmp_system_powerdown(Error **erp)
qemu_system_powerdown_request(); qemu_system_powerdown_request();
} }
void qmp_cpu(int64_t index, Error **errp)
{
/* Just do nothing */
}
void qmp_cpu_add(int64_t id, Error **errp) void qmp_cpu_add(int64_t id, Error **errp)
{ {
MachineClass *mc; MachineClass *mc;

View File

@ -106,13 +106,10 @@ class QAPIDoc(object):
# optional section name (argument/member or section name) # optional section name (argument/member or section name)
self.name = name self.name = name
# the list of lines for this section # the list of lines for this section
self.content = [] self.text = ''
def append(self, line): def append(self, line):
self.content.append(line) self.text += line.rstrip() + '\n'
def __repr__(self):
return '\n'.join(self.content).strip()
class ArgSection(Section): class ArgSection(Section):
def __init__(self, name): def __init__(self, name):
@ -123,11 +120,11 @@ class QAPIDoc(object):
self.member = member self.member = member
def __init__(self, parser, info): 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. # 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 = None
self.body = QAPIDoc.Section() self.body = QAPIDoc.Section()
@ -136,7 +133,7 @@ class QAPIDoc(object):
# a list of Section # a list of Section
self.sections = [] self.sections = []
# the current section # the current section
self.section = self.body self._section = self.body
def has_section(self, name): def has_section(self, name):
"""Return True if we have a section with this name.""" """Return True if we have a section with this name."""
@ -153,20 +150,20 @@ class QAPIDoc(object):
return return
if line[0] != ' ': if line[0] != ' ':
raise QAPIParseError(self.parser, "Missing space after #") raise QAPIParseError(self._parser, "Missing space after #")
line = line[1:] line = line[1:]
# FIXME not nice: things like '# @foo:' and '# @foo: ' aren't # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't
# recognized, and get silently treated as ordinary text # recognized, and get silently treated as ordinary text
if self.symbol: if self.symbol:
self._append_symbol_line(line) 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(':'): 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] self.symbol = line[1:-1]
# FIXME invalid names other than the empty string aren't flagged # FIXME invalid names other than the empty string aren't flagged
if not self.symbol: if not self.symbol:
raise QAPIParseError(self.parser, "Invalid name") raise QAPIParseError(self._parser, "Invalid name")
else: else:
self._append_freeform(line) self._append_freeform(line)
@ -192,53 +189,48 @@ class QAPIDoc(object):
def _start_args_section(self, name): def _start_args_section(self, name):
# 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")
if name in self.args: if name in self.args:
raise QAPIParseError(self.parser, raise QAPIParseError(self._parser,
"'%s' parameter name duplicated" % name) "'%s' parameter name duplicated" % name)
if self.sections: if self.sections:
raise QAPIParseError(self.parser, raise QAPIParseError(self._parser,
"'@%s:' can't follow '%s' section" "'@%s:' can't follow '%s' section"
% (name, self.sections[0].name)) % (name, self.sections[0].name))
self._end_section() self._end_section()
self.section = QAPIDoc.ArgSection(name) self._section = QAPIDoc.ArgSection(name)
self.args[name] = self.section 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): 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)
self._end_section() self._end_section()
self.section = QAPIDoc.Section(name) self._section = QAPIDoc.Section(name)
self.sections.append(self.section) self.sections.append(self._section)
def _end_section(self): def _end_section(self):
if self.section: if self._section:
contents = str(self.section) text = self._section.text = self._section.text.strip()
if self.section.name and (not contents or contents.isspace()): if self._section.name and (not text or text.isspace()):
raise QAPIParseError(self.parser, "Empty doc section '%s'" raise QAPIParseError(self._parser, "Empty doc section '%s'"
% self.section.name) % self._section.name)
self.section = None self._section = None
def _append_freeform(self, line): def _append_freeform(self, line):
in_arg = isinstance(self.section, QAPIDoc.ArgSection) in_arg = isinstance(self._section, QAPIDoc.ArgSection)
if (in_arg and self.section.content if (in_arg and self._section.text.endswith('\n\n')
and not self.section.content[-1]
and line and not line[0].isspace()): and line and not line[0].isspace()):
self._start_section() self._start_section()
if (in_arg or not self.section.name if (in_arg or not self._section.name
or not self.section.name.startswith('Example')): or not self._section.name.startswith('Example')):
line = line.strip() line = line.strip()
match = re.match(r'(@\S+:)', line) match = re.match(r'(@\S+:)', line)
if match: if match:
raise QAPIParseError(self.parser, raise QAPIParseError(self._parser,
"'%s' not allowed in free-form documentation" "'%s' not allowed in free-form documentation"
% match.group(1)) % match.group(1))
# TODO Drop this once the dust has settled self._section.append(line)
if (isinstance(self.section, QAPIDoc.ArgSection)
and '#optional' in line):
raise QAPISemError(self.info, "Please drop the #optional tag")
self.section.append(line)
def connect_member(self, member): def connect_member(self, member):
if member.name not in self.args: if member.name not in self.args:
@ -265,8 +257,7 @@ class QAPISchemaParser(object):
def __init__(self, fp, previously_included=[], incl_info=None): def __init__(self, fp, previously_included=[], incl_info=None):
abs_fname = os.path.abspath(fp.name) abs_fname = os.path.abspath(fp.name)
fname = fp.name self.fname = fp.name
self.fname = fname
previously_included.append(abs_fname) previously_included.append(abs_fname)
self.incl_info = incl_info self.incl_info = incl_info
self.src = fp.read() self.src = fp.read()
@ -277,21 +268,21 @@ class QAPISchemaParser(object):
self.line_pos = 0 self.line_pos = 0
self.exprs = [] self.exprs = []
self.docs = [] self.docs = []
self.cur_doc = None
self.accept() self.accept()
cur_doc = None
while self.tok is not None: while self.tok is not None:
info = {'file': fname, 'line': self.line, info = {'file': self.fname, 'line': self.line,
'parent': self.incl_info} 'parent': self.incl_info}
if self.tok == '#': if self.tok == '#':
self.reject_expr_doc() self.reject_expr_doc(cur_doc)
self.cur_doc = self.get_doc(info) cur_doc = self.get_doc(info)
self.docs.append(self.cur_doc) self.docs.append(cur_doc)
continue continue
expr = self.get_expr(False) expr = self.get_expr(False)
if 'include' in expr: if 'include' in expr:
self.reject_expr_doc() self.reject_expr_doc(cur_doc)
if len(expr) != 1: if len(expr) != 1:
raise QAPISemError(info, "Invalid 'include' directive") raise QAPISemError(info, "Invalid 'include' directive")
include = expr['include'] include = expr['include']
@ -301,7 +292,7 @@ class QAPISchemaParser(object):
self._include(include, info, os.path.dirname(abs_fname), self._include(include, info, os.path.dirname(abs_fname),
previously_included) previously_included)
elif "pragma" in expr: elif "pragma" in expr:
self.reject_expr_doc() self.reject_expr_doc(cur_doc)
if len(expr) != 1: if len(expr) != 1:
raise QAPISemError(info, "Invalid 'pragma' directive") raise QAPISemError(info, "Invalid 'pragma' directive")
pragma = expr['pragma'] pragma = expr['pragma']
@ -313,22 +304,22 @@ class QAPISchemaParser(object):
else: else:
expr_elem = {'expr': expr, expr_elem = {'expr': expr,
'info': info} 'info': info}
if self.cur_doc: if cur_doc:
if not self.cur_doc.symbol: if not cur_doc.symbol:
raise QAPISemError( raise QAPISemError(
self.cur_doc.info, cur_doc.info, "Expression documentation required")
"Expression documentation required") expr_elem['doc'] = cur_doc
expr_elem['doc'] = self.cur_doc
self.exprs.append(expr_elem) self.exprs.append(expr_elem)
self.cur_doc = None cur_doc = None
self.reject_expr_doc() self.reject_expr_doc(cur_doc)
def reject_expr_doc(self): @staticmethod
if self.cur_doc and self.cur_doc.symbol: def reject_expr_doc(doc):
if doc and doc.symbol:
raise QAPISemError( raise QAPISemError(
self.cur_doc.info, doc.info,
"Documentation for '%s' is not followed by the definition" "Documentation for '%s' is not followed by the definition"
% self.cur_doc.symbol) % doc.symbol)
def _include(self, include, info, base_dir, previously_included): def _include(self, include, info, base_dir, previously_included):
incl_abs_fname = os.path.join(base_dir, include) incl_abs_fname = os.path.join(base_dir, include)

View File

@ -13,7 +13,6 @@ MSG_FMT = """
@deftypefn {type} {{}} {name} @deftypefn {type} {{}} {name}
{body} {body}
@end deftypefn @end deftypefn
""".format """.format
@ -22,7 +21,6 @@ TYPE_FMT = """
@deftp {{{type}}} {name} @deftp {{{type}}} {name}
{body} {body}
@end deftp @end deftp
""".format """.format
@ -74,7 +72,7 @@ def texi_format(doc):
- 1. or 1): generates an @enumerate @item - 1. or 1): generates an @enumerate @item
- */-: generates an @itemize list - */-: generates an @itemize list
""" """
lines = [] ret = ''
doc = subst_braces(doc) doc = subst_braces(doc)
doc = subst_vars(doc) doc = subst_vars(doc)
doc = subst_emph(doc) doc = subst_emph(doc)
@ -100,32 +98,32 @@ def texi_format(doc):
line = '@subsection ' + line[3:] line = '@subsection ' + line[3:]
elif re.match(r'^([0-9]*\.) ', line): elif re.match(r'^([0-9]*\.) ', line):
if not inlist: if not inlist:
lines.append('@enumerate') ret += '@enumerate\n'
inlist = 'enumerate' inlist = 'enumerate'
ret += '@item\n'
line = line[line.find(' ')+1:] line = line[line.find(' ')+1:]
lines.append('@item')
elif re.match(r'^[*-] ', line): elif re.match(r'^[*-] ', line):
if not inlist: if not inlist:
lines.append('@itemize %s' % {'*': '@bullet', ret += '@itemize %s\n' % {'*': '@bullet',
'-': '@minus'}[line[0]]) '-': '@minus'}[line[0]]
inlist = 'itemize' inlist = 'itemize'
lines.append('@item') ret += '@item\n'
line = line[2:] line = line[2:]
elif lastempty and inlist: elif lastempty and inlist:
lines.append('@end %s\n' % inlist) ret += '@end %s\n\n' % inlist
inlist = '' inlist = ''
lastempty = empty lastempty = empty
lines.append(line) ret += line + '\n'
if inlist: if inlist:
lines.append('@end %s\n' % inlist) ret += '@end %s\n\n' % inlist
return '\n'.join(lines) return ret
def texi_body(doc): def texi_body(doc):
"""Format the main documentation body""" """Format the main documentation body"""
return texi_format(str(doc.body)) + '\n' return texi_format(doc.body.text)
def texi_enum_value(value): def texi_enum_value(value):
@ -149,15 +147,16 @@ def texi_members(doc, what, base, variants, member_func):
items = '' items = ''
for section in doc.args.itervalues(): for section in doc.args.itervalues():
# TODO Drop fallbacks when undocumented members are outlawed # TODO Drop fallbacks when undocumented members are outlawed
if section.content: if section.text:
desc = texi_format(str(section)) desc = texi_format(section.text)
elif (variants and variants.tag_member == section.member elif (variants and variants.tag_member == section.member
and not section.member.type.doc_type()): and not section.member.type.doc_type()):
values = section.member.type.member_names() 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: else:
desc = 'Not documented' desc = 'Not documented\n'
items += member_func(section.member) + desc + '\n' items += member_func(section.member) + desc
if base: if base:
items += '@item The members of @code{%s}\n' % base.doc_type() items += '@item The members of @code{%s}\n' % base.doc_type()
if variants: if variants:
@ -180,16 +179,13 @@ def texi_sections(doc):
"""Format additional sections following arguments""" """Format additional sections following arguments"""
body = '' body = ''
for section in doc.sections: for section in doc.sections:
name, doc = (section.name, str(section)) if section.name:
func = texi_format
if name.startswith('Example'):
func = texi_example
if name:
# prefer @b over @strong, so txt doesn't translate it to *Foo:* # prefer @b over @strong, so txt doesn't translate it to *Foo:*
body += '\n\n@b{%s:}\n' % name body += '\n@b{%s:}\n' % section.name
if section.name and section.name.startswith('Example'):
body += func(doc) body += texi_example(section.text)
else:
body += texi_format(section.text)
return body return body
@ -210,8 +206,6 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
def visit_enum_type(self, name, info, values, prefix): def visit_enum_type(self, name, info, values, prefix):
doc = self.cur_doc doc = self.cur_doc
if self.out:
self.out += '\n'
self.out += TYPE_FMT(type='Enum', self.out += TYPE_FMT(type='Enum',
name=doc.symbol, name=doc.symbol,
body=texi_entity(doc, 'Values', body=texi_entity(doc, 'Values',
@ -221,16 +215,12 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
doc = self.cur_doc doc = self.cur_doc
if base and base.is_implicit(): if base and base.is_implicit():
base = None base = None
if self.out:
self.out += '\n'
self.out += TYPE_FMT(type='Object', self.out += TYPE_FMT(type='Object',
name=doc.symbol, name=doc.symbol,
body=texi_entity(doc, 'Members', base, variants)) body=texi_entity(doc, 'Members', base, variants))
def visit_alternate_type(self, name, info, variants): def visit_alternate_type(self, name, info, variants):
doc = self.cur_doc doc = self.cur_doc
if self.out:
self.out += '\n'
self.out += TYPE_FMT(type='Alternate', self.out += TYPE_FMT(type='Alternate',
name=doc.symbol, name=doc.symbol,
body=texi_entity(doc, 'Members')) body=texi_entity(doc, 'Members'))
@ -238,11 +228,10 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
def visit_command(self, name, info, arg_type, ret_type, def visit_command(self, name, info, arg_type, ret_type,
gen, success_response, boxed): gen, success_response, boxed):
doc = self.cur_doc doc = self.cur_doc
if self.out:
self.out += '\n'
if boxed: if boxed:
body = texi_body(doc) 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) body += texi_sections(doc)
else: else:
body = texi_entity(doc, 'Arguments') body = texi_entity(doc, 'Arguments')
@ -252,13 +241,13 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
def visit_event(self, name, info, arg_type, boxed): def visit_event(self, name, info, arg_type, boxed):
doc = self.cur_doc doc = self.cur_doc
if self.out:
self.out += '\n'
self.out += MSG_FMT(type='Event', self.out += MSG_FMT(type='Event',
name=doc.symbol, name=doc.symbol,
body=texi_entity(doc, 'Arguments')) body=texi_entity(doc, 'Arguments'))
def symbol(self, doc, entity): def symbol(self, doc, entity):
if self.out:
self.out += '\n'
self.cur_doc = doc self.cur_doc = doc
entity.visit(self) entity.visit(self)
self.cur_doc = None self.cur_doc = None

View File

@ -416,6 +416,7 @@ qapi-schema += command-int.json
qapi-schema += comments.json qapi-schema += comments.json
qapi-schema += doc-bad-alternate-member.json qapi-schema += doc-bad-alternate-member.json
qapi-schema += doc-bad-command-arg.json qapi-schema += doc-bad-command-arg.json
qapi-schema += doc-bad-section.json
qapi-schema += doc-bad-symbol.json qapi-schema += doc-bad-symbol.json
qapi-schema += doc-bad-union-member.json qapi-schema += doc-bad-union-member.json
qapi-schema += doc-before-include.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-return.json
qapi-schema += doc-invalid-section.json qapi-schema += doc-invalid-section.json
qapi-schema += doc-invalid-start.json qapi-schema += doc-invalid-start.json
qapi-schema += doc-missing.json
qapi-schema += doc-missing-colon.json qapi-schema += doc-missing-colon.json
qapi-schema += doc-missing-expr.json qapi-schema += doc-missing-expr.json
qapi-schema += doc-missing-space.json qapi-schema += doc-missing-space.json
qapi-schema += doc-missing.json
qapi-schema += doc-no-symbol.json qapi-schema += doc-no-symbol.json
qapi-schema += double-data.json qapi-schema += double-data.json
qapi-schema += double-type.json qapi-schema += double-type.json

View File

View File

@ -0,0 +1 @@
0

View File

@ -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' ] }

View File

@ -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

View File

@ -51,7 +51,6 @@
## ##
# @Enum: # @Enum:
# == Produces *invalid* texinfo
# @one: The _one_ {and only} # @one: The _one_ {and only}
# #
# @two is undocumented # @two is undocumented

View File

@ -77,12 +77,12 @@ Examples:
- {braces} - {braces}
doc symbol=Enum doc symbol=Enum
body= body=
== Produces *invalid* texinfo
arg=one arg=one
The _one_ {and only} The _one_ {and only}
arg=two arg=two
section= section=None
@two is undocumented @two is undocumented
doc symbol=Base doc symbol=Base
body= body=

View File

@ -76,7 +76,7 @@ Examples:
@deftp {Enum} Enum @deftp {Enum} Enum
@subsection Produces @strong{invalid} texinfo
@b{Values:} @b{Values:}
@table @asis @table @asis
@ -101,7 +101,6 @@ Not documented
the first member the first member
@end table @end table
@end deftp @end deftp
@ -118,7 +117,6 @@ Another paragraph (but no @code{var}: line)
Not documented Not documented
@end table @end table
@end deftp @end deftp
@ -127,7 +125,6 @@ Not documented
@end deftp @end deftp
@ -143,7 +140,6 @@ Not documented
@item The members of @code{Variant2} when @code{base1} is @t{"two"} @item The members of @code{Variant2} when @code{base1} is @t{"two"}
@end table @end table
@end deftp @end deftp
@ -160,7 +156,6 @@ One of @t{"one"}, @t{"two"}
@item @code{data: Variant2} when @code{type} is @t{"two"} @item @code{data: Variant2} when @code{type} is @t{"two"}
@end table @end table
@end deftp @end deftp
@ -182,7 +177,6 @@ argument
Not documented Not documented
@end table @end table
@b{Note:} @b{Note:}
@code{arg3} is undocumented @code{arg3} is undocumented
@ -209,14 +203,12 @@ Duis aute irure dolor
<- out <- out
@end example @end example
@b{Examples:} @b{Examples:}
@example @example
- *verbatim* - *verbatim*
- @{braces@} - @{braces@}
@end example @end example
@b{Since:} @b{Since:}
2.10 2.10
@ -237,7 +229,6 @@ If you're bored enough to read this, go see a video of boxed cats
<- out <- out
@end example @end example
@end deftypefn @end deftypefn

View File

@ -61,8 +61,8 @@ for doc in schema.docs:
print 'doc symbol=%s' % doc.symbol print 'doc symbol=%s' % doc.symbol
else: else:
print 'doc freeform' print 'doc freeform'
print ' body=\n%s' % doc.body print ' body=\n%s' % doc.body.text
for arg, section in doc.args.iteritems(): 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: for section in doc.sections:
print ' section=%s\n%s' % (section.name, section) print ' section=%s\n%s' % (section.name, section.text)