mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Enable automatic formatting for `sphinx/domains/c/
`
This commit is contained in:
parent
e47d12862e
commit
3e2f89b820
@ -394,11 +394,6 @@ preview = true
|
||||
quote-style = "single"
|
||||
exclude = [
|
||||
"sphinx/builders/latex/constants.py",
|
||||
"sphinx/domains/c/_parser.py",
|
||||
"sphinx/domains/c/_ids.py",
|
||||
"sphinx/domains/c/__init__.py",
|
||||
"sphinx/domains/c/_symbol.py",
|
||||
"sphinx/domains/c/_ast.py",
|
||||
"sphinx/domains/changeset.py",
|
||||
"sphinx/domains/citation.py",
|
||||
"sphinx/domains/cpp/_parser.py",
|
||||
|
@ -101,7 +101,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _make_phony_error_name() -> ASTNestedName:
|
||||
return ASTNestedName([ASTIdentifier("PhonyNameDueToError")], rooted=False)
|
||||
return ASTNestedName([ASTIdentifier('PhonyNameDueToError')], rooted=False)
|
||||
|
||||
|
||||
class CObject(ObjectDescription[ASTDeclaration]):
|
||||
@ -125,38 +125,44 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
symbol = ast.symbol
|
||||
assert symbol
|
||||
assert symbol.ident is not None
|
||||
parentSymbol = symbol.parent
|
||||
assert parentSymbol
|
||||
if parentSymbol.parent is None:
|
||||
parent_symbol = symbol.parent
|
||||
assert parent_symbol
|
||||
if parent_symbol.parent is None:
|
||||
# TODO: we could warn, but it is somewhat equivalent to
|
||||
# enumeratorss, without the enum
|
||||
return # no parent
|
||||
parentDecl = parentSymbol.declaration
|
||||
if parentDecl is None:
|
||||
parent_decl = parent_symbol.declaration
|
||||
if parent_decl is None:
|
||||
# the parent is not explicitly declared
|
||||
# TODO: we could warn, but?
|
||||
return
|
||||
if parentDecl.objectType != 'enum':
|
||||
if parent_decl.objectType != 'enum':
|
||||
# TODO: maybe issue a warning, enumerators in non-enums is weird,
|
||||
# but it is somewhat equivalent to enumeratorss, without the enum
|
||||
return
|
||||
if parentDecl.directiveType != 'enum':
|
||||
if parent_decl.directiveType != 'enum':
|
||||
return
|
||||
|
||||
targetSymbol = parentSymbol.parent
|
||||
s = targetSymbol.find_identifier(symbol.ident, matchSelf=False, recurseInAnon=True,
|
||||
searchInSiblings=False)
|
||||
target_symbol = parent_symbol.parent
|
||||
s = target_symbol.find_identifier(
|
||||
symbol.ident, matchSelf=False, recurseInAnon=True, searchInSiblings=False
|
||||
)
|
||||
if s is not None:
|
||||
# something is already declared with that name
|
||||
return
|
||||
declClone = symbol.declaration.clone()
|
||||
declClone.enumeratorScopedSymbol = symbol
|
||||
Symbol(parent=targetSymbol, ident=symbol.ident,
|
||||
declaration=declClone,
|
||||
docname=self.env.docname, line=self.get_source_info()[1])
|
||||
decl_clone = symbol.declaration.clone()
|
||||
decl_clone.enumeratorScopedSymbol = symbol
|
||||
Symbol(
|
||||
parent=target_symbol,
|
||||
ident=symbol.ident,
|
||||
declaration=decl_clone,
|
||||
docname=self.env.docname,
|
||||
line=self.get_source_info()[1],
|
||||
)
|
||||
|
||||
def add_target_and_index(self, ast: ASTDeclaration, sig: str,
|
||||
signode: TextElement) -> None:
|
||||
def add_target_and_index(
|
||||
self, ast: ASTDeclaration, sig: str, signode: TextElement
|
||||
) -> None:
|
||||
ids = []
|
||||
for i in range(1, _max_id + 1):
|
||||
try:
|
||||
@ -166,14 +172,14 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
assert i < _max_id
|
||||
# let's keep the newest first
|
||||
ids.reverse()
|
||||
newestId = ids[0]
|
||||
assert newestId # shouldn't be None
|
||||
newest_id = ids[0]
|
||||
assert newest_id # shouldn't be None
|
||||
|
||||
name = ast.symbol.get_full_nested_name().get_display_string().lstrip('.')
|
||||
if newestId not in self.state.document.ids:
|
||||
if newest_id not in self.state.document.ids:
|
||||
# always add the newest id
|
||||
assert newestId
|
||||
signode['ids'].append(newestId)
|
||||
assert newest_id
|
||||
signode['ids'].append(newest_id)
|
||||
# only add compatibility ids when there are no conflicts
|
||||
for id in ids[1:]:
|
||||
if not id: # is None when the element didn't exist in that version
|
||||
@ -184,8 +190,14 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
self.state.document.note_explicit_target(signode)
|
||||
|
||||
if 'no-index-entry' not in self.options:
|
||||
indexText = self.get_index_text(name)
|
||||
self.indexnode['entries'].append(('single', indexText, newestId, '', None))
|
||||
index_text = self.get_index_text(name)
|
||||
self.indexnode['entries'].append((
|
||||
'single',
|
||||
index_text,
|
||||
newest_id,
|
||||
'',
|
||||
None,
|
||||
))
|
||||
|
||||
@property
|
||||
def object_type(self) -> str:
|
||||
@ -201,8 +213,9 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
def parse_definition(self, parser: DefinitionParser) -> ASTDeclaration:
|
||||
return parser.parse_declaration(self.object_type, self.objtype)
|
||||
|
||||
def describe_signature(self, signode: TextElement, ast: ASTDeclaration,
|
||||
options: dict) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, ast: ASTDeclaration, options: dict
|
||||
) -> None:
|
||||
ast.describe_signature(signode, 'lastIsName', self.env, options)
|
||||
|
||||
def run(self) -> list[Node]:
|
||||
@ -219,11 +232,13 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
return super().run()
|
||||
|
||||
def handle_signature(self, sig: str, signode: TextElement) -> ASTDeclaration:
|
||||
parentSymbol: Symbol = self.env.temp_data['c:parent_symbol']
|
||||
parent_symbol: Symbol = self.env.temp_data['c:parent_symbol']
|
||||
|
||||
max_len = (self.env.config.c_maximum_signature_line_length
|
||||
or self.env.config.maximum_signature_line_length
|
||||
or 0)
|
||||
max_len = (
|
||||
self.env.config.c_maximum_signature_line_length
|
||||
or self.env.config.maximum_signature_line_length
|
||||
or 0
|
||||
)
|
||||
signode['multi_line_parameter_list'] = (
|
||||
'single-line-parameter-list' not in self.options
|
||||
and (len(sig) > max_len > 0)
|
||||
@ -238,13 +253,14 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
# It is easier to assume some phony name than handling the error in
|
||||
# the possibly inner declarations.
|
||||
name = _make_phony_error_name()
|
||||
symbol = parentSymbol.add_name(name)
|
||||
symbol = parent_symbol.add_name(name)
|
||||
self.env.temp_data['c:last_symbol'] = symbol
|
||||
raise ValueError from e
|
||||
|
||||
try:
|
||||
symbol = parentSymbol.add_declaration(
|
||||
ast, docname=self.env.docname, line=self.get_source_info()[1])
|
||||
symbol = parent_symbol.add_declaration(
|
||||
ast, docname=self.env.docname, line=self.get_source_info()[1]
|
||||
)
|
||||
# append the new declaration to the sibling list
|
||||
assert symbol.siblingAbove is None
|
||||
assert symbol.siblingBelow is None
|
||||
@ -257,8 +273,10 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
# Assume we are actually in the old symbol,
|
||||
# instead of the newly created duplicate.
|
||||
self.env.temp_data['c:last_symbol'] = e.symbol
|
||||
msg = __("Duplicate C declaration, also defined at %s:%s.\n"
|
||||
"Declaration is '.. c:%s:: %s'.")
|
||||
msg = __(
|
||||
'Duplicate C declaration, also defined at %s:%s.\n'
|
||||
"Declaration is '.. c:%s:: %s'."
|
||||
)
|
||||
logger.warning(
|
||||
msg,
|
||||
e.symbol.docname,
|
||||
@ -278,12 +296,12 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
return ast
|
||||
|
||||
def before_content(self) -> None:
|
||||
lastSymbol: Symbol = self.env.temp_data['c:last_symbol']
|
||||
assert lastSymbol
|
||||
last_symbol: Symbol = self.env.temp_data['c:last_symbol']
|
||||
assert last_symbol
|
||||
self.oldParentSymbol = self.env.temp_data['c:parent_symbol']
|
||||
self.oldParentKey: LookupKey = self.env.ref_context['c:parent_key']
|
||||
self.env.temp_data['c:parent_symbol'] = lastSymbol
|
||||
self.env.ref_context['c:parent_key'] = lastSymbol.get_lookup_key()
|
||||
self.env.temp_data['c:parent_symbol'] = last_symbol
|
||||
self.env.ref_context['c:parent_key'] = last_symbol.get_lookup_key()
|
||||
|
||||
def after_content(self) -> None:
|
||||
self.env.temp_data['c:parent_symbol'] = self.oldParentSymbol
|
||||
@ -301,16 +319,31 @@ class CMemberObject(CObject):
|
||||
|
||||
|
||||
_function_doc_field_types = [
|
||||
TypedField('parameter', label=_('Parameters'),
|
||||
names=('param', 'parameter', 'arg', 'argument'),
|
||||
typerolename='expr', typenames=('type',)),
|
||||
GroupedField('retval', label=_('Return values'),
|
||||
names=('retvals', 'retval'),
|
||||
can_collapse=True),
|
||||
Field('returnvalue', label=_('Returns'), has_arg=False,
|
||||
names=('returns', 'return')),
|
||||
Field('returntype', label=_('Return type'), has_arg=False,
|
||||
names=('rtype',)),
|
||||
TypedField(
|
||||
'parameter',
|
||||
label=_('Parameters'),
|
||||
names=('param', 'parameter', 'arg', 'argument'),
|
||||
typerolename='expr',
|
||||
typenames=('type',),
|
||||
),
|
||||
GroupedField(
|
||||
'retval',
|
||||
label=_('Return values'),
|
||||
names=('retvals', 'retval'),
|
||||
can_collapse=True,
|
||||
),
|
||||
Field(
|
||||
'returnvalue',
|
||||
label=_('Returns'),
|
||||
has_arg=False,
|
||||
names=('returns', 'return'),
|
||||
),
|
||||
Field(
|
||||
'returntype',
|
||||
label=_('Return type'),
|
||||
has_arg=False,
|
||||
names=('rtype',),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@ -359,21 +392,21 @@ class CNamespaceObject(SphinxDirective):
|
||||
option_spec: ClassVar[OptionSpec] = {}
|
||||
|
||||
def run(self) -> list[Node]:
|
||||
rootSymbol = self.env.domaindata['c']['root_symbol']
|
||||
root_symbol = self.env.domaindata['c']['root_symbol']
|
||||
if self.arguments[0].strip() in {'NULL', '0', 'nullptr'}:
|
||||
symbol = rootSymbol
|
||||
symbol = root_symbol
|
||||
stack: list[Symbol] = []
|
||||
else:
|
||||
parser = DefinitionParser(self.arguments[0],
|
||||
location=self.get_location(),
|
||||
config=self.env.config)
|
||||
parser = DefinitionParser(
|
||||
self.arguments[0], location=self.get_location(), config=self.env.config
|
||||
)
|
||||
try:
|
||||
name = parser.parse_namespace_object()
|
||||
parser.assert_end()
|
||||
except DefinitionError as e:
|
||||
logger.warning(e, location=self.get_location())
|
||||
name = _make_phony_error_name()
|
||||
symbol = rootSymbol.add_name(name)
|
||||
symbol = root_symbol.add_name(name)
|
||||
stack = [symbol]
|
||||
self.env.temp_data['c:parent_symbol'] = symbol
|
||||
self.env.temp_data['c:namespace_stack'] = stack
|
||||
@ -391,19 +424,19 @@ class CNamespacePushObject(SphinxDirective):
|
||||
def run(self) -> list[Node]:
|
||||
if self.arguments[0].strip() in {'NULL', '0', 'nullptr'}:
|
||||
return []
|
||||
parser = DefinitionParser(self.arguments[0],
|
||||
location=self.get_location(),
|
||||
config=self.env.config)
|
||||
parser = DefinitionParser(
|
||||
self.arguments[0], location=self.get_location(), config=self.env.config
|
||||
)
|
||||
try:
|
||||
name = parser.parse_namespace_object()
|
||||
parser.assert_end()
|
||||
except DefinitionError as e:
|
||||
logger.warning(e, location=self.get_location())
|
||||
name = _make_phony_error_name()
|
||||
oldParent = self.env.temp_data.get('c:parent_symbol', None)
|
||||
if not oldParent:
|
||||
oldParent = self.env.domaindata['c']['root_symbol']
|
||||
symbol = oldParent.add_name(name)
|
||||
old_parent = self.env.temp_data.get('c:parent_symbol', None)
|
||||
if not old_parent:
|
||||
old_parent = self.env.domaindata['c']['root_symbol']
|
||||
symbol = old_parent.add_name(name)
|
||||
stack = self.env.temp_data.get('c:namespace_stack', [])
|
||||
stack.append(symbol)
|
||||
self.env.temp_data['c:parent_symbol'] = symbol
|
||||
@ -422,8 +455,10 @@ class CNamespacePopObject(SphinxDirective):
|
||||
def run(self) -> list[Node]:
|
||||
stack = self.env.temp_data.get('c:namespace_stack', None)
|
||||
if not stack or len(stack) == 0:
|
||||
logger.warning("C namespace pop on empty stack. Defaulting to global scope.",
|
||||
location=self.get_location())
|
||||
logger.warning(
|
||||
'C namespace pop on empty stack. Defaulting to global scope.',
|
||||
location=self.get_location(),
|
||||
)
|
||||
stack = []
|
||||
else:
|
||||
stack.pop()
|
||||
@ -461,16 +496,27 @@ class AliasNode(nodes.Element):
|
||||
self.parentKey = parentKey
|
||||
|
||||
def copy(self) -> AliasNode:
|
||||
return self.__class__(self.sig, self.aliasOptions, self.document,
|
||||
env=None, parentKey=self.parentKey)
|
||||
return self.__class__(
|
||||
self.sig,
|
||||
self.aliasOptions,
|
||||
self.document,
|
||||
env=None,
|
||||
parentKey=self.parentKey,
|
||||
)
|
||||
|
||||
|
||||
class AliasTransform(SphinxTransform):
|
||||
default_priority = ReferencesResolver.default_priority - 1
|
||||
|
||||
def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool,
|
||||
aliasOptions: dict, renderOptions: dict,
|
||||
document: Any) -> list[Node]:
|
||||
def _render_symbol(
|
||||
self,
|
||||
s: Symbol,
|
||||
maxdepth: int,
|
||||
skip_this: bool,
|
||||
alias_options: dict,
|
||||
render_options: dict,
|
||||
document: Any,
|
||||
) -> list[Node]:
|
||||
if maxdepth == 0:
|
||||
recurse = True
|
||||
elif maxdepth == 1:
|
||||
@ -480,14 +526,16 @@ class AliasTransform(SphinxTransform):
|
||||
recurse = True
|
||||
|
||||
nodes: list[Node] = []
|
||||
if not skipThis:
|
||||
if not skip_this:
|
||||
signode = addnodes.desc_signature('', '')
|
||||
nodes.append(signode)
|
||||
s.declaration.describe_signature(signode, 'markName', self.env, renderOptions)
|
||||
s.declaration.describe_signature(
|
||||
signode, 'markName', self.env, render_options
|
||||
)
|
||||
|
||||
if recurse:
|
||||
if skipThis:
|
||||
childContainer: list[Node] | addnodes.desc = nodes
|
||||
if skip_this:
|
||||
child_container: list[Node] | addnodes.desc = nodes
|
||||
else:
|
||||
content = addnodes.desc_content()
|
||||
desc = addnodes.desc()
|
||||
@ -497,28 +545,31 @@ class AliasTransform(SphinxTransform):
|
||||
# 'desctype' is a backwards compatible attribute
|
||||
desc['objtype'] = desc['desctype'] = 'alias'
|
||||
desc['no-index'] = True
|
||||
childContainer = desc
|
||||
child_container = desc
|
||||
|
||||
for sChild in s.children:
|
||||
if sChild.declaration is None:
|
||||
for s_child in s.children:
|
||||
if s_child.declaration is None:
|
||||
continue
|
||||
childNodes = self._render_symbol(
|
||||
sChild, maxdepth=maxdepth, skipThis=False,
|
||||
aliasOptions=aliasOptions, renderOptions=renderOptions,
|
||||
document=document)
|
||||
childContainer.extend(childNodes)
|
||||
child_nodes = self._render_symbol(
|
||||
s_child,
|
||||
maxdepth=maxdepth,
|
||||
skip_this=False,
|
||||
alias_options=alias_options,
|
||||
render_options=render_options,
|
||||
document=document,
|
||||
)
|
||||
child_container.extend(child_nodes)
|
||||
|
||||
if not skipThis and len(desc.children) != 0:
|
||||
if not skip_this and len(desc.children) != 0:
|
||||
nodes.append(content)
|
||||
return nodes
|
||||
|
||||
def apply(self, **kwargs: Any) -> None:
|
||||
for node in self.document.findall(AliasNode):
|
||||
sig = node.sig
|
||||
parentKey = node.parentKey
|
||||
parent_key = node.parentKey
|
||||
try:
|
||||
parser = DefinitionParser(sig, location=node,
|
||||
config=self.env.config)
|
||||
parser = DefinitionParser(sig, location=node, config=self.env.config)
|
||||
name = parser.parse_xref_object()
|
||||
except DefinitionError as e:
|
||||
logger.warning(e, location=node)
|
||||
@ -532,25 +583,26 @@ class AliasTransform(SphinxTransform):
|
||||
node.replace_self(signode)
|
||||
continue
|
||||
|
||||
rootSymbol: Symbol = self.env.domains.c_domain.data['root_symbol']
|
||||
parentSymbol: Symbol | None = rootSymbol.direct_lookup(parentKey)
|
||||
if not parentSymbol:
|
||||
logger.debug("Target: %s", sig)
|
||||
logger.debug("ParentKey: %s", parentKey)
|
||||
logger.debug(rootSymbol.dump(1))
|
||||
assert parentSymbol # should be there
|
||||
root_symbol: Symbol = self.env.domains.c_domain.data['root_symbol']
|
||||
parent_symbol: Symbol | None = root_symbol.direct_lookup(parent_key)
|
||||
if not parent_symbol:
|
||||
logger.debug('Target: %s', sig)
|
||||
logger.debug('ParentKey: %s', parent_key)
|
||||
logger.debug(root_symbol.dump(1))
|
||||
assert parent_symbol # should be there
|
||||
|
||||
s = parentSymbol.find_declaration(
|
||||
name, 'any',
|
||||
matchSelf=True, recurseInAnon=True)
|
||||
s = parent_symbol.find_declaration(
|
||||
name, 'any', matchSelf=True, recurseInAnon=True
|
||||
)
|
||||
if s is None:
|
||||
signode = addnodes.desc_signature(sig, '')
|
||||
node.append(signode)
|
||||
signode.clear()
|
||||
signode += addnodes.desc_name(sig, sig)
|
||||
|
||||
logger.warning("Could not find C declaration for alias '%s'.", name,
|
||||
location=node)
|
||||
logger.warning(
|
||||
"Could not find C declaration for alias '%s'.", name, location=node
|
||||
)
|
||||
node.replace_self(signode)
|
||||
continue
|
||||
# Declarations like .. var:: int Missing::var
|
||||
@ -563,15 +615,21 @@ class AliasTransform(SphinxTransform):
|
||||
signode += addnodes.desc_name(sig, sig)
|
||||
|
||||
logger.warning(
|
||||
"Can not render C declaration for alias '%s'. No such declaration.", name,
|
||||
location=node)
|
||||
"Can not render C declaration for alias '%s'. No such declaration.",
|
||||
name,
|
||||
location=node,
|
||||
)
|
||||
node.replace_self(signode)
|
||||
continue
|
||||
|
||||
nodes = self._render_symbol(s, maxdepth=node.aliasOptions['maxdepth'],
|
||||
skipThis=node.aliasOptions['noroot'],
|
||||
aliasOptions=node.aliasOptions,
|
||||
renderOptions={}, document=node.document)
|
||||
nodes = self._render_symbol(
|
||||
s,
|
||||
maxdepth=node.aliasOptions['maxdepth'],
|
||||
skip_this=node.aliasOptions['noroot'],
|
||||
alias_options=node.aliasOptions,
|
||||
render_options={},
|
||||
document=node.document,
|
||||
)
|
||||
node.replace_self(nodes)
|
||||
|
||||
|
||||
@ -600,30 +658,40 @@ class CAliasObject(ObjectDescription):
|
||||
node['no-index'] = True
|
||||
|
||||
self.names: list[str] = []
|
||||
aliasOptions = {
|
||||
alias_options = {
|
||||
'maxdepth': self.options.get('maxdepth', 1),
|
||||
'noroot': 'noroot' in self.options,
|
||||
}
|
||||
if aliasOptions['noroot'] and aliasOptions['maxdepth'] == 1:
|
||||
logger.warning("Error in C alias declaration."
|
||||
" Requested 'noroot' but 'maxdepth' 1."
|
||||
" When skipping the root declaration,"
|
||||
" need 'maxdepth' 0 for infinite or at least 2.",
|
||||
location=self.get_location())
|
||||
if alias_options['noroot'] and alias_options['maxdepth'] == 1:
|
||||
logger.warning(
|
||||
'Error in C alias declaration.'
|
||||
" Requested 'noroot' but 'maxdepth' 1."
|
||||
' When skipping the root declaration,'
|
||||
" need 'maxdepth' 0 for infinite or at least 2.",
|
||||
location=self.get_location(),
|
||||
)
|
||||
for sig in self.get_signatures():
|
||||
node.append(AliasNode(sig, aliasOptions, self.state.document, env=self.env))
|
||||
node.append(
|
||||
AliasNode(sig, alias_options, self.state.document, env=self.env)
|
||||
)
|
||||
return [node]
|
||||
|
||||
|
||||
class CXRefRole(XRefRole):
|
||||
def process_link(self, env: BuildEnvironment, refnode: Element,
|
||||
has_explicit_title: bool, title: str, target: str) -> tuple[str, str]:
|
||||
def process_link(
|
||||
self,
|
||||
env: BuildEnvironment,
|
||||
refnode: Element,
|
||||
has_explicit_title: bool,
|
||||
title: str,
|
||||
target: str,
|
||||
) -> tuple[str, str]:
|
||||
refnode.attributes.update(env.ref_context)
|
||||
|
||||
if not has_explicit_title:
|
||||
# major hax: replace anon names via simple string manipulation.
|
||||
# Can this actually fail?
|
||||
title = anon_identifier_re.sub("[anonymous]", str(title))
|
||||
title = anon_identifier_re.sub('[anonymous]', str(title))
|
||||
|
||||
if not has_explicit_title:
|
||||
target = target.lstrip('~') # only has a meaning for the title
|
||||
@ -633,7 +701,7 @@ class CXRefRole(XRefRole):
|
||||
title = title[1:]
|
||||
dot = title.rfind('.')
|
||||
if dot != -1:
|
||||
title = title[dot + 1:]
|
||||
title = title[dot + 1 :]
|
||||
return title, target
|
||||
|
||||
|
||||
@ -649,23 +717,29 @@ class CExprRole(SphinxRole):
|
||||
|
||||
def run(self) -> tuple[list[Node], list[system_message]]:
|
||||
text = self.text.replace('\n', ' ')
|
||||
parser = DefinitionParser(text, location=self.get_location(),
|
||||
config=self.env.config)
|
||||
parser = DefinitionParser(
|
||||
text, location=self.get_location(), config=self.env.config
|
||||
)
|
||||
# attempt to mimic XRefRole classes, except that...
|
||||
try:
|
||||
ast = parser.parse_expression()
|
||||
except DefinitionError as ex:
|
||||
logger.warning('Unparseable C expression: %r\n%s', text, ex,
|
||||
location=self.get_location())
|
||||
logger.warning(
|
||||
'Unparseable C expression: %r\n%s',
|
||||
text,
|
||||
ex,
|
||||
location=self.get_location(),
|
||||
)
|
||||
# see below
|
||||
return [addnodes.desc_inline('c', text, text, classes=[self.class_type])], []
|
||||
parentSymbol = self.env.temp_data.get('c:parent_symbol', None)
|
||||
if parentSymbol is None:
|
||||
parentSymbol = self.env.domaindata['c']['root_symbol']
|
||||
node = addnodes.desc_inline('c', text, text, classes=[self.class_type])
|
||||
return [node], []
|
||||
parent_symbol = self.env.temp_data.get('c:parent_symbol', None)
|
||||
if parent_symbol is None:
|
||||
parent_symbol = self.env.domaindata['c']['root_symbol']
|
||||
# ...most if not all of these classes should really apply to the individual references,
|
||||
# not the container node
|
||||
signode = addnodes.desc_inline('c', classes=[self.class_type])
|
||||
ast.describe_signature(signode, 'markType', self.env, parentSymbol)
|
||||
ast.describe_signature(signode, 'markType', self.env, parent_symbol)
|
||||
return [signode], []
|
||||
|
||||
|
||||
@ -677,16 +751,18 @@ class CDomain(Domain):
|
||||
object_types = {
|
||||
# 'identifier' is the one used for xrefs generated in signatures, not in roles
|
||||
'member': ObjType(_('member'), 'var', 'member', 'data', 'identifier'),
|
||||
'var': ObjType(_('variable'), 'var', 'member', 'data', 'identifier'),
|
||||
'function': ObjType(_('function'), 'func', 'identifier', 'type'),
|
||||
'macro': ObjType(_('macro'), 'macro', 'identifier'),
|
||||
'struct': ObjType(_('struct'), 'struct', 'identifier', 'type'),
|
||||
'union': ObjType(_('union'), 'union', 'identifier', 'type'),
|
||||
'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'),
|
||||
'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'),
|
||||
'type': ObjType(_('type'), 'identifier', 'type'),
|
||||
'var': ObjType(_('variable'), 'var', 'member', 'data', 'identifier'),
|
||||
'function': ObjType(_('function'), 'func', 'identifier', 'type'),
|
||||
'macro': ObjType(_('macro'), 'macro', 'identifier'),
|
||||
'struct': ObjType(_('struct'), 'struct', 'identifier', 'type'),
|
||||
'union': ObjType(_('union'), 'union', 'identifier', 'type'),
|
||||
'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'),
|
||||
'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'),
|
||||
'type': ObjType(_('type'), 'identifier', 'type'),
|
||||
# generated object types
|
||||
'functionParam': ObjType(_('function parameter'), 'identifier', 'var', 'member', 'data'), # NoQA: E501
|
||||
'functionParam': ObjType(
|
||||
_('function parameter'), 'identifier', 'var', 'member', 'data'
|
||||
), # NoQA: E501
|
||||
}
|
||||
|
||||
directives = {
|
||||
@ -727,126 +803,156 @@ class CDomain(Domain):
|
||||
|
||||
def clear_doc(self, docname: str) -> None:
|
||||
if Symbol.debug_show_tree:
|
||||
logger.debug("clear_doc: %s", docname)
|
||||
logger.debug("\tbefore:")
|
||||
logger.debug('clear_doc: %s', docname)
|
||||
logger.debug('\tbefore:')
|
||||
logger.debug(self.data['root_symbol'].dump(1))
|
||||
logger.debug("\tbefore end")
|
||||
logger.debug('\tbefore end')
|
||||
|
||||
rootSymbol = self.data['root_symbol']
|
||||
rootSymbol.clear_doc(docname)
|
||||
root_symbol = self.data['root_symbol']
|
||||
root_symbol.clear_doc(docname)
|
||||
|
||||
if Symbol.debug_show_tree:
|
||||
logger.debug("\tafter:")
|
||||
logger.debug('\tafter:')
|
||||
logger.debug(self.data['root_symbol'].dump(1))
|
||||
logger.debug("\tafter end")
|
||||
logger.debug("clear_doc end: %s", docname)
|
||||
logger.debug('\tafter end')
|
||||
logger.debug('clear_doc end: %s', docname)
|
||||
|
||||
def process_doc(self, env: BuildEnvironment, docname: str,
|
||||
document: nodes.document) -> None:
|
||||
def process_doc(
|
||||
self, env: BuildEnvironment, docname: str, document: nodes.document
|
||||
) -> None:
|
||||
if Symbol.debug_show_tree:
|
||||
logger.debug("process_doc: %s", docname)
|
||||
logger.debug('process_doc: %s', docname)
|
||||
logger.debug(self.data['root_symbol'].dump(0))
|
||||
logger.debug("process_doc end: %s", docname)
|
||||
logger.debug('process_doc end: %s', docname)
|
||||
|
||||
def process_field_xref(self, pnode: pending_xref) -> None:
|
||||
pnode.attributes.update(self.env.ref_context)
|
||||
|
||||
def merge_domaindata(self, docnames: Set[str], otherdata: dict[str, Any]) -> None:
|
||||
if Symbol.debug_show_tree:
|
||||
logger.debug("merge_domaindata:")
|
||||
logger.debug("\tself:")
|
||||
logger.debug('merge_domaindata:')
|
||||
logger.debug('\tself:')
|
||||
logger.debug(self.data['root_symbol'].dump(1))
|
||||
logger.debug("\tself end")
|
||||
logger.debug("\tother:")
|
||||
logger.debug('\tself end')
|
||||
logger.debug('\tother:')
|
||||
logger.debug(otherdata['root_symbol'].dump(1))
|
||||
logger.debug("\tother end")
|
||||
logger.debug("merge_domaindata end")
|
||||
logger.debug('\tother end')
|
||||
logger.debug('merge_domaindata end')
|
||||
|
||||
self.data['root_symbol'].merge_with(otherdata['root_symbol'],
|
||||
docnames, self.env)
|
||||
ourObjects = self.data['objects']
|
||||
self.data['root_symbol'].merge_with(
|
||||
otherdata['root_symbol'], docnames, self.env
|
||||
)
|
||||
our_objects = self.data['objects']
|
||||
for fullname, (fn, id_, objtype) in otherdata['objects'].items():
|
||||
if fn in docnames:
|
||||
if fullname not in ourObjects:
|
||||
ourObjects[fullname] = (fn, id_, objtype)
|
||||
if fullname not in our_objects:
|
||||
our_objects[fullname] = (fn, id_, objtype)
|
||||
# no need to warn on duplicates, the symbol merge already does that
|
||||
|
||||
def _resolve_xref_inner(
|
||||
self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
||||
typ: str, target: str, node: pending_xref, contnode: Element
|
||||
self,
|
||||
env: BuildEnvironment,
|
||||
fromdocname: str,
|
||||
builder: Builder,
|
||||
typ: str,
|
||||
target: str,
|
||||
node: pending_xref,
|
||||
contnode: Element,
|
||||
) -> tuple[nodes.reference, str] | tuple[None, None]:
|
||||
parser = DefinitionParser(target, location=node, config=env.config)
|
||||
try:
|
||||
name = parser.parse_xref_object()
|
||||
except DefinitionError as e:
|
||||
logger.warning('Unparseable C cross-reference: %r\n%s', target, e,
|
||||
location=node)
|
||||
logger.warning(
|
||||
'Unparseable C cross-reference: %r\n%s', target, e, location=node
|
||||
)
|
||||
return None, None
|
||||
parentKey: LookupKey = node.get("c:parent_key", None)
|
||||
rootSymbol = self.data['root_symbol']
|
||||
if parentKey:
|
||||
parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
|
||||
if not parentSymbol:
|
||||
logger.debug("Target: %s", target)
|
||||
logger.debug("ParentKey: %s", parentKey)
|
||||
logger.debug(rootSymbol.dump(1))
|
||||
assert parentSymbol # should be there
|
||||
parent_key: LookupKey = node.get('c:parent_key', None)
|
||||
root_symbol = self.data['root_symbol']
|
||||
if parent_key:
|
||||
parent_symbol: Symbol = root_symbol.direct_lookup(parent_key)
|
||||
if not parent_symbol:
|
||||
logger.debug('Target: %s', target)
|
||||
logger.debug('ParentKey: %s', parent_key)
|
||||
logger.debug(root_symbol.dump(1))
|
||||
assert parent_symbol # should be there
|
||||
else:
|
||||
parentSymbol = rootSymbol
|
||||
s = parentSymbol.find_declaration(name, typ,
|
||||
matchSelf=True, recurseInAnon=True)
|
||||
parent_symbol = root_symbol
|
||||
s = parent_symbol.find_declaration(
|
||||
name, typ, matchSelf=True, recurseInAnon=True
|
||||
)
|
||||
if s is None or s.declaration is None:
|
||||
return None, None
|
||||
|
||||
# TODO: check role type vs. object type
|
||||
|
||||
declaration = s.declaration
|
||||
displayName = name.get_display_string()
|
||||
display_name = name.get_display_string()
|
||||
docname = s.docname
|
||||
assert docname
|
||||
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
declaration.get_newest_id(), contnode, displayName,
|
||||
), declaration.objectType
|
||||
return make_refnode(
|
||||
builder,
|
||||
fromdocname,
|
||||
docname,
|
||||
declaration.get_newest_id(),
|
||||
contnode,
|
||||
display_name,
|
||||
), declaration.objectType
|
||||
|
||||
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
||||
typ: str, target: str, node: pending_xref,
|
||||
contnode: Element) -> nodes.reference | None:
|
||||
return self._resolve_xref_inner(env, fromdocname, builder, typ,
|
||||
target, node, contnode)[0]
|
||||
def resolve_xref(
|
||||
self,
|
||||
env: BuildEnvironment,
|
||||
fromdocname: str,
|
||||
builder: Builder,
|
||||
typ: str,
|
||||
target: str,
|
||||
node: pending_xref,
|
||||
contnode: Element,
|
||||
) -> nodes.reference | None:
|
||||
return self._resolve_xref_inner(
|
||||
env, fromdocname, builder, typ, target, node, contnode
|
||||
)[0]
|
||||
|
||||
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
||||
target: str, node: pending_xref, contnode: Element,
|
||||
) -> list[tuple[str, nodes.reference]]:
|
||||
def resolve_any_xref(
|
||||
self,
|
||||
env: BuildEnvironment,
|
||||
fromdocname: str,
|
||||
builder: Builder,
|
||||
target: str,
|
||||
node: pending_xref,
|
||||
contnode: Element,
|
||||
) -> list[tuple[str, nodes.reference]]:
|
||||
with logging.suppress_logging():
|
||||
retnode, objtype = self._resolve_xref_inner(env, fromdocname, builder,
|
||||
'any', target, node, contnode)
|
||||
retnode, objtype = self._resolve_xref_inner(
|
||||
env, fromdocname, builder, 'any', target, node, contnode
|
||||
)
|
||||
if retnode:
|
||||
return [('c:' + self.role_for_objtype(objtype), retnode)]
|
||||
return []
|
||||
|
||||
def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]:
|
||||
rootSymbol = self.data['root_symbol']
|
||||
for symbol in rootSymbol.get_all_symbols():
|
||||
root_symbol = self.data['root_symbol']
|
||||
for symbol in root_symbol.get_all_symbols():
|
||||
if symbol.declaration is None:
|
||||
continue
|
||||
assert symbol.docname
|
||||
fullNestedName = symbol.get_full_nested_name()
|
||||
name = str(fullNestedName).lstrip('.')
|
||||
dispname = fullNestedName.get_display_string().lstrip('.')
|
||||
objectType = symbol.declaration.objectType
|
||||
full_nested_name = symbol.get_full_nested_name()
|
||||
name = str(full_nested_name).lstrip('.')
|
||||
dispname = full_nested_name.get_display_string().lstrip('.')
|
||||
object_type = symbol.declaration.objectType
|
||||
docname = symbol.docname
|
||||
newestId = symbol.declaration.get_newest_id()
|
||||
yield name, dispname, objectType, docname, newestId, 1
|
||||
newest_id = symbol.declaration.get_newest_id()
|
||||
yield name, dispname, object_type, docname, newest_id, 1
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> ExtensionMetadata:
|
||||
app.add_domain(CDomain)
|
||||
app.add_config_value("c_id_attributes", [], 'env', types={list, tuple})
|
||||
app.add_config_value("c_paren_attributes", [], 'env', types={list, tuple})
|
||||
app.add_config_value("c_extra_keywords", _macroKeywords, 'env', types={set, list})
|
||||
app.add_config_value('c_id_attributes', [], 'env', types={list, tuple})
|
||||
app.add_config_value('c_paren_attributes', [], 'env', types={list, tuple})
|
||||
app.add_config_value('c_extra_keywords', _macroKeywords, 'env', types={set, list})
|
||||
app.add_config_value(
|
||||
"c_maximum_signature_line_length", None, 'env', types={int, type(None)}
|
||||
'c_maximum_signature_line_length', None, 'env', types={int, type(None)}
|
||||
)
|
||||
app.add_post_transform(AliasTransform)
|
||||
|
||||
|
@ -26,20 +26,27 @@ if TYPE_CHECKING:
|
||||
from sphinx.util.cfamily import StringifyTransform
|
||||
|
||||
DeclarationType: TypeAlias = Union[ # NoQA: UP007
|
||||
"ASTStruct", "ASTUnion", "ASTEnum", "ASTEnumerator",
|
||||
"ASTType", "ASTTypeWithInit", "ASTMacro",
|
||||
'ASTStruct',
|
||||
'ASTUnion',
|
||||
'ASTEnum',
|
||||
'ASTEnumerator',
|
||||
'ASTType',
|
||||
'ASTTypeWithInit',
|
||||
'ASTMacro',
|
||||
]
|
||||
|
||||
|
||||
class ASTBase(ASTBaseBase):
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
raise NotImplementedError(repr(self))
|
||||
|
||||
|
||||
# Names
|
||||
################################################################################
|
||||
|
||||
|
||||
class ASTIdentifier(ASTBaseBase):
|
||||
def __init__(self, name: str) -> None:
|
||||
if not isinstance(name, str) or len(name) == 0:
|
||||
@ -66,25 +73,35 @@ class ASTIdentifier(ASTBaseBase):
|
||||
return self.name
|
||||
|
||||
def get_display_string(self) -> str:
|
||||
return "[anonymous]" if self.is_anonymous else self.name
|
||||
return '[anonymous]' if self.is_anonymous else self.name
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return transform(self.get_display_string())
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str, env: BuildEnvironment,
|
||||
prefix: str, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self,
|
||||
signode: TextElement,
|
||||
mode: str,
|
||||
env: BuildEnvironment,
|
||||
prefix: str,
|
||||
symbol: Symbol,
|
||||
) -> None:
|
||||
# note: slightly different signature of describe_signature due to the prefix
|
||||
verify_description_mode(mode)
|
||||
if self.is_anonymous:
|
||||
node = addnodes.desc_sig_name(text="[anonymous]")
|
||||
node = addnodes.desc_sig_name(text='[anonymous]')
|
||||
else:
|
||||
node = addnodes.desc_sig_name(self.name, self.name)
|
||||
if mode == 'markType':
|
||||
target_text = prefix + self.name
|
||||
pnode = addnodes.pending_xref('', refdomain='c',
|
||||
reftype='identifier',
|
||||
reftarget=target_text, modname=None,
|
||||
classname=None)
|
||||
pnode = addnodes.pending_xref(
|
||||
'',
|
||||
refdomain='c',
|
||||
reftype='identifier',
|
||||
reftarget=target_text,
|
||||
modname=None,
|
||||
classname=None,
|
||||
)
|
||||
pnode['c:parent_key'] = symbol.get_lookup_key()
|
||||
pnode += node
|
||||
signode += pnode
|
||||
@ -101,7 +118,8 @@ class ASTIdentifier(ASTBaseBase):
|
||||
def identifier(self) -> str:
|
||||
warnings.warn(
|
||||
'`ASTIdentifier.identifier` is deprecated, use `ASTIdentifier.name` instead',
|
||||
DeprecationWarning, stacklevel=2,
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.name
|
||||
|
||||
@ -134,18 +152,19 @@ class ASTNestedName(ASTBase):
|
||||
else:
|
||||
return res
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
# just print the name part, with template args, not template params
|
||||
if mode == 'noneIsName':
|
||||
if self.rooted:
|
||||
unreachable = "Can this happen?"
|
||||
unreachable = 'Can this happen?'
|
||||
raise AssertionError(unreachable) # TODO
|
||||
signode += nodes.Text('.')
|
||||
for i in range(len(self.names)):
|
||||
if i != 0:
|
||||
unreachable = "Can this happen?"
|
||||
unreachable = 'Can this happen?'
|
||||
raise AssertionError(unreachable) # TODO
|
||||
signode += nodes.Text('.')
|
||||
n = self.names[i]
|
||||
@ -197,6 +216,7 @@ class ASTNestedName(ASTBase):
|
||||
# Expressions
|
||||
################################################################################
|
||||
|
||||
|
||||
class ASTExpression(ASTBase):
|
||||
pass
|
||||
|
||||
@ -204,6 +224,7 @@ class ASTExpression(ASTBase):
|
||||
# Primary expressions
|
||||
################################################################################
|
||||
|
||||
|
||||
class ASTLiteral(ASTExpression):
|
||||
pass
|
||||
|
||||
@ -226,8 +247,9 @@ class ASTBooleanLiteral(ASTLiteral):
|
||||
else:
|
||||
return 'false'
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
txt = str(self)
|
||||
signode += addnodes.desc_sig_keyword(txt, txt)
|
||||
|
||||
@ -247,8 +269,9 @@ class ASTNumberLiteral(ASTLiteral):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return self.data
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
txt = str(self)
|
||||
signode += addnodes.desc_sig_literal_number(txt, txt)
|
||||
|
||||
@ -266,10 +289,7 @@ class ASTCharLiteral(ASTLiteral):
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, ASTCharLiteral):
|
||||
return NotImplemented
|
||||
return (
|
||||
self.prefix == other.prefix
|
||||
and self.value == other.value
|
||||
)
|
||||
return self.prefix == other.prefix and self.value == other.value
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.prefix, self.value))
|
||||
@ -280,8 +300,9 @@ class ASTCharLiteral(ASTLiteral):
|
||||
else:
|
||||
return self.prefix + "'" + self.data + "'"
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
txt = str(self)
|
||||
signode += addnodes.desc_sig_literal_char(txt, txt)
|
||||
|
||||
@ -301,8 +322,9 @@ class ASTStringLiteral(ASTLiteral):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return self.data
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
txt = str(self)
|
||||
signode += addnodes.desc_sig_literal_string(txt, txt)
|
||||
|
||||
@ -326,8 +348,9 @@ class ASTIdExpression(ASTExpression):
|
||||
def get_id(self, version: int) -> str:
|
||||
return self.name.get_id(version)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
self.name.describe_signature(signode, mode, env, symbol)
|
||||
|
||||
|
||||
@ -349,8 +372,9 @@ class ASTParenExpr(ASTExpression):
|
||||
def get_id(self, version: int) -> str:
|
||||
return self.expr.get_id(version) # type: ignore[attr-defined]
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
signode += addnodes.desc_sig_punctuation('(', '(')
|
||||
self.expr.describe_signature(signode, mode, env, symbol)
|
||||
signode += addnodes.desc_sig_punctuation(')', ')')
|
||||
@ -359,6 +383,7 @@ class ASTParenExpr(ASTExpression):
|
||||
# Postfix expressions
|
||||
################################################################################
|
||||
|
||||
|
||||
class ASTPostfixOp(ASTBase):
|
||||
pass
|
||||
|
||||
@ -378,8 +403,9 @@ class ASTPostfixCallExpr(ASTPostfixOp):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return transform(self.lst)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
self.lst.describe_signature(signode, mode, env, symbol)
|
||||
|
||||
|
||||
@ -398,8 +424,9 @@ class ASTPostfixArray(ASTPostfixOp):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return '[' + transform(self.expr) + ']'
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
signode += addnodes.desc_sig_punctuation('[', '[')
|
||||
self.expr.describe_signature(signode, mode, env, symbol)
|
||||
signode += addnodes.desc_sig_punctuation(']', ']')
|
||||
@ -409,8 +436,9 @@ class ASTPostfixInc(ASTPostfixOp):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return '++'
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
signode += addnodes.desc_sig_operator('++', '++')
|
||||
|
||||
|
||||
@ -418,8 +446,9 @@ class ASTPostfixDec(ASTPostfixOp):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return '--'
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
signode += addnodes.desc_sig_operator('--', '--')
|
||||
|
||||
|
||||
@ -438,8 +467,9 @@ class ASTPostfixMemberOfPointer(ASTPostfixOp):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return '->' + transform(self.name)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
signode += addnodes.desc_sig_operator('->', '->')
|
||||
self.name.describe_signature(signode, 'noneIsName', env, symbol)
|
||||
|
||||
@ -458,10 +488,14 @@ class ASTPostfixExpr(ASTExpression):
|
||||
return hash((self.prefix, self.postFixes))
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return ''.join([transform(self.prefix), *(transform(p) for p in self.postFixes)])
|
||||
return ''.join([
|
||||
transform(self.prefix),
|
||||
*(transform(p) for p in self.postFixes),
|
||||
])
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
self.prefix.describe_signature(signode, mode, env, symbol)
|
||||
for p in self.postFixes:
|
||||
p.describe_signature(signode, mode, env, symbol)
|
||||
@ -470,6 +504,7 @@ class ASTPostfixExpr(ASTExpression):
|
||||
# Unary expressions
|
||||
################################################################################
|
||||
|
||||
|
||||
class ASTUnaryOpExpr(ASTExpression):
|
||||
def __init__(self, op: str, expr: ASTExpression) -> None:
|
||||
self.op = op
|
||||
@ -485,12 +520,13 @@ class ASTUnaryOpExpr(ASTExpression):
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
if self.op[0] in 'cn':
|
||||
return self.op + " " + transform(self.expr)
|
||||
return self.op + ' ' + transform(self.expr)
|
||||
else:
|
||||
return self.op + transform(self.expr)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
if self.op[0] in 'cn':
|
||||
signode += addnodes.desc_sig_keyword(self.op, self.op)
|
||||
signode += addnodes.desc_sig_space()
|
||||
@ -512,10 +548,11 @@ class ASTSizeofType(ASTExpression):
|
||||
return hash(self.typ)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return "sizeof(" + transform(self.typ) + ")"
|
||||
return 'sizeof(' + transform(self.typ) + ')'
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
|
||||
signode += addnodes.desc_sig_punctuation('(', '(')
|
||||
self.typ.describe_signature(signode, mode, env, symbol)
|
||||
@ -535,10 +572,11 @@ class ASTSizeofExpr(ASTExpression):
|
||||
return hash(self.expr)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return "sizeof " + transform(self.expr)
|
||||
return 'sizeof ' + transform(self.expr)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
|
||||
signode += addnodes.desc_sig_space()
|
||||
self.expr.describe_signature(signode, mode, env, symbol)
|
||||
@ -557,10 +595,11 @@ class ASTAlignofExpr(ASTExpression):
|
||||
return hash(self.typ)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return "alignof(" + transform(self.typ) + ")"
|
||||
return 'alignof(' + transform(self.typ) + ')'
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
signode += addnodes.desc_sig_keyword('alignof', 'alignof')
|
||||
signode += addnodes.desc_sig_punctuation('(', '(')
|
||||
self.typ.describe_signature(signode, mode, env, symbol)
|
||||
@ -570,6 +609,7 @@ class ASTAlignofExpr(ASTExpression):
|
||||
# Other expressions
|
||||
################################################################################
|
||||
|
||||
|
||||
class ASTCastExpr(ASTExpression):
|
||||
def __init__(self, typ: ASTType, expr: ASTExpression) -> None:
|
||||
self.typ = typ
|
||||
@ -578,10 +618,7 @@ class ASTCastExpr(ASTExpression):
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, ASTCastExpr):
|
||||
return NotImplemented
|
||||
return (
|
||||
self.typ == other.typ
|
||||
and self.expr == other.expr
|
||||
)
|
||||
return self.typ == other.typ and self.expr == other.expr
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.typ, self.expr))
|
||||
@ -593,8 +630,9 @@ class ASTCastExpr(ASTExpression):
|
||||
res.append(transform(self.expr))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
signode += addnodes.desc_sig_punctuation('(', '(')
|
||||
self.typ.describe_signature(signode, mode, env, symbol)
|
||||
signode += addnodes.desc_sig_punctuation(')', ')')
|
||||
@ -611,10 +649,7 @@ class ASTBinOpExpr(ASTBase):
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, ASTBinOpExpr):
|
||||
return NotImplemented
|
||||
return (
|
||||
self.exprs == other.exprs
|
||||
and self.ops == other.ops
|
||||
)
|
||||
return self.exprs == other.exprs and self.ops == other.ops
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.exprs, self.ops))
|
||||
@ -629,8 +664,9 @@ class ASTBinOpExpr(ASTBase):
|
||||
res.append(transform(self.exprs[i]))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
self.exprs[0].describe_signature(signode, mode, env, symbol)
|
||||
for i in range(1, len(self.exprs)):
|
||||
signode += addnodes.desc_sig_space()
|
||||
@ -653,10 +689,7 @@ class ASTAssignmentExpr(ASTExpression):
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, ASTAssignmentExpr):
|
||||
return NotImplemented
|
||||
return (
|
||||
self.exprs == other.exprs
|
||||
and self.ops == other.ops
|
||||
)
|
||||
return self.exprs == other.exprs and self.ops == other.ops
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.exprs, self.ops))
|
||||
@ -671,8 +704,9 @@ class ASTAssignmentExpr(ASTExpression):
|
||||
res.append(transform(self.exprs[i]))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
self.exprs[0].describe_signature(signode, mode, env, symbol)
|
||||
for i in range(1, len(self.exprs)):
|
||||
signode += addnodes.desc_sig_space()
|
||||
@ -703,8 +737,9 @@ class ASTFallbackExpr(ASTExpression):
|
||||
def get_id(self, version: int) -> str:
|
||||
return str(self.expr)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
signode += nodes.literal(self.expr, self.expr)
|
||||
|
||||
|
||||
@ -712,6 +747,7 @@ class ASTFallbackExpr(ASTExpression):
|
||||
# Types
|
||||
################################################################################
|
||||
|
||||
|
||||
class ASTTrailingTypeSpec(ASTBase):
|
||||
pass
|
||||
|
||||
@ -732,8 +768,9 @@ class ASTTrailingTypeSpecFundamental(ASTTrailingTypeSpec):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return ' '.join(self.names)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
first = True
|
||||
for n in self.names:
|
||||
if not first:
|
||||
@ -751,10 +788,7 @@ class ASTTrailingTypeSpecName(ASTTrailingTypeSpec):
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, ASTTrailingTypeSpecName):
|
||||
return NotImplemented
|
||||
return (
|
||||
self.prefix == other.prefix
|
||||
and self.nestedName == other.nestedName
|
||||
)
|
||||
return self.prefix == other.prefix and self.nestedName == other.nestedName
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.prefix, self.nestedName))
|
||||
@ -771,8 +805,9 @@ class ASTTrailingTypeSpecName(ASTTrailingTypeSpec):
|
||||
res.append(transform(self.nestedName))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
if self.prefix:
|
||||
signode += addnodes.desc_sig_keyword(self.prefix, self.prefix)
|
||||
signode += addnodes.desc_sig_space()
|
||||
@ -802,8 +837,9 @@ class ASTFunctionParameter(ASTBase):
|
||||
else:
|
||||
return transform(self.arg)
|
||||
|
||||
def describe_signature(self, signode: Any, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: Any, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
if self.ellipsis:
|
||||
signode += addnodes.desc_sig_punctuation('...', '...')
|
||||
@ -812,7 +848,9 @@ class ASTFunctionParameter(ASTBase):
|
||||
|
||||
|
||||
class ASTParameters(ASTBase):
|
||||
def __init__(self, args: list[ASTFunctionParameter], attrs: ASTAttributeList) -> None:
|
||||
def __init__(
|
||||
self, args: list[ASTFunctionParameter], attrs: ASTAttributeList
|
||||
) -> None:
|
||||
self.args = args
|
||||
self.attrs = attrs
|
||||
|
||||
@ -843,8 +881,9 @@ class ASTParameters(ASTBase):
|
||||
res.append(transform(self.attrs))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
multi_line_parameter_list = False
|
||||
test_node: Element = signode
|
||||
@ -852,7 +891,9 @@ class ASTParameters(ASTBase):
|
||||
if not isinstance(test_node, addnodes.desc_signature):
|
||||
test_node = test_node.parent
|
||||
continue
|
||||
multi_line_parameter_list = test_node.get('multi_line_parameter_list', False)
|
||||
multi_line_parameter_list = test_node.get(
|
||||
'multi_line_parameter_list', False
|
||||
)
|
||||
break
|
||||
|
||||
# only use the desc_parameterlist for the outer list, not for inner lists
|
||||
@ -881,8 +922,16 @@ class ASTParameters(ASTBase):
|
||||
|
||||
|
||||
class ASTDeclSpecsSimple(ASTBaseBase):
|
||||
def __init__(self, storage: str, threadLocal: str, inline: bool,
|
||||
restrict: bool, volatile: bool, const: bool, attrs: ASTAttributeList) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
storage: str,
|
||||
threadLocal: str,
|
||||
inline: bool,
|
||||
restrict: bool,
|
||||
volatile: bool,
|
||||
const: bool,
|
||||
attrs: ASTAttributeList,
|
||||
) -> None:
|
||||
self.storage = storage
|
||||
self.threadLocal = threadLocal
|
||||
self.inline = inline
|
||||
@ -918,13 +967,15 @@ class ASTDeclSpecsSimple(ASTBaseBase):
|
||||
def mergeWith(self, other: ASTDeclSpecsSimple) -> ASTDeclSpecsSimple:
|
||||
if not other:
|
||||
return self
|
||||
return ASTDeclSpecsSimple(self.storage or other.storage,
|
||||
self.threadLocal or other.threadLocal,
|
||||
self.inline or other.inline,
|
||||
self.volatile or other.volatile,
|
||||
self.const or other.const,
|
||||
self.restrict or other.restrict,
|
||||
self.attrs + other.attrs)
|
||||
return ASTDeclSpecsSimple(
|
||||
self.storage or other.storage,
|
||||
self.threadLocal or other.threadLocal,
|
||||
self.inline or other.inline,
|
||||
self.volatile or other.volatile,
|
||||
self.const or other.const,
|
||||
self.restrict or other.restrict,
|
||||
self.attrs + other.attrs,
|
||||
)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
res: list[str] = []
|
||||
@ -970,10 +1021,13 @@ class ASTDeclSpecsSimple(ASTBaseBase):
|
||||
|
||||
|
||||
class ASTDeclSpecs(ASTBase):
|
||||
def __init__(self, outer: str,
|
||||
leftSpecs: ASTDeclSpecsSimple,
|
||||
rightSpecs: ASTDeclSpecsSimple,
|
||||
trailing: ASTTrailingTypeSpec) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
outer: str,
|
||||
leftSpecs: ASTDeclSpecsSimple,
|
||||
rightSpecs: ASTDeclSpecsSimple,
|
||||
trailing: ASTTrailingTypeSpec,
|
||||
) -> None:
|
||||
# leftSpecs and rightSpecs are used for output
|
||||
# allSpecs are used for id generation TODO: remove?
|
||||
self.outer = outer
|
||||
@ -1007,17 +1061,18 @@ class ASTDeclSpecs(ASTBase):
|
||||
res.append(l)
|
||||
if self.trailingTypeSpec:
|
||||
if len(res) > 0:
|
||||
res.append(" ")
|
||||
res.append(' ')
|
||||
res.append(transform(self.trailingTypeSpec))
|
||||
r = str(self.rightSpecs)
|
||||
if len(r) > 0:
|
||||
if len(res) > 0:
|
||||
res.append(" ")
|
||||
res.append(' ')
|
||||
res.append(r)
|
||||
return "".join(res)
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
modifiers: list[Node] = []
|
||||
|
||||
@ -1028,8 +1083,7 @@ class ASTDeclSpecs(ASTBase):
|
||||
if self.trailingTypeSpec:
|
||||
if len(modifiers) > 0:
|
||||
signode += addnodes.desc_sig_space()
|
||||
self.trailingTypeSpec.describe_signature(signode, mode, env,
|
||||
symbol=symbol)
|
||||
self.trailingTypeSpec.describe_signature(signode, mode, env, symbol=symbol)
|
||||
modifiers = []
|
||||
self.rightSpecs.describe_signature(modifiers)
|
||||
if len(modifiers) > 0:
|
||||
@ -1041,9 +1095,17 @@ class ASTDeclSpecs(ASTBase):
|
||||
# Declarator
|
||||
################################################################################
|
||||
|
||||
|
||||
class ASTArray(ASTBase):
|
||||
def __init__(self, static: bool, const: bool, volatile: bool, restrict: bool,
|
||||
vla: bool, size: ASTExpression) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
static: bool,
|
||||
const: bool,
|
||||
volatile: bool,
|
||||
restrict: bool,
|
||||
vla: bool,
|
||||
size: ASTExpression,
|
||||
) -> None:
|
||||
self.static = static
|
||||
self.const = const
|
||||
self.volatile = volatile
|
||||
@ -1093,8 +1155,9 @@ class ASTArray(ASTBase):
|
||||
el.append(transform(self.size))
|
||||
return '[' + ' '.join(el) + ']'
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
signode += addnodes.desc_sig_punctuation('[', '[')
|
||||
add_space = False
|
||||
@ -1136,8 +1199,9 @@ class ASTDeclarator(ASTBase):
|
||||
|
||||
|
||||
class ASTDeclaratorNameParam(ASTDeclarator):
|
||||
def __init__(self, declId: ASTNestedName,
|
||||
arrayOps: list[ASTArray], param: ASTParameters) -> None:
|
||||
def __init__(
|
||||
self, declId: ASTNestedName, arrayOps: list[ASTArray], param: ASTParameters
|
||||
) -> None:
|
||||
self.declId = declId
|
||||
self.arrayOps = arrayOps
|
||||
self.param = param
|
||||
@ -1176,8 +1240,9 @@ class ASTDeclaratorNameParam(ASTDeclarator):
|
||||
res.append(transform(self.param))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
if self.declId:
|
||||
self.declId.describe_signature(signode, mode, env, symbol)
|
||||
@ -1213,12 +1278,13 @@ class ASTDeclaratorNameBitField(ASTDeclarator):
|
||||
res = []
|
||||
if self.declId:
|
||||
res.append(transform(self.declId))
|
||||
res.append(" : ")
|
||||
res.append(' : ')
|
||||
res.append(transform(self.size))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
if self.declId:
|
||||
self.declId.describe_signature(signode, mode, env, symbol)
|
||||
@ -1229,8 +1295,14 @@ class ASTDeclaratorNameBitField(ASTDeclarator):
|
||||
|
||||
|
||||
class ASTDeclaratorPtr(ASTDeclarator):
|
||||
def __init__(self, next: ASTDeclarator, restrict: bool, volatile: bool, const: bool,
|
||||
attrs: ASTAttributeList) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
next: ASTDeclarator,
|
||||
restrict: bool,
|
||||
volatile: bool,
|
||||
const: bool,
|
||||
attrs: ASTAttributeList,
|
||||
) -> None:
|
||||
assert next
|
||||
self.next = next
|
||||
self.restrict = restrict
|
||||
@ -1261,9 +1333,13 @@ class ASTDeclaratorPtr(ASTDeclarator):
|
||||
return self.next.function_params
|
||||
|
||||
def require_space_after_declSpecs(self) -> bool:
|
||||
return self.const or self.volatile or self.restrict or \
|
||||
len(self.attrs) > 0 or \
|
||||
self.next.require_space_after_declSpecs()
|
||||
return (
|
||||
self.const
|
||||
or self.volatile
|
||||
or self.restrict
|
||||
or len(self.attrs) > 0
|
||||
or self.next.require_space_after_declSpecs()
|
||||
)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
res = ['*']
|
||||
@ -1286,8 +1362,9 @@ class ASTDeclaratorPtr(ASTDeclarator):
|
||||
res.append(transform(self.next))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
signode += addnodes.desc_sig_punctuation('*', '*')
|
||||
self.attrs.describe_signature(signode)
|
||||
@ -1347,18 +1424,20 @@ class ASTDeclaratorParen(ASTDeclarator):
|
||||
res.append(transform(self.next))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
signode += addnodes.desc_sig_punctuation('(', '(')
|
||||
self.inner.describe_signature(signode, mode, env, symbol)
|
||||
signode += addnodes.desc_sig_punctuation(')', ')')
|
||||
self.next.describe_signature(signode, "noneIsName", env, symbol)
|
||||
self.next.describe_signature(signode, 'noneIsName', env, symbol)
|
||||
|
||||
|
||||
# Initializer
|
||||
################################################################################
|
||||
|
||||
|
||||
class ASTParenExprList(ASTBaseParenExprList):
|
||||
def __init__(self, exprs: list[ASTExpression]) -> None:
|
||||
self.exprs = exprs
|
||||
@ -1375,8 +1454,9 @@ class ASTParenExprList(ASTBaseParenExprList):
|
||||
exprs = [transform(e) for e in self.exprs]
|
||||
return '(%s)' % ', '.join(exprs)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
signode += addnodes.desc_sig_punctuation('(', '(')
|
||||
first = True
|
||||
@ -1408,8 +1488,9 @@ class ASTBracedInitList(ASTBase):
|
||||
trailing_comma = ',' if self.trailingComma else ''
|
||||
return f'{{{exprs}{trailing_comma}}}'
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
signode += addnodes.desc_sig_punctuation('{', '{')
|
||||
first = True
|
||||
@ -1426,8 +1507,9 @@ class ASTBracedInitList(ASTBase):
|
||||
|
||||
|
||||
class ASTInitializer(ASTBase):
|
||||
def __init__(self, value: ASTBracedInitList | ASTExpression,
|
||||
hasAssign: bool = True) -> None:
|
||||
def __init__(
|
||||
self, value: ASTBracedInitList | ASTExpression, hasAssign: bool = True
|
||||
) -> None:
|
||||
self.value = value
|
||||
self.hasAssign = hasAssign
|
||||
|
||||
@ -1446,8 +1528,9 @@ class ASTInitializer(ASTBase):
|
||||
else:
|
||||
return val
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
if self.hasAssign:
|
||||
signode += addnodes.desc_sig_space()
|
||||
@ -1497,12 +1580,12 @@ class ASTType(ASTBase):
|
||||
else:
|
||||
return 'type'
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
self.declSpecs.describe_signature(signode, 'markType', env, symbol)
|
||||
if (self.decl.require_space_after_declSpecs() and
|
||||
len(str(self.declSpecs)) > 0):
|
||||
if self.decl.require_space_after_declSpecs() and len(str(self.declSpecs)) > 0:
|
||||
signode += addnodes.desc_sig_space()
|
||||
# for parameters that don't really declare new names we get 'markType',
|
||||
# this should not be propagated, but be 'noneIsName'.
|
||||
@ -1538,8 +1621,9 @@ class ASTTypeWithInit(ASTBase):
|
||||
res.append(transform(self.init))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
self.type.describe_signature(signode, mode, env, symbol)
|
||||
if self.init:
|
||||
@ -1547,8 +1631,9 @@ class ASTTypeWithInit(ASTBase):
|
||||
|
||||
|
||||
class ASTMacroParameter(ASTBase):
|
||||
def __init__(self, arg: ASTNestedName | None, ellipsis: bool = False,
|
||||
variadic: bool = False) -> None:
|
||||
def __init__(
|
||||
self, arg: ASTNestedName | None, ellipsis: bool = False, variadic: bool = False
|
||||
) -> None:
|
||||
self.arg = arg
|
||||
self.ellipsis = ellipsis
|
||||
self.variadic = variadic
|
||||
@ -1573,8 +1658,9 @@ class ASTMacroParameter(ASTBase):
|
||||
else:
|
||||
return transform(self.arg)
|
||||
|
||||
def describe_signature(self, signode: Any, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: Any, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
if self.ellipsis:
|
||||
signode += addnodes.desc_sig_punctuation('...', '...')
|
||||
@ -1586,7 +1672,9 @@ class ASTMacroParameter(ASTBase):
|
||||
|
||||
|
||||
class ASTMacro(ASTBase):
|
||||
def __init__(self, ident: ASTNestedName, args: list[ASTMacroParameter] | None) -> None:
|
||||
def __init__(
|
||||
self, ident: ASTNestedName, args: list[ASTMacroParameter] | None
|
||||
) -> None:
|
||||
self.ident = ident
|
||||
self.args = args
|
||||
|
||||
@ -1619,8 +1707,9 @@ class ASTMacro(ASTBase):
|
||||
res.append(')')
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
self.ident.describe_signature(signode, mode, env, symbol)
|
||||
if self.args is None:
|
||||
@ -1651,8 +1740,9 @@ class ASTStruct(ASTBase):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return transform(self.name)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
self.name.describe_signature(signode, mode, env, symbol=symbol)
|
||||
|
||||
@ -1675,8 +1765,9 @@ class ASTUnion(ASTBase):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return transform(self.name)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
self.name.describe_signature(signode, mode, env, symbol=symbol)
|
||||
|
||||
@ -1699,15 +1790,17 @@ class ASTEnum(ASTBase):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return transform(self.name)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
self.name.describe_signature(signode, mode, env, symbol=symbol)
|
||||
|
||||
|
||||
class ASTEnumerator(ASTBase):
|
||||
def __init__(self, name: ASTNestedName, init: ASTInitializer | None,
|
||||
attrs: ASTAttributeList) -> None:
|
||||
def __init__(
|
||||
self, name: ASTNestedName, init: ASTInitializer | None, attrs: ASTAttributeList
|
||||
) -> None:
|
||||
self.name = name
|
||||
self.init = init
|
||||
self.attrs = attrs
|
||||
@ -1737,8 +1830,9 @@ class ASTEnumerator(ASTBase):
|
||||
res.append(transform(self.init))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, symbol: Symbol) -> None:
|
||||
def describe_signature(
|
||||
self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
self.name.describe_signature(signode, mode, env, symbol)
|
||||
if len(self.attrs) != 0:
|
||||
@ -1749,9 +1843,13 @@ class ASTEnumerator(ASTBase):
|
||||
|
||||
|
||||
class ASTDeclaration(ASTBaseBase):
|
||||
def __init__(self, objectType: str, directiveType: str | None,
|
||||
declaration: DeclarationType | ASTFunctionParameter,
|
||||
semicolon: bool = False) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
objectType: str,
|
||||
directiveType: str | None,
|
||||
declaration: DeclarationType | ASTFunctionParameter,
|
||||
semicolon: bool = False,
|
||||
) -> None:
|
||||
self.objectType = objectType
|
||||
self.directiveType = directiveType
|
||||
self.declaration = declaration
|
||||
@ -1788,8 +1886,12 @@ class ASTDeclaration(ASTBaseBase):
|
||||
))
|
||||
|
||||
def clone(self) -> ASTDeclaration:
|
||||
return ASTDeclaration(self.objectType, self.directiveType,
|
||||
self.declaration.clone(), self.semicolon)
|
||||
return ASTDeclaration(
|
||||
self.objectType,
|
||||
self.directiveType,
|
||||
self.declaration.clone(),
|
||||
self.semicolon,
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self) -> ASTNestedName:
|
||||
@ -1823,8 +1925,13 @@ class ASTDeclaration(ASTBaseBase):
|
||||
res += ';'
|
||||
return res
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: BuildEnvironment, options: dict[str, bool]) -> None:
|
||||
def describe_signature(
|
||||
self,
|
||||
signode: TextElement,
|
||||
mode: str,
|
||||
env: BuildEnvironment,
|
||||
options: dict[str, bool],
|
||||
) -> None:
|
||||
verify_description_mode(mode)
|
||||
assert self.symbol
|
||||
# The caller of the domain added a desc_signature node.
|
||||
|
@ -4,18 +4,41 @@ import re
|
||||
|
||||
# https://en.cppreference.com/w/c/keyword
|
||||
_keywords = [
|
||||
'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', 'double',
|
||||
'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'inline', 'int', 'long',
|
||||
'register', 'restrict', 'return', 'short', 'signed', 'sizeof', 'static', 'struct',
|
||||
'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while',
|
||||
'_Alignas', '_Alignof', '_Atomic', '_Bool', '_Complex',
|
||||
'auto',
|
||||
'break',
|
||||
'case', 'char', 'const', 'continue',
|
||||
'default', 'do', 'double',
|
||||
'else', 'enum', 'extern',
|
||||
'float', 'for',
|
||||
'goto',
|
||||
'if', 'inline', 'int',
|
||||
'long',
|
||||
'register', 'restrict', 'return',
|
||||
'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
|
||||
'typedef',
|
||||
'union', 'unsigned',
|
||||
'void', 'volatile',
|
||||
'while',
|
||||
'_Alignas', '_Alignof', '_Atomic',
|
||||
'_Bool',
|
||||
'_Complex',
|
||||
'_Decimal32', '_Decimal64', '_Decimal128',
|
||||
'_Generic', '_Imaginary', '_Noreturn', '_Static_assert', '_Thread_local',
|
||||
]
|
||||
'_Generic',
|
||||
'_Imaginary',
|
||||
'_Noreturn',
|
||||
'_Static_assert',
|
||||
'_Thread_local',
|
||||
] # fmt: skip
|
||||
# These are only keyword'y when the corresponding headers are included.
|
||||
# They are used as default value for c_extra_keywords.
|
||||
_macroKeywords = [
|
||||
'alignas', 'alignof', 'bool', 'complex', 'imaginary', 'noreturn', 'static_assert',
|
||||
'alignas',
|
||||
'alignof',
|
||||
'bool',
|
||||
'complex',
|
||||
'imaginary',
|
||||
'noreturn',
|
||||
'static_assert',
|
||||
'thread_local',
|
||||
]
|
||||
|
||||
@ -33,20 +56,49 @@ _expression_bin_ops = [
|
||||
['*', '/', '%'],
|
||||
['.*', '->*'],
|
||||
]
|
||||
_expression_unary_ops = ["++", "--", "*", "&", "+", "-", "!", "not", "~", "compl"]
|
||||
_expression_assignment_ops = ["=", "*=", "/=", "%=", "+=", "-=",
|
||||
">>=", "<<=", "&=", "and_eq", "^=", "xor_eq", "|=", "or_eq"]
|
||||
_expression_unary_ops = [
|
||||
'++',
|
||||
'--',
|
||||
'*',
|
||||
'&',
|
||||
'+',
|
||||
'-',
|
||||
'!',
|
||||
'not',
|
||||
'~',
|
||||
'compl',
|
||||
]
|
||||
_expression_assignment_ops = [
|
||||
'=',
|
||||
'*=',
|
||||
'/=',
|
||||
'%=',
|
||||
'+=',
|
||||
'-=',
|
||||
'>>=',
|
||||
'<<=',
|
||||
'&=',
|
||||
'and_eq',
|
||||
'^=',
|
||||
'xor_eq',
|
||||
'|=',
|
||||
'or_eq',
|
||||
]
|
||||
|
||||
_max_id = 1
|
||||
_id_prefix = [None, 'c.', 'Cv2.']
|
||||
# Ids are used in lookup keys which are used across pickled files,
|
||||
# so when _max_id changes, make sure to update the ENV_VERSION.
|
||||
|
||||
_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'"
|
||||
r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.DOTALL)
|
||||
_string_re = re.compile(
|
||||
r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'"
|
||||
r'|"([^"\\]*(?:\\.[^"\\]*)*)")',
|
||||
re.DOTALL,
|
||||
)
|
||||
|
||||
# bool, complex, and imaginary are macro "keywords", so they are handled separately
|
||||
_simple_type_specifiers_re = re.compile(r"""
|
||||
_simple_type_specifiers_re = re.compile(
|
||||
r"""
|
||||
\b(
|
||||
void|_Bool
|
||||
|signed|unsigned
|
||||
@ -62,4 +114,6 @@ _simple_type_specifiers_re = re.compile(r"""
|
||||
|__fp16 # extension
|
||||
|_Sat|_Fract|fract|_Accum|accum # extension
|
||||
)\b
|
||||
""", re.VERBOSE)
|
||||
""",
|
||||
re.VERBOSE,
|
||||
)
|
||||
|
@ -105,7 +105,7 @@ class DefinitionParser(BaseParser):
|
||||
escape = False
|
||||
while True:
|
||||
if self.eof:
|
||||
self.fail("Unexpected end during inside string.")
|
||||
self.fail('Unexpected end during inside string.')
|
||||
elif self.current_char == '"' and not escape:
|
||||
self.pos += 1
|
||||
break
|
||||
@ -114,7 +114,7 @@ class DefinitionParser(BaseParser):
|
||||
else:
|
||||
escape = False
|
||||
self.pos += 1
|
||||
return self.definition[start_pos:self.pos]
|
||||
return self.definition[start_pos : self.pos]
|
||||
|
||||
def _parse_literal(self) -> ASTLiteral | None:
|
||||
# -> integer-literal
|
||||
@ -130,12 +130,16 @@ class DefinitionParser(BaseParser):
|
||||
pos = self.pos
|
||||
if self.match(float_literal_re):
|
||||
self.match(float_literal_suffix_re)
|
||||
return ASTNumberLiteral(self.definition[pos:self.pos])
|
||||
for regex in (binary_literal_re, hex_literal_re,
|
||||
integer_literal_re, octal_literal_re):
|
||||
return ASTNumberLiteral(self.definition[pos : self.pos])
|
||||
for regex in (
|
||||
binary_literal_re,
|
||||
hex_literal_re,
|
||||
integer_literal_re,
|
||||
octal_literal_re,
|
||||
):
|
||||
if self.match(regex):
|
||||
self.match(integers_literal_suffix_re)
|
||||
return ASTNumberLiteral(self.definition[pos:self.pos])
|
||||
return ASTNumberLiteral(self.definition[pos : self.pos])
|
||||
|
||||
string = self._parse_string()
|
||||
if string is not None:
|
||||
@ -148,10 +152,14 @@ class DefinitionParser(BaseParser):
|
||||
try:
|
||||
return ASTCharLiteral(prefix, data)
|
||||
except UnicodeDecodeError as e:
|
||||
self.fail("Can not handle character literal. Internal error was: %s" % e)
|
||||
self.fail(
|
||||
'Can not handle character literal. Internal error was: %s' % e
|
||||
)
|
||||
except UnsupportedMultiCharacterCharLiteral:
|
||||
self.fail("Can not handle character literal"
|
||||
" resulting in multiple decoded characters.")
|
||||
self.fail(
|
||||
'Can not handle character literal'
|
||||
' resulting in multiple decoded characters.'
|
||||
)
|
||||
return None
|
||||
|
||||
def _parse_paren_expression(self) -> ASTExpression | None:
|
||||
@ -181,8 +189,9 @@ class DefinitionParser(BaseParser):
|
||||
return ASTIdExpression(nn)
|
||||
return None
|
||||
|
||||
def _parse_initializer_list(self, name: str, open: str, close: str,
|
||||
) -> tuple[list[ASTExpression] | None, bool | None]:
|
||||
def _parse_initializer_list(
|
||||
self, name: str, open: str, close: str
|
||||
) -> tuple[list[ASTExpression] | None, bool | None]:
|
||||
# Parse open and close with the actual initializer-list in between
|
||||
# -> initializer-clause '...'[opt]
|
||||
# | initializer-list ',' initializer-clause '...'[opt]
|
||||
@ -218,8 +227,9 @@ class DefinitionParser(BaseParser):
|
||||
#
|
||||
# expression-list
|
||||
# -> initializer-list
|
||||
exprs, trailing_comma = self._parse_initializer_list("parenthesized expression-list",
|
||||
'(', ')')
|
||||
exprs, trailing_comma = self._parse_initializer_list(
|
||||
'parenthesized expression-list', '(', ')'
|
||||
)
|
||||
if exprs is None:
|
||||
return None
|
||||
return ASTParenExprList(exprs)
|
||||
@ -227,7 +237,9 @@ class DefinitionParser(BaseParser):
|
||||
def _parse_braced_init_list(self) -> ASTBracedInitList | None:
|
||||
# -> '{' initializer-list ','[opt] '}'
|
||||
# | '{' '}'
|
||||
exprs, trailing_comma = self._parse_initializer_list("braced-init-list", '{', '}')
|
||||
exprs, trailing_comma = self._parse_initializer_list(
|
||||
'braced-init-list', '{', '}'
|
||||
)
|
||||
if exprs is None:
|
||||
return None
|
||||
return ASTBracedInitList(exprs, trailing_comma)
|
||||
@ -331,10 +343,11 @@ class DefinitionParser(BaseParser):
|
||||
return self._parse_unary_expression()
|
||||
except DefinitionError as ex_unary:
|
||||
errs = []
|
||||
errs.append((ex_cast, "If type cast expression"))
|
||||
errs.append((ex_unary, "If unary expression"))
|
||||
raise self._make_multi_error(errs,
|
||||
"Error in cast expression.") from ex_unary
|
||||
errs.append((ex_cast, 'If type cast expression'))
|
||||
errs.append((ex_unary, 'If unary expression'))
|
||||
raise self._make_multi_error(
|
||||
errs, 'Error in cast expression.'
|
||||
) from ex_unary
|
||||
else:
|
||||
return self._parse_unary_expression()
|
||||
|
||||
@ -352,11 +365,15 @@ class DefinitionParser(BaseParser):
|
||||
# pm = cast .*, ->*
|
||||
def _parse_bin_op_expr(self: DefinitionParser, op_id: int) -> ASTExpression:
|
||||
if op_id + 1 == len(_expression_bin_ops):
|
||||
|
||||
def parser() -> ASTExpression:
|
||||
return self._parse_cast_expression()
|
||||
|
||||
else:
|
||||
|
||||
def parser() -> ASTExpression:
|
||||
return _parse_bin_op_expr(self, op_id + 1)
|
||||
|
||||
exprs = []
|
||||
ops = []
|
||||
exprs.append(parser())
|
||||
@ -387,9 +404,12 @@ class DefinitionParser(BaseParser):
|
||||
if not one_more:
|
||||
break
|
||||
return ASTBinOpExpr(exprs, ops) # type: ignore[return-value]
|
||||
|
||||
return _parse_bin_op_expr(self, 0)
|
||||
|
||||
def _parse_conditional_expression_tail(self, or_expr_head: Any) -> ASTExpression | None:
|
||||
def _parse_conditional_expression_tail(
|
||||
self, or_expr_head: Any
|
||||
) -> ASTExpression | None:
|
||||
# -> "?" expression ":" assignment-expression
|
||||
return None
|
||||
|
||||
@ -436,9 +456,8 @@ class DefinitionParser(BaseParser):
|
||||
return self._parse_assignment_expression()
|
||||
|
||||
def _parse_expression_fallback(
|
||||
self, end: list[str],
|
||||
parser: Callable[[], ASTExpression],
|
||||
allow: bool = True) -> ASTExpression:
|
||||
self, end: list[str], parser: Callable[[], ASTExpression], allow: bool = True
|
||||
) -> ASTExpression:
|
||||
# Stupidly "parse" an expression.
|
||||
# 'end' should be a list of characters which ends the expression.
|
||||
|
||||
@ -451,8 +470,10 @@ class DefinitionParser(BaseParser):
|
||||
# and for testing we may want to globally disable it
|
||||
if not allow or not self.allowFallbackExpressionParsing:
|
||||
raise
|
||||
self.warn("Parsing of expression failed. Using fallback parser."
|
||||
" Error was:\n%s" % e)
|
||||
self.warn(
|
||||
'Parsing of expression failed. Using fallback parser.'
|
||||
' Error was:\n%s' % e
|
||||
)
|
||||
self.pos = prev_pos
|
||||
# and then the fallback scanning
|
||||
assert end is not None
|
||||
@ -473,9 +494,10 @@ class DefinitionParser(BaseParser):
|
||||
symbols.pop()
|
||||
self.pos += 1
|
||||
if len(end) > 0 and self.eof:
|
||||
self.fail("Could not find end of expression starting at %d."
|
||||
% start_pos)
|
||||
value = self.definition[start_pos:self.pos].strip()
|
||||
self.fail(
|
||||
'Could not find end of expression starting at %d.' % start_pos
|
||||
)
|
||||
value = self.definition[start_pos : self.pos].strip()
|
||||
return ASTFallbackExpr(value.strip())
|
||||
|
||||
def _parse_nested_name(self) -> ASTNestedName:
|
||||
@ -488,20 +510,20 @@ class DefinitionParser(BaseParser):
|
||||
while 1:
|
||||
self.skip_ws()
|
||||
if not self.match(identifier_re):
|
||||
self.fail("Expected identifier in nested name.")
|
||||
self.fail('Expected identifier in nested name.')
|
||||
identifier = self.matched_text
|
||||
# make sure there isn't a keyword
|
||||
if identifier in _keywords:
|
||||
self.fail("Expected identifier in nested name, "
|
||||
"got keyword: %s" % identifier)
|
||||
self.fail(
|
||||
'Expected identifier in nested name, got keyword: %s' % identifier
|
||||
)
|
||||
if self.matched_text in self.config.c_extra_keywords:
|
||||
msg = (
|
||||
'Expected identifier, got user-defined keyword: %s.'
|
||||
' Remove it from c_extra_keywords to allow it as identifier.\n'
|
||||
'Currently c_extra_keywords is %s.'
|
||||
)
|
||||
self.fail(msg % (self.matched_text,
|
||||
str(self.config.c_extra_keywords)))
|
||||
self.fail(msg % (self.matched_text, str(self.config.c_extra_keywords)))
|
||||
ident = ASTIdentifier(identifier)
|
||||
names.append(ident)
|
||||
|
||||
@ -582,13 +604,15 @@ class DefinitionParser(BaseParser):
|
||||
continue
|
||||
if self.skip_string(')'):
|
||||
break
|
||||
self.fail(f'Expecting "," or ")" in parameters, got "{self.current_char}".')
|
||||
self.fail(
|
||||
f'Expecting "," or ")" in parameters, got "{self.current_char}".'
|
||||
)
|
||||
|
||||
attrs = self._parse_attribute_list()
|
||||
return ASTParameters(args, attrs)
|
||||
|
||||
def _parse_decl_specs_simple(
|
||||
self, outer: str | None, typed: bool,
|
||||
self, outer: str | None, typed: bool
|
||||
) -> ASTDeclSpecsSimple:
|
||||
"""Just parse the simple ones."""
|
||||
storage = None
|
||||
@ -644,8 +668,15 @@ class DefinitionParser(BaseParser):
|
||||
attrs.append(attr)
|
||||
continue
|
||||
break
|
||||
return ASTDeclSpecsSimple(storage, thread_local, inline,
|
||||
restrict, volatile, const, ASTAttributeList(attrs))
|
||||
return ASTDeclSpecsSimple(
|
||||
storage,
|
||||
thread_local,
|
||||
inline,
|
||||
restrict,
|
||||
volatile,
|
||||
const,
|
||||
ASTAttributeList(attrs),
|
||||
)
|
||||
|
||||
def _parse_decl_specs(self, outer: str | None, typed: bool = True) -> ASTDeclSpecs:
|
||||
if outer:
|
||||
@ -662,23 +693,25 @@ class DefinitionParser(BaseParser):
|
||||
return ASTDeclSpecs(outer, left_specs, right_specs, trailing)
|
||||
|
||||
def _parse_declarator_name_suffix(
|
||||
self, named: bool | str, param_mode: str, typed: bool,
|
||||
self, named: bool | str, param_mode: str, typed: bool
|
||||
) -> ASTDeclarator:
|
||||
assert named in {True, False, 'single'}
|
||||
# now we should parse the name, and then suffixes
|
||||
if named == 'single':
|
||||
if self.match(identifier_re):
|
||||
if self.matched_text in _keywords:
|
||||
self.fail("Expected identifier, "
|
||||
"got keyword: %s" % self.matched_text)
|
||||
self.fail(
|
||||
'Expected identifier, got keyword: %s' % self.matched_text
|
||||
)
|
||||
if self.matched_text in self.config.c_extra_keywords:
|
||||
msg = (
|
||||
'Expected identifier, got user-defined keyword: %s. '
|
||||
'Remove it from c_extra_keywords to allow it as identifier.\n'
|
||||
'Currently c_extra_keywords is %s.'
|
||||
)
|
||||
self.fail(msg % (self.matched_text,
|
||||
str(self.config.c_extra_keywords)))
|
||||
self.fail(
|
||||
msg % (self.matched_text, str(self.config.c_extra_keywords))
|
||||
)
|
||||
identifier = ASTIdentifier(self.matched_text)
|
||||
decl_id = ASTNestedName([identifier], rooted=False)
|
||||
else:
|
||||
@ -726,6 +759,7 @@ class DefinitionParser(BaseParser):
|
||||
|
||||
def parser() -> ASTExpression:
|
||||
return self._parse_expression()
|
||||
|
||||
size = self._parse_expression_fallback([']'], parser)
|
||||
self.skip_ws()
|
||||
if not self.skip_string(']'):
|
||||
@ -741,15 +775,14 @@ class DefinitionParser(BaseParser):
|
||||
if self.skip_string(':'):
|
||||
size = self._parse_constant_expression()
|
||||
return ASTDeclaratorNameBitField(declId=decl_id, size=size)
|
||||
return ASTDeclaratorNameParam(declId=decl_id, arrayOps=array_ops,
|
||||
param=param)
|
||||
return ASTDeclaratorNameParam(declId=decl_id, arrayOps=array_ops, param=param)
|
||||
|
||||
def _parse_declarator(self, named: bool | str, param_mode: str,
|
||||
typed: bool = True) -> ASTDeclarator:
|
||||
def _parse_declarator(
|
||||
self, named: bool | str, param_mode: str, typed: bool = True
|
||||
) -> ASTDeclarator:
|
||||
# 'typed' here means 'parse return type stuff'
|
||||
if param_mode not in {'type', 'function'}:
|
||||
raise Exception(
|
||||
"Internal error, unknown param_mode '%s'." % param_mode)
|
||||
raise Exception("Internal error, unknown param_mode '%s'." % param_mode)
|
||||
prev_errors = []
|
||||
self.skip_ws()
|
||||
if typed and self.skip_string('*'):
|
||||
@ -777,20 +810,23 @@ class DefinitionParser(BaseParser):
|
||||
continue
|
||||
break
|
||||
next = self._parse_declarator(named, param_mode, typed)
|
||||
return ASTDeclaratorPtr(next=next,
|
||||
restrict=restrict, volatile=volatile, const=const,
|
||||
attrs=ASTAttributeList(attrs))
|
||||
return ASTDeclaratorPtr(
|
||||
next=next,
|
||||
restrict=restrict,
|
||||
volatile=volatile,
|
||||
const=const,
|
||||
attrs=ASTAttributeList(attrs),
|
||||
)
|
||||
if typed and self.current_char == '(': # note: peeking, not skipping
|
||||
# maybe this is the beginning of params, try that first,
|
||||
# otherwise assume it's noptr->declarator > ( ptr-declarator )
|
||||
pos = self.pos
|
||||
try:
|
||||
# assume this is params
|
||||
res = self._parse_declarator_name_suffix(named, param_mode,
|
||||
typed)
|
||||
res = self._parse_declarator_name_suffix(named, param_mode, typed)
|
||||
return res
|
||||
except DefinitionError as ex_param_qual:
|
||||
msg = "If declarator-id with parameters"
|
||||
msg = 'If declarator-id with parameters'
|
||||
if param_mode == 'function':
|
||||
msg += " (e.g., 'void f(int arg)')"
|
||||
prev_errors.append((ex_param_qual, msg))
|
||||
@ -803,30 +839,33 @@ class DefinitionParser(BaseParser):
|
||||
# inside, right?
|
||||
inner = self._parse_declarator(named, param_mode, typed)
|
||||
if not self.skip_string(')'):
|
||||
self.fail("Expected ')' in \"( ptr-declarator )\"")
|
||||
next = self._parse_declarator(named=False,
|
||||
param_mode="type",
|
||||
typed=typed)
|
||||
self.fail('Expected \')\' in "( ptr-declarator )"')
|
||||
next = self._parse_declarator(
|
||||
named=False, param_mode='type', typed=typed
|
||||
)
|
||||
return ASTDeclaratorParen(inner=inner, next=next)
|
||||
except DefinitionError as ex_no_ptr_paren:
|
||||
self.pos = pos
|
||||
msg = "If parenthesis in noptr-declarator"
|
||||
msg = 'If parenthesis in noptr-declarator'
|
||||
if param_mode == 'function':
|
||||
msg += " (e.g., 'void (*f(int arg))(double)')"
|
||||
prev_errors.append((ex_no_ptr_paren, msg))
|
||||
header = "Error in declarator"
|
||||
raise self._make_multi_error(prev_errors, header) from ex_no_ptr_paren
|
||||
header = 'Error in declarator'
|
||||
raise self._make_multi_error(
|
||||
prev_errors, header
|
||||
) from ex_no_ptr_paren
|
||||
pos = self.pos
|
||||
try:
|
||||
return self._parse_declarator_name_suffix(named, param_mode, typed)
|
||||
except DefinitionError as e:
|
||||
self.pos = pos
|
||||
prev_errors.append((e, "If declarator-id"))
|
||||
header = "Error in declarator or parameters"
|
||||
prev_errors.append((e, 'If declarator-id'))
|
||||
header = 'Error in declarator or parameters'
|
||||
raise self._make_multi_error(prev_errors, header) from e
|
||||
|
||||
def _parse_initializer(self, outer: str | None = None, allow_fallback: bool = True,
|
||||
) -> ASTInitializer | None:
|
||||
def _parse_initializer(
|
||||
self, outer: str | None = None, allow_fallback: bool = True
|
||||
) -> ASTInitializer | None:
|
||||
self.skip_ws()
|
||||
if outer == 'member' and False: # NoQA: SIM223 # TODO
|
||||
braced_init = self._parse_braced_init_list()
|
||||
@ -845,13 +884,16 @@ class DefinitionParser(BaseParser):
|
||||
elif outer is None: # function parameter
|
||||
fallback_end = [',', ')']
|
||||
else:
|
||||
self.fail("Internal error, initializer for outer '%s' not "
|
||||
"implemented." % outer)
|
||||
self.fail(
|
||||
"Internal error, initializer for outer '%s' not implemented." % outer
|
||||
)
|
||||
|
||||
def parser() -> ASTExpression:
|
||||
return self._parse_assignment_expression()
|
||||
|
||||
value = self._parse_expression_fallback(fallback_end, parser, allow=allow_fallback)
|
||||
value = self._parse_expression_fallback(
|
||||
fallback_end, parser, allow=allow_fallback
|
||||
)
|
||||
return ASTInitializer(value)
|
||||
|
||||
def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType:
|
||||
@ -871,11 +913,10 @@ class DefinitionParser(BaseParser):
|
||||
# first try without the type
|
||||
try:
|
||||
decl_specs = self._parse_decl_specs(outer=outer, typed=False)
|
||||
decl = self._parse_declarator(named=True, param_mode=outer,
|
||||
typed=False)
|
||||
decl = self._parse_declarator(named=True, param_mode=outer, typed=False)
|
||||
self.assert_end(allowSemicolon=True)
|
||||
except DefinitionError as ex_untyped:
|
||||
desc = "If just a name"
|
||||
desc = 'If just a name'
|
||||
prev_errors.append((ex_untyped, desc))
|
||||
self.pos = start_pos
|
||||
try:
|
||||
@ -883,14 +924,14 @@ class DefinitionParser(BaseParser):
|
||||
decl = self._parse_declarator(named=True, param_mode=outer)
|
||||
except DefinitionError as ex_typed:
|
||||
self.pos = start_pos
|
||||
desc = "If typedef-like declaration"
|
||||
desc = 'If typedef-like declaration'
|
||||
prev_errors.append((ex_typed, desc))
|
||||
# Retain the else branch for easier debugging.
|
||||
# TODO: it would be nice to save the previous stacktrace
|
||||
# and output it here.
|
||||
if True:
|
||||
header = "Type must be either just a name or a "
|
||||
header += "typedef-like declaration."
|
||||
header = 'Type must be either just a name or a '
|
||||
header += 'typedef-like declaration.'
|
||||
raise self._make_multi_error(prev_errors, header) from ex_typed
|
||||
else: # NoQA: RET506
|
||||
# For testing purposes.
|
||||
@ -900,8 +941,9 @@ class DefinitionParser(BaseParser):
|
||||
self.pos = start_pos
|
||||
typed = True
|
||||
decl_specs = self._parse_decl_specs(outer=outer, typed=typed)
|
||||
decl = self._parse_declarator(named=True, param_mode=outer,
|
||||
typed=typed)
|
||||
decl = self._parse_declarator(
|
||||
named=True, param_mode=outer, typed=typed
|
||||
)
|
||||
elif outer == 'function':
|
||||
decl_specs = self._parse_decl_specs(outer=outer)
|
||||
decl = self._parse_declarator(named=True, param_mode=outer)
|
||||
@ -913,7 +955,9 @@ class DefinitionParser(BaseParser):
|
||||
decl = self._parse_declarator(named=named, param_mode=param_mode)
|
||||
return ASTType(decl_specs, decl)
|
||||
|
||||
def _parse_type_with_init(self, named: bool | str, outer: str | None) -> ASTTypeWithInit:
|
||||
def _parse_type_with_init(
|
||||
self, named: bool | str, outer: str | None
|
||||
) -> ASTTypeWithInit:
|
||||
if outer:
|
||||
assert outer in {'type', 'member', 'function'}
|
||||
type = self._parse_type(outer=outer, named=named)
|
||||
@ -924,7 +968,7 @@ class DefinitionParser(BaseParser):
|
||||
self.skip_ws()
|
||||
ident = self._parse_nested_name()
|
||||
if ident is None:
|
||||
self.fail("Expected identifier in macro definition.")
|
||||
self.fail('Expected identifier in macro definition.')
|
||||
self.skip_ws()
|
||||
if not self.skip_string_and_ws('('):
|
||||
return ASTMacro(ident, None)
|
||||
@ -940,7 +984,7 @@ class DefinitionParser(BaseParser):
|
||||
self.fail('Expected ")" after "..." in macro parameters.')
|
||||
break
|
||||
if not self.match(identifier_re):
|
||||
self.fail("Expected identifier in macro parameters.")
|
||||
self.fail('Expected identifier in macro parameters.')
|
||||
nn = ASTNestedName([ASTIdentifier(self.matched_text)], rooted=False)
|
||||
# Allow named variadic args:
|
||||
# https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
|
||||
@ -989,12 +1033,31 @@ class DefinitionParser(BaseParser):
|
||||
def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclaration:
|
||||
object_type = objectType
|
||||
directive_type = directiveType
|
||||
if object_type not in {'function', 'member',
|
||||
'macro', 'struct', 'union', 'enum', 'enumerator', 'type'}:
|
||||
if object_type not in {
|
||||
'function',
|
||||
'member',
|
||||
'macro',
|
||||
'struct',
|
||||
'union',
|
||||
'enum',
|
||||
'enumerator',
|
||||
'type',
|
||||
}:
|
||||
raise Exception('Internal error, unknown objectType "%s".' % object_type)
|
||||
if directive_type not in {'function', 'member', 'var',
|
||||
'macro', 'struct', 'union', 'enum', 'enumerator', 'type'}:
|
||||
raise Exception('Internal error, unknown directiveType "%s".' % directive_type)
|
||||
if directive_type not in {
|
||||
'function',
|
||||
'member',
|
||||
'var',
|
||||
'macro',
|
||||
'struct',
|
||||
'union',
|
||||
'enum',
|
||||
'enumerator',
|
||||
'type',
|
||||
}:
|
||||
raise Exception(
|
||||
'Internal error, unknown directiveType "%s".' % directive_type
|
||||
)
|
||||
|
||||
declaration: DeclarationType | None = None
|
||||
if object_type == 'member':
|
||||
@ -1047,9 +1110,9 @@ class DefinitionParser(BaseParser):
|
||||
self.skip_ws()
|
||||
self.assert_end()
|
||||
except DefinitionError as ex_type:
|
||||
header = "Error when parsing (type) expression."
|
||||
header = 'Error when parsing (type) expression.'
|
||||
errs = []
|
||||
errs.append((ex_expr, "If expression"))
|
||||
errs.append((ex_type, "If type"))
|
||||
errs.append((ex_expr, 'If expression'))
|
||||
errs.append((ex_type, 'If type'))
|
||||
raise self._make_multi_error(errs, header) from ex_type
|
||||
return res
|
||||
|
@ -27,12 +27,13 @@ class _DuplicateSymbolError(Exception):
|
||||
self.declaration = declaration
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "Internal C duplicate symbol error:\n%s" % self.symbol.dump(0)
|
||||
return 'Internal C duplicate symbol error:\n%s' % self.symbol.dump(0)
|
||||
|
||||
|
||||
class SymbolLookupResult:
|
||||
def __init__(self, symbols: Sequence[Symbol], parentSymbol: Symbol,
|
||||
ident: ASTIdentifier) -> None:
|
||||
def __init__(
|
||||
self, symbols: Sequence[Symbol], parentSymbol: Symbol, ident: ASTIdentifier
|
||||
) -> None:
|
||||
self.symbols = symbols
|
||||
self.parentSymbol = parentSymbol
|
||||
self.ident = ident
|
||||
@ -43,13 +44,13 @@ class LookupKey:
|
||||
self.data = data
|
||||
|
||||
def __str__(self) -> str:
|
||||
inner = ', '.join(f"({ident}, {id_})" for ident, id_ in self.data)
|
||||
inner = ', '.join(f'({ident}, {id_})' for ident, id_ in self.data)
|
||||
return f'[{inner}]'
|
||||
|
||||
|
||||
class Symbol:
|
||||
debug_indent = 0
|
||||
debug_indent_string = " "
|
||||
debug_indent_string = ' '
|
||||
debug_lookup = False
|
||||
debug_show_tree = False
|
||||
|
||||
@ -65,7 +66,7 @@ class Symbol:
|
||||
@staticmethod
|
||||
def debug_print(*args: Any) -> None:
|
||||
msg = Symbol.debug_indent_string * Symbol.debug_indent
|
||||
msg += "".join(str(e) for e in args)
|
||||
msg += ''.join(str(e) for e in args)
|
||||
logger.debug(msg)
|
||||
|
||||
def _assert_invariants(self) -> None:
|
||||
@ -78,7 +79,7 @@ class Symbol:
|
||||
assert self.docname
|
||||
|
||||
def __setattr__(self, key: str, value: Any) -> None:
|
||||
if key == "children":
|
||||
if key == 'children':
|
||||
raise AssertionError
|
||||
return super().__setattr__(key, value)
|
||||
|
||||
@ -159,12 +160,15 @@ class Symbol:
|
||||
def _add_function_params(self) -> None:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("_add_function_params:")
|
||||
Symbol.debug_print('_add_function_params:')
|
||||
# Note: we may be called from _fill_empty, so the symbols we want
|
||||
# to add may actually already be present (as empty symbols).
|
||||
|
||||
# add symbols for function parameters, if any
|
||||
if self.declaration is not None and self.declaration.function_params is not None:
|
||||
if (
|
||||
self.declaration is not None
|
||||
and self.declaration.function_params is not None
|
||||
):
|
||||
for p in self.declaration.function_params:
|
||||
if p.arg is None:
|
||||
continue
|
||||
@ -205,8 +209,8 @@ class Symbol:
|
||||
|
||||
def get_all_symbols(self) -> Iterator[Symbol]:
|
||||
yield self
|
||||
for sChild in self._children:
|
||||
yield from sChild.get_all_symbols()
|
||||
for s_child in self._children:
|
||||
yield from s_child.get_all_symbols()
|
||||
|
||||
@property
|
||||
def children(self) -> Iterator[Symbol]:
|
||||
@ -244,70 +248,74 @@ class Symbol:
|
||||
|
||||
def _symbol_lookup(
|
||||
self,
|
||||
nestedName: ASTNestedName,
|
||||
onMissingQualifiedSymbol: Callable[[Symbol, ASTIdentifier], Symbol | None],
|
||||
ancestorLookupType: str | None,
|
||||
matchSelf: bool,
|
||||
recurseInAnon: bool,
|
||||
searchInSiblings: bool,
|
||||
nested_name: ASTNestedName,
|
||||
on_missing_qualified_symbol: Callable[[Symbol, ASTIdentifier], Symbol | None],
|
||||
ancestor_lookup_type: str | None,
|
||||
match_self: bool,
|
||||
recurse_in_anon: bool,
|
||||
search_in_siblings: bool,
|
||||
) -> SymbolLookupResult | None:
|
||||
# TODO: further simplification from C++ to C
|
||||
# ancestorLookupType: if not None, specifies the target type of the lookup
|
||||
# ancestor_lookup_type: if not None, specifies the target type of the lookup
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("_symbol_lookup:")
|
||||
Symbol.debug_print('_symbol_lookup:')
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("self:")
|
||||
Symbol.debug_print('self:')
|
||||
logger.debug(self.to_string(Symbol.debug_indent + 1, addEndNewline=False))
|
||||
Symbol.debug_print("nestedName: ", nestedName)
|
||||
Symbol.debug_print("ancestorLookupType:", ancestorLookupType)
|
||||
Symbol.debug_print("matchSelf: ", matchSelf)
|
||||
Symbol.debug_print("recurseInAnon: ", recurseInAnon)
|
||||
Symbol.debug_print("searchInSiblings: ", searchInSiblings)
|
||||
Symbol.debug_print('nested_name: ', nested_name)
|
||||
Symbol.debug_print('ancestor_lookup_type:', ancestor_lookup_type)
|
||||
Symbol.debug_print('match_self: ', match_self)
|
||||
Symbol.debug_print('recurse_in_anon: ', recurse_in_anon)
|
||||
Symbol.debug_print('search_in_siblings: ', search_in_siblings)
|
||||
|
||||
names = nestedName.names
|
||||
names = nested_name.names
|
||||
|
||||
# find the right starting point for lookup
|
||||
parentSymbol = self
|
||||
if nestedName.rooted:
|
||||
while parentSymbol.parent is not None:
|
||||
parentSymbol = parentSymbol.parent
|
||||
parent_symbol = self
|
||||
if nested_name.rooted:
|
||||
while parent_symbol.parent is not None:
|
||||
parent_symbol = parent_symbol.parent
|
||||
|
||||
if ancestorLookupType is not None:
|
||||
if ancestor_lookup_type is not None:
|
||||
# walk up until we find the first identifier
|
||||
firstName = names[0]
|
||||
while parentSymbol.parent:
|
||||
if firstName.name in parentSymbol._children_by_name:
|
||||
first_name = names[0]
|
||||
while parent_symbol.parent:
|
||||
if first_name.name in parent_symbol._children_by_name:
|
||||
break
|
||||
parentSymbol = parentSymbol.parent
|
||||
parent_symbol = parent_symbol.parent
|
||||
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("starting point:")
|
||||
logger.debug(parentSymbol.to_string(Symbol.debug_indent + 1, addEndNewline=False))
|
||||
Symbol.debug_print('starting point:')
|
||||
logger.debug(
|
||||
parent_symbol.to_string(Symbol.debug_indent + 1, addEndNewline=False)
|
||||
)
|
||||
|
||||
# and now the actual lookup
|
||||
for ident in names[:-1]:
|
||||
name = ident.name
|
||||
if name in parentSymbol._children_by_name:
|
||||
symbol = parentSymbol._children_by_name[name]
|
||||
if name in parent_symbol._children_by_name:
|
||||
symbol = parent_symbol._children_by_name[name]
|
||||
else:
|
||||
symbol = onMissingQualifiedSymbol(parentSymbol, ident)
|
||||
symbol = on_missing_qualified_symbol(parent_symbol, ident)
|
||||
if symbol is None:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 2
|
||||
return None
|
||||
parentSymbol = symbol
|
||||
parent_symbol = symbol
|
||||
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("handle last name from:")
|
||||
logger.debug(parentSymbol.to_string(Symbol.debug_indent + 1, addEndNewline=False))
|
||||
Symbol.debug_print('handle last name from:')
|
||||
logger.debug(
|
||||
parent_symbol.to_string(Symbol.debug_indent + 1, addEndNewline=False)
|
||||
)
|
||||
|
||||
# handle the last name
|
||||
ident = names[-1]
|
||||
name = ident.name
|
||||
symbol = parentSymbol._children_by_name.get(name)
|
||||
if not symbol and recurseInAnon:
|
||||
for child in parentSymbol._anon_children:
|
||||
symbol = parent_symbol._children_by_name.get(name)
|
||||
if not symbol and recurse_in_anon:
|
||||
for child in parent_symbol._anon_children:
|
||||
if name in child._children_by_name:
|
||||
symbol = child._children_by_name[name]
|
||||
break
|
||||
@ -316,11 +324,11 @@ class Symbol:
|
||||
Symbol.debug_indent -= 2
|
||||
|
||||
result = [symbol] if symbol else []
|
||||
return SymbolLookupResult(result, parentSymbol, ident)
|
||||
return SymbolLookupResult(result, parent_symbol, ident)
|
||||
|
||||
def _add_symbols(
|
||||
self,
|
||||
nestedName: ASTNestedName,
|
||||
nested_name: ASTNestedName,
|
||||
declaration: ASTDeclaration | None,
|
||||
docname: str | None,
|
||||
line: int | None,
|
||||
@ -331,152 +339,172 @@ class Symbol:
|
||||
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("_add_symbols:")
|
||||
Symbol.debug_print('_add_symbols:')
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("nn: ", nestedName)
|
||||
Symbol.debug_print("decl: ", declaration)
|
||||
Symbol.debug_print(f"location: {docname}:{line}")
|
||||
Symbol.debug_print('nn: ', nested_name)
|
||||
Symbol.debug_print('decl: ', declaration)
|
||||
Symbol.debug_print(f'location: {docname}:{line}')
|
||||
|
||||
def onMissingQualifiedSymbol(parentSymbol: Symbol, ident: ASTIdentifier) -> Symbol:
|
||||
def on_missing_qualified_symbol(
|
||||
parent_symbol: Symbol, ident: ASTIdentifier
|
||||
) -> Symbol:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("_add_symbols, onMissingQualifiedSymbol:")
|
||||
Symbol.debug_print('_add_symbols, on_missing_qualified_symbol:')
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("ident: ", ident)
|
||||
Symbol.debug_print('ident: ', ident)
|
||||
Symbol.debug_indent -= 2
|
||||
return Symbol(parent=parentSymbol, ident=ident,
|
||||
declaration=None, docname=None, line=None)
|
||||
return Symbol(
|
||||
parent=parent_symbol,
|
||||
ident=ident,
|
||||
declaration=None,
|
||||
docname=None,
|
||||
line=None,
|
||||
)
|
||||
|
||||
lookupResult = self._symbol_lookup(nestedName,
|
||||
onMissingQualifiedSymbol,
|
||||
ancestorLookupType=None,
|
||||
matchSelf=False,
|
||||
recurseInAnon=False,
|
||||
searchInSiblings=False)
|
||||
assert lookupResult is not None # we create symbols all the way, so that can't happen
|
||||
symbols = list(lookupResult.symbols)
|
||||
lookup_result = self._symbol_lookup(
|
||||
nested_name,
|
||||
on_missing_qualified_symbol,
|
||||
ancestor_lookup_type=None,
|
||||
match_self=False,
|
||||
recurse_in_anon=False,
|
||||
search_in_siblings=False,
|
||||
)
|
||||
# we create symbols all the way, so that can't happen
|
||||
assert lookup_result is not None
|
||||
symbols = list(lookup_result.symbols)
|
||||
if len(symbols) == 0:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("_add_symbols, result, no symbol:")
|
||||
Symbol.debug_print('_add_symbols, result, no symbol:')
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("ident: ", lookupResult.ident)
|
||||
Symbol.debug_print("declaration: ", declaration)
|
||||
Symbol.debug_print(f"location: {docname}:{line}")
|
||||
Symbol.debug_print('ident: ', lookup_result.ident)
|
||||
Symbol.debug_print('declaration: ', declaration)
|
||||
Symbol.debug_print(f'location: {docname}:{line}')
|
||||
Symbol.debug_indent -= 1
|
||||
symbol = Symbol(parent=lookupResult.parentSymbol,
|
||||
ident=lookupResult.ident,
|
||||
declaration=declaration,
|
||||
docname=docname, line=line)
|
||||
symbol = Symbol(
|
||||
parent=lookup_result.parentSymbol,
|
||||
ident=lookup_result.ident,
|
||||
declaration=declaration,
|
||||
docname=docname,
|
||||
line=line,
|
||||
)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 2
|
||||
return symbol
|
||||
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("_add_symbols, result, symbols:")
|
||||
Symbol.debug_print('_add_symbols, result, symbols:')
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("number symbols:", len(symbols))
|
||||
Symbol.debug_print('number symbols:', len(symbols))
|
||||
Symbol.debug_indent -= 1
|
||||
|
||||
if not declaration:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("no declaration")
|
||||
Symbol.debug_print('no declaration')
|
||||
Symbol.debug_indent -= 2
|
||||
# good, just a scope creation
|
||||
# TODO: what if we have more than one symbol?
|
||||
return symbols[0]
|
||||
|
||||
noDecl = []
|
||||
withDecl = []
|
||||
dupDecl = []
|
||||
no_decl = []
|
||||
with_decl = []
|
||||
dup_decl = []
|
||||
for s in symbols:
|
||||
if s.declaration is None:
|
||||
noDecl.append(s)
|
||||
no_decl.append(s)
|
||||
elif s.isRedeclaration:
|
||||
dupDecl.append(s)
|
||||
dup_decl.append(s)
|
||||
else:
|
||||
withDecl.append(s)
|
||||
with_decl.append(s)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("#noDecl: ", len(noDecl))
|
||||
Symbol.debug_print("#withDecl:", len(withDecl))
|
||||
Symbol.debug_print("#dupDecl: ", len(dupDecl))
|
||||
Symbol.debug_print('#no_decl: ', len(no_decl))
|
||||
Symbol.debug_print('#with_decl:', len(with_decl))
|
||||
Symbol.debug_print('#dup_decl: ', len(dup_decl))
|
||||
|
||||
# With partial builds we may start with a large symbol tree stripped of declarations.
|
||||
# Essentially any combination of noDecl, withDecl, and dupDecls seems possible.
|
||||
# Essentially any combination of no_decl, with_decl, and dup_decls seems possible.
|
||||
# TODO: make partial builds fully work. What should happen when the primary symbol gets
|
||||
# deleted, and other duplicates exist? The full document should probably be rebuild.
|
||||
|
||||
# First check if one of those with a declaration matches.
|
||||
# If it's a function, we need to compare IDs,
|
||||
# otherwise there should be only one symbol with a declaration.
|
||||
def makeCandSymbol() -> Symbol:
|
||||
def make_cand_symbol() -> Symbol:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("begin: creating candidate symbol")
|
||||
symbol = Symbol(parent=lookupResult.parentSymbol,
|
||||
ident=lookupResult.ident,
|
||||
declaration=declaration,
|
||||
docname=docname, line=line)
|
||||
Symbol.debug_print('begin: creating candidate symbol')
|
||||
symbol = Symbol(
|
||||
parent=lookup_result.parentSymbol,
|
||||
ident=lookup_result.ident,
|
||||
declaration=declaration,
|
||||
docname=docname,
|
||||
line=line,
|
||||
)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("end: creating candidate symbol")
|
||||
Symbol.debug_print('end: creating candidate symbol')
|
||||
return symbol
|
||||
|
||||
if len(withDecl) == 0:
|
||||
candSymbol = None
|
||||
if len(with_decl) == 0:
|
||||
cand_symbol = None
|
||||
else:
|
||||
candSymbol = makeCandSymbol()
|
||||
cand_symbol = make_cand_symbol()
|
||||
|
||||
def handleDuplicateDeclaration(symbol: Symbol, candSymbol: Symbol) -> None:
|
||||
def handle_duplicate_declaration(
|
||||
symbol: Symbol, cand_symbol: Symbol
|
||||
) -> None:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("redeclaration")
|
||||
Symbol.debug_print('redeclaration')
|
||||
Symbol.debug_indent -= 1
|
||||
Symbol.debug_indent -= 2
|
||||
# Redeclaration of the same symbol.
|
||||
# Let the new one be there, but raise an error to the client
|
||||
# so it can use the real symbol as subscope.
|
||||
# This will probably result in a duplicate id warning.
|
||||
candSymbol.isRedeclaration = True
|
||||
cand_symbol.isRedeclaration = True
|
||||
raise _DuplicateSymbolError(symbol, declaration)
|
||||
|
||||
if declaration.objectType != "function":
|
||||
assert len(withDecl) <= 1
|
||||
handleDuplicateDeclaration(withDecl[0], candSymbol)
|
||||
if declaration.objectType != 'function':
|
||||
assert len(with_decl) <= 1
|
||||
handle_duplicate_declaration(with_decl[0], cand_symbol)
|
||||
# (not reachable)
|
||||
|
||||
# a function, so compare IDs
|
||||
candId = declaration.get_newest_id()
|
||||
cand_id = declaration.get_newest_id()
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("candId:", candId)
|
||||
for symbol in withDecl:
|
||||
oldId = symbol.declaration.get_newest_id()
|
||||
Symbol.debug_print('cand_id:', cand_id)
|
||||
for symbol in with_decl:
|
||||
old_id = symbol.declaration.get_newest_id()
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("oldId: ", oldId)
|
||||
if candId == oldId:
|
||||
handleDuplicateDeclaration(symbol, candSymbol)
|
||||
Symbol.debug_print('old_id: ', old_id)
|
||||
if cand_id == old_id:
|
||||
handle_duplicate_declaration(symbol, cand_symbol)
|
||||
# (not reachable)
|
||||
# no candidate symbol found with matching ID
|
||||
# if there is an empty symbol, fill that one
|
||||
if len(noDecl) == 0:
|
||||
if len(no_decl) == 0:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print(
|
||||
"no match, no empty, candSybmol is not None?:", candSymbol is not None,
|
||||
'no match, no empty, cand_sybmol is not None?:',
|
||||
cand_symbol is not None,
|
||||
)
|
||||
Symbol.debug_indent -= 2
|
||||
if candSymbol is not None:
|
||||
return candSymbol
|
||||
if cand_symbol is not None:
|
||||
return cand_symbol
|
||||
else:
|
||||
return makeCandSymbol()
|
||||
return make_cand_symbol()
|
||||
else:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print(
|
||||
"no match, but fill an empty declaration, candSybmol is not None?:",
|
||||
candSymbol is not None)
|
||||
'no match, but fill an empty declaration, cand_sybmol is not None?:',
|
||||
cand_symbol is not None,
|
||||
)
|
||||
Symbol.debug_indent -= 2
|
||||
if candSymbol is not None:
|
||||
candSymbol.remove()
|
||||
# assert len(noDecl) == 1
|
||||
if cand_symbol is not None:
|
||||
cand_symbol.remove()
|
||||
# assert len(no_decl) == 1
|
||||
# TODO: enable assertion when we at some point find out how to do cleanup
|
||||
# for now, just take the first one, it should work fine ... right?
|
||||
symbol = noDecl[0]
|
||||
symbol = no_decl[0]
|
||||
# If someone first opened the scope, and then later
|
||||
# declares it, e.g,
|
||||
# .. namespace:: Test
|
||||
@ -485,44 +513,48 @@ class Symbol:
|
||||
symbol._fill_empty(declaration, docname, line)
|
||||
return symbol
|
||||
|
||||
def merge_with(self, other: Symbol, docnames: list[str],
|
||||
env: BuildEnvironment) -> None:
|
||||
def merge_with(
|
||||
self, other: Symbol, docnames: list[str], env: BuildEnvironment
|
||||
) -> None:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("merge_with:")
|
||||
Symbol.debug_print('merge_with:')
|
||||
|
||||
assert other is not None
|
||||
for otherChild in other._children:
|
||||
otherName = otherChild.ident.name
|
||||
if otherName not in self._children_by_name:
|
||||
for other_child in other._children:
|
||||
other_name = other_child.ident.name
|
||||
if other_name not in self._children_by_name:
|
||||
# TODO: hmm, should we prune by docnames?
|
||||
otherChild.parent = self
|
||||
self._add_child(otherChild)
|
||||
otherChild._assert_invariants()
|
||||
other_child.parent = self
|
||||
self._add_child(other_child)
|
||||
other_child._assert_invariants()
|
||||
continue
|
||||
ourChild = self._children_by_name[otherName]
|
||||
if otherChild.declaration and otherChild.docname in docnames:
|
||||
if not ourChild.declaration:
|
||||
ourChild._fill_empty(otherChild.declaration,
|
||||
otherChild.docname, otherChild.line)
|
||||
elif ourChild.docname != otherChild.docname:
|
||||
name = str(ourChild.declaration)
|
||||
msg = __("Duplicate C declaration, also defined at %s:%s.\n"
|
||||
"Declaration is '.. c:%s:: %s'.")
|
||||
our_child = self._children_by_name[other_name]
|
||||
if other_child.declaration and other_child.docname in docnames:
|
||||
if not our_child.declaration:
|
||||
our_child._fill_empty(
|
||||
other_child.declaration, other_child.docname, other_child.line
|
||||
)
|
||||
elif our_child.docname != other_child.docname:
|
||||
name = str(our_child.declaration)
|
||||
msg = __(
|
||||
'Duplicate C declaration, also defined at %s:%s.\n'
|
||||
"Declaration is '.. c:%s:: %s'."
|
||||
)
|
||||
logger.warning(
|
||||
msg,
|
||||
ourChild.docname,
|
||||
ourChild.line,
|
||||
ourChild.declaration.directiveType,
|
||||
our_child.docname,
|
||||
our_child.line,
|
||||
our_child.declaration.directiveType,
|
||||
name,
|
||||
location=(otherChild.docname, otherChild.line),
|
||||
location=(other_child.docname, other_child.line),
|
||||
)
|
||||
else:
|
||||
# Both have declarations, and in the same docname.
|
||||
# This can apparently happen, it should be safe to
|
||||
# just ignore it, right?
|
||||
pass
|
||||
ourChild.merge_with(otherChild, docnames, env)
|
||||
our_child.merge_with(other_child, docnames, env)
|
||||
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 1
|
||||
@ -530,45 +562,52 @@ class Symbol:
|
||||
def add_name(self, nestedName: ASTNestedName) -> Symbol:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("add_name:")
|
||||
Symbol.debug_print('add_name:')
|
||||
res = self._add_symbols(nestedName, declaration=None, docname=None, line=None)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 1
|
||||
return res
|
||||
|
||||
def add_declaration(self, declaration: ASTDeclaration,
|
||||
docname: str, line: int) -> Symbol:
|
||||
def add_declaration(
|
||||
self, declaration: ASTDeclaration, docname: str, line: int
|
||||
) -> Symbol:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("add_declaration:")
|
||||
Symbol.debug_print('add_declaration:')
|
||||
assert declaration is not None
|
||||
assert docname is not None
|
||||
assert line is not None
|
||||
nestedName = declaration.name
|
||||
res = self._add_symbols(nestedName, declaration, docname, line)
|
||||
nested_name = declaration.name
|
||||
res = self._add_symbols(nested_name, declaration, docname, line)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 1
|
||||
return res
|
||||
|
||||
def find_identifier(self, ident: ASTIdentifier,
|
||||
matchSelf: bool, recurseInAnon: bool, searchInSiblings: bool,
|
||||
) -> Symbol | None:
|
||||
def find_identifier(
|
||||
self,
|
||||
ident: ASTIdentifier,
|
||||
matchSelf: bool,
|
||||
recurseInAnon: bool,
|
||||
searchInSiblings: bool,
|
||||
) -> Symbol | None:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("find_identifier:")
|
||||
Symbol.debug_print('find_identifier:')
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("ident: ", ident)
|
||||
Symbol.debug_print("matchSelf: ", matchSelf)
|
||||
Symbol.debug_print("recurseInAnon: ", recurseInAnon)
|
||||
Symbol.debug_print("searchInSiblings:", searchInSiblings)
|
||||
Symbol.debug_print('ident: ', ident)
|
||||
Symbol.debug_print('matchSelf: ', matchSelf)
|
||||
Symbol.debug_print('recurseInAnon: ', recurseInAnon)
|
||||
Symbol.debug_print('searchInSiblings:', searchInSiblings)
|
||||
logger.debug(self.to_string(Symbol.debug_indent + 1, addEndNewline=False))
|
||||
Symbol.debug_indent -= 2
|
||||
current = self
|
||||
while current is not None:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 2
|
||||
Symbol.debug_print("trying:")
|
||||
logger.debug(current.to_string(Symbol.debug_indent + 1, addEndNewline=False))
|
||||
Symbol.debug_print('trying:')
|
||||
logger.debug(
|
||||
current.to_string(Symbol.debug_indent + 1, addEndNewline=False)
|
||||
)
|
||||
Symbol.debug_indent -= 2
|
||||
if matchSelf and current.ident == ident:
|
||||
return current
|
||||
@ -587,49 +626,53 @@ class Symbol:
|
||||
def direct_lookup(self, key: LookupKey) -> Symbol | None:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("direct_lookup:")
|
||||
Symbol.debug_print('direct_lookup:')
|
||||
Symbol.debug_indent += 1
|
||||
s = self
|
||||
for ident, id_ in key.data:
|
||||
s = s._children_by_name.get(ident.name)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("name: ", ident.name)
|
||||
Symbol.debug_print("id: ", id_)
|
||||
Symbol.debug_print('name: ', ident.name)
|
||||
Symbol.debug_print('id: ', id_)
|
||||
if s is not None:
|
||||
logger.debug(s.to_string(Symbol.debug_indent + 1, addEndNewline=False))
|
||||
logger.debug(
|
||||
s.to_string(Symbol.debug_indent + 1, addEndNewline=False)
|
||||
)
|
||||
else:
|
||||
Symbol.debug_print("not found")
|
||||
Symbol.debug_print('not found')
|
||||
if s is None:
|
||||
break
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 2
|
||||
return s
|
||||
|
||||
def find_declaration(self, nestedName: ASTNestedName, typ: str,
|
||||
matchSelf: bool, recurseInAnon: bool) -> Symbol | None:
|
||||
def find_declaration(
|
||||
self, nestedName: ASTNestedName, typ: str, matchSelf: bool, recurseInAnon: bool
|
||||
) -> Symbol | None:
|
||||
# templateShorthand: missing template parameter lists for templates is ok
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("find_declaration:")
|
||||
Symbol.debug_print('find_declaration:')
|
||||
|
||||
def onMissingQualifiedSymbol(
|
||||
parentSymbol: Symbol,
|
||||
ident: ASTIdentifier,
|
||||
def on_missing_qualified_symbol(
|
||||
parent_symbol: Symbol, ident: ASTIdentifier
|
||||
) -> Symbol | None:
|
||||
return None
|
||||
|
||||
lookupResult = self._symbol_lookup(nestedName,
|
||||
onMissingQualifiedSymbol,
|
||||
ancestorLookupType=typ,
|
||||
matchSelf=matchSelf,
|
||||
recurseInAnon=recurseInAnon,
|
||||
searchInSiblings=False)
|
||||
lookup_result = self._symbol_lookup(
|
||||
nestedName,
|
||||
on_missing_qualified_symbol,
|
||||
ancestor_lookup_type=typ,
|
||||
match_self=matchSelf,
|
||||
recurse_in_anon=recurseInAnon,
|
||||
search_in_siblings=False,
|
||||
)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 1
|
||||
if lookupResult is None:
|
||||
if lookup_result is None:
|
||||
return None
|
||||
|
||||
symbols = list(lookupResult.symbols)
|
||||
symbols = list(lookup_result.symbols)
|
||||
if len(symbols) == 0:
|
||||
return None
|
||||
return symbols[0]
|
||||
@ -644,7 +687,7 @@ class Symbol:
|
||||
else:
|
||||
res.append(str(self.declaration))
|
||||
if self.declaration:
|
||||
res.append(": ")
|
||||
res.append(': ')
|
||||
if self.isRedeclaration:
|
||||
res.append('!!duplicate!! ')
|
||||
res.append(str(self.declaration))
|
||||
@ -657,4 +700,7 @@ class Symbol:
|
||||
return ''.join(res)
|
||||
|
||||
def dump(self, indent: int) -> str:
|
||||
return ''.join([self.to_string(indent), *(c.dump(indent + 1) for c in self._children)])
|
||||
return ''.join([
|
||||
self.to_string(indent),
|
||||
*(c.dump(indent + 1) for c in self._children),
|
||||
])
|
||||
|
Loading…
Reference in New Issue
Block a user