Skip to content

Commit

Permalink
C, update fundamental types, including GNU exts
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobandersen committed Aug 20, 2021
1 parent 8fd4373 commit c5962b7
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 38 deletions.
1 change: 1 addition & 0 deletions CHANGES
Expand Up @@ -19,6 +19,7 @@ Features added
template variable ``sphinx_version_tuple``
* #9445: py domain: ``:py:property:`` directive supports ``:classmethod:``
option to describe the class property
* #9535: C, support more fundamental types, including GNU extensions.

Bugs fixed
----------
Expand Down
70 changes: 32 additions & 38 deletions sphinx/domains/c.py
Expand Up @@ -92,6 +92,33 @@
_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'"
r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)

_simple_type_sepcifiers_re = re.compile(r"""(?x)
\b(
void|_Bool|bool
# Integer
# -------
|((signed|unsigned)\s+)?(char|(
((long\s+long|long)\s+)?int
))
|__uint128|__int128
# extensions
|((signed|unsigned)\s+)?__int(8|16|32|64|128)
# Floating-point
# --------------
|(float|double|long\s+double)(\s+(_Complex|complex|_Imaginary|imaginary))?
|_Decimal(32|64|128)
# extensions
|__float80|_Float64x|__float128|_Float128|__ibm128
|__fp16
# Fixed-point, extension
|(_Sat\s+)?((signed|unsigned)\s+)?((short|long|long\s+long)\s+)?(_Fract|_Accum)
# Integer types that could be prefixes of the previous ones
# ---------------------------------------------------------
|((signed|unsigned)\s+)?(short|long\s+long|long)
|signed|unsigned
)\b
""")


class _DuplicateSymbolError(Exception):
def __init__(self, symbol: "Symbol", declaration: "ASTDeclaration") -> None:
Expand Down Expand Up @@ -2123,15 +2150,6 @@ def dump(self, indent: int) -> str:


class DefinitionParser(BaseParser):
# those without signedness and size modifiers
# see https://en.cppreference.com/w/cpp/language/types
_simple_fundamental_types = (
'void', '_Bool', 'bool', 'char', 'int', 'float', 'double',
'__int64',
)

_prefix_keys = ('struct', 'enum', 'union')

@property
def language(self) -> str:
return 'C'
Expand Down Expand Up @@ -2556,40 +2574,16 @@ def _parse_nested_name(self) -> ASTNestedName:
return ASTNestedName(names, rooted)

def _parse_trailing_type_spec(self) -> ASTTrailingTypeSpec:
# fundamental types
# fundamental types, https://en.cppreference.com/w/c/language/type
# and extensions
self.skip_ws()
for t in self._simple_fundamental_types:
if self.skip_word(t):
return ASTTrailingTypeSpecFundamental(t)

# TODO: this could/should be more strict
elements = []
if self.skip_word_and_ws('signed'):
elements.append('signed')
elif self.skip_word_and_ws('unsigned'):
elements.append('unsigned')
while 1:
if self.skip_word_and_ws('short'):
elements.append('short')
elif self.skip_word_and_ws('long'):
elements.append('long')
else:
break
if self.skip_word_and_ws('char'):
elements.append('char')
elif self.skip_word_and_ws('int'):
elements.append('int')
elif self.skip_word_and_ws('double'):
elements.append('double')
elif self.skip_word_and_ws('__int64'):
elements.append('__int64')
if len(elements) > 0:
return ASTTrailingTypeSpecFundamental(' '.join(elements))
if self.match(_simple_type_sepcifiers_re):
return ASTTrailingTypeSpecFundamental(self.matched_text)

# prefixed
prefix = None
self.skip_ws()
for k in self._prefix_keys:
for k in ('struct', 'enum', 'union'):
if self.skip_word_and_ws(k):
prefix = k
break
Expand Down
52 changes: 52 additions & 0 deletions tests/test_domain_c.py
Expand Up @@ -275,6 +275,58 @@ def exprCheck(expr, output=None):
exprCheck('a or_eq 5')


def test_domain_c_ast_fundamental_types():
def types():
def signed(t):
yield t
yield 'signed ' + t
yield 'unsigned ' + t

# integer types
# -------------
yield 'void'
yield from ('_Bool', 'bool')
yield from signed('char')
yield from signed('short')
yield from signed('int')
yield from ('signed', 'unsigned')
yield from signed('long')
yield from signed('long int')
yield from signed('long long')
yield from signed('long long int')
yield from ('__int128', '__uint128')
# extensions
for t in ('__int8', '__int16', '__int32', '__int64', '__int128'):
yield from signed(t)

# floating point types
# --------------------
yield from ('_Decimal32', '_Decimal64', '_Decimal128')
for f in ('float', 'double', 'long double'):
yield f
yield from (f + " _Complex", f + " complex")
yield from (f + " _Imaginary", f + " imaginary")
# extensions
# https://gcc.gnu.org/onlinedocs/gcc/Floating-Types.html#Floating-Types
yield from ('__float80', '_Float64x',
'__float128', '_Float128',
'__ibm128')
# https://gcc.gnu.org/onlinedocs/gcc/Half-Precision.html#Half-Precision
yield '__fp16'

# fixed-point types (extension)
# -----------------------------
# https://gcc.gnu.org/onlinedocs/gcc/Fixed-Point.html#Fixed-Point
for sat in ('', '_Sat '):
for t in ('_Fract', '_Accum'):
for size in ('short ', '', 'long ', 'long long '):
for tt in signed(size + t):
yield sat + tt

for t in types():
check('type', "{key}%s foo" % t, {1: 'foo'}, key='typedef')


def test_domain_c_ast_type_definitions():
check('type', "{key}T", {1: "T"})

Expand Down

0 comments on commit c5962b7

Please sign in to comment.