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.
- sphinx/__init__.py +8 -9
- sphinx/addnodes.py +31 -28
- sphinx/application.py +9 -15
- sphinx/builders/__init__.py +5 -6
- sphinx/builders/_epub_base.py +17 -9
- sphinx/builders/changes.py +10 -5
- sphinx/builders/dirhtml.py +4 -2
- sphinx/builders/dummy.py +3 -2
- sphinx/builders/epub3.py +5 -3
- sphinx/builders/gettext.py +24 -7
- sphinx/builders/html/__init__.py +88 -96
- sphinx/builders/html/_assets.py +16 -16
- sphinx/builders/html/transforms.py +4 -2
- sphinx/builders/latex/__init__.py +40 -33
- sphinx/builders/latex/nodes.py +6 -2
- sphinx/builders/latex/transforms.py +17 -8
- sphinx/builders/latex/util.py +1 -1
- sphinx/builders/linkcheck.py +86 -27
- sphinx/builders/manpage.py +8 -6
- sphinx/builders/singlehtml.py +5 -4
- sphinx/builders/texinfo.py +18 -14
- sphinx/builders/text.py +3 -2
- sphinx/builders/xml.py +5 -2
- sphinx/cmd/build.py +119 -76
- sphinx/cmd/make_mode.py +21 -20
- sphinx/cmd/quickstart.py +13 -16
- sphinx/config.py +432 -250
- sphinx/deprecation.py +23 -13
- sphinx/directives/__init__.py +8 -8
- sphinx/directives/code.py +7 -7
- sphinx/directives/other.py +23 -13
- sphinx/directives/patches.py +7 -6
- sphinx/domains/__init__.py +2 -2
- sphinx/domains/c/__init__.py +796 -0
- sphinx/domains/c/_ast.py +1421 -0
- sphinx/domains/c/_ids.py +65 -0
- sphinx/domains/c/_parser.py +1048 -0
- sphinx/domains/c/_symbol.py +700 -0
- sphinx/domains/changeset.py +11 -7
- sphinx/domains/citation.py +5 -2
- sphinx/domains/cpp/__init__.py +1089 -0
- sphinx/domains/cpp/_ast.py +3635 -0
- sphinx/domains/cpp/_ids.py +537 -0
- sphinx/domains/cpp/_parser.py +2117 -0
- sphinx/domains/cpp/_symbol.py +1092 -0
- sphinx/domains/index.py +6 -4
- sphinx/domains/javascript.py +16 -13
- sphinx/domains/math.py +9 -4
- sphinx/domains/python/__init__.py +890 -0
- sphinx/domains/python/_annotations.py +507 -0
- sphinx/domains/python/_object.py +426 -0
- sphinx/domains/rst.py +12 -7
- sphinx/domains/{std.py → std/__init__.py} +19 -16
- sphinx/environment/__init__.py +21 -19
- sphinx/environment/adapters/indexentries.py +2 -2
- sphinx/environment/adapters/toctree.py +10 -9
- sphinx/environment/collectors/__init__.py +6 -3
- sphinx/environment/collectors/asset.py +4 -3
- sphinx/environment/collectors/dependencies.py +3 -2
- sphinx/environment/collectors/metadata.py +6 -5
- sphinx/environment/collectors/title.py +3 -2
- sphinx/environment/collectors/toctree.py +5 -4
- sphinx/errors.py +13 -2
- sphinx/events.py +14 -9
- sphinx/ext/apidoc.py +9 -11
- sphinx/ext/autodoc/__init__.py +105 -71
- sphinx/ext/autodoc/directive.py +7 -6
- sphinx/ext/autodoc/importer.py +132 -52
- sphinx/ext/autodoc/mock.py +7 -5
- sphinx/ext/autodoc/preserve_defaults.py +4 -3
- sphinx/ext/autodoc/type_comment.py +2 -1
- sphinx/ext/autodoc/typehints.py +5 -4
- sphinx/ext/autosectionlabel.py +3 -2
- sphinx/ext/autosummary/__init__.py +21 -17
- sphinx/ext/autosummary/generate.py +9 -9
- sphinx/ext/coverage.py +26 -20
- sphinx/ext/doctest.py +38 -33
- sphinx/ext/duration.py +1 -0
- sphinx/ext/extlinks.py +4 -3
- sphinx/ext/githubpages.py +3 -2
- sphinx/ext/graphviz.py +10 -7
- sphinx/ext/ifconfig.py +5 -5
- sphinx/ext/imgconverter.py +6 -5
- sphinx/ext/imgmath.py +9 -8
- sphinx/ext/inheritance_diagram.py +31 -31
- sphinx/ext/intersphinx.py +140 -23
- sphinx/ext/linkcode.py +3 -2
- sphinx/ext/mathjax.py +2 -1
- sphinx/ext/napoleon/__init__.py +12 -7
- sphinx/ext/napoleon/docstring.py +34 -32
- sphinx/ext/todo.py +10 -7
- sphinx/ext/viewcode.py +12 -11
- sphinx/extension.py +18 -8
- sphinx/highlighting.py +39 -20
- sphinx/io.py +17 -8
- sphinx/jinja2glue.py +16 -15
- sphinx/locale/__init__.py +30 -23
- sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +818 -761
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +835 -778
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +864 -807
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +816 -759
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +819 -762
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +838 -781
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +838 -781
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +853 -796
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +856 -799
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +820 -763
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +856 -799
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +845 -788
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +854 -797
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +816 -759
- sphinx/locale/fr/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr/LC_MESSAGES/sphinx.po +904 -847
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/gl/LC_MESSAGES/sphinx.js +54 -54
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +1506 -1449
- sphinx/locale/he/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.po +823 -766
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +853 -796
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +844 -787
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +854 -797
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +853 -796
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +848 -791
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +855 -798
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +825 -768
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +27 -27
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +876 -818
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +844 -787
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +845 -788
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +908 -851
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ru/LC_MESSAGES/sphinx.po +838 -781
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +823 -766
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +854 -797
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +832 -775
- sphinx/locale/sphinx.pot +813 -755
- sphinx/locale/sq/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sq/LC_MESSAGES/sphinx.po +865 -808
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +835 -778
- sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/ta/LC_MESSAGES/sphinx.js +54 -54
- sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ta/LC_MESSAGES/sphinx.po +1530 -1473
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +853 -796
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +833 -776
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +855 -798
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +879 -822
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +811 -754
- sphinx/parsers.py +7 -5
- sphinx/project.py +18 -11
- sphinx/pycode/__init__.py +6 -5
- sphinx/pycode/ast.py +23 -8
- sphinx/pycode/parser.py +6 -5
- sphinx/registry.py +12 -6
- sphinx/roles.py +103 -57
- sphinx/search/__init__.py +17 -18
- sphinx/search/da.py +2 -2
- sphinx/search/de.py +2 -2
- sphinx/search/en.py +1 -1
- sphinx/search/es.py +2 -2
- sphinx/search/fi.py +2 -2
- sphinx/search/fr.py +2 -2
- sphinx/search/hu.py +2 -2
- sphinx/search/it.py +2 -2
- sphinx/search/ja.py +13 -22
- sphinx/search/nl.py +2 -2
- sphinx/search/no.py +2 -2
- sphinx/search/pt.py +2 -2
- sphinx/search/ro.py +1 -1
- sphinx/search/ru.py +2 -2
- sphinx/search/sv.py +2 -2
- sphinx/search/tr.py +1 -1
- sphinx/search/zh.py +2 -3
- sphinx/templates/graphviz/graphviz.css +1 -1
- sphinx/testing/fixtures.py +41 -24
- sphinx/testing/path.py +1 -1
- sphinx/testing/util.py +142 -53
- sphinx/texinputs/sphinx.xdy +1 -1
- sphinx/texinputs/sphinxlatextables.sty +1 -1
- sphinx/texinputs/sphinxpackagesubstitutefont.sty +21 -0
- sphinx/themes/agogo/layout.html +4 -4
- sphinx/themes/agogo/static/agogo.css_t +1 -1
- sphinx/themes/agogo/theme.toml +22 -0
- sphinx/themes/basic/defindex.html +1 -1
- sphinx/themes/basic/domainindex.html +1 -1
- sphinx/themes/basic/genindex-single.html +1 -1
- sphinx/themes/basic/genindex-split.html +1 -1
- sphinx/themes/basic/genindex.html +1 -1
- sphinx/themes/basic/globaltoc.html +1 -1
- sphinx/themes/basic/layout.html +1 -1
- sphinx/themes/basic/localtoc.html +1 -1
- sphinx/themes/basic/page.html +1 -1
- sphinx/themes/basic/relations.html +1 -1
- sphinx/themes/basic/search.html +5 -20
- sphinx/themes/basic/searchbox.html +3 -3
- sphinx/themes/basic/searchfield.html +3 -3
- sphinx/themes/basic/sourcelink.html +1 -1
- sphinx/themes/basic/static/basic.css_t +1 -1
- sphinx/themes/basic/static/doctools.js +1 -1
- sphinx/themes/basic/static/language_data.js_t +2 -2
- sphinx/themes/basic/static/searchtools.js +105 -60
- sphinx/themes/basic/theme.toml +23 -0
- sphinx/themes/bizstyle/layout.html +1 -6
- sphinx/themes/bizstyle/static/bizstyle.css_t +1 -1
- sphinx/themes/bizstyle/static/bizstyle.js_t +1 -1
- sphinx/themes/bizstyle/static/css3-mediaqueries_src.js +3 -3
- sphinx/themes/bizstyle/theme.toml +12 -0
- sphinx/themes/classic/layout.html +1 -1
- sphinx/themes/classic/static/classic.css_t +1 -1
- sphinx/themes/classic/static/sidebar.js_t +1 -1
- sphinx/themes/classic/theme.toml +34 -0
- sphinx/themes/default/theme.toml +2 -0
- sphinx/themes/epub/epub-cover.html +1 -1
- sphinx/themes/epub/layout.html +1 -1
- sphinx/themes/epub/static/epub.css_t +1 -1
- sphinx/themes/epub/theme.toml +10 -0
- sphinx/themes/haiku/layout.html +3 -3
- sphinx/themes/haiku/static/haiku.css_t +2 -2
- sphinx/themes/haiku/theme.toml +16 -0
- sphinx/themes/nature/static/nature.css_t +1 -1
- sphinx/themes/nature/theme.toml +6 -0
- sphinx/themes/nonav/layout.html +1 -1
- sphinx/themes/nonav/static/nonav.css_t +1 -1
- sphinx/themes/nonav/theme.toml +10 -0
- sphinx/themes/pyramid/static/epub.css_t +1 -1
- sphinx/themes/pyramid/static/pyramid.css_t +1 -1
- sphinx/themes/pyramid/theme.toml +6 -0
- sphinx/themes/scrolls/artwork/logo.svg +1 -1
- sphinx/themes/scrolls/layout.html +2 -2
- sphinx/themes/scrolls/static/scrolls.css_t +1 -1
- sphinx/themes/scrolls/theme.toml +15 -0
- sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +1 -1
- sphinx/themes/sphinxdoc/theme.toml +6 -0
- sphinx/themes/traditional/static/traditional.css_t +1 -1
- sphinx/themes/traditional/theme.toml +9 -0
- sphinx/theming.py +427 -131
- sphinx/transforms/__init__.py +21 -24
- sphinx/transforms/compact_bullet_list.py +5 -5
- sphinx/transforms/i18n.py +30 -28
- sphinx/transforms/post_transforms/__init__.py +9 -7
- sphinx/transforms/post_transforms/code.py +4 -1
- sphinx/transforms/post_transforms/images.py +17 -13
- sphinx/transforms/references.py +3 -1
- sphinx/util/__init__.py +15 -11
- sphinx/util/_io.py +34 -0
- sphinx/util/_pathlib.py +23 -18
- sphinx/util/build_phase.py +1 -0
- sphinx/util/cfamily.py +19 -11
- sphinx/util/console.py +101 -21
- sphinx/util/display.py +3 -2
- sphinx/util/docfields.py +12 -8
- sphinx/util/docutils.py +21 -35
- sphinx/util/exceptions.py +3 -2
- sphinx/util/fileutil.py +5 -5
- sphinx/util/http_date.py +9 -2
- sphinx/util/i18n.py +40 -9
- sphinx/util/inspect.py +317 -245
- sphinx/util/inventory.py +22 -5
- sphinx/util/logging.py +81 -7
- sphinx/util/matching.py +2 -1
- sphinx/util/math.py +1 -2
- sphinx/util/nodes.py +39 -29
- sphinx/util/osutil.py +25 -6
- sphinx/util/parallel.py +6 -1
- sphinx/util/requests.py +8 -5
- sphinx/util/rst.py +8 -6
- sphinx/util/tags.py +3 -3
- sphinx/util/template.py +8 -3
- sphinx/util/typing.py +76 -42
- sphinx/versioning.py +6 -2
- sphinx/writers/html.py +1 -1
- sphinx/writers/html5.py +17 -13
- sphinx/writers/latex.py +12 -12
- sphinx/writers/manpage.py +13 -7
- sphinx/writers/texinfo.py +13 -10
- sphinx/writers/text.py +13 -23
- sphinx/writers/xml.py +1 -1
- sphinx-7.2.5.dist-info/LICENSE → sphinx-7.3.0.dist-info/LICENSE.rst +1 -1
- {sphinx-7.2.5.dist-info → sphinx-7.3.0.dist-info}/METADATA +13 -12
- sphinx-7.3.0.dist-info/RECORD +581 -0
- sphinx/domains/c.py +0 -3906
- sphinx/domains/cpp.py +0 -8233
- sphinx/domains/python.py +0 -1769
- sphinx/themes/agogo/theme.conf +0 -20
- sphinx/themes/basic/theme.conf +0 -16
- sphinx/themes/bizstyle/theme.conf +0 -10
- sphinx/themes/classic/theme.conf +0 -32
- sphinx/themes/default/theme.conf +0 -2
- sphinx/themes/epub/theme.conf +0 -8
- sphinx/themes/haiku/theme.conf +0 -14
- sphinx/themes/nature/theme.conf +0 -4
- sphinx/themes/nonav/theme.conf +0 -8
- sphinx/themes/pyramid/theme.conf +0 -4
- sphinx/themes/scrolls/theme.conf +0 -13
- sphinx/themes/sphinxdoc/theme.conf +0 -4
- sphinx/themes/traditional/theme.conf +0 -7
- sphinx-7.2.5.dist-info/RECORD +0 -569
- {sphinx-7.2.5.dist-info → sphinx-7.3.0.dist-info}/WHEEL +0 -0
- {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
|