Skip to content

Commit 89163a5

Browse files
authored
Fix rendering of variables (#105)
Fixes the rendering of variables, which after #103 would always have extra colons being inserted, due to how variables are parsed. This PR makes similar transformations as #103 did to separate types and default values to solve this problem
2 parents 4066169 + 3bacce7 commit 89163a5

File tree

4 files changed

+148
-50
lines changed

4 files changed

+148
-50
lines changed

doc-test/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Module 'Foo'
2222
foo
2323
cpp_test
2424
nested
25+
variables
2526

2627
**Does it work???**
2728

doc-test/variables.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Variables
2+
=========
3+
4+
5+
6+
Chapel variables
7+
----------------
8+
9+
.. default-domain:: chpl
10+
11+
.. module:: Variables
12+
:synopsis: Variables, constants, and configuration parameters.
13+
14+
.. data:: param e = 2.7182818284590452354
15+
16+
This is a constant.
17+
18+
.. data:: param pi: real = 3.1415926535897932385
19+
20+
This is another constant.

sphinxcontrib/chapeldomain/__init__.py

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,38 @@ def match_chpl_sig_pattern(sig: str):
125125
r"""^ ((?:\w+\s+)*)? # optional: prefixes
126126
([\w$.]*\.)? # class name(s)
127127
([\w$]+) # const, var, param, etc name
128-
(\s* [:={] \s* .+)? # optional: type, default value
128+
(\s*:\s*[^=]+)? # optional: return type
129+
(\s*[={]\s*.+)? # optional: value
129130
$""", re.VERBOSE)
130131

131132

133+
def match_chpl_attr_sig_pattern(sig: str):
134+
"""
135+
Match a Chapel signature against the regex pattern defined in
136+
chpl_attr_sig_pattern.
137+
138+
This function cleans up the whitespace on the type (and removes ':'!)
139+
and default value to make testing more consistent.
140+
"""
141+
sig_match = chpl_attr_sig_pattern.match(sig)
142+
if not sig_match:
143+
return None
144+
(
145+
func_prefix,
146+
name_prefix,
147+
name,
148+
return_type,
149+
default_value,
150+
) = sig_match.groups()
151+
152+
if return_type:
153+
return_type = return_type.strip().removeprefix(':').lstrip()
154+
if default_value:
155+
default_value = default_value.strip()
156+
157+
return (func_prefix, name_prefix, name, return_type, default_value)
158+
159+
132160
# This would be the ideal way to create a chapelerific desc_returns similar to
133161
# addnodes.desc_returns. However, due to some update issue, the
134162
# nodes._add_node_class_names() call does not seem to make chapel_desc_returns
@@ -267,7 +295,13 @@ def _pseudo_parse_arglist(signode, arglist):
267295

268296
@staticmethod
269297
def _handle_signature_suffix(
270-
signode, return_intent, return_type, throws, anno, where_clause
298+
signode,
299+
return_intent,
300+
return_type,
301+
default_value,
302+
throws,
303+
anno,
304+
where_clause,
271305
):
272306
"""
273307
handle the signature suffix items like return intent, return type,
@@ -282,6 +316,10 @@ def _handle_signature_suffix(
282316
signode += addnodes.desc_sig_space(' ', ' ')
283317
signode += addnodes.desc_annotation(' : ' + return_type,
284318
' : ' + return_type)
319+
if default_value:
320+
signode += addnodes.desc_sig_space(' ', ' ')
321+
signode += addnodes.desc_annotation(default_value,
322+
default_value)
285323
if throws:
286324
signode += addnodes.desc_sig_space(' ', ' ')
287325
signode += addnodes.desc_annotation(' throws', ' throws')
@@ -293,11 +331,11 @@ def _handle_signature_suffix(
293331

294332
def _get_attr_like_prefix(self, sig):
295333
"""Return prefix text for attribute or data directive."""
296-
sig_match = chpl_attr_sig_pattern.match(sig)
334+
sig_match = match_chpl_attr_sig_pattern(sig)
297335
if sig_match is None:
298336
return ChapelObject.get_signature_prefix(self, sig)
299337

300-
prefixes, _, _, _ = sig_match.groups()
338+
prefixes = sig_match[0]
301339
if prefixes:
302340
return prefixes.strip() + ' '
303341
elif self.objtype == 'type':
@@ -374,10 +412,17 @@ def handle_signature(self, sig, signode):
374412
class(es)) and the classes. See also :py:meth:`add_target_and_index`.
375413
"""
376414
if self._is_attr_like():
377-
sig_match = chpl_attr_sig_pattern.match(sig)
415+
sig_match = match_chpl_attr_sig_pattern(sig)
378416
if sig_match is None:
379417
raise ValueError('Signature does not parse: {0}'.format(sig))
380-
func_prefix, name_prefix, name, return_type = sig_match.groups()
418+
(
419+
func_prefix,
420+
name_prefix,
421+
name,
422+
return_type,
423+
default_value,
424+
) = sig_match
425+
381426
return_intent = None
382427
throws = None
383428
arglist = None
@@ -397,6 +442,7 @@ def handle_signature(self, sig, signode):
397442
throws,
398443
where_clause,
399444
) = sig_match
445+
default_value = None
400446

