annotate DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/distutils/from_template.py @ 133:4acb5d8d80b6 tip

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