forked from TRIQS/cpp2py
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcpp2rst.py
More file actions
180 lines (138 loc) · 6.98 KB
/
cpp2rst.py
File metadata and controls
180 lines (138 loc) · 6.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import os, re, sys, itertools
from collections import OrderedDict
import cpp2py.clang_parser as CL
import synopsis
from doc import ProcessDoc
from render_fnt import render_fnt, render_cls
def clean_end_white_char(s):
""" remove the space at the end of the lines (for clean git diff...)"""
reg = re.compile(r"[ \t\r\f\v]+$",re.MULTILINE)
return re.sub(reg,'',s.strip())
def safe_write(output_name, data):
if '/' in output_name:
print "Skipping ", output_name
return
with open("{output_name}.rst".format(output_name=output_name), "w") as f:
f.write((clean_end_white_char(data)))
def mkchdir(*subdirs):
for d in subdirs:
try:
os.mkdir(d)
except OSError:
pass
os.chdir(d)
def mkchdir_for_one_class(node):
"""c : AST node for a class A::B::C::clsname
makes and cd into A/B/C
"""
mkchdir(* ( CL.fully_qualified(node.referenced).split('::')[:-1]))
class Cpp2Rst:
""" """
def __init__(self, filename, namespaces=(), compiler_options=None, includes= (), parse_all_comments = False, libclang_location = None):
"""
Parse the file at construction
Parameters
-----------
filename : string
Name of the file to parse
namespaces : list of string
Restrict the generation to the given namespaces.
includes : string, optional
Additional includes to add (-I xxx) for clang
compiler_options : string, optional
Additional option for clang compiler
libclang_location : string, optional
Absolute path to libclang. By default, the detected one.
"""
self.filename, self.namespaces = filename, namespaces
self.root = CL.parse(filename, compiler_options, includes, libclang_location, parse_all_comments)
def keep_ns(self, n):
ns = CL.fully_qualified(n)
if 'std' in ns or 'boost' in ns or 'detail' in ns or 'impl' in ns : return False
if len(self.namespaces) == 0 : return True
return any((ns in x) for x in self.namespaces)
def keep_cls(self, c):
"""Keeps the class if its namespace is EXACTLY in self.namespaces
e.g. A::B::cls will be kept iif A::B is in self.namespaces, not it A is.
"""
if not c.raw_comment : return False
if len(self.namespaces)>0 :
ns = CL.fully_qualified(c.referenced).rsplit('::',1)[0]
return ns in self.namespaces
return True
def keep_fnt(self, f) :
if not f.raw_comment : return False
if f.spelling.startswith('operator') or f.spelling in ['begin','end'] : return False
return self.keep_cls(f)
def all_functions_gen(self):
"""Generates all the AST nodes of classes (mode = 'C') or functions (mode = 'F')"""
return CL.get_functions(self.root, self.keep_fnt, traverse_namespaces = True, keep_ns = self.keep_ns)
def all_classes_gen(self):
"""Generates all the AST nodes of classes (mode = 'C') or functions (mode = 'F')"""
return CL.get_classes(self.root, self.keep_cls, traverse_namespaces = True, keep_ns = self.keep_ns)
def regroup_func_by_names(self, fs):
""" Given a list of functions, regroup them by names"""
d = OrderedDict()
def decay(name):
if 'operator' not in name : return name
a, ca, c, co = '+ - * /', '+= -= *= /=', "== !=", r" comparison"
d = {'*=' : ca,'+=' : ca,'/=' : ca,'-=' : ca,'*' : a,'+' : a,'/' : a,'-' : a, '==': c, '!=' : c, '<': co, '>' : co, '<=' : co, '>=' : co}
n = name.replace('operator','').strip()
return 'operator' + d[n] if n in d else name
for f in fs:
d.setdefault(decay(f.spelling),[]).append(f)
return d
def process_doc_function(self, f):
"""Process the doc of the function f"""
return ProcessDoc(f, ['include', 'return', 'synopsis', 'warning','figure', 'note', 'example'],['param', 'tparam'])
def process_doc_class(self, c):
"""Process the doc of the class c"""
return ProcessDoc(c, ['include', 'manual_methods', 'manual_friends','warning','figure', 'note', 'example'],['tparam'])
def run(self, output_directory):
print "Generating the documentation ..."
mkchdir(output_directory)
classes = list(self.all_classes_gen())
# FIXME
synopsis.class_list = classes
synopsis.class_list_name = [n.spelling for n in classes]
for c in classes:
if not c.spelling.strip() :
print "Skipping a class with an empty name !"
continue
print " ... class : " + c.spelling, CL.fully_qualified(c.referenced)
# process the doc of the class
cls_doc = self.process_doc_class(c)
# all methods and constructors
all_m = self.regroup_func_by_names(CL.get_methods(c, True)) # True : with inherited ?
constructors = list(CL.get_constructors(c))
if constructors: all_m['constructor'] = constructors
# all non member functions
all_friend_functions = self.regroup_func_by_names(CL.get_friend_functions(c))
# process the doc
doc_methods = dict ( (n, [self.process_doc_function(f) for f in fs]) for (n,fs) in (all_m.items() + all_friend_functions.items()))
# One directory for the class
cur_dir = os.getcwd()
mkchdir_for_one_class(c)
# the file for the class
r = render_cls(doc_class = self.process_doc_class(c), doc_methods = doc_methods, cls = c, all_m = all_m, all_friend_functions = all_friend_functions)
safe_write(c.spelling, r)
mkchdir(c.spelling)
def render(mess, d) :
for f_name, f_overloads in all_m.items():
print " ...... %s %s"%(mess, f_name)
r = render_fnt(doc_methods = doc_methods[f_name], parent_class = c, f_name = f_name, f_overloads = f_overloads)
safe_write(f_name, r)
render('method', all_m)
render('non member function', all_friend_functions)
os.chdir(cur_dir)
all_functions = self.regroup_func_by_names(self.all_functions_gen())
docs = dict ( (n, [self.process_doc_function(f) for f in fs]) for (n,fs) in all_functions.items())
for f_name, f_overloads in all_functions.items():
print " ... function " + f_name
cur_dir = os.getcwd()
mkchdir_for_one_class(f_overloads[0])
print " ..... located: ", f_overloads[0].location.file.name
r = render_fnt( doc_methods = docs[f_name], parent_class = None, f_name = f_name, f_overloads = f_overloads)
safe_write(f_name, r)
os.chdir(cur_dir)
print "... done"