401447
# check if where clause is valid
402448
if where_clause is not None and not self._is_proc_like():
@@ -453,13 +499,25 @@ def handle_signature(self, sig, signode):
453499
# for callables, add an empty parameter list
454500
signode += addnodes.desc_parameterlist()
455501
self._handle_signature_suffix(
456-
signode, return_intent, return_type, throws, anno, where_clause
502+
signode,
503+
return_intent,
504+
return_type,
505+
default_value,
506+
throws,
507+
anno,
508+
where_clause,
457509
)
458510
return fullname, name_prefix
459511

460512
self._pseudo_parse_arglist(signode, arglist)
461513
self._handle_signature_suffix(
462-
signode, return_intent, return_type, throws, anno, where_clause
514+
signode,
515+
return_intent,
516+
return_type,
517+
default_value,
518+
throws,
519+
anno,
520+
where_clause,
463521
)
464522

465523
return fullname, name_prefix

test/test_chapeldomain.py

Lines changed: 61 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
from sphinxcontrib.chapeldomain import (
1212
ChapelDomain, ChapelModuleIndex, ChapelClassObject, ChapelModuleLevel, ChapelObject,
1313
ChapelTypedField, ChapelClassMember,
14-
chpl_sig_pattern, match_chpl_sig_pattern, chpl_attr_sig_pattern,
14+
chpl_sig_pattern, match_chpl_sig_pattern,
15+
chpl_attr_sig_pattern, match_chpl_attr_sig_pattern
1516
)
1617

1718

@@ -892,16 +893,23 @@ class AttrSigPatternTests(PatternTestCase):
892893

893894
pattern = chpl_attr_sig_pattern
894895

895-
def check_sig(self, sig, func_prefix, name_prefix, name, retann):
896+
def check_sig(self, sig, func_prefix, name_prefix, name, type_, default_value):
896897
"""Verify signature results in appropriate matches."""
897-
match = self.pattern.match(sig)
898+
match = match_chpl_attr_sig_pattern(sig)
898899
self.assertIsNotNone(match)
899900

900-
(actual_func_prefix, actual_name_prefix, actual_name, actual_retann) = match.groups()
901+
(
902+
actual_func_prefix,
903+
actual_name_prefix,
904+
actual_name,
905+
actual_type,
906+
actual_default_value,
907+
) = match
901908
self.assertEqual(func_prefix, actual_func_prefix)
902909
self.assertEqual(name_prefix, actual_name_prefix)
903910
self.assertEqual(name, actual_name)
904-
self.assertEqual(retann, actual_retann)
911+
self.assertEqual(type_, actual_type)
912+
self.assertEqual(default_value, actual_default_value)
905913

906914
def test_does_not_match(self):
907915
"""Verify various signatures that should not match."""
@@ -927,7 +935,7 @@ def test_simple_label(self):
927935
'1',
928936
]
929937
for sig in test_cases:
930-
self.check_sig(sig, '', None, sig, None)
938+
self.check_sig(sig, '', None, sig, None, None)
931939

932940
def test_with_class_names(self):
933941
"""Verify symbols with class names match pattern."""
@@ -937,7 +945,7 @@ def test_with_class_names(self):
937945
('BigNum.fromInt', 'BigNum.', 'fromInt'),
938946
]
939947
for sig, class_name, attr in test_cases:
940-
self.check_sig(sig, '', class_name, attr, None)
948+
self.check_sig(sig, '', class_name, attr, None, None)
941949

