Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Tools/c-analyzer/c_parser/parser/_common.py
12 views
1
import re
2
3
from ._regexes import (
4
_ind,
5
STRING_LITERAL,
6
VAR_DECL as _VAR_DECL,
7
)
8
9
10
def log_match(group, m, depth_before=None, depth_after=None):
11
from . import _logger
12
13
if m is not None:
14
text = m.group(0)
15
if text.startswith(('(', ')')) or text.endswith(('(', ')')):
16
_logger.debug(f'matched <{group}> ({text!r})')
17
else:
18
_logger.debug(f'matched <{group}> ({text})')
19
20
elif depth_before is not None or depth_after is not None:
21
if depth_before is None:
22
depth_before = '???'
23
elif depth_after is None:
24
depth_after = '???'
25
_logger.log(1, f'depth: %s -> %s', depth_before, depth_after)
26
27
else:
28
raise NotImplementedError('this should not have been hit')
29
30
31
#############################
32
# regex utils
33
34
def set_capture_group(pattern, group, *, strict=True):
35
old = f'(?: # <{group}>'
36
if strict and f'(?: # <{group}>' not in pattern:
37
raise ValueError(f'{old!r} not found in pattern')
38
return pattern.replace(old, f'( # <{group}>', 1)
39
40
41
def set_capture_groups(pattern, groups, *, strict=True):
42
for group in groups:
43
pattern = set_capture_group(pattern, group, strict=strict)
44
return pattern
45
46
47
#############################
48
# syntax-related utils
49
50
_PAREN_RE = re.compile(rf'''
51
(?:
52
(?:
53
[^'"()]*
54
{_ind(STRING_LITERAL, 3)}
55
)*
56
[^'"()]*
57
(?:
58
( [(] )
59
|
60
( [)] )
61
)
62
)
63
''', re.VERBOSE)
64
65
66
def match_paren(text, depth=0):
67
pos = 0
68
while (m := _PAREN_RE.match(text, pos)):
69
pos = m.end()
70
_open, _close = m.groups()
71
if _open:
72
depth += 1
73
else: # _close
74
depth -= 1
75
if depth == 0:
76
return pos
77
else:
78
raise ValueError(f'could not find matching parens for {text!r}')
79
80
81
VAR_DECL = set_capture_groups(_VAR_DECL, (
82
'STORAGE',
83
'TYPE_QUAL',
84
'TYPE_SPEC',
85
'DECLARATOR',
86
'IDENTIFIER',
87
'WRAPPED_IDENTIFIER',
88
'FUNC_IDENTIFIER',
89
))
90
91
92
def parse_var_decl(decl):
93
m = re.match(VAR_DECL, decl, re.VERBOSE)
94
(storage, typequal, typespec, declarator,
95
name,
96
wrappedname,
97
funcptrname,
98
) = m.groups()
99
if name:
100
kind = 'simple'
101
elif wrappedname:
102
kind = 'wrapped'
103
name = wrappedname
104
elif funcptrname:
105
kind = 'funcptr'
106
name = funcptrname
107
else:
108
raise NotImplementedError
109
abstract = declarator.replace(name, '')
110
vartype = {
111
'storage': storage,
112
'typequal': typequal,
113
'typespec': typespec,
114
'abstract': abstract,
115
}
116
return (kind, name, vartype)
117
118
119
#############################
120
# parser state utils
121
122
# XXX Drop this or use it!
123
def iter_results(results):
124
if not results:
125
return
126
if callable(results):
127
results = results()
128
129
for result, text in results():
130
if result:
131
yield result, text
132
133