~ubuntu-branches/ubuntu/feisty/python-numpy/feisty

« back to all changes in this revision

Viewing changes to numpy/distutils/from_template.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-07-12 10:00:24 UTC
  • Revision ID: james.westby@ubuntu.com-20060712100024-5lw9q2yczlisqcrt
Tags: upstream-0.9.8
ImportĀ upstreamĀ versionĀ 0.9.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
49
__all__ = ['process_str','process_file']
 
50
 
 
51
import string,os,sys
 
52
if sys.version[:3]>='2.3':
 
53
    import re
 
54
else:
 
55
    import pre as re
 
56
    False = 0
 
57
    True = 1
 
58
if sys.version[:5]=='2.2.1':
 
59
    import re
 
60
 
 
61
routine_start_re = re.compile(r'(\n|\A)((     (\$|\*))|)\s*(subroutine|function)\b',re.I)
 
62
routine_end_re = re.compile(r'\n\s*end\s*(subroutine|function)\b.*(\n|\Z)',re.I)
 
63
function_start_re = re.compile(r'\n     (\$|\*)\s*function\b',re.I)
 
64
 
 
65
def parse_structure(astr):
 
66
    """ Return a list of tuples for each function or subroutine each
 
67
    tuple is the start and end of a subroutine or function to be
 
68
    expanded.
 
69
    """
 
70
 
 
71
    spanlist = []
 
72
    ind = 0
 
73
    while 1:
 
74
        m = routine_start_re.search(astr,ind)
 
75
        if m is None:
 
76
            break
 
77
        start = m.start()
 
78
        if function_start_re.match(astr,start,m.end()):
 
79
            while 1:
 
80
                i = astr.rfind('\n',ind,start)
 
81
                if i==-1:
 
82
                    break
 
83
                start = i
 
84
                if astr[i:i+7]!='\n     $':
 
85
                    break
 
86
        start += 1
 
87
        m = routine_end_re.search(astr,m.end())
 
88
        ind = end = m and m.end()-1 or len(astr)
 
89
        spanlist.append((start,end))
 
90
    return spanlist
 
91
 
 
92
template_re = re.compile(r"<\s*(\w[\w\d]*)\s*>")
 
93
named_re = re.compile(r"<\s*(\w[\w\d]*)\s*=\s*(.*?)\s*>")
 
94
list_re = re.compile(r"<\s*((.*?))\s*>")
 
95
 
 
96
def find_repl_patterns(astr):
 
97
    reps = named_re.findall(astr)
 
98
    names = {}
 
99
    for rep in reps:
 
100
        name = rep[0].strip() or unique_key(names)
 
101
        repl = rep[1].replace('\,','@comma@')
 
102
        thelist = conv(repl)
 
103
        names[name] = thelist
 
104
    return names
 
105
 
 
106
item_re = re.compile(r"\A\\(?P<index>\d+)\Z")
 
107
def conv(astr):
 
108
    b = astr.split(',')
 
109
    l = [x.strip() for x in b]
 
110
    for i in range(len(l)):
 
111
        m = item_re.match(l[i])
 
112
        if m:
 
113
            j = int(m.group('index'))
 
114
            l[i] = l[j]
 
115
    return ','.join(l)
 
116
 
 
117
def unique_key(adict):
 
118
    """ Obtain a unique key given a dictionary."""
 
119
    allkeys = adict.keys()
 
120
    done = False
 
121
    n = 1
 
122
    while not done:
 
123
        newkey = '__l%s' % (n)
 
124
        if newkey in allkeys:
 
125
            n += 1
 
126
        else:
 
127
            done = True
 
128
    return newkey
 
129
 
 
130
 
 
131
template_name_re = re.compile(r'\A\s*(\w[\w\d]*)\s*\Z')
 
132
def expand_sub(substr,names):
 
133
    substr = substr.replace('\>','@rightarrow@')
 
134
    substr = substr.replace('\<','@leftarrow@')
 
135
    lnames = find_repl_patterns(substr)
 
136
    substr = named_re.sub(r"<\1>",substr)  # get rid of definition templates
 
137
 
 
138
    def listrepl(mobj):
 
139
        thelist = conv(mobj.group(1).replace('\,','@comma@'))
 
140
        if template_name_re.match(thelist):
 
141
            return "<%s>" % (thelist)
 
142
        name = None
 
143
        for key in lnames.keys():    # see if list is already in dictionary
 
144
            if lnames[key] == thelist:
 
145
                name = key
 
146
        if name is None:      # this list is not in the dictionary yet
 
147
            name = unique_key(lnames)
 