942950
def test_with_prefixes(self):
943951
"""Verify type, config, etc prefixes work."""
@@ -949,51 +957,62 @@ def test_with_prefixes(self):
949957
('const baz', 'const ', 'baz'),
950958
]
951959
for sig, prefix, attr in test_cases:
952-
self.check_sig(sig, prefix, None, attr, None)
960+
self.check_sig(sig, prefix, None, attr, None, None)
953961

954962
def test_with_types(self):
955963
"""Verify types parse correctly."""
956964
test_cases = [
957-
('foo: int', 'foo', ': int'),
958-
('bar: real', 'bar', ': real'),
959-
('baz: int(32)', 'baz', ': int(32)'),
960-
('D: domain(9)', 'D', ': domain(9)'),
961-
('A: [{1..n}] BigNum', 'A', ': [{1..n}] BigNum'),
962-
('x: MyModule.MyClass', 'x', ': MyModule.MyClass'),
963-
('x : sync real', 'x', ' : sync real'),
965+
('foo: int', 'foo', 'int', None),
966+
('bar: real', 'bar', 'real', None),
967+
('baz: int(32)', 'baz', 'int(32)', None),
968+
('D: domain(9)', 'D', 'domain(9)', None),
969+
('A: [{1..n}] BigNum', 'A', '[{1..n}] BigNum', None),
970+
('x: MyModule.MyClass', 'x', 'MyModule.MyClass', None),
971+
('x : sync real', 'x', 'sync real', None),
972+
]
973+
for sig, attr, type_name, default_val in test_cases:
974+
self.check_sig(sig, '', None, attr, type_name, default_val)
975+
976+
def test_with_defaults(self):
977+
"""Verify default values parse correctly."""
978+
test_cases = [
979+
('x = 5', 'x', None, '= 5'),
980+
('y = [i in 1..10] i == 1', 'y', None, '= [i in 1..10] i == 1'),
981+
('z { A=1, B}', 'z', None, '{ A=1, B}'),
964982
]
965-
for sig, attr, type_name in test_cases:
966-
self.check_sig(sig, '', None, attr, type_name)
983+
for sig, attr, type_name, default_val in test_cases:
984+
self.check_sig(sig, '', None, attr, type_name, default_val)
967985

