Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
func2subr.py330 linesDownload Raw Back to f2py
1"""
2
3Rules for building C/API module with f2py2e.
4
5Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
6Copyright 2011 -- present NumPy Developers.
7Permission to use, modify, and distribute this software is given under the
8terms of the NumPy License.
9
10NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
11"""
12import copy
13
14from ._isocbind import isoc_kindmap
15from .auxfuncs import (
16    getfortranname,
17    isexternal,
18    isfunction,
19    isfunction_wrap,
20    isintent_in,
21    isintent_out,
22    islogicalfunction,
23    ismoduleroutine,
24    isscalar,
25    issubroutine,
26    issubroutine_wrap,
27    outmess,
28    show,
29)
30
31
32def var2fixfortran(vars, a, fa=None, f90mode=None):
33    if fa is None:
34        fa = a
35    if a not in vars:
36        show(vars)
37        outmess(f'var2fixfortran: No definition for argument "{a}".\n')
38        return ''
39    if 'typespec' not in vars[a]:
40        show(vars[a])
41        outmess(f'var2fixfortran: No typespec for argument "{a}".\n')
42        return ''
43    vardef = vars[a]['typespec']
44    if vardef == 'type' and 'typename' in vars[a]:
45        vardef = f"{vardef}({vars[a]['typename']})"
46    selector = {}
47    lk = ''
48    if 'kindselector' in vars[a]:
49        selector = vars[a]['kindselector']
50        lk = 'kind'
51    elif 'charselector' in vars[a]:
52        selector = vars[a]['charselector']
53        lk = 'len'
54    if '*' in selector:
55        if f90mode:
56            if selector['*'] in ['*', ':', '(*)']:
57                vardef = f'{vardef}(len=*)'
58            else:
59                vardef = f"{vardef}({lk}={selector['*']})"
60        elif selector['*'] in ['*', ':']:
61            vardef = f"{vardef}*({selector['*']})"
62        else:
63            vardef = f"{vardef}*{selector['*']}"
64    elif 'len' in selector:
65        vardef = f"{vardef}(len={selector['len']}"
66        if 'kind' in selector:
67            vardef = f"{vardef},kind={selector['kind']})"
68        else:
69            vardef = f'{vardef})'
70    elif 'kind' in selector:
71        vardef = f"{vardef}(kind={selector['kind']})"
72
73    vardef = f'{vardef} {fa}'
74    if 'dimension' in vars[a]:
75        vardef = f"{vardef}({','.join(vars[a]['dimension'])})"
76    return vardef
77
78def useiso_c_binding(rout):
79    useisoc = False
80    for value in rout['vars'].values():
81        kind_value = value.get('kindselector', {}).get('kind')
82        if kind_value in isoc_kindmap:
83            return True
84    return useisoc
85
86def createfuncwrapper(rout, signature=0):
87    assert isfunction(rout)
88
89    extra_args = []
90    vars = rout['vars']
91    for a in rout['args']:
92        v = rout['vars'][a]
93        for i, d in enumerate(v.get('dimension', [])):
94            if d == ':':
95                dn = f'f2py_{a}_d{i}'
96                dv = {'typespec': 'integer', 'intent': ['hide']}
97                dv['='] = f'shape({a}, {i})'
98                extra_args.append(dn)
99                vars[dn] = dv
100                v['dimension'][i] = dn
101    rout['args'].extend(extra_args)
102    need_interface = bool(extra_args)
103
104    ret = ['']
105
106    def add(line, ret=ret):
107        ret[0] = f'{ret[0]}\n      {line}'
108    name = rout['name']
109    fortranname = getfortranname(rout)
110    f90mode = ismoduleroutine(rout)
111    newname = f'{name}f2pywrap'
112
113    if newname not in vars:
114        vars[newname] = vars[name]
115        args = [newname] + rout['args'][1:]
116    else:
117        args = [newname] + rout['args']
118
119    l_tmpl = var2fixfortran(vars, name, '@@@NAME@@@', f90mode)
120    if l_tmpl[:13] == 'character*(*)':
121        if f90mode:
122            l_tmpl = 'character(len=10)' + l_tmpl[13:]
123        else:
124            l_tmpl = 'character*10' + l_tmpl[13:]
125        charselect = vars[name]['charselector']
126        if charselect.get('*', '') == '(*)':
127            charselect['*'] = '10'
128
129    l1 = l_tmpl.replace('@@@NAME@@@', newname)
130    rl = None
131
132    useisoc = useiso_c_binding(rout)
133    sargs = ', '.join(args)
134    if f90mode:
135        # gh-23598 fix warning
136        # Essentially, this gets called again with modules where the name of the
137        # function is added to the arguments, which is not required, and removed
138        sargs = sargs.replace(f"{name}, ", '')
139        args = [arg for arg in args if arg != name]
140        rout['args'] = args
141        add(f"subroutine f2pywrap_{rout['modulename']}_{name} ({sargs})")
142        if not signature:
143            add(f"use {rout['modulename']}, only : {fortranname}")
144        if useisoc:
145            add('use iso_c_binding')
146    else:
147        add(f'subroutine f2pywrap{name} ({sargs})')
148        if useisoc:
149            add('use iso_c_binding')
150        if not need_interface:
151            add(f'external {fortranname}')
152            rl = l_tmpl.replace('@@@NAME@@@', '') + ' ' + fortranname
153
154    if need_interface:
155        for line in rout['saved_interface'].split('\n'):
156            if line.lstrip().startswith('use ') and '__user__' not in line:
157                add(line)
158
159    args = args[1:]
160    dumped_args = []
161    for a in args:
162        if isexternal(vars[a]):
163            add(f'external {a}')
164            dumped_args.append(a)
165    for a in args:
166        if a in dumped_args:
167            continue
168        if isscalar(vars[a]):
169            add(var2fixfortran(vars, a, f90mode=f90mode))
170            dumped_args.append(a)
171    for a in args:
172        if a in dumped_args:
173            continue
174        if isintent_in(vars[a]):
175            add(var2fixfortran(vars, a, f90mode=f90mode))
176            dumped_args.append(a)
177    for a in args:
178        if a in dumped_args:
179            continue
180        add(var2fixfortran(vars, a, f90mode=f90mode))
181
182    add(l1)
183    if rl is not None:
184        add(rl)
185
186    if need_interface:
187        if f90mode:
188            # f90 module already defines needed interface
189            pass
190        else:
191            add('interface')
192            add(rout['saved_interface'].lstrip())
193            add('end interface')
194
195    sargs = ', '.join([a for a in args if a not in extra_args])
196
197    if not signature:
198        if islogicalfunction(rout):
199            add(f'{newname} = .not.(.not.{fortranname}({sargs}))')
200        else:
201            add(f'{newname} = {fortranname}({sargs})')
202    if f90mode:
203        add(f"end subroutine f2pywrap_{rout['modulename']}_{name}")
204    else:
205        add('end')
206    return ret[0]
207
208
209def createsubrwrapper(rout, signature=0):
210    assert issubroutine(rout)
211
212    extra_args = []
213    vars = rout['vars']
214    for a in rout['args']:
215        v = rout['vars'][a]
216        for i, d in enumerate(v.get('dimension', [])):
217            if d == ':':
218                dn = f'f2py_{a}_d{i}'
219                dv = {'typespec': 'integer', 'intent': ['hide']}
220                dv['='] = f'shape({a}, {i})'
221                extra_args.append(dn)
222                vars[dn] = dv
223                v['dimension'][i] = dn
224    rout['args'].extend(extra_args)
225    need_interface = bool(extra_args)
226
227    ret = ['']
228
229    def add(line, ret=ret):
230        ret[0] = f'{ret[0]}\n      {line}'
231    name = rout['name']
232    fortranname = getfortranname(rout)
233    f90mode = ismoduleroutine(rout)
234
235    args = rout['args']
236
237    useisoc = useiso_c_binding(rout)
238    sargs = ', '.join(args)
239    if f90mode:
240        add(f"subroutine f2pywrap_{rout['modulename']}_{name} ({sargs})")
241        if useisoc:
242            add('use iso_c_binding')
243        if not signature:
244            add(f"use {rout['modulename']}, only : {fortranname}")
245    else:
246        add(f'subroutine f2pywrap{name} ({sargs})')
247        if useisoc:
248            add('use iso_c_binding')
249        if not need_interface:
250            add(f'external {fortranname}')
251
252    if need_interface:
253        for line in rout['saved_interface'].split('\n'):
254            if line.lstrip().startswith('use ') and '__user__' not in line:
255                add(line)
256
257    dumped_args = []
258    for a in args:
259        if isexternal(vars[a]):
260            add(f'external {a}')
261            dumped_args.append(a)
262    for a in args:
263        if a in dumped_args:
264            continue
265        if isscalar(vars[a]):
266            add(var2fixfortran(vars, a, f90mode=f90mode))
267            dumped_args.append(a)
268    for a in args:
269        if a in dumped_args:
270            continue
271        add(var2fixfortran(vars, a, f90mode=f90mode))
272
273    if need_interface:
274        if f90mode:
275            # f90 module already defines needed interface
276            pass
277        else:
278            add('interface')
279            for line in rout['saved_interface'].split('\n'):
280                if line.lstrip().startswith('use ') and '__user__' in line:
281                    continue
282                add(line)
283            add('end interface')
284
285    sargs = ', '.join([a for a in args if a not in extra_args])
286
287    if not signature:
288        add(f'call {fortranname}({sargs})')
289    if f90mode:
290        add(f"end subroutine f2pywrap_{rout['modulename']}_{name}")
291    else:
292        add('end')
293    return ret[0]
294
295
296def assubr(rout):
297    if isfunction_wrap(rout):
298        fortranname = getfortranname(rout)
299        name = rout['name']
300        outmess('\t\tCreating wrapper for Fortran function "%s"("%s")...\n' % (
301            name, fortranname))
302        rout = copy.copy(rout)
303        fname = name
304        rname = fname
305        if 'result' in rout:
306            rname = rout['result']
307            rout['vars'][fname] = rout['vars'][rname]
308        fvar = rout['vars'][fname]
309        if not isintent_out(fvar):
310            if 'intent' not in fvar:
311                fvar['intent'] = []
312            fvar['intent'].append('out')
313            flag = 1
314            for i in fvar['intent']:
315                if i.startswith('out='):
316                    flag = 0
317                    break
318            if flag:
319                fvar['intent'].append(f'out={rname}')
320        rout['args'][:] = [fname] + rout['args']
321        return rout, createfuncwrapper(rout)
322    if issubroutine_wrap(rout):
323        fortranname = getfortranname(rout)
324        name = rout['name']
325        outmess('\t\tCreating wrapper for Fortran subroutine "%s"("%s")...\n'
326                % (name, fortranname))
327        rout = copy.copy(rout)
328        return rout, createsubrwrapper(rout)
329    return rout, ''
330 
codekingpro/portable-devtools · Team Ai