Sphinx 7.2.6__py3-none-any.whl → 7.3.1__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.1.dist-info/LICENSE.rst +1 -1
- {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/METADATA +14 -12
- sphinx-7.3.1.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.1.dist-info}/WHEEL +0 -0
- {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/entry_points.txt +0 -0
sphinx/domains/c.py
DELETED
|
@@ -1,3906 +0,0 @@
|
|
|
1
|
-
"""The C language domain."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import re
|
|
6
|
-
from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union, cast
|
|
7
|
-
|
|
8
|
-
from docutils import nodes
|
|
9
|
-
from docutils.parsers.rst import directives
|
|
10
|
-
|
|
11
|
-
from sphinx import addnodes
|
|
12
|
-
from sphinx.directives import ObjectDescription
|
|
13
|
-
from sphinx.domains import Domain, ObjType
|
|
14
|
-
from sphinx.locale import _, __
|
|
15
|
-
from sphinx.roles import SphinxRole, XRefRole
|
|
16
|
-
from sphinx.transforms import SphinxTransform
|
|
17
|
-
from sphinx.transforms.post_transforms import ReferencesResolver
|
|
18
|
-
from sphinx.util import logging
|
|
19
|
-
from sphinx.util.cfamily import (
|
|
20
|
-
ASTAttributeList,
|
|
21
|
-
ASTBaseBase,
|
|
22
|
-
ASTBaseParenExprList,
|
|
23
|
-
BaseParser,
|
|
24
|
-
DefinitionError,
|
|
25
|
-
NoOldIdError,
|
|
26
|
-
StringifyTransform,
|
|
27
|
-
UnsupportedMultiCharacterCharLiteral,
|
|
28
|
-
anon_identifier_re,
|
|
29
|
-
binary_literal_re,
|
|
30
|
-
char_literal_re,
|
|
31
|
-
float_literal_re,
|
|
32
|
-
float_literal_suffix_re,
|
|
33
|
-
hex_literal_re,
|
|
34
|
-
identifier_re,
|
|
35
|
-
integer_literal_re,
|
|
36
|
-
integers_literal_suffix_re,
|
|
37
|
-
octal_literal_re,
|
|
38
|
-
verify_description_mode,
|
|
39
|
-
)
|
|
40
|
-
from sphinx.util.docfields import Field, GroupedField, TypedField
|
|
41
|
-
from sphinx.util.docutils import SphinxDirective
|
|
42
|
-
from sphinx.util.nodes import make_refnode
|
|
43
|
-
|
|
44
|
-
if TYPE_CHECKING:
|
|
45
|
-
from collections.abc import Generator, Iterator
|
|
46
|
-
|
|
47
|
-
from docutils.nodes import Element, Node, TextElement, system_message
|
|
48
|
-
|
|
49
|
-
from sphinx.addnodes import pending_xref
|
|
50
|
-
from sphinx.application import Sphinx
|
|
51
|
-
from sphinx.builders import Builder
|
|
52
|
-
from sphinx.environment import BuildEnvironment
|
|
53
|
-
from sphinx.util.typing import OptionSpec
|
|
54
|
-
|
|
55
|
-
logger = logging.getLogger(__name__)
|
|
56
|
-
T = TypeVar('T')
|
|
57
|
-
|
|
58
|
-
DeclarationType = Union[
|
|
59
|
-
"ASTStruct", "ASTUnion", "ASTEnum", "ASTEnumerator",
|
|
60
|
-
"ASTType", "ASTTypeWithInit", "ASTMacro",
|
|
61
|
-
]
|
|
62
|
-
|
|
63
|
-
# https://en.cppreference.com/w/c/keyword
|
|
64
|
-
_keywords = [
|
|
65
|
-
'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', 'double',
|
|
66
|
-
'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'inline', 'int', 'long',
|
|
67
|
-
'register', 'restrict', 'return', 'short', 'signed', 'sizeof', 'static', 'struct',
|
|
68
|
-
'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while',
|
|
69
|
-
'_Alignas', '_Alignof', '_Atomic', '_Bool', '_Complex',
|
|
70
|
-
'_Decimal32', '_Decimal64', '_Decimal128',
|
|
71
|
-
'_Generic', '_Imaginary', '_Noreturn', '_Static_assert', '_Thread_local',
|
|
72
|
-
]
|
|
73
|
-
# These are only keyword'y when the corresponding headers are included.
|
|
74
|
-
# They are used as default value for c_extra_keywords.
|
|
75
|
-
_macroKeywords = [
|
|
76
|
-
'alignas', 'alignof', 'bool', 'complex', 'imaginary', 'noreturn', 'static_assert',
|
|
77
|
-
'thread_local',
|
|
78
|
-
]
|
|
79
|
-
|
|
80
|
-
# these are ordered by precedence
|
|
81
|
-
_expression_bin_ops = [
|
|
82
|
-
['||', 'or'],
|
|
83
|
-
['&&', 'and'],
|
|
84
|
-
['|', 'bitor'],
|
|
85
|
-
['^', 'xor'],
|
|
86
|
-
['&', 'bitand'],
|
|
87
|
-
['==', '!=', 'not_eq'],
|
|
88
|
-
['<=', '>=', '<', '>'],
|
|
89
|
-
['<<', '>>'],
|
|
90
|
-
['+', '-'],
|
|
91
|
-
['*', '/', '%'],
|
|
92
|
-
['.*', '->*'],
|
|
93
|
-
]
|
|
94
|
-
_expression_unary_ops = ["++", "--", "*", "&", "+", "-", "!", "not", "~", "compl"]
|
|
95
|
-
_expression_assignment_ops = ["=", "*=", "/=", "%=", "+=", "-=",
|
|
96
|
-
">>=", "<<=", "&=", "and_eq", "^=", "xor_eq", "|=", "or_eq"]
|
|
97
|
-
|
|
98
|
-
_max_id = 1
|
|
99
|
-
_id_prefix = [None, 'c.', 'Cv2.']
|
|
100
|
-
# Ids are used in lookup keys which are used across pickled files,
|
|
101
|
-
# so when _max_id changes, make sure to update the ENV_VERSION.
|
|
102
|
-
|
|
103
|
-
_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'"
|
|
104
|
-
r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)
|
|
105
|
-
|
|
106
|
-
# bool, complex, and imaginary are macro "keywords", so they are handled separately
|
|
107
|
-
_simple_type_specifiers_re = re.compile(r"""
|
|
108
|
-
\b(
|
|
109
|
-
void|_Bool
|
|
110
|
-
|signed|unsigned
|
|
111
|
-
|short|long
|
|
112
|
-
|char
|
|
113
|
-
|int
|
|
114
|
-
|__uint128|__int128
|
|
115
|
-
|__int(8|16|32|64|128) # extension
|
|
116
|
-
|float|double
|
|
117
|
-
|_Decimal(32|64|128)
|
|
118
|
-
|_Complex|_Imaginary
|
|
119
|
-
|__float80|_Float64x|__float128|_Float128|__ibm128 # extension
|
|
120
|
-
|__fp16 # extension
|
|
121
|
-
|_Sat|_Fract|fract|_Accum|accum # extension
|
|
122
|
-
)\b
|
|
123
|
-
""", re.VERBOSE)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
class _DuplicateSymbolError(Exception):
|
|
127
|
-
def __init__(self, symbol: Symbol, declaration: ASTDeclaration) -> None:
|
|
128
|
-
assert symbol
|
|
129
|
-
assert declaration
|
|
130
|
-
self.symbol = symbol
|
|
131
|
-
self.declaration = declaration
|
|
132
|
-
|
|
133
|
-
def __str__(self) -> str:
|
|
134
|
-
return "Internal C duplicate symbol error:\n%s" % self.symbol.dump(0)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
class ASTBase(ASTBaseBase):
|
|
138
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
139
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
140
|
-
raise NotImplementedError(repr(self))
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
# Names
|
|
144
|
-
################################################################################
|
|
145
|
-
|
|
146
|
-
class ASTIdentifier(ASTBaseBase):
|
|
147
|
-
def __init__(self, identifier: str) -> None:
|
|
148
|
-
assert identifier is not None
|
|
149
|
-
assert len(identifier) != 0
|
|
150
|
-
self.identifier = identifier
|
|
151
|
-
|
|
152
|
-
def __eq__(self, other: Any) -> bool:
|
|
153
|
-
return type(other) is ASTIdentifier and self.identifier == other.identifier
|
|
154
|
-
|
|
155
|
-
def is_anon(self) -> bool:
|
|
156
|
-
return self.identifier[0] == '@'
|
|
157
|
-
|
|
158
|
-
# and this is where we finally make a difference between __str__ and the display string
|
|
159
|
-
|
|
160
|
-
def __str__(self) -> str:
|
|
161
|
-
return self.identifier
|
|
162
|
-
|
|
163
|
-
def get_display_string(self) -> str:
|
|
164
|
-
return "[anonymous]" if self.is_anon() else self.identifier
|
|
165
|
-
|
|
166
|
-
def describe_signature(self, signode: TextElement, mode: str, env: BuildEnvironment,
|
|
167
|
-
prefix: str, symbol: Symbol) -> None:
|
|
168
|
-
# note: slightly different signature of describe_signature due to the prefix
|
|
169
|
-
verify_description_mode(mode)
|
|
170
|
-
if self.is_anon():
|
|
171
|
-
node = addnodes.desc_sig_name(text="[anonymous]")
|
|
172
|
-
else:
|
|
173
|
-
node = addnodes.desc_sig_name(self.identifier, self.identifier)
|
|
174
|
-
if mode == 'markType':
|
|
175
|
-
targetText = prefix + self.identifier
|
|
176
|
-
pnode = addnodes.pending_xref('', refdomain='c',
|
|
177
|
-
reftype='identifier',
|
|
178
|
-
reftarget=targetText, modname=None,
|
|
179
|
-
classname=None)
|
|
180
|
-
pnode['c:parent_key'] = symbol.get_lookup_key()
|
|
181
|
-
pnode += node
|
|
182
|
-
signode += pnode
|
|
183
|
-
elif mode == 'lastIsName':
|
|
184
|
-
nameNode = addnodes.desc_name()
|
|
185
|
-
nameNode += node
|
|
186
|
-
signode += nameNode
|
|
187
|
-
elif mode == 'noneIsName':
|
|
188
|
-
signode += node
|
|
189
|
-
else:
|
|
190
|
-
raise Exception('Unknown description mode: %s' % mode)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
class ASTNestedName(ASTBase):
|
|
194
|
-
def __init__(self, names: list[ASTIdentifier], rooted: bool) -> None:
|
|
195
|
-
assert len(names) > 0
|
|
196
|
-
self.names = names
|
|
197
|
-
self.rooted = rooted
|
|
198
|
-
|
|
199
|
-
@property
|
|
200
|
-
def name(self) -> ASTNestedName:
|
|
201
|
-
return self
|
|
202
|
-
|
|
203
|
-
def get_id(self, version: int) -> str:
|
|
204
|
-
return '.'.join(str(n) for n in self.names)
|
|
205
|
-
|
|
206
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
207
|
-
res = '.'.join(transform(n) for n in self.names)
|
|
208
|
-
if self.rooted:
|
|
209
|
-
return '.' + res
|
|
210
|
-
else:
|
|
211
|
-
return res
|
|
212
|
-
|
|
213
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
214
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
215
|
-
verify_description_mode(mode)
|
|
216
|
-
# just print the name part, with template args, not template params
|
|
217
|
-
if mode == 'noneIsName':
|
|
218
|
-
if self.rooted:
|
|
219
|
-
unreachable = "Can this happen?"
|
|
220
|
-
raise AssertionError(unreachable) # TODO
|
|
221
|
-
signode += nodes.Text('.')
|
|
222
|
-
for i in range(len(self.names)):
|
|
223
|
-
if i != 0:
|
|
224
|
-
unreachable = "Can this happen?"
|
|
225
|
-
raise AssertionError(unreachable) # TODO
|
|
226
|
-
signode += nodes.Text('.')
|
|
227
|
-
n = self.names[i]
|
|
228
|
-
n.describe_signature(signode, mode, env, '', symbol)
|
|
229
|
-
elif mode == 'param':
|
|
230
|
-
assert not self.rooted, str(self)
|
|
231
|
-
assert len(self.names) == 1
|
|
232
|
-
self.names[0].describe_signature(signode, 'noneIsName', env, '', symbol)
|
|
233
|
-
elif mode in ('markType', 'lastIsName', 'markName'):
|
|
234
|
-
# Each element should be a pending xref targeting the complete
|
|
235
|
-
# prefix.
|
|
236
|
-
prefix = ''
|
|
237
|
-
first = True
|
|
238
|
-
names = self.names[:-1] if mode == 'lastIsName' else self.names
|
|
239
|
-
# If lastIsName, then wrap all of the prefix in a desc_addname,
|
|
240
|
-
# else append directly to signode.
|
|
241
|
-
# TODO: also for C?
|
|
242
|
-
# NOTE: Breathe previously relied on the prefix being in the desc_addname node,
|
|
243
|
-
# so it can remove it in inner declarations.
|
|
244
|
-
dest = signode
|
|
245
|
-
if mode == 'lastIsName':
|
|
246
|
-
dest = addnodes.desc_addname()
|
|
247
|
-
if self.rooted:
|
|
248
|
-
prefix += '.'
|
|
249
|
-
if mode == 'lastIsName' and len(names) == 0:
|
|
250
|
-
signode += addnodes.desc_sig_punctuation('.', '.')
|
|
251
|
-
else:
|
|
252
|
-
dest += addnodes.desc_sig_punctuation('.', '.')
|
|
253
|
-
for i in range(len(names)):
|
|
254
|
-
ident = names[i]
|
|
255
|
-
if not first:
|
|
256
|
-
dest += addnodes.desc_sig_punctuation('.', '.')
|
|
257
|
-
prefix += '.'
|
|
258
|
-
first = False
|
|
259
|
-
txt_ident = str(ident)
|
|
260
|
-
if txt_ident != '':
|
|
261
|
-
ident.describe_signature(dest, 'markType', env, prefix, symbol)
|
|
262
|
-
prefix += txt_ident
|
|
263
|
-
if mode == 'lastIsName':
|
|
264
|
-
if len(self.names) > 1:
|
|
265
|
-
dest += addnodes.desc_sig_punctuation('.', '.')
|
|
266
|
-
signode += dest
|
|
267
|
-
self.names[-1].describe_signature(signode, mode, env, '', symbol)
|
|
268
|
-
else:
|
|
269
|
-
raise Exception('Unknown description mode: %s' % mode)
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
################################################################################
|
|
273
|
-
# Expressions
|
|
274
|
-
################################################################################
|
|
275
|
-
|
|
276
|
-
class ASTExpression(ASTBase):
|
|
277
|
-
pass
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
# Primary expressions
|
|
281
|
-
################################################################################
|
|
282
|
-
|
|
283
|
-
class ASTLiteral(ASTExpression):
|
|
284
|
-
pass
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
class ASTBooleanLiteral(ASTLiteral):
|
|
288
|
-
def __init__(self, value: bool) -> None:
|
|
289
|
-
self.value = value
|
|
290
|
-
|
|
291
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
292
|
-
if self.value:
|
|
293
|
-
return 'true'
|
|
294
|
-
else:
|
|
295
|
-
return 'false'
|
|
296
|
-
|
|
297
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
298
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
299
|
-
txt = str(self)
|
|
300
|
-
signode += addnodes.desc_sig_keyword(txt, txt)
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
class ASTNumberLiteral(ASTLiteral):
|
|
304
|
-
def __init__(self, data: str) -> None:
|
|
305
|
-
self.data = data
|
|
306
|
-
|
|
307
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
308
|
-
return self.data
|
|
309
|
-
|
|
310
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
311
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
312
|
-
txt = str(self)
|
|
313
|
-
signode += addnodes.desc_sig_literal_number(txt, txt)
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
class ASTCharLiteral(ASTLiteral):
|
|
317
|
-
def __init__(self, prefix: str, data: str) -> None:
|
|
318
|
-
self.prefix = prefix # may be None when no prefix
|
|
319
|
-
self.data = data
|
|
320
|
-
decoded = data.encode().decode('unicode-escape')
|
|
321
|
-
if len(decoded) == 1:
|
|
322
|
-
self.value = ord(decoded)
|
|
323
|
-
else:
|
|
324
|
-
raise UnsupportedMultiCharacterCharLiteral(decoded)
|
|
325
|
-
|
|
326
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
327
|
-
if self.prefix is None:
|
|
328
|
-
return "'" + self.data + "'"
|
|
329
|
-
else:
|
|
330
|
-
return self.prefix + "'" + self.data + "'"
|
|
331
|
-
|
|
332
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
333
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
334
|
-
txt = str(self)
|
|
335
|
-
signode += addnodes.desc_sig_literal_char(txt, txt)
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
class ASTStringLiteral(ASTLiteral):
|
|
339
|
-
def __init__(self, data: str) -> None:
|
|
340
|
-
self.data = data
|
|
341
|
-
|
|
342
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
343
|
-
return self.data
|
|
344
|
-
|
|
345
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
346
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
347
|
-
txt = str(self)
|
|
348
|
-
signode += addnodes.desc_sig_literal_string(txt, txt)
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
class ASTIdExpression(ASTExpression):
|
|
352
|
-
def __init__(self, name: ASTNestedName):
|
|
353
|
-
# note: this class is basically to cast a nested name as an expression
|
|
354
|
-
self.name = name
|
|
355
|
-
|
|
356
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
357
|
-
return transform(self.name)
|
|
358
|
-
|
|
359
|
-
def get_id(self, version: int) -> str:
|
|
360
|
-
return self.name.get_id(version)
|
|
361
|
-
|
|
362
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
363
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
364
|
-
self.name.describe_signature(signode, mode, env, symbol)
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
class ASTParenExpr(ASTExpression):
|
|
368
|
-
def __init__(self, expr):
|
|
369
|
-
self.expr = expr
|
|
370
|
-
|
|
371
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
372
|
-
return '(' + transform(self.expr) + ')'
|
|
373
|
-
|
|
374
|
-
def get_id(self, version: int) -> str:
|
|
375
|
-
return self.expr.get_id(version)
|
|
376
|
-
|
|
377
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
378
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
379
|
-
signode += addnodes.desc_sig_punctuation('(', '(')
|
|
380
|
-
self.expr.describe_signature(signode, mode, env, symbol)
|
|
381
|
-
signode += addnodes.desc_sig_punctuation(')', ')')
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
# Postfix expressions
|
|
385
|
-
################################################################################
|
|
386
|
-
|
|
387
|
-
class ASTPostfixOp(ASTBase):
|
|
388
|
-
pass
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
class ASTPostfixCallExpr(ASTPostfixOp):
|
|
392
|
-
def __init__(self, lst: ASTParenExprList | ASTBracedInitList) -> None:
|
|
393
|
-
self.lst = lst
|
|
394
|
-
|
|
395
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
396
|
-
return transform(self.lst)
|
|
397
|
-
|
|
398
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
399
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
400
|
-
self.lst.describe_signature(signode, mode, env, symbol)
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
class ASTPostfixArray(ASTPostfixOp):
|
|
404
|
-
def __init__(self, expr: ASTExpression) -> None:
|
|
405
|
-
self.expr = expr
|
|
406
|
-
|
|
407
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
408
|
-
return '[' + transform(self.expr) + ']'
|
|
409
|
-
|
|
410
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
411
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
412
|
-
signode += addnodes.desc_sig_punctuation('[', '[')
|
|
413
|
-
self.expr.describe_signature(signode, mode, env, symbol)
|
|
414
|
-
signode += addnodes.desc_sig_punctuation(']', ']')
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
class ASTPostfixInc(ASTPostfixOp):
|
|
418
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
419
|
-
return '++'
|
|
420
|
-
|
|
421
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
422
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
423
|
-
signode += addnodes.desc_sig_operator('++', '++')
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
class ASTPostfixDec(ASTPostfixOp):
|
|
427
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
428
|
-
return '--'
|
|
429
|
-
|
|
430
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
431
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
432
|
-
signode += addnodes.desc_sig_operator('--', '--')
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
class ASTPostfixMemberOfPointer(ASTPostfixOp):
|
|
436
|
-
def __init__(self, name):
|
|
437
|
-
self.name = name
|
|
438
|
-
|
|
439
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
440
|
-
return '->' + transform(self.name)
|
|
441
|
-
|
|
442
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
443
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
444
|
-
signode += addnodes.desc_sig_operator('->', '->')
|
|
445
|
-
self.name.describe_signature(signode, 'noneIsName', env, symbol)
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
class ASTPostfixExpr(ASTExpression):
|
|
449
|
-
def __init__(self, prefix: ASTExpression, postFixes: list[ASTPostfixOp]):
|
|
450
|
-
self.prefix = prefix
|
|
451
|
-
self.postFixes = postFixes
|
|
452
|
-
|
|
453
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
454
|
-
res = [transform(self.prefix)]
|
|
455
|
-
for p in self.postFixes:
|
|
456
|
-
res.append(transform(p))
|
|
457
|
-
return ''.join(res)
|
|
458
|
-
|
|
459
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
460
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
461
|
-
self.prefix.describe_signature(signode, mode, env, symbol)
|
|
462
|
-
for p in self.postFixes:
|
|
463
|
-
p.describe_signature(signode, mode, env, symbol)
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
# Unary expressions
|
|
467
|
-
################################################################################
|
|
468
|
-
|
|
469
|
-
class ASTUnaryOpExpr(ASTExpression):
|
|
470
|
-
def __init__(self, op: str, expr: ASTExpression):
|
|
471
|
-
self.op = op
|
|
472
|
-
self.expr = expr
|
|
473
|
-
|
|
474
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
475
|
-
if self.op[0] in 'cn':
|
|
476
|
-
return self.op + " " + transform(self.expr)
|
|
477
|
-
else:
|
|
478
|
-
return self.op + transform(self.expr)
|
|
479
|
-
|
|
480
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
481
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
482
|
-
if self.op[0] in 'cn':
|
|
483
|
-
signode += addnodes.desc_sig_keyword(self.op, self.op)
|
|
484
|
-
signode += addnodes.desc_sig_space()
|
|
485
|
-
else:
|
|
486
|
-
signode += addnodes.desc_sig_operator(self.op, self.op)
|
|
487
|
-
self.expr.describe_signature(signode, mode, env, symbol)
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
class ASTSizeofType(ASTExpression):
|
|
491
|
-
def __init__(self, typ):
|
|
492
|
-
self.typ = typ
|
|
493
|
-
|
|
494
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
495
|
-
return "sizeof(" + transform(self.typ) + ")"
|
|
496
|
-
|
|
497
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
498
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
499
|
-
signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
|
|
500
|
-
signode += addnodes.desc_sig_punctuation('(', '(')
|
|
501
|
-
self.typ.describe_signature(signode, mode, env, symbol)
|
|
502
|
-
signode += addnodes.desc_sig_punctuation(')', ')')
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
class ASTSizeofExpr(ASTExpression):
|
|
506
|
-
def __init__(self, expr: ASTExpression):
|
|
507
|
-
self.expr = expr
|
|
508
|
-
|
|
509
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
510
|
-
return "sizeof " + transform(self.expr)
|
|
511
|
-
|
|
512
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
513
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
514
|
-
signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
|
|
515
|
-
signode += addnodes.desc_sig_space()
|
|
516
|
-
self.expr.describe_signature(signode, mode, env, symbol)
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
class ASTAlignofExpr(ASTExpression):
|
|
520
|
-
def __init__(self, typ: ASTType):
|
|
521
|
-
self.typ = typ
|
|
522
|
-
|
|
523
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
524
|
-
return "alignof(" + transform(self.typ) + ")"
|
|
525
|
-
|
|
526
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
527
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
528
|
-
signode += addnodes.desc_sig_keyword('alignof', 'alignof')
|
|
529
|
-
signode += addnodes.desc_sig_punctuation('(', '(')
|
|
530
|
-
self.typ.describe_signature(signode, mode, env, symbol)
|
|
531
|
-
signode += addnodes.desc_sig_punctuation(')', ')')
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
# Other expressions
|
|
535
|
-
################################################################################
|
|
536
|
-
|
|
537
|
-
class ASTCastExpr(ASTExpression):
|
|
538
|
-
def __init__(self, typ: ASTType, expr: ASTExpression):
|
|
539
|
-
self.typ = typ
|
|
540
|
-
self.expr = expr
|
|
541
|
-
|
|
542
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
543
|
-
res = ['(']
|
|
544
|
-
res.append(transform(self.typ))
|
|
545
|
-
res.append(')')
|
|
546
|
-
res.append(transform(self.expr))
|
|
547
|
-
return ''.join(res)
|
|
548
|
-
|
|
549
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
550
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
551
|
-
signode += addnodes.desc_sig_punctuation('(', '(')
|
|
552
|
-
self.typ.describe_signature(signode, mode, env, symbol)
|
|
553
|
-
signode += addnodes.desc_sig_punctuation(')', ')')
|
|
554
|
-
self.expr.describe_signature(signode, mode, env, symbol)
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
class ASTBinOpExpr(ASTBase):
|
|
558
|
-
def __init__(self, exprs: list[ASTExpression], ops: list[str]):
|
|
559
|
-
assert len(exprs) > 0
|
|
560
|
-
assert len(exprs) == len(ops) + 1
|
|
561
|
-
self.exprs = exprs
|
|
562
|
-
self.ops = ops
|
|
563
|
-
|
|
564
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
565
|
-
res = []
|
|
566
|
-
res.append(transform(self.exprs[0]))
|
|
567
|
-
for i in range(1, len(self.exprs)):
|
|
568
|
-
res.append(' ')
|
|
569
|
-
res.append(self.ops[i - 1])
|
|
570
|
-
res.append(' ')
|
|
571
|
-
res.append(transform(self.exprs[i]))
|
|
572
|
-
return ''.join(res)
|
|
573
|
-
|
|
574
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
575
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
576
|
-
self.exprs[0].describe_signature(signode, mode, env, symbol)
|
|
577
|
-
for i in range(1, len(self.exprs)):
|
|
578
|
-
signode += addnodes.desc_sig_space()
|
|
579
|
-
op = self.ops[i - 1]
|
|
580
|
-
if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'):
|
|
581
|
-
signode += addnodes.desc_sig_keyword(op, op)
|
|
582
|
-
else:
|
|
583
|
-
signode += addnodes.desc_sig_operator(op, op)
|
|
584
|
-
signode += addnodes.desc_sig_space()
|
|
585
|
-
self.exprs[i].describe_signature(signode, mode, env, symbol)
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
class ASTAssignmentExpr(ASTExpression):
|
|
589
|
-
def __init__(self, exprs: list[ASTExpression], ops: list[str]):
|
|
590
|
-
assert len(exprs) > 0
|
|
591
|
-
assert len(exprs) == len(ops) + 1
|
|
592
|
-
self.exprs = exprs
|
|
593
|
-
self.ops = ops
|
|
594
|
-
|
|
595
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
596
|
-
res = []
|
|
597
|
-
res.append(transform(self.exprs[0]))
|
|
598
|
-
for i in range(1, len(self.exprs)):
|
|
599
|
-
res.append(' ')
|
|
600
|
-
res.append(self.ops[i - 1])
|
|
601
|
-
res.append(' ')
|
|
602
|
-
res.append(transform(self.exprs[i]))
|
|
603
|
-
return ''.join(res)
|
|
604
|
-
|
|
605
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
606
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
607
|
-
self.exprs[0].describe_signature(signode, mode, env, symbol)
|
|
608
|
-
for i in range(1, len(self.exprs)):
|
|
609
|
-
signode += addnodes.desc_sig_space()
|
|
610
|
-
op = self.ops[i - 1]
|
|
611
|
-
if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'):
|
|
612
|
-
signode += addnodes.desc_sig_keyword(op, op)
|
|
613
|
-
else:
|
|
614
|
-
signode += addnodes.desc_sig_operator(op, op)
|
|
615
|
-
signode += addnodes.desc_sig_space()
|
|
616
|
-
self.exprs[i].describe_signature(signode, mode, env, symbol)
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
class ASTFallbackExpr(ASTExpression):
|
|
620
|
-
def __init__(self, expr: str):
|
|
621
|
-
self.expr = expr
|
|
622
|
-
|
|
623
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
624
|
-
return self.expr
|
|
625
|
-
|
|
626
|
-
def get_id(self, version: int) -> str:
|
|
627
|
-
return str(self.expr)
|
|
628
|
-
|
|
629
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
630
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
631
|
-
signode += nodes.literal(self.expr, self.expr)
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
################################################################################
|
|
635
|
-
# Types
|
|
636
|
-
################################################################################
|
|
637
|
-
|
|
638
|
-
class ASTTrailingTypeSpec(ASTBase):
|
|
639
|
-
pass
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
class ASTTrailingTypeSpecFundamental(ASTTrailingTypeSpec):
|
|
643
|
-
def __init__(self, names: list[str]) -> None:
|
|
644
|
-
assert len(names) != 0
|
|
645
|
-
self.names = names
|
|
646
|
-
|
|
647
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
648
|
-
return ' '.join(self.names)
|
|
649
|
-
|
|
650
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
651
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
652
|
-
first = True
|
|
653
|
-
for n in self.names:
|
|
654
|
-
if not first:
|
|
655
|
-
signode += addnodes.desc_sig_space()
|
|
656
|
-
else:
|
|
657
|
-
first = False
|
|
658
|
-
signode += addnodes.desc_sig_keyword_type(n, n)
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
class ASTTrailingTypeSpecName(ASTTrailingTypeSpec):
|
|
662
|
-
def __init__(self, prefix: str, nestedName: ASTNestedName) -> None:
|
|
663
|
-
self.prefix = prefix
|
|
664
|
-
self.nestedName = nestedName
|
|
665
|
-
|
|
666
|
-
@property
|
|
667
|
-
def name(self) -> ASTNestedName:
|
|
668
|
-
return self.nestedName
|
|
669
|
-
|
|
670
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
671
|
-
res = []
|
|
672
|
-
if self.prefix:
|
|
673
|
-
res.append(self.prefix)
|
|
674
|
-
res.append(' ')
|
|
675
|
-
res.append(transform(self.nestedName))
|
|
676
|
-
return ''.join(res)
|
|
677
|
-
|
|
678
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
679
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
680
|
-
if self.prefix:
|
|
681
|
-
signode += addnodes.desc_sig_keyword(self.prefix, self.prefix)
|
|
682
|
-
signode += addnodes.desc_sig_space()
|
|
683
|
-
self.nestedName.describe_signature(signode, mode, env, symbol=symbol)
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
class ASTFunctionParameter(ASTBase):
|
|
687
|
-
def __init__(self, arg: ASTTypeWithInit | None, ellipsis: bool = False) -> None:
|
|
688
|
-
self.arg = arg
|
|
689
|
-
self.ellipsis = ellipsis
|
|
690
|
-
|
|
691
|
-
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
|
|
692
|
-
# the anchor will be our parent
|
|
693
|
-
return symbol.parent.declaration.get_id(version, prefixed=False)
|
|
694
|
-
|
|
695
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
696
|
-
if self.ellipsis:
|
|
697
|
-
return '...'
|
|
698
|
-
else:
|
|
699
|
-
return transform(self.arg)
|
|
700
|
-
|
|
701
|
-
def describe_signature(self, signode: Any, mode: str,
|
|
702
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
703
|
-
verify_description_mode(mode)
|
|
704
|
-
if self.ellipsis:
|
|
705
|
-
signode += addnodes.desc_sig_punctuation('...', '...')
|
|
706
|
-
else:
|
|
707
|
-
self.arg.describe_signature(signode, mode, env, symbol=symbol)
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
class ASTParameters(ASTBase):
|
|
711
|
-
def __init__(self, args: list[ASTFunctionParameter], attrs: ASTAttributeList) -> None:
|
|
712
|
-
self.args = args
|
|
713
|
-
self.attrs = attrs
|
|
714
|
-
|
|
715
|
-
@property
|
|
716
|
-
def function_params(self) -> list[ASTFunctionParameter]:
|
|
717
|
-
return self.args
|
|
718
|
-
|
|
719
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
720
|
-
res = []
|
|
721
|
-
res.append('(')
|
|
722
|
-
first = True
|
|
723
|
-
for a in self.args:
|
|
724
|
-
if not first:
|
|
725
|
-
res.append(', ')
|
|
726
|
-
first = False
|
|
727
|
-
res.append(str(a))
|
|
728
|
-
res.append(')')
|
|
729
|
-
if len(self.attrs) != 0:
|
|
730
|
-
res.append(' ')
|
|
731
|
-
res.append(transform(self.attrs))
|
|
732
|
-
return ''.join(res)
|
|
733
|
-
|
|
734
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
735
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
736
|
-
verify_description_mode(mode)
|
|
737
|
-
multi_line_parameter_list = False
|
|
738
|
-
test_node: Element = signode
|
|
739
|
-
while test_node.parent:
|
|
740
|
-
if not isinstance(test_node, addnodes.desc_signature):
|
|
741
|
-
test_node = test_node.parent
|
|
742
|
-
continue
|
|
743
|
-
multi_line_parameter_list = test_node.get('multi_line_parameter_list', False)
|
|
744
|
-
break
|
|
745
|
-
|
|
746
|
-
# only use the desc_parameterlist for the outer list, not for inner lists
|
|
747
|
-
if mode == 'lastIsName':
|
|
748
|
-
paramlist = addnodes.desc_parameterlist()
|
|
749
|
-
paramlist['multi_line_parameter_list'] = multi_line_parameter_list
|
|
750
|
-
for arg in self.args:
|
|
751
|
-
param = addnodes.desc_parameter('', '', noemph=True)
|
|
752
|
-
arg.describe_signature(param, 'param', env, symbol=symbol)
|
|
753
|
-
paramlist += param
|
|
754
|
-
signode += paramlist
|
|
755
|
-
else:
|
|
756
|
-
signode += addnodes.desc_sig_punctuation('(', '(')
|
|
757
|
-
first = True
|
|
758
|
-
for arg in self.args:
|
|
759
|
-
if not first:
|
|
760
|
-
signode += addnodes.desc_sig_punctuation(',', ',')
|
|
761
|
-
signode += addnodes.desc_sig_space()
|
|
762
|
-
first = False
|
|
763
|
-
arg.describe_signature(signode, 'markType', env, symbol=symbol)
|
|
764
|
-
signode += addnodes.desc_sig_punctuation(')', ')')
|
|
765
|
-
|
|
766
|
-
if len(self.attrs) != 0:
|
|
767
|
-
signode += addnodes.desc_sig_space()
|
|
768
|
-
self.attrs.describe_signature(signode)
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
class ASTDeclSpecsSimple(ASTBaseBase):
|
|
772
|
-
def __init__(self, storage: str, threadLocal: str, inline: bool,
|
|
773
|
-
restrict: bool, volatile: bool, const: bool, attrs: ASTAttributeList) -> None:
|
|
774
|
-
self.storage = storage
|
|
775
|
-
self.threadLocal = threadLocal
|
|
776
|
-
self.inline = inline
|
|
777
|
-
self.restrict = restrict
|
|
778
|
-
self.volatile = volatile
|
|
779
|
-
self.const = const
|
|
780
|
-
self.attrs = attrs
|
|
781
|
-
|
|
782
|
-
def mergeWith(self, other: ASTDeclSpecsSimple) -> ASTDeclSpecsSimple:
|
|
783
|
-
if not other:
|
|
784
|
-
return self
|
|
785
|
-
return ASTDeclSpecsSimple(self.storage or other.storage,
|
|
786
|
-
self.threadLocal or other.threadLocal,
|
|
787
|
-
self.inline or other.inline,
|
|
788
|
-
self.volatile or other.volatile,
|
|
789
|
-
self.const or other.const,
|
|
790
|
-
self.restrict or other.restrict,
|
|
791
|
-
self.attrs + other.attrs)
|
|
792
|
-
|
|
793
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
794
|
-
res: list[str] = []
|
|
795
|
-
if len(self.attrs) != 0:
|
|
796
|
-
res.append(transform(self.attrs))
|
|
797
|
-
if self.storage:
|
|
798
|
-
res.append(self.storage)
|
|
799
|
-
if self.threadLocal:
|
|
800
|
-
res.append(self.threadLocal)
|
|
801
|
-
if self.inline:
|
|
802
|
-
res.append('inline')
|
|
803
|
-
if self.restrict:
|
|
804
|
-
res.append('restrict')
|
|
805
|
-
if self.volatile:
|
|
806
|
-
res.append('volatile')
|
|
807
|
-
if self.const:
|
|
808
|
-
res.append('const')
|
|
809
|
-
return ' '.join(res)
|
|
810
|
-
|
|
811
|
-
def describe_signature(self, modifiers: list[Node]) -> None:
|
|
812
|
-
def _add(modifiers: list[Node], text: str) -> None:
|
|
813
|
-
if len(modifiers) != 0:
|
|
814
|
-
modifiers.append(addnodes.desc_sig_space())
|
|
815
|
-
modifiers.append(addnodes.desc_sig_keyword(text, text))
|
|
816
|
-
|
|
817
|
-
if len(modifiers) != 0 and len(self.attrs) != 0:
|
|
818
|
-
modifiers.append(addnodes.desc_sig_space())
|
|
819
|
-
tempNode = nodes.TextElement()
|
|
820
|
-
self.attrs.describe_signature(tempNode)
|
|
821
|
-
modifiers.extend(tempNode.children)
|
|
822
|
-
if self.storage:
|
|
823
|
-
_add(modifiers, self.storage)
|
|
824
|
-
if self.threadLocal:
|
|
825
|
-
_add(modifiers, self.threadLocal)
|
|
826
|
-
if self.inline:
|
|
827
|
-
_add(modifiers, 'inline')
|
|
828
|
-
if self.restrict:
|
|
829
|
-
_add(modifiers, 'restrict')
|
|
830
|
-
if self.volatile:
|
|
831
|
-
_add(modifiers, 'volatile')
|
|
832
|
-
if self.const:
|
|
833
|
-
_add(modifiers, 'const')
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
class ASTDeclSpecs(ASTBase):
|
|
837
|
-
def __init__(self, outer: str,
|
|
838
|
-
leftSpecs: ASTDeclSpecsSimple,
|
|
839
|
-
rightSpecs: ASTDeclSpecsSimple,
|
|
840
|
-
trailing: ASTTrailingTypeSpec) -> None:
|
|
841
|
-
# leftSpecs and rightSpecs are used for output
|
|
842
|
-
# allSpecs are used for id generation TODO: remove?
|
|
843
|
-
self.outer = outer
|
|
844
|
-
self.leftSpecs = leftSpecs
|
|
845
|
-
self.rightSpecs = rightSpecs
|
|
846
|
-
self.allSpecs = self.leftSpecs.mergeWith(self.rightSpecs)
|
|
847
|
-
self.trailingTypeSpec = trailing
|
|
848
|
-
|
|
849
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
850
|
-
res: list[str] = []
|
|
851
|
-
l = transform(self.leftSpecs)
|
|
852
|
-
if len(l) > 0:
|
|
853
|
-
res.append(l)
|
|
854
|
-
if self.trailingTypeSpec:
|
|
855
|
-
if len(res) > 0:
|
|
856
|
-
res.append(" ")
|
|
857
|
-
res.append(transform(self.trailingTypeSpec))
|
|
858
|
-
r = str(self.rightSpecs)
|
|
859
|
-
if len(r) > 0:
|
|
860
|
-
if len(res) > 0:
|
|
861
|
-
res.append(" ")
|
|
862
|
-
res.append(r)
|
|
863
|
-
return "".join(res)
|
|
864
|
-
|
|
865
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
866
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
867
|
-
verify_description_mode(mode)
|
|
868
|
-
modifiers: list[Node] = []
|
|
869
|
-
|
|
870
|
-
self.leftSpecs.describe_signature(modifiers)
|
|
871
|
-
|
|
872
|
-
for m in modifiers:
|
|
873
|
-
signode += m
|
|
874
|
-
if self.trailingTypeSpec:
|
|
875
|
-
if len(modifiers) > 0:
|
|
876
|
-
signode += addnodes.desc_sig_space()
|
|
877
|
-
self.trailingTypeSpec.describe_signature(signode, mode, env,
|
|
878
|
-
symbol=symbol)
|
|
879
|
-
modifiers = []
|
|
880
|
-
self.rightSpecs.describe_signature(modifiers)
|
|
881
|
-
if len(modifiers) > 0:
|
|
882
|
-
signode += addnodes.desc_sig_space()
|
|
883
|
-
for m in modifiers:
|
|
884
|
-
signode += m
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
# Declarator
|
|
888
|
-
################################################################################
|
|
889
|
-
|
|
890
|
-
class ASTArray(ASTBase):
|
|
891
|
-
def __init__(self, static: bool, const: bool, volatile: bool, restrict: bool,
|
|
892
|
-
vla: bool, size: ASTExpression):
|
|
893
|
-
self.static = static
|
|
894
|
-
self.const = const
|
|
895
|
-
self.volatile = volatile
|
|
896
|
-
self.restrict = restrict
|
|
897
|
-
self.vla = vla
|
|
898
|
-
self.size = size
|
|
899
|
-
if vla:
|
|
900
|
-
assert size is None
|
|
901
|
-
if size is not None:
|
|
902
|
-
assert not vla
|
|
903
|
-
|
|
904
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
905
|
-
el = []
|
|
906
|
-
if self.static:
|
|
907
|
-
el.append('static')
|
|
908
|
-
if self.restrict:
|
|
909
|
-
el.append('restrict')
|
|
910
|
-
if self.volatile:
|
|
911
|
-
el.append('volatile')
|
|
912
|
-
if self.const:
|
|
913
|
-
el.append('const')
|
|
914
|
-
if self.vla:
|
|
915
|
-
return '[' + ' '.join(el) + '*]'
|
|
916
|
-
elif self.size:
|
|
917
|
-
el.append(transform(self.size))
|
|
918
|
-
return '[' + ' '.join(el) + ']'
|
|
919
|
-
|
|
920
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
921
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
922
|
-
verify_description_mode(mode)
|
|
923
|
-
signode += addnodes.desc_sig_punctuation('[', '[')
|
|
924
|
-
addSpace = False
|
|
925
|
-
|
|
926
|
-
def _add(signode: TextElement, text: str) -> bool:
|
|
927
|
-
if addSpace:
|
|
928
|
-
signode += addnodes.desc_sig_space()
|
|
929
|
-
signode += addnodes.desc_sig_keyword(text, text)
|
|
930
|
-
return True
|
|
931
|
-
|
|
932
|
-
if self.static:
|
|
933
|
-
addSpace = _add(signode, 'static')
|
|
934
|
-
if self.restrict:
|
|
935
|
-
addSpace = _add(signode, 'restrict')
|
|
936
|
-
if self.volatile:
|
|
937
|
-
addSpace = _add(signode, 'volatile')
|
|
938
|
-
if self.const:
|
|
939
|
-
addSpace = _add(signode, 'const')
|
|
940
|
-
if self.vla:
|
|
941
|
-
signode += addnodes.desc_sig_punctuation('*', '*')
|
|
942
|
-
elif self.size:
|
|
943
|
-
if addSpace:
|
|
944
|
-
signode += addnodes.desc_sig_space()
|
|
945
|
-
self.size.describe_signature(signode, 'markType', env, symbol)
|
|
946
|
-
signode += addnodes.desc_sig_punctuation(']', ']')
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
class ASTDeclarator(ASTBase):
|
|
950
|
-
@property
|
|
951
|
-
def name(self) -> ASTNestedName:
|
|
952
|
-
raise NotImplementedError(repr(self))
|
|
953
|
-
|
|
954
|
-
@property
|
|
955
|
-
def function_params(self) -> list[ASTFunctionParameter]:
|
|
956
|
-
raise NotImplementedError(repr(self))
|
|
957
|
-
|
|
958
|
-
def require_space_after_declSpecs(self) -> bool:
|
|
959
|
-
raise NotImplementedError(repr(self))
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
class ASTDeclaratorNameParam(ASTDeclarator):
|
|
963
|
-
def __init__(self, declId: ASTNestedName,
|
|
964
|
-
arrayOps: list[ASTArray], param: ASTParameters) -> None:
|
|
965
|
-
self.declId = declId
|
|
966
|
-
self.arrayOps = arrayOps
|
|
967
|
-
self.param = param
|
|
968
|
-
|
|
969
|
-
@property
|
|
970
|
-
def name(self) -> ASTNestedName:
|
|
971
|
-
return self.declId
|
|
972
|
-
|
|
973
|
-
@property
|
|
974
|
-
def function_params(self) -> list[ASTFunctionParameter]:
|
|
975
|
-
return self.param.function_params
|
|
976
|
-
|
|
977
|
-
# ------------------------------------------------------------------------
|
|
978
|
-
|
|
979
|
-
def require_space_after_declSpecs(self) -> bool:
|
|
980
|
-
return self.declId is not None
|
|
981
|
-
|
|
982
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
983
|
-
res = []
|
|
984
|
-
if self.declId:
|
|
985
|
-
res.append(transform(self.declId))
|
|
986
|
-
for op in self.arrayOps:
|
|
987
|
-
res.append(transform(op))
|
|
988
|
-
if self.param:
|
|
989
|
-
res.append(transform(self.param))
|
|
990
|
-
return ''.join(res)
|
|
991
|
-
|
|
992
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
993
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
994
|
-
verify_description_mode(mode)
|
|
995
|
-
if self.declId:
|
|
996
|
-
self.declId.describe_signature(signode, mode, env, symbol)
|
|
997
|
-
for op in self.arrayOps:
|
|
998
|
-
op.describe_signature(signode, mode, env, symbol)
|
|
999
|
-
if self.param:
|
|
1000
|
-
self.param.describe_signature(signode, mode, env, symbol)
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
class ASTDeclaratorNameBitField(ASTDeclarator):
|
|
1004
|
-
def __init__(self, declId: ASTNestedName, size: ASTExpression):
|
|
1005
|
-
self.declId = declId
|
|
1006
|
-
self.size = size
|
|
1007
|
-
|
|
1008
|
-
@property
|
|
1009
|
-
def name(self) -> ASTNestedName:
|
|
1010
|
-
return self.declId
|
|
1011
|
-
|
|
1012
|
-
# ------------------------------------------------------------------------
|
|
1013
|
-
|
|
1014
|
-
def require_space_after_declSpecs(self) -> bool:
|
|
1015
|
-
return self.declId is not None
|
|
1016
|
-
|
|
1017
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1018
|
-
res = []
|
|
1019
|
-
if self.declId:
|
|
1020
|
-
res.append(transform(self.declId))
|
|
1021
|
-
res.append(" : ")
|
|
1022
|
-
res.append(transform(self.size))
|
|
1023
|
-
return ''.join(res)
|
|
1024
|
-
|
|
1025
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1026
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1027
|
-
verify_description_mode(mode)
|
|
1028
|
-
if self.declId:
|
|
1029
|
-
self.declId.describe_signature(signode, mode, env, symbol)
|
|
1030
|
-
signode += addnodes.desc_sig_space()
|
|
1031
|
-
signode += addnodes.desc_sig_punctuation(':', ':')
|
|
1032
|
-
signode += addnodes.desc_sig_space()
|
|
1033
|
-
self.size.describe_signature(signode, mode, env, symbol)
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
class ASTDeclaratorPtr(ASTDeclarator):
|
|
1037
|
-
def __init__(self, next: ASTDeclarator, restrict: bool, volatile: bool, const: bool,
|
|
1038
|
-
attrs: ASTAttributeList) -> None:
|
|
1039
|
-
assert next
|
|
1040
|
-
self.next = next
|
|
1041
|
-
self.restrict = restrict
|
|
1042
|
-
self.volatile = volatile
|
|
1043
|
-
self.const = const
|
|
1044
|
-
self.attrs = attrs
|
|
1045
|
-
|
|
1046
|
-
@property
|
|
1047
|
-
def name(self) -> ASTNestedName:
|
|
1048
|
-
return self.next.name
|
|
1049
|
-
|
|
1050
|
-
@property
|
|
1051
|
-
def function_params(self) -> list[ASTFunctionParameter]:
|
|
1052
|
-
return self.next.function_params
|
|
1053
|
-
|
|
1054
|
-
def require_space_after_declSpecs(self) -> bool:
|
|
1055
|
-
return self.const or self.volatile or self.restrict or \
|
|
1056
|
-
len(self.attrs) > 0 or \
|
|
1057
|
-
self.next.require_space_after_declSpecs()
|
|
1058
|
-
|
|
1059
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1060
|
-
res = ['*']
|
|
1061
|
-
res.append(transform(self.attrs))
|
|
1062
|
-
if len(self.attrs) != 0 and (self.restrict or self.volatile or self.const):
|
|
1063
|
-
res.append(' ')
|
|
1064
|
-
if self.restrict:
|
|
1065
|
-
res.append('restrict')
|
|
1066
|
-
if self.volatile:
|
|
1067
|
-
if self.restrict:
|
|
1068
|
-
res.append(' ')
|
|
1069
|
-
res.append('volatile')
|
|
1070
|
-
if self.const:
|
|
1071
|
-
if self.restrict or self.volatile:
|
|
1072
|
-
res.append(' ')
|
|
1073
|
-
res.append('const')
|
|
1074
|
-
if self.const or self.volatile or self.restrict or len(self.attrs) > 0:
|
|
1075
|
-
if self.next.require_space_after_declSpecs():
|
|
1076
|
-
res.append(' ')
|
|
1077
|
-
res.append(transform(self.next))
|
|
1078
|
-
return ''.join(res)
|
|
1079
|
-
|
|
1080
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1081
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1082
|
-
verify_description_mode(mode)
|
|
1083
|
-
signode += addnodes.desc_sig_punctuation('*', '*')
|
|
1084
|
-
self.attrs.describe_signature(signode)
|
|
1085
|
-
if len(self.attrs) != 0 and (self.restrict or self.volatile or self.const):
|
|
1086
|
-
signode += addnodes.desc_sig_space()
|
|
1087
|
-
|
|
1088
|
-
def _add_anno(signode: TextElement, text: str) -> None:
|
|
1089
|
-
signode += addnodes.desc_sig_keyword(text, text)
|
|
1090
|
-
|
|
1091
|
-
if self.restrict:
|
|
1092
|
-
_add_anno(signode, 'restrict')
|
|
1093
|
-
if self.volatile:
|
|
1094
|
-
if self.restrict:
|
|
1095
|
-
signode += addnodes.desc_sig_space()
|
|
1096
|
-
_add_anno(signode, 'volatile')
|
|
1097
|
-
if self.const:
|
|
1098
|
-
if self.restrict or self.volatile:
|
|
1099
|
-
signode += addnodes.desc_sig_space()
|
|
1100
|
-
_add_anno(signode, 'const')
|
|
1101
|
-
if self.const or self.volatile or self.restrict or len(self.attrs) > 0:
|
|
1102
|
-
if self.next.require_space_after_declSpecs():
|
|
1103
|
-
signode += addnodes.desc_sig_space()
|
|
1104
|
-
self.next.describe_signature(signode, mode, env, symbol)
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
class ASTDeclaratorParen(ASTDeclarator):
|
|
1108
|
-
def __init__(self, inner: ASTDeclarator, next: ASTDeclarator) -> None:
|
|
1109
|
-
assert inner
|
|
1110
|
-
assert next
|
|
1111
|
-
self.inner = inner
|
|
1112
|
-
self.next = next
|
|
1113
|
-
# TODO: we assume the name and params are in inner
|
|
1114
|
-
|
|
1115
|
-
@property
|
|
1116
|
-
def name(self) -> ASTNestedName:
|
|
1117
|
-
return self.inner.name
|
|
1118
|
-
|
|
1119
|
-
@property
|
|
1120
|
-
def function_params(self) -> list[ASTFunctionParameter]:
|
|
1121
|
-
return self.inner.function_params
|
|
1122
|
-
|
|
1123
|
-
def require_space_after_declSpecs(self) -> bool:
|
|
1124
|
-
return True
|
|
1125
|
-
|
|
1126
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1127
|
-
res = ['(']
|
|
1128
|
-
res.append(transform(self.inner))
|
|
1129
|
-
res.append(')')
|
|
1130
|
-
res.append(transform(self.next))
|
|
1131
|
-
return ''.join(res)
|
|
1132
|
-
|
|
1133
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1134
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1135
|
-
verify_description_mode(mode)
|
|
1136
|
-
signode += addnodes.desc_sig_punctuation('(', '(')
|
|
1137
|
-
self.inner.describe_signature(signode, mode, env, symbol)
|
|
1138
|
-
signode += addnodes.desc_sig_punctuation(')', ')')
|
|
1139
|
-
self.next.describe_signature(signode, "noneIsName", env, symbol)
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
# Initializer
|
|
1143
|
-
################################################################################
|
|
1144
|
-
|
|
1145
|
-
class ASTParenExprList(ASTBaseParenExprList):
|
|
1146
|
-
def __init__(self, exprs: list[ASTExpression]) -> None:
|
|
1147
|
-
self.exprs = exprs
|
|
1148
|
-
|
|
1149
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1150
|
-
exprs = [transform(e) for e in self.exprs]
|
|
1151
|
-
return '(%s)' % ', '.join(exprs)
|
|
1152
|
-
|
|
1153
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1154
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1155
|
-
verify_description_mode(mode)
|
|
1156
|
-
signode += addnodes.desc_sig_punctuation('(', '(')
|
|
1157
|
-
first = True
|
|
1158
|
-
for e in self.exprs:
|
|
1159
|
-
if not first:
|
|
1160
|
-
signode += addnodes.desc_sig_punctuation(',', ',')
|
|
1161
|
-
signode += addnodes.desc_sig_space()
|
|
1162
|
-
else:
|
|
1163
|
-
first = False
|
|
1164
|
-
e.describe_signature(signode, mode, env, symbol)
|
|
1165
|
-
signode += addnodes.desc_sig_punctuation(')', ')')
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
class ASTBracedInitList(ASTBase):
|
|
1169
|
-
def __init__(self, exprs: list[ASTExpression], trailingComma: bool) -> None:
|
|
1170
|
-
self.exprs = exprs
|
|
1171
|
-
self.trailingComma = trailingComma
|
|
1172
|
-
|
|
1173
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1174
|
-
exprs = ', '.join(transform(e) for e in self.exprs)
|
|
1175
|
-
trailingComma = ',' if self.trailingComma else ''
|
|
1176
|
-
return f'{{{exprs}{trailingComma}}}'
|
|
1177
|
-
|
|
1178
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1179
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1180
|
-
verify_description_mode(mode)
|
|
1181
|
-
signode += addnodes.desc_sig_punctuation('{', '{')
|
|
1182
|
-
first = True
|
|
1183
|
-
for e in self.exprs:
|
|
1184
|
-
if not first:
|
|
1185
|
-
signode += addnodes.desc_sig_punctuation(',', ',')
|
|
1186
|
-
signode += addnodes.desc_sig_space()
|
|
1187
|
-
else:
|
|
1188
|
-
first = False
|
|
1189
|
-
e.describe_signature(signode, mode, env, symbol)
|
|
1190
|
-
if self.trailingComma:
|
|
1191
|
-
signode += addnodes.desc_sig_punctuation(',', ',')
|
|
1192
|
-
signode += addnodes.desc_sig_punctuation('}', '}')
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
class ASTInitializer(ASTBase):
|
|
1196
|
-
def __init__(self, value: ASTBracedInitList | ASTExpression,
|
|
1197
|
-
hasAssign: bool = True) -> None:
|
|
1198
|
-
self.value = value
|
|
1199
|
-
self.hasAssign = hasAssign
|
|
1200
|
-
|
|
1201
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1202
|
-
val = transform(self.value)
|
|
1203
|
-
if self.hasAssign:
|
|
1204
|
-
return ' = ' + val
|
|
1205
|
-
else:
|
|
1206
|
-
return val
|
|
1207
|
-
|
|
1208
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1209
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1210
|
-
verify_description_mode(mode)
|
|
1211
|
-
if self.hasAssign:
|
|
1212
|
-
signode += addnodes.desc_sig_space()
|
|
1213
|
-
signode += addnodes.desc_sig_punctuation('=', '=')
|
|
1214
|
-
signode += addnodes.desc_sig_space()
|
|
1215
|
-
self.value.describe_signature(signode, 'markType', env, symbol)
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
class ASTType(ASTBase):
|
|
1219
|
-
def __init__(self, declSpecs: ASTDeclSpecs, decl: ASTDeclarator) -> None:
|
|
1220
|
-
assert declSpecs
|
|
1221
|
-
assert decl
|
|
1222
|
-
self.declSpecs = declSpecs
|
|
1223
|
-
self.decl = decl
|
|
1224
|
-
|
|
1225
|
-
@property
|
|
1226
|
-
def name(self) -> ASTNestedName:
|
|
1227
|
-
return self.decl.name
|
|
1228
|
-
|
|
1229
|
-
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
|
|
1230
|
-
return symbol.get_full_nested_name().get_id(version)
|
|
1231
|
-
|
|
1232
|
-
@property
|
|
1233
|
-
def function_params(self) -> list[ASTFunctionParameter]:
|
|
1234
|
-
return self.decl.function_params
|
|
1235
|
-
|
|
1236
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1237
|
-
res = []
|
|
1238
|
-
declSpecs = transform(self.declSpecs)
|
|
1239
|
-
res.append(declSpecs)
|
|
1240
|
-
if self.decl.require_space_after_declSpecs() and len(declSpecs) > 0:
|
|
1241
|
-
res.append(' ')
|
|
1242
|
-
res.append(transform(self.decl))
|
|
1243
|
-
return ''.join(res)
|
|
1244
|
-
|
|
1245
|
-
def get_type_declaration_prefix(self) -> str:
|
|
1246
|
-
if self.declSpecs.trailingTypeSpec:
|
|
1247
|
-
return 'typedef'
|
|
1248
|
-
else:
|
|
1249
|
-
return 'type'
|
|
1250
|
-
|
|
1251
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1252
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1253
|
-
verify_description_mode(mode)
|
|
1254
|
-
self.declSpecs.describe_signature(signode, 'markType', env, symbol)
|
|
1255
|
-
if (self.decl.require_space_after_declSpecs() and
|
|
1256
|
-
len(str(self.declSpecs)) > 0):
|
|
1257
|
-
signode += addnodes.desc_sig_space()
|
|
1258
|
-
# for parameters that don't really declare new names we get 'markType',
|
|
1259
|
-
# this should not be propagated, but be 'noneIsName'.
|
|
1260
|
-
if mode == 'markType':
|
|
1261
|
-
mode = 'noneIsName'
|
|
1262
|
-
self.decl.describe_signature(signode, mode, env, symbol)
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
class ASTTypeWithInit(ASTBase):
|
|
1266
|
-
def __init__(self, type: ASTType, init: ASTInitializer) -> None:
|
|
1267
|
-
self.type = type
|
|
1268
|
-
self.init = init
|
|
1269
|
-
|
|
1270
|
-
@property
|
|
1271
|
-
def name(self) -> ASTNestedName:
|
|
1272
|
-
return self.type.name
|
|
1273
|
-
|
|
1274
|
-
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
|
|
1275
|
-
return self.type.get_id(version, objectType, symbol)
|
|
1276
|
-
|
|
1277
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1278
|
-
res = []
|
|
1279
|
-
res.append(transform(self.type))
|
|
1280
|
-
if self.init:
|
|
1281
|
-
res.append(transform(self.init))
|
|
1282
|
-
return ''.join(res)
|
|
1283
|
-
|
|
1284
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1285
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1286
|
-
verify_description_mode(mode)
|
|
1287
|
-
self.type.describe_signature(signode, mode, env, symbol)
|
|
1288
|
-
if self.init:
|
|
1289
|
-
self.init.describe_signature(signode, mode, env, symbol)
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
class ASTMacroParameter(ASTBase):
|
|
1293
|
-
def __init__(self, arg: ASTNestedName | None, ellipsis: bool = False,
|
|
1294
|
-
variadic: bool = False) -> None:
|
|
1295
|
-
self.arg = arg
|
|
1296
|
-
self.ellipsis = ellipsis
|
|
1297
|
-
self.variadic = variadic
|
|
1298
|
-
|
|
1299
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1300
|
-
if self.ellipsis:
|
|
1301
|
-
return '...'
|
|
1302
|
-
elif self.variadic:
|
|
1303
|
-
return transform(self.arg) + '...'
|
|
1304
|
-
else:
|
|
1305
|
-
return transform(self.arg)
|
|
1306
|
-
|
|
1307
|
-
def describe_signature(self, signode: Any, mode: str,
|
|
1308
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1309
|
-
verify_description_mode(mode)
|
|
1310
|
-
if self.ellipsis:
|
|
1311
|
-
signode += addnodes.desc_sig_punctuation('...', '...')
|
|
1312
|
-
elif self.variadic:
|
|
1313
|
-
name = str(self)
|
|
1314
|
-
signode += addnodes.desc_sig_name(name, name)
|
|
1315
|
-
else:
|
|
1316
|
-
self.arg.describe_signature(signode, mode, env, symbol=symbol)
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
class ASTMacro(ASTBase):
|
|
1320
|
-
def __init__(self, ident: ASTNestedName, args: list[ASTMacroParameter] | None) -> None:
|
|
1321
|
-
self.ident = ident
|
|
1322
|
-
self.args = args
|
|
1323
|
-
|
|
1324
|
-
@property
|
|
1325
|
-
def name(self) -> ASTNestedName:
|
|
1326
|
-
return self.ident
|
|
1327
|
-
|
|
1328
|
-
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
|
|
1329
|
-
return symbol.get_full_nested_name().get_id(version)
|
|
1330
|
-
|
|
1331
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1332
|
-
res = []
|
|
1333
|
-
res.append(transform(self.ident))
|
|
1334
|
-
if self.args is not None:
|
|
1335
|
-
res.append('(')
|
|
1336
|
-
first = True
|
|
1337
|
-
for arg in self.args:
|
|
1338
|
-
if not first:
|
|
1339
|
-
res.append(', ')
|
|
1340
|
-
first = False
|
|
1341
|
-
res.append(transform(arg))
|
|
1342
|
-
res.append(')')
|
|
1343
|
-
return ''.join(res)
|
|
1344
|
-
|
|
1345
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1346
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1347
|
-
verify_description_mode(mode)
|
|
1348
|
-
self.ident.describe_signature(signode, mode, env, symbol)
|
|
1349
|
-
if self.args is None:
|
|
1350
|
-
return
|
|
1351
|
-
paramlist = addnodes.desc_parameterlist()
|
|
1352
|
-
for arg in self.args:
|
|
1353
|
-
param = addnodes.desc_parameter('', '', noemph=True)
|
|
1354
|
-
arg.describe_signature(param, 'param', env, symbol=symbol)
|
|
1355
|
-
paramlist += param
|
|
1356
|
-
signode += paramlist
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
class ASTStruct(ASTBase):
|
|
1360
|
-
def __init__(self, name: ASTNestedName) -> None:
|
|
1361
|
-
self.name = name
|
|
1362
|
-
|
|
1363
|
-
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
|
|
1364
|
-
return symbol.get_full_nested_name().get_id(version)
|
|
1365
|
-
|
|
1366
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1367
|
-
return transform(self.name)
|
|
1368
|
-
|
|
1369
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1370
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1371
|
-
verify_description_mode(mode)
|
|
1372
|
-
self.name.describe_signature(signode, mode, env, symbol=symbol)
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
class ASTUnion(ASTBase):
|
|
1376
|
-
def __init__(self, name: ASTNestedName) -> None:
|
|
1377
|
-
self.name = name
|
|
1378
|
-
|
|
1379
|
-
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
|
|
1380
|
-
return symbol.get_full_nested_name().get_id(version)
|
|
1381
|
-
|
|
1382
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1383
|
-
return transform(self.name)
|
|
1384
|
-
|
|
1385
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1386
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1387
|
-
verify_description_mode(mode)
|
|
1388
|
-
self.name.describe_signature(signode, mode, env, symbol=symbol)
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
class ASTEnum(ASTBase):
|
|
1392
|
-
def __init__(self, name: ASTNestedName) -> None:
|
|
1393
|
-
self.name = name
|
|
1394
|
-
|
|
1395
|
-
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
|
|
1396
|
-
return symbol.get_full_nested_name().get_id(version)
|
|
1397
|
-
|
|
1398
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1399
|
-
return transform(self.name)
|
|
1400
|
-
|
|
1401
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1402
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1403
|
-
verify_description_mode(mode)
|
|
1404
|
-
self.name.describe_signature(signode, mode, env, symbol=symbol)
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
class ASTEnumerator(ASTBase):
|
|
1408
|
-
def __init__(self, name: ASTNestedName, init: ASTInitializer | None,
|
|
1409
|
-
attrs: ASTAttributeList) -> None:
|
|
1410
|
-
self.name = name
|
|
1411
|
-
self.init = init
|
|
1412
|
-
self.attrs = attrs
|
|
1413
|
-
|
|
1414
|
-
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
|
|
1415
|
-
return symbol.get_full_nested_name().get_id(version)
|
|
1416
|
-
|
|
1417
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1418
|
-
res = []
|
|
1419
|
-
res.append(transform(self.name))
|
|
1420
|
-
if len(self.attrs) != 0:
|
|
1421
|
-
res.append(' ')
|
|
1422
|
-
res.append(transform(self.attrs))
|
|
1423
|
-
if self.init:
|
|
1424
|
-
res.append(transform(self.init))
|
|
1425
|
-
return ''.join(res)
|
|
1426
|
-
|
|
1427
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1428
|
-
env: BuildEnvironment, symbol: Symbol) -> None:
|
|
1429
|
-
verify_description_mode(mode)
|
|
1430
|
-
self.name.describe_signature(signode, mode, env, symbol)
|
|
1431
|
-
if len(self.attrs) != 0:
|
|
1432
|
-
signode += addnodes.desc_sig_space()
|
|
1433
|
-
self.attrs.describe_signature(signode)
|
|
1434
|
-
if self.init:
|
|
1435
|
-
self.init.describe_signature(signode, 'markType', env, symbol)
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
class ASTDeclaration(ASTBaseBase):
|
|
1439
|
-
def __init__(self, objectType: str, directiveType: str | None,
|
|
1440
|
-
declaration: DeclarationType | ASTFunctionParameter,
|
|
1441
|
-
semicolon: bool = False) -> None:
|
|
1442
|
-
self.objectType = objectType
|
|
1443
|
-
self.directiveType = directiveType
|
|
1444
|
-
self.declaration = declaration
|
|
1445
|
-
self.semicolon = semicolon
|
|
1446
|
-
|
|
1447
|
-
self.symbol: Symbol = None
|
|
1448
|
-
# set by CObject._add_enumerator_to_parent
|
|
1449
|
-
self.enumeratorScopedSymbol: Symbol = None
|
|
1450
|
-
|
|
1451
|
-
def clone(self) -> ASTDeclaration:
|
|
1452
|
-
return ASTDeclaration(self.objectType, self.directiveType,
|
|
1453
|
-
self.declaration.clone(), self.semicolon)
|
|
1454
|
-
|
|
1455
|
-
@property
|
|
1456
|
-
def name(self) -> ASTNestedName:
|
|
1457
|
-
decl = cast(DeclarationType, self.declaration)
|
|
1458
|
-
return decl.name
|
|
1459
|
-
|
|
1460
|
-
@property
|
|
1461
|
-
def function_params(self) -> list[ASTFunctionParameter] | None:
|
|
1462
|
-
if self.objectType != 'function':
|
|
1463
|
-
return None
|
|
1464
|
-
decl = cast(ASTType, self.declaration)
|
|
1465
|
-
return decl.function_params
|
|
1466
|
-
|
|
1467
|
-
def get_id(self, version: int, prefixed: bool = True) -> str:
|
|
1468
|
-
if self.objectType == 'enumerator' and self.enumeratorScopedSymbol:
|
|
1469
|
-
return self.enumeratorScopedSymbol.declaration.get_id(version, prefixed)
|
|
1470
|
-
id_ = self.declaration.get_id(version, self.objectType, self.symbol)
|
|
1471
|
-
if prefixed:
|
|
1472
|
-
return _id_prefix[version] + id_
|
|
1473
|
-
else:
|
|
1474
|
-
return id_
|
|
1475
|
-
|
|
1476
|
-
def get_newest_id(self) -> str:
|
|
1477
|
-
return self.get_id(_max_id, True)
|
|
1478
|
-
|
|
1479
|
-
def _stringify(self, transform: StringifyTransform) -> str:
|
|
1480
|
-
res = transform(self.declaration)
|
|
1481
|
-
if self.semicolon:
|
|
1482
|
-
res += ';'
|
|
1483
|
-
return res
|
|
1484
|
-
|
|
1485
|
-
def describe_signature(self, signode: TextElement, mode: str,
|
|
1486
|
-
env: BuildEnvironment, options: dict) -> None:
|
|
1487
|
-
verify_description_mode(mode)
|
|
1488
|
-
assert self.symbol
|
|
1489
|
-
# The caller of the domain added a desc_signature node.
|
|
1490
|
-
# Always enable multiline:
|
|
1491
|
-
signode['is_multiline'] = True
|
|
1492
|
-
# Put each line in a desc_signature_line node.
|
|
1493
|
-
mainDeclNode = addnodes.desc_signature_line()
|
|
1494
|
-
mainDeclNode.sphinx_line_type = 'declarator'
|
|
1495
|
-
mainDeclNode['add_permalink'] = not self.symbol.isRedeclaration
|
|
1496
|
-
signode += mainDeclNode
|
|
1497
|
-
|
|
1498
|
-
if self.objectType in {'member', 'function', 'macro'}:
|
|
1499
|
-
pass
|
|
1500
|
-
elif self.objectType == 'struct':
|
|
1501
|
-
mainDeclNode += addnodes.desc_sig_keyword('struct', 'struct')
|
|
1502
|
-
mainDeclNode += addnodes.desc_sig_space()
|
|
1503
|
-
elif self.objectType == 'union':
|
|
1504
|
-
mainDeclNode += addnodes.desc_sig_keyword('union', 'union')
|
|
1505
|
-
mainDeclNode += addnodes.desc_sig_space()
|
|
1506
|
-
elif self.objectType == 'enum':
|
|
1507
|
-
mainDeclNode += addnodes.desc_sig_keyword('enum', 'enum')
|
|
1508
|
-
mainDeclNode += addnodes.desc_sig_space()
|
|
1509
|
-
elif self.objectType == 'enumerator':
|
|
1510
|
-
mainDeclNode += addnodes.desc_sig_keyword('enumerator', 'enumerator')
|
|
1511
|
-
mainDeclNode += addnodes.desc_sig_space()
|
|
1512
|
-
elif self.objectType == 'type':
|
|
1513
|
-
decl = cast(ASTType, self.declaration)
|
|
1514
|
-
prefix = decl.get_type_declaration_prefix()
|
|
1515
|
-
mainDeclNode += addnodes.desc_sig_keyword(prefix, prefix)
|
|
1516
|
-
mainDeclNode += addnodes.desc_sig_space()
|
|
1517
|
-
else:
|
|
1518
|
-
raise AssertionError
|
|
1519
|
-
self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
|
|
1520
|
-
if self.semicolon:
|
|
1521
|
-
mainDeclNode += addnodes.desc_sig_punctuation(';', ';')
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
class SymbolLookupResult:
|
|
1525
|
-
def __init__(self, symbols: Iterator[Symbol], parentSymbol: Symbol,
|
|
1526
|
-
ident: ASTIdentifier) -> None:
|
|
1527
|
-
self.symbols = symbols
|
|
1528
|
-
self.parentSymbol = parentSymbol
|
|
1529
|
-
self.ident = ident
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
class LookupKey:
|
|
1533
|
-
def __init__(self, data: list[tuple[ASTIdentifier, str]]) -> None:
|
|
1534
|
-
self.data = data
|
|
1535
|
-
|
|
1536
|
-
def __str__(self) -> str:
|
|
1537
|
-
inner = ', '.join(f"({ident}, {id_})" for ident, id_ in self.data)
|
|
1538
|
-
return f'[{inner}]'
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
class Symbol:
|
|
1542
|
-
debug_indent = 0
|
|
1543
|
-
debug_indent_string = " "
|
|
1544
|
-
debug_lookup = False
|
|
1545
|
-
debug_show_tree = False
|
|
1546
|
-
|
|
1547
|
-
def __copy__(self):
|
|
1548
|
-
raise AssertionError # shouldn't happen
|
|
1549
|
-
|
|
1550
|
-
def __deepcopy__(self, memo):
|
|
1551
|
-
if self.parent:
|
|
1552
|
-
raise AssertionError # shouldn't happen
|
|
1553
|
-
# the domain base class makes a copy of the initial data, which is fine
|
|
1554
|
-
return Symbol(None, None, None, None, None)
|
|
1555
|
-
|
|
1556
|
-
@staticmethod
|
|
1557
|
-
def debug_print(*args: Any) -> None:
|
|
1558
|
-
logger.debug(Symbol.debug_indent_string * Symbol.debug_indent, end="")
|
|
1559
|
-
logger.debug(*args)
|
|
1560
|
-
|
|
1561
|
-
def _assert_invariants(self) -> None:
|
|
1562
|
-
if not self.parent:
|
|
1563
|
-
# parent == None means global scope, so declaration means a parent
|
|
1564
|
-
assert not self.declaration
|
|
1565
|
-
assert not self.docname
|
|
1566
|
-
else:
|
|
1567
|
-
if self.declaration:
|
|
1568
|
-
assert self.docname
|
|
1569
|
-
|
|
1570
|
-
def __setattr__(self, key: str, value: Any) -> None:
|
|
1571
|
-
if key == "children":
|
|
1572
|
-
raise AssertionError
|
|
1573
|
-
return super().__setattr__(key, value)
|
|
1574
|
-
|
|
1575
|
-
def __init__(
|
|
1576
|
-
self,
|
|
1577
|
-
parent: Symbol,
|
|
1578
|
-
ident: ASTIdentifier,
|
|
1579
|
-
declaration: ASTDeclaration | None,
|
|
1580
|
-
docname: str | None,
|
|
1581
|
-
line: int | None,
|
|
1582
|
-
) -> None:
|
|
1583
|
-
self.parent = parent
|
|
1584
|
-
# declarations in a single directive are linked together
|
|
1585
|
-
self.siblingAbove: Symbol = None
|
|
1586
|
-
self.siblingBelow: Symbol = None
|
|
1587
|
-
self.ident = ident
|
|
1588
|
-
self.declaration = declaration
|
|
1589
|
-
self.docname = docname
|
|
1590
|
-
self.line = line
|
|
1591
|
-
self.isRedeclaration = False
|
|
1592
|
-
self._assert_invariants()
|
|
1593
|
-
|
|
1594
|
-
# Remember to modify Symbol.remove if modifications to the parent change.
|
|
1595
|
-
self._children: list[Symbol] = []
|
|
1596
|
-
self._anonChildren: list[Symbol] = []
|
|
1597
|
-
# note: _children includes _anonChildren
|
|
1598
|
-
if self.parent:
|
|
1599
|
-
self.parent._children.append(self)
|
|
1600
|
-
if self.declaration:
|
|
1601
|
-
self.declaration.symbol = self
|
|
1602
|
-
|
|
1603
|
-
# Do symbol addition after self._children has been initialised.
|
|
1604
|
-
self._add_function_params()
|
|
1605
|
-
|
|
1606
|
-
def _fill_empty(self, declaration: ASTDeclaration, docname: str, line: int) -> None:
|
|
1607
|
-
self._assert_invariants()
|
|
1608
|
-
assert self.declaration is None
|
|
1609
|
-
assert self.docname is None
|
|
1610
|
-
assert self.line is None
|
|
1611
|
-
assert declaration is not None
|
|
1612
|
-
assert docname is not None
|
|
1613
|
-
assert line is not None
|
|
1614
|
-
self.declaration = declaration
|
|
1615
|
-
self.declaration.symbol = self
|
|
1616
|
-
self.docname = docname
|
|
1617
|
-
self.line = line
|
|
1618
|
-
self._assert_invariants()
|
|
1619
|
-
# and symbol addition should be done as well
|
|
1620
|
-
self._add_function_params()
|
|
1621
|
-
|
|
1622
|
-
def _add_function_params(self) -> None:
|
|
1623
|
-
if Symbol.debug_lookup:
|
|
1624
|
-
Symbol.debug_indent += 1
|
|
1625
|
-
Symbol.debug_print("_add_function_params:")
|
|
1626
|
-
# Note: we may be called from _fill_empty, so the symbols we want
|
|
1627
|
-
# to add may actually already be present (as empty symbols).
|
|
1628
|
-
|
|
1629
|
-
# add symbols for function parameters, if any
|
|
1630
|
-
if self.declaration is not None and self.declaration.function_params is not None:
|
|
1631
|
-
for p in self.declaration.function_params:
|
|
1632
|
-
if p.arg is None:
|
|
1633
|
-
continue
|
|
1634
|
-
nn = p.arg.name
|
|
1635
|
-
if nn is None:
|
|
1636
|
-
continue
|
|
1637
|
-
# (comparing to the template params: we have checked that we are a declaration)
|
|
1638
|
-
decl = ASTDeclaration('functionParam', None, p)
|
|
1639
|
-
assert not nn.rooted
|
|
1640
|
-
assert len(nn.names) == 1
|
|
1641
|
-
self._add_symbols(nn, decl, self.docname, self.line)
|
|
1642
|
-
if Symbol.debug_lookup:
|
|
1643
|
-
Symbol.debug_indent -= 1
|
|
1644
|
-
|
|
1645
|
-
def remove(self) -> None:
|
|
1646
|
-
if self.parent is None:
|
|
1647
|
-
return
|
|
1648
|
-
assert self in self.parent._children
|
|
1649
|
-
self.parent._children.remove(self)
|
|
1650
|
-
self.parent = None
|
|
1651
|
-
|
|
1652
|
-
def clear_doc(self, docname: str) -> None:
|
|
1653
|
-
for sChild in self._children:
|
|
1654
|
-
sChild.clear_doc(docname)
|
|
1655
|
-
if sChild.declaration and sChild.docname == docname:
|
|
1656
|
-
sChild.declaration = None
|
|
1657
|
-
sChild.docname = None
|
|
1658
|
-
sChild.line = None
|
|
1659
|
-
if sChild.siblingAbove is not None:
|
|
1660
|
-
sChild.siblingAbove.siblingBelow = sChild.siblingBelow
|
|
1661
|
-
if sChild.siblingBelow is not None:
|
|
1662
|
-
sChild.siblingBelow.siblingAbove = sChild.siblingAbove
|
|
1663
|
-
sChild.siblingAbove = None
|
|
1664
|
-
sChild.siblingBelow = None
|
|
1665
|
-
|
|
1666
|
-
def get_all_symbols(self) -> Iterator[Symbol]:
|
|
1667
|
-
yield self
|
|
1668
|
-
for sChild in self._children:
|
|
1669
|
-
yield from sChild.get_all_symbols()
|
|
1670
|
-
|
|
1671
|
-
@property
|
|
1672
|
-
def children(self) -> Iterator[Symbol]:
|
|
1673
|
-
yield from self._children
|
|
1674
|
-
|
|
1675
|
-
@property
|
|
1676
|
-
def children_recurse_anon(self) -> Iterator[Symbol]:
|
|
1677
|
-
for c in self._children:
|
|
1678
|
-
yield c
|
|
1679
|
-
if not c.ident.is_anon():
|
|
1680
|
-
continue
|
|
1681
|
-
yield from c.children_recurse_anon
|
|
1682
|
-
|
|
1683
|
-
def get_lookup_key(self) -> LookupKey:
|
|
1684
|
-
# The pickle files for the environment and for each document are distinct.
|
|
1685
|
-
# The environment has all the symbols, but the documents has xrefs that
|
|
1686
|
-
# must know their scope. A lookup key is essentially a specification of
|
|
1687
|
-
# how to find a specific symbol.
|
|
1688
|
-
symbols = []
|
|
1689
|
-
s = self
|
|
1690
|
-
while s.parent:
|
|
1691
|
-
symbols.append(s)
|
|
1692
|
-
s = s.parent
|
|
1693
|
-
symbols.reverse()
|
|
1694
|
-
key = []
|
|
1695
|
-
for s in symbols:
|
|
1696
|
-
if s.declaration is not None:
|
|
1697
|
-
# TODO: do we need the ID?
|
|
1698
|
-
key.append((s.ident, s.declaration.get_newest_id()))
|
|
1699
|
-
else:
|
|
1700
|
-
key.append((s.ident, None))
|
|
1701
|
-
return LookupKey(key)
|
|
1702
|
-
|
|
1703
|
-
def get_full_nested_name(self) -> ASTNestedName:
|
|
1704
|
-
symbols = []
|
|
1705
|
-
s = self
|
|
1706
|
-
while s.parent:
|
|
1707
|
-
symbols.append(s)
|
|
1708
|
-
s = s.parent
|
|
1709
|
-
symbols.reverse()
|
|
1710
|
-
names = []
|
|
1711
|
-
for s in symbols:
|
|
1712
|
-
names.append(s.ident)
|
|
1713
|
-
return ASTNestedName(names, rooted=False)
|
|
1714
|
-
|
|
1715
|
-
def _find_first_named_symbol(self, ident: ASTIdentifier,
|
|
1716
|
-
matchSelf: bool, recurseInAnon: bool) -> Symbol | None:
|
|
1717
|
-
# TODO: further simplification from C++ to C
|
|
1718
|
-
if Symbol.debug_lookup:
|
|
1719
|
-
Symbol.debug_print("_find_first_named_symbol ->")
|
|
1720
|
-
res = self._find_named_symbols(ident, matchSelf, recurseInAnon,
|
|
1721
|
-
searchInSiblings=False)
|
|
1722
|
-
try:
|
|
1723
|
-
return next(res)
|
|
1724
|
-
except StopIteration:
|
|
1725
|
-
return None
|
|
1726
|
-
|
|
1727
|
-
def _find_named_symbols(self, ident: ASTIdentifier,
|
|
1728
|
-
matchSelf: bool, recurseInAnon: bool,
|
|
1729
|
-
searchInSiblings: bool) -> Iterator[Symbol]:
|
|
1730
|
-
# TODO: further simplification from C++ to C
|
|
1731
|
-
if Symbol.debug_lookup:
|
|
1732
|
-
Symbol.debug_indent += 1
|
|
1733
|
-
Symbol.debug_print("_find_named_symbols:")
|
|
1734
|
-
Symbol.debug_indent += 1
|
|
1735
|
-
Symbol.debug_print("self:")
|
|
1736
|
-
logger.debug(self.to_string(Symbol.debug_indent + 1), end="")
|
|
1737
|
-
Symbol.debug_print("ident: ", ident)
|
|
1738
|
-
Symbol.debug_print("matchSelf: ", matchSelf)
|
|
1739
|
-
Symbol.debug_print("recurseInAnon: ", recurseInAnon)
|
|
1740
|
-
Symbol.debug_print("searchInSiblings: ", searchInSiblings)
|
|
1741
|
-
|
|
1742
|
-
def candidates() -> Generator[Symbol, None, None]:
|
|
1743
|
-
s = self
|
|
1744
|
-
if Symbol.debug_lookup:
|
|
1745
|
-
Symbol.debug_print("searching in self:")
|
|
1746
|
-
logger.debug(s.to_string(Symbol.debug_indent + 1), end="")
|
|
1747
|
-
while True:
|
|
1748
|
-
if matchSelf:
|
|
1749
|
-
yield s
|
|
1750
|
-
if recurseInAnon:
|
|
1751
|
-
yield from s.children_recurse_anon
|
|
1752
|
-
else:
|
|
1753
|
-
yield from s._children
|
|
1754
|
-
|
|
1755
|
-
if s.siblingAbove is None:
|
|
1756
|
-
break
|
|
1757
|
-
s = s.siblingAbove
|
|
1758
|
-
if Symbol.debug_lookup:
|
|
1759
|
-
Symbol.debug_print("searching in sibling:")
|
|
1760
|
-
logger.debug(s.to_string(Symbol.debug_indent + 1), end="")
|
|
1761
|
-
|
|
1762
|
-
for s in candidates():
|
|
1763
|
-
if Symbol.debug_lookup:
|
|
1764
|
-
Symbol.debug_print("candidate:")
|
|
1765
|
-
logger.debug(s.to_string(Symbol.debug_indent + 1), end="")
|
|
1766
|
-
if s.ident == ident:
|
|
1767
|
-
if Symbol.debug_lookup:
|
|
1768
|
-
Symbol.debug_indent += 1
|
|
1769
|
-
Symbol.debug_print("matches")
|
|
1770
|
-
Symbol.debug_indent -= 3
|
|
1771
|
-
yield s
|
|
1772
|
-
if Symbol.debug_lookup:
|
|
1773
|
-
Symbol.debug_indent += 2
|
|
1774
|
-
if Symbol.debug_lookup:
|
|
1775
|
-
Symbol.debug_indent -= 2
|
|
1776
|
-
|
|
1777
|
-
def _symbol_lookup(
|
|
1778
|
-
self,
|
|
1779
|
-
nestedName: ASTNestedName,
|
|
1780
|
-
onMissingQualifiedSymbol: Callable[[Symbol, ASTIdentifier], Symbol | None],
|
|
1781
|
-
ancestorLookupType: str | None,
|
|
1782
|
-
matchSelf: bool,
|
|
1783
|
-
recurseInAnon: bool,
|
|
1784
|
-
searchInSiblings: bool,
|
|
1785
|
-
) -> SymbolLookupResult | None:
|
|
1786
|
-
# TODO: further simplification from C++ to C
|
|
1787
|
-
# ancestorLookupType: if not None, specifies the target type of the lookup
|
|
1788
|
-
if Symbol.debug_lookup:
|
|
1789
|
-
Symbol.debug_indent += 1
|
|
1790
|
-
Symbol.debug_print("_symbol_lookup:")
|
|
1791
|
-
Symbol.debug_indent += 1
|
|
1792
|
-
Symbol.debug_print("self:")
|
|
1793
|
-
logger.debug(self.to_string(Symbol.debug_indent + 1), end="")
|
|
1794
|
-
Symbol.debug_print("nestedName: ", nestedName)
|
|
1795
|
-
Symbol.debug_print("ancestorLookupType:", ancestorLookupType)
|
|
1796
|
-
Symbol.debug_print("matchSelf: ", matchSelf)
|
|
1797
|
-
Symbol.debug_print("recurseInAnon: ", recurseInAnon)
|
|
1798
|
-
Symbol.debug_print("searchInSiblings: ", searchInSiblings)
|
|
1799
|
-
|
|
1800
|
-
names = nestedName.names
|
|
1801
|
-
|
|
1802
|
-
# find the right starting point for lookup
|
|
1803
|
-
parentSymbol = self
|
|
1804
|
-
if nestedName.rooted:
|
|
1805
|
-
while parentSymbol.parent:
|
|
1806
|
-
parentSymbol = parentSymbol.parent
|
|
1807
|
-
if ancestorLookupType is not None:
|
|
1808
|
-
# walk up until we find the first identifier
|
|
1809
|
-
firstName = names[0]
|
|
1810
|
-
while parentSymbol.parent:
|
|
1811
|
-
if parentSymbol.find_identifier(firstName,
|
|
1812
|
-
matchSelf=matchSelf,
|
|
1813
|
-
recurseInAnon=recurseInAnon,
|
|
1814
|
-
searchInSiblings=searchInSiblings):
|
|
1815
|
-
break
|
|
1816
|
-
parentSymbol = parentSymbol.parent
|
|
1817
|
-
|
|
1818
|
-
if Symbol.debug_lookup:
|
|
1819
|
-
Symbol.debug_print("starting point:")
|
|
1820
|
-
logger.debug(parentSymbol.to_string(Symbol.debug_indent + 1), end="")
|
|
1821
|
-
|
|
1822
|
-
# and now the actual lookup
|
|
1823
|
-
for ident in names[:-1]:
|
|
1824
|
-
symbol = parentSymbol._find_first_named_symbol(
|
|
1825
|
-
ident, matchSelf=matchSelf, recurseInAnon=recurseInAnon)
|
|
1826
|
-
if symbol is None:
|
|
1827
|
-
symbol = onMissingQualifiedSymbol(parentSymbol, ident)
|
|
1828
|
-
if symbol is None:
|
|
1829
|
-
if Symbol.debug_lookup:
|
|
1830
|
-
Symbol.debug_indent -= 2
|
|
1831
|
-
return None
|
|
1832
|
-
# We have now matched part of a nested name, and need to match more
|
|
1833
|
-
# so even if we should matchSelf before, we definitely shouldn't
|
|
1834
|
-
# even more. (see also issue #2666)
|
|
1835
|
-
matchSelf = False
|
|
1836
|
-
parentSymbol = symbol
|
|
1837
|
-
|
|
1838
|
-
if Symbol.debug_lookup:
|
|
1839
|
-
Symbol.debug_print("handle last name from:")
|
|
1840
|
-
logger.debug(parentSymbol.to_string(Symbol.debug_indent + 1), end="")
|
|
1841
|
-
|
|
1842
|
-
# handle the last name
|
|
1843
|
-
ident = names[-1]
|
|
1844
|
-
|
|
1845
|
-
symbols = parentSymbol._find_named_symbols(
|
|
1846
|
-
ident, matchSelf=matchSelf,
|
|
1847
|
-
recurseInAnon=recurseInAnon,
|
|
1848
|
-
searchInSiblings=searchInSiblings)
|
|
1849
|
-
if Symbol.debug_lookup:
|
|
1850
|
-
symbols = list(symbols) # type: ignore[assignment]
|
|
1851
|
-
Symbol.debug_indent -= 2
|
|
1852
|
-
return SymbolLookupResult(symbols, parentSymbol, ident)
|
|
1853
|
-
|
|
1854
|
-
def _add_symbols(
|
|
1855
|
-
self,
|
|
1856
|
-
nestedName: ASTNestedName,
|
|
1857
|
-
declaration: ASTDeclaration | None,
|
|
1858
|
-
docname: str | None,
|
|
1859
|
-
line: int | None,
|
|
1860
|
-
) -> Symbol:
|
|
1861
|
-
# TODO: further simplification from C++ to C
|
|
1862
|
-
# Used for adding a whole path of symbols, where the last may or may not
|
|
1863
|
-
# be an actual declaration.
|
|
1864
|
-
|
|
1865
|
-
if Symbol.debug_lookup:
|
|
1866
|
-
Symbol.debug_indent += 1
|
|
1867
|
-
Symbol.debug_print("_add_symbols:")
|
|
1868
|
-
Symbol.debug_indent += 1
|
|
1869
|
-
Symbol.debug_print("nn: ", nestedName)
|
|
1870
|
-
Symbol.debug_print("decl: ", declaration)
|
|
1871
|
-
Symbol.debug_print(f"location: {docname}:{line}")
|
|
1872
|
-
|
|
1873
|
-
def onMissingQualifiedSymbol(parentSymbol: Symbol, ident: ASTIdentifier) -> Symbol:
|
|
1874
|
-
if Symbol.debug_lookup:
|
|
1875
|
-
Symbol.debug_indent += 1
|
|
1876
|
-
Symbol.debug_print("_add_symbols, onMissingQualifiedSymbol:")
|
|
1877
|
-
Symbol.debug_indent += 1
|
|
1878
|
-
Symbol.debug_print("ident: ", ident)
|
|
1879
|
-
Symbol.debug_indent -= 2
|
|
1880
|
-
return Symbol(parent=parentSymbol, ident=ident,
|
|
1881
|
-
declaration=None, docname=None, line=None)
|
|
1882
|
-
|
|
1883
|
-
lookupResult = self._symbol_lookup(nestedName,
|
|
1884
|
-
onMissingQualifiedSymbol,
|
|
1885
|
-
ancestorLookupType=None,
|
|
1886
|
-
matchSelf=False,
|
|
1887
|
-
recurseInAnon=False,
|
|
1888
|
-
searchInSiblings=False)
|
|
1889
|
-
assert lookupResult is not None # we create symbols all the way, so that can't happen
|
|
1890
|
-
symbols = list(lookupResult.symbols)
|
|
1891
|
-
if len(symbols) == 0:
|
|
1892
|
-
if Symbol.debug_lookup:
|
|
1893
|
-
Symbol.debug_print("_add_symbols, result, no symbol:")
|
|
1894
|
-
Symbol.debug_indent += 1
|
|
1895
|
-
Symbol.debug_print("ident: ", lookupResult.ident)
|
|
1896
|
-
Symbol.debug_print("declaration: ", declaration)
|
|
1897
|
-
Symbol.debug_print(f"location: {docname}:{line}")
|
|
1898
|
-
Symbol.debug_indent -= 1
|
|
1899
|
-
symbol = Symbol(parent=lookupResult.parentSymbol,
|
|
1900
|
-
ident=lookupResult.ident,
|
|
1901
|
-
declaration=declaration,
|
|
1902
|
-
docname=docname, line=line)
|
|
1903
|
-
if Symbol.debug_lookup:
|
|
1904
|
-
Symbol.debug_indent -= 2
|
|
1905
|
-
return symbol
|
|
1906
|
-
|
|
1907
|
-
if Symbol.debug_lookup:
|
|
1908
|
-
Symbol.debug_print("_add_symbols, result, symbols:")
|
|
1909
|
-
Symbol.debug_indent += 1
|
|
1910
|
-
Symbol.debug_print("number symbols:", len(symbols))
|
|
1911
|
-
Symbol.debug_indent -= 1
|
|
1912
|
-
|
|
1913
|
-
if not declaration:
|
|
1914
|
-
if Symbol.debug_lookup:
|
|
1915
|
-
Symbol.debug_print("no declaration")
|
|
1916
|
-
Symbol.debug_indent -= 2
|
|
1917
|
-
# good, just a scope creation
|
|
1918
|
-
# TODO: what if we have more than one symbol?
|
|
1919
|
-
return symbols[0]
|
|
1920
|
-
|
|
1921
|
-
noDecl = []
|
|
1922
|
-
withDecl = []
|
|
1923
|
-
dupDecl = []
|
|
1924
|
-
for s in symbols:
|
|
1925
|
-
if s.declaration is None:
|
|
1926
|
-
noDecl.append(s)
|
|
1927
|
-
elif s.isRedeclaration:
|
|
1928
|
-
dupDecl.append(s)
|
|
1929
|
-
else:
|
|
1930
|
-
withDecl.append(s)
|
|
1931
|
-
if Symbol.debug_lookup:
|
|
1932
|
-
Symbol.debug_print("#noDecl: ", len(noDecl))
|
|
1933
|
-
Symbol.debug_print("#withDecl:", len(withDecl))
|
|
1934
|
-
Symbol.debug_print("#dupDecl: ", len(dupDecl))
|
|
1935
|
-
|
|
1936
|
-
# With partial builds we may start with a large symbol tree stripped of declarations.
|
|
1937
|
-
# Essentially any combination of noDecl, withDecl, and dupDecls seems possible.
|
|
1938
|
-
# TODO: make partial builds fully work. What should happen when the primary symbol gets
|
|
1939
|
-
# deleted, and other duplicates exist? The full document should probably be rebuild.
|
|
1940
|
-
|
|
1941
|
-
# First check if one of those with a declaration matches.
|
|
1942
|
-
# If it's a function, we need to compare IDs,
|
|
1943
|
-
# otherwise there should be only one symbol with a declaration.
|
|
1944
|
-
def makeCandSymbol() -> Symbol:
|
|
1945
|
-
if Symbol.debug_lookup:
|
|
1946
|
-
Symbol.debug_print("begin: creating candidate symbol")
|
|
1947
|
-
symbol = Symbol(parent=lookupResult.parentSymbol,
|
|
1948
|
-
ident=lookupResult.ident,
|
|
1949
|
-
declaration=declaration,
|
|
1950
|
-
docname=docname, line=line)
|
|
1951
|
-
if Symbol.debug_lookup:
|
|
1952
|
-
Symbol.debug_print("end: creating candidate symbol")
|
|
1953
|
-
return symbol
|
|
1954
|
-
|
|
1955
|
-
if len(withDecl) == 0:
|
|
1956
|
-
candSymbol = None
|
|
1957
|
-
else:
|
|
1958
|
-
candSymbol = makeCandSymbol()
|
|
1959
|
-
|
|
1960
|
-
def handleDuplicateDeclaration(symbol: Symbol, candSymbol: Symbol) -> None:
|
|
1961
|
-
if Symbol.debug_lookup:
|
|
1962
|
-
Symbol.debug_indent += 1
|
|
1963
|
-
Symbol.debug_print("redeclaration")
|
|
1964
|
-
Symbol.debug_indent -= 1
|
|
1965
|
-
Symbol.debug_indent -= 2
|
|
1966
|
-
# Redeclaration of the same symbol.
|
|
1967
|
-
# Let the new one be there, but raise an error to the client
|
|
1968
|
-
# so it can use the real symbol as subscope.
|
|
1969
|
-
# This will probably result in a duplicate id warning.
|
|
1970
|
-
candSymbol.isRedeclaration = True
|
|
1971
|
-
raise _DuplicateSymbolError(symbol, declaration)
|
|
1972
|
-
|
|
1973
|
-
if declaration.objectType != "function":
|
|
1974
|
-
assert len(withDecl) <= 1
|
|
1975
|
-
handleDuplicateDeclaration(withDecl[0], candSymbol)
|
|
1976
|
-
# (not reachable)
|
|
1977
|
-
|
|
1978
|
-
# a function, so compare IDs
|
|
1979
|
-
candId = declaration.get_newest_id()
|
|
1980
|
-
if Symbol.debug_lookup:
|
|
1981
|
-
Symbol.debug_print("candId:", candId)
|
|
1982
|
-
for symbol in withDecl:
|
|
1983
|
-
oldId = symbol.declaration.get_newest_id()
|
|
1984
|
-
if Symbol.debug_lookup:
|
|
1985
|
-
Symbol.debug_print("oldId: ", oldId)
|
|
1986
|
-
if candId == oldId:
|
|
1987
|
-
handleDuplicateDeclaration(symbol, candSymbol)
|
|
1988
|
-
# (not reachable)
|
|
1989
|
-
# no candidate symbol found with matching ID
|
|
1990
|
-
# if there is an empty symbol, fill that one
|
|
1991
|
-
if len(noDecl) == 0:
|
|
1992
|
-
if Symbol.debug_lookup:
|
|
1993
|
-
Symbol.debug_print(
|
|
1994
|
-
"no match, no empty, candSybmol is not None?:", candSymbol is not None,
|
|
1995
|
-
)
|
|
1996
|
-
Symbol.debug_indent -= 2
|
|
1997
|
-
if candSymbol is not None:
|
|
1998
|
-
return candSymbol
|
|
1999
|
-
else:
|
|
2000
|
-
return makeCandSymbol()
|
|
2001
|
-
else:
|
|
2002
|
-
if Symbol.debug_lookup:
|
|
2003
|
-
Symbol.debug_print(
|
|
2004
|
-
"no match, but fill an empty declaration, candSybmol is not None?:",
|
|
2005
|
-
candSymbol is not None)
|
|
2006
|
-
Symbol.debug_indent -= 2
|
|
2007
|
-
if candSymbol is not None:
|
|
2008
|
-
candSymbol.remove()
|
|
2009
|
-
# assert len(noDecl) == 1
|
|
2010
|
-
# TODO: enable assertion when we at some point find out how to do cleanup
|
|
2011
|
-
# for now, just take the first one, it should work fine ... right?
|
|
2012
|
-
symbol = noDecl[0]
|
|
2013
|
-
# If someone first opened the scope, and then later
|
|
2014
|
-
# declares it, e.g,
|
|
2015
|
-
# .. namespace:: Test
|
|
2016
|
-
# .. namespace:: nullptr
|
|
2017
|
-
# .. class:: Test
|
|
2018
|
-
symbol._fill_empty(declaration, docname, line)
|
|
2019
|
-
return symbol
|
|
2020
|
-
|
|
2021
|
-
def merge_with(self, other: Symbol, docnames: list[str],
|
|
2022
|
-
env: BuildEnvironment) -> None:
|
|
2023
|
-
if Symbol.debug_lookup:
|
|
2024
|
-
Symbol.debug_indent += 1
|
|
2025
|
-
Symbol.debug_print("merge_with:")
|
|
2026
|
-
assert other is not None
|
|
2027
|
-
for otherChild in other._children:
|
|
2028
|
-
ourChild = self._find_first_named_symbol(
|
|
2029
|
-
ident=otherChild.ident, matchSelf=False,
|
|
2030
|
-
recurseInAnon=False)
|
|
2031
|
-
if ourChild is None:
|
|
2032
|
-
# TODO: hmm, should we prune by docnames?
|
|
2033
|
-
self._children.append(otherChild)
|
|
2034
|
-
otherChild.parent = self
|
|
2035
|
-
otherChild._assert_invariants()
|
|
2036
|
-
continue
|
|
2037
|
-
if otherChild.declaration and otherChild.docname in docnames:
|
|
2038
|
-
if not ourChild.declaration:
|
|
2039
|
-
ourChild._fill_empty(otherChild.declaration,
|
|
2040
|
-
otherChild.docname, otherChild.line)
|
|
2041
|
-
elif ourChild.docname != otherChild.docname:
|
|
2042
|
-
name = str(ourChild.declaration)
|
|
2043
|
-
msg = __("Duplicate C declaration, also defined at %s:%s.\n"
|
|
2044
|
-
"Declaration is '.. c:%s:: %s'.")
|
|
2045
|
-
msg = msg % (ourChild.docname, ourChild.line,
|
|
2046
|
-
ourChild.declaration.directiveType, name)
|
|
2047
|
-
logger.warning(msg, location=(otherChild.docname, otherChild.line))
|
|
2048
|
-
else:
|
|
2049
|
-
# Both have declarations, and in the same docname.
|
|
2050
|
-
# This can apparently happen, it should be safe to
|
|
2051
|
-
# just ignore it, right?
|
|
2052
|
-
pass
|
|
2053
|
-
ourChild.merge_with(otherChild, docnames, env)
|
|
2054
|
-
if Symbol.debug_lookup:
|
|
2055
|
-
Symbol.debug_indent -= 1
|
|
2056
|
-
|
|
2057
|
-
def add_name(self, nestedName: ASTNestedName) -> Symbol:
|
|
2058
|
-
if Symbol.debug_lookup:
|
|
2059
|
-
Symbol.debug_indent += 1
|
|
2060
|
-
Symbol.debug_print("add_name:")
|
|
2061
|
-
res = self._add_symbols(nestedName, declaration=None, docname=None, line=None)
|
|
2062
|
-
if Symbol.debug_lookup:
|
|
2063
|
-
Symbol.debug_indent -= 1
|
|
2064
|
-
return res
|
|
2065
|
-
|
|
2066
|
-
def add_declaration(self, declaration: ASTDeclaration,
|
|
2067
|
-
docname: str, line: int) -> Symbol:
|
|
2068
|
-
if Symbol.debug_lookup:
|
|
2069
|
-
Symbol.debug_indent += 1
|
|
2070
|
-
Symbol.debug_print("add_declaration:")
|
|
2071
|
-
assert declaration is not None
|
|
2072
|
-
assert docname is not None
|
|
2073
|
-
assert line is not None
|
|
2074
|
-
nestedName = declaration.name
|
|
2075
|
-
res = self._add_symbols(nestedName, declaration, docname, line)
|
|
2076
|
-
if Symbol.debug_lookup:
|
|
2077
|
-
Symbol.debug_indent -= 1
|
|
2078
|
-
return res
|
|
2079
|
-
|
|
2080
|
-
def find_identifier(self, ident: ASTIdentifier,
|
|
2081
|
-
matchSelf: bool, recurseInAnon: bool, searchInSiblings: bool,
|
|
2082
|
-
) -> Symbol | None:
|
|
2083
|
-
if Symbol.debug_lookup:
|
|
2084
|
-
Symbol.debug_indent += 1
|
|
2085
|
-
Symbol.debug_print("find_identifier:")
|
|
2086
|
-
Symbol.debug_indent += 1
|
|
2087
|
-
Symbol.debug_print("ident: ", ident)
|
|
2088
|
-
Symbol.debug_print("matchSelf: ", matchSelf)
|
|
2089
|
-
Symbol.debug_print("recurseInAnon: ", recurseInAnon)
|
|
2090
|
-
Symbol.debug_print("searchInSiblings:", searchInSiblings)
|
|
2091
|
-
logger.debug(self.to_string(Symbol.debug_indent + 1), end="")
|
|
2092
|
-
Symbol.debug_indent -= 2
|
|
2093
|
-
current = self
|
|
2094
|
-
while current is not None:
|
|
2095
|
-
if Symbol.debug_lookup:
|
|
2096
|
-
Symbol.debug_indent += 2
|
|
2097
|
-
Symbol.debug_print("trying:")
|
|
2098
|
-
logger.debug(current.to_string(Symbol.debug_indent + 1), end="")
|
|
2099
|
-
Symbol.debug_indent -= 2
|
|
2100
|
-
if matchSelf and current.ident == ident:
|
|
2101
|
-
return current
|
|
2102
|
-
children = current.children_recurse_anon if recurseInAnon else current._children
|
|
2103
|
-
for s in children:
|
|
2104
|
-
if s.ident == ident:
|
|
2105
|
-
return s
|
|
2106
|
-
if not searchInSiblings:
|
|
2107
|
-
break
|
|
2108
|
-
current = current.siblingAbove
|
|
2109
|
-
return None
|
|
2110
|
-
|
|
2111
|
-
def direct_lookup(self, key: LookupKey) -> Symbol | None:
|
|
2112
|
-
if Symbol.debug_lookup:
|
|
2113
|
-
Symbol.debug_indent += 1
|
|
2114
|
-
Symbol.debug_print("direct_lookup:")
|
|
2115
|
-
Symbol.debug_indent += 1
|
|
2116
|
-
s = self
|
|
2117
|
-
for name, id_ in key.data:
|
|
2118
|
-
res = None
|
|
2119
|
-
for cand in s._children:
|
|
2120
|
-
if cand.ident == name:
|
|
2121
|
-
res = cand
|
|
2122
|
-
break
|
|
2123
|
-
s = res
|
|
2124
|
-
if Symbol.debug_lookup:
|
|
2125
|
-
Symbol.debug_print("name: ", name)
|
|
2126
|
-
Symbol.debug_print("id: ", id_)
|
|
2127
|
-
if s is not None:
|
|
2128
|
-
logger.debug(s.to_string(Symbol.debug_indent + 1), end="")
|
|
2129
|
-
else:
|
|
2130
|
-
Symbol.debug_print("not found")
|
|
2131
|
-
if s is None:
|
|
2132
|
-
if Symbol.debug_lookup:
|
|
2133
|
-
Symbol.debug_indent -= 2
|
|
2134
|
-
return None
|
|
2135
|
-
if Symbol.debug_lookup:
|
|
2136
|
-
Symbol.debug_indent -= 2
|
|
2137
|
-
return s
|
|
2138
|
-
|
|
2139
|
-
def find_declaration(self, nestedName: ASTNestedName, typ: str,
|
|
2140
|
-
matchSelf: bool, recurseInAnon: bool) -> Symbol | None:
|
|
2141
|
-
# templateShorthand: missing template parameter lists for templates is ok
|
|
2142
|
-
if Symbol.debug_lookup:
|
|
2143
|
-
Symbol.debug_indent += 1
|
|
2144
|
-
Symbol.debug_print("find_declaration:")
|
|
2145
|
-
|
|
2146
|
-
def onMissingQualifiedSymbol(
|
|
2147
|
-
parentSymbol: Symbol,
|
|
2148
|
-
ident: ASTIdentifier,
|
|
2149
|
-
) -> Symbol | None:
|
|
2150
|
-
return None
|
|
2151
|
-
|
|
2152
|
-
lookupResult = self._symbol_lookup(nestedName,
|
|
2153
|
-
onMissingQualifiedSymbol,
|
|
2154
|
-
ancestorLookupType=typ,
|
|
2155
|
-
matchSelf=matchSelf,
|
|
2156
|
-
recurseInAnon=recurseInAnon,
|
|
2157
|
-
searchInSiblings=False)
|
|
2158
|
-
if Symbol.debug_lookup:
|
|
2159
|
-
Symbol.debug_indent -= 1
|
|
2160
|
-
if lookupResult is None:
|
|
2161
|
-
return None
|
|
2162
|
-
|
|
2163
|
-
symbols = list(lookupResult.symbols)
|
|
2164
|
-
if len(symbols) == 0:
|
|
2165
|
-
return None
|
|
2166
|
-
return symbols[0]
|
|
2167
|
-
|
|
2168
|
-
def to_string(self, indent: int) -> str:
|
|
2169
|
-
res = [Symbol.debug_indent_string * indent]
|
|
2170
|
-
if not self.parent:
|
|
2171
|
-
res.append('::')
|
|
2172
|
-
else:
|
|
2173
|
-
if self.ident:
|
|
2174
|
-
res.append(str(self.ident))
|
|
2175
|
-
else:
|
|
2176
|
-
res.append(str(self.declaration))
|
|
2177
|
-
if self.declaration:
|
|
2178
|
-
res.append(": ")
|
|
2179
|
-
if self.isRedeclaration:
|
|
2180
|
-
res.append('!!duplicate!! ')
|
|
2181
|
-
res.append(str(self.declaration))
|
|
2182
|
-
if self.docname:
|
|
2183
|
-
res.append('\t(')
|
|
2184
|
-
res.append(self.docname)
|
|
2185
|
-
res.append(')')
|
|
2186
|
-
res.append('\n')
|
|
2187
|
-
return ''.join(res)
|
|
2188
|
-
|
|
2189
|
-
def dump(self, indent: int) -> str:
|
|
2190
|
-
res = [self.to_string(indent)]
|
|
2191
|
-
for c in self._children:
|
|
2192
|
-
res.append(c.dump(indent + 1))
|
|
2193
|
-
return ''.join(res)
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
class DefinitionParser(BaseParser):
|
|
2197
|
-
@property
|
|
2198
|
-
def language(self) -> str:
|
|
2199
|
-
return 'C'
|
|
2200
|
-
|
|
2201
|
-
@property
|
|
2202
|
-
def id_attributes(self):
|
|
2203
|
-
return self.config.c_id_attributes
|
|
2204
|
-
|
|
2205
|
-
@property
|
|
2206
|
-
def paren_attributes(self):
|
|
2207
|
-
return self.config.c_paren_attributes
|
|
2208
|
-
|
|
2209
|
-
def _parse_string(self) -> str | None:
|
|
2210
|
-
if self.current_char != '"':
|
|
2211
|
-
return None
|
|
2212
|
-
startPos = self.pos
|
|
2213
|
-
self.pos += 1
|
|
2214
|
-
escape = False
|
|
2215
|
-
while True:
|
|
2216
|
-
if self.eof:
|
|
2217
|
-
self.fail("Unexpected end during inside string.")
|
|
2218
|
-
elif self.current_char == '"' and not escape:
|
|
2219
|
-
self.pos += 1
|
|
2220
|
-
break
|
|
2221
|
-
elif self.current_char == '\\':
|
|
2222
|
-
escape = True
|
|
2223
|
-
else:
|
|
2224
|
-
escape = False
|
|
2225
|
-
self.pos += 1
|
|
2226
|
-
return self.definition[startPos:self.pos]
|
|
2227
|
-
|
|
2228
|
-
def _parse_literal(self) -> ASTLiteral | None:
|
|
2229
|
-
# -> integer-literal
|
|
2230
|
-
# | character-literal
|
|
2231
|
-
# | floating-literal
|
|
2232
|
-
# | string-literal
|
|
2233
|
-
# | boolean-literal -> "false" | "true"
|
|
2234
|
-
self.skip_ws()
|
|
2235
|
-
if self.skip_word('true'):
|
|
2236
|
-
return ASTBooleanLiteral(True)
|
|
2237
|
-
if self.skip_word('false'):
|
|
2238
|
-
return ASTBooleanLiteral(False)
|
|
2239
|
-
pos = self.pos
|
|
2240
|
-
if self.match(float_literal_re):
|
|
2241
|
-
self.match(float_literal_suffix_re)
|
|
2242
|
-
return ASTNumberLiteral(self.definition[pos:self.pos])
|
|
2243
|
-
for regex in [binary_literal_re, hex_literal_re,
|
|
2244
|
-
integer_literal_re, octal_literal_re]:
|
|
2245
|
-
if self.match(regex):
|
|
2246
|
-
self.match(integers_literal_suffix_re)
|
|
2247
|
-
return ASTNumberLiteral(self.definition[pos:self.pos])
|
|
2248
|
-
|
|
2249
|
-
string = self._parse_string()
|
|
2250
|
-
if string is not None:
|
|
2251
|
-
return ASTStringLiteral(string)
|
|
2252
|
-
|
|
2253
|
-
# character-literal
|
|
2254
|
-
if self.match(char_literal_re):
|
|
2255
|
-
prefix = self.last_match.group(1) # may be None when no prefix
|
|
2256
|
-
data = self.last_match.group(2)
|
|
2257
|
-
try:
|
|
2258
|
-
return ASTCharLiteral(prefix, data)
|
|
2259
|
-
except UnicodeDecodeError as e:
|
|
2260
|
-
self.fail("Can not handle character literal. Internal error was: %s" % e)
|
|
2261
|
-
except UnsupportedMultiCharacterCharLiteral:
|
|
2262
|
-
self.fail("Can not handle character literal"
|
|
2263
|
-
" resulting in multiple decoded characters.")
|
|
2264
|
-
return None
|
|
2265
|
-
|
|
2266
|
-
def _parse_paren_expression(self) -> ASTExpression | None:
|
|
2267
|
-
# "(" expression ")"
|
|
2268
|
-
if self.current_char != '(':
|
|
2269
|
-
return None
|
|
2270
|
-
self.pos += 1
|
|
2271
|
-
res = self._parse_expression()
|
|
2272
|
-
self.skip_ws()
|
|
2273
|
-
if not self.skip_string(')'):
|
|
2274
|
-
self.fail("Expected ')' in end of parenthesized expression.")
|
|
2275
|
-
return ASTParenExpr(res)
|
|
2276
|
-
|
|
2277
|
-
def _parse_primary_expression(self) -> ASTExpression | None:
|
|
2278
|
-
# literal
|
|
2279
|
-
# "(" expression ")"
|
|
2280
|
-
# id-expression -> we parse this with _parse_nested_name
|
|
2281
|
-
self.skip_ws()
|
|
2282
|
-
res: ASTExpression | None = self._parse_literal()
|
|
2283
|
-
if res is not None:
|
|
2284
|
-
return res
|
|
2285
|
-
res = self._parse_paren_expression()
|
|
2286
|
-
if res is not None:
|
|
2287
|
-
return res
|
|
2288
|
-
nn = self._parse_nested_name()
|
|
2289
|
-
if nn is not None:
|
|
2290
|
-
return ASTIdExpression(nn)
|
|
2291
|
-
return None
|
|
2292
|
-
|
|
2293
|
-
def _parse_initializer_list(self, name: str, open: str, close: str,
|
|
2294
|
-
) -> tuple[list[ASTExpression], bool]:
|
|
2295
|
-
# Parse open and close with the actual initializer-list in between
|
|
2296
|
-
# -> initializer-clause '...'[opt]
|
|
2297
|
-
# | initializer-list ',' initializer-clause '...'[opt]
|
|
2298
|
-
# TODO: designators
|
|
2299
|
-
self.skip_ws()
|
|
2300
|
-
if not self.skip_string_and_ws(open):
|
|
2301
|
-
return None, None
|
|
2302
|
-
if self.skip_string(close):
|
|
2303
|
-
return [], False
|
|
2304
|
-
|
|
2305
|
-
exprs = []
|
|
2306
|
-
trailingComma = False
|
|
2307
|
-
while True:
|
|
2308
|
-
self.skip_ws()
|
|
2309
|
-
expr = self._parse_expression()
|
|
2310
|
-
self.skip_ws()
|
|
2311
|
-
exprs.append(expr)
|
|
2312
|
-
self.skip_ws()
|
|
2313
|
-
if self.skip_string(close):
|
|
2314
|
-
break
|
|
2315
|
-
if not self.skip_string_and_ws(','):
|
|
2316
|
-
self.fail(f"Error in {name}, expected ',' or '{close}'.")
|
|
2317
|
-
if self.current_char == close and close == '}':
|
|
2318
|
-
self.pos += 1
|
|
2319
|
-
trailingComma = True
|
|
2320
|
-
break
|
|
2321
|
-
return exprs, trailingComma
|
|
2322
|
-
|
|
2323
|
-
def _parse_paren_expression_list(self) -> ASTParenExprList | None:
|
|
2324
|
-
# -> '(' expression-list ')'
|
|
2325
|
-
# though, we relax it to also allow empty parens
|
|
2326
|
-
# as it's needed in some cases
|
|
2327
|
-
#
|
|
2328
|
-
# expression-list
|
|
2329
|
-
# -> initializer-list
|
|
2330
|
-
exprs, trailingComma = self._parse_initializer_list("parenthesized expression-list",
|
|
2331
|
-
'(', ')')
|
|
2332
|
-
if exprs is None:
|
|
2333
|
-
return None
|
|
2334
|
-
return ASTParenExprList(exprs)
|
|
2335
|
-
|
|
2336
|
-
def _parse_braced_init_list(self) -> ASTBracedInitList | None:
|
|
2337
|
-
# -> '{' initializer-list ','[opt] '}'
|
|
2338
|
-
# | '{' '}'
|
|
2339
|
-
exprs, trailingComma = self._parse_initializer_list("braced-init-list", '{', '}')
|
|
2340
|
-
if exprs is None:
|
|
2341
|
-
return None
|
|
2342
|
-
return ASTBracedInitList(exprs, trailingComma)
|
|
2343
|
-
|
|
2344
|
-
def _parse_postfix_expression(self) -> ASTPostfixExpr:
|
|
2345
|
-
# -> primary
|
|
2346
|
-
# | postfix "[" expression "]"
|
|
2347
|
-
# | postfix "[" braced-init-list [opt] "]"
|
|
2348
|
-
# | postfix "(" expression-list [opt] ")"
|
|
2349
|
-
# | postfix "." id-expression // taken care of in primary by nested name
|
|
2350
|
-
# | postfix "->" id-expression
|
|
2351
|
-
# | postfix "++"
|
|
2352
|
-
# | postfix "--"
|
|
2353
|
-
|
|
2354
|
-
prefix = self._parse_primary_expression()
|
|
2355
|
-
|
|
2356
|
-
# and now parse postfixes
|
|
2357
|
-
postFixes: list[ASTPostfixOp] = []
|
|
2358
|
-
while True:
|
|
2359
|
-
self.skip_ws()
|
|
2360
|
-
if self.skip_string_and_ws('['):
|
|
2361
|
-
expr = self._parse_expression()
|
|
2362
|
-
self.skip_ws()
|
|
2363
|
-
if not self.skip_string(']'):
|
|
2364
|
-
self.fail("Expected ']' in end of postfix expression.")
|
|
2365
|
-
postFixes.append(ASTPostfixArray(expr))
|
|
2366
|
-
continue
|
|
2367
|
-
if self.skip_string('->'):
|
|
2368
|
-
if self.skip_string('*'):
|
|
2369
|
-
# don't steal the arrow
|
|
2370
|
-
self.pos -= 3
|
|
2371
|
-
else:
|
|
2372
|
-
name = self._parse_nested_name()
|
|
2373
|
-
postFixes.append(ASTPostfixMemberOfPointer(name))
|
|
2374
|
-
continue
|
|
2375
|
-
if self.skip_string('++'):
|
|
2376
|
-
postFixes.append(ASTPostfixInc())
|
|
2377
|
-
continue
|
|
2378
|
-
if self.skip_string('--'):
|
|
2379
|
-
postFixes.append(ASTPostfixDec())
|
|
2380
|
-
continue
|
|
2381
|
-
lst = self._parse_paren_expression_list()
|
|
2382
|
-
if lst is not None:
|
|
2383
|
-
postFixes.append(ASTPostfixCallExpr(lst))
|
|
2384
|
-
continue
|
|
2385
|
-
break
|
|
2386
|
-
return ASTPostfixExpr(prefix, postFixes)
|
|
2387
|
-
|
|
2388
|
-
def _parse_unary_expression(self) -> ASTExpression:
|
|
2389
|
-
# -> postfix
|
|
2390
|
-
# | "++" cast
|
|
2391
|
-
# | "--" cast
|
|
2392
|
-
# | unary-operator cast -> (* | & | + | - | ! | ~) cast
|
|
2393
|
-
# The rest:
|
|
2394
|
-
# | "sizeof" unary
|
|
2395
|
-
# | "sizeof" "(" type-id ")"
|
|
2396
|
-
# | "alignof" "(" type-id ")"
|
|
2397
|
-
self.skip_ws()
|
|
2398
|
-
for op in _expression_unary_ops:
|
|
2399
|
-
# TODO: hmm, should we be able to backtrack here?
|
|
2400
|
-
if op[0] in 'cn':
|
|
2401
|
-
res = self.skip_word(op)
|
|
2402
|
-
else:
|
|
2403
|
-
res = self.skip_string(op)
|
|
2404
|
-
if res:
|
|
2405
|
-
expr = self._parse_cast_expression()
|
|
2406
|
-
return ASTUnaryOpExpr(op, expr)
|
|
2407
|
-
if self.skip_word_and_ws('sizeof'):
|
|
2408
|
-
if self.skip_string_and_ws('('):
|
|
2409
|
-
typ = self._parse_type(named=False)
|
|
2410
|
-
self.skip_ws()
|
|
2411
|
-
if not self.skip_string(')'):
|
|
2412
|
-
self.fail("Expecting ')' to end 'sizeof'.")
|
|
2413
|
-
return ASTSizeofType(typ)
|
|
2414
|
-
expr = self._parse_unary_expression()
|
|
2415
|
-
return ASTSizeofExpr(expr)
|
|
2416
|
-
if self.skip_word_and_ws('alignof'):
|
|
2417
|
-
if not self.skip_string_and_ws('('):
|
|
2418
|
-
self.fail("Expecting '(' after 'alignof'.")
|
|
2419
|
-
typ = self._parse_type(named=False)
|
|
2420
|
-
self.skip_ws()
|
|
2421
|
-
if not self.skip_string(')'):
|
|
2422
|
-
self.fail("Expecting ')' to end 'alignof'.")
|
|
2423
|
-
return ASTAlignofExpr(typ)
|
|
2424
|
-
return self._parse_postfix_expression()
|
|
2425
|
-
|
|
2426
|
-
def _parse_cast_expression(self) -> ASTExpression:
|
|
2427
|
-
# -> unary | "(" type-id ")" cast
|
|
2428
|
-
pos = self.pos
|
|
2429
|
-
self.skip_ws()
|
|
2430
|
-
if self.skip_string('('):
|
|
2431
|
-
try:
|
|
2432
|
-
typ = self._parse_type(False)
|
|
2433
|
-
if not self.skip_string(')'):
|
|
2434
|
-
self.fail("Expected ')' in cast expression.")
|
|
2435
|
-
expr = self._parse_cast_expression()
|
|
2436
|
-
return ASTCastExpr(typ, expr)
|
|
2437
|
-
except DefinitionError as exCast:
|
|
2438
|
-
self.pos = pos
|
|
2439
|
-
try:
|
|
2440
|
-
return self._parse_unary_expression()
|
|
2441
|
-
except DefinitionError as exUnary:
|
|
2442
|
-
errs = []
|
|
2443
|
-
errs.append((exCast, "If type cast expression"))
|
|
2444
|
-
errs.append((exUnary, "If unary expression"))
|
|
2445
|
-
raise self._make_multi_error(errs,
|
|
2446
|
-
"Error in cast expression.") from exUnary
|
|
2447
|
-
else:
|
|
2448
|
-
return self._parse_unary_expression()
|
|
2449
|
-
|
|
2450
|
-
def _parse_logical_or_expression(self) -> ASTExpression:
|
|
2451
|
-
# logical-or = logical-and ||
|
|
2452
|
-
# logical-and = inclusive-or &&
|
|
2453
|
-
# inclusive-or = exclusive-or |
|
|
2454
|
-
# exclusive-or = and ^
|
|
2455
|
-
# and = equality &
|
|
2456
|
-
# equality = relational ==, !=
|
|
2457
|
-
# relational = shift <, >, <=, >=
|
|
2458
|
-
# shift = additive <<, >>
|
|
2459
|
-
# additive = multiplicative +, -
|
|
2460
|
-
# multiplicative = pm *, /, %
|
|
2461
|
-
# pm = cast .*, ->*
|
|
2462
|
-
def _parse_bin_op_expr(self, opId):
|
|
2463
|
-
if opId + 1 == len(_expression_bin_ops):
|
|
2464
|
-
def parser() -> ASTExpression:
|
|
2465
|
-
return self._parse_cast_expression()
|
|
2466
|
-
else:
|
|
2467
|
-
def parser() -> ASTExpression:
|
|
2468
|
-
return _parse_bin_op_expr(self, opId + 1)
|
|
2469
|
-
exprs = []
|
|
2470
|
-
ops = []
|
|
2471
|
-
exprs.append(parser())
|
|
2472
|
-
while True:
|
|
2473
|
-
self.skip_ws()
|
|
2474
|
-
pos = self.pos
|
|
2475
|
-
oneMore = False
|
|
2476
|
-
for op in _expression_bin_ops[opId]:
|
|
2477
|
-
if op[0] in 'abcnox':
|
|
2478
|
-
if not self.skip_word(op):
|
|
2479
|
-
continue
|
|
2480
|
-
else:
|
|
2481
|
-
if not self.skip_string(op):
|
|
2482
|
-
continue
|
|
2483
|
-
if op == '&' and self.current_char == '&':
|
|
2484
|
-
# don't split the && 'token'
|
|
2485
|
-
self.pos -= 1
|
|
2486
|
-
# and btw. && has lower precedence, so we are done
|
|
2487
|
-
break
|
|
2488
|
-
try:
|
|
2489
|
-
expr = parser()
|
|
2490
|
-
exprs.append(expr)
|
|
2491
|
-
ops.append(op)
|
|
2492
|
-
oneMore = True
|
|
2493
|
-
break
|
|
2494
|
-
except DefinitionError:
|
|
2495
|
-
self.pos = pos
|
|
2496
|
-
if not oneMore:
|
|
2497
|
-
break
|
|
2498
|
-
return ASTBinOpExpr(exprs, ops)
|
|
2499
|
-
return _parse_bin_op_expr(self, 0)
|
|
2500
|
-
|
|
2501
|
-
def _parse_conditional_expression_tail(self, orExprHead: Any) -> ASTExpression | None:
|
|
2502
|
-
# -> "?" expression ":" assignment-expression
|
|
2503
|
-
return None
|
|
2504
|
-
|
|
2505
|
-
def _parse_assignment_expression(self) -> ASTExpression:
|
|
2506
|
-
# -> conditional-expression
|
|
2507
|
-
# | logical-or-expression assignment-operator initializer-clause
|
|
2508
|
-
# -> conditional-expression ->
|
|
2509
|
-
# logical-or-expression
|
|
2510
|
-
# | logical-or-expression "?" expression ":" assignment-expression
|
|
2511
|
-
# | logical-or-expression assignment-operator initializer-clause
|
|
2512
|
-
exprs = []
|
|
2513
|
-
ops = []
|
|
2514
|
-
orExpr = self._parse_logical_or_expression()
|
|
2515
|
-
exprs.append(orExpr)
|
|
2516
|
-
# TODO: handle ternary with _parse_conditional_expression_tail
|
|
2517
|
-
while True:
|
|
2518
|
-
oneMore = False
|
|
2519
|
-
self.skip_ws()
|
|
2520
|
-
for op in _expression_assignment_ops:
|
|
2521
|
-
if op[0] in 'abcnox':
|
|
2522
|
-
if not self.skip_word(op):
|
|
2523
|
-
continue
|
|
2524
|
-
else:
|
|
2525
|
-
if not self.skip_string(op):
|
|
2526
|
-
continue
|
|
2527
|
-
expr = self._parse_logical_or_expression()
|
|
2528
|
-
exprs.append(expr)
|
|
2529
|
-
ops.append(op)
|
|
2530
|
-
oneMore = True
|
|
2531
|
-
if not oneMore:
|
|
2532
|
-
break
|
|
2533
|
-
return ASTAssignmentExpr(exprs, ops)
|
|
2534
|
-
|
|
2535
|
-
def _parse_constant_expression(self) -> ASTExpression:
|
|
2536
|
-
# -> conditional-expression
|
|
2537
|
-
orExpr = self._parse_logical_or_expression()
|
|
2538
|
-
# TODO: use _parse_conditional_expression_tail
|
|
2539
|
-
return orExpr
|
|
2540
|
-
|
|
2541
|
-
def _parse_expression(self) -> ASTExpression:
|
|
2542
|
-
# -> assignment-expression
|
|
2543
|
-
# | expression "," assignment-expression
|
|
2544
|
-
# TODO: actually parse the second production
|
|
2545
|
-
return self._parse_assignment_expression()
|
|
2546
|
-
|
|
2547
|
-
def _parse_expression_fallback(
|
|
2548
|
-
self, end: list[str],
|
|
2549
|
-
parser: Callable[[], ASTExpression],
|
|
2550
|
-
allow: bool = True) -> ASTExpression:
|
|
2551
|
-
# Stupidly "parse" an expression.
|
|
2552
|
-
# 'end' should be a list of characters which ends the expression.
|
|
2553
|
-
|
|
2554
|
-
# first try to use the provided parser
|
|
2555
|
-
prevPos = self.pos
|
|
2556
|
-
try:
|
|
2557
|
-
return parser()
|
|
2558
|
-
except DefinitionError as e:
|
|
2559
|
-
# some places (e.g., template parameters) we really don't want to use fallback,
|
|
2560
|
-
# and for testing we may want to globally disable it
|
|
2561
|
-
if not allow or not self.allowFallbackExpressionParsing:
|
|
2562
|
-
raise
|
|
2563
|
-
self.warn("Parsing of expression failed. Using fallback parser."
|
|
2564
|
-
" Error was:\n%s" % e)
|
|
2565
|
-
self.pos = prevPos
|
|
2566
|
-
# and then the fallback scanning
|
|
2567
|
-
assert end is not None
|
|
2568
|
-
self.skip_ws()
|
|
2569
|
-
startPos = self.pos
|
|
2570
|
-
if self.match(_string_re):
|
|
2571
|
-
value = self.matched_text
|
|
2572
|
-
else:
|
|
2573
|
-
# TODO: add handling of more bracket-like things, and quote handling
|
|
2574
|
-
brackets = {'(': ')', '{': '}', '[': ']'}
|
|
2575
|
-
symbols: list[str] = []
|
|
2576
|
-
while not self.eof:
|
|
2577
|
-
if (len(symbols) == 0 and self.current_char in end):
|
|
2578
|
-
break
|
|
2579
|
-
if self.current_char in brackets:
|
|
2580
|
-
symbols.append(brackets[self.current_char])
|
|
2581
|
-
elif len(symbols) > 0 and self.current_char == symbols[-1]:
|
|
2582
|
-
symbols.pop()
|
|
2583
|
-
self.pos += 1
|
|
2584
|
-
if len(end) > 0 and self.eof:
|
|
2585
|
-
self.fail("Could not find end of expression starting at %d."
|
|
2586
|
-
% startPos)
|
|
2587
|
-
value = self.definition[startPos:self.pos].strip()
|
|
2588
|
-
return ASTFallbackExpr(value.strip())
|
|
2589
|
-
|
|
2590
|
-
def _parse_nested_name(self) -> ASTNestedName:
|
|
2591
|
-
names: list[Any] = []
|
|
2592
|
-
|
|
2593
|
-
self.skip_ws()
|
|
2594
|
-
rooted = False
|
|
2595
|
-
if self.skip_string('.'):
|
|
2596
|
-
rooted = True
|
|
2597
|
-
while 1:
|
|
2598
|
-
self.skip_ws()
|
|
2599
|
-
if not self.match(identifier_re):
|
|
2600
|
-
self.fail("Expected identifier in nested name.")
|
|
2601
|
-
identifier = self.matched_text
|
|
2602
|
-
# make sure there isn't a keyword
|
|
2603
|
-
if identifier in _keywords:
|
|
2604
|
-
self.fail("Expected identifier in nested name, "
|
|
2605
|
-
"got keyword: %s" % identifier)
|
|
2606
|
-
if self.matched_text in self.config.c_extra_keywords:
|
|
2607
|
-
msg = "Expected identifier, got user-defined keyword: %s." \
|
|
2608
|
-
+ " Remove it from c_extra_keywords to allow it as identifier.\n" \
|
|
2609
|
-
+ "Currently c_extra_keywords is %s."
|
|
2610
|
-
self.fail(msg % (self.matched_text,
|
|
2611
|
-
str(self.config.c_extra_keywords)))
|
|
2612
|
-
ident = ASTIdentifier(identifier)
|
|
2613
|
-
names.append(ident)
|
|
2614
|
-
|
|
2615
|
-
self.skip_ws()
|
|
2616
|
-
if not self.skip_string('.'):
|
|
2617
|
-
break
|
|
2618
|
-
return ASTNestedName(names, rooted)
|
|
2619
|
-
|
|
2620
|
-
def _parse_simple_type_specifier(self) -> str | None:
|
|
2621
|
-
if self.match(_simple_type_specifiers_re):
|
|
2622
|
-
return self.matched_text
|
|
2623
|
-
for t in ('bool', 'complex', 'imaginary'):
|
|
2624
|
-
if t in self.config.c_extra_keywords:
|
|
2625
|
-
if self.skip_word(t):
|
|
2626
|
-
return t
|
|
2627
|
-
return None
|
|
2628
|
-
|
|
2629
|
-
def _parse_simple_type_specifiers(self) -> ASTTrailingTypeSpecFundamental | None:
|
|
2630
|
-
names: list[str] = []
|
|
2631
|
-
|
|
2632
|
-
self.skip_ws()
|
|
2633
|
-
while True:
|
|
2634
|
-
t = self._parse_simple_type_specifier()
|
|
2635
|
-
if t is None:
|
|
2636
|
-
break
|
|
2637
|
-
names.append(t)
|
|
2638
|
-
self.skip_ws()
|
|
2639
|
-
if len(names) == 0:
|
|
2640
|
-
return None
|
|
2641
|
-
return ASTTrailingTypeSpecFundamental(names)
|
|
2642
|
-
|
|
2643
|
-
def _parse_trailing_type_spec(self) -> ASTTrailingTypeSpec:
|
|
2644
|
-
# fundamental types, https://en.cppreference.com/w/c/language/type
|
|
2645
|
-
# and extensions
|
|
2646
|
-
self.skip_ws()
|
|
2647
|
-
res = self._parse_simple_type_specifiers()
|
|
2648
|
-
if res is not None:
|
|
2649
|
-
return res
|
|
2650
|
-
|
|
2651
|
-
# prefixed
|
|
2652
|
-
prefix = None
|
|
2653
|
-
self.skip_ws()
|
|
2654
|
-
for k in ('struct', 'enum', 'union'):
|
|
2655
|
-
if self.skip_word_and_ws(k):
|
|
2656
|
-
prefix = k
|
|
2657
|
-
break
|
|
2658
|
-
|
|
2659
|
-
nestedName = self._parse_nested_name()
|
|
2660
|
-
return ASTTrailingTypeSpecName(prefix, nestedName)
|
|
2661
|
-
|
|
2662
|
-
def _parse_parameters(self, paramMode: str) -> ASTParameters | None:
|
|
2663
|
-
self.skip_ws()
|
|
2664
|
-
if not self.skip_string('('):
|
|
2665
|
-
if paramMode == 'function':
|
|
2666
|
-
self.fail('Expecting "(" in parameters.')
|
|
2667
|
-
else:
|
|
2668
|
-
return None
|
|
2669
|
-
|
|
2670
|
-
args = []
|
|
2671
|
-
self.skip_ws()
|
|
2672
|
-
if not self.skip_string(')'):
|
|
2673
|
-
while 1:
|
|
2674
|
-
self.skip_ws()
|
|
2675
|
-
if self.skip_string('...'):
|
|
2676
|
-
args.append(ASTFunctionParameter(None, True))
|
|
2677
|
-
self.skip_ws()
|
|
2678
|
-
if not self.skip_string(')'):
|
|
2679
|
-
self.fail('Expected ")" after "..." in parameters.')
|
|
2680
|
-
break
|
|
2681
|
-
# note: it seems that function arguments can always be named,
|
|
2682
|
-
# even in function pointers and similar.
|
|
2683
|
-
arg = self._parse_type_with_init(outer=None, named='single')
|
|
2684
|
-
# TODO: parse default parameters # TODO: didn't we just do that?
|
|
2685
|
-
args.append(ASTFunctionParameter(arg))
|
|
2686
|
-
|
|
2687
|
-
self.skip_ws()
|
|
2688
|
-
if self.skip_string(','):
|
|
2689
|
-
continue
|
|
2690
|
-
if self.skip_string(')'):
|
|
2691
|
-
break
|
|
2692
|
-
self.fail(f'Expecting "," or ")" in parameters, got "{self.current_char}".')
|
|
2693
|
-
|
|
2694
|
-
attrs = self._parse_attribute_list()
|
|
2695
|
-
return ASTParameters(args, attrs)
|
|
2696
|
-
|
|
2697
|
-
def _parse_decl_specs_simple(
|
|
2698
|
-
self, outer: str | None, typed: bool,
|
|
2699
|
-
) -> ASTDeclSpecsSimple:
|
|
2700
|
-
"""Just parse the simple ones."""
|
|
2701
|
-
storage = None
|
|
2702
|
-
threadLocal = None
|
|
2703
|
-
inline = None
|
|
2704
|
-
restrict = None
|
|
2705
|
-
volatile = None
|
|
2706
|
-
const = None
|
|
2707
|
-
attrs = []
|
|
2708
|
-
while 1: # accept any permutation of a subset of some decl-specs
|
|
2709
|
-
self.skip_ws()
|
|
2710
|
-
if not storage:
|
|
2711
|
-
if outer == 'member':
|
|
2712
|
-
if self.skip_word('auto'):
|
|
2713
|
-
storage = 'auto'
|
|
2714
|
-
continue
|
|
2715
|
-
if self.skip_word('register'):
|
|
2716
|
-
storage = 'register'
|
|
2717
|
-
continue
|
|
2718
|
-
if outer in ('member', 'function'):
|
|
2719
|
-
if self.skip_word('static'):
|
|
2720
|
-
storage = 'static'
|
|
2721
|
-
continue
|
|
2722
|
-
if self.skip_word('extern'):
|
|
2723
|
-
storage = 'extern'
|
|
2724
|
-
continue
|
|
2725
|
-
if outer == 'member' and not threadLocal:
|
|
2726
|
-
if self.skip_word('thread_local'):
|
|
2727
|
-
threadLocal = 'thread_local'
|
|
2728
|
-
continue
|
|
2729
|
-
if self.skip_word('_Thread_local'):
|
|
2730
|
-
threadLocal = '_Thread_local'
|
|
2731
|
-
continue
|
|
2732
|
-
if outer == 'function' and not inline:
|
|
2733
|
-
inline = self.skip_word('inline')
|
|
2734
|
-
if inline:
|
|
2735
|
-
continue
|
|
2736
|
-
|
|
2737
|
-
if not restrict and typed:
|
|
2738
|
-
restrict = self.skip_word('restrict')
|
|
2739
|
-
if restrict:
|
|
2740
|
-
continue
|
|
2741
|
-
if not volatile and typed:
|
|
2742
|
-
volatile = self.skip_word('volatile')
|
|
2743
|
-
if volatile:
|
|
2744
|
-
continue
|
|
2745
|
-
if not const and typed:
|
|
2746
|
-
const = self.skip_word('const')
|
|
2747
|
-
if const:
|
|
2748
|
-
continue
|
|
2749
|
-
attr = self._parse_attribute()
|
|
2750
|
-
if attr:
|
|
2751
|
-
attrs.append(attr)
|
|
2752
|
-
continue
|
|
2753
|
-
break
|
|
2754
|
-
return ASTDeclSpecsSimple(storage, threadLocal, inline,
|
|
2755
|
-
restrict, volatile, const, ASTAttributeList(attrs))
|
|
2756
|
-
|
|
2757
|
-
def _parse_decl_specs(self, outer: str | None, typed: bool = True) -> ASTDeclSpecs:
|
|
2758
|
-
if outer:
|
|
2759
|
-
if outer not in ('type', 'member', 'function'):
|
|
2760
|
-
raise Exception('Internal error, unknown outer "%s".' % outer)
|
|
2761
|
-
leftSpecs = self._parse_decl_specs_simple(outer, typed)
|
|
2762
|
-
rightSpecs = None
|
|
2763
|
-
|
|
2764
|
-
if typed:
|
|
2765
|
-
trailing = self._parse_trailing_type_spec()
|
|
2766
|
-
rightSpecs = self._parse_decl_specs_simple(outer, typed)
|
|
2767
|
-
else:
|
|
2768
|
-
trailing = None
|
|
2769
|
-
return ASTDeclSpecs(outer, leftSpecs, rightSpecs, trailing)
|
|
2770
|
-
|
|
2771
|
-
def _parse_declarator_name_suffix(
|
|
2772
|
-
self, named: bool | str, paramMode: str, typed: bool,
|
|
2773
|
-
) -> ASTDeclarator:
|
|
2774
|
-
assert named in (True, False, 'single')
|
|
2775
|
-
# now we should parse the name, and then suffixes
|
|
2776
|
-
if named == 'single':
|
|
2777
|
-
if self.match(identifier_re):
|
|
2778
|
-
if self.matched_text in _keywords:
|
|
2779
|
-
self.fail("Expected identifier, "
|
|
2780
|
-
"got keyword: %s" % self.matched_text)
|
|
2781
|
-
if self.matched_text in self.config.c_extra_keywords:
|
|
2782
|
-
msg = "Expected identifier, got user-defined keyword: %s." \
|
|
2783
|
-
+ " Remove it from c_extra_keywords to allow it as identifier.\n" \
|
|
2784
|
-
+ "Currently c_extra_keywords is %s."
|
|
2785
|
-
self.fail(msg % (self.matched_text,
|
|
2786
|
-
str(self.config.c_extra_keywords)))
|
|
2787
|
-
identifier = ASTIdentifier(self.matched_text)
|
|
2788
|
-
declId = ASTNestedName([identifier], rooted=False)
|
|
2789
|
-
else:
|
|
2790
|
-
declId = None
|
|
2791
|
-
elif named:
|
|
2792
|
-
declId = self._parse_nested_name()
|
|
2793
|
-
else:
|
|
2794
|
-
declId = None
|
|
2795
|
-
arrayOps = []
|
|
2796
|
-
while 1:
|
|
2797
|
-
self.skip_ws()
|
|
2798
|
-
if typed and self.skip_string('['):
|
|
2799
|
-
self.skip_ws()
|
|
2800
|
-
static = False
|
|
2801
|
-
const = False
|
|
2802
|
-
volatile = False
|
|
2803
|
-
restrict = False
|
|
2804
|
-
while True:
|
|
2805
|
-
if not static:
|
|
2806
|
-
if self.skip_word_and_ws('static'):
|
|
2807
|
-
static = True
|
|
2808
|
-
continue
|
|
2809
|
-
if not const:
|
|
2810
|
-
if self.skip_word_and_ws('const'):
|
|
2811
|
-
const = True
|
|
2812
|
-
continue
|
|
2813
|
-
if not volatile:
|
|
2814
|
-
if self.skip_word_and_ws('volatile'):
|
|
2815
|
-
volatile = True
|
|
2816
|
-
continue
|
|
2817
|
-
if not restrict:
|
|
2818
|
-
if self.skip_word_and_ws('restrict'):
|
|
2819
|
-
restrict = True
|
|
2820
|
-
continue
|
|
2821
|
-
break
|
|
2822
|
-
vla = False if static else self.skip_string_and_ws('*')
|
|
2823
|
-
if vla:
|
|
2824
|
-
if not self.skip_string(']'):
|
|
2825
|
-
self.fail("Expected ']' in end of array operator.")
|
|
2826
|
-
size = None
|
|
2827
|
-
else:
|
|
2828
|
-
if self.skip_string(']'):
|
|
2829
|
-
size = None
|
|
2830
|
-
else:
|
|
2831
|
-
|
|
2832
|
-
def parser():
|
|
2833
|
-
return self._parse_expression()
|
|
2834
|
-
size = self._parse_expression_fallback([']'], parser)
|
|
2835
|
-
self.skip_ws()
|
|
2836
|
-
if not self.skip_string(']'):
|
|
2837
|
-
self.fail("Expected ']' in end of array operator.")
|
|
2838
|
-
arrayOps.append(ASTArray(static, const, volatile, restrict, vla, size))
|
|
2839
|
-
else:
|
|
2840
|
-
break
|
|
2841
|
-
param = self._parse_parameters(paramMode)
|
|
2842
|
-
if param is None and len(arrayOps) == 0:
|
|
2843
|
-
# perhaps a bit-field
|
|
2844
|
-
if named and paramMode == 'type' and typed:
|
|
2845
|
-
self.skip_ws()
|
|
2846
|
-
if self.skip_string(':'):
|
|
2847
|
-
size = self._parse_constant_expression()
|
|
2848
|
-
return ASTDeclaratorNameBitField(declId=declId, size=size)
|
|
2849
|
-
return ASTDeclaratorNameParam(declId=declId, arrayOps=arrayOps,
|
|
2850
|
-
param=param)
|
|
2851
|
-
|
|
2852
|
-
def _parse_declarator(self, named: bool | str, paramMode: str,
|
|
2853
|
-
typed: bool = True) -> ASTDeclarator:
|
|
2854
|
-
# 'typed' here means 'parse return type stuff'
|
|
2855
|
-
if paramMode not in ('type', 'function'):
|
|
2856
|
-
raise Exception(
|
|
2857
|
-
"Internal error, unknown paramMode '%s'." % paramMode)
|
|
2858
|
-
prevErrors = []
|
|
2859
|
-
self.skip_ws()
|
|
2860
|
-
if typed and self.skip_string('*'):
|
|
2861
|
-
self.skip_ws()
|
|
2862
|
-
restrict = False
|
|
2863
|
-
volatile = False
|
|
2864
|
-
const = False
|
|
2865
|
-
attrs = []
|
|
2866
|
-
while 1:
|
|
2867
|
-
if not restrict:
|
|
2868
|
-
restrict = self.skip_word_and_ws('restrict')
|
|
2869
|
-
if restrict:
|
|
2870
|
-
continue
|
|
2871
|
-
if not volatile:
|
|
2872
|
-
volatile = self.skip_word_and_ws('volatile')
|
|
2873
|
-
if volatile:
|
|
2874
|
-
continue
|
|
2875
|
-
if not const:
|
|
2876
|
-
const = self.skip_word_and_ws('const')
|
|
2877
|
-
if const:
|
|
2878
|
-
continue
|
|
2879
|
-
attr = self._parse_attribute()
|
|
2880
|
-
if attr is not None:
|
|
2881
|
-
attrs.append(attr)
|
|
2882
|
-
continue
|
|
2883
|
-
break
|
|
2884
|
-
next = self._parse_declarator(named, paramMode, typed)
|
|
2885
|
-
return ASTDeclaratorPtr(next=next,
|
|
2886
|
-
restrict=restrict, volatile=volatile, const=const,
|
|
2887
|
-
attrs=ASTAttributeList(attrs))
|
|
2888
|
-
if typed and self.current_char == '(': # note: peeking, not skipping
|
|
2889
|
-
# maybe this is the beginning of params, try that first,
|
|
2890
|
-
# otherwise assume it's noptr->declarator > ( ptr-declarator )
|
|
2891
|
-
pos = self.pos
|
|
2892
|
-
try:
|
|
2893
|
-
# assume this is params
|
|
2894
|
-
res = self._parse_declarator_name_suffix(named, paramMode,
|
|
2895
|
-
typed)
|
|
2896
|
-
return res
|
|
2897
|
-
except DefinitionError as exParamQual:
|
|
2898
|
-
msg = "If declarator-id with parameters"
|
|
2899
|
-
if paramMode == 'function':
|
|
2900
|
-
msg += " (e.g., 'void f(int arg)')"
|
|
2901
|
-
prevErrors.append((exParamQual, msg))
|
|
2902
|
-
self.pos = pos
|
|
2903
|
-
try:
|
|
2904
|
-
assert self.current_char == '('
|
|
2905
|
-
self.skip_string('(')
|
|
2906
|
-
# TODO: hmm, if there is a name, it must be in inner, right?
|
|
2907
|
-
# TODO: hmm, if there must be parameters, they must b
|
|
2908
|
-
# inside, right?
|
|
2909
|
-
inner = self._parse_declarator(named, paramMode, typed)
|
|
2910
|
-
if not self.skip_string(')'):
|
|
2911
|
-
self.fail("Expected ')' in \"( ptr-declarator )\"")
|
|
2912
|
-
next = self._parse_declarator(named=False,
|
|
2913
|
-
paramMode="type",
|
|
2914
|
-
typed=typed)
|
|
2915
|
-
return ASTDeclaratorParen(inner=inner, next=next)
|
|
2916
|
-
except DefinitionError as exNoPtrParen:
|
|
2917
|
-
self.pos = pos
|
|
2918
|
-
msg = "If parenthesis in noptr-declarator"
|
|
2919
|
-
if paramMode == 'function':
|
|
2920
|
-
msg += " (e.g., 'void (*f(int arg))(double)')"
|
|
2921
|
-
prevErrors.append((exNoPtrParen, msg))
|
|
2922
|
-
header = "Error in declarator"
|
|
2923
|
-
raise self._make_multi_error(prevErrors, header) from exNoPtrParen
|
|
2924
|
-
pos = self.pos
|
|
2925
|
-
try:
|
|
2926
|
-
return self._parse_declarator_name_suffix(named, paramMode, typed)
|
|
2927
|
-
except DefinitionError as e:
|
|
2928
|
-
self.pos = pos
|
|
2929
|
-
prevErrors.append((e, "If declarator-id"))
|
|
2930
|
-
header = "Error in declarator or parameters"
|
|
2931
|
-
raise self._make_multi_error(prevErrors, header) from e
|
|
2932
|
-
|
|
2933
|
-
def _parse_initializer(self, outer: str | None = None, allowFallback: bool = True,
|
|
2934
|
-
) -> ASTInitializer | None:
|
|
2935
|
-
self.skip_ws()
|
|
2936
|
-
if outer == 'member' and False: # NoQA: SIM223 # TODO
|
|
2937
|
-
bracedInit = self._parse_braced_init_list()
|
|
2938
|
-
if bracedInit is not None:
|
|
2939
|
-
return ASTInitializer(bracedInit, hasAssign=False)
|
|
2940
|
-
|
|
2941
|
-
if not self.skip_string('='):
|
|
2942
|
-
return None
|
|
2943
|
-
|
|
2944
|
-
bracedInit = self._parse_braced_init_list()
|
|
2945
|
-
if bracedInit is not None:
|
|
2946
|
-
return ASTInitializer(bracedInit)
|
|
2947
|
-
|
|
2948
|
-
if outer == 'member':
|
|
2949
|
-
fallbackEnd: list[str] = []
|
|
2950
|
-
elif outer is None: # function parameter
|
|
2951
|
-
fallbackEnd = [',', ')']
|
|
2952
|
-
else:
|
|
2953
|
-
self.fail("Internal error, initializer for outer '%s' not "
|
|
2954
|
-
"implemented." % outer)
|
|
2955
|
-
|
|
2956
|
-
def parser():
|
|
2957
|
-
return self._parse_assignment_expression()
|
|
2958
|
-
|
|
2959
|
-
value = self._parse_expression_fallback(fallbackEnd, parser, allow=allowFallback)
|
|
2960
|
-
return ASTInitializer(value)
|
|
2961
|
-
|
|
2962
|
-
def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType:
|
|
2963
|
-
"""
|
|
2964
|
-
named=False|'single'|True: 'single' is e.g., for function objects which
|
|
2965
|
-
doesn't need to name the arguments, but otherwise is a single name
|
|
2966
|
-
"""
|
|
2967
|
-
if outer: # always named
|
|
2968
|
-
if outer not in ('type', 'member', 'function'):
|
|
2969
|
-
raise Exception('Internal error, unknown outer "%s".' % outer)
|
|
2970
|
-
assert named
|
|
2971
|
-
|
|
2972
|
-
if outer == 'type':
|
|
2973
|
-
# We allow type objects to just be a name.
|
|
2974
|
-
prevErrors = []
|
|
2975
|
-
startPos = self.pos
|
|
2976
|
-
# first try without the type
|
|
2977
|
-
try:
|
|
2978
|
-
declSpecs = self._parse_decl_specs(outer=outer, typed=False)
|
|
2979
|
-
decl = self._parse_declarator(named=True, paramMode=outer,
|
|
2980
|
-
typed=False)
|
|
2981
|
-
self.assert_end(allowSemicolon=True)
|
|
2982
|
-
except DefinitionError as exUntyped:
|
|
2983
|
-
desc = "If just a name"
|
|
2984
|
-
prevErrors.append((exUntyped, desc))
|
|
2985
|
-
self.pos = startPos
|
|
2986
|
-
try:
|
|
2987
|
-
declSpecs = self._parse_decl_specs(outer=outer)
|
|
2988
|
-
decl = self._parse_declarator(named=True, paramMode=outer)
|
|
2989
|
-
except DefinitionError as exTyped:
|
|
2990
|
-
self.pos = startPos
|
|
2991
|
-
desc = "If typedef-like declaration"
|
|
2992
|
-
prevErrors.append((exTyped, desc))
|
|
2993
|
-
# Retain the else branch for easier debugging.
|
|
2994
|
-
# TODO: it would be nice to save the previous stacktrace
|
|
2995
|
-
# and output it here.
|
|
2996
|
-
if True:
|
|
2997
|
-
header = "Type must be either just a name or a "
|
|
2998
|
-
header += "typedef-like declaration."
|
|
2999
|
-
raise self._make_multi_error(prevErrors, header) from exTyped
|
|
3000
|
-
else: # NoQA: RET506
|
|
3001
|
-
# For testing purposes.
|
|
3002
|
-
# do it again to get the proper traceback (how do you
|
|
3003
|
-
# reliably save a traceback when an exception is
|
|
3004
|
-
# constructed?)
|
|
3005
|
-
self.pos = startPos
|
|
3006
|
-
typed = True
|
|
3007
|
-
declSpecs = self._parse_decl_specs(outer=outer, typed=typed)
|
|
3008
|
-
decl = self._parse_declarator(named=True, paramMode=outer,
|
|
3009
|
-
typed=typed)
|
|
3010
|
-
elif outer == 'function':
|
|
3011
|
-
declSpecs = self._parse_decl_specs(outer=outer)
|
|
3012
|
-
decl = self._parse_declarator(named=True, paramMode=outer)
|
|
3013
|
-
else:
|
|
3014
|
-
paramMode = 'type'
|
|
3015
|
-
if outer == 'member': # i.e., member
|
|
3016
|
-
named = True
|
|
3017
|
-
declSpecs = self._parse_decl_specs(outer=outer)
|
|
3018
|
-
decl = self._parse_declarator(named=named, paramMode=paramMode)
|
|
3019
|
-
return ASTType(declSpecs, decl)
|
|
3020
|
-
|
|
3021
|
-
def _parse_type_with_init(self, named: bool | str, outer: str | None) -> ASTTypeWithInit:
|
|
3022
|
-
if outer:
|
|
3023
|
-
assert outer in ('type', 'member', 'function')
|
|
3024
|
-
type = self._parse_type(outer=outer, named=named)
|
|
3025
|
-
init = self._parse_initializer(outer=outer)
|
|
3026
|
-
return ASTTypeWithInit(type, init)
|
|
3027
|
-
|
|
3028
|
-
def _parse_macro(self) -> ASTMacro:
|
|
3029
|
-
self.skip_ws()
|
|
3030
|
-
ident = self._parse_nested_name()
|
|
3031
|
-
if ident is None:
|
|
3032
|
-
self.fail("Expected identifier in macro definition.")
|
|
3033
|
-
self.skip_ws()
|
|
3034
|
-
if not self.skip_string_and_ws('('):
|
|
3035
|
-
return ASTMacro(ident, None)
|
|
3036
|
-
if self.skip_string(')'):
|
|
3037
|
-
return ASTMacro(ident, [])
|
|
3038
|
-
args = []
|
|
3039
|
-
while 1:
|
|
3040
|
-
self.skip_ws()
|
|
3041
|
-
if self.skip_string('...'):
|
|
3042
|
-
args.append(ASTMacroParameter(None, True))
|
|
3043
|
-
self.skip_ws()
|
|
3044
|
-
if not self.skip_string(')'):
|
|
3045
|
-
self.fail('Expected ")" after "..." in macro parameters.')
|
|
3046
|
-
break
|
|
3047
|
-
if not self.match(identifier_re):
|
|
3048
|
-
self.fail("Expected identifier in macro parameters.")
|
|
3049
|
-
nn = ASTNestedName([ASTIdentifier(self.matched_text)], rooted=False)
|
|
3050
|
-
# Allow named variadic args:
|
|
3051
|
-
# https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
|
|
3052
|
-
self.skip_ws()
|
|
3053
|
-
if self.skip_string_and_ws('...'):
|
|
3054
|
-
args.append(ASTMacroParameter(nn, False, True))
|
|
3055
|
-
self.skip_ws()
|
|
3056
|
-
if not self.skip_string(')'):
|
|
3057
|
-
self.fail('Expected ")" after "..." in macro parameters.')
|
|
3058
|
-
break
|
|
3059
|
-
args.append(ASTMacroParameter(nn))
|
|
3060
|
-
if self.skip_string_and_ws(','):
|
|
3061
|
-
continue
|
|
3062
|
-
if self.skip_string_and_ws(')'):
|
|
3063
|
-
break
|
|
3064
|
-
self.fail("Expected identifier, ')', or ',' in macro parameter list.")
|
|
3065
|
-
return ASTMacro(ident, args)
|
|
3066
|
-
|
|
3067
|
-
def _parse_struct(self) -> ASTStruct:
|
|
3068
|
-
name = self._parse_nested_name()
|
|
3069
|
-
return ASTStruct(name)
|
|
3070
|
-
|
|
3071
|
-
def _parse_union(self) -> ASTUnion:
|
|
3072
|
-
name = self._parse_nested_name()
|
|
3073
|
-
return ASTUnion(name)
|
|
3074
|
-
|
|
3075
|
-
def _parse_enum(self) -> ASTEnum:
|
|
3076
|
-
name = self._parse_nested_name()
|
|
3077
|
-
return ASTEnum(name)
|
|
3078
|
-
|
|
3079
|
-
def _parse_enumerator(self) -> ASTEnumerator:
|
|
3080
|
-
name = self._parse_nested_name()
|
|
3081
|
-
attrs = self._parse_attribute_list()
|
|
3082
|
-
self.skip_ws()
|
|
3083
|
-
init = None
|
|
3084
|
-
if self.skip_string('='):
|
|
3085
|
-
self.skip_ws()
|
|
3086
|
-
|
|
3087
|
-
def parser() -> ASTExpression:
|
|
3088
|
-
return self._parse_constant_expression()
|
|
3089
|
-
|
|
3090
|
-
initVal = self._parse_expression_fallback([], parser)
|
|
3091
|
-
init = ASTInitializer(initVal)
|
|
3092
|
-
return ASTEnumerator(name, init, attrs)
|
|
3093
|
-
|
|
3094
|
-
def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclaration:
|
|
3095
|
-
if objectType not in ('function', 'member',
|
|
3096
|
-
'macro', 'struct', 'union', 'enum', 'enumerator', 'type'):
|
|
3097
|
-
raise Exception('Internal error, unknown objectType "%s".' % objectType)
|
|
3098
|
-
if directiveType not in ('function', 'member', 'var',
|
|
3099
|
-
'macro', 'struct', 'union', 'enum', 'enumerator', 'type'):
|
|
3100
|
-
raise Exception('Internal error, unknown directiveType "%s".' % directiveType)
|
|
3101
|
-
|
|
3102
|
-
declaration: DeclarationType = None
|
|
3103
|
-
if objectType == 'member':
|
|
3104
|
-
declaration = self._parse_type_with_init(named=True, outer='member')
|
|
3105
|
-
elif objectType == 'function':
|
|
3106
|
-
declaration = self._parse_type(named=True, outer='function')
|
|
3107
|
-
elif objectType == 'macro':
|
|
3108
|
-
declaration = self._parse_macro()
|
|
3109
|
-
elif objectType == 'struct':
|
|
3110
|
-
declaration = self._parse_struct()
|
|
3111
|
-
elif objectType == 'union':
|
|
3112
|
-
declaration = self._parse_union()
|
|
3113
|
-
elif objectType == 'enum':
|
|
3114
|
-
declaration = self._parse_enum()
|
|
3115
|
-
elif objectType == 'enumerator':
|
|
3116
|
-
declaration = self._parse_enumerator()
|
|
3117
|
-
elif objectType == 'type':
|
|
3118
|
-
declaration = self._parse_type(named=True, outer='type')
|
|
3119
|
-
else:
|
|
3120
|
-
raise AssertionError
|
|
3121
|
-
if objectType != 'macro':
|
|
3122
|
-
self.skip_ws()
|
|
3123
|
-
semicolon = self.skip_string(';')
|
|
3124
|
-
else:
|
|
3125
|
-
semicolon = False
|
|
3126
|
-
return ASTDeclaration(objectType, directiveType, declaration, semicolon)
|
|
3127
|
-
|
|
3128
|
-
def parse_namespace_object(self) -> ASTNestedName:
|
|
3129
|
-
return self._parse_nested_name()
|
|
3130
|
-
|
|
3131
|
-
def parse_xref_object(self) -> ASTNestedName:
|
|
3132
|
-
name = self._parse_nested_name()
|
|
3133
|
-
# if there are '()' left, just skip them
|
|
3134
|
-
self.skip_ws()
|
|
3135
|
-
self.skip_string('()')
|
|
3136
|
-
self.assert_end()
|
|
3137
|
-
return name
|
|
3138
|
-
|
|
3139
|
-
def parse_expression(self) -> ASTExpression | ASTType:
|
|
3140
|
-
pos = self.pos
|
|
3141
|
-
res: ASTExpression | ASTType = None
|
|
3142
|
-
try:
|
|
3143
|
-
res = self._parse_expression()
|
|
3144
|
-
self.skip_ws()
|
|
3145
|
-
self.assert_end()
|
|
3146
|
-
except DefinitionError as exExpr:
|
|
3147
|
-
self.pos = pos
|
|
3148
|
-
try:
|
|
3149
|
-
res = self._parse_type(False)
|
|
3150
|
-
self.skip_ws()
|
|
3151
|
-
self.assert_end()
|
|
3152
|
-
except DefinitionError as exType:
|
|
3153
|
-
header = "Error when parsing (type) expression."
|
|
3154
|
-
errs = []
|
|
3155
|
-
errs.append((exExpr, "If expression"))
|
|
3156
|
-
errs.append((exType, "If type"))
|
|
3157
|
-
raise self._make_multi_error(errs, header) from exType
|
|
3158
|
-
return res
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
def _make_phony_error_name() -> ASTNestedName:
|
|
3162
|
-
return ASTNestedName([ASTIdentifier("PhonyNameDueToError")], rooted=False)
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
class CObject(ObjectDescription[ASTDeclaration]):
|
|
3166
|
-
"""
|
|
3167
|
-
Description of a C language object.
|
|
3168
|
-
"""
|
|
3169
|
-
|
|
3170
|
-
option_spec: OptionSpec = {
|
|
3171
|
-
'no-index-entry': directives.flag,
|
|
3172
|
-
'no-contents-entry': directives.flag,
|
|
3173
|
-
'no-typesetting': directives.flag,
|
|
3174
|
-
'noindexentry': directives.flag,
|
|
3175
|
-
'nocontentsentry': directives.flag,
|
|
3176
|
-
'single-line-parameter-list': directives.flag,
|
|
3177
|
-
}
|
|
3178
|
-
|
|
3179
|
-
def _add_enumerator_to_parent(self, ast: ASTDeclaration) -> None:
|
|
3180
|
-
assert ast.objectType == 'enumerator'
|
|
3181
|
-
# find the parent, if it exists && is an enum
|
|
3182
|
-
# then add the name to the parent scope
|
|
3183
|
-
symbol = ast.symbol
|
|
3184
|
-
assert symbol
|
|
3185
|
-
assert symbol.ident is not None
|
|
3186
|
-
parentSymbol = symbol.parent
|
|
3187
|
-
assert parentSymbol
|
|
3188
|
-
if parentSymbol.parent is None:
|
|
3189
|
-
# TODO: we could warn, but it is somewhat equivalent to
|
|
3190
|
-
# enumeratorss, without the enum
|
|
3191
|
-
return # no parent
|
|
3192
|
-
parentDecl = parentSymbol.declaration
|
|
3193
|
-
if parentDecl is None:
|
|
3194
|
-
# the parent is not explicitly declared
|
|
3195
|
-
# TODO: we could warn, but?
|
|
3196
|
-
return
|
|
3197
|
-
if parentDecl.objectType != 'enum':
|
|
3198
|
-
# TODO: maybe issue a warning, enumerators in non-enums is weird,
|
|
3199
|
-
# but it is somewhat equivalent to enumeratorss, without the enum
|
|
3200
|
-
return
|
|
3201
|
-
if parentDecl.directiveType != 'enum':
|
|
3202
|
-
return
|
|
3203
|
-
|
|
3204
|
-
targetSymbol = parentSymbol.parent
|
|
3205
|
-
s = targetSymbol.find_identifier(symbol.ident, matchSelf=False, recurseInAnon=True,
|
|
3206
|
-
searchInSiblings=False)
|
|
3207
|
-
if s is not None:
|
|
3208
|
-
# something is already declared with that name
|
|
3209
|
-
return
|
|
3210
|
-
declClone = symbol.declaration.clone()
|
|
3211
|
-
declClone.enumeratorScopedSymbol = symbol
|
|
3212
|
-
Symbol(parent=targetSymbol, ident=symbol.ident,
|
|
3213
|
-
declaration=declClone,
|
|
3214
|
-
docname=self.env.docname, line=self.get_source_info()[1])
|
|
3215
|
-
|
|
3216
|
-
def add_target_and_index(self, ast: ASTDeclaration, sig: str,
|
|
3217
|
-
signode: TextElement) -> None:
|
|
3218
|
-
ids = []
|
|
3219
|
-
for i in range(1, _max_id + 1):
|
|
3220
|
-
try:
|
|
3221
|
-
id = ast.get_id(version=i)
|
|
3222
|
-
ids.append(id)
|
|
3223
|
-
except NoOldIdError:
|
|
3224
|
-
assert i < _max_id
|
|
3225
|
-
# let's keep the newest first
|
|
3226
|
-
ids = list(reversed(ids))
|
|
3227
|
-
newestId = ids[0]
|
|
3228
|
-
assert newestId # shouldn't be None
|
|
3229
|
-
|
|
3230
|
-
name = ast.symbol.get_full_nested_name().get_display_string().lstrip('.')
|
|
3231
|
-
if newestId not in self.state.document.ids:
|
|
3232
|
-
# always add the newest id
|
|
3233
|
-
assert newestId
|
|
3234
|
-
signode['ids'].append(newestId)
|
|
3235
|
-
# only add compatibility ids when there are no conflicts
|
|
3236
|
-
for id in ids[1:]:
|
|
3237
|
-
if not id: # is None when the element didn't exist in that version
|
|
3238
|
-
continue
|
|
3239
|
-
if id not in self.state.document.ids:
|
|
3240
|
-
signode['ids'].append(id)
|
|
3241
|
-
|
|
3242
|
-
self.state.document.note_explicit_target(signode)
|
|
3243
|
-
|
|
3244
|
-
if 'no-index-entry' not in self.options:
|
|
3245
|
-
indexText = self.get_index_text(name)
|
|
3246
|
-
self.indexnode['entries'].append(('single', indexText, newestId, '', None))
|
|
3247
|
-
|
|
3248
|
-
@property
|
|
3249
|
-
def object_type(self) -> str:
|
|
3250
|
-
raise NotImplementedError
|
|
3251
|
-
|
|
3252
|
-
@property
|
|
3253
|
-
def display_object_type(self) -> str:
|
|
3254
|
-
return self.object_type
|
|
3255
|
-
|
|
3256
|
-
def get_index_text(self, name: str) -> str:
|
|
3257
|
-
return _('%s (C %s)') % (name, self.display_object_type)
|
|
3258
|
-
|
|
3259
|
-
def parse_definition(self, parser: DefinitionParser) -> ASTDeclaration:
|
|
3260
|
-
return parser.parse_declaration(self.object_type, self.objtype)
|
|
3261
|
-
|
|
3262
|
-
def describe_signature(self, signode: TextElement, ast: ASTDeclaration,
|
|
3263
|
-
options: dict) -> None:
|
|
3264
|
-
ast.describe_signature(signode, 'lastIsName', self.env, options)
|
|
3265
|
-
|
|
3266
|
-
def run(self) -> list[Node]:
|
|
3267
|
-
env = self.state.document.settings.env # from ObjectDescription.run
|
|
3268
|
-
if 'c:parent_symbol' not in env.temp_data:
|
|
3269
|
-
root = env.domaindata['c']['root_symbol']
|
|
3270
|
-
env.temp_data['c:parent_symbol'] = root
|
|
3271
|
-
env.ref_context['c:parent_key'] = root.get_lookup_key()
|
|
3272
|
-
|
|
3273
|
-
# When multiple declarations are made in the same directive
|
|
3274
|
-
# they need to know about each other to provide symbol lookup for function parameters.
|
|
3275
|
-
# We use last_symbol to store the latest added declaration in a directive.
|
|
3276
|
-
env.temp_data['c:last_symbol'] = None
|
|
3277
|
-
return super().run()
|
|
3278
|
-
|
|
3279
|
-
def handle_signature(self, sig: str, signode: TextElement) -> ASTDeclaration:
|
|
3280
|
-
parentSymbol: Symbol = self.env.temp_data['c:parent_symbol']
|
|
3281
|
-
|
|
3282
|
-
max_len = (self.env.config.c_maximum_signature_line_length
|
|
3283
|
-
or self.env.config.maximum_signature_line_length
|
|
3284
|
-
or 0)
|
|
3285
|
-
signode['multi_line_parameter_list'] = (
|
|
3286
|
-
'single-line-parameter-list' not in self.options
|
|
3287
|
-
and (len(sig) > max_len > 0)
|
|
3288
|
-
)
|
|
3289
|
-
|
|
3290
|
-
parser = DefinitionParser(sig, location=signode, config=self.env.config)
|
|
3291
|
-
try:
|
|
3292
|
-
ast = self.parse_definition(parser)
|
|
3293
|
-
parser.assert_end()
|
|
3294
|
-
except DefinitionError as e:
|
|
3295
|
-
logger.warning(e, location=signode)
|
|
3296
|
-
# It is easier to assume some phony name than handling the error in
|
|
3297
|
-
# the possibly inner declarations.
|
|
3298
|
-
name = _make_phony_error_name()
|
|
3299
|
-
symbol = parentSymbol.add_name(name)
|
|
3300
|
-
self.env.temp_data['c:last_symbol'] = symbol
|
|
3301
|
-
raise ValueError from e
|
|
3302
|
-
|
|
3303
|
-
try:
|
|
3304
|
-
symbol = parentSymbol.add_declaration(
|
|
3305
|
-
ast, docname=self.env.docname, line=self.get_source_info()[1])
|
|
3306
|
-
# append the new declaration to the sibling list
|
|
3307
|
-
assert symbol.siblingAbove is None
|
|
3308
|
-
assert symbol.siblingBelow is None
|
|
3309
|
-
symbol.siblingAbove = self.env.temp_data['c:last_symbol']
|
|
3310
|
-
if symbol.siblingAbove is not None:
|
|
3311
|
-
assert symbol.siblingAbove.siblingBelow is None
|
|
3312
|
-
symbol.siblingAbove.siblingBelow = symbol
|
|
3313
|
-
self.env.temp_data['c:last_symbol'] = symbol
|
|
3314
|
-
except _DuplicateSymbolError as e:
|
|
3315
|
-
# Assume we are actually in the old symbol,
|
|
3316
|
-
# instead of the newly created duplicate.
|
|
3317
|
-
self.env.temp_data['c:last_symbol'] = e.symbol
|
|
3318
|
-
msg = __("Duplicate C declaration, also defined at %s:%s.\n"
|
|
3319
|
-
"Declaration is '.. c:%s:: %s'.")
|
|
3320
|
-
msg = msg % (e.symbol.docname, e.symbol.line, self.display_object_type, sig)
|
|
3321
|
-
logger.warning(msg, location=signode)
|
|
3322
|
-
|
|
3323
|
-
if ast.objectType == 'enumerator':
|
|
3324
|
-
self._add_enumerator_to_parent(ast)
|
|
3325
|
-
|
|
3326
|
-
# note: handle_signature may be called multiple time per directive,
|
|
3327
|
-
# if it has multiple signatures, so don't mess with the original options.
|
|
3328
|
-
options = dict(self.options)
|
|
3329
|
-
self.describe_signature(signode, ast, options)
|
|
3330
|
-
return ast
|
|
3331
|
-
|
|
3332
|
-
def before_content(self) -> None:
|
|
3333
|
-
lastSymbol: Symbol = self.env.temp_data['c:last_symbol']
|
|
3334
|
-
assert lastSymbol
|
|
3335
|
-
self.oldParentSymbol = self.env.temp_data['c:parent_symbol']
|
|
3336
|
-
self.oldParentKey: LookupKey = self.env.ref_context['c:parent_key']
|
|
3337
|
-
self.env.temp_data['c:parent_symbol'] = lastSymbol
|
|
3338
|
-
self.env.ref_context['c:parent_key'] = lastSymbol.get_lookup_key()
|
|
3339
|
-
|
|
3340
|
-
def after_content(self) -> None:
|
|
3341
|
-
self.env.temp_data['c:parent_symbol'] = self.oldParentSymbol
|
|
3342
|
-
self.env.ref_context['c:parent_key'] = self.oldParentKey
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
class CMemberObject(CObject):
|
|
3346
|
-
object_type = 'member'
|
|
3347
|
-
|
|
3348
|
-
@property
|
|
3349
|
-
def display_object_type(self) -> str:
|
|
3350
|
-
# the distinction between var and member is only cosmetic
|
|
3351
|
-
assert self.objtype in ('member', 'var')
|
|
3352
|
-
return self.objtype
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
_function_doc_field_types = [
|
|
3356
|
-
TypedField('parameter', label=_('Parameters'),
|
|
3357
|
-
names=('param', 'parameter', 'arg', 'argument'),
|
|
3358
|
-
typerolename='expr', typenames=('type',)),
|
|
3359
|
-
GroupedField('retval', label=_('Return values'),
|
|
3360
|
-
names=('retvals', 'retval'),
|
|
3361
|
-
can_collapse=True),
|
|
3362
|
-
Field('returnvalue', label=_('Returns'), has_arg=False,
|
|
3363
|
-
names=('returns', 'return')),
|
|
3364
|
-
Field('returntype', label=_('Return type'), has_arg=False,
|
|
3365
|
-
names=('rtype',)),
|
|
3366
|
-
]
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
class CFunctionObject(CObject):
|
|
3370
|
-
object_type = 'function'
|
|
3371
|
-
|
|
3372
|
-
doc_field_types = _function_doc_field_types.copy()
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
class CMacroObject(CObject):
|
|
3376
|
-
object_type = 'macro'
|
|
3377
|
-
|
|
3378
|
-
doc_field_types = _function_doc_field_types.copy()
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
class CStructObject(CObject):
|
|
3382
|
-
object_type = 'struct'
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
class CUnionObject(CObject):
|
|
3386
|
-
object_type = 'union'
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
class CEnumObject(CObject):
|
|
3390
|
-
object_type = 'enum'
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
class CEnumeratorObject(CObject):
|
|
3394
|
-
object_type = 'enumerator'
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
class CTypeObject(CObject):
|
|
3398
|
-
object_type = 'type'
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
class CNamespaceObject(SphinxDirective):
|
|
3402
|
-
"""
|
|
3403
|
-
This directive is just to tell Sphinx that we're documenting stuff in
|
|
3404
|
-
namespace foo.
|
|
3405
|
-
"""
|
|
3406
|
-
|
|
3407
|
-
has_content = False
|
|
3408
|
-
required_arguments = 1
|
|
3409
|
-
optional_arguments = 0
|
|
3410
|
-
final_argument_whitespace = True
|
|
3411
|
-
option_spec: OptionSpec = {}
|
|
3412
|
-
|
|
3413
|
-
def run(self) -> list[Node]:
|
|
3414
|
-
rootSymbol = self.env.domaindata['c']['root_symbol']
|
|
3415
|
-
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
|
|
3416
|
-
symbol = rootSymbol
|
|
3417
|
-
stack: list[Symbol] = []
|
|
3418
|
-
else:
|
|
3419
|
-
parser = DefinitionParser(self.arguments[0],
|
|
3420
|
-
location=self.get_location(),
|
|
3421
|
-
config=self.env.config)
|
|
3422
|
-
try:
|
|
3423
|
-
name = parser.parse_namespace_object()
|
|
3424
|
-
parser.assert_end()
|
|
3425
|
-
except DefinitionError as e:
|
|
3426
|
-
logger.warning(e, location=self.get_location())
|
|
3427
|
-
name = _make_phony_error_name()
|
|
3428
|
-
symbol = rootSymbol.add_name(name)
|
|
3429
|
-
stack = [symbol]
|
|
3430
|
-
self.env.temp_data['c:parent_symbol'] = symbol
|
|
3431
|
-
self.env.temp_data['c:namespace_stack'] = stack
|
|
3432
|
-
self.env.ref_context['c:parent_key'] = symbol.get_lookup_key()
|
|
3433
|
-
return []
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
class CNamespacePushObject(SphinxDirective):
|
|
3437
|
-
has_content = False
|
|
3438
|
-
required_arguments = 1
|
|
3439
|
-
optional_arguments = 0
|
|
3440
|
-
final_argument_whitespace = True
|
|
3441
|
-
option_spec: OptionSpec = {}
|
|
3442
|
-
|
|
3443
|
-
def run(self) -> list[Node]:
|
|
3444
|
-
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
|
|
3445
|
-
return []
|
|
3446
|
-
parser = DefinitionParser(self.arguments[0],
|
|
3447
|
-
location=self.get_location(),
|
|
3448
|
-
config=self.env.config)
|
|
3449
|
-
try:
|
|
3450
|
-
name = parser.parse_namespace_object()
|
|
3451
|
-
parser.assert_end()
|
|
3452
|
-
except DefinitionError as e:
|
|
3453
|
-
logger.warning(e, location=self.get_location())
|
|
3454
|
-
name = _make_phony_error_name()
|
|
3455
|
-
oldParent = self.env.temp_data.get('c:parent_symbol', None)
|
|
3456
|
-
if not oldParent:
|
|
3457
|
-
oldParent = self.env.domaindata['c']['root_symbol']
|
|
3458
|
-
symbol = oldParent.add_name(name)
|
|
3459
|
-
stack = self.env.temp_data.get('c:namespace_stack', [])
|
|
3460
|
-
stack.append(symbol)
|
|
3461
|
-
self.env.temp_data['c:parent_symbol'] = symbol
|
|
3462
|
-
self.env.temp_data['c:namespace_stack'] = stack
|
|
3463
|
-
self.env.ref_context['c:parent_key'] = symbol.get_lookup_key()
|
|
3464
|
-
return []
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
class CNamespacePopObject(SphinxDirective):
|
|
3468
|
-
has_content = False
|
|
3469
|
-
required_arguments = 0
|
|
3470
|
-
optional_arguments = 0
|
|
3471
|
-
final_argument_whitespace = True
|
|
3472
|
-
option_spec: OptionSpec = {}
|
|
3473
|
-
|
|
3474
|
-
def run(self) -> list[Node]:
|
|
3475
|
-
stack = self.env.temp_data.get('c:namespace_stack', None)
|
|
3476
|
-
if not stack or len(stack) == 0:
|
|
3477
|
-
logger.warning("C namespace pop on empty stack. Defaulting to global scope.",
|
|
3478
|
-
location=self.get_location())
|
|
3479
|
-
stack = []
|
|
3480
|
-
else:
|
|
3481
|
-
stack.pop()
|
|
3482
|
-
if len(stack) > 0:
|
|
3483
|
-
symbol = stack[-1]
|
|
3484
|
-
else:
|
|
3485
|
-
symbol = self.env.domaindata['c']['root_symbol']
|
|
3486
|
-
self.env.temp_data['c:parent_symbol'] = symbol
|
|
3487
|
-
self.env.temp_data['c:namespace_stack'] = stack
|
|
3488
|
-
self.env.ref_context['cp:parent_key'] = symbol.get_lookup_key()
|
|
3489
|
-
return []
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
class AliasNode(nodes.Element):
|
|
3493
|
-
def __init__(
|
|
3494
|
-
self,
|
|
3495
|
-
sig: str,
|
|
3496
|
-
aliasOptions: dict,
|
|
3497
|
-
document: Any,
|
|
3498
|
-
env: BuildEnvironment | None = None,
|
|
3499
|
-
parentKey: LookupKey | None = None,
|
|
3500
|
-
) -> None:
|
|
3501
|
-
super().__init__()
|
|
3502
|
-
self.sig = sig
|
|
3503
|
-
self.aliasOptions = aliasOptions
|
|
3504
|
-
self.document = document
|
|
3505
|
-
if env is not None:
|
|
3506
|
-
if 'c:parent_symbol' not in env.temp_data:
|
|
3507
|
-
root = env.domaindata['c']['root_symbol']
|
|
3508
|
-
env.temp_data['c:parent_symbol'] = root
|
|
3509
|
-
env.ref_context['c:parent_key'] = root.get_lookup_key()
|
|
3510
|
-
self.parentKey = env.ref_context['c:parent_key']
|
|
3511
|
-
else:
|
|
3512
|
-
assert parentKey is not None
|
|
3513
|
-
self.parentKey = parentKey
|
|
3514
|
-
|
|
3515
|
-
def copy(self) -> AliasNode:
|
|
3516
|
-
return self.__class__(self.sig, self.aliasOptions, self.document,
|
|
3517
|
-
env=None, parentKey=self.parentKey)
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
class AliasTransform(SphinxTransform):
|
|
3521
|
-
default_priority = ReferencesResolver.default_priority - 1
|
|
3522
|
-
|
|
3523
|
-
def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool,
|
|
3524
|
-
aliasOptions: dict, renderOptions: dict,
|
|
3525
|
-
document: Any) -> list[Node]:
|
|
3526
|
-
if maxdepth == 0:
|
|
3527
|
-
recurse = True
|
|
3528
|
-
elif maxdepth == 1:
|
|
3529
|
-
recurse = False
|
|
3530
|
-
else:
|
|
3531
|
-
maxdepth -= 1
|
|
3532
|
-
recurse = True
|
|
3533
|
-
|
|
3534
|
-
nodes: list[Node] = []
|
|
3535
|
-
if not skipThis:
|
|
3536
|
-
signode = addnodes.desc_signature('', '')
|
|
3537
|
-
nodes.append(signode)
|
|
3538
|
-
s.declaration.describe_signature(signode, 'markName', self.env, renderOptions)
|
|
3539
|
-
|
|
3540
|
-
if recurse:
|
|
3541
|
-
if skipThis:
|
|
3542
|
-
childContainer: list[Node] | addnodes.desc = nodes
|
|
3543
|
-
else:
|
|
3544
|
-
content = addnodes.desc_content()
|
|
3545
|
-
desc = addnodes.desc()
|
|
3546
|
-
content.append(desc)
|
|
3547
|
-
desc.document = document
|
|
3548
|
-
desc['domain'] = 'c'
|
|
3549
|
-
# 'desctype' is a backwards compatible attribute
|
|
3550
|
-
desc['objtype'] = desc['desctype'] = 'alias'
|
|
3551
|
-
desc['no-index'] = True
|
|
3552
|
-
childContainer = desc
|
|
3553
|
-
|
|
3554
|
-
for sChild in s.children:
|
|
3555
|
-
if sChild.declaration is None:
|
|
3556
|
-
continue
|
|
3557
|
-
childNodes = self._render_symbol(
|
|
3558
|
-
sChild, maxdepth=maxdepth, skipThis=False,
|
|
3559
|
-
aliasOptions=aliasOptions, renderOptions=renderOptions,
|
|
3560
|
-
document=document)
|
|
3561
|
-
childContainer.extend(childNodes)
|
|
3562
|
-
|
|
3563
|
-
if not skipThis and len(desc.children) != 0:
|
|
3564
|
-
nodes.append(content)
|
|
3565
|
-
return nodes
|
|
3566
|
-
|
|
3567
|
-
def apply(self, **kwargs: Any) -> None:
|
|
3568
|
-
for node in self.document.findall(AliasNode):
|
|
3569
|
-
sig = node.sig
|
|
3570
|
-
parentKey = node.parentKey
|
|
3571
|
-
try:
|
|
3572
|
-
parser = DefinitionParser(sig, location=node,
|
|
3573
|
-
config=self.env.config)
|
|
3574
|
-
name = parser.parse_xref_object()
|
|
3575
|
-
except DefinitionError as e:
|
|
3576
|
-
logger.warning(e, location=node)
|
|
3577
|
-
name = None
|
|
3578
|
-
|
|
3579
|
-
if name is None:
|
|
3580
|
-
# could not be parsed, so stop here
|
|
3581
|
-
signode = addnodes.desc_signature(sig, '')
|
|
3582
|
-
signode.clear()
|
|
3583
|
-
signode += addnodes.desc_name(sig, sig)
|
|
3584
|
-
node.replace_self(signode)
|
|
3585
|
-
continue
|
|
3586
|
-
|
|
3587
|
-
rootSymbol: Symbol = self.env.domains['c'].data['root_symbol']
|
|
3588
|
-
parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
|
|
3589
|
-
if not parentSymbol:
|
|
3590
|
-
logger.debug("Target: %s", sig)
|
|
3591
|
-
logger.debug("ParentKey: %s", parentKey)
|
|
3592
|
-
logger.debug(rootSymbol.dump(1))
|
|
3593
|
-
assert parentSymbol # should be there
|
|
3594
|
-
|
|
3595
|
-
s = parentSymbol.find_declaration(
|
|
3596
|
-
name, 'any',
|
|
3597
|
-
matchSelf=True, recurseInAnon=True)
|
|
3598
|
-
if s is None:
|
|
3599
|
-
signode = addnodes.desc_signature(sig, '')
|
|
3600
|
-
node.append(signode)
|
|
3601
|
-
signode.clear()
|
|
3602
|
-
signode += addnodes.desc_name(sig, sig)
|
|
3603
|
-
|
|
3604
|
-
logger.warning("Could not find C declaration for alias '%s'." % name,
|
|
3605
|
-
location=node)
|
|
3606
|
-
node.replace_self(signode)
|
|
3607
|
-
continue
|
|
3608
|
-
# Declarations like .. var:: int Missing::var
|
|
3609
|
-
# may introduce symbols without declarations.
|
|
3610
|
-
# But if we skip the root then it is ok to start recursion from it.
|
|
3611
|
-
if not node.aliasOptions['noroot'] and s.declaration is None:
|
|
3612
|
-
signode = addnodes.desc_signature(sig, '')
|
|
3613
|
-
node.append(signode)
|
|
3614
|
-
signode.clear()
|
|
3615
|
-
signode += addnodes.desc_name(sig, sig)
|
|
3616
|
-
|
|
3617
|
-
logger.warning(
|
|
3618
|
-
"Can not render C declaration for alias '%s'. No such declaration." % name,
|
|
3619
|
-
location=node)
|
|
3620
|
-
node.replace_self(signode)
|
|
3621
|
-
continue
|
|
3622
|
-
|
|
3623
|
-
nodes = self._render_symbol(s, maxdepth=node.aliasOptions['maxdepth'],
|
|
3624
|
-
skipThis=node.aliasOptions['noroot'],
|
|
3625
|
-
aliasOptions=node.aliasOptions,
|
|
3626
|
-
renderOptions={}, document=node.document)
|
|
3627
|
-
node.replace_self(nodes)
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
class CAliasObject(ObjectDescription):
|
|
3631
|
-
option_spec: OptionSpec = {
|
|
3632
|
-
'maxdepth': directives.nonnegative_int,
|
|
3633
|
-
'noroot': directives.flag,
|
|
3634
|
-
}
|
|
3635
|
-
|
|
3636
|
-
def run(self) -> list[Node]:
|
|
3637
|
-
"""
|
|
3638
|
-
On purpose this doesn't call the ObjectDescription version, but is based on it.
|
|
3639
|
-
Each alias signature may expand into multiple real signatures if 'noroot'.
|
|
3640
|
-
The code is therefore based on the ObjectDescription version.
|
|
3641
|
-
"""
|
|
3642
|
-
if ':' in self.name:
|
|
3643
|
-
self.domain, self.objtype = self.name.split(':', 1)
|
|
3644
|
-
else:
|
|
3645
|
-
self.domain, self.objtype = '', self.name
|
|
3646
|
-
|
|
3647
|
-
node = addnodes.desc()
|
|
3648
|
-
node.document = self.state.document
|
|
3649
|
-
node['domain'] = self.domain
|
|
3650
|
-
# 'desctype' is a backwards compatible attribute
|
|
3651
|
-
node['objtype'] = node['desctype'] = self.objtype
|
|
3652
|
-
node['no-index'] = True
|
|
3653
|
-
|
|
3654
|
-
self.names: list[str] = []
|
|
3655
|
-
aliasOptions = {
|
|
3656
|
-
'maxdepth': self.options.get('maxdepth', 1),
|
|
3657
|
-
'noroot': 'noroot' in self.options,
|
|
3658
|
-
}
|
|
3659
|
-
if aliasOptions['noroot'] and aliasOptions['maxdepth'] == 1:
|
|
3660
|
-
logger.warning("Error in C alias declaration."
|
|
3661
|
-
" Requested 'noroot' but 'maxdepth' 1."
|
|
3662
|
-
" When skipping the root declaration,"
|
|
3663
|
-
" need 'maxdepth' 0 for infinite or at least 2.",
|
|
3664
|
-
location=self.get_location())
|
|
3665
|
-
for sig in self.get_signatures():
|
|
3666
|
-
node.append(AliasNode(sig, aliasOptions, self.state.document, env=self.env))
|
|
3667
|
-
return [node]
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
class CXRefRole(XRefRole):
|
|
3671
|
-
def process_link(self, env: BuildEnvironment, refnode: Element,
|
|
3672
|
-
has_explicit_title: bool, title: str, target: str) -> tuple[str, str]:
|
|
3673
|
-
refnode.attributes.update(env.ref_context)
|
|
3674
|
-
|
|
3675
|
-
if not has_explicit_title:
|
|
3676
|
-
# major hax: replace anon names via simple string manipulation.
|
|
3677
|
-
# Can this actually fail?
|
|
3678
|
-
title = anon_identifier_re.sub("[anonymous]", str(title))
|
|
3679
|
-
|
|
3680
|
-
if not has_explicit_title:
|
|
3681
|
-
target = target.lstrip('~') # only has a meaning for the title
|
|
3682
|
-
# if the first character is a tilde, don't display the module/class
|
|
3683
|
-
# parts of the contents
|
|
3684
|
-
if title[0:1] == '~':
|
|
3685
|
-
title = title[1:]
|
|
3686
|
-
dot = title.rfind('.')
|
|
3687
|
-
if dot != -1:
|
|
3688
|
-
title = title[dot + 1:]
|
|
3689
|
-
return title, target
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
class CExprRole(SphinxRole):
|
|
3693
|
-
def __init__(self, asCode: bool) -> None:
|
|
3694
|
-
super().__init__()
|
|
3695
|
-
if asCode:
|
|
3696
|
-
# render the expression as inline code
|
|
3697
|
-
self.class_type = 'c-expr'
|
|
3698
|
-
else:
|
|
3699
|
-
# render the expression as inline text
|
|
3700
|
-
self.class_type = 'c-texpr'
|
|
3701
|
-
|
|
3702
|
-
def run(self) -> tuple[list[Node], list[system_message]]:
|
|
3703
|
-
text = self.text.replace('\n', ' ')
|
|
3704
|
-
parser = DefinitionParser(text, location=self.get_location(),
|
|
3705
|
-
config=self.env.config)
|
|
3706
|
-
# attempt to mimic XRefRole classes, except that...
|
|
3707
|
-
try:
|
|
3708
|
-
ast = parser.parse_expression()
|
|
3709
|
-
except DefinitionError as ex:
|
|
3710
|
-
logger.warning('Unparseable C expression: %r\n%s', text, ex,
|
|
3711
|
-
location=self.get_location())
|
|
3712
|
-
# see below
|
|
3713
|
-
return [addnodes.desc_inline('c', text, text, classes=[self.class_type])], []
|
|
3714
|
-
parentSymbol = self.env.temp_data.get('c:parent_symbol', None)
|
|
3715
|
-
if parentSymbol is None:
|
|
3716
|
-
parentSymbol = self.env.domaindata['c']['root_symbol']
|
|
3717
|
-
# ...most if not all of these classes should really apply to the individual references,
|
|
3718
|
-
# not the container node
|
|
3719
|
-
signode = addnodes.desc_inline('c', classes=[self.class_type])
|
|
3720
|
-
ast.describe_signature(signode, 'markType', self.env, parentSymbol)
|
|
3721
|
-
return [signode], []
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
class CDomain(Domain):
|
|
3725
|
-
"""C language domain."""
|
|
3726
|
-
name = 'c'
|
|
3727
|
-
label = 'C'
|
|
3728
|
-
object_types = {
|
|
3729
|
-
# 'identifier' is the one used for xrefs generated in signatures, not in roles
|
|
3730
|
-
'member': ObjType(_('member'), 'var', 'member', 'data', 'identifier'),
|
|
3731
|
-
'var': ObjType(_('variable'), 'var', 'member', 'data', 'identifier'),
|
|
3732
|
-
'function': ObjType(_('function'), 'func', 'identifier', 'type'),
|
|
3733
|
-
'macro': ObjType(_('macro'), 'macro', 'identifier'),
|
|
3734
|
-
'struct': ObjType(_('struct'), 'struct', 'identifier', 'type'),
|
|
3735
|
-
'union': ObjType(_('union'), 'union', 'identifier', 'type'),
|
|
3736
|
-
'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'),
|
|
3737
|
-
'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'),
|
|
3738
|
-
'type': ObjType(_('type'), 'identifier', 'type'),
|
|
3739
|
-
# generated object types
|
|
3740
|
-
'functionParam': ObjType(_('function parameter'), 'identifier', 'var', 'member', 'data'), # noqa: E501
|
|
3741
|
-
}
|
|
3742
|
-
|
|
3743
|
-
directives = {
|
|
3744
|
-
'member': CMemberObject,
|
|
3745
|
-
'var': CMemberObject,
|
|
3746
|
-
'function': CFunctionObject,
|
|
3747
|
-
'macro': CMacroObject,
|
|
3748
|
-
'struct': CStructObject,
|
|
3749
|
-
'union': CUnionObject,
|
|
3750
|
-
'enum': CEnumObject,
|
|
3751
|
-
'enumerator': CEnumeratorObject,
|
|
3752
|
-
'type': CTypeObject,
|
|
3753
|
-
# scope control
|
|
3754
|
-
'namespace': CNamespaceObject,
|
|
3755
|
-
'namespace-push': CNamespacePushObject,
|
|
3756
|
-
'namespace-pop': CNamespacePopObject,
|
|
3757
|
-
# other
|
|
3758
|
-
'alias': CAliasObject,
|
|
3759
|
-
}
|
|
3760
|
-
roles = {
|
|
3761
|
-
'member': CXRefRole(),
|
|
3762
|
-
'data': CXRefRole(),
|
|
3763
|
-
'var': CXRefRole(),
|
|
3764
|
-
'func': CXRefRole(fix_parens=True),
|
|
3765
|
-
'macro': CXRefRole(),
|
|
3766
|
-
'struct': CXRefRole(),
|
|
3767
|
-
'union': CXRefRole(),
|
|
3768
|
-
'enum': CXRefRole(),
|
|
3769
|
-
'enumerator': CXRefRole(),
|
|
3770
|
-
'type': CXRefRole(),
|
|
3771
|
-
'expr': CExprRole(asCode=True),
|
|
3772
|
-
'texpr': CExprRole(asCode=False),
|
|
3773
|
-
}
|
|
3774
|
-
initial_data: dict[str, Symbol | dict[str, tuple[str, str, str]]] = {
|
|
3775
|
-
'root_symbol': Symbol(None, None, None, None, None),
|
|
3776
|
-
'objects': {}, # fullname -> docname, node_id, objtype
|
|
3777
|
-
}
|
|
3778
|
-
|
|
3779
|
-
def clear_doc(self, docname: str) -> None:
|
|
3780
|
-
if Symbol.debug_show_tree:
|
|
3781
|
-
logger.debug("clear_doc: %s", docname)
|
|
3782
|
-
logger.debug("\tbefore:")
|
|
3783
|
-
logger.debug(self.data['root_symbol'].dump(1))
|
|
3784
|
-
logger.debug("\tbefore end")
|
|
3785
|
-
|
|
3786
|
-
rootSymbol = self.data['root_symbol']
|
|
3787
|
-
rootSymbol.clear_doc(docname)
|
|
3788
|
-
|
|
3789
|
-
if Symbol.debug_show_tree:
|
|
3790
|
-
logger.debug("\tafter:")
|
|
3791
|
-
logger.debug(self.data['root_symbol'].dump(1))
|
|
3792
|
-
logger.debug("\tafter end")
|
|
3793
|
-
logger.debug("clear_doc end: %s", docname)
|
|
3794
|
-
|
|
3795
|
-
def process_doc(self, env: BuildEnvironment, docname: str,
|
|
3796
|
-
document: nodes.document) -> None:
|
|
3797
|
-
if Symbol.debug_show_tree:
|
|
3798
|
-
logger.debug("process_doc: %s", docname)
|
|
3799
|
-
logger.debug(self.data['root_symbol'].dump(0))
|
|
3800
|
-
logger.debug("process_doc end: %s", docname)
|
|
3801
|
-
|
|
3802
|
-
def process_field_xref(self, pnode: pending_xref) -> None:
|
|
3803
|
-
pnode.attributes.update(self.env.ref_context)
|
|
3804
|
-
|
|
3805
|
-
def merge_domaindata(self, docnames: list[str], otherdata: dict) -> None:
|
|
3806
|
-
if Symbol.debug_show_tree:
|
|
3807
|
-
logger.debug("merge_domaindata:")
|
|
3808
|
-
logger.debug("\tself:")
|
|
3809
|
-
logger.debug(self.data['root_symbol'].dump(1))
|
|
3810
|
-
logger.debug("\tself end")
|
|
3811
|
-
logger.debug("\tother:")
|
|
3812
|
-
logger.debug(otherdata['root_symbol'].dump(1))
|
|
3813
|
-
logger.debug("\tother end")
|
|
3814
|
-
logger.debug("merge_domaindata end")
|
|
3815
|
-
|
|
3816
|
-
self.data['root_symbol'].merge_with(otherdata['root_symbol'],
|
|
3817
|
-
docnames, self.env)
|
|
3818
|
-
ourObjects = self.data['objects']
|
|
3819
|
-
for fullname, (fn, id_, objtype) in otherdata['objects'].items():
|
|
3820
|
-
if fn in docnames:
|
|
3821
|
-
if fullname not in ourObjects:
|
|
3822
|
-
ourObjects[fullname] = (fn, id_, objtype)
|
|
3823
|
-
# no need to warn on duplicates, the symbol merge already does that
|
|
3824
|
-
|
|
3825
|
-
def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
|
3826
|
-
typ: str, target: str, node: pending_xref,
|
|
3827
|
-
contnode: Element) -> tuple[Element | None, str | None]:
|
|
3828
|
-
parser = DefinitionParser(target, location=node, config=env.config)
|
|
3829
|
-
try:
|
|
3830
|
-
name = parser.parse_xref_object()
|
|
3831
|
-
except DefinitionError as e:
|
|
3832
|
-
logger.warning('Unparseable C cross-reference: %r\n%s', target, e,
|
|
3833
|
-
location=node)
|
|
3834
|
-
return None, None
|
|
3835
|
-
parentKey: LookupKey = node.get("c:parent_key", None)
|
|
3836
|
-
rootSymbol = self.data['root_symbol']
|
|
3837
|
-
if parentKey:
|
|
3838
|
-
parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
|
|
3839
|
-
if not parentSymbol:
|
|
3840
|
-
logger.debug("Target: %s", target)
|
|
3841
|
-
logger.debug("ParentKey: %s", parentKey)
|
|
3842
|
-
logger.debug(rootSymbol.dump(1))
|
|
3843
|
-
assert parentSymbol # should be there
|
|
3844
|
-
else:
|
|
3845
|
-
parentSymbol = rootSymbol
|
|
3846
|
-
s = parentSymbol.find_declaration(name, typ,
|
|
3847
|
-
matchSelf=True, recurseInAnon=True)
|
|
3848
|
-
if s is None or s.declaration is None:
|
|
3849
|
-
return None, None
|
|
3850
|
-
|
|
3851
|
-
# TODO: check role type vs. object type
|
|
3852
|
-
|
|
3853
|
-
declaration = s.declaration
|
|
3854
|
-
displayName = name.get_display_string()
|
|
3855
|
-
docname = s.docname
|
|
3856
|
-
assert docname
|
|
3857
|
-
|
|
3858
|
-
return make_refnode(builder, fromdocname, docname,
|
|
3859
|
-
declaration.get_newest_id(), contnode, displayName,
|
|
3860
|
-
), declaration.objectType
|
|
3861
|
-
|
|
3862
|
-
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
|
3863
|
-
typ: str, target: str, node: pending_xref,
|
|
3864
|
-
contnode: Element) -> Element | None:
|
|
3865
|
-
return self._resolve_xref_inner(env, fromdocname, builder, typ,
|
|
3866
|
-
target, node, contnode)[0]
|
|
3867
|
-
|
|
3868
|
-
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
|
3869
|
-
target: str, node: pending_xref, contnode: Element,
|
|
3870
|
-
) -> list[tuple[str, Element]]:
|
|
3871
|
-
with logging.suppress_logging():
|
|
3872
|
-
retnode, objtype = self._resolve_xref_inner(env, fromdocname, builder,
|
|
3873
|
-
'any', target, node, contnode)
|
|
3874
|
-
if retnode:
|
|
3875
|
-
return [('c:' + self.role_for_objtype(objtype), retnode)]
|
|
3876
|
-
return []
|
|
3877
|
-
|
|
3878
|
-
def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]:
|
|
3879
|
-
rootSymbol = self.data['root_symbol']
|
|
3880
|
-
for symbol in rootSymbol.get_all_symbols():
|
|
3881
|
-
if symbol.declaration is None:
|
|
3882
|
-
continue
|
|
3883
|
-
assert symbol.docname
|
|
3884
|
-
fullNestedName = symbol.get_full_nested_name()
|
|
3885
|
-
name = str(fullNestedName).lstrip('.')
|
|
3886
|
-
dispname = fullNestedName.get_display_string().lstrip('.')
|
|
3887
|
-
objectType = symbol.declaration.objectType
|
|
3888
|
-
docname = symbol.docname
|
|
3889
|
-
newestId = symbol.declaration.get_newest_id()
|
|
3890
|
-
yield (name, dispname, objectType, docname, newestId, 1)
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
def setup(app: Sphinx) -> dict[str, Any]:
|
|
3894
|
-
app.add_domain(CDomain)
|
|
3895
|
-
app.add_config_value("c_id_attributes", [], 'env')
|
|
3896
|
-
app.add_config_value("c_paren_attributes", [], 'env')
|
|
3897
|
-
app.add_config_value("c_extra_keywords", _macroKeywords, 'env')
|
|
3898
|
-
app.add_config_value("c_maximum_signature_line_length", None, 'env', types={int, None})
|
|
3899
|
-
app.add_post_transform(AliasTransform)
|
|
3900
|
-
|
|
3901
|
-
return {
|
|
3902
|
-
'version': 'builtin',
|
|
3903
|
-
'env_version': 3,
|
|
3904
|
-
'parallel_read_safe': True,
|
|
3905
|
-
'parallel_write_safe': True,
|
|
3906
|
-
}
|