mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
C, add expression parsing and expr role
This commit is contained in:
parent
815a9c657d
commit
b2ca906830
@ -674,6 +674,38 @@ Explicit ref: :c:var:`Data.@data.a`. Short-hand ref: :c:var:`Data.a`.
|
|||||||
.. versionadded:: 3.0
|
.. versionadded:: 3.0
|
||||||
|
|
||||||
|
|
||||||
|
Inline Expressions and Types
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. rst:role:: c:expr
|
||||||
|
c:texpr
|
||||||
|
|
||||||
|
Insert a C expression or type either as inline code (``cpp:expr``)
|
||||||
|
or inline text (``cpp:texpr``). For example::
|
||||||
|
|
||||||
|
.. c:var:: int a = 42
|
||||||
|
|
||||||
|
.. c:function:: int f(int i)
|
||||||
|
|
||||||
|
An expression: :c:expr:`a * f(a)` (or as text: :c:texpr:`a * f(a)`).
|
||||||
|
|
||||||
|
A type: :c:expr:`const Data*`
|
||||||
|
(or as text :c:texpr:`const Data*`).
|
||||||
|
|
||||||
|
will be rendered as follows:
|
||||||
|
|
||||||
|
.. c:var:: int a = 42
|
||||||
|
|
||||||
|
.. c:function:: int f(int i)
|
||||||
|
|
||||||
|
An expression: :c:expr:`a * f(a)` (or as text: :c:texpr:`a * f(a)`).
|
||||||
|
|
||||||
|
A type: :c:expr:`const Data*`
|
||||||
|
(or as text :c:texpr:`const Data*`).
|
||||||
|
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
|
||||||
|
|
||||||
.. _cpp-domain:
|
.. _cpp-domain:
|
||||||
|
|
||||||
The C++ Domain
|
The C++ Domain
|
||||||
|
@ -14,8 +14,9 @@ from typing import (
|
|||||||
)
|
)
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes, utils
|
||||||
from docutils.nodes import Element, Node
|
from docutils.nodes import Element, Node, TextElement, system_message
|
||||||
|
from docutils.parsers.rst.states import Inliner
|
||||||
|
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
from sphinx.addnodes import pending_xref, desc_signature
|
from sphinx.addnodes import pending_xref, desc_signature
|
||||||
@ -30,7 +31,10 @@ from sphinx.roles import XRefRole
|
|||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
from sphinx.util.cfamily import (
|
from sphinx.util.cfamily import (
|
||||||
NoOldIdError, ASTBase, verify_description_mode, StringifyTransform,
|
NoOldIdError, ASTBase, verify_description_mode, StringifyTransform,
|
||||||
BaseParser, DefinitionError, identifier_re, anon_identifier_re
|
BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral,
|
||||||
|
identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re,
|
||||||
|
hex_literal_re, binary_literal_re, float_literal_re,
|
||||||
|
char_literal_re
|
||||||
)
|
)
|
||||||
from sphinx.util.docfields import Field, TypedField
|
from sphinx.util.docfields import Field, TypedField
|
||||||
from sphinx.util.nodes import make_refnode
|
from sphinx.util.nodes import make_refnode
|
||||||
@ -49,6 +53,24 @@ _keywords = [
|
|||||||
'_Thread_local', 'thread_local',
|
'_Thread_local', 'thread_local',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# these are ordered by preceedence
|
||||||
|
_expression_bin_ops = [
|
||||||
|
['||'],
|
||||||
|
['&&'],
|
||||||
|
['|'],
|
||||||
|
['^'],
|
||||||
|
['&'],
|
||||||
|
['==', '!='],
|
||||||
|
['<=', '>=', '<', '>'],
|
||||||
|
['<<', '>>'],
|
||||||
|
['+', '-'],
|
||||||
|
['*', '/', '%'],
|
||||||
|
['.*', '->*']
|
||||||
|
]
|
||||||
|
_expression_unary_ops = ["++", "--", "*", "&", "+", "-", "!", "~"]
|
||||||
|
_expression_assignment_ops = ["=", "*=", "/=", "%=", "+=", "-=",
|
||||||
|
">>=", "<<=", "&=", "^=", "|="]
|
||||||
|
|
||||||
_max_id = 1
|
_max_id = 1
|
||||||
_id_prefix = [None, 'c.', 'Cv2.']
|
_id_prefix = [None, 'c.', 'Cv2.']
|
||||||
# Ids are used in lookup keys which are used across pickled files,
|
# Ids are used in lookup keys which are used across pickled files,
|
||||||
@ -69,7 +91,307 @@ class _DuplicateSymbolError(Exception):
|
|||||||
return "Internal C duplicate symbol error:\n%s" % self.symbol.dump(0)
|
return "Internal C duplicate symbol error:\n%s" % self.symbol.dump(0)
|
||||||
|
|
||||||
|
|
||||||
##############################################################################################
|
################################################################################
|
||||||
|
# Expressions and Literals
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
class ASTBooleanLiteral(ASTBase):
|
||||||
|
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: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text(str(self)))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTNumberLiteral(ASTBase):
|
||||||
|
def __init__(self, data: str) -> None:
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return self.data
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
txt = str(self)
|
||||||
|
signode.append(nodes.Text(txt, txt))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTCharLiteral(ASTBase):
|
||||||
|
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: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
txt = str(self)
|
||||||
|
signode.append(nodes.Text(txt, txt))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTStringLiteral(ASTBase):
|
||||||
|
def __init__(self, data: str) -> None:
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return self.data
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
txt = str(self)
|
||||||
|
signode.append(nodes.Text(txt, txt))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTParenExpr(ASTBase):
|
||||||
|
def __init__(self, expr):
|
||||||
|
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)
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text('(', '('))
|
||||||
|
self.expr.describe_signature(signode, mode, env, symbol)
|
||||||
|
signode.append(nodes.Text(')', ')'))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTBinOpExpr(ASTBase):
|
||||||
|
def __init__(self, exprs, ops):
|
||||||
|
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: desc_signature, 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.append(nodes.Text(' '))
|
||||||
|
signode.append(nodes.Text(self.ops[i - 1]))
|
||||||
|
signode.append(nodes.Text(' '))
|
||||||
|
self.exprs[i].describe_signature(signode, mode, env, symbol)
|
||||||
|
|
||||||
|
|
||||||
|
class ASTAssignmentExpr(ASTBase):
|
||||||
|
def __init__(self, exprs, ops):
|
||||||
|
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: desc_signature, 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.append(nodes.Text(' '))
|
||||||
|
signode.append(nodes.Text(self.ops[i - 1]))
|
||||||
|
signode.append(nodes.Text(' '))
|
||||||
|
self.exprs[i].describe_signature(signode, mode, env, symbol)
|
||||||
|
|
||||||
|
|
||||||
|
class ASTCastExpr(ASTBase):
|
||||||
|
def __init__(self, typ, expr):
|
||||||
|
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: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text('('))
|
||||||
|
self.typ.describe_signature(signode, mode, env, symbol)
|
||||||
|
signode.append(nodes.Text(')'))
|
||||||
|
self.expr.describe_signature(signode, mode, env, symbol)
|
||||||
|
|
||||||
|
|
||||||
|
class ASTUnaryOpExpr(ASTBase):
|
||||||
|
def __init__(self, op, expr):
|
||||||
|
self.op = op
|
||||||
|
self.expr = expr
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return transform(self.op) + transform(self.expr)
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text(self.op))
|
||||||
|
self.expr.describe_signature(signode, mode, env, symbol)
|
||||||
|
|
||||||
|
|
||||||
|
class ASTSizeofType(ASTBase):
|
||||||
|
def __init__(self, typ):
|
||||||
|
self.typ = typ
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return "sizeof(" + transform(self.typ) + ")"
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text('sizeof('))
|
||||||
|
self.typ.describe_signature(signode, mode, env, symbol)
|
||||||
|
signode.append(nodes.Text(')'))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTSizeofExpr(ASTBase):
|
||||||
|
def __init__(self, expr):
|
||||||
|
self.expr = expr
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return "sizeof " + transform(self.expr)
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text('sizeof '))
|
||||||
|
self.expr.describe_signature(signode, mode, env, symbol)
|
||||||
|
|
||||||
|
|
||||||
|
class ASTAlignofExpr(ASTBase):
|
||||||
|
def __init__(self, typ):
|
||||||
|
self.typ = typ
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return "alignof(" + transform(self.typ) + ")"
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text('alignof('))
|
||||||
|
self.typ.describe_signature(signode, mode, env, symbol)
|
||||||
|
signode.append(nodes.Text(')'))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTPostfixCallExpr(ASTBase):
|
||||||
|
def __init__(self, lst: Union["ASTParenExprList", "ASTBracedInitList"]) -> None:
|
||||||
|
self.lst = lst
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return transform(self.lst)
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
self.lst.describe_signature(signode, mode, env, symbol)
|
||||||
|
|
||||||
|
|
||||||
|
class ASTPostfixArray(ASTBase):
|
||||||
|
def __init__(self, expr):
|
||||||
|
self.expr = expr
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return '[' + transform(self.expr) + ']'
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text('['))
|
||||||
|
self.expr.describe_signature(signode, mode, env, symbol)
|
||||||
|
signode.append(nodes.Text(']'))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTPostfixInc(ASTBase):
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return '++'
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text('++'))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTPostfixDec(ASTBase):
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return '--'
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text('--'))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTPostfixMember(ASTBase):
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return '.' + transform(self.name)
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text('.'))
|
||||||
|
self.name.describe_signature(signode, 'noneIsName', env, symbol)
|
||||||
|
|
||||||
|
|
||||||
|
class ASTPostfixMemberOfPointer(ASTBase):
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
return '->' + transform(self.name)
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
signode.append(nodes.Text('->'))
|
||||||
|
self.name.describe_signature(signode, 'noneIsName', env, symbol)
|
||||||
|
|
||||||
|
|
||||||
|
class ASTPostfixExpr(ASTBase):
|
||||||
|
def __init__(self, prefix, postFixes):
|
||||||
|
assert len(postFixes) > 0
|
||||||
|
self.prefix = prefix
|
||||||
|
self.postFixes = postFixes
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
res = [transform(self.prefix)]
|
||||||
|
for p in self.postFixes:
|
||||||
|
res.append(transform(p))
|
||||||
|
return ''.join(res)
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, 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)
|
||||||
|
|
||||||
|
|
||||||
class ASTFallbackExpr(ASTBase):
|
class ASTFallbackExpr(ASTBase):
|
||||||
def __init__(self, expr):
|
def __init__(self, expr):
|
||||||
@ -452,7 +774,9 @@ class ASTDeclaratorPtr(ASTBase):
|
|||||||
return self.next.function_params
|
return self.next.function_params
|
||||||
|
|
||||||
def require_space_after_declSpecs(self) -> bool:
|
def require_space_after_declSpecs(self) -> bool:
|
||||||
return True
|
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:
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
res = ['*']
|
res = ['*']
|
||||||
@ -598,9 +922,7 @@ class ASTDeclaratorNameBitField(ASTBase):
|
|||||||
if self.declId:
|
if self.declId:
|
||||||
res.append(transform(self.declId))
|
res.append(transform(self.declId))
|
||||||
res.append(" : ")
|
res.append(" : ")
|
||||||
# TODO: when size is properly parsed
|
res.append(transform(self.size))
|
||||||
# res.append(transform(self.size))
|
|
||||||
res.append(self.size)
|
|
||||||
return ''.join(res)
|
return ''.join(res)
|
||||||
|
|
||||||
def describe_signature(self, signode: desc_signature, mode: str,
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
@ -609,11 +931,58 @@ class ASTDeclaratorNameBitField(ASTBase):
|
|||||||
if self.declId:
|
if self.declId:
|
||||||
self.declId.describe_signature(signode, mode, env, symbol)
|
self.declId.describe_signature(signode, mode, env, symbol)
|
||||||
signode += nodes.Text(' : ', ' : ')
|
signode += nodes.Text(' : ', ' : ')
|
||||||
# TODO: when size is properly parsed
|
self.size.describe_signature(signode, mode, env, symbol)
|
||||||
# self.size.describe_signature(signode, mode, env, symbol)
|
|
||||||
signode += nodes.Text(self.size, self.size)
|
signode += nodes.Text(self.size, self.size)
|
||||||
|
|
||||||
|
|
||||||
|
class ASTParenExprList(ASTBase):
|
||||||
|
def __init__(self, exprs: List[Any]) -> 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: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
verify_description_mode(mode)
|
||||||
|
signode.append(nodes.Text('('))
|
||||||
|
first = True
|
||||||
|
for e in self.exprs:
|
||||||
|
if not first:
|
||||||
|
signode.append(nodes.Text(', '))
|
||||||
|
else:
|
||||||
|
first = False
|
||||||
|
e.describe_signature(signode, mode, env, symbol)
|
||||||
|
signode.append(nodes.Text(')'))
|
||||||
|
|
||||||
|
|
||||||
|
class ASTBracedInitList(ASTBase):
|
||||||
|
def __init__(self, exprs: List[Any], trailingComma: bool) -> None:
|
||||||
|
self.exprs = exprs
|
||||||
|
self.trailingComma = trailingComma
|
||||||
|
|
||||||
|
def _stringify(self, transform: StringifyTransform) -> str:
|
||||||
|
exprs = [transform(e) for e in self.exprs]
|
||||||
|
trailingComma = ',' if self.trailingComma else ''
|
||||||
|
return '{%s%s}' % (', '.join(exprs), trailingComma)
|
||||||
|
|
||||||
|
def describe_signature(self, signode: desc_signature, mode: str,
|
||||||
|
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||||
|
verify_description_mode(mode)
|
||||||
|
signode.append(nodes.Text('{'))
|
||||||
|
first = True
|
||||||
|
for e in self.exprs:
|
||||||
|
if not first:
|
||||||
|
signode.append(nodes.Text(', '))
|
||||||
|
else:
|
||||||
|
first = False
|
||||||
|
e.describe_signature(signode, mode, env, symbol)
|
||||||
|
if self.trailingComma:
|
||||||
|
signode.append(nodes.Text(','))
|
||||||
|
signode.append(nodes.Text('}'))
|
||||||
|
|
||||||
|
|
||||||
class ASTInitializer(ASTBase):
|
class ASTInitializer(ASTBase):
|
||||||
def __init__(self, value: Any, hasAssign: bool = True) -> None:
|
def __init__(self, value: Any, hasAssign: bool = True) -> None:
|
||||||
self.value = value
|
self.value = value
|
||||||
@ -1526,6 +1895,25 @@ class DefinitionParser(BaseParser):
|
|||||||
|
|
||||||
_prefix_keys = ('struct', 'enum', 'union')
|
_prefix_keys = ('struct', 'enum', 'union')
|
||||||
|
|
||||||
|
def _parse_string(self):
|
||||||
|
if self.current_char != '"':
|
||||||
|
return None
|
||||||
|
startPos = self.pos
|
||||||
|
self.pos += 1
|
||||||
|
escape = False
|
||||||
|
while True:
|
||||||
|
if self.eof:
|
||||||
|
self.fail("Unexpected end during inside string.")
|
||||||
|
elif self.current_char == '"' and not escape:
|
||||||
|
self.pos += 1
|
||||||
|
break
|
||||||
|
elif self.current_char == '\\':
|
||||||
|
escape = True
|
||||||
|
else:
|
||||||
|
escape = False
|
||||||
|
self.pos += 1
|
||||||
|
return self.definition[startPos:self.pos]
|
||||||
|
|
||||||
def _parse_attribute(self) -> Any:
|
def _parse_attribute(self) -> Any:
|
||||||
return None
|
return None
|
||||||
# self.skip_ws()
|
# self.skip_ws()
|
||||||
@ -1586,23 +1974,340 @@ class DefinitionParser(BaseParser):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _parse_literal(self):
|
||||||
|
# -> integer-literal
|
||||||
|
# | character-literal
|
||||||
|
# | floating-literal
|
||||||
|
# | string-literal
|
||||||
|
# | boolean-literal -> "false" | "true"
|
||||||
|
self.skip_ws()
|
||||||
|
if self.skip_word('true'):
|
||||||
|
return ASTBooleanLiteral(True)
|
||||||
|
if self.skip_word('false'):
|
||||||
|
return ASTBooleanLiteral(False)
|
||||||
|
for regex in [float_literal_re, binary_literal_re, hex_literal_re,
|
||||||
|
integer_literal_re, octal_literal_re]:
|
||||||
|
pos = self.pos
|
||||||
|
if self.match(regex):
|
||||||
|
while self.current_char in 'uUlLfF':
|
||||||
|
self.pos += 1
|
||||||
|
return ASTNumberLiteral(self.definition[pos:self.pos])
|
||||||
|
|
||||||
|
string = self._parse_string()
|
||||||
|
if string is not None:
|
||||||
|
return ASTStringLiteral(string)
|
||||||
|
|
||||||
|
# character-literal
|
||||||
|
if self.match(char_literal_re):
|
||||||
|
prefix = self.last_match.group(1) # may be None when no prefix
|
||||||
|
data = self.last_match.group(2)
|
||||||
|
try:
|
||||||
|
return ASTCharLiteral(prefix, data)
|
||||||
|
except UnicodeDecodeError as 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.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _parse_paren_expression(self):
|
||||||
|
# "(" expression ")"
|
||||||
|
if self.current_char != '(':
|
||||||
|
return None
|
||||||
|
self.pos += 1
|
||||||
|
res = self._parse_expression()
|
||||||
|
self.skip_ws()
|
||||||
|
if not self.skip_string(')'):
|
||||||
|
self.fail("Expected ')' in end of parenthesized expression.")
|
||||||
|
return ASTParenExpr(res)
|
||||||
|
|
||||||
|
def _parse_primary_expression(self):
|
||||||
|
# literal
|
||||||
|
# "(" expression ")"
|
||||||
|
# id-expression -> we parse this with _parse_nested_name
|
||||||
|
self.skip_ws()
|
||||||
|
res = self._parse_literal()
|
||||||
|
if res is not None:
|
||||||
|
return res
|
||||||
|
res = self._parse_paren_expression()
|
||||||
|
if res is not None:
|
||||||
|
return res
|
||||||
|
return self._parse_nested_name()
|
||||||
|
|
||||||
|
def _parse_initializer_list(self, name: str, open: str, close: str
|
||||||
|
) -> Tuple[List[Any], bool]:
|
||||||
|
# Parse open and close with the actual initializer-list inbetween
|
||||||
|
# -> initializer-clause '...'[opt]
|
||||||
|
# | initializer-list ',' initializer-clause '...'[opt]
|
||||||
|
# TODO: designators
|
||||||
|
self.skip_ws()
|
||||||
|
if not self.skip_string_and_ws(open):
|
||||||
|
return None, None
|
||||||
|
if self.skip_string(close):
|
||||||
|
return [], False
|
||||||
|
|
||||||
|
exprs = []
|
||||||
|
trailingComma = False
|
||||||
|
while True:
|
||||||
|
self.skip_ws()
|
||||||
|
expr = self._parse_expression()
|
||||||
|
self.skip_ws()
|
||||||
|
exprs.append(expr)
|
||||||
|
self.skip_ws()
|
||||||
|
if self.skip_string(close):
|
||||||
|
break
|
||||||
|
if not self.skip_string_and_ws(','):
|
||||||
|
self.fail("Error in %s, expected ',' or '%s'." % (name, close))
|
||||||
|
if self.current_char == close and close == '}':
|
||||||
|
self.pos += 1
|
||||||
|
trailingComma = True
|
||||||
|
break
|
||||||
|
return exprs, trailingComma
|
||||||
|
|
||||||
|
def _parse_paren_expression_list(self) -> ASTParenExprList:
|
||||||
|
# -> '(' expression-list ')'
|
||||||
|
# though, we relax it to also allow empty parens
|
||||||
|
# as it's needed in some cases
|
||||||
|
#
|
||||||
|
# expression-list
|
||||||
|
# -> initializer-list
|
||||||
|
exprs, trailingComma = self._parse_initializer_list("parenthesized expression-list",
|
||||||
|
'(', ')')
|
||||||
|
if exprs is None:
|
||||||
|
return None
|
||||||
|
return ASTParenExprList(exprs)
|
||||||
|
|
||||||
|
def _parse_braced_init_list(self) -> ASTBracedInitList:
|
||||||
|
# -> '{' initializer-list ','[opt] '}'
|
||||||
|
# | '{' '}'
|
||||||
|
exprs, trailingComma = self._parse_initializer_list("braced-init-list", '{', '}')
|
||||||
|
if exprs is None:
|
||||||
|
return None
|
||||||
|
return ASTBracedInitList(exprs, trailingComma)
|
||||||
|
|
||||||
|
def _parse_postfix_expression(self):
|
||||||
|
# -> primary
|
||||||
|
# | postfix "[" expression "]"
|
||||||
|
# | postfix "[" braced-init-list [opt] "]"
|
||||||
|
# | postfix "(" expression-list [opt] ")"
|
||||||
|
# | postfix "." id-expression
|
||||||
|
# | postfix "->" id-expression
|
||||||
|
# | postfix "++"
|
||||||
|
# | postfix "--"
|
||||||
|
|
||||||
|
prefix = self._parse_primary_expression()
|
||||||
|
|
||||||
|
# and now parse postfixes
|
||||||
|
postFixes = [] # type: List[Any]
|
||||||
|
while True:
|
||||||
|
self.skip_ws()
|
||||||
|
if self.skip_string_and_ws('['):
|
||||||
|
expr = self._parse_expression()
|
||||||
|
self.skip_ws()
|
||||||
|
if not self.skip_string(']'):
|
||||||
|
self.fail("Expected ']' in end of postfix expression.")
|
||||||
|
postFixes.append(ASTPostfixArray(expr))
|
||||||
|
continue
|
||||||
|
if self.skip_string('.'):
|
||||||
|
if self.skip_string('*'):
|
||||||
|
# don't steal the dot
|
||||||
|
self.pos -= 2
|
||||||
|
elif self.skip_string('..'):
|
||||||
|
# don't steal the dot
|
||||||
|
self.pos -= 3
|
||||||
|
else:
|
||||||
|
name = self._parse_nested_name()
|
||||||
|
postFixes.append(ASTPostfixMember(name))
|
||||||
|
continue
|
||||||
|
if self.skip_string('->'):
|
||||||
|
if self.skip_string('*'):
|
||||||
|
# don't steal the arrow
|
||||||
|
self.pos -= 3
|
||||||
|
else:
|
||||||
|
name = self._parse_nested_name()
|
||||||
|
postFixes.append(ASTPostfixMemberOfPointer(name))
|
||||||
|
continue
|
||||||
|
if self.skip_string('++'):
|
||||||
|
postFixes.append(ASTPostfixInc())
|
||||||
|
continue
|
||||||
|
if self.skip_string('--'):
|
||||||
|
postFixes.append(ASTPostfixDec())
|
||||||
|
continue
|
||||||
|
lst = self._parse_paren_expression_list()
|
||||||
|
if lst is not None:
|
||||||
|
postFixes.append(ASTPostfixCallExpr(lst))
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
if len(postFixes) == 0:
|
||||||
|
return prefix
|
||||||
|
else:
|
||||||
|
return ASTPostfixExpr(prefix, postFixes)
|
||||||
|
|
||||||
|
def _parse_unary_expression(self):
|
||||||
|
# -> postfix
|
||||||
|
# | "++" cast
|
||||||
|
# | "--" cast
|
||||||
|
# | unary-operator cast -> (* | & | + | - | ! | ~) cast
|
||||||
|
# The rest:
|
||||||
|
# | "sizeof" unary
|
||||||
|
# | "sizeof" "(" type-id ")"
|
||||||
|
# | "alignof" "(" type-id ")"
|
||||||
|
self.skip_ws()
|
||||||
|
for op in _expression_unary_ops:
|
||||||
|
# TODO: hmm, should we be able to backtrack here?
|
||||||
|
if self.skip_string(op):
|
||||||
|
expr = self._parse_cast_expression()
|
||||||
|
return ASTUnaryOpExpr(op, expr)
|
||||||
|
if self.skip_word_and_ws('sizeof'):
|
||||||
|
if self.skip_string_and_ws('('):
|
||||||
|
typ = self._parse_type(named=False)
|
||||||
|
self.skip_ws()
|
||||||
|
if not self.skip_string(')'):
|
||||||
|
self.fail("Expecting ')' to end 'sizeof'.")
|
||||||
|
return ASTSizeofType(typ)
|
||||||
|
expr = self._parse_unary_expression()
|
||||||
|
return ASTSizeofExpr(expr)
|
||||||
|
if self.skip_word_and_ws('alignof'):
|
||||||
|
if not self.skip_string_and_ws('('):
|
||||||
|
self.fail("Expecting '(' after 'alignof'.")
|
||||||
|
typ = self._parse_type(named=False)
|
||||||
|
self.skip_ws()
|
||||||
|
if not self.skip_string(')'):
|
||||||
|
self.fail("Expecting ')' to end 'alignof'.")
|
||||||
|
return ASTAlignofExpr(typ)
|
||||||
|
return self._parse_postfix_expression()
|
||||||
|
|
||||||
|
def _parse_cast_expression(self):
|
||||||
|
# -> unary | "(" type-id ")" cast
|
||||||
|
pos = self.pos
|
||||||
|
self.skip_ws()
|
||||||
|
if self.skip_string('('):
|
||||||
|
try:
|
||||||
|
typ = self._parse_type(False)
|
||||||
|
if not self.skip_string(')'):
|
||||||
|
self.fail("Expected ')' in cast expression.")
|
||||||
|
expr = self._parse_cast_expression()
|
||||||
|
return ASTCastExpr(typ, expr)
|
||||||
|
except DefinitionError as exCast:
|
||||||
|
self.pos = pos
|
||||||
|
try:
|
||||||
|
return self._parse_unary_expression()
|
||||||
|
except DefinitionError as exUnary:
|
||||||
|
errs = []
|
||||||
|
errs.append((exCast, "If type cast expression"))
|
||||||
|
errs.append((exUnary, "If unary expression"))
|
||||||
|
raise self._make_multi_error(errs, "Error in cast expression.")
|
||||||
|
else:
|
||||||
|
return self._parse_unary_expression()
|
||||||
|
|
||||||
|
def _parse_logical_or_expression(self):
|
||||||
|
# logical-or = logical-and ||
|
||||||
|
# logical-and = inclusive-or &&
|
||||||
|
# inclusive-or = exclusive-or |
|
||||||
|
# exclusive-or = and ^
|
||||||
|
# and = equality &
|
||||||
|
# equality = relational ==, !=
|
||||||
|
# relational = shift <, >, <=, >=
|
||||||
|
# shift = additive <<, >>
|
||||||
|
# additive = multiplicative +, -
|
||||||
|
# multiplicative = pm *, /, %
|
||||||
|
# pm = cast .*, ->*
|
||||||
|
def _parse_bin_op_expr(self, opId):
|
||||||
|
if opId + 1 == len(_expression_bin_ops):
|
||||||
|
def parser():
|
||||||
|
return self._parse_cast_expression()
|
||||||
|
else:
|
||||||
|
def parser():
|
||||||
|
return _parse_bin_op_expr(self, opId + 1)
|
||||||
|
exprs = []
|
||||||
|
ops = []
|
||||||
|
exprs.append(parser())
|
||||||
|
while True:
|
||||||
|
self.skip_ws()
|
||||||
|
pos = self.pos
|
||||||
|
oneMore = False
|
||||||
|
for op in _expression_bin_ops[opId]:
|
||||||
|
if not self.skip_string(op):
|
||||||
|
continue
|
||||||
|
if op == '&' and self.current_char == '&':
|
||||||
|
# don't split the && 'token'
|
||||||
|
self.pos -= 1
|
||||||
|
# and btw. && has lower precedence, so we are done
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
expr = parser()
|
||||||
|
exprs.append(expr)
|
||||||
|
ops.append(op)
|
||||||
|
oneMore = True
|
||||||
|
break
|
||||||
|
except DefinitionError:
|
||||||
|
self.pos = pos
|
||||||
|
if not oneMore:
|
||||||
|
break
|
||||||
|
return ASTBinOpExpr(exprs, ops)
|
||||||
|
return _parse_bin_op_expr(self, 0)
|
||||||
|
|
||||||
|
def _parse_conditional_expression_tail(self, orExprHead):
|
||||||
|
# -> "?" expression ":" assignment-expression
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _parse_assignment_expression(self):
|
||||||
|
# -> conditional-expression
|
||||||
|
# | logical-or-expression assignment-operator initializer-clause
|
||||||
|
# -> conditional-expression ->
|
||||||
|
# logical-or-expression
|
||||||
|
# | logical-or-expression "?" expression ":" assignment-expression
|
||||||
|
# | logical-or-expression assignment-operator initializer-clause
|
||||||
|
exprs = []
|
||||||
|
ops = []
|
||||||
|
orExpr = self._parse_logical_or_expression()
|
||||||
|
exprs.append(orExpr)
|
||||||
|
# TODO: handle ternary with _parse_conditional_expression_tail
|
||||||
|
while True:
|
||||||
|
oneMore = False
|
||||||
|
self.skip_ws()
|
||||||
|
for op in _expression_assignment_ops:
|
||||||
|
if not self.skip_string(op):
|
||||||
|
continue
|
||||||
|
expr = self._parse_logical_or_expression()
|
||||||
|
exprs.append(expr)
|
||||||
|
ops.append(op)
|
||||||
|
oneMore = True
|
||||||
|
if not oneMore:
|
||||||
|
break
|
||||||
|
if len(ops) == 0:
|
||||||
|
return orExpr
|
||||||
|
else:
|
||||||
|
return ASTAssignmentExpr(exprs, ops)
|
||||||
|
|
||||||
|
def _parse_constant_expression(self):
|
||||||
|
# -> conditional-expression
|
||||||
|
orExpr = self._parse_logical_or_expression()
|
||||||
|
# TODO: use _parse_conditional_expression_tail
|
||||||
|
return orExpr
|
||||||
|
|
||||||
|
def _parse_expression(self):
|
||||||
|
# -> assignment-expression
|
||||||
|
# | expression "," assignment-expresion
|
||||||
|
# TODO: actually parse the second production
|
||||||
|
return self._parse_assignment_expression()
|
||||||
|
|
||||||
def _parse_expression_fallback(self, end, parser, allow=True):
|
def _parse_expression_fallback(self, end, parser, allow=True):
|
||||||
# Stupidly "parse" an expression.
|
# Stupidly "parse" an expression.
|
||||||
# 'end' should be a list of characters which ends the expression.
|
# 'end' should be a list of characters which ends the expression.
|
||||||
|
|
||||||
# first try to use the provided parser
|
# first try to use the provided parser
|
||||||
# TODO: copy-paste and adapt real expression parser
|
prevPos = self.pos
|
||||||
# prevPos = self.pos
|
try:
|
||||||
# try:
|
return parser()
|
||||||
# return parser()
|
except DefinitionError as e:
|
||||||
# except DefinitionError as e:
|
# some places (e.g., template parameters) we really don't want to use fallback,
|
||||||
# # some places (e.g., template parameters) we really don't want to use fallback,
|
# and for testing we may want to globally disable it
|
||||||
# # and for testing we may want to globally disable it
|
if not allow or not self.allowFallbackExpressionParsing:
|
||||||
# if not allow or not self.allowFallbackExpressionParsing:
|
raise
|
||||||
# raise
|
self.warn("Parsing of expression failed. Using fallback parser."
|
||||||
# self.warn("Parsing of expression failed. Using fallback parser."
|
" Error was:\n%s" % e)
|
||||||
# " Error was:\n%s" % e)
|
self.pos = prevPos
|
||||||
# self.pos = prevPos
|
|
||||||
# and then the fallback scanning
|
# and then the fallback scanning
|
||||||
assert end is not None
|
assert end is not None
|
||||||
self.skip_ws()
|
self.skip_ws()
|
||||||
@ -1831,7 +2536,7 @@ class DefinitionParser(BaseParser):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
def parser():
|
def parser():
|
||||||
return self._parse_expression(inTemplate=False)
|
return self._parse_expression()
|
||||||
|
|
||||||
value = self._parse_expression_fallback([']'], parser)
|
value = self._parse_expression_fallback([']'], parser)
|
||||||
if not self.skip_string(']'):
|
if not self.skip_string(']'):
|
||||||
@ -1846,9 +2551,7 @@ class DefinitionParser(BaseParser):
|
|||||||
if named and paramMode == 'type' and typed:
|
if named and paramMode == 'type' and typed:
|
||||||
self.skip_ws()
|
self.skip_ws()
|
||||||
if self.skip_string(':'):
|
if self.skip_string(':'):
|
||||||
# TODO: copy-paste and adapt proper parser
|
size = self._parse_constant_expression()
|
||||||
# size = self._parse_constant_expression(inTemplate=False)
|
|
||||||
size = self.read_rest().strip()
|
|
||||||
return ASTDeclaratorNameBitField(declId=declId, size=size)
|
return ASTDeclaratorNameBitField(declId=declId, size=size)
|
||||||
return ASTDeclaratorNameParam(declId=declId, arrayOps=arrayOps,
|
return ASTDeclaratorNameParam(declId=declId, arrayOps=arrayOps,
|
||||||
param=param)
|
param=param)
|
||||||
@ -1939,10 +2642,9 @@ class DefinitionParser(BaseParser):
|
|||||||
if not self.skip_string('='):
|
if not self.skip_string('='):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# TODO: implement
|
bracedInit = self._parse_braced_init_list()
|
||||||
# bracedInit = self._parse_braced_init_list()
|
if bracedInit is not None:
|
||||||
# if bracedInit is not None:
|
return ASTInitializer(bracedInit)
|
||||||
# return ASTInitializer(bracedInit)
|
|
||||||
|
|
||||||
if outer == 'member':
|
if outer == 'member':
|
||||||
fallbackEnd = [] # type: List[str]
|
fallbackEnd = [] # type: List[str]
|
||||||
@ -2077,7 +2779,7 @@ class DefinitionParser(BaseParser):
|
|||||||
self.skip_ws()
|
self.skip_ws()
|
||||||
|
|
||||||
def parser():
|
def parser():
|
||||||
return self._parse_constant_expression(inTemplate=False)
|
return self._parse_constant_expression()
|
||||||
|
|
||||||
initVal = self._parse_expression_fallback([], parser)
|
initVal = self._parse_expression_fallback([], parser)
|
||||||
init = ASTInitializer(initVal)
|
init = ASTInitializer(initVal)
|
||||||
@ -2119,6 +2821,26 @@ class DefinitionParser(BaseParser):
|
|||||||
self.assert_end()
|
self.assert_end()
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
def parse_expression(self):
|
||||||
|
pos = self.pos
|
||||||
|
try:
|
||||||
|
expr = self._parse_expression()
|
||||||
|
self.skip_ws()
|
||||||
|
self.assert_end()
|
||||||
|
except DefinitionError as exExpr:
|
||||||
|
self.pos = pos
|
||||||
|
try:
|
||||||
|
expr = self._parse_type(False)
|
||||||
|
self.skip_ws()
|
||||||
|
self.assert_end()
|
||||||
|
except DefinitionError as exType:
|
||||||
|
header = "Error when parsing (type) expression."
|
||||||
|
errs = []
|
||||||
|
errs.append((exExpr, "If expression"))
|
||||||
|
errs.append((exType, "If type"))
|
||||||
|
raise self._make_multi_error(errs, header)
|
||||||
|
return expr
|
||||||
|
|
||||||
|
|
||||||
def _make_phony_error_name() -> ASTNestedName:
|
def _make_phony_error_name() -> ASTNestedName:
|
||||||
return ASTNestedName([ASTIdentifier("PhonyNameDueToError")], rooted=False)
|
return ASTNestedName([ASTIdentifier("PhonyNameDueToError")], rooted=False)
|
||||||
@ -2365,6 +3087,44 @@ class CXRefRole(XRefRole):
|
|||||||
return title, target
|
return title, target
|
||||||
|
|
||||||
|
|
||||||
|
class CExprRole:
|
||||||
|
def __init__(self, asCode: bool) -> None:
|
||||||
|
if asCode:
|
||||||
|
# render the expression as inline code
|
||||||
|
self.class_type = 'c-expr'
|
||||||
|
self.node_type = nodes.literal # type: Type[TextElement]
|
||||||
|
else:
|
||||||
|
# render the expression as inline text
|
||||||
|
self.class_type = 'c-texpr'
|
||||||
|
self.node_type = nodes.inline
|
||||||
|
|
||||||
|
def __call__(self, typ: str, rawtext: str, text: str, lineno: int,
|
||||||
|
inliner: Inliner, options: Dict = {}, content: List[str] = []
|
||||||
|
) -> Tuple[List[Node], List[system_message]]:
|
||||||
|
class Warner:
|
||||||
|
def warn(self, msg: str) -> None:
|
||||||
|
inliner.reporter.warning(msg, line=lineno)
|
||||||
|
text = utils.unescape(text).replace('\n', ' ')
|
||||||
|
env = inliner.document.settings.env
|
||||||
|
parser = DefinitionParser(text, Warner())
|
||||||
|
# attempt to mimic XRefRole classes, except that...
|
||||||
|
classes = ['xref', 'c', self.class_type]
|
||||||
|
try:
|
||||||
|
ast = parser.parse_expression()
|
||||||
|
except DefinitionError as ex:
|
||||||
|
Warner().warn('Unparseable C expression: %r\n%s' % (text, ex))
|
||||||
|
# see below
|
||||||
|
return [self.node_type(text, text, classes=classes)], []
|
||||||
|
parentSymbol = env.temp_data.get('cpp:parent_symbol', None)
|
||||||
|
if parentSymbol is None:
|
||||||
|
parentSymbol = env.domaindata['c']['root_symbol']
|
||||||
|
# ...most if not all of these classes should really apply to the individual references,
|
||||||
|
# not the container node
|
||||||
|
signode = self.node_type(classes=classes)
|
||||||
|
ast.describe_signature(signode, 'markType', env, parentSymbol)
|
||||||
|
return [signode], []
|
||||||
|
|
||||||
|
|
||||||
class CDomain(Domain):
|
class CDomain(Domain):
|
||||||
"""C language domain."""
|
"""C language domain."""
|
||||||
name = 'c'
|
name = 'c'
|
||||||
@ -2399,6 +3159,8 @@ class CDomain(Domain):
|
|||||||
'enum': CXRefRole(),
|
'enum': CXRefRole(),
|
||||||
'enumerator': CXRefRole(),
|
'enumerator': CXRefRole(),
|
||||||
'type': CXRefRole(),
|
'type': CXRefRole(),
|
||||||
|
'expr': CExprRole(asCode=True),
|
||||||
|
'texpr': CExprRole(asCode=False)
|
||||||
}
|
}
|
||||||
initial_data = {
|
initial_data = {
|
||||||
'root_symbol': Symbol(None, None, None, None),
|
'root_symbol': Symbol(None, None, None, None),
|
||||||
|
@ -36,7 +36,10 @@ from sphinx.transforms.post_transforms import ReferencesResolver
|
|||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
from sphinx.util.cfamily import (
|
from sphinx.util.cfamily import (
|
||||||
NoOldIdError, ASTBase, verify_description_mode, StringifyTransform,
|
NoOldIdError, ASTBase, verify_description_mode, StringifyTransform,
|
||||||
BaseParser, DefinitionError, identifier_re, anon_identifier_re
|
BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral,
|
||||||
|
identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re,
|
||||||
|
hex_literal_re, binary_literal_re, float_literal_re,
|
||||||
|
char_literal_re
|
||||||
)
|
)
|
||||||
from sphinx.util.docfields import Field, GroupedField
|
from sphinx.util.docfields import Field, GroupedField
|
||||||
from sphinx.util.docutils import SphinxDirective
|
from sphinx.util.docutils import SphinxDirective
|
||||||
@ -296,37 +299,6 @@ T = TypeVar('T')
|
|||||||
nested-name
|
nested-name
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_integer_literal_re = re.compile(r'[1-9][0-9]*')
|
|
||||||
_octal_literal_re = re.compile(r'0[0-7]*')
|
|
||||||
_hex_literal_re = re.compile(r'0[xX][0-9a-fA-F][0-9a-fA-F]*')
|
|
||||||
_binary_literal_re = re.compile(r'0[bB][01][01]*')
|
|
||||||
_integer_suffix_re = re.compile(r'')
|
|
||||||
_float_literal_re = re.compile(r'''(?x)
|
|
||||||
[+-]?(
|
|
||||||
# decimal
|
|
||||||
([0-9]+[eE][+-]?[0-9]+)
|
|
||||||
| ([0-9]*\.[0-9]+([eE][+-]?[0-9]+)?)
|
|
||||||
| ([0-9]+\.([eE][+-]?[0-9]+)?)
|
|
||||||
# hex
|
|
||||||
| (0[xX][0-9a-fA-F]+[pP][+-]?[0-9a-fA-F]+)
|
|
||||||
| (0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+([pP][+-]?[0-9a-fA-F]+)?)
|
|
||||||
| (0[xX][0-9a-fA-F]+\.([pP][+-]?[0-9a-fA-F]+)?)
|
|
||||||
)
|
|
||||||
''')
|
|
||||||
_char_literal_re = re.compile(r'''(?x)
|
|
||||||
((?:u8)|u|U|L)?
|
|
||||||
'(
|
|
||||||
(?:[^\\'])
|
|
||||||
| (\\(
|
|
||||||
(?:['"?\\abfnrtv])
|
|
||||||
| (?:[0-7]{1,3})
|
|
||||||
| (?:x[0-9a-fA-F]{2})
|
|
||||||
| (?:u[0-9a-fA-F]{4})
|
|
||||||
| (?:U[0-9a-fA-F]{8})
|
|
||||||
))
|
|
||||||
)'
|
|
||||||
''')
|
|
||||||
|
|
||||||
_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'"
|
_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'"
|
||||||
r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)
|
r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)
|
||||||
_visibility_re = re.compile(r'\b(public|private|protected)\b')
|
_visibility_re = re.compile(r'\b(public|private|protected)\b')
|
||||||
@ -716,15 +688,6 @@ class ASTNumberLiteral(ASTBase):
|
|||||||
signode.append(nodes.Text(txt, txt))
|
signode.append(nodes.Text(txt, txt))
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedMultiCharacterCharLiteral(Exception):
|
|
||||||
@property
|
|
||||||
def decoded(self) -> str:
|
|
||||||
warnings.warn('%s.decoded is deprecated. '
|
|
||||||
'Coerce the instance to a string instead.' % self.__class__.__name__,
|
|
||||||
RemovedInSphinx40Warning, stacklevel=2)
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
|
|
||||||
class ASTCharLiteral(ASTBase):
|
class ASTCharLiteral(ASTBase):
|
||||||
def __init__(self, prefix: str, data: str) -> None:
|
def __init__(self, prefix: str, data: str) -> None:
|
||||||
self.prefix = prefix # may be None when no prefix
|
self.prefix = prefix # may be None when no prefix
|
||||||
@ -4561,8 +4524,8 @@ class DefinitionParser(BaseParser):
|
|||||||
return ASTBooleanLiteral(True)
|
return ASTBooleanLiteral(True)
|
||||||
if self.skip_word('false'):
|
if self.skip_word('false'):
|
||||||
return ASTBooleanLiteral(False)
|
return ASTBooleanLiteral(False)
|
||||||
for regex in [_float_literal_re, _binary_literal_re, _hex_literal_re,
|
for regex in [float_literal_re, binary_literal_re, hex_literal_re,
|
||||||
_integer_literal_re, _octal_literal_re]:
|
integer_literal_re, octal_literal_re]:
|
||||||
pos = self.pos
|
pos = self.pos
|
||||||
if self.match(regex):
|
if self.match(regex):
|
||||||
while self.current_char in 'uUlLfF':
|
while self.current_char in 'uUlLfF':
|
||||||
@ -4574,7 +4537,7 @@ class DefinitionParser(BaseParser):
|
|||||||
return ASTStringLiteral(string)
|
return ASTStringLiteral(string)
|
||||||
|
|
||||||
# character-literal
|
# character-literal
|
||||||
if self.match(_char_literal_re):
|
if self.match(char_literal_re):
|
||||||
prefix = self.last_match.group(1) # may be None when no prefix
|
prefix = self.last_match.group(1) # may be None when no prefix
|
||||||
data = self.last_match.group(2)
|
data = self.last_match.group(2)
|
||||||
try:
|
try:
|
||||||
|
@ -31,6 +31,35 @@ identifier_re = re.compile(r'''(?x)
|
|||||||
)
|
)
|
||||||
[a-zA-Z0-9_]*\b
|
[a-zA-Z0-9_]*\b
|
||||||
''')
|
''')
|
||||||
|
integer_literal_re = re.compile(r'[1-9][0-9]*')
|
||||||
|
octal_literal_re = re.compile(r'0[0-7]*')
|
||||||
|
hex_literal_re = re.compile(r'0[xX][0-9a-fA-F][0-9a-fA-F]*')
|
||||||
|
binary_literal_re = re.compile(r'0[bB][01][01]*')
|
||||||
|
float_literal_re = re.compile(r'''(?x)
|
||||||
|
[+-]?(
|
||||||
|
# decimal
|
||||||
|
([0-9]+[eE][+-]?[0-9]+)
|
||||||
|
| ([0-9]*\.[0-9]+([eE][+-]?[0-9]+)?)
|
||||||
|
| ([0-9]+\.([eE][+-]?[0-9]+)?)
|
||||||
|
# hex
|
||||||
|
| (0[xX][0-9a-fA-F]+[pP][+-]?[0-9a-fA-F]+)
|
||||||
|
| (0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+([pP][+-]?[0-9a-fA-F]+)?)
|
||||||
|
| (0[xX][0-9a-fA-F]+\.([pP][+-]?[0-9a-fA-F]+)?)
|
||||||
|
)
|
||||||
|
''')
|
||||||
|
char_literal_re = re.compile(r'''(?x)
|
||||||
|
((?:u8)|u|U|L)?
|
||||||
|
'(
|
||||||
|
(?:[^\\'])
|
||||||
|
| (\\(
|
||||||
|
(?:['"?\\abfnrtv])
|
||||||
|
| (?:[0-7]{1,3})
|
||||||
|
| (?:x[0-9a-fA-F]{2})
|
||||||
|
| (?:u[0-9a-fA-F]{4})
|
||||||
|
| (?:U[0-9a-fA-F]{8})
|
||||||
|
))
|
||||||
|
)'
|
||||||
|
''')
|
||||||
|
|
||||||
|
|
||||||
def verify_description_mode(mode: str) -> None:
|
def verify_description_mode(mode: str) -> None:
|
||||||
@ -79,6 +108,15 @@ class ASTBase:
|
|||||||
return '<%s>' % self.__class__.__name__
|
return '<%s>' % self.__class__.__name__
|
||||||
|
|
||||||
|
|
||||||
|
class UnsupportedMultiCharacterCharLiteral(Exception):
|
||||||
|
@property
|
||||||
|
def decoded(self) -> str:
|
||||||
|
warnings.warn('%s.decoded is deprecated. '
|
||||||
|
'Coerce the instance to a string instead.' % self.__class__.__name__,
|
||||||
|
RemovedInSphinx40Warning, stacklevel=2)
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
|
||||||
class DefinitionError(Exception):
|
class DefinitionError(Exception):
|
||||||
@property
|
@property
|
||||||
def description(self) -> str:
|
def description(self) -> str:
|
||||||
|
@ -36,3 +36,11 @@ directives
|
|||||||
|
|
||||||
- :c:member:`A.@data.a`
|
- :c:member:`A.@data.a`
|
||||||
- :c:member:`A.a`
|
- :c:member:`A.a`
|
||||||
|
|
||||||
|
- :c:expr:`unsigned int`
|
||||||
|
- :c:texpr:`unsigned int`
|
||||||
|
|
||||||
|
.. c:var:: A a
|
||||||
|
|
||||||
|
- :c:expr:`a->b`
|
||||||
|
- :c:texpr:`a->b`
|
||||||
|
@ -86,17 +86,34 @@ def check(name, input, idDict, output=None):
|
|||||||
|
|
||||||
|
|
||||||
def test_expressions():
|
def test_expressions():
|
||||||
return # TODO
|
def exprCheck(expr, output=None):
|
||||||
def exprCheck(expr, id, id4=None):
|
parser = DefinitionParser(expr, None)
|
||||||
ids = 'IE1CIA%s_1aE'
|
parser.allowFallbackExpressionParsing = False
|
||||||
idDict = {2: ids % expr, 3: ids % id}
|
ast = parser.parse_expression()
|
||||||
if id4 is not None:
|
parser.assert_end()
|
||||||
idDict[4] = ids % id4
|
# first a simple check of the AST
|
||||||
check('class', 'template<> C<a[%s]>' % expr, idDict)
|
if output is None:
|
||||||
|
output = expr
|
||||||
|
res = str(ast)
|
||||||
|
if res != output:
|
||||||
|
print("")
|
||||||
|
print("Input: ", input)
|
||||||
|
print("Result: ", res)
|
||||||
|
print("Expected: ", output)
|
||||||
|
raise DefinitionError("")
|
||||||
|
# type expressions
|
||||||
|
exprCheck('int*')
|
||||||
|
exprCheck('int *const*')
|
||||||
|
exprCheck('int *volatile*')
|
||||||
|
exprCheck('int *restrict*')
|
||||||
|
exprCheck('int *(*)(double)')
|
||||||
|
exprCheck('const int*')
|
||||||
|
|
||||||
|
# actual expressions
|
||||||
|
|
||||||
# primary
|
# primary
|
||||||
exprCheck('nullptr', 'LDnE')
|
exprCheck('true')
|
||||||
exprCheck('true', 'L1E')
|
exprCheck('false')
|
||||||
exprCheck('false', 'L0E')
|
|
||||||
ints = ['5', '0', '075', '0x0123456789ABCDEF', '0XF', '0b1', '0B1']
|
ints = ['5', '0', '075', '0x0123456789ABCDEF', '0XF', '0b1', '0B1']
|
||||||
unsignedSuffix = ['', 'u', 'U']
|
unsignedSuffix = ['', 'u', 'U']
|
||||||
longSuffix = ['', 'l', 'L', 'll', 'LL']
|
longSuffix = ['', 'l', 'L', 'll', 'LL']
|
||||||
@ -104,9 +121,9 @@ def test_expressions():
|
|||||||
for u in unsignedSuffix:
|
for u in unsignedSuffix:
|
||||||
for l in longSuffix:
|
for l in longSuffix:
|
||||||
expr = i + u + l
|
expr = i + u + l
|
||||||
exprCheck(expr, 'L' + expr + 'E')
|
exprCheck(expr)
|
||||||
expr = i + l + u
|
expr = i + l + u
|
||||||
exprCheck(expr, 'L' + expr + 'E')
|
exprCheck(expr)
|
||||||
for suffix in ['', 'f', 'F', 'l', 'L']:
|
for suffix in ['', 'f', 'F', 'l', 'L']:
|
||||||
for e in [
|
for e in [
|
||||||
'5e42', '5e+42', '5e-42',
|
'5e42', '5e+42', '5e-42',
|
||||||
@ -114,134 +131,90 @@ def test_expressions():
|
|||||||
'.5', '.5e42', '.5e+42', '.5e-42',
|
'.5', '.5e42', '.5e+42', '.5e-42',
|
||||||
'5.0', '5.0e42', '5.0e+42', '5.0e-42']:
|
'5.0', '5.0e42', '5.0e+42', '5.0e-42']:
|
||||||
expr = e + suffix
|
expr = e + suffix
|
||||||
exprCheck(expr, 'L' + expr + 'E')
|
exprCheck(expr)
|
||||||
for e in [
|
for e in [
|
||||||
'ApF', 'Ap+F', 'Ap-F',
|
'ApF', 'Ap+F', 'Ap-F',
|
||||||
'A.', 'A.pF', 'A.p+F', 'A.p-F',
|
'A.', 'A.pF', 'A.p+F', 'A.p-F',
|
||||||
'.A', '.ApF', '.Ap+F', '.Ap-F',
|
'.A', '.ApF', '.Ap+F', '.Ap-F',
|
||||||
'A.B', 'A.BpF', 'A.Bp+F', 'A.Bp-F']:
|
'A.B', 'A.BpF', 'A.Bp+F', 'A.Bp-F']:
|
||||||
expr = "0x" + e + suffix
|
expr = "0x" + e + suffix
|
||||||
exprCheck(expr, 'L' + expr + 'E')
|
exprCheck(expr)
|
||||||
exprCheck('"abc\\"cba"', 'LA8_KcE') # string
|
exprCheck('"abc\\"cba"') # string
|
||||||
exprCheck('this', 'fpT')
|
|
||||||
# character literals
|
# character literals
|
||||||
for p, t in [('', 'c'), ('u8', 'c'), ('u', 'Ds'), ('U', 'Di'), ('L', 'w')]:
|
for p in ['', 'u8', 'u', 'U', 'L']:
|
||||||
exprCheck(p + "'a'", t + "97")
|
exprCheck(p + "'a'")
|
||||||
exprCheck(p + "'\\n'", t + "10")
|
exprCheck(p + "'\\n'")
|
||||||
exprCheck(p + "'\\012'", t + "10")
|
exprCheck(p + "'\\012'")
|
||||||
exprCheck(p + "'\\0'", t + "0")
|
exprCheck(p + "'\\0'")
|
||||||
exprCheck(p + "'\\x0a'", t + "10")
|
exprCheck(p + "'\\x0a'")
|
||||||
exprCheck(p + "'\\x0A'", t + "10")
|
exprCheck(p + "'\\x0A'")
|
||||||
exprCheck(p + "'\\u0a42'", t + "2626")
|
exprCheck(p + "'\\u0a42'")
|
||||||
exprCheck(p + "'\\u0A42'", t + "2626")
|
exprCheck(p + "'\\u0A42'")
|
||||||
exprCheck(p + "'\\U0001f34c'", t + "127820")
|
exprCheck(p + "'\\U0001f34c'")
|
||||||
exprCheck(p + "'\\U0001F34C'", t + "127820")
|
exprCheck(p + "'\\U0001F34C'")
|
||||||
|
|
||||||
# TODO: user-defined lit
|
exprCheck('(5)')
|
||||||
exprCheck('(... + Ns)', '(... + Ns)', id4='flpl2Ns')
|
exprCheck('C')
|
||||||
exprCheck('(Ns + ...)', '(Ns + ...)', id4='frpl2Ns')
|
|
||||||
exprCheck('(Ns + ... + 0)', '(Ns + ... + 0)', id4='fLpl2NsL0E')
|
|
||||||
exprCheck('(5)', 'L5E')
|
|
||||||
exprCheck('C', '1C')
|
|
||||||
# postfix
|
# postfix
|
||||||
exprCheck('A(2)', 'cl1AL2EE')
|
exprCheck('A(2)')
|
||||||
exprCheck('A[2]', 'ix1AL2E')
|
exprCheck('A[2]')
|
||||||
exprCheck('a.b.c', 'dtdt1a1b1c')
|
exprCheck('a.b.c')
|
||||||
exprCheck('a->b->c', 'ptpt1a1b1c')
|
exprCheck('a->b->c')
|
||||||
exprCheck('i++', 'pp1i')
|
exprCheck('i++')
|
||||||
exprCheck('i--', 'mm1i')
|
exprCheck('i--')
|
||||||
exprCheck('dynamic_cast<T&>(i)++', 'ppdcR1T1i')
|
|
||||||
exprCheck('static_cast<T&>(i)++', 'ppscR1T1i')
|
|
||||||
exprCheck('reinterpret_cast<T&>(i)++', 'pprcR1T1i')
|
|
||||||
exprCheck('const_cast<T&>(i)++', 'ppccR1T1i')
|
|
||||||
exprCheck('typeid(T).name', 'dtti1T4name')
|
|
||||||
exprCheck('typeid(a + b).name', 'dttepl1a1b4name')
|
|
||||||
# unary
|
# unary
|
||||||
exprCheck('++5', 'pp_L5E')
|
exprCheck('++5')
|
||||||
exprCheck('--5', 'mm_L5E')
|
exprCheck('--5')
|
||||||
exprCheck('*5', 'deL5E')
|
exprCheck('*5')
|
||||||
exprCheck('&5', 'adL5E')
|
exprCheck('&5')
|
||||||
exprCheck('+5', 'psL5E')
|
exprCheck('+5')
|
||||||
exprCheck('-5', 'ngL5E')
|
exprCheck('-5')
|
||||||
exprCheck('!5', 'ntL5E')
|
exprCheck('!5')
|
||||||
exprCheck('~5', 'coL5E')
|
exprCheck('~5')
|
||||||
exprCheck('sizeof...(a)', 'sZ1a')
|
exprCheck('sizeof(T)')
|
||||||
exprCheck('sizeof(T)', 'st1T')
|
exprCheck('sizeof -42')
|
||||||
exprCheck('sizeof -42', 'szngL42E')
|
exprCheck('alignof(T)')
|
||||||
exprCheck('alignof(T)', 'at1T')
|
|
||||||
exprCheck('noexcept(-42)', 'nxngL42E')
|
|
||||||
# new-expression
|
|
||||||
exprCheck('new int', 'nw_iE')
|
|
||||||
exprCheck('new volatile int', 'nw_ViE')
|
|
||||||
exprCheck('new int[42]', 'nw_AL42E_iE')
|
|
||||||
exprCheck('new int()', 'nw_ipiE')
|
|
||||||
exprCheck('new int(5, 42)', 'nw_ipiL5EL42EE')
|
|
||||||
exprCheck('::new int', 'nw_iE')
|
|
||||||
exprCheck('new int{}', 'nw_iilE')
|
|
||||||
exprCheck('new int{5, 42}', 'nw_iilL5EL42EE')
|
|
||||||
# delete-expression
|
|
||||||
exprCheck('delete p', 'dl1p')
|
|
||||||
exprCheck('delete [] p', 'da1p')
|
|
||||||
exprCheck('::delete p', 'dl1p')
|
|
||||||
exprCheck('::delete [] p', 'da1p')
|
|
||||||
# cast
|
# cast
|
||||||
exprCheck('(int)2', 'cviL2E')
|
exprCheck('(int)2')
|
||||||
# binary op
|
# binary op
|
||||||
exprCheck('5 || 42', 'ooL5EL42E')
|
exprCheck('5 || 42')
|
||||||
exprCheck('5 && 42', 'aaL5EL42E')
|
exprCheck('5 && 42')
|
||||||
exprCheck('5 | 42', 'orL5EL42E')
|
exprCheck('5 | 42')
|
||||||
exprCheck('5 ^ 42', 'eoL5EL42E')
|
exprCheck('5 ^ 42')
|
||||||
exprCheck('5 & 42', 'anL5EL42E')
|
exprCheck('5 & 42')
|
||||||
# ['==', '!=']
|
# ['==', '!=']
|
||||||
exprCheck('5 == 42', 'eqL5EL42E')
|
exprCheck('5 == 42')
|
||||||
exprCheck('5 != 42', 'neL5EL42E')
|
exprCheck('5 != 42')
|
||||||
# ['<=', '>=', '<', '>']
|
# ['<=', '>=', '<', '>']
|
||||||
exprCheck('5 <= 42', 'leL5EL42E')
|
exprCheck('5 <= 42')
|
||||||
exprCheck('5 >= 42', 'geL5EL42E')
|
exprCheck('5 >= 42')
|
||||||
exprCheck('5 < 42', 'ltL5EL42E')
|
exprCheck('5 < 42')
|
||||||
exprCheck('5 > 42', 'gtL5EL42E')
|
exprCheck('5 > 42')
|
||||||
# ['<<', '>>']
|
# ['<<', '>>']
|
||||||
exprCheck('5 << 42', 'lsL5EL42E')
|
exprCheck('5 << 42')
|
||||||
exprCheck('5 >> 42', 'rsL5EL42E')
|
exprCheck('5 >> 42')
|
||||||
# ['+', '-']
|
# ['+', '-']
|
||||||
exprCheck('5 + 42', 'plL5EL42E')
|
exprCheck('5 + 42')
|
||||||
exprCheck('5 - 42', 'miL5EL42E')
|
exprCheck('5 - 42')
|
||||||
# ['*', '/', '%']
|
# ['*', '/', '%']
|
||||||
exprCheck('5 * 42', 'mlL5EL42E')
|
exprCheck('5 * 42')
|
||||||
exprCheck('5 / 42', 'dvL5EL42E')
|
exprCheck('5 / 42')
|
||||||
exprCheck('5 % 42', 'rmL5EL42E')
|
exprCheck('5 % 42')
|
||||||
# ['.*', '->*']
|
# ['.*', '->*']
|
||||||
exprCheck('5 .* 42', 'dsL5EL42E')
|
|
||||||
exprCheck('5 ->* 42', 'pmL5EL42E')
|
|
||||||
# conditional
|
# conditional
|
||||||
# TODO
|
# TODO
|
||||||
# assignment
|
# assignment
|
||||||
exprCheck('a = 5', 'aS1aL5E')
|
exprCheck('a = 5')
|
||||||
exprCheck('a *= 5', 'mL1aL5E')
|
exprCheck('a *= 5')
|
||||||
exprCheck('a /= 5', 'dV1aL5E')
|
exprCheck('a /= 5')
|
||||||
exprCheck('a %= 5', 'rM1aL5E')
|
exprCheck('a %= 5')
|
||||||
exprCheck('a += 5', 'pL1aL5E')
|
exprCheck('a += 5')
|
||||||
exprCheck('a -= 5', 'mI1aL5E')
|
exprCheck('a -= 5')
|
||||||
exprCheck('a >>= 5', 'rS1aL5E')
|
exprCheck('a >>= 5')
|
||||||
exprCheck('a <<= 5', 'lS1aL5E')
|
exprCheck('a <<= 5')
|
||||||
exprCheck('a &= 5', 'aN1aL5E')
|
exprCheck('a &= 5')
|
||||||
exprCheck('a ^= 5', 'eO1aL5E')
|
exprCheck('a ^= 5')
|
||||||
exprCheck('a |= 5', 'oR1aL5E')
|
exprCheck('a |= 5')
|
||||||
|
|
||||||
# Additional tests
|
|
||||||
# a < expression that starts with something that could be a template
|
|
||||||
exprCheck('A < 42', 'lt1AL42E')
|
|
||||||
check('function', 'template<> void f(A<B, 2> &v)',
|
|
||||||
{2: "IE1fR1AI1BX2EE", 3: "IE1fR1AI1BXL2EEE", 4: "IE1fvR1AI1BXL2EEE"})
|
|
||||||
exprCheck('A<1>::value', 'N1AIXL1EEE5valueE')
|
|
||||||
check('class', "template<int T = 42> A", {2: "I_iE1A"})
|
|
||||||
check('enumerator', 'A = std::numeric_limits<unsigned long>::max()', {2: "1A"})
|
|
||||||
|
|
||||||
exprCheck('operator()()', 'clclE')
|
|
||||||
exprCheck('operator()<int>()', 'clclIiEE')
|
|
||||||
|
|
||||||
# pack expansion
|
|
||||||
exprCheck('a(b(c, 1 + d...)..., e(f..., g))', 'cl1aspcl1b1cspplL1E1dEcl1esp1f1gEE')
|
|
||||||
|
|
||||||
|
|
||||||
def test_type_definitions():
|
def test_type_definitions():
|
||||||
@ -249,6 +222,9 @@ def test_type_definitions():
|
|||||||
|
|
||||||
check('type', "bool *b", {1: 'b'})
|
check('type', "bool *b", {1: 'b'})
|
||||||
check('type', "bool *const b", {1: 'b'})
|
check('type', "bool *const b", {1: 'b'})
|
||||||
|
check('type', "bool *const *b", {1: 'b'})
|
||||||
|
check('type', "bool *volatile *b", {1: 'b'})
|
||||||
|
check('type', "bool *restrict *b", {1: 'b'})
|
||||||
check('type', "bool *volatile const b", {1: 'b'})
|
check('type', "bool *volatile const b", {1: 'b'})
|
||||||
check('type', "bool *volatile const b", {1: 'b'})
|
check('type', "bool *volatile const b", {1: 'b'})
|
||||||
check('type', "bool *volatile const *b", {1: 'b'})
|
check('type', "bool *volatile const *b", {1: 'b'})
|
||||||
@ -394,38 +370,22 @@ def test_anon_definitions():
|
|||||||
|
|
||||||
|
|
||||||
def test_initializers():
|
def test_initializers():
|
||||||
return # TODO
|
idsMember = {1: 'v'}
|
||||||
idsMember = {1: 'v__T', 2: '1v'}
|
idsFunction = {1: 'f'}
|
||||||
idsFunction = {1: 'f__T', 2: '1f1T'}
|
|
||||||
idsTemplate = {2: 'I_1TE1fv', 4: 'I_1TE1fvv'}
|
|
||||||
# no init
|
# no init
|
||||||
check('member', 'T v', idsMember)
|
check('member', 'T v', idsMember)
|
||||||
check('function', 'void f(T v)', idsFunction)
|
check('function', 'void f(T v)', idsFunction)
|
||||||
check('function', 'template<T v> void f()', idsTemplate)
|
|
||||||
# with '=', assignment-expression
|
# with '=', assignment-expression
|
||||||
check('member', 'T v = 42', idsMember)
|
check('member', 'T v = 42', idsMember)
|
||||||
check('function', 'void f(T v = 42)', idsFunction)
|
check('function', 'void f(T v = 42)', idsFunction)
|
||||||
check('function', 'template<T v = 42> void f()', idsTemplate)
|
|
||||||
# with '=', braced-init
|
# with '=', braced-init
|
||||||
check('member', 'T v = {}', idsMember)
|
check('member', 'T v = {}', idsMember)
|
||||||
check('function', 'void f(T v = {})', idsFunction)
|
check('function', 'void f(T v = {})', idsFunction)
|
||||||
check('function', 'template<T v = {}> void f()', idsTemplate)
|
|
||||||
check('member', 'T v = {42, 42, 42}', idsMember)
|
check('member', 'T v = {42, 42, 42}', idsMember)
|
||||||
check('function', 'void f(T v = {42, 42, 42})', idsFunction)
|
check('function', 'void f(T v = {42, 42, 42})', idsFunction)
|
||||||
check('function', 'template<T v = {42, 42, 42}> void f()', idsTemplate)
|
|
||||||
check('member', 'T v = {42, 42, 42,}', idsMember)
|
check('member', 'T v = {42, 42, 42,}', idsMember)
|
||||||
check('function', 'void f(T v = {42, 42, 42,})', idsFunction)
|
check('function', 'void f(T v = {42, 42, 42,})', idsFunction)
|
||||||
check('function', 'template<T v = {42, 42, 42,}> void f()', idsTemplate)
|
# TODO: designator-list
|
||||||
check('member', 'T v = {42, 42, args...}', idsMember)
|
|
||||||
check('function', 'void f(T v = {42, 42, args...})', idsFunction)
|
|
||||||
check('function', 'template<T v = {42, 42, args...}> void f()', idsTemplate)
|
|
||||||
# without '=', braced-init
|
|
||||||
check('member', 'T v{}', idsMember)
|
|
||||||
check('member', 'T v{42, 42, 42}', idsMember)
|
|
||||||
check('member', 'T v{42, 42, 42,}', idsMember)
|
|
||||||
check('member', 'T v{42, 42, args...}', idsMember)
|
|
||||||
# other
|
|
||||||
check('member', 'T v = T{}', idsMember)
|
|
||||||
|
|
||||||
|
|
||||||
def test_attributes():
|
def test_attributes():
|
||||||
|
Loading…
Reference in New Issue
Block a user