Sphinx 7.2.5__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 +21 -20
  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 +132 -52
  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.5.dist-info/LICENSE → sphinx-7.3.0.dist-info/LICENSE.rst +1 -1
  368. {sphinx-7.2.5.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.5.dist-info/RECORD +0 -569
  387. {sphinx-7.2.5.dist-info → sphinx-7.3.0.dist-info}/WHEEL +0 -0
  388. {sphinx-7.2.5.dist-info → sphinx-7.3.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,2117 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from typing import TYPE_CHECKING, Any, Callable
5
+
6
+ from sphinx.domains.cpp._ast import (
7
+ ASTAlignofExpr,
8
+ ASTArray,
9
+ ASTAssignmentExpr,
10
+ ASTBaseClass,
11
+ ASTBinOpExpr,
12
+ ASTBooleanLiteral,
13
+ ASTBracedInitList,
14
+ ASTCastExpr,
15
+ ASTCharLiteral,
16
+ ASTClass,
17
+ ASTCommaExpr,
18
+ ASTConcept,
19
+ ASTConditionalExpr,
20
+ ASTDeclaration,
21
+ ASTDeclarator,
22
+ ASTDeclaratorMemPtr,
23
+ ASTDeclaratorNameBitField,
24
+ ASTDeclaratorNameParamQual,
25
+ ASTDeclaratorParamPack,
26
+ ASTDeclaratorParen,
27
+ ASTDeclaratorPtr,
28
+ ASTDeclaratorRef,
29
+ ASTDeclSpecs,
30
+ ASTDeclSpecsSimple,
31
+ ASTDeleteExpr,
32
+ ASTEnum,
33
+ ASTEnumerator,
34
+ ASTExplicitCast,
35
+ ASTExplicitSpec,
36
+ ASTExpression,
37
+ ASTFallbackExpr,
38
+ ASTFoldExpr,
39
+ ASTFunctionParameter,
40
+ ASTIdentifier,
41
+ ASTIdExpression,
42
+ ASTInitializer,
43
+ ASTLiteral,
44
+ ASTNamespace,
45
+ ASTNestedName,
46
+ ASTNestedNameElement,
47
+ ASTNewExpr,
48
+ ASTNoexceptExpr,
49
+ ASTNoexceptSpec,
50
+ ASTNumberLiteral,
51
+ ASTOperator,
52
+ ASTOperatorBuildIn,
53
+ ASTOperatorLiteral,
54
+ ASTOperatorType,
55
+ ASTPackExpansionExpr,
56
+ ASTParametersQualifiers,
57
+ ASTParenExpr,
58
+ ASTParenExprList,
59
+ ASTPointerLiteral,
60
+ ASTPostfixArray,
61
+ ASTPostfixCallExpr,
62
+ ASTPostfixDec,
63
+ ASTPostfixExpr,
64
+ ASTPostfixInc,
65
+ ASTPostfixMember,
66
+ ASTPostfixMemberOfPointer,
67
+ ASTPostfixOp,
68
+ ASTRequiresClause,
69
+ ASTSizeofExpr,
70
+ ASTSizeofParamPack,
71
+ ASTSizeofType,
72
+ ASTStringLiteral,
73
+ ASTTemplateArgConstant,
74
+ ASTTemplateArgs,
75
+ ASTTemplateDeclarationPrefix,
76
+ ASTTemplateIntroduction,
77
+ ASTTemplateIntroductionParameter,
78
+ ASTTemplateKeyParamPackIdDefault,
79
+ ASTTemplateParam,
80
+ ASTTemplateParamConstrainedTypeWithInit,
81
+ ASTTemplateParamNonType,
82
+ ASTTemplateParams,
83
+ ASTTemplateParamTemplateType,
84
+ ASTTemplateParamType,
85
+ ASTThisLiteral,
86
+ ASTTrailingTypeSpec,
87
+ ASTTrailingTypeSpecDecltype,
88
+ ASTTrailingTypeSpecDecltypeAuto,
89
+ ASTTrailingTypeSpecFundamental,
90
+ ASTTrailingTypeSpecName,
91
+ ASTType,
92
+ ASTTypeId,
93
+ ASTTypeUsing,
94
+ ASTTypeWithInit,
95
+ ASTUnaryOpExpr,
96
+ ASTUnion,
97
+ ASTUserDefinedLiteral,
98
+ )
99
+ from sphinx.domains.cpp._ids import (
100
+ _expression_assignment_ops,
101
+ _expression_bin_ops,
102
+ _expression_unary_ops,
103
+ _fold_operator_re,
104
+ _id_explicit_cast,
105
+ _keywords,
106
+ _operator_re,
107
+ _simple_type_specifiers_re,
108
+ _string_re,
109
+ _visibility_re,
110
+ udl_identifier_re,
111
+ )
112
+ from sphinx.util import logging
113
+ from sphinx.util.cfamily import (
114
+ ASTAttributeList,
115
+ BaseParser,
116
+ DefinitionError,
117
+ UnsupportedMultiCharacterCharLiteral,
118
+ binary_literal_re,
119
+ char_literal_re,
120
+ float_literal_re,
121
+ float_literal_suffix_re,
122
+ hex_literal_re,
123
+ identifier_re,
124
+ integer_literal_re,
125
+ integers_literal_suffix_re,
126
+ octal_literal_re,
127
+ )
128
+
129
+ if TYPE_CHECKING:
130
+ from collections.abc import Sequence
131
+
132
+ logger = logging.getLogger(__name__)
133
+
134
+
135
+ class DefinitionParser(BaseParser):
136
+ @property
137
+ def language(self) -> str:
138
+ return 'C++'
139
+
140
+ @property
141
+ def id_attributes(self) -> Sequence[str]:
142
+ return self.config.cpp_id_attributes
143
+
144
+ @property
145
+ def paren_attributes(self) -> Sequence[str]:
146
+ return self.config.cpp_paren_attributes
147
+
148
+ def _parse_string(self) -> str:
149
+ if self.current_char != '"':
150
+ return None
151
+ startPos = self.pos
152
+ self.pos += 1
153
+ escape = False
154
+ while True:
155
+ if self.eof:
156
+ self.fail("Unexpected end during inside string.")
157
+ elif self.current_char == '"' and not escape:
158
+ self.pos += 1
159
+ break
160
+ elif self.current_char == '\\':
161
+ escape = True
162
+ else:
163
+ escape = False
164
+ self.pos += 1
165
+ return self.definition[startPos:self.pos]
166
+
167
+ def _parse_literal(self) -> ASTLiteral:
168
+ # -> integer-literal
169
+ # | character-literal
170
+ # | floating-literal
171
+ # | string-literal
172
+ # | boolean-literal -> "false" | "true"
173
+ # | pointer-literal -> "nullptr"
174
+ # | user-defined-literal
175
+
176
+ def _udl(literal: ASTLiteral) -> ASTLiteral:
177
+ if not self.match(udl_identifier_re):
178
+ return literal
179
+ # hmm, should we care if it's a keyword?
180
+ # it looks like GCC does not disallow keywords
181
+ ident = ASTIdentifier(self.matched_text)
182
+ return ASTUserDefinedLiteral(literal, ident)
183
+
184
+ self.skip_ws()
185
+ if self.skip_word('nullptr'):
186
+ return ASTPointerLiteral()
187
+ if self.skip_word('true'):
188
+ return ASTBooleanLiteral(True)
189
+ if self.skip_word('false'):
190
+ return ASTBooleanLiteral(False)
191
+ pos = self.pos
192
+ if self.match(float_literal_re):
193
+ hasSuffix = self.match(float_literal_suffix_re)
194
+ floatLit = ASTNumberLiteral(self.definition[pos:self.pos])
195
+ if hasSuffix:
196
+ return floatLit
197
+ else:
198
+ return _udl(floatLit)
199
+ for regex in (binary_literal_re, hex_literal_re,
200
+ integer_literal_re, octal_literal_re):
201
+ if self.match(regex):
202
+ hasSuffix = self.match(integers_literal_suffix_re)
203
+ intLit = ASTNumberLiteral(self.definition[pos:self.pos])
204
+ if hasSuffix:
205
+ return intLit
206
+ else:
207
+ return _udl(intLit)
208
+
209
+ string = self._parse_string()
210
+ if string is not None:
211
+ return _udl(ASTStringLiteral(string))
212
+
213
+ # character-literal
214
+ if self.match(char_literal_re):
215
+ prefix = self.last_match.group(1) # may be None when no prefix
216
+ data = self.last_match.group(2)
217
+ try:
218
+ charLit = ASTCharLiteral(prefix, data)
219
+ except UnicodeDecodeError as e:
220
+ self.fail("Can not handle character literal. Internal error was: %s" % e)
221
+ except UnsupportedMultiCharacterCharLiteral:
222
+ self.fail("Can not handle character literal"
223
+ " resulting in multiple decoded characters.")
224
+ return _udl(charLit)
225
+ return None
226
+
227
+ def _parse_fold_or_paren_expression(self) -> ASTExpression | None:
228
+ # "(" expression ")"
229
+ # fold-expression
230
+ # -> ( cast-expression fold-operator ... )
231
+ # | ( ... fold-operator cast-expression )
232
+ # | ( cast-expression fold-operator ... fold-operator cast-expression
233
+ if self.current_char != '(':
234
+ return None
235
+ self.pos += 1
236
+ self.skip_ws()
237
+ if self.skip_string_and_ws("..."):
238
+ # ( ... fold-operator cast-expression )
239
+ if not self.match(_fold_operator_re):
240
+ self.fail("Expected fold operator after '...' in fold expression.")
241
+ op = self.matched_text
242
+ rightExpr = self._parse_cast_expression()
243
+ if not self.skip_string(')'):
244
+ self.fail("Expected ')' in end of fold expression.")
245
+ return ASTFoldExpr(None, op, rightExpr)
246
+ # try first parsing a unary right fold, or a binary fold
247
+ pos = self.pos
248
+ try:
249
+ self.skip_ws()
250
+ leftExpr = self._parse_cast_expression()
251
+ self.skip_ws()
252
+ if not self.match(_fold_operator_re):
253
+ self.fail("Expected fold operator after left expression in fold expression.")
254
+ op = self.matched_text
255
+ self.skip_ws()
256
+ if not self.skip_string_and_ws('...'):
257
+ self.fail("Expected '...' after fold operator in fold expression.")
258
+ except DefinitionError as eFold:
259
+ self.pos = pos
260
+ # fall back to a paren expression
261
+ try:
262
+ res = self._parse_expression()
263
+ self.skip_ws()
264
+ if not self.skip_string(')'):
265
+ self.fail("Expected ')' in end of parenthesized expression.")
266
+ except DefinitionError as eExpr:
267
+ raise self._make_multi_error([
268
+ (eFold, "If fold expression"),
269
+ (eExpr, "If parenthesized expression"),
270
+ ], "Error in fold expression or parenthesized expression.") from eExpr
271
+ return ASTParenExpr(res)
272
+ # now it definitely is a fold expression
273
+ if self.skip_string(')'):
274
+ return ASTFoldExpr(leftExpr, op, None)
275
+ if not self.match(_fold_operator_re):
276
+ self.fail("Expected fold operator or ')' after '...' in fold expression.")
277
+ if op != self.matched_text:
278
+ self.fail("Operators are different in binary fold: '%s' and '%s'."
279
+ % (op, self.matched_text))
280
+ rightExpr = self._parse_cast_expression()
281
+ self.skip_ws()
282
+ if not self.skip_string(')'):
283
+ self.fail("Expected ')' to end binary fold expression.")
284
+ return ASTFoldExpr(leftExpr, op, rightExpr)
285
+
286
+ def _parse_primary_expression(self) -> ASTExpression:
287
+ # literal
288
+ # "this"
289
+ # lambda-expression
290
+ # "(" expression ")"
291
+ # fold-expression
292
+ # id-expression -> we parse this with _parse_nested_name
293
+ self.skip_ws()
294
+ res: ASTExpression = self._parse_literal()
295
+ if res is not None:
296
+ return res
297
+ self.skip_ws()
298
+ if self.skip_word("this"):
299
+ return ASTThisLiteral()
300
+ # TODO: try lambda expression
301
+ res = self._parse_fold_or_paren_expression()
302
+ if res is not None:
303
+ return res
304
+ nn = self._parse_nested_name()
305
+ if nn is not None:
306
+ return ASTIdExpression(nn)
307
+ return None
308
+
309
+ def _parse_initializer_list(self, name: str, open: str, close: str,
310
+ ) -> tuple[list[ASTExpression | ASTBracedInitList],
311
+ bool]:
312
+ # Parse open and close with the actual initializer-list in between
313
+ # -> initializer-clause '...'[opt]
314
+ # | initializer-list ',' initializer-clause '...'[opt]
315
+ self.skip_ws()
316
+ if not self.skip_string_and_ws(open):
317
+ return None, None
318
+ if self.skip_string(close):
319
+ return [], False
320
+
321
+ exprs: list[ASTExpression | ASTBracedInitList] = []
322
+ trailingComma = False
323
+ while True:
324
+ self.skip_ws()
325
+ expr = self._parse_initializer_clause()
326
+ self.skip_ws()
327
+ if self.skip_string('...'):
328
+ exprs.append(ASTPackExpansionExpr(expr))
329
+ else:
330
+ exprs.append(expr)
331
+ self.skip_ws()
332
+ if self.skip_string(close):
333
+ break
334
+ if not self.skip_string_and_ws(','):
335
+ self.fail(f"Error in {name}, expected ',' or '{close}'.")
336
+ if self.current_char == close == '}':
337
+ self.pos += 1
338
+ trailingComma = True
339
+ break
340
+ return exprs, trailingComma
341
+
342
+ def _parse_paren_expression_list(self) -> ASTParenExprList:
343
+ # -> '(' expression-list ')'
344
+ # though, we relax it to also allow empty parens
345
+ # as it's needed in some cases
346
+ #
347
+ # expression-list
348
+ # -> initializer-list
349
+ exprs, trailingComma = self._parse_initializer_list("parenthesized expression-list",
350
+ '(', ')')
351
+ if exprs is None:
352
+ return None
353
+ return ASTParenExprList(exprs)
354
+
355
+ def _parse_initializer_clause(self) -> ASTExpression | ASTBracedInitList:
356
+ bracedInitList = self._parse_braced_init_list()
357
+ if bracedInitList is not None:
358
+ return bracedInitList
359
+ return self._parse_assignment_expression(inTemplate=False)
360
+
361
+ def _parse_braced_init_list(self) -> ASTBracedInitList:
362
+ # -> '{' initializer-list ','[opt] '}'
363
+ # | '{' '}'
364
+ exprs, trailingComma = self._parse_initializer_list("braced-init-list", '{', '}')
365
+ if exprs is None:
366
+ return None
367
+ return ASTBracedInitList(exprs, trailingComma)
368
+
369
+ def _parse_expression_list_or_braced_init_list(
370
+ self,
371
+ ) -> ASTParenExprList | ASTBracedInitList:
372
+ paren = self._parse_paren_expression_list()
373
+ if paren is not None:
374
+ return paren
375
+ return self._parse_braced_init_list()
376
+
377
+ def _parse_postfix_expression(self) -> ASTPostfixExpr:
378
+ # -> primary
379
+ # | postfix "[" expression "]"
380
+ # | postfix "[" braced-init-list [opt] "]"
381
+ # | postfix "(" expression-list [opt] ")"
382
+ # | postfix "." "template" [opt] id-expression
383
+ # | postfix "->" "template" [opt] id-expression
384
+ # | postfix "." pseudo-destructor-name
385
+ # | postfix "->" pseudo-destructor-name
386
+ # | postfix "++"
387
+ # | postfix "--"
388
+ # | simple-type-specifier "(" expression-list [opt] ")"
389
+ # | simple-type-specifier braced-init-list
390
+ # | typename-specifier "(" expression-list [opt] ")"
391
+ # | typename-specifier braced-init-list
392
+ # | "dynamic_cast" "<" type-id ">" "(" expression ")"
393
+ # | "static_cast" "<" type-id ">" "(" expression ")"
394
+ # | "reinterpret_cast" "<" type-id ">" "(" expression ")"
395
+ # | "const_cast" "<" type-id ">" "(" expression ")"
396
+ # | "typeid" "(" expression ")"
397
+ # | "typeid" "(" type-id ")"
398
+
399
+ prefixType = None
400
+ prefix: Any = None
401
+ self.skip_ws()
402
+
403
+ cast = None
404
+ for c in _id_explicit_cast:
405
+ if self.skip_word_and_ws(c):
406
+ cast = c
407
+ break
408
+ if cast is not None:
409
+ prefixType = "cast"
410
+ if not self.skip_string("<"):
411
+ self.fail("Expected '<' after '%s'." % cast)
412
+ typ = self._parse_type(False)
413
+ self.skip_ws()
414
+ if not self.skip_string_and_ws(">"):
415
+ self.fail("Expected '>' after type in '%s'." % cast)
416
+ if not self.skip_string("("):
417
+ self.fail("Expected '(' in '%s'." % cast)
418
+
419
+ def parser() -> ASTExpression:
420
+ return self._parse_expression()
421
+ expr = self._parse_expression_fallback([')'], parser)
422
+ self.skip_ws()
423
+ if not self.skip_string(")"):
424
+ self.fail("Expected ')' to end '%s'." % cast)
425
+ prefix = ASTExplicitCast(cast, typ, expr)
426
+ elif self.skip_word_and_ws("typeid"):
427
+ prefixType = "typeid"
428
+ if not self.skip_string_and_ws('('):
429
+ self.fail("Expected '(' after 'typeid'.")
430
+ pos = self.pos
431
+ try:
432
+ typ = self._parse_type(False)
433
+ prefix = ASTTypeId(typ, isType=True)
434
+ if not self.skip_string(')'):
435
+ self.fail("Expected ')' to end 'typeid' of type.")
436
+ except DefinitionError as eType:
437
+ self.pos = pos
438
+ try:
439
+
440
+ def parser() -> ASTExpression:
441
+ return self._parse_expression()
442
+ expr = self._parse_expression_fallback([')'], parser)
443
+ prefix = ASTTypeId(expr, isType=False)
444
+ if not self.skip_string(')'):
445
+ self.fail("Expected ')' to end 'typeid' of expression.")
446
+ except DefinitionError as eExpr:
447
+ self.pos = pos
448
+ header = "Error in 'typeid(...)'."
449
+ header += " Expected type or expression."
450
+ errors = []
451
+ errors.append((eType, "If type"))
452
+ errors.append((eExpr, "If expression"))
453
+ raise self._make_multi_error(errors, header) from eExpr
454
+ else: # a primary expression or a type
455
+ pos = self.pos
456
+ try:
457
+ prefix = self._parse_primary_expression()
458
+ prefixType = 'expr'
459
+ except DefinitionError as eOuter:
460
+ self.pos = pos
461
+ try:
462
+ # we are potentially casting, so save parens for us
463
+ # TODO: hmm, would we need to try both with operatorCast and with None?
464
+ prefix = self._parse_type(False, 'operatorCast')
465
+ prefixType = 'typeOperatorCast'
466
+ # | simple-type-specifier "(" expression-list [opt] ")"
467
+ # | simple-type-specifier braced-init-list
468
+ # | typename-specifier "(" expression-list [opt] ")"
469
+ # | typename-specifier braced-init-list
470
+ self.skip_ws()
471
+ if self.current_char != '(' and self.current_char != '{':
472
+ self.fail("Expecting '(' or '{' after type in cast expression.")
473
+ except DefinitionError as eInner:
474
+ self.pos = pos
475
+ header = "Error in postfix expression,"
476
+ header += " expected primary expression or type."
477
+ errors = []
478
+ errors.append((eOuter, "If primary expression"))
479
+ errors.append((eInner, "If type"))
480
+ raise self._make_multi_error(errors, header) from eInner
481
+
482
+ # and now parse postfixes
483
+ postFixes: list[ASTPostfixOp] = []
484
+ while True:
485
+ self.skip_ws()
486
+ if prefixType in ('expr', 'cast', 'typeid'):
487
+ if self.skip_string_and_ws('['):
488
+ expr = self._parse_expression()
489
+ self.skip_ws()
490
+ if not self.skip_string(']'):
491
+ self.fail("Expected ']' in end of postfix expression.")
492
+ postFixes.append(ASTPostfixArray(expr))
493
+ continue
494
+ if self.skip_string('.'):
495
+ if self.skip_string('*'):
496
+ # don't steal the dot
497
+ self.pos -= 2
498
+ elif self.skip_string('..'):
499
+ # don't steal the dot
500
+ self.pos -= 3
501
+ else:
502
+ name = self._parse_nested_name()
503
+ postFixes.append(ASTPostfixMember(name))
504
+ continue
505
+ if self.skip_string('->'):
506
+ if self.skip_string('*'):
507
+ # don't steal the arrow
508
+ self.pos -= 3
509
+ else:
510
+ name = self._parse_nested_name()
511
+ postFixes.append(ASTPostfixMemberOfPointer(name))
512
+ continue
513
+ if self.skip_string('++'):
514
+ postFixes.append(ASTPostfixInc())
515
+ continue
516
+ if self.skip_string('--'):
517
+ postFixes.append(ASTPostfixDec())
518
+ continue
519
+ lst = self._parse_expression_list_or_braced_init_list()
520
+ if lst is not None:
521
+ postFixes.append(ASTPostfixCallExpr(lst))
522
+ continue
523
+ break
524
+ return ASTPostfixExpr(prefix, postFixes)
525
+
526
+ def _parse_unary_expression(self) -> ASTExpression:
527
+ # -> postfix
528
+ # | "++" cast
529
+ # | "--" cast
530
+ # | unary-operator cast -> (* | & | + | - | ! | ~) cast
531
+ # The rest:
532
+ # | "sizeof" unary
533
+ # | "sizeof" "(" type-id ")"
534
+ # | "sizeof" "..." "(" identifier ")"
535
+ # | "alignof" "(" type-id ")"
536
+ # | noexcept-expression -> noexcept "(" expression ")"
537
+ # | new-expression
538
+ # | delete-expression
539
+ self.skip_ws()
540
+ for op in _expression_unary_ops:
541
+ # TODO: hmm, should we be able to backtrack here?
542
+ if op[0] in 'cn':
543
+ res = self.skip_word(op)
544
+ else:
545
+ res = self.skip_string(op)
546
+ if res:
547
+ expr = self._parse_cast_expression()
548
+ return ASTUnaryOpExpr(op, expr)
549
+ if self.skip_word_and_ws('sizeof'):
550
+ if self.skip_string_and_ws('...'):
551
+ if not self.skip_string_and_ws('('):
552
+ self.fail("Expecting '(' after 'sizeof...'.")
553
+ if not self.match(identifier_re):
554
+ self.fail("Expecting identifier for 'sizeof...'.")
555
+ ident = ASTIdentifier(self.matched_text)
556
+ self.skip_ws()
557
+ if not self.skip_string(")"):
558
+ self.fail("Expecting ')' to end 'sizeof...'.")
559
+ return ASTSizeofParamPack(ident)
560
+ if self.skip_string_and_ws('('):
561
+ typ = self._parse_type(named=False)
562
+ self.skip_ws()
563
+ if not self.skip_string(')'):
564
+ self.fail("Expecting ')' to end 'sizeof'.")
565
+ return ASTSizeofType(typ)
566
+ expr = self._parse_unary_expression()
567
+ return ASTSizeofExpr(expr)
568
+ if self.skip_word_and_ws('alignof'):
569
+ if not self.skip_string_and_ws('('):
570
+ self.fail("Expecting '(' after 'alignof'.")
571
+ typ = self._parse_type(named=False)
572
+ self.skip_ws()
573
+ if not self.skip_string(')'):
574
+ self.fail("Expecting ')' to end 'alignof'.")
575
+ return ASTAlignofExpr(typ)
576
+ if self.skip_word_and_ws('noexcept'):
577
+ if not self.skip_string_and_ws('('):
578
+ self.fail("Expecting '(' after 'noexcept'.")
579
+ expr = self._parse_expression()
580
+ self.skip_ws()
581
+ if not self.skip_string(')'):
582
+ self.fail("Expecting ')' to end 'noexcept'.")
583
+ return ASTNoexceptExpr(expr)
584
+ # new-expression
585
+ pos = self.pos
586
+ rooted = self.skip_string('::')
587
+ self.skip_ws()
588
+ if not self.skip_word_and_ws('new'):
589
+ self.pos = pos
590
+ else:
591
+ # new-placement[opt] new-type-id new-initializer[opt]
592
+ # new-placement[opt] ( type-id ) new-initializer[opt]
593
+ isNewTypeId = True
594
+ if self.skip_string_and_ws('('):
595
+ # either this is a new-placement or it's the second production
596
+ # without placement, and it's actually the ( type-id ) part
597
+ self.fail("Sorry, neither new-placement nor parenthesised type-id "
598
+ "in new-epression is supported yet.")
599
+ # set isNewTypeId = False if it's (type-id)
600
+ if isNewTypeId:
601
+ declSpecs = self._parse_decl_specs(outer=None)
602
+ decl = self._parse_declarator(named=False, paramMode="new")
603
+ else:
604
+ self.fail("Sorry, parenthesised type-id in new expression not yet supported.")
605
+ lst = self._parse_expression_list_or_braced_init_list()
606
+ return ASTNewExpr(rooted, isNewTypeId, ASTType(declSpecs, decl), lst)
607
+ # delete-expression
608
+ pos = self.pos
609
+ rooted = self.skip_string('::')
610
+ self.skip_ws()
611
+ if not self.skip_word_and_ws('delete'):
612
+ self.pos = pos
613
+ else:
614
+ array = self.skip_string_and_ws('[')
615
+ if array and not self.skip_string_and_ws(']'):
616
+ self.fail("Expected ']' in array delete-expression.")
617
+ expr = self._parse_cast_expression()
618
+ return ASTDeleteExpr(rooted, array, expr)
619
+ return self._parse_postfix_expression()
620
+
621
+ def _parse_cast_expression(self) -> ASTExpression:
622
+ # -> unary | "(" type-id ")" cast
623
+ pos = self.pos
624
+ self.skip_ws()
625
+ if self.skip_string('('):
626
+ try:
627
+ typ = self._parse_type(False)
628
+ if not self.skip_string(')'):
629
+ self.fail("Expected ')' in cast expression.")
630
+ expr = self._parse_cast_expression()
631
+ return ASTCastExpr(typ, expr)
632
+ except DefinitionError as exCast:
633
+ self.pos = pos
634
+ try:
635
+ return self._parse_unary_expression()
636
+ except DefinitionError as exUnary:
637
+ errs = []
638
+ errs.append((exCast, "If type cast expression"))
639
+ errs.append((exUnary, "If unary expression"))
640
+ raise self._make_multi_error(errs,
641
+ "Error in cast expression.") from exUnary
642
+ else:
643
+ return self._parse_unary_expression()
644
+
645
+ def _parse_logical_or_expression(self, inTemplate: bool) -> ASTExpression:
646
+ # logical-or = logical-and ||
647
+ # logical-and = inclusive-or &&
648
+ # inclusive-or = exclusive-or |
649
+ # exclusive-or = and ^
650
+ # and = equality &
651
+ # equality = relational ==, !=
652
+ # relational = shift <, >, <=, >=, <=>
653
+ # shift = additive <<, >>
654
+ # additive = multiplicative +, -
655
+ # multiplicative = pm *, /, %
656
+ # pm = cast .*, ->*
657
+ def _parse_bin_op_expr(self: DefinitionParser,
658
+ opId: int, inTemplate: bool) -> ASTExpression:
659
+ if opId + 1 == len(_expression_bin_ops):
660
+ def parser(inTemplate: bool) -> ASTExpression:
661
+ return self._parse_cast_expression()
662
+ else:
663
+ def parser(inTemplate: bool) -> ASTExpression:
664
+ return _parse_bin_op_expr(self, opId + 1, inTemplate=inTemplate)
665
+ exprs = []
666
+ ops = []
667
+ exprs.append(parser(inTemplate=inTemplate))
668
+ while True:
669
+ self.skip_ws()
670
+ if inTemplate and self.current_char == '>':
671
+ break
672
+ pos = self.pos
673
+ oneMore = False
674
+ for op in _expression_bin_ops[opId]:
675
+ if op[0] in 'abcnox':
676
+ if not self.skip_word(op):
677
+ continue
678
+ else:
679
+ if not self.skip_string(op):
680
+ continue
681
+ if op == self.current_char == '&':
682
+ # don't split the && 'token'
683
+ self.pos -= 1
684
+ # and btw. && has lower precedence, so we are done
685
+ break
686
+ try:
687
+ expr = parser(inTemplate=inTemplate)
688
+ exprs.append(expr)
689
+ ops.append(op)
690
+ oneMore = True
691
+ break
692
+ except DefinitionError:
693
+ self.pos = pos
694
+ if not oneMore:
695
+ break
696
+ return ASTBinOpExpr(exprs, ops)
697
+ return _parse_bin_op_expr(self, 0, inTemplate=inTemplate)
698
+
699
+ def _parse_conditional_expression_tail(self, orExprHead: ASTExpression,
700
+ inTemplate: bool) -> ASTConditionalExpr | None:
701
+ # Consumes the orExprHead on success.
702
+
703
+ # -> "?" expression ":" assignment-expression
704
+ self.skip_ws()
705
+ if not self.skip_string("?"):
706
+ return None
707
+ thenExpr = self._parse_expression()
708
+ self.skip_ws()
709
+ if not self.skip_string(":"):
710
+ self.fail('Expected ":" after then-expression in conditional expression.')
711
+ elseExpr = self._parse_assignment_expression(inTemplate)
712
+ return ASTConditionalExpr(orExprHead, thenExpr, elseExpr)
713
+
714
+ def _parse_assignment_expression(self, inTemplate: bool) -> ASTExpression:
715
+ # -> conditional-expression
716
+ # | logical-or-expression assignment-operator initializer-clause
717
+ # | yield-expression -> "co_yield" assignment-expression
718
+ # | "co_yield" braced-init-list
719
+ # | throw-expression -> "throw" assignment-expression[opt]
720
+ # TODO: yield-expression
721
+ # TODO: throw-expression
722
+
723
+ # Now we have (after expanding conditional-expression:
724
+ # logical-or-expression
725
+ # | logical-or-expression "?" expression ":" assignment-expression
726
+ # | logical-or-expression assignment-operator initializer-clause
727
+ leftExpr = self._parse_logical_or_expression(inTemplate=inTemplate)
728
+ # the ternary operator
729
+ condExpr = self._parse_conditional_expression_tail(leftExpr, inTemplate)
730
+ if condExpr is not None:
731
+ return condExpr
732
+ # and actual assignment
733
+ for op in _expression_assignment_ops:
734
+ if op[0] in 'anox':
735
+ if not self.skip_word(op):
736
+ continue
737
+ else:
738
+ if not self.skip_string(op):
739
+ continue
740
+ rightExpr = self._parse_initializer_clause()
741
+ return ASTAssignmentExpr(leftExpr, op, rightExpr)
742
+ # just a logical-or-expression
743
+ return leftExpr
744
+
745
+ def _parse_constant_expression(self, inTemplate: bool) -> ASTExpression:
746
+ # -> conditional-expression ->
747
+ # logical-or-expression
748
+ # | logical-or-expression "?" expression ":" assignment-expression
749
+ orExpr = self._parse_logical_or_expression(inTemplate=inTemplate)
750
+ condExpr = self._parse_conditional_expression_tail(orExpr, inTemplate)
751
+ if condExpr is not None:
752
+ return condExpr
753
+ return orExpr
754
+
755
+ def _parse_expression(self) -> ASTExpression:
756
+ # -> assignment-expression
757
+ # | expression "," assignment-expression
758
+ exprs = [self._parse_assignment_expression(inTemplate=False)]
759
+ while True:
760
+ self.skip_ws()
761
+ if not self.skip_string(','):
762
+ break
763
+ exprs.append(self._parse_assignment_expression(inTemplate=False))
764
+ if len(exprs) == 1:
765
+ return exprs[0]
766
+ else:
767
+ return ASTCommaExpr(exprs)
768
+
769
+ def _parse_expression_fallback(self, end: list[str],
770
+ parser: Callable[[], ASTExpression],
771
+ allow: bool = True) -> ASTExpression:
772
+ # Stupidly "parse" an expression.
773
+ # 'end' should be a list of characters which ends the expression.
774
+
775
+ # first try to use the provided parser
776
+ prevPos = self.pos
777
+ try:
778
+ return parser()
779
+ except DefinitionError as e:
780
+ # some places (e.g., template parameters) we really don't want to use fallback,
781
+ # and for testing we may want to globally disable it
782
+ if not allow or not self.allowFallbackExpressionParsing:
783
+ raise
784
+ self.warn("Parsing of expression failed. Using fallback parser."
785
+ " Error was:\n%s" % e)
786
+ self.pos = prevPos
787
+ # and then the fallback scanning
788
+ assert end is not None
789
+ self.skip_ws()
790
+ startPos = self.pos
791
+ if self.match(_string_re):
792
+ value = self.matched_text
793
+ else:
794
+ # TODO: add handling of more bracket-like things, and quote handling
795
+ brackets = {'(': ')', '{': '}', '[': ']', '<': '>'}
796
+ symbols: list[str] = []
797
+ while not self.eof:
798
+ if (len(symbols) == 0 and self.current_char in end):
799
+ break
800
+ if self.current_char in brackets:
801
+ symbols.append(brackets[self.current_char])
802
+ elif len(symbols) > 0 and self.current_char == symbols[-1]:
803
+ symbols.pop()
804
+ self.pos += 1
805
+ if len(end) > 0 and self.eof:
806
+ self.fail("Could not find end of expression starting at %d."
807
+ % startPos)
808
+ value = self.definition[startPos:self.pos].strip()
809
+ return ASTFallbackExpr(value.strip())
810
+
811
+ # ==========================================================================
812
+
813
+ def _parse_operator(self) -> ASTOperator:
814
+ self.skip_ws()
815
+ # adapted from the old code
816
+ # yay, a regular operator definition
817
+ if self.match(_operator_re):
818
+ return ASTOperatorBuildIn(self.matched_text)
819
+
820
+ # new/delete operator?
821
+ for op in 'new', 'delete':
822
+ if not self.skip_word(op):
823
+ continue
824
+ self.skip_ws()
825
+ if self.skip_string('['):
826
+ self.skip_ws()
827
+ if not self.skip_string(']'):
828
+ self.fail('Expected "]" after "operator ' + op + '["')
829
+ op += '[]'
830
+ return ASTOperatorBuildIn(op)
831
+
832
+ # user-defined literal?
833
+ if self.skip_string('""'):
834
+ self.skip_ws()
835
+ if not self.match(identifier_re):
836
+ self.fail("Expected user-defined literal suffix.")
837
+ identifier = ASTIdentifier(self.matched_text)
838
+ return ASTOperatorLiteral(identifier)
839
+
840
+ # oh well, looks like a cast operator definition.
841
+ # In that case, eat another type.
842
+ type = self._parse_type(named=False, outer="operatorCast")
843
+ return ASTOperatorType(type)
844
+
845
+ def _parse_template_argument_list(self) -> ASTTemplateArgs:
846
+ # template-argument-list: (but we include the < and > here
847
+ # template-argument ...[opt]
848
+ # template-argument-list, template-argument ...[opt]
849
+ # template-argument:
850
+ # constant-expression
851
+ # type-id
852
+ # id-expression
853
+ self.skip_ws()
854
+ if not self.skip_string_and_ws('<'):
855
+ return None
856
+ if self.skip_string('>'):
857
+ return ASTTemplateArgs([], False)
858
+ prevErrors = []
859
+ templateArgs: list[ASTType | ASTTemplateArgConstant] = []
860
+ packExpansion = False
861
+ while 1:
862
+ pos = self.pos
863
+ parsedComma = False
864
+ parsedEnd = False
865
+ try:
866
+ type = self._parse_type(named=False)
867
+ self.skip_ws()
868
+ if self.skip_string_and_ws('...'):
869
+ packExpansion = True
870
+ parsedEnd = True
871
+ if not self.skip_string('>'):
872
+ self.fail('Expected ">" after "..." in template argument list.')
873
+ elif self.skip_string('>'):
874
+ parsedEnd = True
875
+ elif self.skip_string(','):
876
+ parsedComma = True
877
+ else:
878
+ self.fail('Expected "...>", ">" or "," in template argument list.')
879
+ templateArgs.append(type)
880
+ except DefinitionError as e:
881
+ prevErrors.append((e, "If type argument"))
882
+ self.pos = pos
883
+ try:
884
+ value = self._parse_constant_expression(inTemplate=True)
885
+ self.skip_ws()
886
+ if self.skip_string_and_ws('...'):
887
+ packExpansion = True
888
+ parsedEnd = True
889
+ if not self.skip_string('>'):
890
+ self.fail('Expected ">" after "..." in template argument list.')
891
+ elif self.skip_string('>'):
892
+ parsedEnd = True
893
+ elif self.skip_string(','):
894
+ parsedComma = True
895
+ else:
896
+ self.fail('Expected "...>", ">" or "," in template argument list.')
897
+ templateArgs.append(ASTTemplateArgConstant(value))
898
+ except DefinitionError as e:
899
+ self.pos = pos
900
+ prevErrors.append((e, "If non-type argument"))
901
+ header = "Error in parsing template argument list."
902
+ raise self._make_multi_error(prevErrors, header) from e
903
+ if parsedEnd:
904
+ assert not parsedComma
905
+ break
906
+ assert not packExpansion
907
+ return ASTTemplateArgs(templateArgs, packExpansion)
908
+
909
+ def _parse_nested_name(self, memberPointer: bool = False) -> ASTNestedName:
910
+ names: list[ASTNestedNameElement] = []
911
+ templates: list[bool] = []
912
+
913
+ self.skip_ws()
914
+ rooted = False
915
+ if self.skip_string('::'):
916
+ rooted = True
917
+ while 1:
918
+ self.skip_ws()
919
+ if len(names) > 0:
920
+ template = self.skip_word_and_ws('template')
921
+ else:
922
+ template = False
923
+ templates.append(template)
924
+ identOrOp: ASTIdentifier | ASTOperator | None = None
925
+ if self.skip_word_and_ws('operator'):
926
+ identOrOp = self._parse_operator()
927
+ else:
928
+ if not self.match(identifier_re):
929
+ if memberPointer and len(names) > 0:
930
+ templates.pop()
931
+ break
932
+ self.fail("Expected identifier in nested name.")
933
+ identifier = self.matched_text
934
+ # make sure there isn't a keyword
935
+ if identifier in _keywords:
936
+ self.fail("Expected identifier in nested name, "
937
+ "got keyword: %s" % identifier)
938
+ identOrOp = ASTIdentifier(identifier)
939
+ # try greedily to get template arguments,
940
+ # but otherwise a < might be because we are in an expression
941
+ pos = self.pos
942
+ try:
943
+ templateArgs = self._parse_template_argument_list()
944
+ except DefinitionError as ex:
945
+ self.pos = pos
946
+ templateArgs = None
947
+ self.otherErrors.append(ex)
948
+ names.append(ASTNestedNameElement(identOrOp, templateArgs))
949
+
950
+ self.skip_ws()
951
+ if not self.skip_string('::'):
952
+ if memberPointer:
953
+ self.fail("Expected '::' in pointer to member (function).")
954
+ break
955
+ return ASTNestedName(names, templates, rooted)
956
+
957
+ # ==========================================================================
958
+
959
+ def _parse_simple_type_specifiers(self) -> ASTTrailingTypeSpecFundamental:
960
+ modifier: str | None = None
961
+ signedness: str | None = None
962
+ width: list[str] = []
963
+ typ: str | None = None
964
+ names: list[str] = [] # the parsed sequence
965
+
966
+ self.skip_ws()
967
+ while self.match(_simple_type_specifiers_re):
968
+ t = self.matched_text
969
+ names.append(t)
970
+ if t in ('auto', 'void', 'bool',
971
+ 'char', 'wchar_t', 'char8_t', 'char16_t', 'char32_t',
972
+ 'int', '__int64', '__int128',
973
+ 'float', 'double',
974
+ '__float80', '_Float64x', '__float128', '_Float128'):
975
+ if typ is not None:
976
+ self.fail(f"Can not have both {t} and {typ}.")
977
+ typ = t
978
+ elif t in ('signed', 'unsigned'):
979
+ if signedness is not None:
980
+ self.fail(f"Can not have both {t} and {signedness}.")
981
+ signedness = t
982
+ elif t == 'short':
983
+ if len(width) != 0:
984
+ self.fail(f"Can not have both {t} and {width[0]}.")
985
+ width.append(t)
986
+ elif t == 'long':
987
+ if len(width) != 0 and width[0] != 'long':
988
+ self.fail(f"Can not have both {t} and {width[0]}.")
989
+ width.append(t)
990
+ elif t in ('_Imaginary', '_Complex'):
991
+ if modifier is not None:
992
+ self.fail(f"Can not have both {t} and {modifier}.")
993
+ modifier = t
994
+ self.skip_ws()
995
+ if len(names) == 0:
996
+ return None
997
+
998
+ if typ in ('auto', 'void', 'bool',
999
+ 'wchar_t', 'char8_t', 'char16_t', 'char32_t',
1000
+ '__float80', '_Float64x', '__float128', '_Float128'):
1001
+ if modifier is not None:
1002
+ self.fail(f"Can not have both {typ} and {modifier}.")
1003
+ if signedness is not None:
1004
+ self.fail(f"Can not have both {typ} and {signedness}.")
1005
+ if len(width) != 0:
1006
+ self.fail(f"Can not have both {typ} and {' '.join(width)}.")
1007
+ elif typ == 'char':
1008
+ if modifier is not None:
1009
+ self.fail(f"Can not have both {typ} and {modifier}.")
1010
+ if len(width) != 0:
1011
+ self.fail(f"Can not have both {typ} and {' '.join(width)}.")
1012
+ elif typ == 'int':
1013
+ if modifier is not None:
1014
+ self.fail(f"Can not have both {typ} and {modifier}.")
1015
+ elif typ in ('__int64', '__int128'):
1016
+ if modifier is not None:
1017
+ self.fail(f"Can not have both {typ} and {modifier}.")
1018
+ if len(width) != 0:
1019
+ self.fail(f"Can not have both {typ} and {' '.join(width)}.")
1020
+ elif typ == 'float':
1021
+ if signedness is not None:
1022
+ self.fail(f"Can not have both {typ} and {signedness}.")
1023
+ if len(width) != 0:
1024
+ self.fail(f"Can not have both {typ} and {' '.join(width)}.")
1025
+ elif typ == 'double':
1026
+ if signedness is not None:
1027
+ self.fail(f"Can not have both {typ} and {signedness}.")
1028
+ if len(width) > 1:
1029
+ self.fail(f"Can not have both {typ} and {' '.join(width)}.")
1030
+ if len(width) == 1 and width[0] != 'long':
1031
+ self.fail(f"Can not have both {typ} and {' '.join(width)}.")
1032
+ elif typ is None:
1033
+ if modifier is not None:
1034
+ self.fail(f"Can not have {modifier} without a floating point type.")
1035
+ else:
1036
+ msg = f'Unhandled type {typ}'
1037
+ raise AssertionError(msg)
1038
+
1039
+ canonNames: list[str] = []
1040
+ if modifier is not None:
1041
+ canonNames.append(modifier)
1042
+ if signedness is not None:
1043
+ canonNames.append(signedness)
1044
+ canonNames.extend(width)
1045
+ if typ is not None:
1046
+ canonNames.append(typ)
1047
+ return ASTTrailingTypeSpecFundamental(names, canonNames)
1048
+
1049
+ def _parse_trailing_type_spec(self) -> ASTTrailingTypeSpec:
1050
+ # fundamental types, https://en.cppreference.com/w/cpp/language/type
1051
+ # and extensions
1052
+ self.skip_ws()
1053
+ res = self._parse_simple_type_specifiers()
1054
+ if res is not None:
1055
+ return res
1056
+
1057
+ # decltype
1058
+ self.skip_ws()
1059
+ if self.skip_word_and_ws('decltype'):
1060
+ if not self.skip_string_and_ws('('):
1061
+ self.fail("Expected '(' after 'decltype'.")
1062
+ if self.skip_word_and_ws('auto'):
1063
+ if not self.skip_string(')'):
1064
+ self.fail("Expected ')' after 'decltype(auto'.")
1065
+ return ASTTrailingTypeSpecDecltypeAuto()
1066
+ expr = self._parse_expression()
1067
+ self.skip_ws()
1068
+ if not self.skip_string(')'):
1069
+ self.fail("Expected ')' after 'decltype(<expr>'.")
1070
+ return ASTTrailingTypeSpecDecltype(expr)
1071
+
1072
+ # prefixed
1073
+ prefix = None
1074
+ self.skip_ws()
1075
+ for k in ('class', 'struct', 'enum', 'union', 'typename'):
1076
+ if self.skip_word_and_ws(k):
1077
+ prefix = k
1078
+ break
1079
+ nestedName = self._parse_nested_name()
1080
+ self.skip_ws()
1081
+ placeholderType = None
1082
+ if self.skip_word('auto'):
1083
+ placeholderType = 'auto'
1084
+ elif self.skip_word_and_ws('decltype'):
1085
+ if not self.skip_string_and_ws('('):
1086
+ self.fail("Expected '(' after 'decltype' in placeholder type specifier.")
1087
+ if not self.skip_word_and_ws('auto'):
1088
+ self.fail("Expected 'auto' after 'decltype(' in placeholder type specifier.")
1089
+ if not self.skip_string_and_ws(')'):
1090
+ self.fail("Expected ')' after 'decltype(auto' in placeholder type specifier.")
1091
+ placeholderType = 'decltype(auto)'
1092
+ return ASTTrailingTypeSpecName(prefix, nestedName, placeholderType)
1093
+
1094
+ def _parse_parameters_and_qualifiers(
1095
+ self, paramMode: str,
1096
+ ) -> ASTParametersQualifiers | None:
1097
+ if paramMode == 'new':
1098
+ return None
1099
+ self.skip_ws()
1100
+ if not self.skip_string('('):
1101
+ if paramMode == 'function':
1102
+ self.fail('Expecting "(" in parameters-and-qualifiers.')
1103
+ else:
1104
+ return None
1105
+ args = []
1106
+ self.skip_ws()
1107
+ if not self.skip_string(')'):
1108
+ while 1:
1109
+ self.skip_ws()
1110
+ if self.skip_string('...'):
1111
+ args.append(ASTFunctionParameter(None, True))
1112
+ self.skip_ws()
1113
+ if not self.skip_string(')'):
1114
+ self.fail('Expected ")" after "..." in '
1115
+ 'parameters-and-qualifiers.')
1116
+ break
1117
+ # note: it seems that function arguments can always be named,
1118
+ # even in function pointers and similar.
1119
+ arg = self._parse_type_with_init(outer=None, named='single')
1120
+ # TODO: parse default parameters # TODO: didn't we just do that?
1121
+ args.append(ASTFunctionParameter(arg))
1122
+
1123
+ self.skip_ws()
1124
+ if self.skip_string(','):
1125
+ continue
1126
+ if self.skip_string(')'):
1127
+ break
1128
+ self.fail('Expecting "," or ")" in parameters-and-qualifiers, '
1129
+ f'got "{self.current_char}".')
1130
+
1131
+ self.skip_ws()
1132
+ const = self.skip_word_and_ws('const')
1133
+ volatile = self.skip_word_and_ws('volatile')
1134
+ if not const: # the can be permuted
1135
+ const = self.skip_word_and_ws('const')
1136
+
1137
+ refQual = None
1138
+ if self.skip_string('&&'):
1139
+ refQual = '&&'
1140
+ if not refQual and self.skip_string('&'):
1141
+ refQual = '&'
1142
+
1143
+ exceptionSpec = None
1144
+ self.skip_ws()
1145
+ if self.skip_string('noexcept'):
1146
+ if self.skip_string_and_ws('('):
1147
+ expr = self._parse_constant_expression(False)
1148
+ self.skip_ws()
1149
+ if not self.skip_string(')'):
1150
+ self.fail("Expecting ')' to end 'noexcept'.")
1151
+ exceptionSpec = ASTNoexceptSpec(expr)
1152
+ else:
1153
+ exceptionSpec = ASTNoexceptSpec(None)
1154
+
1155
+ self.skip_ws()
1156
+ if self.skip_string('->'):
1157
+ trailingReturn = self._parse_type(named=False)
1158
+ else:
1159
+ trailingReturn = None
1160
+
1161
+ self.skip_ws()
1162
+ override = self.skip_word_and_ws('override')
1163
+ final = self.skip_word_and_ws('final')
1164
+ if not override:
1165
+ override = self.skip_word_and_ws(
1166
+ 'override') # they can be permuted
1167
+
1168
+ attrs = self._parse_attribute_list()
1169
+
1170
+ self.skip_ws()
1171
+ initializer = None
1172
+ # if this is a function pointer we should not swallow an initializer
1173
+ if paramMode == 'function' and self.skip_string('='):
1174
+ self.skip_ws()
1175
+ valid = ('0', 'delete', 'default')
1176
+ for w in valid:
1177
+ if self.skip_word_and_ws(w):
1178
+ initializer = w
1179
+ break
1180
+ if not initializer:
1181
+ self.fail(
1182
+ 'Expected "%s" in initializer-specifier.'
1183
+ % '" or "'.join(valid))
1184
+
1185
+ return ASTParametersQualifiers(
1186
+ args, volatile, const, refQual, exceptionSpec, trailingReturn,
1187
+ override, final, attrs, initializer)
1188
+
1189
+ def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple:
1190
+ """Just parse the simple ones."""
1191
+ storage = None
1192
+ threadLocal = None
1193
+ inline = None
1194
+ virtual = None
1195
+ explicitSpec = None
1196
+ consteval = None
1197
+ constexpr = None
1198
+ constinit = None
1199
+ volatile = None
1200
+ const = None
1201
+ friend = None
1202
+ attrs = []
1203
+ while 1: # accept any permutation of a subset of some decl-specs
1204
+ self.skip_ws()
1205
+ if not const and typed:
1206
+ const = self.skip_word('const')
1207
+ if const:
1208
+ continue
1209
+ if not volatile and typed:
1210
+ volatile = self.skip_word('volatile')
1211
+ if volatile:
1212
+ continue
1213
+ if not storage:
1214
+ if outer in ('member', 'function'):
1215
+ if self.skip_word('static'):
1216
+ storage = 'static'
1217
+ continue
1218
+ if self.skip_word('extern'):
1219
+ storage = 'extern'
1220
+ continue
1221
+ if outer == 'member':
1222
+ if self.skip_word('mutable'):
1223
+ storage = 'mutable'
1224
+ continue
1225
+ if self.skip_word('register'):
1226
+ storage = 'register'
1227
+ continue
1228
+ if not inline and outer in ('function', 'member'):
1229
+ inline = self.skip_word('inline')
1230
+ if inline:
1231
+ continue
1232
+ if not constexpr and outer in ('member', 'function'):
1233
+ constexpr = self.skip_word("constexpr")
1234
+ if constexpr:
1235
+ continue
1236
+
1237
+ if outer == 'member':
1238
+ if not constinit:
1239
+ constinit = self.skip_word('constinit')
1240
+ if constinit:
1241
+ continue
1242
+ if not threadLocal:
1243
+ threadLocal = self.skip_word('thread_local')
1244
+ if threadLocal:
1245
+ continue
1246
+ if outer == 'function':
1247
+ if not consteval:
1248
+ consteval = self.skip_word('consteval')
1249
+ if consteval:
1250
+ continue
1251
+ if not friend:
1252
+ friend = self.skip_word('friend')
1253
+ if friend:
1254
+ continue
1255
+ if not virtual:
1256
+ virtual = self.skip_word('virtual')
1257
+ if virtual:
1258
+ continue
1259
+ if not explicitSpec:
1260
+ explicit = self.skip_word_and_ws('explicit')
1261
+ if explicit:
1262
+ expr: ASTExpression = None
1263
+ if self.skip_string('('):
1264
+ expr = self._parse_constant_expression(inTemplate=False)
1265
+ if not expr:
1266
+ self.fail("Expected constant expression after '('" +
1267
+ " in explicit specifier.")
1268
+ self.skip_ws()
1269
+ if not self.skip_string(')'):
1270
+ self.fail("Expected ')' to end explicit specifier.")
1271
+ explicitSpec = ASTExplicitSpec(expr)
1272
+ continue
1273
+ attr = self._parse_attribute()
1274
+ if attr:
1275
+ attrs.append(attr)
1276
+ continue
1277
+ break
1278
+ return ASTDeclSpecsSimple(storage, threadLocal, inline, virtual,
1279
+ explicitSpec, consteval, constexpr, constinit,
1280
+ volatile, const, friend, ASTAttributeList(attrs))
1281
+
1282
+ def _parse_decl_specs(self, outer: str, typed: bool = True) -> ASTDeclSpecs:
1283
+ if outer:
1284
+ if outer not in ('type', 'member', 'function', 'templateParam'):
1285
+ raise Exception('Internal error, unknown outer "%s".' % outer)
1286
+ """
1287
+ storage-class-specifier function-specifier "constexpr"
1288
+ "volatile" "const" trailing-type-specifier
1289
+
1290
+ storage-class-specifier ->
1291
+ "static" (only for member_object and function_object)
1292
+ | "register"
1293
+
1294
+ function-specifier -> "inline" | "virtual" | "explicit" (only for
1295
+ function_object)
1296
+
1297
+ "constexpr" (only for member_object and function_object)
1298
+ """
1299
+ leftSpecs = self._parse_decl_specs_simple(outer, typed)
1300
+ rightSpecs = None
1301
+
1302
+ if typed:
1303
+ trailing = self._parse_trailing_type_spec()
1304
+ rightSpecs = self._parse_decl_specs_simple(outer, typed)
1305
+ else:
1306
+ trailing = None
1307
+ return ASTDeclSpecs(outer, leftSpecs, rightSpecs, trailing)
1308
+
1309
+ def _parse_declarator_name_suffix(
1310
+ self, named: bool | str, paramMode: str, typed: bool,
1311
+ ) -> ASTDeclaratorNameParamQual | ASTDeclaratorNameBitField:
1312
+ # now we should parse the name, and then suffixes
1313
+ if named == 'maybe':
1314
+ pos = self.pos
1315
+ try:
1316
+ declId = self._parse_nested_name()
1317
+ except DefinitionError:
1318
+ self.pos = pos
1319
+ declId = None
1320
+ elif named == 'single':
1321
+ if self.match(identifier_re):
1322
+ identifier = ASTIdentifier(self.matched_text)
1323
+ nne = ASTNestedNameElement(identifier, None)
1324
+ declId = ASTNestedName([nne], [False], rooted=False)
1325
+ # if it's a member pointer, we may have '::', which should be an error
1326
+ self.skip_ws()
1327
+ if self.current_char == ':':
1328
+ self.fail("Unexpected ':' after identifier.")
1329
+ else:
1330
+ declId = None
1331
+ elif named:
1332
+ declId = self._parse_nested_name()
1333
+ else:
1334
+ declId = None
1335
+ arrayOps = []
1336
+ while 1:
1337
+ self.skip_ws()
1338
+ if typed and self.skip_string('['):
1339
+ self.skip_ws()
1340
+ if self.skip_string(']'):
1341
+ arrayOps.append(ASTArray(None))
1342
+ continue
1343
+
1344
+ def parser() -> ASTExpression:
1345
+ return self._parse_expression()
1346
+ value = self._parse_expression_fallback([']'], parser)
1347
+ if not self.skip_string(']'):
1348
+ self.fail("Expected ']' in end of array operator.")
1349
+ arrayOps.append(ASTArray(value))
1350
+ continue
1351
+ break
1352
+ paramQual = self._parse_parameters_and_qualifiers(paramMode)
1353
+ if paramQual is None and len(arrayOps) == 0:
1354
+ # perhaps a bit-field
1355
+ if named and paramMode == 'type' and typed:
1356
+ self.skip_ws()
1357
+ if self.skip_string(':'):
1358
+ size = self._parse_constant_expression(inTemplate=False)
1359
+ return ASTDeclaratorNameBitField(declId=declId, size=size)
1360
+ return ASTDeclaratorNameParamQual(declId=declId, arrayOps=arrayOps,
1361
+ paramQual=paramQual)
1362
+
1363
+ def _parse_declarator(self, named: bool | str, paramMode: str,
1364
+ typed: bool = True,
1365
+ ) -> ASTDeclarator:
1366
+ # 'typed' here means 'parse return type stuff'
1367
+ if paramMode not in ('type', 'function', 'operatorCast', 'new'):
1368
+ raise Exception(
1369
+ "Internal error, unknown paramMode '%s'." % paramMode)
1370
+ prevErrors = []
1371
+ self.skip_ws()
1372
+ if typed and self.skip_string('*'):
1373
+ self.skip_ws()
1374
+ volatile = False
1375
+ const = False
1376
+ attrList = []
1377
+ while 1:
1378
+ if not volatile:
1379
+ volatile = self.skip_word_and_ws('volatile')
1380
+ if volatile:
1381
+ continue
1382
+ if not const:
1383
+ const = self.skip_word_and_ws('const')
1384
+ if const:
1385
+ continue
1386
+ attr = self._parse_attribute()
1387
+ if attr is not None:
1388
+ attrList.append(attr)
1389
+ continue
1390
+ break
1391
+ next = self._parse_declarator(named, paramMode, typed)
1392
+ return ASTDeclaratorPtr(next=next, volatile=volatile, const=const,
1393
+ attrs=ASTAttributeList(attrList))
1394
+ # TODO: shouldn't we parse an R-value ref here first?
1395
+ if typed and self.skip_string("&"):
1396
+ attrs = self._parse_attribute_list()
1397
+ next = self._parse_declarator(named, paramMode, typed)
1398
+ return ASTDeclaratorRef(next=next, attrs=attrs)
1399
+ if typed and self.skip_string("..."):
1400
+ next = self._parse_declarator(named, paramMode, False)
1401
+ return ASTDeclaratorParamPack(next=next)
1402
+ if typed and self.current_char == '(': # note: peeking, not skipping
1403
+ if paramMode == "operatorCast":
1404
+ # TODO: we should be able to parse cast operators which return
1405
+ # function pointers. For now, just hax it and ignore.
1406
+ return ASTDeclaratorNameParamQual(declId=None, arrayOps=[],
1407
+ paramQual=None)
1408
+ # maybe this is the beginning of params and quals,try that first,
1409
+ # otherwise assume it's noptr->declarator > ( ptr-declarator )
1410
+ pos = self.pos
1411
+ try:
1412
+ # assume this is params and quals
1413
+ res = self._parse_declarator_name_suffix(named, paramMode,
1414
+ typed)
1415
+ return res
1416
+ except DefinitionError as exParamQual:
1417
+ prevErrors.append((exParamQual,
1418
+ "If declarator-id with parameters-and-qualifiers"))
1419
+ self.pos = pos
1420
+ try:
1421
+ assert self.current_char == '('
1422
+ self.skip_string('(')
1423
+ # TODO: hmm, if there is a name, it must be in inner, right?
1424
+ # TODO: hmm, if there must be parameters, they must be
1425
+ # inside, right?
1426
+ inner = self._parse_declarator(named, paramMode, typed)
1427
+ if not self.skip_string(')'):
1428
+ self.fail("Expected ')' in \"( ptr-declarator )\"")
1429
+ next = self._parse_declarator(named=False,
1430
+ paramMode="type",
1431
+ typed=typed)
1432
+ return ASTDeclaratorParen(inner=inner, next=next)
1433
+ except DefinitionError as exNoPtrParen:
1434
+ self.pos = pos
1435
+ prevErrors.append((exNoPtrParen, "If parenthesis in noptr-declarator"))
1436
+ header = "Error in declarator"
1437
+ raise self._make_multi_error(prevErrors, header) from exNoPtrParen
1438
+ if typed: # pointer to member
1439
+ pos = self.pos
1440
+ try:
1441
+ name = self._parse_nested_name(memberPointer=True)
1442
+ self.skip_ws()
1443
+ if not self.skip_string('*'):
1444
+ self.fail("Expected '*' in pointer to member declarator.")
1445
+ self.skip_ws()
1446
+ except DefinitionError as e:
1447
+ self.pos = pos
1448
+ prevErrors.append((e, "If pointer to member declarator"))
1449
+ else:
1450
+ volatile = False
1451
+ const = False
1452
+ while 1:
1453
+ if not volatile:
1454
+ volatile = self.skip_word_and_ws('volatile')
1455
+ if volatile:
1456
+ continue
1457
+ if not const:
1458
+ const = self.skip_word_and_ws('const')
1459
+ if const:
1460
+ continue
1461
+ break
1462
+ next = self._parse_declarator(named, paramMode, typed)
1463
+ return ASTDeclaratorMemPtr(name, const, volatile, next=next)
1464
+ pos = self.pos
1465
+ try:
1466
+ res = self._parse_declarator_name_suffix(named, paramMode, typed)
1467
+ # this is a heuristic for error messages, for when there is a < after a
1468
+ # nested name, but it was not a successful template argument list
1469
+ if self.current_char == '<':
1470
+ self.otherErrors.append(self._make_multi_error(prevErrors, ""))
1471
+ return res
1472
+ except DefinitionError as e:
1473
+ self.pos = pos
1474
+ prevErrors.append((e, "If declarator-id"))
1475
+ header = "Error in declarator or parameters-and-qualifiers"
1476
+ raise self._make_multi_error(prevErrors, header) from e
1477
+
1478
+ def _parse_initializer(self, outer: str | None = None, allowFallback: bool = True,
1479
+ ) -> ASTInitializer | None:
1480
+ # initializer # global vars
1481
+ # -> brace-or-equal-initializer
1482
+ # | '(' expression-list ')'
1483
+ #
1484
+ # brace-or-equal-initializer # member vars
1485
+ # -> '=' initializer-clause
1486
+ # | braced-init-list
1487
+ #
1488
+ # initializer-clause # function params, non-type template params (with '=' in front)
1489
+ # -> assignment-expression
1490
+ # | braced-init-list
1491
+ #
1492
+ # we don't distinguish between global and member vars, so disallow paren:
1493
+ #
1494
+ # -> braced-init-list # var only
1495
+ # | '=' assignment-expression
1496
+ # | '=' braced-init-list
1497
+ self.skip_ws()
1498
+ if outer == 'member':
1499
+ bracedInit = self._parse_braced_init_list()
1500
+ if bracedInit is not None:
1501
+ return ASTInitializer(bracedInit, hasAssign=False)
1502
+
1503
+ if not self.skip_string('='):
1504
+ return None
1505
+
1506
+ bracedInit = self._parse_braced_init_list()
1507
+ if bracedInit is not None:
1508
+ return ASTInitializer(bracedInit)
1509
+
1510
+ if outer == 'member':
1511
+ fallbackEnd: list[str] = []
1512
+ elif outer == 'templateParam':
1513
+ fallbackEnd = [',', '>']
1514
+ elif outer is None: # function parameter
1515
+ fallbackEnd = [',', ')']
1516
+ else:
1517
+ self.fail("Internal error, initializer for outer '%s' not "
1518
+ "implemented." % outer)
1519
+
1520
+ inTemplate = outer == 'templateParam'
1521
+
1522
+ def parser() -> ASTExpression:
1523
+ return self._parse_assignment_expression(inTemplate=inTemplate)
1524
+ value = self._parse_expression_fallback(fallbackEnd, parser, allow=allowFallback)
1525
+ return ASTInitializer(value)
1526
+
1527
+ def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType:
1528
+ """
1529
+ named=False|'maybe'|True: 'maybe' is e.g., for function objects which
1530
+ doesn't need to name the arguments
1531
+
1532
+ outer == operatorCast: annoying case, we should not take the params
1533
+ """
1534
+ if outer: # always named
1535
+ if outer not in ('type', 'member', 'function',
1536
+ 'operatorCast', 'templateParam'):
1537
+ raise Exception('Internal error, unknown outer "%s".' % outer)
1538
+ if outer != 'operatorCast':
1539
+ assert named
1540
+ if outer in ('type', 'function'):
1541
+ # We allow type objects to just be a name.
1542
+ # Some functions don't have normal return types: constructors,
1543
+ # destructors, cast operators
1544
+ prevErrors = []
1545
+ startPos = self.pos
1546
+ # first try without the type
1547
+ try:
1548
+ declSpecs = self._parse_decl_specs(outer=outer, typed=False)
1549
+ decl = self._parse_declarator(named=True, paramMode=outer,
1550
+ typed=False)
1551
+ mustEnd = True
1552
+ if outer == 'function':
1553
+ # Allow trailing requires on functions.
1554
+ self.skip_ws()
1555
+ if re.compile(r'requires\b').match(self.definition, self.pos):
1556
+ mustEnd = False
1557
+ if mustEnd:
1558
+ self.assert_end(allowSemicolon=True)
1559
+ except DefinitionError as exUntyped:
1560
+ if outer == 'type':
1561
+ desc = "If just a name"
1562
+ elif outer == 'function':
1563
+ desc = "If the function has no return type"
1564
+ else:
1565
+ raise AssertionError from exUntyped
1566
+ prevErrors.append((exUntyped, desc))
1567
+ self.pos = startPos
1568
+ try:
1569
+ declSpecs = self._parse_decl_specs(outer=outer)
1570
+ decl = self._parse_declarator(named=True, paramMode=outer)
1571
+ except DefinitionError as exTyped:
1572
+ self.pos = startPos
1573
+ if outer == 'type':
1574
+ desc = "If typedef-like declaration"
1575
+ elif outer == 'function':
1576
+ desc = "If the function has a return type"
1577
+ else:
1578
+ raise AssertionError from exUntyped
1579
+ prevErrors.append((exTyped, desc))
1580
+ # Retain the else branch for easier debugging.
1581
+ # TODO: it would be nice to save the previous stacktrace
1582
+ # and output it here.
1583
+ if True:
1584
+ if outer == 'type':
1585
+ header = "Type must be either just a name or a "
1586
+ header += "typedef-like declaration."
1587
+ elif outer == 'function':
1588
+ header = "Error when parsing function declaration."
1589
+ else:
1590
+ raise AssertionError from exUntyped
1591
+ raise self._make_multi_error(prevErrors, header) from exTyped
1592
+ else: # NoQA: RET506
1593
+ # For testing purposes.
1594
+ # do it again to get the proper traceback (how do you
1595
+ # reliably save a traceback when an exception is
1596
+ # constructed?)
1597
+ self.pos = startPos
1598
+ typed = True
1599
+ declSpecs = self._parse_decl_specs(outer=outer, typed=typed)
1600
+ decl = self._parse_declarator(named=True, paramMode=outer,
1601
+ typed=typed)
1602
+ else:
1603
+ paramMode = 'type'
1604
+ if outer == 'member':
1605
+ named = True
1606
+ elif outer == 'operatorCast':
1607
+ paramMode = 'operatorCast'
1608
+ outer = None
1609
+ elif outer == 'templateParam':
1610
+ named = 'single'
1611
+ declSpecs = self._parse_decl_specs(outer=outer)
1612
+ decl = self._parse_declarator(named=named, paramMode=paramMode)
1613
+ return ASTType(declSpecs, decl)
1614
+
1615
+ def _parse_type_with_init(
1616
+ self, named: bool | str,
1617
+ outer: str) -> ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit:
1618
+ if outer:
1619
+ assert outer in ('type', 'member', 'function', 'templateParam')
1620
+ type = self._parse_type(outer=outer, named=named)
1621
+ if outer != 'templateParam':
1622
+ init = self._parse_initializer(outer=outer)
1623
+ return ASTTypeWithInit(type, init)
1624
+ # it could also be a constrained type parameter, e.g., C T = int&
1625
+ pos = self.pos
1626
+ eExpr = None
1627
+ try:
1628
+ init = self._parse_initializer(outer=outer, allowFallback=False)
1629
+ # note: init may be None if there is no =
1630
+ if init is None:
1631
+ return ASTTypeWithInit(type, None)
1632
+ # we parsed an expression, so we must have a , or a >,
1633
+ # otherwise the expression didn't get everything
1634
+ self.skip_ws()
1635
+ if self.current_char != ',' and self.current_char != '>':
1636
+ # pretend it didn't happen
1637
+ self.pos = pos
1638
+ init = None
1639
+ else:
1640
+ # we assume that it was indeed an expression
1641
+ return ASTTypeWithInit(type, init)
1642
+ except DefinitionError as e:
1643
+ self.pos = pos
1644
+ eExpr = e
1645
+ if not self.skip_string("="):
1646
+ return ASTTypeWithInit(type, None)
1647
+ try:
1648
+ typeInit = self._parse_type(named=False, outer=None)
1649
+ return ASTTemplateParamConstrainedTypeWithInit(type, typeInit)
1650
+ except DefinitionError as eType:
1651
+ if eExpr is None:
1652
+ raise
1653
+ errs = []
1654
+ errs.append((eExpr, "If default template argument is an expression"))
1655
+ errs.append((eType, "If default template argument is a type"))
1656
+ msg = "Error in non-type template parameter"
1657
+ msg += " or constrained template parameter."
1658
+ raise self._make_multi_error(errs, msg) from eType
1659
+
1660
+ def _parse_type_using(self) -> ASTTypeUsing:
1661
+ name = self._parse_nested_name()
1662
+ self.skip_ws()
1663
+ if not self.skip_string('='):
1664
+ return ASTTypeUsing(name, None)
1665
+ type = self._parse_type(False, None)
1666
+ return ASTTypeUsing(name, type)
1667
+
1668
+ def _parse_concept(self) -> ASTConcept:
1669
+ nestedName = self._parse_nested_name()
1670
+ self.skip_ws()
1671
+ initializer = self._parse_initializer('member')
1672
+ return ASTConcept(nestedName, initializer)
1673
+
1674
+ def _parse_class(self) -> ASTClass:
1675
+ attrs = self._parse_attribute_list()
1676
+ name = self._parse_nested_name()
1677
+ self.skip_ws()
1678
+ final = self.skip_word_and_ws('final')
1679
+ bases = []
1680
+ self.skip_ws()
1681
+ if self.skip_string(':'):
1682
+ while 1:
1683
+ self.skip_ws()
1684
+ visibility = None
1685
+ virtual = False
1686
+ pack = False
1687
+ if self.skip_word_and_ws('virtual'):
1688
+ virtual = True
1689
+ if self.match(_visibility_re):
1690
+ visibility = self.matched_text
1691
+ self.skip_ws()
1692
+ if not virtual and self.skip_word_and_ws('virtual'):
1693
+ virtual = True
1694
+ baseName = self._parse_nested_name()
1695
+ self.skip_ws()
1696
+ pack = self.skip_string('...')
1697
+ bases.append(ASTBaseClass(baseName, visibility, virtual, pack))
1698
+ self.skip_ws()
1699
+ if self.skip_string(','):
1700
+ continue
1701
+ break
1702
+ return ASTClass(name, final, bases, attrs)
1703
+
1704
+ def _parse_union(self) -> ASTUnion:
1705
+ attrs = self._parse_attribute_list()
1706
+ name = self._parse_nested_name()
1707
+ return ASTUnion(name, attrs)
1708
+
1709
+ def _parse_enum(self) -> ASTEnum:
1710
+ scoped = None # is set by CPPEnumObject
1711
+ attrs = self._parse_attribute_list()
1712
+ name = self._parse_nested_name()
1713
+ self.skip_ws()
1714
+ underlyingType = None
1715
+ if self.skip_string(':'):
1716
+ underlyingType = self._parse_type(named=False)
1717
+ return ASTEnum(name, scoped, underlyingType, attrs)
1718
+
1719
+ def _parse_enumerator(self) -> ASTEnumerator:
1720
+ name = self._parse_nested_name()
1721
+ attrs = self._parse_attribute_list()
1722
+ self.skip_ws()
1723
+ init = None
1724
+ if self.skip_string('='):
1725
+ self.skip_ws()
1726
+
1727
+ def parser() -> ASTExpression:
1728
+ return self._parse_constant_expression(inTemplate=False)
1729
+ initVal = self._parse_expression_fallback([], parser)
1730
+ init = ASTInitializer(initVal)
1731
+ return ASTEnumerator(name, init, attrs)
1732
+
1733
+ # ==========================================================================
1734
+
1735
+ def _parse_template_parameter(self) -> ASTTemplateParam:
1736
+ self.skip_ws()
1737
+ if self.skip_word('template'):
1738
+ # declare a template template parameter
1739
+ nestedParams = self._parse_template_parameter_list()
1740
+ else:
1741
+ nestedParams = None
1742
+
1743
+ pos = self.pos
1744
+ try:
1745
+ # Unconstrained type parameter or template type parameter
1746
+ key = None
1747
+ self.skip_ws()
1748
+ if self.skip_word_and_ws('typename'):
1749
+ key = 'typename'
1750
+ elif self.skip_word_and_ws('class'):
1751
+ key = 'class'
1752
+ elif nestedParams:
1753
+ self.fail("Expected 'typename' or 'class' after "
1754
+ "template template parameter list.")
1755
+ else:
1756
+ self.fail("Expected 'typename' or 'class' in the "
1757
+ "beginning of template type parameter.")
1758
+ self.skip_ws()
1759
+ parameterPack = self.skip_string('...')
1760
+ self.skip_ws()
1761
+ if self.match(identifier_re):
1762
+ identifier = ASTIdentifier(self.matched_text)
1763
+ else:
1764
+ identifier = None
1765
+ self.skip_ws()
1766
+ if not parameterPack and self.skip_string('='):
1767
+ default = self._parse_type(named=False, outer=None)
1768
+ else:
1769
+ default = None
1770
+ if self.current_char not in ',>':
1771
+ self.fail('Expected "," or ">" after (template) type parameter.')
1772
+ data = ASTTemplateKeyParamPackIdDefault(key, identifier,
1773
+ parameterPack, default)
1774
+ if nestedParams:
1775
+ return ASTTemplateParamTemplateType(nestedParams, data)
1776
+ else:
1777
+ return ASTTemplateParamType(data)
1778
+ except DefinitionError as eType:
1779
+ if nestedParams:
1780
+ raise
1781
+ try:
1782
+ # non-type parameter or constrained type parameter
1783
+ self.pos = pos
1784
+ param = self._parse_type_with_init('maybe', 'templateParam')
1785
+ self.skip_ws()
1786
+ parameterPack = self.skip_string('...')
1787
+ return ASTTemplateParamNonType(param, parameterPack)
1788
+ except DefinitionError as eNonType:
1789
+ self.pos = pos
1790
+ header = "Error when parsing template parameter."
1791
+ errs = []
1792
+ errs.append(
1793
+ (eType, "If unconstrained type parameter or template type parameter"))
1794
+ errs.append(
1795
+ (eNonType, "If constrained type parameter or non-type parameter"))
1796
+ raise self._make_multi_error(errs, header) from None
1797
+
1798
+ def _parse_template_parameter_list(self) -> ASTTemplateParams:
1799
+ # only: '<' parameter-list '>'
1800
+ # we assume that 'template' has just been parsed
1801
+ templateParams: list[ASTTemplateParam] = []
1802
+ self.skip_ws()
1803
+ if not self.skip_string("<"):
1804
+ self.fail("Expected '<' after 'template'")
1805
+ while 1:
1806
+ pos = self.pos
1807
+ err = None
1808
+ try:
1809
+ param = self._parse_template_parameter()
1810
+ templateParams.append(param)
1811
+ except DefinitionError as eParam:
1812
+ self.pos = pos
1813
+ err = eParam
1814
+ self.skip_ws()
1815
+ if self.skip_string('>'):
1816
+ requiresClause = self._parse_requires_clause()
1817
+ return ASTTemplateParams(templateParams, requiresClause)
1818
+ elif self.skip_string(','):
1819
+ continue
1820
+ else:
1821
+ header = "Error in template parameter list."
1822
+ errs = []
1823
+ if err:
1824
+ errs.append((err, "If parameter"))
1825
+ try:
1826
+ self.fail('Expected "," or ">".')
1827
+ except DefinitionError as e:
1828
+ errs.append((e, "If no parameter"))
1829
+ logger.debug(errs)
1830
+ raise self._make_multi_error(errs, header)
1831
+
1832
+ def _parse_template_introduction(self) -> ASTTemplateIntroduction | None:
1833
+ pos = self.pos
1834
+ try:
1835
+ concept = self._parse_nested_name()
1836
+ except Exception:
1837
+ self.pos = pos
1838
+ return None
1839
+ self.skip_ws()
1840
+ if not self.skip_string('{'):
1841
+ self.pos = pos
1842
+ return None
1843
+
1844
+ # for sure it must be a template introduction now
1845
+ params = []
1846
+ while 1:
1847
+ self.skip_ws()
1848
+ parameterPack = self.skip_string('...')
1849
+ self.skip_ws()
1850
+ if not self.match(identifier_re):
1851
+ self.fail("Expected identifier in template introduction list.")
1852
+ txt_identifier = self.matched_text
1853
+ # make sure there isn't a keyword
1854
+ if txt_identifier in _keywords:
1855
+ self.fail("Expected identifier in template introduction list, "
1856
+ "got keyword: %s" % txt_identifier)
1857
+ identifier = ASTIdentifier(txt_identifier)
1858
+ params.append(ASTTemplateIntroductionParameter(identifier, parameterPack))
1859
+
1860
+ self.skip_ws()
1861
+ if self.skip_string('}'):
1862
+ break
1863
+ if self.skip_string(','):
1864
+ continue
1865
+ self.fail('Error in template introduction list. Expected ",", or "}".')
1866
+ return ASTTemplateIntroduction(concept, params)
1867
+
1868
+ def _parse_requires_clause(self) -> ASTRequiresClause | None:
1869
+ # requires-clause -> 'requires' constraint-logical-or-expression
1870
+ # constraint-logical-or-expression
1871
+ # -> constraint-logical-and-expression
1872
+ # | constraint-logical-or-expression '||' constraint-logical-and-expression
1873
+ # constraint-logical-and-expression
1874
+ # -> primary-expression
1875
+ # | constraint-logical-and-expression '&&' primary-expression
1876
+ self.skip_ws()
1877
+ if not self.skip_word('requires'):
1878
+ return None
1879
+
1880
+ def parse_and_expr(self: DefinitionParser) -> ASTExpression:
1881
+ andExprs = []
1882
+ ops = []
1883
+ andExprs.append(self._parse_primary_expression())
1884
+ while True:
1885
+ self.skip_ws()
1886
+ oneMore = False
1887
+ if self.skip_string('&&'):
1888
+ oneMore = True
1889
+ ops.append('&&')
1890
+ elif self.skip_word('and'):
1891
+ oneMore = True
1892
+ ops.append('and')
1893
+ if not oneMore:
1894
+ break
1895
+ andExprs.append(self._parse_primary_expression())
1896
+ if len(andExprs) == 1:
1897
+ return andExprs[0]
1898
+ else:
1899
+ return ASTBinOpExpr(andExprs, ops)
1900
+
1901
+ orExprs = []
1902
+ ops = []
1903
+ orExprs.append(parse_and_expr(self))
1904
+ while True:
1905
+ self.skip_ws()
1906
+ oneMore = False
1907
+ if self.skip_string('||'):
1908
+ oneMore = True
1909
+ ops.append('||')
1910
+ elif self.skip_word('or'):
1911
+ oneMore = True
1912
+ ops.append('or')
1913
+ if not oneMore:
1914
+ break
1915
+ orExprs.append(parse_and_expr(self))
1916
+ if len(orExprs) == 1:
1917
+ return ASTRequiresClause(orExprs[0])
1918
+ else:
1919
+ return ASTRequiresClause(ASTBinOpExpr(orExprs, ops))
1920
+
1921
+ def _parse_template_declaration_prefix(self, objectType: str,
1922
+ ) -> ASTTemplateDeclarationPrefix | None:
1923
+ templates: list[ASTTemplateParams | ASTTemplateIntroduction] = []
1924
+ while 1:
1925
+ self.skip_ws()
1926
+ # the saved position is only used to provide a better error message
1927
+ params: ASTTemplateParams | ASTTemplateIntroduction | None = None
1928
+ pos = self.pos
1929
+ if self.skip_word("template"):
1930
+ try:
1931
+ params = self._parse_template_parameter_list()
1932
+ except DefinitionError as e:
1933
+ if objectType == 'member' and len(templates) == 0:
1934
+ return ASTTemplateDeclarationPrefix(None)
1935
+ else:
1936
+ raise e
1937
+ if objectType == 'concept' and params.requiresClause is not None:
1938
+ self.fail('requires-clause not allowed for concept')
1939
+ else:
1940
+ params = self._parse_template_introduction()
1941
+ if not params:
1942
+ break
1943
+ if objectType == 'concept' and len(templates) > 0:
1944
+ self.pos = pos
1945
+ self.fail("More than 1 template parameter list for concept.")
1946
+ templates.append(params)
1947
+ if len(templates) == 0 and objectType == 'concept':
1948
+ self.fail('Missing template parameter list for concept.')
1949
+ if len(templates) == 0:
1950
+ return None
1951
+ else:
1952
+ return ASTTemplateDeclarationPrefix(templates)
1953
+
1954
+ def _check_template_consistency(self, nestedName: ASTNestedName,
1955
+ templatePrefix: ASTTemplateDeclarationPrefix,
1956
+ fullSpecShorthand: bool, isMember: bool = False,
1957
+ ) -> ASTTemplateDeclarationPrefix:
1958
+ numArgs = nestedName.num_templates()
1959
+ isMemberInstantiation = False
1960
+ if not templatePrefix:
1961
+ numParams = 0
1962
+ else:
1963
+ if isMember and templatePrefix.templates is None:
1964
+ numParams = 0
1965
+ isMemberInstantiation = True
1966
+ else:
1967
+ numParams = len(templatePrefix.templates)
1968
+ if numArgs + 1 < numParams:
1969
+ self.fail("Too few template argument lists compared to parameter"
1970
+ " lists. Argument lists: %d, Parameter lists: %d."
1971
+ % (numArgs, numParams))
1972
+ if numArgs > numParams:
1973
+ numExtra = numArgs - numParams
1974
+ if not fullSpecShorthand and not isMemberInstantiation:
1975
+ msg = "Too many template argument lists compared to parameter" \
1976
+ " lists. Argument lists: %d, Parameter lists: %d," \
1977
+ " Extra empty parameters lists prepended: %d." \
1978
+ % (numArgs, numParams, numExtra)
1979
+ msg += " Declaration:\n\t"
1980
+ if templatePrefix:
1981
+ msg += "%s\n\t" % templatePrefix
1982
+ msg += str(nestedName)
1983
+ self.warn(msg)
1984
+
1985
+ newTemplates: list[ASTTemplateParams | ASTTemplateIntroduction] = [
1986
+ ASTTemplateParams([], requiresClause=None)
1987
+ for _i in range(numExtra)
1988
+ ]
1989
+ if templatePrefix and not isMemberInstantiation:
1990
+ newTemplates.extend(templatePrefix.templates)
1991
+ templatePrefix = ASTTemplateDeclarationPrefix(newTemplates)
1992
+ return templatePrefix
1993
+
1994
+ def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclaration:
1995
+ if objectType not in ('class', 'union', 'function', 'member', 'type',
1996
+ 'concept', 'enum', 'enumerator'):
1997
+ raise Exception('Internal error, unknown objectType "%s".' % objectType)
1998
+ if directiveType not in ('class', 'struct', 'union', 'function', 'member', 'var',
1999
+ 'type', 'concept',
2000
+ 'enum', 'enum-struct', 'enum-class', 'enumerator'):
2001
+ raise Exception('Internal error, unknown directiveType "%s".' % directiveType)
2002
+ visibility = None
2003
+ templatePrefix = None
2004
+ trailingRequiresClause = None
2005
+ declaration: Any = None
2006
+
2007
+ self.skip_ws()
2008
+ if self.match(_visibility_re):
2009
+ visibility = self.matched_text
2010
+
2011
+ if objectType in ('type', 'concept', 'member', 'function', 'class', 'union'):
2012
+ templatePrefix = self._parse_template_declaration_prefix(objectType)
2013
+
2014
+ if objectType == 'type':
2015
+ prevErrors = []
2016
+ pos = self.pos
2017
+ try:
2018
+ if not templatePrefix:
2019
+ declaration = self._parse_type(named=True, outer='type')
2020
+ except DefinitionError as e:
2021
+ prevErrors.append((e, "If typedef-like declaration"))
2022
+ self.pos = pos
2023
+ pos = self.pos
2024
+ try:
2025
+ if not declaration:
2026
+ declaration = self._parse_type_using()
2027
+ except DefinitionError as e:
2028
+ self.pos = pos
2029
+ prevErrors.append((e, "If type alias or template alias"))
2030
+ header = "Error in type declaration."
2031
+ raise self._make_multi_error(prevErrors, header) from e
2032
+ elif objectType == 'concept':
2033
+ declaration = self._parse_concept()
2034
+ elif objectType == 'member':
2035
+ declaration = self._parse_type_with_init(named=True, outer='member')
2036
+ elif objectType == 'function':
2037
+ declaration = self._parse_type(named=True, outer='function')
2038
+ trailingRequiresClause = self._parse_requires_clause()
2039
+ elif objectType == 'class':
2040
+ declaration = self._parse_class()
2041
+ elif objectType == 'union':
2042
+ declaration = self._parse_union()
2043
+ elif objectType == 'enum':
2044
+ declaration = self._parse_enum()
2045
+ elif objectType == 'enumerator':
2046
+ declaration = self._parse_enumerator()
2047
+ else:
2048
+ raise AssertionError
2049
+ templatePrefix = self._check_template_consistency(declaration.name,
2050
+ templatePrefix,
2051
+ fullSpecShorthand=False,
2052
+ isMember=objectType == 'member')
2053
+ self.skip_ws()
2054
+ semicolon = self.skip_string(';')
2055
+ return ASTDeclaration(objectType, directiveType, visibility,
2056
+ templatePrefix, declaration,
2057
+ trailingRequiresClause, semicolon)
2058
+
2059
+ def parse_namespace_object(self) -> ASTNamespace:
2060
+ templatePrefix = self._parse_template_declaration_prefix(objectType="namespace")
2061
+ name = self._parse_nested_name()
2062
+ templatePrefix = self._check_template_consistency(name, templatePrefix,
2063
+ fullSpecShorthand=False)
2064
+ res = ASTNamespace(name, templatePrefix)
2065
+ res.objectType = 'namespace' # type: ignore[attr-defined]
2066
+ return res
2067
+
2068
+ def parse_xref_object(self) -> tuple[ASTNamespace | ASTDeclaration, bool]:
2069
+ pos = self.pos
2070
+ try:
2071
+ templatePrefix = self._parse_template_declaration_prefix(objectType="xref")
2072
+ name = self._parse_nested_name()
2073
+ # if there are '()' left, just skip them
2074
+ self.skip_ws()
2075
+ self.skip_string('()')
2076
+ self.assert_end()
2077
+ templatePrefix = self._check_template_consistency(name, templatePrefix,
2078
+ fullSpecShorthand=True)
2079
+ res1 = ASTNamespace(name, templatePrefix)
2080
+ res1.objectType = 'xref' # type: ignore[attr-defined]
2081
+ return res1, True
2082
+ except DefinitionError as e1:
2083
+ try:
2084
+ self.pos = pos
2085
+ res2 = self.parse_declaration('function', 'function')
2086
+ # if there are '()' left, just skip them
2087
+ self.skip_ws()
2088
+ self.skip_string('()')
2089
+ self.assert_end()
2090
+ return res2, False
2091
+ except DefinitionError as e2:
2092
+ errs = []
2093
+ errs.append((e1, "If shorthand ref"))
2094
+ errs.append((e2, "If full function ref"))
2095
+ msg = "Error in cross-reference."
2096
+ raise self._make_multi_error(errs, msg) from e2
2097
+
2098
+ def parse_expression(self) -> ASTExpression | ASTType:
2099
+ pos = self.pos
2100
+ try:
2101
+ expr = self._parse_expression()
2102
+ self.skip_ws()
2103
+ self.assert_end()
2104
+ return expr
2105
+ except DefinitionError as exExpr:
2106
+ self.pos = pos
2107
+ try:
2108
+ typ = self._parse_type(False)
2109
+ self.skip_ws()
2110
+ self.assert_end()
2111
+ return typ
2112
+ except DefinitionError as exType:
2113
+ header = "Error when parsing (type) expression."
2114
+ errs = []
2115
+ errs.append((exExpr, "If expression"))
2116
+ errs.append((exType, "If type"))
2117
+ raise self._make_multi_error(errs, header) from exType