From c5962b70bdabf4ccd4e1fbadd9a2bc0d8a1fc61f Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 14 Aug 2021 15:59:11 +0200 Subject: [PATCH] C, update fundamental types, including GNU exts Fixes sphinx-doc/sphinx#9535 --- CHANGES | 1 + sphinx/domains/c.py | 70 +++++++++++++++++++----------------------- tests/test_domain_c.py | 52 +++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 38 deletions(-) diff --git a/CHANGES b/CHANGES index 26282a80744..df321b47f3e 100644 --- a/CHANGES +++ b/CHANGES @@ -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 ---------- diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index d79172b0581..ff592d0deba 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -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: @@ -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' @@ -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 diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py index d59c4fc1c9c..d8429861a5f 100644 --- a/tests/test_domain_c.py +++ b/tests/test_domain_c.py @@ -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"})