968986
def test_with_all(self):
969987
"""Verify full specified signatures parse correctly."""
970988
test_cases = [
971-
('config const MyModule.MyClass.n: int', 'config const ', 'MyModule.MyClass.', 'n', ': int'),
972-
('var X.n: MyMod.MyClass', 'var ', 'X.', 'n', ': MyMod.MyClass'),
973-
('config param debugAdvancedIters:bool', 'config param ', None, 'debugAdvancedIters', ':bool'),
974-
('config param MyMod.DEBUG: bool', 'config param ', 'MyMod.', 'DEBUG', ': bool'),
975-
('var RandomStreamPrivate_lock$: _syncvar(bool)', 'var ', None, 'RandomStreamPrivate_lock$', ': _syncvar(bool)'),
976-
('var RandomStreamPrivate_lock$: sync bool', 'var ', None, 'RandomStreamPrivate_lock$', ': sync bool'),
977-
('const RS$.lock$: sync MyMod$.MyClass$.bool', 'const ', 'RS$.', 'lock$', ': sync MyMod$.MyClass$.bool'),
978-
('type commDiagnostics = chpl_commDiagnostics', 'type ', None, 'commDiagnostics', ' = chpl_commDiagnostics'),
979-
('type age = int(64)', 'type ', None, 'age', ' = int(64)'),
980-
('type MyMod.BigAge=BigNum.BigInt', 'type ', 'MyMod.', 'BigAge', '=BigNum.BigInt'),
981-
('const x = false', 'const ', None, 'x', ' = false'),
982-
('config const MyC.x: int(64) = 5', 'config const ', 'MyC.', 'x', ': int(64) = 5'),
983-
('config param n: uint(64) = 5: uint(64)', 'config param ', None, 'n', ': uint(64) = 5: uint(64)'),
984-
('var MyM.MyC.x = 4: uint(64)', 'var ', 'MyM.MyC.', 'x', ' = 4: uint(64)'),
985-
('type MyT = 2*real(64)', 'type ', None, 'MyT', ' = 2*real(64)'),
986-
('type myFloats = 2*(real(64))', 'type ', None, 'myFloats', ' = 2*(real(64))'),
987-
('enum Color { Red, Yellow, Blue }', 'enum ', None, 'Color', ' { Red, Yellow, Blue }'),
988-
('enum Month { January=1, February }', 'enum ', None, 'Month', ' { January=1, February }'),
989-
('enum One { Neo }', 'enum ', None, 'One', ' { Neo }'),
990-
('enum constant Pink', 'enum constant ', None, 'Pink', None),
991-
('enum constant December', 'enum constant ', None, 'December', None),
992-
('enum constant Hibiscus', 'enum constant ', None, 'Hibiscus', None),
993-
('enum constant Aquarius', 'enum constant ', None, 'Aquarius', None)
989+
('config const MyModule.MyClass.n: int', 'config const ', 'MyModule.MyClass.', 'n', 'int', None),
990+
('var X.n: MyMod.MyClass', 'var ', 'X.', 'n', 'MyMod.MyClass', None),
991+
('config param debugAdvancedIters:bool', 'config param ', None, 'debugAdvancedIters', 'bool', None),
992+
('config param MyMod.DEBUG: bool', 'config param ', 'MyMod.', 'DEBUG', 'bool', None),
993+
('var RandomStreamPrivate_lock$: _syncvar(bool)', 'var ', None, 'RandomStreamPrivate_lock$', '_syncvar(bool)', None),
994+
('var RandomStreamPrivate_lock$: sync bool', 'var ', None, 'RandomStreamPrivate_lock$', 'sync bool', None),
995+
('const RS$.lock$: sync MyMod$.MyClass$.bool', 'const ', 'RS$.', 'lock$', 'sync MyMod$.MyClass$.bool', None),
996+
('var arr: [{1..10}] real(64) = [i in 1..10] i:real(64)', 'var ', None, 'arr', '[{1..10}] real(64)', '= [i in 1..10] i:real(64)'),
997+
('type commDiagnostics = chpl_commDiagnostics', 'type ', None, 'commDiagnostics', None, '= chpl_commDiagnostics'),
998+
('type age = int(64)', 'type ', None, 'age', None, '= int(64)'),
999+
('type MyMod.BigAge=BigNum.BigInt', 'type ', 'MyMod.', 'BigAge', None, '=BigNum.BigInt'),
1000+
('const x = false', 'const ', None, 'x', None, '= false'),
1001+
('config const MyC.x: int(64) = 5', 'config const ', 'MyC.', 'x', 'int(64)', '= 5'),
1002+
('config param n: uint(64) = 5: uint(64)', 'config param ', None, 'n', 'uint(64)', '= 5: uint(64)'),
1003+
('var MyM.MyC.x = 4: uint(64)', 'var ', 'MyM.MyC.', 'x', None, '= 4: uint(64)'),
1004+
('type MyT = 2*real(64)', 'type ', None, 'MyT', None, '= 2*real(64)'),
1005+
('type myFloats = 2*(real(64))', 'type ', None, 'myFloats', None, '= 2*(real(64))'),
1006+
('enum Color { Red, Yellow, Blue }', 'enum ', None, 'Color', None, '{ Red, Yellow, Blue }'),
1007+
('enum Month { January=1, February }', 'enum ', None, 'Month', None, '{ January=1, February }'),
1008+
('enum One { Neo }', 'enum ', None, 'One', None, '{ Neo }'),
1009+
('enum constant Pink', 'enum constant ', None, 'Pink', None, None),
1010+
('enum constant December', 'enum constant ', None, 'December', None, None),
1011+
('enum constant Hibiscus', 'enum constant ', None, 'Hibiscus', None, None),
1012+
('enum constant Aquarius', 'enum constant ', None, 'Aquarius', None, None)
9941013
]
995-
for sig, prefix, class_name, attr, type_name in test_cases:
996-
self.check_sig(sig, prefix, class_name, attr, type_name)
1014+
for sig, prefix, class_name, attr, type_name, default_value in test_cases:
1015+
self.check_sig(sig, prefix, class_name, attr, type_name, default_value)
9971016

9981017

9991018
if __name__ == '__main__':

0 commit comments

Comments
 (0)