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