Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/distutils/from_template.py @ 87:2a2c65a20a8b
Add Python libs and headers
author | Chris Cannam |
---|---|
date | Wed, 25 Feb 2015 14:05:22 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
86:413a9d26189e | 87:2a2c65a20a8b |
---|---|
1 #!/usr/bin/python | |
2 """ | |
3 | |
4 process_file(filename) | |
5 | |
6 takes templated file .xxx.src and produces .xxx file where .xxx | |
7 is .pyf .f90 or .f using the following template rules: | |
8 | |
9 '<..>' denotes a template. | |
10 | |
11 All function and subroutine blocks in a source file with names that | |
12 contain '<..>' will be replicated according to the rules in '<..>'. | |
13 | |
14 The number of comma-separeted words in '<..>' will determine the number of | |
15 replicates. | |
16 | |
17 '<..>' may have two different forms, named and short. For example, | |
18 | |
19 named: | |
20 <p=d,s,z,c> where anywhere inside a block '<p>' will be replaced with | |
21 'd', 's', 'z', and 'c' for each replicate of the block. | |
22 | |
23 <_c> is already defined: <_c=s,d,c,z> | |
24 <_t> is already defined: <_t=real,double precision,complex,double complex> | |
25 | |
26 short: | |
27 <s,d,c,z>, a short form of the named, useful when no <p> appears inside | |
28 a block. | |
29 | |
30 In general, '<..>' contains a comma separated list of arbitrary | |
31 expressions. If these expression must contain a comma|leftarrow|rightarrow, | |
32 then prepend the comma|leftarrow|rightarrow with a backslash. | |
33 | |
34 If an expression matches '\\<index>' then it will be replaced | |
35 by <index>-th expression. | |
36 | |
37 Note that all '<..>' forms in a block must have the same number of | |
38 comma-separated entries. | |
39 | |
40 Predefined named template rules: | |
41 <prefix=s,d,c,z> | |
42 <ftype=real,double precision,complex,double complex> | |
43 <ftypereal=real,double precision,\\0,\\1> | |
44 <ctype=float,double,complex_float,complex_double> | |
45 <ctypereal=float,double,\\0,\\1> | |
46 | |
47 """ | |
48 from __future__ import division, absolute_import, print_function | |
49 | |
50 __all__ = ['process_str', 'process_file'] | |
51 | |
52 import os | |
53 import sys | |
54 import re | |
55 | |
56 routine_start_re = re.compile(r'(\n|\A)(( (\$|\*))|)\s*(subroutine|function)\b', re.I) | |
57 routine_end_re = re.compile(r'\n\s*end\s*(subroutine|function)\b.*(\n|\Z)', re.I) | |
58 function_start_re = re.compile(r'\n (\$|\*)\s*function\b', re.I) | |
59 | |
60 def parse_structure(astr): | |
61 """ Return a list of tuples for each function or subroutine each | |
62 tuple is the start and end of a subroutine or function to be | |
63 expanded. | |
64 """ | |
65 | |
66 spanlist = [] | |
67 ind = 0 | |
68 while True: | |
69 m = routine_start_re.search(astr, ind) | |
70 if m is None: | |
71 break | |
72 start = m.start() | |
73 if function_start_re.match(astr, start, m.end()): | |
74 while True: | |
75 i = astr.rfind('\n', ind, start) | |
76 if i==-1: | |
77 break | |
78 start = i | |
79 if astr[i:i+7]!='\n $': | |
80 break | |
81 start += 1 | |
82 m = routine_end_re.search(astr, m.end()) | |
83 ind = end = m and m.end()-1 or len(astr) | |
84 spanlist.append((start, end)) | |
85 return spanlist | |
86 | |
87 template_re = re.compile(r"<\s*(\w[\w\d]*)\s*>") | |
88 named_re = re.compile(r"<\s*(\w[\w\d]*)\s*=\s*(.*?)\s*>") | |
89 list_re = re.compile(r"<\s*((.*?))\s*>") | |
90 | |
91 def find_repl_patterns(astr): | |
92 reps = named_re.findall(astr) | |
93 names = {} | |
94 for rep in reps: | |
95 name = rep[0].strip() or unique_key(names) | |
96 repl = rep[1].replace('\,', '@comma@') | |
97 thelist = conv(repl) | |
98 names[name] = thelist | |
99 return names | |
100 | |
101 item_re = re.compile(r"\A\\(?P<index>\d+)\Z") | |
102 def conv(astr): | |
103 b = astr.split(',') | |
104 l = [x.strip() for x in b] | |
105 for i in range(len(l)): | |
106 m = item_re.match(l[i]) | |
107 if m: | |
108 j = int(m.group('index')) | |
109 l[i] = l[j] | |
110 return ','.join(l) | |
111 | |
112 def unique_key(adict): | |
113 """ Obtain a unique key given a dictionary.""" | |
114 allkeys = list(adict.keys()) | |
115 done = False | |
116 n = 1 | |
117 while not done: | |
118 newkey = '__l%s' % (n) | |
119 if newkey in allkeys: | |
120 n += 1 | |
121 else: | |
122 done = True | |
123 return newkey | |
124 | |
125 | |
126 template_name_re = re.compile(r'\A\s*(\w[\w\d]*)\s*\Z') | |
127 def expand_sub(substr, names): | |
128 substr = substr.replace('\>', '@rightarrow@') | |
129 substr = substr.replace('\<', '@leftarrow@') | |
130 lnames = find_repl_patterns(substr) | |
131 substr = named_re.sub(r"<\1>", substr) # get rid of definition templates | |
132 | |
133 def listrepl(mobj): | |
134 thelist = conv(mobj.group(1).replace('\,', '@comma@')) | |
135 if template_name_re.match(thelist): | |
136 return "<%s>" % (thelist) | |
137 name = None | |
138 for key in lnames.keys(): # see if list is already in dictionary | |
139 if lnames[key] == thelist: | |
140 name = key | |
141 if name is None: # this list is not in the dictionary yet | |
142 name = unique_key(lnames) | |
143 lnames[name] = thelist | |
144 return "<%s>" % name | |
145 | |
146 substr = list_re.sub(listrepl, substr) # convert all lists to named templates | |
147 # newnames are constructed as needed | |
148 | |
149 numsubs = None | |
150 base_rule = None | |
151 rules = {} | |
152 for r in template_re.findall(substr): | |
153 if r not in rules: | |
154 thelist = lnames.get(r, names.get(r, None)) | |
155 if thelist is None: | |
156 raise ValueError('No replicates found for <%s>' % (r)) | |
157 if r not in names and not thelist.startswith('_'): | |
158 names[r] = thelist | |
159 rule = [i.replace('@comma@', ',') for i in thelist.split(',')] | |
160 num = len(rule) | |
161 | |
162 if numsubs is None: | |
163 numsubs = num | |
164 rules[r] = rule | |
165 base_rule = r | |
166 elif num == numsubs: | |
167 rules[r] = rule | |
168 else: | |
169 print("Mismatch in number of replacements (base <%s=%s>)" | |
170 " for <%s=%s>. Ignoring." % | |
171 (base_rule, ','.join(rules[base_rule]), r, thelist)) | |
172 if not rules: | |
173 return substr | |
174 | |
175 def namerepl(mobj): | |
176 name = mobj.group(1) | |
177 return rules.get(name, (k+1)*[name])[k] | |
178 | |
179 newstr = '' | |
180 for k in range(numsubs): | |
181 newstr += template_re.sub(namerepl, substr) + '\n\n' | |
182 | |
183 newstr = newstr.replace('@rightarrow@', '>') | |
184 newstr = newstr.replace('@leftarrow@', '<') | |
185 return newstr | |
186 | |
187 def process_str(allstr): | |
188 newstr = allstr | |
189 writestr = '' #_head # using _head will break free-format files | |
190 | |
191 struct = parse_structure(newstr) | |
192 | |
193 oldend = 0 | |
194 names = {} | |
195 names.update(_special_names) | |
196 for sub in struct: | |
197 writestr += newstr[oldend:sub[0]] | |
198 names.update(find_repl_patterns(newstr[oldend:sub[0]])) | |
199 writestr += expand_sub(newstr[sub[0]:sub[1]], names) | |
200 oldend = sub[1] | |
201 writestr += newstr[oldend:] | |
202 | |
203 return writestr | |
204 | |
205 include_src_re = re.compile(r"(\n|\A)\s*include\s*['\"](?P<name>[\w\d./\\]+[.]src)['\"]", re.I) | |
206 | |
207 def resolve_includes(source): | |
208 d = os.path.dirname(source) | |
209 fid = open(source) | |
210 lines = [] | |
211 for line in fid: | |
212 m = include_src_re.match(line) | |
213 if m: | |
214 fn = m.group('name') | |
215 if not os.path.isabs(fn): | |
216 fn = os.path.join(d, fn) | |
217 if os.path.isfile(fn): | |
218 print('Including file', fn) | |
219 lines.extend(resolve_includes(fn)) | |
220 else: | |
221 lines.append(line) | |
222 else: | |
223 lines.append(line) | |
224 fid.close() | |
225 return lines | |
226 | |
227 def process_file(source): | |
228 lines = resolve_includes(source) | |
229 return process_str(''.join(lines)) | |
230 | |
231 _special_names = find_repl_patterns(''' | |
232 <_c=s,d,c,z> | |
233 <_t=real,double precision,complex,double complex> | |
234 <prefix=s,d,c,z> | |
235 <ftype=real,double precision,complex,double complex> | |
236 <ctype=float,double,complex_float,complex_double> | |
237 <ftypereal=real,double precision,\\0,\\1> | |
238 <ctypereal=float,double,\\0,\\1> | |
239 ''') | |
240 | |
241 if __name__ == "__main__": | |
242 | |
243 try: | |
244 file = sys.argv[1] | |
245 except IndexError: | |
246 fid = sys.stdin | |
247 outfile = sys.stdout | |
248 else: | |
249 fid = open(file, 'r') | |
250 (base, ext) = os.path.splitext(file) | |
251 newname = base | |
252 outfile = open(newname, 'w') | |
253 | |
254 allstr = fid.read() | |
255 writestr = process_str(allstr) | |
256 outfile.write(writestr) |