Sphinx 7.2.6__py3-none-any.whl → 7.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Sphinx might be problematic. Click here for more details.

Files changed (388) hide show
  1. sphinx/__init__.py +8 -9
  2. sphinx/addnodes.py +31 -28
  3. sphinx/application.py +9 -15
  4. sphinx/builders/__init__.py +5 -6
  5. sphinx/builders/_epub_base.py +17 -9
  6. sphinx/builders/changes.py +10 -5
  7. sphinx/builders/dirhtml.py +4 -2
  8. sphinx/builders/dummy.py +3 -2
  9. sphinx/builders/epub3.py +5 -3
  10. sphinx/builders/gettext.py +24 -7
  11. sphinx/builders/html/__init__.py +88 -96
  12. sphinx/builders/html/_assets.py +16 -16
  13. sphinx/builders/html/transforms.py +4 -2
  14. sphinx/builders/latex/__init__.py +40 -33
  15. sphinx/builders/latex/nodes.py +6 -2
  16. sphinx/builders/latex/transforms.py +17 -8
  17. sphinx/builders/latex/util.py +1 -1
  18. sphinx/builders/linkcheck.py +86 -27
  19. sphinx/builders/manpage.py +8 -6
  20. sphinx/builders/singlehtml.py +5 -4
  21. sphinx/builders/texinfo.py +18 -14
  22. sphinx/builders/text.py +3 -2
  23. sphinx/builders/xml.py +5 -2
  24. sphinx/cmd/build.py +119 -76
  25. sphinx/cmd/make_mode.py +4 -9
  26. sphinx/cmd/quickstart.py +13 -16
  27. sphinx/config.py +432 -250
  28. sphinx/deprecation.py +23 -13
  29. sphinx/directives/__init__.py +8 -8
  30. sphinx/directives/code.py +7 -7
  31. sphinx/directives/other.py +23 -13
  32. sphinx/directives/patches.py +7 -6
  33. sphinx/domains/__init__.py +2 -2
  34. sphinx/domains/c/__init__.py +796 -0
  35. sphinx/domains/c/_ast.py +1421 -0
  36. sphinx/domains/c/_ids.py +65 -0
  37. sphinx/domains/c/_parser.py +1048 -0
  38. sphinx/domains/c/_symbol.py +700 -0
  39. sphinx/domains/changeset.py +11 -7
  40. sphinx/domains/citation.py +5 -2
  41. sphinx/domains/cpp/__init__.py +1089 -0
  42. sphinx/domains/cpp/_ast.py +3635 -0
  43. sphinx/domains/cpp/_ids.py +537 -0
  44. sphinx/domains/cpp/_parser.py +2117 -0
  45. sphinx/domains/cpp/_symbol.py +1092 -0
  46. sphinx/domains/index.py +6 -4
  47. sphinx/domains/javascript.py +16 -13
  48. sphinx/domains/math.py +9 -4
  49. sphinx/domains/python/__init__.py +890 -0
  50. sphinx/domains/python/_annotations.py +507 -0
  51. sphinx/domains/python/_object.py +426 -0
  52. sphinx/domains/rst.py +12 -7
  53. sphinx/domains/{std.py → std/__init__.py} +19 -16
  54. sphinx/environment/__init__.py +21 -19
  55. sphinx/environment/adapters/indexentries.py +2 -2
  56. sphinx/environment/adapters/toctree.py +10 -9
  57. sphinx/environment/collectors/__init__.py +6 -3
  58. sphinx/environment/collectors/asset.py +4 -3
  59. sphinx/environment/collectors/dependencies.py +3 -2
  60. sphinx/environment/collectors/metadata.py +6 -5
  61. sphinx/environment/collectors/title.py +3 -2
  62. sphinx/environment/collectors/toctree.py +5 -4
  63. sphinx/errors.py +13 -2
  64. sphinx/events.py +14 -9
  65. sphinx/ext/apidoc.py +9 -11
  66. sphinx/ext/autodoc/__init__.py +105 -71
  67. sphinx/ext/autodoc/directive.py +7 -6
  68. sphinx/ext/autodoc/importer.py +102 -36
  69. sphinx/ext/autodoc/mock.py +7 -5
  70. sphinx/ext/autodoc/preserve_defaults.py +4 -3
  71. sphinx/ext/autodoc/type_comment.py +2 -1
  72. sphinx/ext/autodoc/typehints.py +5 -4
  73. sphinx/ext/autosectionlabel.py +3 -2
  74. sphinx/ext/autosummary/__init__.py +21 -17
  75. sphinx/ext/autosummary/generate.py +9 -9
  76. sphinx/ext/coverage.py +26 -20
  77. sphinx/ext/doctest.py +38 -33
  78. sphinx/ext/duration.py +1 -0
  79. sphinx/ext/extlinks.py +4 -3
  80. sphinx/ext/githubpages.py +3 -2
  81. sphinx/ext/graphviz.py +10 -7
  82. sphinx/ext/ifconfig.py +5 -5
  83. sphinx/ext/imgconverter.py +6 -5
  84. sphinx/ext/imgmath.py +9 -8
  85. sphinx/ext/inheritance_diagram.py +31 -31
  86. sphinx/ext/intersphinx.py +140 -23
  87. sphinx/ext/linkcode.py +3 -2
  88. sphinx/ext/mathjax.py +2 -1
  89. sphinx/ext/napoleon/__init__.py +12 -7
  90. sphinx/ext/napoleon/docstring.py +34 -32
  91. sphinx/ext/todo.py +10 -7
  92. sphinx/ext/viewcode.py +12 -11
  93. sphinx/extension.py +18 -8
  94. sphinx/highlighting.py +39 -20
  95. sphinx/io.py +17 -8
  96. sphinx/jinja2glue.py +16 -15
  97. sphinx/locale/__init__.py +30 -23
  98. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  99. sphinx/locale/ar/LC_MESSAGES/sphinx.po +818 -761
  100. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  101. sphinx/locale/bg/LC_MESSAGES/sphinx.po +811 -754
  102. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  103. sphinx/locale/bn/LC_MESSAGES/sphinx.po +835 -778
  104. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  105. sphinx/locale/ca/LC_MESSAGES/sphinx.po +864 -807
  106. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  107. sphinx/locale/cak/LC_MESSAGES/sphinx.po +816 -759
  108. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  109. sphinx/locale/cs/LC_MESSAGES/sphinx.po +837 -780
  110. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  111. sphinx/locale/cy/LC_MESSAGES/sphinx.po +819 -762
  112. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  113. sphinx/locale/da/LC_MESSAGES/sphinx.po +838 -781
  114. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  115. sphinx/locale/de/LC_MESSAGES/sphinx.po +838 -781
  116. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  117. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +811 -754
  118. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  119. sphinx/locale/el/LC_MESSAGES/sphinx.po +853 -796
  120. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  121. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +811 -754
  122. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +811 -754
  124. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  125. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +856 -799
  126. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  127. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +811 -754
  128. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  129. sphinx/locale/eo/LC_MESSAGES/sphinx.po +820 -763
  130. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  131. sphinx/locale/es/LC_MESSAGES/sphinx.po +856 -799
  132. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  133. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +811 -754
  134. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  135. sphinx/locale/et/LC_MESSAGES/sphinx.po +845 -788
  136. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  137. sphinx/locale/eu/LC_MESSAGES/sphinx.po +837 -780
  138. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  139. sphinx/locale/fa/LC_MESSAGES/sphinx.po +854 -797
  140. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  141. sphinx/locale/fi/LC_MESSAGES/sphinx.po +816 -759
  142. sphinx/locale/fr/LC_MESSAGES/sphinx.js +1 -1
  143. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/fr/LC_MESSAGES/sphinx.po +904 -847
  145. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +811 -754
  147. sphinx/locale/gl/LC_MESSAGES/sphinx.js +54 -54
  148. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  149. sphinx/locale/gl/LC_MESSAGES/sphinx.po +1506 -1449
  150. sphinx/locale/he/LC_MESSAGES/sphinx.js +1 -1
  151. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  152. sphinx/locale/he/LC_MESSAGES/sphinx.po +823 -766
  153. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/hi/LC_MESSAGES/sphinx.po +853 -796
  155. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +811 -754
  157. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  158. sphinx/locale/hr/LC_MESSAGES/sphinx.po +844 -787
  159. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/hu/LC_MESSAGES/sphinx.po +837 -780
  161. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/id/LC_MESSAGES/sphinx.po +854 -797
  163. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  164. sphinx/locale/is/LC_MESSAGES/sphinx.po +811 -754
  165. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/it/LC_MESSAGES/sphinx.po +837 -780
  167. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/ja/LC_MESSAGES/sphinx.po +853 -796
  169. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  170. sphinx/locale/ka/LC_MESSAGES/sphinx.po +848 -791
  171. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/ko/LC_MESSAGES/sphinx.po +855 -798
  173. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/lt/LC_MESSAGES/sphinx.po +837 -780
  175. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  176. sphinx/locale/lv/LC_MESSAGES/sphinx.po +837 -780
  177. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/mk/LC_MESSAGES/sphinx.po +825 -768
  179. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +27 -27
  180. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  181. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +876 -818
  182. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  183. sphinx/locale/ne/LC_MESSAGES/sphinx.po +837 -780
  184. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  185. sphinx/locale/nl/LC_MESSAGES/sphinx.po +844 -787
  186. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  187. sphinx/locale/pl/LC_MESSAGES/sphinx.po +845 -788
  188. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  189. sphinx/locale/pt/LC_MESSAGES/sphinx.po +811 -754
  190. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  191. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +908 -851
  192. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  193. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +837 -780
  194. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  195. sphinx/locale/ro/LC_MESSAGES/sphinx.po +837 -780
  196. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  197. sphinx/locale/ru/LC_MESSAGES/sphinx.po +838 -781
  198. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  199. sphinx/locale/si/LC_MESSAGES/sphinx.po +823 -766
  200. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  201. sphinx/locale/sk/LC_MESSAGES/sphinx.po +854 -797
  202. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  203. sphinx/locale/sl/LC_MESSAGES/sphinx.po +832 -775
  204. sphinx/locale/sphinx.pot +813 -755
  205. sphinx/locale/sq/LC_MESSAGES/sphinx.js +1 -1
  206. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/sq/LC_MESSAGES/sphinx.po +865 -808
  208. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  209. sphinx/locale/sr/LC_MESSAGES/sphinx.po +835 -778
  210. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
  212. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/sv/LC_MESSAGES/sphinx.po +837 -780
  214. sphinx/locale/ta/LC_MESSAGES/sphinx.js +54 -54
  215. sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
  216. sphinx/locale/ta/LC_MESSAGES/sphinx.po +1530 -1473
  217. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  218. sphinx/locale/te/LC_MESSAGES/sphinx.po +811 -754
  219. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  220. sphinx/locale/tr/LC_MESSAGES/sphinx.po +853 -796
  221. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  222. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +833 -776
  223. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  224. sphinx/locale/ur/LC_MESSAGES/sphinx.po +811 -754
  225. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  226. sphinx/locale/vi/LC_MESSAGES/sphinx.po +837 -780
  227. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  228. sphinx/locale/yue/LC_MESSAGES/sphinx.po +811 -754
  229. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
  230. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +855 -798
  231. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  232. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +811 -754
  233. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js +1 -1
  234. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  235. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +879 -822
  236. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  237. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +811 -754
  238. sphinx/parsers.py +7 -5
  239. sphinx/project.py +18 -11
  240. sphinx/pycode/__init__.py +6 -5
  241. sphinx/pycode/ast.py +23 -8
  242. sphinx/pycode/parser.py +6 -5
  243. sphinx/registry.py +12 -6
  244. sphinx/roles.py +103 -57
  245. sphinx/search/__init__.py +17 -18
  246. sphinx/search/da.py +2 -2
  247. sphinx/search/de.py +2 -2
  248. sphinx/search/en.py +1 -1
  249. sphinx/search/es.py +2 -2
  250. sphinx/search/fi.py +2 -2
  251. sphinx/search/fr.py +2 -2
  252. sphinx/search/hu.py +2 -2
  253. sphinx/search/it.py +2 -2
  254. sphinx/search/ja.py +13 -22
  255. sphinx/search/nl.py +2 -2
  256. sphinx/search/no.py +2 -2
  257. sphinx/search/pt.py +2 -2
  258. sphinx/search/ro.py +1 -1
  259. sphinx/search/ru.py +2 -2
  260. sphinx/search/sv.py +2 -2
  261. sphinx/search/tr.py +1 -1
  262. sphinx/search/zh.py +2 -3
  263. sphinx/templates/graphviz/graphviz.css +1 -1
  264. sphinx/testing/fixtures.py +41 -24
  265. sphinx/testing/path.py +1 -1
  266. sphinx/testing/util.py +142 -53
  267. sphinx/texinputs/sphinx.xdy +1 -1
  268. sphinx/texinputs/sphinxlatextables.sty +1 -1
  269. sphinx/texinputs/sphinxpackagesubstitutefont.sty +21 -0
  270. sphinx/themes/agogo/layout.html +4 -4
  271. sphinx/themes/agogo/static/agogo.css_t +1 -1
  272. sphinx/themes/agogo/theme.toml +22 -0
  273. sphinx/themes/basic/defindex.html +1 -1
  274. sphinx/themes/basic/domainindex.html +1 -1
  275. sphinx/themes/basic/genindex-single.html +1 -1
  276. sphinx/themes/basic/genindex-split.html +1 -1
  277. sphinx/themes/basic/genindex.html +1 -1
  278. sphinx/themes/basic/globaltoc.html +1 -1
  279. sphinx/themes/basic/layout.html +1 -1
  280. sphinx/themes/basic/localtoc.html +1 -1
  281. sphinx/themes/basic/page.html +1 -1
  282. sphinx/themes/basic/relations.html +1 -1
  283. sphinx/themes/basic/search.html +5 -20
  284. sphinx/themes/basic/searchbox.html +3 -3
  285. sphinx/themes/basic/searchfield.html +3 -3
  286. sphinx/themes/basic/sourcelink.html +1 -1
  287. sphinx/themes/basic/static/basic.css_t +1 -1
  288. sphinx/themes/basic/static/doctools.js +1 -1
  289. sphinx/themes/basic/static/language_data.js_t +2 -2
  290. sphinx/themes/basic/static/searchtools.js +105 -60
  291. sphinx/themes/basic/theme.toml +23 -0
  292. sphinx/themes/bizstyle/layout.html +1 -6
  293. sphinx/themes/bizstyle/static/bizstyle.css_t +1 -1
  294. sphinx/themes/bizstyle/static/bizstyle.js_t +1 -1
  295. sphinx/themes/bizstyle/static/css3-mediaqueries_src.js +3 -3
  296. sphinx/themes/bizstyle/theme.toml +12 -0
  297. sphinx/themes/classic/layout.html +1 -1
  298. sphinx/themes/classic/static/classic.css_t +1 -1
  299. sphinx/themes/classic/static/sidebar.js_t +1 -1
  300. sphinx/themes/classic/theme.toml +34 -0
  301. sphinx/themes/default/theme.toml +2 -0
  302. sphinx/themes/epub/epub-cover.html +1 -1
  303. sphinx/themes/epub/layout.html +1 -1
  304. sphinx/themes/epub/static/epub.css_t +1 -1
  305. sphinx/themes/epub/theme.toml +10 -0
  306. sphinx/themes/haiku/layout.html +3 -3
  307. sphinx/themes/haiku/static/haiku.css_t +2 -2
  308. sphinx/themes/haiku/theme.toml +16 -0
  309. sphinx/themes/nature/static/nature.css_t +1 -1
  310. sphinx/themes/nature/theme.toml +6 -0
  311. sphinx/themes/nonav/layout.html +1 -1
  312. sphinx/themes/nonav/static/nonav.css_t +1 -1
  313. sphinx/themes/nonav/theme.toml +10 -0
  314. sphinx/themes/pyramid/static/epub.css_t +1 -1
  315. sphinx/themes/pyramid/static/pyramid.css_t +1 -1
  316. sphinx/themes/pyramid/theme.toml +6 -0
  317. sphinx/themes/scrolls/artwork/logo.svg +1 -1
  318. sphinx/themes/scrolls/layout.html +2 -2
  319. sphinx/themes/scrolls/static/scrolls.css_t +1 -1
  320. sphinx/themes/scrolls/theme.toml +15 -0
  321. sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +1 -1
  322. sphinx/themes/sphinxdoc/theme.toml +6 -0
  323. sphinx/themes/traditional/static/traditional.css_t +1 -1
  324. sphinx/themes/traditional/theme.toml +9 -0
  325. sphinx/theming.py +427 -131
  326. sphinx/transforms/__init__.py +21 -24
  327. sphinx/transforms/compact_bullet_list.py +5 -5
  328. sphinx/transforms/i18n.py +30 -28
  329. sphinx/transforms/post_transforms/__init__.py +9 -7
  330. sphinx/transforms/post_transforms/code.py +4 -1
  331. sphinx/transforms/post_transforms/images.py +17 -13
  332. sphinx/transforms/references.py +3 -1
  333. sphinx/util/__init__.py +15 -11
  334. sphinx/util/_io.py +34 -0
  335. sphinx/util/_pathlib.py +23 -18
  336. sphinx/util/build_phase.py +1 -0
  337. sphinx/util/cfamily.py +19 -11
  338. sphinx/util/console.py +101 -21
  339. sphinx/util/display.py +3 -2
  340. sphinx/util/docfields.py +12 -8
  341. sphinx/util/docutils.py +21 -35
  342. sphinx/util/exceptions.py +3 -2
  343. sphinx/util/fileutil.py +5 -5
  344. sphinx/util/http_date.py +9 -2
  345. sphinx/util/i18n.py +40 -9
  346. sphinx/util/inspect.py +317 -245
  347. sphinx/util/inventory.py +22 -5
  348. sphinx/util/logging.py +81 -7
  349. sphinx/util/matching.py +2 -1
  350. sphinx/util/math.py +1 -2
  351. sphinx/util/nodes.py +39 -29
  352. sphinx/util/osutil.py +25 -6
  353. sphinx/util/parallel.py +6 -1
  354. sphinx/util/requests.py +8 -5
  355. sphinx/util/rst.py +8 -6
  356. sphinx/util/tags.py +3 -3
  357. sphinx/util/template.py +8 -3
  358. sphinx/util/typing.py +76 -42
  359. sphinx/versioning.py +6 -2
  360. sphinx/writers/html.py +1 -1
  361. sphinx/writers/html5.py +17 -13
  362. sphinx/writers/latex.py +12 -12
  363. sphinx/writers/manpage.py +13 -7
  364. sphinx/writers/texinfo.py +13 -10
  365. sphinx/writers/text.py +13 -23
  366. sphinx/writers/xml.py +1 -1
  367. sphinx-7.2.6.dist-info/LICENSE → sphinx-7.3.0.dist-info/LICENSE.rst +1 -1
  368. {sphinx-7.2.6.dist-info → sphinx-7.3.0.dist-info}/METADATA +13 -12
  369. sphinx-7.3.0.dist-info/RECORD +581 -0
  370. sphinx/domains/c.py +0 -3906
  371. sphinx/domains/cpp.py +0 -8233
  372. sphinx/domains/python.py +0 -1769
  373. sphinx/themes/agogo/theme.conf +0 -20
  374. sphinx/themes/basic/theme.conf +0 -16
  375. sphinx/themes/bizstyle/theme.conf +0 -10
  376. sphinx/themes/classic/theme.conf +0 -32
  377. sphinx/themes/default/theme.conf +0 -2
  378. sphinx/themes/epub/theme.conf +0 -8
  379. sphinx/themes/haiku/theme.conf +0 -14
  380. sphinx/themes/nature/theme.conf +0 -4
  381. sphinx/themes/nonav/theme.conf +0 -8
  382. sphinx/themes/pyramid/theme.conf +0 -4
  383. sphinx/themes/scrolls/theme.conf +0 -13
  384. sphinx/themes/sphinxdoc/theme.conf +0 -4
  385. sphinx/themes/traditional/theme.conf +0 -7
  386. sphinx-7.2.6.dist-info/RECORD +0 -569
  387. {sphinx-7.2.6.dist-info → sphinx-7.3.0.dist-info}/WHEEL +0 -0
  388. {sphinx-7.2.6.dist-info → sphinx-7.3.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,1048 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any, Callable
4
+
5
+ from sphinx.domains.c._ast import (
6
+ ASTAlignofExpr,
7
+ ASTArray,
8
+ ASTAssignmentExpr,
9
+ ASTBinOpExpr,
10
+ ASTBooleanLiteral,
11
+ ASTBracedInitList,
12
+ ASTCastExpr,
13
+ ASTCharLiteral,
14
+ ASTDeclaration,
15
+ ASTDeclarator,
16
+ ASTDeclaratorNameBitField,
17
+ ASTDeclaratorNameParam,
18
+ ASTDeclaratorParen,
19
+ ASTDeclaratorPtr,
20
+ ASTDeclSpecs,
21
+ ASTDeclSpecsSimple,
22
+ ASTEnum,
23
+ ASTEnumerator,
24
+ ASTExpression,
25
+ ASTFallbackExpr,
26
+ ASTFunctionParameter,
27
+ ASTIdentifier,
28
+ ASTIdExpression,
29
+ ASTInitializer,
30
+ ASTLiteral,
31
+ ASTMacro,
32
+ ASTMacroParameter,
33
+ ASTNestedName,
34
+ ASTNumberLiteral,
35
+ ASTParameters,
36
+ ASTParenExpr,
37
+ ASTParenExprList,
38
+ ASTPostfixArray,
39
+ ASTPostfixCallExpr,
40
+ ASTPostfixDec,
41
+ ASTPostfixExpr,
42
+ ASTPostfixInc,
43
+ ASTPostfixMemberOfPointer,
44
+ ASTPostfixOp,
45
+ ASTSizeofExpr,
46
+ ASTSizeofType,
47
+ ASTStringLiteral,
48
+ ASTStruct,
49
+ ASTTrailingTypeSpec,
50
+ ASTTrailingTypeSpecFundamental,
51
+ ASTTrailingTypeSpecName,
52
+ ASTType,
53
+ ASTTypeWithInit,
54
+ ASTUnaryOpExpr,
55
+ ASTUnion,
56
+ DeclarationType,
57
+ )
58
+ from sphinx.domains.c._ids import (
59
+ _expression_assignment_ops,
60
+ _expression_bin_ops,
61
+ _expression_unary_ops,
62
+ _keywords,
63
+ _simple_type_specifiers_re,
64
+ _string_re,
65
+ )
66
+ from sphinx.util.cfamily import (
67
+ ASTAttributeList,
68
+ BaseParser,
69
+ DefinitionError,
70
+ UnsupportedMultiCharacterCharLiteral,
71
+ binary_literal_re,
72
+ char_literal_re,
73
+ float_literal_re,
74
+ float_literal_suffix_re,
75
+ hex_literal_re,
76
+ identifier_re,
77
+ integer_literal_re,
78
+ integers_literal_suffix_re,
79
+ octal_literal_re,
80
+ )
81
+
82
+ if TYPE_CHECKING:
83
+ from collections.abc import Sequence
84
+
85
+
86
+ class DefinitionParser(BaseParser):
87
+ @property
88
+ def language(self) -> str:
89
+ return 'C'
90
+
91
+ @property
92
+ def id_attributes(self) -> Sequence[str]:
93
+ return self.config.c_id_attributes
94
+
95
+ @property
96
+ def paren_attributes(self) -> Sequence[str]:
97
+ return self.config.c_paren_attributes
98
+
99
+ def _parse_string(self) -> str | None:
100
+ if self.current_char != '"':
101
+ return None
102
+ startPos = self.pos
103
+ self.pos += 1
104
+ escape = False
105
+ while True:
106
+ if self.eof:
107
+ self.fail("Unexpected end during inside string.")
108
+ elif self.current_char == '"' and not escape:
109
+ self.pos += 1
110
+ break
111
+ elif self.current_char == '\\':
112
+ escape = True
113
+ else:
114
+ escape = False
115
+ self.pos += 1
116
+ return self.definition[startPos:self.pos]
117
+
118
+ def _parse_literal(self) -> ASTLiteral | None:
119
+ # -> integer-literal
120
+ # | character-literal
121
+ # | floating-literal
122
+ # | string-literal
123
+ # | boolean-literal -> "false" | "true"
124
+ self.skip_ws()
125
+ if self.skip_word('true'):
126
+ return ASTBooleanLiteral(True)
127
+ if self.skip_word('false'):
128
+ return ASTBooleanLiteral(False)
129
+ pos = self.pos
130
+ if self.match(float_literal_re):
131
+ self.match(float_literal_suffix_re)
132
+ return ASTNumberLiteral(self.definition[pos:self.pos])
133
+ for regex in (binary_literal_re, hex_literal_re,
134
+ integer_literal_re, octal_literal_re):
135
+ if self.match(regex):
136
+ self.match(integers_literal_suffix_re)
137
+ return ASTNumberLiteral(self.definition[pos:self.pos])
138
+
139
+ string = self._parse_string()
140
+ if string is not None:
141
+ return ASTStringLiteral(string)
142
+
143
+ # character-literal
144
+ if self.match(char_literal_re):
145
+ prefix = self.last_match.group(1) # may be None when no prefix
146
+ data = self.last_match.group(2)
147
+ try:
148
+ return ASTCharLiteral(prefix, data)
149
+ except UnicodeDecodeError as e:
150
+ self.fail("Can not handle character literal. Internal error was: %s" % e)
151
+ except UnsupportedMultiCharacterCharLiteral:
152
+ self.fail("Can not handle character literal"
153
+ " resulting in multiple decoded characters.")
154
+ return None
155
+
156
+ def _parse_paren_expression(self) -> ASTExpression | None:
157
+ # "(" expression ")"
158
+ if self.current_char != '(':
159
+ return None
160
+ self.pos += 1
161
+ res = self._parse_expression()
162
+ self.skip_ws()
163
+ if not self.skip_string(')'):
164
+ self.fail("Expected ')' in end of parenthesized expression.")
165
+ return ASTParenExpr(res)
166
+
167
+ def _parse_primary_expression(self) -> ASTExpression | None:
168
+ # literal
169
+ # "(" expression ")"
170
+ # id-expression -> we parse this with _parse_nested_name
171
+ self.skip_ws()
172
+ res: ASTExpression | None = self._parse_literal()
173
+ if res is not None:
174
+ return res
175
+ res = self._parse_paren_expression()
176
+ if res is not None:
177
+ return res
178
+ nn = self._parse_nested_name()
179
+ if nn is not None:
180
+ return ASTIdExpression(nn)
181
+ return None
182
+
183
+ def _parse_initializer_list(self, name: str, open: str, close: str,
184
+ ) -> tuple[list[ASTExpression] | None, bool | None]:
185
+ # Parse open and close with the actual initializer-list in between
186
+ # -> initializer-clause '...'[opt]
187
+ # | initializer-list ',' initializer-clause '...'[opt]
188
+ # TODO: designators
189
+ self.skip_ws()
190
+ if not self.skip_string_and_ws(open):
191
+ return None, None
192
+ if self.skip_string(close):
193
+ return [], False
194
+
195
+ exprs = []
196
+ trailingComma = False
197
+ while True:
198
+ self.skip_ws()
199
+ expr = self._parse_expression()
200
+ self.skip_ws()
201
+ exprs.append(expr)
202
+ self.skip_ws()
203
+ if self.skip_string(close):
204
+ break
205
+ if not self.skip_string_and_ws(','):
206
+ self.fail(f"Error in {name}, expected ',' or '{close}'.")
207
+ if self.current_char == close == '}':
208
+ self.pos += 1
209
+ trailingComma = True
210
+ break
211
+ return exprs, trailingComma
212
+
213
+ def _parse_paren_expression_list(self) -> ASTParenExprList | None:
214
+ # -> '(' expression-list ')'
215
+ # though, we relax it to also allow empty parens
216
+ # as it's needed in some cases
217
+ #
218
+ # expression-list
219
+ # -> initializer-list
220
+ exprs, trailingComma = self._parse_initializer_list("parenthesized expression-list",
221
+ '(', ')')
222
+ if exprs is None:
223
+ return None
224
+ return ASTParenExprList(exprs)
225
+
226
+ def _parse_braced_init_list(self) -> ASTBracedInitList | None:
227
+ # -> '{' initializer-list ','[opt] '}'
228
+ # | '{' '}'
229
+ exprs, trailingComma = self._parse_initializer_list("braced-init-list", '{', '}')
230
+ if exprs is None:
231
+ return None
232
+ return ASTBracedInitList(exprs, trailingComma)
233
+
234
+ def _parse_postfix_expression(self) -> ASTPostfixExpr:
235
+ # -> primary
236
+ # | postfix "[" expression "]"
237
+ # | postfix "[" braced-init-list [opt] "]"
238
+ # | postfix "(" expression-list [opt] ")"
239
+ # | postfix "." id-expression // taken care of in primary by nested name
240
+ # | postfix "->" id-expression
241
+ # | postfix "++"
242
+ # | postfix "--"
243
+
244
+ prefix = self._parse_primary_expression()
245
+
246
+ # and now parse postfixes
247
+ postFixes: list[ASTPostfixOp] = []
248
+ while True:
249
+ self.skip_ws()
250
+ if self.skip_string_and_ws('['):
251
+ expr = self._parse_expression()
252
+ self.skip_ws()
253
+ if not self.skip_string(']'):
254
+ self.fail("Expected ']' in end of postfix expression.")
255
+ postFixes.append(ASTPostfixArray(expr))
256
+ continue
257
+ if self.skip_string('->'):
258
+ if self.skip_string('*'):
259
+ # don't steal the arrow
260
+ self.pos -= 3
261
+ else:
262
+ name = self._parse_nested_name()
263
+ postFixes.append(ASTPostfixMemberOfPointer(name))
264
+ continue
265
+ if self.skip_string('++'):
266
+ postFixes.append(ASTPostfixInc())
267
+ continue
268
+ if self.skip_string('--'):
269
+ postFixes.append(ASTPostfixDec())
270
+ continue
271
+ lst = self._parse_paren_expression_list()
272
+ if lst is not None:
273
+ postFixes.append(ASTPostfixCallExpr(lst))
274
+ continue
275
+ break
276
+ return ASTPostfixExpr(prefix, postFixes)
277
+
278
+ def _parse_unary_expression(self) -> ASTExpression:
279
+ # -> postfix
280
+ # | "++" cast
281
+ # | "--" cast
282
+ # | unary-operator cast -> (* | & | + | - | ! | ~) cast
283
+ # The rest:
284
+ # | "sizeof" unary
285
+ # | "sizeof" "(" type-id ")"
286
+ # | "alignof" "(" type-id ")"
287
+ self.skip_ws()
288
+ for op in _expression_unary_ops:
289
+ # TODO: hmm, should we be able to backtrack here?
290
+ if op[0] in 'cn':
291
+ res = self.skip_word(op)
292
+ else:
293
+ res = self.skip_string(op)
294
+ if res:
295
+ expr = self._parse_cast_expression()
296
+ return ASTUnaryOpExpr(op, expr)
297
+ if self.skip_word_and_ws('sizeof'):
298
+ if self.skip_string_and_ws('('):
299
+ typ = self._parse_type(named=False)
300
+ self.skip_ws()
301
+ if not self.skip_string(')'):
302
+ self.fail("Expecting ')' to end 'sizeof'.")
303
+ return ASTSizeofType(typ)
304
+ expr = self._parse_unary_expression()
305
+ return ASTSizeofExpr(expr)
306
+ if self.skip_word_and_ws('alignof'):
307
+ if not self.skip_string_and_ws('('):
308
+ self.fail("Expecting '(' after 'alignof'.")
309
+ typ = self._parse_type(named=False)
310
+ self.skip_ws()
311
+ if not self.skip_string(')'):
312
+ self.fail("Expecting ')' to end 'alignof'.")
313
+ return ASTAlignofExpr(typ)
314
+ return self._parse_postfix_expression()
315
+
316
+ def _parse_cast_expression(self) -> ASTExpression:
317
+ # -> unary | "(" type-id ")" cast
318
+ pos = self.pos
319
+ self.skip_ws()
320
+ if self.skip_string('('):
321
+ try:
322
+ typ = self._parse_type(False)
323
+ if not self.skip_string(')'):
324
+ self.fail("Expected ')' in cast expression.")
325
+ expr = self._parse_cast_expression()
326
+ return ASTCastExpr(typ, expr)
327
+ except DefinitionError as exCast:
328
+ self.pos = pos
329
+ try:
330
+ return self._parse_unary_expression()
331
+ except DefinitionError as exUnary:
332
+ errs = []
333
+ errs.append((exCast, "If type cast expression"))
334
+ errs.append((exUnary, "If unary expression"))
335
+ raise self._make_multi_error(errs,
336
+ "Error in cast expression.") from exUnary
337
+ else:
338
+ return self._parse_unary_expression()
339
+
340
+ def _parse_logical_or_expression(self) -> ASTExpression:
341
+ # logical-or = logical-and ||
342
+ # logical-and = inclusive-or &&
343
+ # inclusive-or = exclusive-or |
344
+ # exclusive-or = and ^
345
+ # and = equality &
346
+ # equality = relational ==, !=
347
+ # relational = shift <, >, <=, >=
348
+ # shift = additive <<, >>
349
+ # additive = multiplicative +, -
350
+ # multiplicative = pm *, /, %
351
+ # pm = cast .*, ->*
352
+ def _parse_bin_op_expr(self: DefinitionParser, opId: int) -> ASTExpression:
353
+ if opId + 1 == len(_expression_bin_ops):
354
+ def parser() -> ASTExpression:
355
+ return self._parse_cast_expression()
356
+ else:
357
+ def parser() -> ASTExpression:
358
+ return _parse_bin_op_expr(self, opId + 1)
359
+ exprs = []
360
+ ops = []
361
+ exprs.append(parser())
362
+ while True:
363
+ self.skip_ws()
364
+ pos = self.pos
365
+ oneMore = False
366
+ for op in _expression_bin_ops[opId]:
367
+ if op[0] in 'abcnox':
368
+ if not self.skip_word(op):
369
+ continue
370
+ else:
371
+ if not self.skip_string(op):
372
+ continue
373
+ if op == self.current_char == '&':
374
+ # don't split the && 'token'
375
+ self.pos -= 1
376
+ # and btw. && has lower precedence, so we are done
377
+ break
378
+ try:
379
+ expr = parser()
380
+ exprs.append(expr)
381
+ ops.append(op)
382
+ oneMore = True
383
+ break
384
+ except DefinitionError:
385
+ self.pos = pos
386
+ if not oneMore:
387
+ break
388
+ return ASTBinOpExpr(exprs, ops) # type: ignore[return-value]
389
+ return _parse_bin_op_expr(self, 0)
390
+
391
+ def _parse_conditional_expression_tail(self, orExprHead: Any) -> ASTExpression | None:
392
+ # -> "?" expression ":" assignment-expression
393
+ return None
394
+
395
+ def _parse_assignment_expression(self) -> ASTExpression:
396
+ # -> conditional-expression
397
+ # | logical-or-expression assignment-operator initializer-clause
398
+ # -> conditional-expression ->
399
+ # logical-or-expression
400
+ # | logical-or-expression "?" expression ":" assignment-expression
401
+ # | logical-or-expression assignment-operator initializer-clause
402
+ exprs = []
403
+ ops = []
404
+ orExpr = self._parse_logical_or_expression()
405
+ exprs.append(orExpr)
406
+ # TODO: handle ternary with _parse_conditional_expression_tail
407
+ while True:
408
+ oneMore = False
409
+ self.skip_ws()
410
+ for op in _expression_assignment_ops:
411
+ if op[0] in 'abcnox':
412
+ if not self.skip_word(op):
413
+ continue
414
+ else:
415
+ if not self.skip_string(op):
416
+ continue
417
+ expr = self._parse_logical_or_expression()
418
+ exprs.append(expr)
419
+ ops.append(op)
420
+ oneMore = True
421
+ if not oneMore:
422
+ break
423
+ return ASTAssignmentExpr(exprs, ops)
424
+
425
+ def _parse_constant_expression(self) -> ASTExpression:
426
+ # -> conditional-expression
427
+ orExpr = self._parse_logical_or_expression()
428
+ # TODO: use _parse_conditional_expression_tail
429
+ return orExpr
430
+
431
+ def _parse_expression(self) -> ASTExpression:
432
+ # -> assignment-expression
433
+ # | expression "," assignment-expression
434
+ # TODO: actually parse the second production
435
+ return self._parse_assignment_expression()
436
+
437
+ def _parse_expression_fallback(
438
+ self, end: list[str],
439
+ parser: Callable[[], ASTExpression],
440
+ allow: bool = True) -> ASTExpression:
441
+ # Stupidly "parse" an expression.
442
+ # 'end' should be a list of characters which ends the expression.
443
+
444
+ # first try to use the provided parser
445
+ prevPos = self.pos
446
+ try:
447
+ return parser()
448
+ except DefinitionError as e:
449
+ # some places (e.g., template parameters) we really don't want to use fallback,
450
+ # and for testing we may want to globally disable it
451
+ if not allow or not self.allowFallbackExpressionParsing:
452
+ raise
453
+ self.warn("Parsing of expression failed. Using fallback parser."
454
+ " Error was:\n%s" % e)
455
+ self.pos = prevPos
456
+ # and then the fallback scanning
457
+ assert end is not None
458
+ self.skip_ws()
459
+ startPos = self.pos
460
+ if self.match(_string_re):
461
+ value = self.matched_text
462
+ else:
463
+ # TODO: add handling of more bracket-like things, and quote handling
464
+ brackets = {'(': ')', '{': '}', '[': ']'}
465
+ symbols: list[str] = []
466
+ while not self.eof:
467
+ if (len(symbols) == 0 and self.current_char in end):
468
+ break
469
+ if self.current_char in brackets:
470
+ symbols.append(brackets[self.current_char])
471
+ elif len(symbols) > 0 and self.current_char == symbols[-1]:
472
+ symbols.pop()
473
+ self.pos += 1
474
+ if len(end) > 0 and self.eof:
475
+ self.fail("Could not find end of expression starting at %d."
476
+ % startPos)
477
+ value = self.definition[startPos:self.pos].strip()
478
+ return ASTFallbackExpr(value.strip())
479
+
480
+ def _parse_nested_name(self) -> ASTNestedName:
481
+ names: list[Any] = []
482
+
483
+ self.skip_ws()
484
+ rooted = False
485
+ if self.skip_string('.'):
486
+ rooted = True
487
+ while 1:
488
+ self.skip_ws()
489
+ if not self.match(identifier_re):
490
+ self.fail("Expected identifier in nested name.")
491
+ identifier = self.matched_text
492
+ # make sure there isn't a keyword
493
+ if identifier in _keywords:
494
+ self.fail("Expected identifier in nested name, "
495
+ "got keyword: %s" % identifier)
496
+ if self.matched_text in self.config.c_extra_keywords:
497
+ msg = "Expected identifier, got user-defined keyword: %s." \
498
+ + " Remove it from c_extra_keywords to allow it as identifier.\n" \
499
+ + "Currently c_extra_keywords is %s."
500
+ self.fail(msg % (self.matched_text,
501
+ str(self.config.c_extra_keywords)))
502
+ ident = ASTIdentifier(identifier)
503
+ names.append(ident)
504
+
505
+ self.skip_ws()
506
+ if not self.skip_string('.'):
507
+ break
508
+ return ASTNestedName(names, rooted)
509
+
510
+ def _parse_simple_type_specifier(self) -> str | None:
511
+ if self.match(_simple_type_specifiers_re):
512
+ return self.matched_text
513
+ for t in ('bool', 'complex', 'imaginary'):
514
+ if t in self.config.c_extra_keywords:
515
+ if self.skip_word(t):
516
+ return t
517
+ return None
518
+
519
+ def _parse_simple_type_specifiers(self) -> ASTTrailingTypeSpecFundamental | None:
520
+ names: list[str] = []
521
+
522
+ self.skip_ws()
523
+ while True:
524
+ t = self._parse_simple_type_specifier()
525
+ if t is None:
526
+ break
527
+ names.append(t)
528
+ self.skip_ws()
529
+ if len(names) == 0:
530
+ return None
531
+ return ASTTrailingTypeSpecFundamental(names)
532
+
533
+ def _parse_trailing_type_spec(self) -> ASTTrailingTypeSpec:
534
+ # fundamental types, https://en.cppreference.com/w/c/language/type
535
+ # and extensions
536
+ self.skip_ws()
537
+ res = self._parse_simple_type_specifiers()
538
+ if res is not None:
539
+ return res
540
+
541
+ # prefixed
542
+ prefix = None
543
+ self.skip_ws()
544
+ for k in ('struct', 'enum', 'union'):
545
+ if self.skip_word_and_ws(k):
546
+ prefix = k
547
+ break
548
+
549
+ nestedName = self._parse_nested_name()
550
+ return ASTTrailingTypeSpecName(prefix, nestedName)
551
+
552
+ def _parse_parameters(self, paramMode: str) -> ASTParameters | None:
553
+ self.skip_ws()
554
+ if not self.skip_string('('):
555
+ if paramMode == 'function':
556
+ self.fail('Expecting "(" in parameters.')
557
+ else:
558
+ return None
559
+
560
+ args = []
561
+ self.skip_ws()
562
+ if not self.skip_string(')'):
563
+ while 1:
564
+ self.skip_ws()
565
+ if self.skip_string('...'):
566
+ args.append(ASTFunctionParameter(None, True))
567
+ self.skip_ws()
568
+ if not self.skip_string(')'):
569
+ self.fail('Expected ")" after "..." in parameters.')
570
+ break
571
+ # note: it seems that function arguments can always be named,
572
+ # even in function pointers and similar.
573
+ arg = self._parse_type_with_init(outer=None, named='single')
574
+ # TODO: parse default parameters # TODO: didn't we just do that?
575
+ args.append(ASTFunctionParameter(arg))
576
+
577
+ self.skip_ws()
578
+ if self.skip_string(','):
579
+ continue
580
+ if self.skip_string(')'):
581
+ break
582
+ self.fail(f'Expecting "," or ")" in parameters, got "{self.current_char}".')
583
+
584
+ attrs = self._parse_attribute_list()
585
+ return ASTParameters(args, attrs)
586
+
587
+ def _parse_decl_specs_simple(
588
+ self, outer: str | None, typed: bool,
589
+ ) -> ASTDeclSpecsSimple:
590
+ """Just parse the simple ones."""
591
+ storage = None
592
+ threadLocal = None
593
+ inline = None
594
+ restrict = None
595
+ volatile = None
596
+ const = None
597
+ attrs = []
598
+ while 1: # accept any permutation of a subset of some decl-specs
599
+ self.skip_ws()
600
+ if not storage:
601
+ if outer == 'member':
602
+ if self.skip_word('auto'):
603
+ storage = 'auto'
604
+ continue
605
+ if self.skip_word('register'):
606
+ storage = 'register'
607
+ continue
608
+ if outer in ('member', 'function'):
609
+ if self.skip_word('static'):
610
+ storage = 'static'
611
+ continue
612
+ if self.skip_word('extern'):
613
+ storage = 'extern'
614
+ continue
615
+ if outer == 'member' and not threadLocal:
616
+ if self.skip_word('thread_local'):
617
+ threadLocal = 'thread_local'
618
+ continue
619
+ if self.skip_word('_Thread_local'):
620
+ threadLocal = '_Thread_local'
621
+ continue
622
+ if outer == 'function' and not inline:
623
+ inline = self.skip_word('inline')
624
+ if inline:
625
+ continue
626
+
627
+ if not restrict and typed:
628
+ restrict = self.skip_word('restrict')
629
+ if restrict:
630
+ continue
631
+ if not volatile and typed:
632
+ volatile = self.skip_word('volatile')
633
+ if volatile:
634
+ continue
635
+ if not const and typed:
636
+ const = self.skip_word('const')
637
+ if const:
638
+ continue
639
+ attr = self._parse_attribute()
640
+ if attr:
641
+ attrs.append(attr)
642
+ continue
643
+ break
644
+ return ASTDeclSpecsSimple(storage, threadLocal, inline,
645
+ restrict, volatile, const, ASTAttributeList(attrs))
646
+
647
+ def _parse_decl_specs(self, outer: str | None, typed: bool = True) -> ASTDeclSpecs:
648
+ if outer:
649
+ if outer not in ('type', 'member', 'function'):
650
+ raise Exception('Internal error, unknown outer "%s".' % outer)
651
+ leftSpecs = self._parse_decl_specs_simple(outer, typed)
652
+ rightSpecs = None
653
+
654
+ if typed:
655
+ trailing = self._parse_trailing_type_spec()
656
+ rightSpecs = self._parse_decl_specs_simple(outer, typed)
657
+ else:
658
+ trailing = None
659
+ return ASTDeclSpecs(outer, leftSpecs, rightSpecs, trailing)
660
+
661
+ def _parse_declarator_name_suffix(
662
+ self, named: bool | str, paramMode: str, typed: bool,
663
+ ) -> ASTDeclarator:
664
+ assert named in (True, False, 'single')
665
+ # now we should parse the name, and then suffixes
666
+ if named == 'single':
667
+ if self.match(identifier_re):
668
+ if self.matched_text in _keywords:
669
+ self.fail("Expected identifier, "
670
+ "got keyword: %s" % self.matched_text)
671
+ if self.matched_text in self.config.c_extra_keywords:
672
+ msg = "Expected identifier, got user-defined keyword: %s." \
673
+ + " Remove it from c_extra_keywords to allow it as identifier.\n" \
674
+ + "Currently c_extra_keywords is %s."
675
+ self.fail(msg % (self.matched_text,
676
+ str(self.config.c_extra_keywords)))
677
+ identifier = ASTIdentifier(self.matched_text)
678
+ declId = ASTNestedName([identifier], rooted=False)
679
+ else:
680
+ declId = None
681
+ elif named:
682
+ declId = self._parse_nested_name()
683
+ else:
684
+ declId = None
685
+ arrayOps = []
686
+ while 1:
687
+ self.skip_ws()
688
+ if typed and self.skip_string('['):
689
+ self.skip_ws()
690
+ static = False
691
+ const = False
692
+ volatile = False
693
+ restrict = False
694
+ while True:
695
+ if not static:
696
+ if self.skip_word_and_ws('static'):
697
+ static = True
698
+ continue
699
+ if not const:
700
+ if self.skip_word_and_ws('const'):
701
+ const = True
702
+ continue
703
+ if not volatile:
704
+ if self.skip_word_and_ws('volatile'):
705
+ volatile = True
706
+ continue
707
+ if not restrict:
708
+ if self.skip_word_and_ws('restrict'):
709
+ restrict = True
710
+ continue
711
+ break
712
+ vla = False if static else self.skip_string_and_ws('*')
713
+ if vla:
714
+ if not self.skip_string(']'):
715
+ self.fail("Expected ']' in end of array operator.")
716
+ size = None
717
+ else:
718
+ if self.skip_string(']'):
719
+ size = None
720
+ else:
721
+
722
+ def parser() -> ASTExpression:
723
+ return self._parse_expression()
724
+ size = self._parse_expression_fallback([']'], parser)
725
+ self.skip_ws()
726
+ if not self.skip_string(']'):
727
+ self.fail("Expected ']' in end of array operator.")
728
+ arrayOps.append(ASTArray(static, const, volatile, restrict, vla, size))
729
+ else:
730
+ break
731
+ param = self._parse_parameters(paramMode)
732
+ if param is None and len(arrayOps) == 0:
733
+ # perhaps a bit-field
734
+ if named and paramMode == 'type' and typed:
735
+ self.skip_ws()
736
+ if self.skip_string(':'):
737
+ size = self._parse_constant_expression()
738
+ return ASTDeclaratorNameBitField(declId=declId, size=size)
739
+ return ASTDeclaratorNameParam(declId=declId, arrayOps=arrayOps,
740
+ param=param)
741
+
742
+ def _parse_declarator(self, named: bool | str, paramMode: str,
743
+ typed: bool = True) -> ASTDeclarator:
744
+ # 'typed' here means 'parse return type stuff'
745
+ if paramMode not in ('type', 'function'):
746
+ raise Exception(
747
+ "Internal error, unknown paramMode '%s'." % paramMode)
748
+ prevErrors = []
749
+ self.skip_ws()
750
+ if typed and self.skip_string('*'):
751
+ self.skip_ws()
752
+ restrict = False
753
+ volatile = False
754
+ const = False
755
+ attrs = []
756
+ while 1:
757
+ if not restrict:
758
+ restrict = self.skip_word_and_ws('restrict')
759
+ if restrict:
760
+ continue
761
+ if not volatile:
762
+ volatile = self.skip_word_and_ws('volatile')
763
+ if volatile:
764
+ continue
765
+ if not const:
766
+ const = self.skip_word_and_ws('const')
767
+ if const:
768
+ continue
769
+ attr = self._parse_attribute()
770
+ if attr is not None:
771
+ attrs.append(attr)
772
+ continue
773
+ break
774
+ next = self._parse_declarator(named, paramMode, typed)
775
+ return ASTDeclaratorPtr(next=next,
776
+ restrict=restrict, volatile=volatile, const=const,
777
+ attrs=ASTAttributeList(attrs))
778
+ if typed and self.current_char == '(': # note: peeking, not skipping
779
+ # maybe this is the beginning of params, try that first,
780
+ # otherwise assume it's noptr->declarator > ( ptr-declarator )
781
+ pos = self.pos
782
+ try:
783
+ # assume this is params
784
+ res = self._parse_declarator_name_suffix(named, paramMode,
785
+ typed)
786
+ return res
787
+ except DefinitionError as exParamQual:
788
+ msg = "If declarator-id with parameters"
789
+ if paramMode == 'function':
790
+ msg += " (e.g., 'void f(int arg)')"
791
+ prevErrors.append((exParamQual, msg))
792
+ self.pos = pos
793
+ try:
794
+ assert self.current_char == '('
795
+ self.skip_string('(')
796
+ # TODO: hmm, if there is a name, it must be in inner, right?
797
+ # TODO: hmm, if there must be parameters, they must b
798
+ # inside, right?
799
+ inner = self._parse_declarator(named, paramMode, typed)
800
+ if not self.skip_string(')'):
801
+ self.fail("Expected ')' in \"( ptr-declarator )\"")
802
+ next = self._parse_declarator(named=False,
803
+ paramMode="type",
804
+ typed=typed)
805
+ return ASTDeclaratorParen(inner=inner, next=next)
806
+ except DefinitionError as exNoPtrParen:
807
+ self.pos = pos
808
+ msg = "If parenthesis in noptr-declarator"
809
+ if paramMode == 'function':
810
+ msg += " (e.g., 'void (*f(int arg))(double)')"
811
+ prevErrors.append((exNoPtrParen, msg))
812
+ header = "Error in declarator"
813
+ raise self._make_multi_error(prevErrors, header) from exNoPtrParen
814
+ pos = self.pos
815
+ try:
816
+ return self._parse_declarator_name_suffix(named, paramMode, typed)
817
+ except DefinitionError as e:
818
+ self.pos = pos
819
+ prevErrors.append((e, "If declarator-id"))
820
+ header = "Error in declarator or parameters"
821
+ raise self._make_multi_error(prevErrors, header) from e
822
+
823
+ def _parse_initializer(self, outer: str | None = None, allowFallback: bool = True,
824
+ ) -> ASTInitializer | None:
825
+ self.skip_ws()
826
+ if outer == 'member' and False: # NoQA: SIM223 # TODO
827
+ bracedInit = self._parse_braced_init_list()
828
+ if bracedInit is not None:
829
+ return ASTInitializer(bracedInit, hasAssign=False)
830
+
831
+ if not self.skip_string('='):
832
+ return None
833
+
834
+ bracedInit = self._parse_braced_init_list()
835
+ if bracedInit is not None:
836
+ return ASTInitializer(bracedInit)
837
+
838
+ if outer == 'member':
839
+ fallbackEnd: list[str] = []
840
+ elif outer is None: # function parameter
841
+ fallbackEnd = [',', ')']
842
+ else:
843
+ self.fail("Internal error, initializer for outer '%s' not "
844
+ "implemented." % outer)
845
+
846
+ def parser() -> ASTExpression:
847
+ return self._parse_assignment_expression()
848
+
849
+ value = self._parse_expression_fallback(fallbackEnd, parser, allow=allowFallback)
850
+ return ASTInitializer(value)
851
+
852
+ def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType:
853
+ """
854
+ named=False|'single'|True: 'single' is e.g., for function objects which
855
+ doesn't need to name the arguments, but otherwise is a single name
856
+ """
857
+ if outer: # always named
858
+ if outer not in ('type', 'member', 'function'):
859
+ raise Exception('Internal error, unknown outer "%s".' % outer)
860
+ assert named
861
+
862
+ if outer == 'type':
863
+ # We allow type objects to just be a name.
864
+ prevErrors = []
865
+ startPos = self.pos
866
+ # first try without the type
867
+ try:
868
+ declSpecs = self._parse_decl_specs(outer=outer, typed=False)
869
+ decl = self._parse_declarator(named=True, paramMode=outer,
870
+ typed=False)
871
+ self.assert_end(allowSemicolon=True)
872
+ except DefinitionError as exUntyped:
873
+ desc = "If just a name"
874
+ prevErrors.append((exUntyped, desc))
875
+ self.pos = startPos
876
+ try:
877
+ declSpecs = self._parse_decl_specs(outer=outer)
878
+ decl = self._parse_declarator(named=True, paramMode=outer)
879
+ except DefinitionError as exTyped:
880
+ self.pos = startPos
881
+ desc = "If typedef-like declaration"
882
+ prevErrors.append((exTyped, desc))
883
+ # Retain the else branch for easier debugging.
884
+ # TODO: it would be nice to save the previous stacktrace
885
+ # and output it here.
886
+ if True:
887
+ header = "Type must be either just a name or a "
888
+ header += "typedef-like declaration."
889
+ raise self._make_multi_error(prevErrors, header) from exTyped
890
+ else: # NoQA: RET506
891
+ # For testing purposes.
892
+ # do it again to get the proper traceback (how do you
893
+ # reliably save a traceback when an exception is
894
+ # constructed?)
895
+ self.pos = startPos
896
+ typed = True
897
+ declSpecs = self._parse_decl_specs(outer=outer, typed=typed)
898
+ decl = self._parse_declarator(named=True, paramMode=outer,
899
+ typed=typed)
900
+ elif outer == 'function':
901
+ declSpecs = self._parse_decl_specs(outer=outer)
902
+ decl = self._parse_declarator(named=True, paramMode=outer)
903
+ else:
904
+ paramMode = 'type'
905
+ if outer == 'member': # i.e., member
906
+ named = True
907
+ declSpecs = self._parse_decl_specs(outer=outer)
908
+ decl = self._parse_declarator(named=named, paramMode=paramMode)
909
+ return ASTType(declSpecs, decl)
910
+
911
+ def _parse_type_with_init(self, named: bool | str, outer: str | None) -> ASTTypeWithInit:
912
+ if outer:
913
+ assert outer in ('type', 'member', 'function')
914
+ type = self._parse_type(outer=outer, named=named)
915
+ init = self._parse_initializer(outer=outer)
916
+ return ASTTypeWithInit(type, init)
917
+
918
+ def _parse_macro(self) -> ASTMacro:
919
+ self.skip_ws()
920
+ ident = self._parse_nested_name()
921
+ if ident is None:
922
+ self.fail("Expected identifier in macro definition.")
923
+ self.skip_ws()
924
+ if not self.skip_string_and_ws('('):
925
+ return ASTMacro(ident, None)
926
+ if self.skip_string(')'):
927
+ return ASTMacro(ident, [])
928
+ args = []
929
+ while 1:
930
+ self.skip_ws()
931
+ if self.skip_string('...'):
932
+ args.append(ASTMacroParameter(None, True))
933
+ self.skip_ws()
934
+ if not self.skip_string(')'):
935
+ self.fail('Expected ")" after "..." in macro parameters.')
936
+ break
937
+ if not self.match(identifier_re):
938
+ self.fail("Expected identifier in macro parameters.")
939
+ nn = ASTNestedName([ASTIdentifier(self.matched_text)], rooted=False)
940
+ # Allow named variadic args:
941
+ # https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
942
+ self.skip_ws()
943
+ if self.skip_string_and_ws('...'):
944
+ args.append(ASTMacroParameter(nn, False, True))
945
+ self.skip_ws()
946
+ if not self.skip_string(')'):
947
+ self.fail('Expected ")" after "..." in macro parameters.')
948
+ break
949
+ args.append(ASTMacroParameter(nn))
950
+ if self.skip_string_and_ws(','):
951
+ continue
952
+ if self.skip_string_and_ws(')'):
953
+ break
954
+ self.fail("Expected identifier, ')', or ',' in macro parameter list.")
955
+ return ASTMacro(ident, args)
956
+
957
+ def _parse_struct(self) -> ASTStruct:
958
+ name = self._parse_nested_name()
959
+ return ASTStruct(name)
960
+
961
+ def _parse_union(self) -> ASTUnion:
962
+ name = self._parse_nested_name()
963
+ return ASTUnion(name)
964
+
965
+ def _parse_enum(self) -> ASTEnum:
966
+ name = self._parse_nested_name()
967
+ return ASTEnum(name)
968
+
969
+ def _parse_enumerator(self) -> ASTEnumerator:
970
+ name = self._parse_nested_name()
971
+ attrs = self._parse_attribute_list()
972
+ self.skip_ws()
973
+ init = None
974
+ if self.skip_string('='):
975
+ self.skip_ws()
976
+
977
+ def parser() -> ASTExpression:
978
+ return self._parse_constant_expression()
979
+
980
+ initVal = self._parse_expression_fallback([], parser)
981
+ init = ASTInitializer(initVal)
982
+ return ASTEnumerator(name, init, attrs)
983
+
984
+ def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclaration:
985
+ if objectType not in ('function', 'member',
986
+ 'macro', 'struct', 'union', 'enum', 'enumerator', 'type'):
987
+ raise Exception('Internal error, unknown objectType "%s".' % objectType)
988
+ if directiveType not in ('function', 'member', 'var',
989
+ 'macro', 'struct', 'union', 'enum', 'enumerator', 'type'):
990
+ raise Exception('Internal error, unknown directiveType "%s".' % directiveType)
991
+
992
+ declaration: DeclarationType | None = None
993
+ if objectType == 'member':
994
+ declaration = self._parse_type_with_init(named=True, outer='member')
995
+ elif objectType == 'function':
996
+ declaration = self._parse_type(named=True, outer='function')
997
+ elif objectType == 'macro':
998
+ declaration = self._parse_macro()
999
+ elif objectType == 'struct':
1000
+ declaration = self._parse_struct()
1001
+ elif objectType == 'union':
1002
+ declaration = self._parse_union()
1003
+ elif objectType == 'enum':
1004
+ declaration = self._parse_enum()
1005
+ elif objectType == 'enumerator':
1006
+ declaration = self._parse_enumerator()
1007
+ elif objectType == 'type':
1008
+ declaration = self._parse_type(named=True, outer='type')
1009
+ else:
1010
+ raise AssertionError
1011
+ if objectType != 'macro':
1012
+ self.skip_ws()
1013
+ semicolon = self.skip_string(';')
1014
+ else:
1015
+ semicolon = False
1016
+ return ASTDeclaration(objectType, directiveType, declaration, semicolon)
1017
+
1018
+ def parse_namespace_object(self) -> ASTNestedName:
1019
+ return self._parse_nested_name()
1020
+
1021
+ def parse_xref_object(self) -> ASTNestedName:
1022
+ name = self._parse_nested_name()
1023
+ # if there are '()' left, just skip them
1024
+ self.skip_ws()
1025
+ self.skip_string('()')
1026
+ self.assert_end()
1027
+ return name
1028
+
1029
+ def parse_expression(self) -> ASTExpression | ASTType:
1030
+ pos = self.pos
1031
+ res: ASTExpression | ASTType | None = None
1032
+ try:
1033
+ res = self._parse_expression()
1034
+ self.skip_ws()
1035
+ self.assert_end()
1036
+ except DefinitionError as exExpr:
1037
+ self.pos = pos
1038
+ try:
1039
+ res = self._parse_type(False)
1040
+ self.skip_ws()
1041
+ self.assert_end()
1042
+ except DefinitionError as exType:
1043
+ header = "Error when parsing (type) expression."
1044
+ errs = []
1045
+ errs.append((exExpr, "If expression"))
1046
+ errs.append((exType, "If type"))
1047
+ raise self._make_multi_error(errs, header) from exType
1048
+ return res