ยปCore Development>Code coverage>Tools/scripts/abitype.py

Python code coverage for Tools/scripts/abitype.py

#countcontent
1n/a#!/usr/bin/env python3
2n/a# This script converts a C file to use the PEP 384 type definition API
3n/a# Usage: abitype.py < old_code > new_code
4n/aimport re, sys
5n/a
6n/a###### Replacement of PyTypeObject static instances ##############
7n/a
8n/a# classify each token, giving it a one-letter code:
9n/a# S: static
10n/a# T: PyTypeObject
11n/a# I: ident
12n/a# W: whitespace
13n/a# =, {, }, ; : themselves
14n/adef classify():
15n/a res = []
16n/a for t,v in tokens:
17n/a if t == 'other' and v in "={};":
18n/a res.append(v)
19n/a elif t == 'ident':
20n/a if v == 'PyTypeObject':
21n/a res.append('T')
22n/a elif v == 'static':
23n/a res.append('S')
24n/a else:
25n/a res.append('I')
26n/a elif t == 'ws':
27n/a res.append('W')
28n/a else:
29n/a res.append('.')
30n/a return ''.join(res)
31n/a
32n/a# Obtain a list of fields of a PyTypeObject, in declaration order,
33n/a# skipping ob_base
34n/a# All comments are dropped from the variable (which are typically
35n/a# just the slot names, anyway), and information is discarded whether
36n/a# the original type was static.
37n/adef get_fields(start, real_end):
38n/a pos = start
39n/a # static?
40n/a if tokens[pos][1] == 'static':
41n/a pos += 2
42n/a # PyTypeObject
43n/a pos += 2
44n/a # name
45n/a name = tokens[pos][1]
46n/a pos += 1
47n/a while tokens[pos][1] != '{':
48n/a pos += 1
49n/a pos += 1
50n/a # PyVarObject_HEAD_INIT
51n/a while tokens[pos][0] in ('ws', 'comment'):
52n/a pos += 1
53n/a if tokens[pos][1] != 'PyVarObject_HEAD_INIT':
54n/a raise Exception('%s has no PyVarObject_HEAD_INIT' % name)
55n/a while tokens[pos][1] != ')':
56n/a pos += 1
57n/a pos += 1
58n/a # field definitions: various tokens, comma-separated
59n/a fields = []
60n/a while True:
61n/a while tokens[pos][0] in ('ws', 'comment'):
62n/a pos += 1
63n/a end = pos
64n/a while tokens[end][1] not in ',}':
65n/a if tokens[end][1] == '(':
66n/a nesting = 1
67n/a while nesting:
68n/a end += 1
69n/a if tokens[end][1] == '(': nesting+=1
70n/a if tokens[end][1] == ')': nesting-=1
71n/a end += 1
72n/a assert end < real_end
73n/a # join field, excluding separator and trailing ws
74n/a end1 = end-1
75n/a while tokens[end1][0] in ('ws', 'comment'):
76n/a end1 -= 1
77n/a fields.append(''.join(t[1] for t in tokens[pos:end1+1]))
78n/a if tokens[end][1] == '}':
79n/a break
80n/a pos = end+1
81n/a return name, fields
82n/a
83n/a# List of type slots as of Python 3.2, omitting ob_base
84n/atypeslots = [
85n/a 'tp_name',
86n/a 'tp_basicsize',
87n/a 'tp_itemsize',
88n/a 'tp_dealloc',
89n/a 'tp_print',
90n/a 'tp_getattr',
91n/a 'tp_setattr',
92n/a 'tp_reserved',
93n/a 'tp_repr',
94n/a 'tp_as_number',
95n/a 'tp_as_sequence',
96n/a 'tp_as_mapping',
97n/a 'tp_hash',
98n/a 'tp_call',
99n/a 'tp_str',
100n/a 'tp_getattro',
101n/a 'tp_setattro',
102n/a 'tp_as_buffer',
103n/a 'tp_flags',
104n/a 'tp_doc',
105n/a 'tp_traverse',
106n/a 'tp_clear',
107n/a 'tp_richcompare',
108n/a 'tp_weaklistoffset',
109n/a 'tp_iter',
110n/a 'iternextfunc',
111n/a 'tp_methods',
112n/a 'tp_members',
113n/a 'tp_getset',
114n/a 'tp_base',
115n/a 'tp_dict',
116n/a 'tp_descr_get',
117n/a 'tp_descr_set',
118n/a 'tp_dictoffset',
119n/a 'tp_init',
120n/a 'tp_alloc',
121n/a 'tp_new',
122n/a 'tp_free',
123n/a 'tp_is_gc',
124n/a 'tp_bases',
125n/a 'tp_mro',
126n/a 'tp_cache',
127n/a 'tp_subclasses',
128n/a 'tp_weaklist',
129n/a 'tp_del',
130n/a 'tp_version_tag',
131n/a]
132n/a
133n/a# Generate a PyType_Spec definition
134n/adef make_slots(name, fields):
135n/a res = []
136n/a res.append('static PyType_Slot %s_slots[] = {' % name)
137n/a # defaults for spec
138n/a spec = { 'tp_itemsize':'0' }
139n/a for i, val in enumerate(fields):
140n/a if val.endswith('0'):
141n/a continue
142n/a if typeslots[i] in ('tp_name', 'tp_doc', 'tp_basicsize',
143n/a 'tp_itemsize', 'tp_flags'):
144n/a spec[typeslots[i]] = val
145n/a continue
146n/a res.append(' {Py_%s, %s},' % (typeslots[i], val))
147n/a res.append('};')
148n/a res.append('static PyType_Spec %s_spec = {' % name)
149n/a res.append(' %s,' % spec['tp_name'])
150n/a res.append(' %s,' % spec['tp_basicsize'])
151n/a res.append(' %s,' % spec['tp_itemsize'])
152n/a res.append(' %s,' % spec['tp_flags'])
153n/a res.append(' %s_slots,' % name)
154n/a res.append('};\n')
155n/a return '\n'.join(res)
156n/a
157n/a
158n/aif __name__ == '__main__':
159n/a
160n/a ############ Simplistic C scanner ##################################
161n/a tokenizer = re.compile(
162n/a r"(?P<preproc>#.*\n)"
163n/a r"|(?P<comment>/\*.*?\*/)"
164n/a r"|(?P<ident>[a-zA-Z_][a-zA-Z0-9_]*)"
165n/a r"|(?P<ws>[ \t\n]+)"
166n/a r"|(?P<other>.)",
167n/a re.MULTILINE)
168n/a
169n/a tokens = []
170n/a source = sys.stdin.read()
171n/a pos = 0
172n/a while pos != len(source):
173n/a m = tokenizer.match(source, pos)
174n/a tokens.append([m.lastgroup, m.group()])
175n/a pos += len(tokens[-1][1])
176n/a if tokens[-1][0] == 'preproc':
177n/a # continuation lines are considered
178n/a # only in preprocess statements
179n/a while tokens[-1][1].endswith('\\\n'):
180n/a nl = source.find('\n', pos)
181n/a if nl == -1:
182n/a line = source[pos:]
183n/a else:
184n/a line = source[pos:nl+1]
185n/a tokens[-1][1] += line
186n/a pos += len(line)
187n/a
188n/a # Main loop: replace all static PyTypeObjects until
189n/a # there are none left.
190n/a while 1:
191n/a c = classify()
192n/a m = re.search('(SW)?TWIW?=W?{.*?};', c)
193n/a if not m:
194n/a break
195n/a start = m.start()
196n/a end = m.end()
197n/a name, fields = get_fields(start, end)
198n/a tokens[start:end] = [('',make_slots(name, fields))]
199n/a
200n/a # Output result to stdout
201n/a for t, v in tokens:
202n/a sys.stdout.write(v)