Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Tools/c-analyzer/c_parser/preprocessor/__main__.py
12 views
1
import logging
2
import sys
3
4
from c_common.scriptutil import (
5
add_verbosity_cli,
6
add_traceback_cli,
7
add_kind_filtering_cli,
8
add_files_cli,
9
add_failure_filtering_cli,
10
add_commands_cli,
11
process_args_by_key,
12
configure_logger,
13
get_prog,
14
main_for_filenames,
15
)
16
from . import (
17
errors as _errors,
18
get_preprocessor as _get_preprocessor,
19
)
20
21
22
FAIL = {
23
'err': _errors.ErrorDirectiveError,
24
'deps': _errors.MissingDependenciesError,
25
'os': _errors.OSMismatchError,
26
}
27
FAIL_DEFAULT = tuple(v for v in FAIL if v != 'os')
28
29
30
logger = logging.getLogger(__name__)
31
32
33
##################################
34
# CLI helpers
35
36
def add_common_cli(parser, *, get_preprocessor=_get_preprocessor):
37
parser.add_argument('--macros', action='append')
38
parser.add_argument('--incldirs', action='append')
39
parser.add_argument('--same', action='append')
40
process_fail_arg = add_failure_filtering_cli(parser, FAIL)
41
42
def process_args(args, *, argv):
43
ns = vars(args)
44
45
process_fail_arg(args, argv=argv)
46
ignore_exc = ns.pop('ignore_exc')
47
# We later pass ignore_exc to _get_preprocessor().
48
49
args.get_file_preprocessor = get_preprocessor(
50
file_macros=ns.pop('macros'),
51
file_incldirs=ns.pop('incldirs'),
52
file_same=ns.pop('same'),
53
ignore_exc=ignore_exc,
54
log_err=print,
55
)
56
return process_args
57
58
59
def _iter_preprocessed(filename, *,
60
get_preprocessor,
61
match_kind=None,
62
pure=False,
63
):
64
preprocess = get_preprocessor(filename)
65
for line in preprocess(tool=not pure) or ():
66
if match_kind is not None and not match_kind(line.kind):
67
continue
68
yield line
69
70
71
#######################################
72
# the commands
73
74
def _cli_preprocess(parser, excluded=None, **prepr_kwargs):
75
parser.add_argument('--pure', action='store_true')
76
parser.add_argument('--no-pure', dest='pure', action='store_const', const=False)
77
process_kinds = add_kind_filtering_cli(parser)
78
process_common = add_common_cli(parser, **prepr_kwargs)
79
parser.add_argument('--raw', action='store_true')
80
process_files = add_files_cli(parser, excluded=excluded)
81
82
return [
83
process_kinds,
84
process_common,
85
process_files,
86
]
87
88
89
def cmd_preprocess(filenames, *,
90
raw=False,
91
iter_filenames=None,
92
**kwargs
93
):
94
if 'get_file_preprocessor' not in kwargs:
95
kwargs['get_file_preprocessor'] = _get_preprocessor()
96
if raw:
97
def show_file(filename, lines):
98
for line in lines:
99
print(line)
100
#print(line.raw)
101
else:
102
def show_file(filename, lines):
103
for line in lines:
104
linefile = ''
105
if line.filename != filename:
106
linefile = f' ({line.filename})'
107
text = line.data
108
if line.kind == 'comment':
109
text = '/* ' + line.data.splitlines()[0]
110
text += ' */' if '\n' in line.data else r'\n... */'
111
print(f' {line.lno:>4} {line.kind:10} | {text}')
112
113
filenames = main_for_filenames(filenames, iter_filenames)
114
for filename in filenames:
115
lines = _iter_preprocessed(filename, **kwargs)
116
show_file(filename, lines)
117
118
119
def _cli_data(parser):
120
...
121
122
return None
123
124
125
def cmd_data(filenames,
126
**kwargs
127
):
128
# XXX
129
raise NotImplementedError
130
131
132
COMMANDS = {
133
'preprocess': (
134
'preprocess the given C source & header files',
135
[_cli_preprocess],
136
cmd_preprocess,
137
),
138
'data': (
139
'check/manage local data (e.g. excludes, macros)',
140
[_cli_data],
141
cmd_data,
142
),
143
}
144
145
146
#######################################
147
# the script
148
149
def parse_args(argv=sys.argv[1:], prog=sys.argv[0], *,
150
subset='preprocess',
151
excluded=None,
152
**prepr_kwargs
153
):
154
import argparse
155
parser = argparse.ArgumentParser(
156
prog=prog or get_prog(),
157
)
158
159
processors = add_commands_cli(
160
parser,
161
commands={k: v[1] for k, v in COMMANDS.items()},
162
commonspecs=[
163
add_verbosity_cli,
164
add_traceback_cli,
165
],
166
subset=subset,
167
)
168
169
args = parser.parse_args(argv)
170
ns = vars(args)
171
172
cmd = ns.pop('cmd')
173
174
verbosity, traceback_cm = process_args_by_key(
175
args,
176
argv,
177
processors[cmd],
178
['verbosity', 'traceback_cm'],
179
)
180
181
return cmd, ns, verbosity, traceback_cm
182
183
184
def main(cmd, cmd_kwargs):
185
try:
186
run_cmd = COMMANDS[cmd][0]
187
except KeyError:
188
raise ValueError(f'unsupported cmd {cmd!r}')
189
run_cmd(**cmd_kwargs)
190
191
192
if __name__ == '__main__':
193
cmd, cmd_kwargs, verbosity, traceback_cm = parse_args()
194
configure_logger(verbosity)
195
with traceback_cm:
196
main(cmd, cmd_kwargs)
197
198