148
            lnames[name] = thelist
 
149
        return "<%s>" % name
 
150
 
 
151
    substr = list_re.sub(listrepl, substr) # convert all lists to named templates
 
152
                                           # newnames are constructed as needed
 
153
 
 
154
    numsubs = None
 
155
    base_rule = None
 
156
    rules = {}
 
157
    for r in template_re.findall(substr):
 
158
        if not rules.has_key(r):
 
159
            thelist = lnames.get(r,names.get(r,None))
 
160
            if thelist is None:
 
161
                raise ValueError,'No replicates found for <%s>' % (r)
 
162
            if not names.has_key(r) and not thelist.startswith('_'):
 
163
                names[r] = thelist
 
164
            rule = [i.replace('@comma@',',') for i in thelist.split(',')]
 
165
            num = len(rule)
 
166
 
 
167
            if numsubs is None:
 
168
                numsubs = num
 
169
                rules[r] = rule
 
170
                base_rule = r
 
171
            elif num == numsubs:
 
172
                rules[r] = rule
 
173
            else:
 
174
                print "Mismatch in number of replacements (base <%s=%s>)"\
 
175
                      " for <%s=%s>. Ignoring." % (base_rule,
 
176
                                                  ','.join(rules[base_rule]),
 
177
                                                  r,thelist)
 
178
    if not rules:
 
179
        return substr
 
180
 
 
181
    def namerepl(mobj):
 
182
        name = mobj.group(1)
 
183
        return rules.get(name,(k+1)*[name])[k]
 
184
 
 
185
    newstr = ''
 
186
    for k in range(numsubs):
 
187
        newstr += template_re.sub(namerepl, substr) + '\n\n'
 
188
 
 
189
    newstr = newstr.replace('@rightarrow@','>')
 
190
    newstr = newstr.replace('@leftarrow@','<')
 
191
    return newstr
 
192
 
 
193
def process_str(allstr):
 
194
    newstr = allstr
 
195
    writestr = '' #_head # using _head will break free-format files
 
196
 
 
197
    struct = parse_structure(newstr)
 
198
 
 
199
    oldend = 0
 
200
    names = {}
 
201
    names.update(_special_names)
 
202
    for sub in struct:
 
203
        writestr += newstr[oldend:sub[0]]
 
204
        names.update(find_repl_patterns(newstr[oldend:sub[0]]))
 
205
        writestr += expand_sub(newstr[sub[0]:sub[1]],names)
 
206
        oldend =  sub[1]
 
207
    writestr += newstr[oldend:]
 
208
 
 
209
    return writestr
 
210
 
 
211
include_src_re = re.compile(r"(\n|\A)\s*include\s*['\"](?P<name>[\w\d./\\]+[.]src)['\"]",re.I)
 
212
 
 
213
def resolve_includes(source):
 
214
    d = os.path.dirname(source)
 
215
    fid = open(source)
 
216
    lines = []
 
217
    for line in fid.readlines():
 
218
        m = include_src_re.match(line)
 
219
        if m:
 
220
            fn = m.group('name')
 
221
            if not os.path.isabs(fn):
 
222
                fn = os.path.join(d,fn)
 
223
            if os.path.isfile(fn):
 
224
                print 'Including file',fn
 
225
                lines.extend(resolve_includes(fn))
 
226
            else:
 
227
                lines.append(line)
 
228
        else:
 
229
            lines.append(line)
 
230
    fid.close()
 
231
    return lines
 
232
 
 
233
def process_file(source):
 
234
    lines = resolve_includes(source)
 
235
    return process_str(''.join(lines))
 
236
 
 
237
_special_names = find_repl_patterns('''
 
238
<_c=s,d,c,z>
 
239
<_t=real,double precision,complex,double complex>
 
240
<prefix=s,d,c,z>
 
241
<ftype=real,double precision,complex,double complex>
 
242
<ctype=float,double,complex_float,complex_double>
 
243
<ftypereal=real,double precision,\\0,\\1>
 
244
<ctypereal=float,double,\\0,\\1>
 
245
''')
 
246
 
 
247
if __name__ == "__main__":
 
248
 
 
249
    try:
 
250
        file = sys.argv[1]
 
251
    except IndexError:
 
252
        fid = sys.stdin
 
253
        outfile = sys.stdout
 
254
    else:
 
255
        fid = open(file,'r')
 
256
        (base, ext) = os.path.splitext(file)
 
257
        newname = base
 
258
        outfile = open(newname,'w')
 
259
 
 
260
    allstr = fid.read()
 
261
    writestr = process_str(allstr)
 
262
    outfile.write(writestr)