Skip to content

Commit

Permalink
Merge pull request #7556 from jakobandersen/c_array_declarator
Browse files Browse the repository at this point in the history
C, parse all types of array declarators
  • Loading branch information
jakobandersen authored Apr 25, 2020
2 parents 31a34c2 + 082bf7d commit 49e7118
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 17 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Deprecated
Features added
--------------

* C, parse array declarators with static, qualifiers, and VLA specification.

Bugs fixed
----------

Expand Down
101 changes: 84 additions & 17 deletions sphinx/domains/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -791,20 +791,60 @@ def _add(modifiers: List[Node], text: str) -> None:
################################################################################

class ASTArray(ASTBase):
def __init__(self, size: ASTExpression):
def __init__(self, static: bool, const: bool, volatile: bool, restrict: bool,
vla: bool, size: ASTExpression):
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:
if self.size:
return '[' + transform(self.size) + ']'
else:
return '[]'
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.append(nodes.Text("["))
if self.size:
addSpace = False

def _add(signode: TextElement, text: str) -> bool:
if addSpace:
signode += nodes.Text(' ')
signode += addnodes.desc_annotation(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.append(nodes.Text('*'))
elif self.size:
if addSpace:
signode += nodes.Text(' ')
self.size.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text("]"))

Expand Down Expand Up @@ -2587,18 +2627,45 @@ def _parse_declarator_name_suffix(
self.skip_ws()
if typed and self.skip_string('['):
self.skip_ws()
if self.skip_string(']'):
arrayOps.append(ASTArray(None))
continue

def parser():
return self._parse_expression()
static = False
const = False
volatile = False
restrict = False
while True:
if not static:
if self.skip_word_and_ws('static'):
static = True
continue
if not const:
if self.skip_word_and_ws('const'):
const = True
continue
if not volatile:
if self.skip_word_and_ws('volatile'):
volatile = True
continue
if not restrict:
if self.skip_word_and_ws('restrict'):
restrict = True
continue
break
vla = False if static else self.skip_string_and_ws('*')
if vla:
if not self.skip_string(']'):
self.fail("Expected ']' in end of array operator.")
size = None
else:
if self.skip_string(']'):
size = None
else:

value = self._parse_expression_fallback([']'], parser)
if not self.skip_string(']'):
self.fail("Expected ']' in end of array operator.")
arrayOps.append(ASTArray(value))
continue
def parser():
return self._parse_expression()
size = self._parse_expression_fallback([']'], parser)
self.skip_ws()
if not self.skip_string(']'):
self.fail("Expected ']' in end of array operator.")
arrayOps.append(ASTArray(static, const, volatile, restrict, vla, size))
else:
break
param = self._parse_parameters(paramMode)
Expand Down
15 changes: 15 additions & 0 deletions tests/test_domain_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,21 @@ def test_function_definitions():
check('function', 'void f(enum E e)', {1: 'f'})
check('function', 'void f(union E e)', {1: 'f'})

# array declarators
check('function', 'void f(int arr[])', {1: 'f'})
check('function', 'void f(int arr[*])', {1: 'f'})
cvrs = ['', 'const', 'volatile', 'restrict', 'restrict volatile const']
for cvr in cvrs:
space = ' ' if len(cvr) != 0 else ''
check('function', 'void f(int arr[{}*])'.format(cvr), {1: 'f'})
check('function', 'void f(int arr[{}])'.format(cvr), {1: 'f'})
check('function', 'void f(int arr[{}{}42])'.format(cvr, space), {1: 'f'})
check('function', 'void f(int arr[static{}{} 42])'.format(space, cvr), {1: 'f'})
check('function', 'void f(int arr[{}{}static 42])'.format(cvr, space), {1: 'f'},
output='void f(int arr[static{}{} 42])'.format(space, cvr))
check('function', 'void f(int arr[const static volatile 42])', {1: 'f'},
output='void f(int arr[static volatile const 42])')


def test_union_definitions():
check('struct', 'A', {1: 'A'})
Expand Down

0 comments on commit 49e7118

Please sign in to comment.