target/ppc: Fix lxv/stxv MSR facility check
[qemu/ar7.git] / docs / sphinx / hxtool.py
blob3729084a36c782b2c87b760b9cd22b0f4a0de380
1 # coding=utf-8
3 # QEMU hxtool .hx file parsing extension
5 # Copyright (c) 2020 Linaro
7 # This work is licensed under the terms of the GNU GPLv2 or later.
8 # See the COPYING file in the top-level directory.
9 """hxtool is a Sphinx extension that implements the hxtool-doc directive"""
11 # The purpose of this extension is to read fragments of rST
12 # from .hx files, and insert them all into the current document.
13 # The rST fragments are delimited by SRST/ERST lines.
14 # The conf.py file must set the hxtool_srctree config value to
15 # the root of the QEMU source tree.
16 # Each hxtool-doc:: directive takes one argument which is the
17 # path of the .hx file to process, relative to the source tree.
19 import os
20 import re
21 from enum import Enum
23 from docutils import nodes
24 from docutils.statemachine import ViewList
25 from docutils.parsers.rst import directives, Directive
26 from sphinx.errors import ExtensionError
27 from sphinx.util.nodes import nested_parse_with_titles
28 import sphinx
30 # Sphinx up to 1.6 uses AutodocReporter; 1.7 and later
31 # use switch_source_input. Check borrowed from kerneldoc.py.
32 Use_SSI = sphinx.__version__[:3] >= '1.7'
33 if Use_SSI:
34 from sphinx.util.docutils import switch_source_input
35 else:
36 from sphinx.ext.autodoc import AutodocReporter
38 __version__ = '1.0'
40 # We parse hx files with a state machine which may be in one of two
41 # states: reading the C code fragment, or inside a rST fragment.
42 class HxState(Enum):
43 CTEXT = 1
44 RST = 2
46 def serror(file, lnum, errtext):
47 """Raise an exception giving a user-friendly syntax error message"""
48 raise ExtensionError('%s line %d: syntax error: %s' % (file, lnum, errtext))
50 def parse_directive(line):
51 """Return first word of line, if any"""
52 return re.split(r'\W', line)[0]
54 def parse_defheading(file, lnum, line):
55 """Handle a DEFHEADING directive"""
56 # The input should be "DEFHEADING(some string)", though note that
57 # the 'some string' could be the empty string. If the string is
58 # empty we ignore the directive -- these are used only to add
59 # blank lines in the plain-text content of the --help output.
61 # Return the heading text. We strip out any trailing ':' for
62 # consistency with other headings in the rST documentation.
63 match = re.match(r'DEFHEADING\((.*?):?\)', line)
64 if match is None:
65 serror(file, lnum, "Invalid DEFHEADING line")
66 return match.group(1)
68 def parse_archheading(file, lnum, line):
69 """Handle an ARCHHEADING directive"""
70 # The input should be "ARCHHEADING(some string, other arg)",
71 # though note that the 'some string' could be the empty string.
72 # As with DEFHEADING, empty string ARCHHEADINGs will be ignored.
74 # Return the heading text. We strip out any trailing ':' for
75 # consistency with other headings in the rST documentation.
76 match = re.match(r'ARCHHEADING\((.*?):?,.*\)', line)
77 if match is None:
78 serror(file, lnum, "Invalid ARCHHEADING line")
79 return match.group(1)
81 def parse_srst(file, lnum, line):
82 """Handle an SRST directive"""
83 # The input should be either "SRST", or "SRST(label)".
84 match = re.match(r'SRST(\((.*?)\))?', line)
85 if match is None:
86 serror(file, lnum, "Invalid SRST line")
87 return match.group(2)
89 class HxtoolDocDirective(Directive):
90 """Extract rST fragments from the specified .hx file"""
91 required_argument = 1
92 optional_arguments = 1
93 option_spec = {
94 'hxfile': directives.unchanged_required
96 has_content = False
98 def run(self):
99 env = self.state.document.settings.env
100 hxfile = env.config.hxtool_srctree + '/' + self.arguments[0]
102 # Tell sphinx of the dependency
103 env.note_dependency(os.path.abspath(hxfile))
105 state = HxState.CTEXT
106 # We build up lines of rST in this ViewList, which we will
107 # later put into a 'section' node.
108 rstlist = ViewList()
109 current_node = None
110 node_list = []
112 with open(hxfile) as f:
113 lines = (l.rstrip() for l in f)
114 for lnum, line in enumerate(lines, 1):
115 directive = parse_directive(line)
117 if directive == 'HXCOMM':
118 pass
119 elif directive == 'SRST':
120 if state == HxState.RST:
121 serror(hxfile, lnum, 'expected ERST, found SRST')
122 else:
123 state = HxState.RST
124 label = parse_srst(hxfile, lnum, line)
125 if label:
126 rstlist.append("", hxfile, lnum - 1)
127 # Build label as _DOCNAME-HXNAME-LABEL
128 hx = os.path.splitext(os.path.basename(hxfile))[0]
129 refline = ".. _" + env.docname + "-" + hx + \
130 "-" + label + ":"
131 rstlist.append(refline, hxfile, lnum - 1)
132 elif directive == 'ERST':
133 if state == HxState.CTEXT:
134 serror(hxfile, lnum, 'expected SRST, found ERST')
135 else:
136 state = HxState.CTEXT
137 elif directive == 'DEFHEADING' or directive == 'ARCHHEADING':
138 if directive == 'DEFHEADING':
139 heading = parse_defheading(hxfile, lnum, line)
140 else:
141 heading = parse_archheading(hxfile, lnum, line)
142 if heading == "":
143 continue
144 # Put the accumulated rST into the previous node,
145 # and then start a fresh section with this heading.
146 if len(rstlist) > 0:
147 if current_node is None:
148 # We had some rST fragments before the first
149 # DEFHEADING. We don't have a section to put
150 # these in, so rather than magicing up a section,
151 # make it a syntax error.
152 serror(hxfile, lnum,
153 'first DEFHEADING must precede all rST text')
154 self.do_parse(rstlist, current_node)
155 rstlist = ViewList()
156 if current_node is not None:
157 node_list.append(current_node)
158 section_id = 'hxtool-%d' % env.new_serialno('hxtool')
159 current_node = nodes.section(ids=[section_id])
160 current_node += nodes.title(heading, heading)
161 else:
162 # Not a directive: put in output if we are in rST fragment
163 if state == HxState.RST:
164 # Sphinx counts its lines from 0
165 rstlist.append(line, hxfile, lnum - 1)
167 if current_node is None:
168 # We don't have multiple sections, so just parse the rst
169 # fragments into a dummy node so we can return the children.
170 current_node = nodes.section()
171 self.do_parse(rstlist, current_node)
172 return current_node.children
173 else:
174 # Put the remaining accumulated rST into the last section, and
175 # return all the sections.
176 if len(rstlist) > 0:
177 self.do_parse(rstlist, current_node)
178 node_list.append(current_node)
179 return node_list
181 # This is from kerneldoc.py -- it works around an API change in
182 # Sphinx between 1.6 and 1.7. Unlike kerneldoc.py, we use
183 # sphinx.util.nodes.nested_parse_with_titles() rather than the
184 # plain self.state.nested_parse(), and so we can drop the saving
185 # of title_styles and section_level that kerneldoc.py does,
186 # because nested_parse_with_titles() does that for us.
187 def do_parse(self, result, node):
188 if Use_SSI:
189 with switch_source_input(self.state, result):
190 nested_parse_with_titles(self.state, result, node)
191 else:
192 save = self.state.memo.reporter
193 self.state.memo.reporter = AutodocReporter(result, self.state.memo.reporter)
194 try:
195 nested_parse_with_titles(self.state, result, node)
196 finally:
197 self.state.memo.reporter = save
199 def setup(app):
200 """ Register hxtool-doc directive with Sphinx"""
201 app.add_config_value('hxtool_srctree', None, 'env')
202 app.add_directive('hxtool-doc', HxtoolDocDirective)
204 return dict(
205 version = __version__,
206 parallel_read_safe = True,
207 parallel_write_safe = True