Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 497114e

Browse files
committed
Add tool to check documentation against declaration.
1 parent 29fafd8 commit 497114e

1 file changed

Lines changed: 157 additions & 0 deletions

File tree

Doc/tools/cmpcsyms

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#! /usr/bin/env python
2+
from __future__ import with_statement
3+
import errno
4+
import os
5+
import re
6+
import sys
7+
import string
8+
9+
if __name__ == "__main__":
10+
_base = sys.argv[0]
11+
else:
12+
_base = __file__
13+
14+
_script_home = os.path.abspath(os.path.dirname(_base))
15+
16+
srcdir = os.path.dirname(os.path.dirname(_script_home))
17+
18+
EXCLUDES = ["bitset.h", "cStringIO.h", "graminit.h", "grammar.h",
19+
"longintrepr.h", "metagrammar.h",
20+
"node.h", "opcode.h", "osdefs.h", "pgenheaders.h",
21+
"py_curses.h", "parsetok.h", "symtable.h", "token.h"]
22+
23+
24+
def list_headers():
25+
"""Return a list of headers."""
26+
incdir = os.path.join(srcdir, "Include")
27+
return [os.path.join(incdir, fn) for fn in os.listdir(incdir)
28+
if fn.endswith(".h") and fn not in EXCLUDES]
29+
30+
31+
def matcher(pattern):
32+
return re.compile(pattern).search
33+
34+
MATCHERS = [
35+
# XXX this should also deal with ctypedesc, cvardesc and cmemberdesc
36+
matcher(r"\\begin\{cfuncdesc\}\{(?P<result>[^}]*)\}\{(?P<sym>[^}]*)\}{(?P<params>[^}]*)\}"),
37+
matcher(r"\\cfuncline\{(?P<result>[^})]*)\}\{(?P<sym>[^}]*)\}{(?P<params>[^}]*)\}"),
38+
]
39+
40+
def list_documented_items():
41+
"""Return a list of everything that's already documented."""
42+
apidir = os.path.join(srcdir, "Doc", "api")
43+
files = [fn for fn in os.listdir(apidir) if fn.endswith(".tex")]
44+
L = []
45+
for fn in files:
46+
fullname = os.path.join(apidir, fn)
47+
data = open(fullname).read()
48+
for matcher in MATCHERS:
49+
pos = 0
50+
while 1:
51+
m = matcher(data, pos)
52+
if not m: break
53+
pos = m.end()
54+
sym = m.group("sym")
55+
result = m.group("result")
56+
params = m.group("params")
57+
# replace all whitespace with a single one
58+
params = " ".join(params.split())
59+
L.append((sym, result, params, fn))
60+
return L
61+
62+
def normalize_type(t):
63+
t = t.strip()
64+
s = t.rfind("*")
65+
if s != -1:
66+
# strip everything after the pointer name
67+
t = t[:s+1]
68+
# Drop the variable name
69+
s = t.split()
70+
typenames = 1
71+
if len(s)>1 and s[0]=='unsigned' and s[1]=='int':
72+
typenames = 2
73+
if len(s) > typenames and s[-1][0] in string.letters:
74+
del s[-1]
75+
if not s:
76+
print "XXX", t
77+
return ""
78+
# Drop register
79+
if s[0] == "register":
80+
del s[0]
81+
# discard all spaces
82+
return ''.join(s)
83+
84+
def compare_type(t1, t2):
85+
t1 = normalize_type(t1)
86+
t2 = normalize_type(t2)
87+
if t1 == r'\moreargs' and t2 == '...':
88+
return False
89+
if t1 != t2:
90+
#print "different:", t1, t2
91+
return False
92+
return True
93+
94+
95+
def compare_types(ret, params, hret, hparams):
96+
if not compare_type(ret, hret):
97+
return False
98+
params = params.split(",")
99+
hparams = hparams.split(",")
100+
if not params and hparams == ['void']:
101+
return True
102+
if not hparams and params == ['void']:
103+
return True
104+
if len(params) != len(hparams):
105+
return False
106+
for p1, p2 in zip(params, hparams):
107+
if not compare_type(p1, p2):
108+
return False
109+
return True
110+
111+
def main():
112+
headers = list_headers()
113+
documented = list_documented_items()
114+
115+
lines = []
116+
for h in headers:
117+
data = open(h).read()
118+
data, n = re.subn(r"PyAPI_FUNC\(([^)]*)\)", r"\1", data)
119+
name = os.path.basename(h)
120+
with open(name, "w") as f:
121+
f.write(data)
122+
cmd = ("ctags -f - --file-scope=no --c-kinds=p --fields=S "
123+
"-Istaticforward -Istatichere=static " + name)
124+
with os.popen(cmd) as f:
125+
lines.extend(f.readlines())
126+
os.unlink(name)
127+
L = {}
128+
prevsym = None
129+
for line in lines:
130+
if not line:
131+
break
132+
sym, filename, signature = line.split(None, 2)
133+
if sym == prevsym:
134+
continue
135+
expr = "\^(.*)%s" % sym
136+
m = re.search(expr, signature)
137+
if not m:
138+
print "Could not split",signature, "using",expr
139+
rettype = m.group(1).strip()
140+
m = re.search("signature:\(([^)]*)\)", signature)
141+
if not m:
142+
print "Could not get signature from", signature
143+
params = m.group(1)
144+
L[sym] = (rettype, params)
145+
146+
for sym, ret, params, fn in documented:
147+
if sym not in L:
148+
print "No declaration for '%s'" % sym
149+
continue
150+
hret, hparams = L[sym]
151+
if not compare_types(ret, params, hret, hparams):
152+
print "Declaration error for %s (%s):" % (sym, fn)
153+
print ret+": "+params
154+
print hret+": "+hparams
155+
156+
if __name__ == "__main__":
157+
main()

0 commit comments

Comments
 (0)