Team Ai
Datasetpublic

codekingpro/portable-devtools

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