This repository provides User Manual for setting up a Docker environment tailored for testing DGTD code.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1422 lines
52 KiB

8 months ago
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Union, cast
from docutils import nodes
from sphinx import addnodes
from sphinx.domains.c._ids import _id_prefix, _max_id
from sphinx.util.cfamily import (
ASTAttributeList,
ASTBaseBase,
ASTBaseParenExprList,
StringifyTransform,
UnsupportedMultiCharacterCharLiteral,
verify_description_mode,
)
if TYPE_CHECKING:
from docutils.nodes import Element, Node, TextElement
from sphinx.domains.c._symbol import Symbol
from sphinx.environment import BuildEnvironment
DeclarationType = Union[
"ASTStruct", "ASTUnion", "ASTEnum", "ASTEnumerator",
"ASTType", "ASTTypeWithInit", "ASTMacro",
]
class ASTBase(ASTBaseBase):
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
raise NotImplementedError(repr(self))
# Names
################################################################################
class ASTIdentifier(ASTBaseBase):
def __init__(self, identifier: str) -> None:
assert identifier is not None
assert len(identifier) != 0
self.identifier = identifier
# ASTBaseBase already implements this method,
# but specialising it here improves performance
def __eq__(self, other: object) -> bool:
if type(other) is not ASTIdentifier:
return NotImplemented
return self.identifier == other.identifier
def is_anon(self) -> bool:
return self.identifier[0] == '@'
# and this is where we finally make a difference between __str__ and the display string
def __str__(self) -> str:
return self.identifier
def get_display_string(self) -> str:
return "[anonymous]" if self.is_anon() else self.identifier
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_anon():
node = addnodes.desc_sig_name(text="[anonymous]")
else:
node = addnodes.desc_sig_name(self.identifier, self.identifier)
if mode == 'markType':
targetText = prefix + self.identifier
pnode = addnodes.pending_xref('', refdomain='c',
reftype='identifier',
reftarget=targetText, modname=None,
classname=None)
pnode['c:parent_key'] = symbol.get_lookup_key()
pnode += node
signode += pnode
elif mode == 'lastIsName':
nameNode = addnodes.desc_name()
nameNode += node
signode += nameNode
elif mode == 'noneIsName':
signode += node
else:
raise Exception('Unknown description mode: %s' % mode)
class ASTNestedName(ASTBase):
def __init__(self, names: list[ASTIdentifier], rooted: bool) -> None:
assert len(names) > 0
self.names = names
self.rooted = rooted
@property
def name(self) -> ASTNestedName:
return self
def get_id(self, version: int) -> str:
return '.'.join(str(n) for n in self.names)
def _stringify(self, transform: StringifyTransform) -> str:
res = '.'.join(transform(n) for n in self.names)
if self.rooted:
return '.' + res
else:
return res
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?"
raise AssertionError(unreachable) # TODO
signode += nodes.Text('.')
for i in range(len(self.names)):
if i != 0:
unreachable = "Can this happen?"
raise AssertionError(unreachable) # TODO
signode += nodes.Text('.')
n = self.names[i]
n.describe_signature(signode, mode, env, '', symbol)
elif mode == 'param':
assert not self.rooted, str(self)
assert len(self.names) == 1
self.names[0].describe_signature(signode, 'noneIsName', env, '', symbol)
elif mode in ('markType', 'lastIsName', 'markName'):
# Each element should be a pending xref targeting the complete
# prefix.
prefix = ''
first = True
names = self.names[:-1] if mode == 'lastIsName' else self.names
# If lastIsName, then wrap all of the prefix in a desc_addname,
# else append directly to signode.
# TODO: also for C?
# NOTE: Breathe previously relied on the prefix being in the desc_addname node,
# so it can remove it in inner declarations.
dest = signode
if mode == 'lastIsName':
dest = addnodes.desc_addname()
if self.rooted:
prefix += '.'
if mode == 'lastIsName' and len(names) == 0:
signode += addnodes.desc_sig_punctuation('.', '.')
else:
dest += addnodes.desc_sig_punctuation('.', '.')
for i in range(len(names)):
ident = names[i]
if not first:
dest += addnodes.desc_sig_punctuation('.', '.')
prefix += '.'
first = False
txt_ident = str(ident)
if txt_ident != '':
ident.describe_signature(dest, 'markType', env, prefix, symbol)
prefix += txt_ident
if mode == 'lastIsName':
if len(self.names) > 1:
dest += addnodes.desc_sig_punctuation('.', '.')
signode += dest
self.names[-1].describe_signature(signode, mode, env, '', symbol)
else:
raise Exception('Unknown description mode: %s' % mode)
################################################################################
# Expressions
################################################################################
class ASTExpression(ASTBase):
pass
# Primary expressions
################################################################################
class ASTLiteral(ASTExpression):
pass
class ASTBooleanLiteral(ASTLiteral):
def __init__(self, value: bool) -> None:
self.value = value
def _stringify(self, transform: StringifyTransform) -> str:
if self.value:
return 'true'
else:
return 'false'
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
txt = str(self)
signode += addnodes.desc_sig_keyword(txt, txt)
class ASTNumberLiteral(ASTLiteral):
def __init__(self, data: str) -> None:
self.data = data
def _stringify(self, transform: StringifyTransform) -> str:
return self.data
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
txt = str(self)
signode += addnodes.desc_sig_literal_number(txt, txt)
class ASTCharLiteral(ASTLiteral):
def __init__(self, prefix: str, data: str) -> None:
self.prefix = prefix # may be None when no prefix
self.data = data
decoded = data.encode().decode('unicode-escape')
if len(decoded) == 1:
self.value = ord(decoded)
else:
raise UnsupportedMultiCharacterCharLiteral(decoded)
def _stringify(self, transform: StringifyTransform) -> str:
if self.prefix is None:
return "'" + self.data + "'"
else:
return self.prefix + "'" + self.data + "'"
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
txt = str(self)
signode += addnodes.desc_sig_literal_char(txt, txt)
class ASTStringLiteral(ASTLiteral):
def __init__(self, data: str) -> None:
self.data = data
def _stringify(self, transform: StringifyTransform) -> str:
return self.data
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
txt = str(self)
signode += addnodes.desc_sig_literal_string(txt, txt)
class ASTIdExpression(ASTExpression):
def __init__(self, name: ASTNestedName) -> None:
# note: this class is basically to cast a nested name as an expression
self.name = name
def _stringify(self, transform: StringifyTransform) -> str:
return transform(self.name)
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:
self.name.describe_signature(signode, mode, env, symbol)
class ASTParenExpr(ASTExpression):
def __init__(self, expr: ASTExpression) -> None:
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
return '(' + transform(self.expr) + ')'
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:
signode += addnodes.desc_sig_punctuation('(', '(')
self.expr.describe_signature(signode, mode, env, symbol)
signode += addnodes.desc_sig_punctuation(')', ')')
# Postfix expressions
################################################################################
class ASTPostfixOp(ASTBase):
pass
class ASTPostfixCallExpr(ASTPostfixOp):
def __init__(self, lst: ASTParenExprList | ASTBracedInitList) -> None:
self.lst = lst
def _stringify(self, transform: StringifyTransform) -> str:
return transform(self.lst)
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
self.lst.describe_signature(signode, mode, env, symbol)
class ASTPostfixArray(ASTPostfixOp):
def __init__(self, expr: ASTExpression) -> None:
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
return '[' + transform(self.expr) + ']'
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(']', ']')
class ASTPostfixInc(ASTPostfixOp):
def _stringify(self, transform: StringifyTransform) -> str:
return '++'
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
signode += addnodes.desc_sig_operator('++', '++')
class ASTPostfixDec(ASTPostfixOp):
def _stringify(self, transform: StringifyTransform) -> str:
return '--'
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
signode += addnodes.desc_sig_operator('--', '--')
class ASTPostfixMemberOfPointer(ASTPostfixOp):
def __init__(self, name: ASTNestedName) -> None:
self.name = name
def _stringify(self, transform: StringifyTransform) -> str:
return '->' + transform(self.name)
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)
class ASTPostfixExpr(ASTExpression):
def __init__(self, prefix: ASTExpression, postFixes: list[ASTPostfixOp]) -> None:
self.prefix = prefix
self.postFixes = postFixes
def _stringify(self, transform: StringifyTransform) -> str:
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:
self.prefix.describe_signature(signode, mode, env, symbol)
for p in self.postFixes:
p.describe_signature(signode, mode, env, symbol)
# Unary expressions
################################################################################
class ASTUnaryOpExpr(ASTExpression):
def __init__(self, op: str, expr: ASTExpression) -> None:
self.op = op
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
if self.op[0] in 'cn':
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:
if self.op[0] in 'cn':
signode += addnodes.desc_sig_keyword(self.op, self.op)
signode += addnodes.desc_sig_space()
else:
signode += addnodes.desc_sig_operator(self.op, self.op)
self.expr.describe_signature(signode, mode, env, symbol)
class ASTSizeofType(ASTExpression):
def __init__(self, typ: ASTType) -> None:
self.typ = typ
def _stringify(self, transform: StringifyTransform) -> str:
return "sizeof(" + transform(self.typ) + ")"
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)
signode += addnodes.desc_sig_punctuation(')', ')')
class ASTSizeofExpr(ASTExpression):
def __init__(self, expr: ASTExpression) -> None:
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
return "sizeof " + transform(self.expr)
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)
class ASTAlignofExpr(ASTExpression):
def __init__(self, typ: ASTType) -> None:
self.typ = typ
def _stringify(self, transform: StringifyTransform) -> str:
return "alignof(" + transform(self.typ) + ")"
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)
signode += addnodes.desc_sig_punctuation(')', ')')
# Other expressions
################################################################################
class ASTCastExpr(ASTExpression):
def __init__(self, typ: ASTType, expr: ASTExpression) -> None:
self.typ = typ
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
res = ['(']
res.append(transform(self.typ))
res.append(')')
res.append(transform(self.expr))
return ''.join(res)
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(')', ')')
self.expr.describe_signature(signode, mode, env, symbol)
class ASTBinOpExpr(ASTBase):
def __init__(self, exprs: list[ASTExpression], ops: list[str]) -> None:
assert len(exprs) > 0
assert len(exprs) == len(ops) + 1
self.exprs = exprs
self.ops = ops
def _stringify(self, transform: StringifyTransform) -> str:
res = []
res.append(transform(self.exprs[0]))
for i in range(1, len(self.exprs)):
res.append(' ')
res.append(self.ops[i - 1])
res.append(' ')
res.append(transform(self.exprs[i]))
return ''.join(res)
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()
op = self.ops[i - 1]
if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'):
signode += addnodes.desc_sig_keyword(op, op)
else:
signode += addnodes.desc_sig_operator(op, op)
signode += addnodes.desc_sig_space()
self.exprs[i].describe_signature(signode, mode, env, symbol)
class ASTAssignmentExpr(ASTExpression):
def __init__(self, exprs: list[ASTExpression], ops: list[str]) -> None:
assert len(exprs) > 0
assert len(exprs) == len(ops) + 1
self.exprs = exprs
self.ops = ops
def _stringify(self, transform: StringifyTransform) -> str:
res = []
res.append(transform(self.exprs[0]))
for i in range(1, len(self.exprs)):
res.append(' ')
res.append(self.ops[i - 1])
res.append(' ')
res.append(transform(self.exprs[i]))
return ''.join(res)
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()
op = self.ops[i - 1]
if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'):
signode += addnodes.desc_sig_keyword(op, op)
else:
signode += addnodes.desc_sig_operator(op, op)
signode += addnodes.desc_sig_space()
self.exprs[i].describe_signature(signode, mode, env, symbol)
class ASTFallbackExpr(ASTExpression):
def __init__(self, expr: str) -> None:
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
return self.expr
def get_id(self, version: int) -> str:
return str(self.expr)
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
signode += nodes.literal(self.expr, self.expr)
################################################################################
# Types
################################################################################
class ASTTrailingTypeSpec(ASTBase):
pass
class ASTTrailingTypeSpecFundamental(ASTTrailingTypeSpec):
def __init__(self, names: list[str]) -> None:
assert len(names) != 0
self.names = names
def _stringify(self, transform: StringifyTransform) -> str:
return ' '.join(self.names)
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
first = True
for n in self.names:
if not first:
signode += addnodes.desc_sig_space()
else:
first = False
signode += addnodes.desc_sig_keyword_type(n, n)
class ASTTrailingTypeSpecName(ASTTrailingTypeSpec):
def __init__(self, prefix: str, nestedName: ASTNestedName) -> None:
self.prefix = prefix
self.nestedName = nestedName
@property
def name(self) -> ASTNestedName:
return self.nestedName
def _stringify(self, transform: StringifyTransform) -> str:
res = []
if self.prefix:
res.append(self.prefix)
res.append(' ')
res.append(transform(self.nestedName))
return ''.join(res)
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()
self.nestedName.describe_signature(signode, mode, env, symbol=symbol)
class ASTFunctionParameter(ASTBase):
def __init__(self, arg: ASTTypeWithInit | None, ellipsis: bool = False) -> None:
self.arg = arg
self.ellipsis = ellipsis
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
# the anchor will be our parent
return symbol.parent.declaration.get_id(version, prefixed=False)
def _stringify(self, transform: StringifyTransform) -> str:
if self.ellipsis:
return '...'
else:
return transform(self.arg)
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('...', '...')
else:
self.arg.describe_signature(signode, mode, env, symbol=symbol)
class ASTParameters(ASTBase):
def __init__(self, args: list[ASTFunctionParameter], attrs: ASTAttributeList) -> None:
self.args = args
self.attrs = attrs
@property
def function_params(self) -> list[ASTFunctionParameter]:
return self.args
def _stringify(self, transform: StringifyTransform) -> str:
res = []
res.append('(')
first = True
for a in self.args:
if not first:
res.append(', ')
first = False
res.append(str(a))
res.append(')')
if len(self.attrs) != 0:
res.append(' ')
res.append(transform(self.attrs))
return ''.join(res)
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
while test_node.parent:
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)
break
# only use the desc_parameterlist for the outer list, not for inner lists
if mode == 'lastIsName':
paramlist = addnodes.desc_parameterlist()
paramlist['multi_line_parameter_list'] = multi_line_parameter_list
for arg in self.args:
param = addnodes.desc_parameter('', '', noemph=True)
arg.describe_signature(param, 'param', env, symbol=symbol)
paramlist += param
signode += paramlist
else:
signode += addnodes.desc_sig_punctuation('(', '(')
first = True
for arg in self.args:
if not first:
signode += addnodes.desc_sig_punctuation(',', ',')
signode += addnodes.desc_sig_space()
first = False
arg.describe_signature(signode, 'markType', env, symbol=symbol)
signode += addnodes.desc_sig_punctuation(')', ')')
if len(self.attrs) != 0:
signode += addnodes.desc_sig_space()
self.attrs.describe_signature(signode)
class ASTDeclSpecsSimple(ASTBaseBase):
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
self.restrict = restrict
self.volatile = volatile
self.const = const
self.attrs = attrs
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)
def _stringify(self, transform: StringifyTransform) -> str:
res: list[str] = []
if len(self.attrs) != 0:
res.append(transform(self.attrs))
if self.storage:
res.append(self.storage)
if self.threadLocal:
res.append(self.threadLocal)
if self.inline:
res.append('inline')
if self.restrict:
res.append('restrict')
if self.volatile:
res.append('volatile')
if self.const:
res.append('const')
return ' '.join(res)
def describe_signature(self, modifiers: list[Node]) -> None:
def _add(modifiers: list[Node], text: str) -> None:
if len(modifiers) != 0:
modifiers.append(addnodes.desc_sig_space())
modifiers.append(addnodes.desc_sig_keyword(text, text))
if len(modifiers) != 0 and len(self.attrs) != 0:
modifiers.append(addnodes.desc_sig_space())
tempNode = nodes.TextElement()
self.attrs.describe_signature(tempNode)
modifiers.extend(tempNode.children)
if self.storage:
_add(modifiers, self.storage)
if self.threadLocal:
_add(modifiers, self.threadLocal)
if self.inline:
_add(modifiers, 'inline')
if self.restrict:
_add(modifiers, 'restrict')
if self.volatile:
_add(modifiers, 'volatile')
if self.const:
_add(modifiers, 'const')
class ASTDeclSpecs(ASTBase):
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
self.leftSpecs = leftSpecs
self.rightSpecs = rightSpecs
self.allSpecs = self.leftSpecs.mergeWith(self.rightSpecs)
self.trailingTypeSpec = trailing
def _stringify(self, transform: StringifyTransform) -> str:
res: list[str] = []
l = transform(self.leftSpecs)
if len(l) > 0:
res.append(l)
if self.trailingTypeSpec:
if len(res) > 0:
res.append(" ")
res.append(transform(self.trailingTypeSpec))
r = str(self.rightSpecs)
if len(r) > 0:
if len(res) > 0:
res.append(" ")
res.append(r)
return "".join(res)
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
verify_description_mode(mode)
modifiers: list[Node] = []
self.leftSpecs.describe_signature(modifiers)
for m in modifiers:
signode += m
if self.trailingTypeSpec:
if len(modifiers) > 0:
signode += addnodes.desc_sig_space()
self.trailingTypeSpec.describe_signature(signode, mode, env,
symbol=symbol)
modifiers = []
self.rightSpecs.describe_signature(modifiers)
if len(modifiers) > 0:
signode += addnodes.desc_sig_space()
for m in modifiers:
signode += m
# Declarator
################################################################################
class ASTArray(ASTBase):
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
self.restrict = restrict
self.vla = vla
self.size = size
if vla:
assert size is None
if size is not None:
assert not vla
def _stringify(self, transform: StringifyTransform) -> str:
el = []
if self.static:
el.append('static')
if self.restrict:
el.append('restrict')
if self.volatile:
el.append('volatile')
if self.const:
el.append('const')
if self.vla:
return '[' + ' '.join(el) + '*]'
elif self.size:
el.append(transform(self.size))
return '[' + ' '.join(el) + ']'
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
verify_description_mode(mode)
signode += addnodes.desc_sig_punctuation('[', '[')
addSpace = False
def _add(signode: TextElement, text: str) -> bool:
if addSpace:
signode += addnodes.desc_sig_space()
signode += addnodes.desc_sig_keyword(text, text)
return True
if self.static:
addSpace = _add(signode, 'static')
if self.restrict:
addSpace = _add(signode, 'restrict')
if self.volatile:
addSpace = _add(signode, 'volatile')
if self.const:
addSpace = _add(signode, 'const')
if self.vla:
signode += addnodes.desc_sig_punctuation('*', '*')
elif self.size:
if addSpace:
signode += addnodes.desc_sig_space()
self.size.describe_signature(signode, 'markType', env, symbol)
signode += addnodes.desc_sig_punctuation(']', ']')
class ASTDeclarator(ASTBase):
@property
def name(self) -> ASTNestedName:
raise NotImplementedError(repr(self))
@property
def function_params(self) -> list[ASTFunctionParameter]:
raise NotImplementedError(repr(self))
def require_space_after_declSpecs(self) -> bool:
raise NotImplementedError(repr(self))
class ASTDeclaratorNameParam(ASTDeclarator):
def __init__(self, declId: ASTNestedName,
arrayOps: list[ASTArray], param: ASTParameters) -> None:
self.declId = declId
self.arrayOps = arrayOps
self.param = param
@property
def name(self) -> ASTNestedName:
return self.declId
@property
def function_params(self) -> list[ASTFunctionParameter]:
return self.param.function_params
# ------------------------------------------------------------------------
def require_space_after_declSpecs(self) -> bool:
return self.declId is not None
def _stringify(self, transform: StringifyTransform) -> str:
res = []
if self.declId:
res.append(transform(self.declId))
res.extend(transform(op) for op in self.arrayOps)
if self.param:
res.append(transform(self.param))
return ''.join(res)
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)
for op in self.arrayOps:
op.describe_signature(signode, mode, env, symbol)
if self.param:
self.param.describe_signature(signode, mode, env, symbol)
class ASTDeclaratorNameBitField(ASTDeclarator):
def __init__(self, declId: ASTNestedName, size: ASTExpression) -> None:
self.declId = declId
self.size = size
@property
def name(self) -> ASTNestedName:
return self.declId
# ------------------------------------------------------------------------
def require_space_after_declSpecs(self) -> bool:
return self.declId is not None
def _stringify(self, transform: StringifyTransform) -> str:
res = []
if self.declId:
res.append(transform(self.declId))
res.append(" : ")
res.append(transform(self.size))
return ''.join(res)
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)
signode += addnodes.desc_sig_space()
signode += addnodes.desc_sig_punctuation(':', ':')
signode += addnodes.desc_sig_space()
self.size.describe_signature(signode, mode, env, symbol)
class ASTDeclaratorPtr(ASTDeclarator):
def __init__(self, next: ASTDeclarator, restrict: bool, volatile: bool, const: bool,
attrs: ASTAttributeList) -> None:
assert next
self.next = next
self.restrict = restrict
self.volatile = volatile
self.const = const
self.attrs = attrs
@property
def name(self) -> ASTNestedName:
return self.next.name
@property
def function_params(self) -> list[ASTFunctionParameter]:
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()
def _stringify(self, transform: StringifyTransform) -> str:
res = ['*']
res.append(transform(self.attrs))
if len(self.attrs) != 0 and (self.restrict or self.volatile or self.const):
res.append(' ')
if self.restrict:
res.append('restrict')
if self.volatile:
if self.restrict:
res.append(' ')
res.append('volatile')
if self.const:
if self.restrict or self.volatile:
res.append(' ')
res.append('const')
if self.const or self.volatile or self.restrict or len(self.attrs) > 0:
if self.next.require_space_after_declSpecs():
res.append(' ')
res.append(transform(self.next))
return ''.join(res)
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)
if len(self.attrs) != 0 and (self.restrict or self.volatile or self.const):
signode += addnodes.desc_sig_space()
def _add_anno(signode: TextElement, text: str) -> None:
signode += addnodes.desc_sig_keyword(text, text)
if self.restrict:
_add_anno(signode, 'restrict')
if self.volatile:
if self.restrict:
signode += addnodes.desc_sig_space()
_add_anno(signode, 'volatile')
if self.const:
if self.restrict or self.volatile:
signode += addnodes.desc_sig_space()
_add_anno(signode, 'const')
if self.const or self.volatile or self.restrict or len(self.attrs) > 0:
if self.next.require_space_after_declSpecs():
signode += addnodes.desc_sig_space()
self.next.describe_signature(signode, mode, env, symbol)
class ASTDeclaratorParen(ASTDeclarator):
def __init__(self, inner: ASTDeclarator, next: ASTDeclarator) -> None:
assert inner
assert next
self.inner = inner
self.next = next
# TODO: we assume the name and params are in inner
@property
def name(self) -> ASTNestedName:
return self.inner.name
@property
def function_params(self) -> list[ASTFunctionParameter]:
return self.inner.function_params
def require_space_after_declSpecs(self) -> bool:
return True
def _stringify(self, transform: StringifyTransform) -> str:
res = ['(']
res.append(transform(self.inner))
res.append(')')
res.append(transform(self.next))
return ''.join(res)
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)
# Initializer
################################################################################
class ASTParenExprList(ASTBaseParenExprList):
def __init__(self, exprs: list[ASTExpression]) -> None:
self.exprs = exprs
def _stringify(self, transform: StringifyTransform) -> str:
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:
verify_description_mode(mode)
signode += addnodes.desc_sig_punctuation('(', '(')
first = True
for e in self.exprs:
if not first:
signode += addnodes.desc_sig_punctuation(',', ',')
signode += addnodes.desc_sig_space()
else:
first = False
e.describe_signature(signode, mode, env, symbol)
signode += addnodes.desc_sig_punctuation(')', ')')
class ASTBracedInitList(ASTBase):
def __init__(self, exprs: list[ASTExpression], trailingComma: bool) -> None:
self.exprs = exprs
self.trailingComma = trailingComma
def _stringify(self, transform: StringifyTransform) -> str:
exprs = ', '.join(transform(e) for e in self.exprs)
trailingComma = ',' if self.trailingComma else ''
return f'{{{exprs}{trailingComma}}}'
def describe_signature(self, signode: TextElement, mode: str,
env: BuildEnvironment, symbol: Symbol) -> None:
verify_description_mode(mode)
signode += addnodes.desc_sig_punctuation('{', '{')
first = True
for e in self.exprs:
if not first:
signode += addnodes.desc_sig_punctuation(',', ',')
signode += addnodes.desc_sig_space()
else:
first = False
e.describe_signature(signode, mode, env, symbol)
if self.trailingComma:
signode += addnodes.desc_sig_punctuation(',', ',')
signode += addnodes.desc_sig_punctuation('}', '}')
class ASTInitializer(ASTBase):
def __init__(self, value: ASTBracedInitList | ASTExpression,
hasAssign: bool = True) -> None:
self.value = value
self.hasAssign = hasAssign
def _stringify(self, transform: StringifyTransform) -> str:
val = transform(self.value)
if self.hasAssign:
return ' = ' + val
else:
return val
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()
signode += addnodes.desc_sig_punctuation('=', '=')
signode += addnodes.desc_sig_space()
self.value.describe_signature(signode, 'markType', env, symbol)
class ASTType(ASTBase):
def __init__(self, declSpecs: ASTDeclSpecs, decl: ASTDeclarator) -> None:
assert declSpecs
assert decl
self.declSpecs = declSpecs
self.decl = decl
@property
def name(self) -> ASTNestedName:
return self.decl.name
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
return symbol.get_full_nested_name().get_id(version)
@property
def function_params(self) -> list[ASTFunctionParameter]:
return self.decl.function_params
def _stringify(self, transform: StringifyTransform) -> str:
res = []
declSpecs = transform(self.declSpecs)
res.append(declSpecs)
if self.decl.require_space_after_declSpecs() and len(declSpecs) > 0:
res.append(' ')
res.append(transform(self.decl))
return ''.join(res)
def get_type_declaration_prefix(self) -> str:
if self.declSpecs.trailingTypeSpec:
return 'typedef'
else:
return 'type'
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):
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'.
if mode == 'markType':
mode = 'noneIsName'
self.decl.describe_signature(signode, mode, env, symbol)
class ASTTypeWithInit(ASTBase):
def __init__(self, type: ASTType, init: ASTInitializer) -> None:
self.type = type
self.init = init
@property
def name(self) -> ASTNestedName:
return self.type.name
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
return self.type.get_id(version, objectType, symbol)
def _stringify(self, transform: StringifyTransform) -> str:
res = []
res.append(transform(self.type))
if self.init:
res.append(transform(self.init))
return ''.join(res)
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:
self.init.describe_signature(signode, mode, env, symbol)
class ASTMacroParameter(ASTBase):
def __init__(self, arg: ASTNestedName | None, ellipsis: bool = False,
variadic: bool = False) -> None:
self.arg = arg
self.ellipsis = ellipsis
self.variadic = variadic
def _stringify(self, transform: StringifyTransform) -> str:
if self.ellipsis:
return '...'
elif self.variadic:
return transform(self.arg) + '...'
else:
return transform(self.arg)
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('...', '...')
elif self.variadic:
name = str(self)
signode += addnodes.desc_sig_name(name, name)
else:
self.arg.describe_signature(signode, mode, env, symbol=symbol)
class ASTMacro(ASTBase):
def __init__(self, ident: ASTNestedName, args: list[ASTMacroParameter] | None) -> None:
self.ident = ident
self.args = args
@property
def name(self) -> ASTNestedName:
return self.ident
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
return symbol.get_full_nested_name().get_id(version)
def _stringify(self, transform: StringifyTransform) -> str:
res = []
res.append(transform(self.ident))
if self.args is not None:
res.append('(')
first = True
for arg in self.args:
if not first:
res.append(', ')
first = False
res.append(transform(arg))
res.append(')')
return ''.join(res)
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:
return
paramlist = addnodes.desc_parameterlist()
for arg in self.args:
param = addnodes.desc_parameter('', '', noemph=True)
arg.describe_signature(param, 'param', env, symbol=symbol)
paramlist += param
signode += paramlist
class ASTStruct(ASTBase):
def __init__(self, name: ASTNestedName) -> None:
self.name = name
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
return symbol.get_full_nested_name().get_id(version)
def _stringify(self, transform: StringifyTransform) -> str:
return transform(self.name)
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 ASTUnion(ASTBase):
def __init__(self, name: ASTNestedName) -> None:
self.name = name
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
return symbol.get_full_nested_name().get_id(version)
def _stringify(self, transform: StringifyTransform) -> str:
return transform(self.name)
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 ASTEnum(ASTBase):
def __init__(self, name: ASTNestedName) -> None:
self.name = name
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
return symbol.get_full_nested_name().get_id(version)
def _stringify(self, transform: StringifyTransform) -> str:
return transform(self.name)
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:
self.name = name
self.init = init
self.attrs = attrs
def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
return symbol.get_full_nested_name().get_id(version)
def _stringify(self, transform: StringifyTransform) -> str:
res = []
res.append(transform(self.name))
if len(self.attrs) != 0:
res.append(' ')
res.append(transform(self.attrs))
if self.init:
res.append(transform(self.init))
return ''.join(res)
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:
signode += addnodes.desc_sig_space()
self.attrs.describe_signature(signode)
if self.init:
self.init.describe_signature(signode, 'markType', env, symbol)
class ASTDeclaration(ASTBaseBase):
def __init__(self, objectType: str, directiveType: str | None,
declaration: DeclarationType | ASTFunctionParameter,
semicolon: bool = False) -> None:
self.objectType = objectType
self.directiveType = directiveType
self.declaration = declaration
self.semicolon = semicolon
self.symbol: Symbol | None = None
# set by CObject._add_enumerator_to_parent
self.enumeratorScopedSymbol: Symbol | None = None
# the cache assumes that by the time get_newest_id is called, no
# further changes will be made to this object
self._newest_id_cache: str | None = None
def clone(self) -> ASTDeclaration:
return ASTDeclaration(self.objectType, self.directiveType,
self.declaration.clone(), self.semicolon)
@property
def name(self) -> ASTNestedName:
decl = cast(DeclarationType, self.declaration)
return decl.name
@property
def function_params(self) -> list[ASTFunctionParameter] | None:
if self.objectType != 'function':
return None
decl = cast(ASTType, self.declaration)
return decl.function_params
def get_id(self, version: int, prefixed: bool = True) -> str:
if self.objectType == 'enumerator' and self.enumeratorScopedSymbol:
return self.enumeratorScopedSymbol.declaration.get_id(version, prefixed)
id_ = self.declaration.get_id(version, self.objectType, self.symbol)
if prefixed:
return _id_prefix[version] + id_
else:
return id_
def get_newest_id(self) -> str:
if self._newest_id_cache is None:
self._newest_id_cache = self.get_id(_max_id, True)
return self._newest_id_cache
def _stringify(self, transform: StringifyTransform) -> str:
res = transform(self.declaration)
if self.semicolon:
res += ';'
return res
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.
# Always enable multiline:
signode['is_multiline'] = True
# Put each line in a desc_signature_line node.
mainDeclNode = addnodes.desc_signature_line()
mainDeclNode.sphinx_line_type = 'declarator'
mainDeclNode['add_permalink'] = not self.symbol.isRedeclaration
signode += mainDeclNode
if self.objectType in {'member', 'function', 'macro'}:
pass
elif self.objectType == 'struct':
mainDeclNode += addnodes.desc_sig_keyword('struct', 'struct')
mainDeclNode += addnodes.desc_sig_space()
elif self.objectType == 'union':
mainDeclNode += addnodes.desc_sig_keyword('union', 'union')
mainDeclNode += addnodes.desc_sig_space()
elif self.objectType == 'enum':
mainDeclNode += addnodes.desc_sig_keyword('enum', 'enum')
mainDeclNode += addnodes.desc_sig_space()
elif self.objectType == 'enumerator':
mainDeclNode += addnodes.desc_sig_keyword('enumerator', 'enumerator')
mainDeclNode += addnodes.desc_sig_space()
elif self.objectType == 'type':
decl = cast(ASTType, self.declaration)
prefix = decl.get_type_declaration_prefix()
mainDeclNode += addnodes.desc_sig_keyword(prefix, prefix)
mainDeclNode += addnodes.desc_sig_space()
else:
raise AssertionError
self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
if self.semicolon:
mainDeclNode += addnodes.desc_sig_punctuation(';', ';')