done
This commit is contained in:
		
							
								
								
									
										261
									
								
								lib/python3.11/site-packages/numpy/distutils/from_template.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								lib/python3.11/site-packages/numpy/distutils/from_template.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,261 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
process_file(filename)
 | 
			
		||||
 | 
			
		||||
  takes templated file .xxx.src and produces .xxx file where .xxx
 | 
			
		||||
  is .pyf .f90 or .f using the following template rules:
 | 
			
		||||
 | 
			
		||||
  '<..>' denotes a template.
 | 
			
		||||
 | 
			
		||||
  All function and subroutine blocks in a source file with names that
 | 
			
		||||
  contain '<..>' will be replicated according to the rules in '<..>'.
 | 
			
		||||
 | 
			
		||||
  The number of comma-separated words in '<..>' will determine the number of
 | 
			
		||||
  replicates.
 | 
			
		||||
 | 
			
		||||
  '<..>' may have two different forms, named and short. For example,
 | 
			
		||||
 | 
			
		||||
  named:
 | 
			
		||||
   <p=d,s,z,c> where anywhere inside a block '<p>' will be replaced with
 | 
			
		||||
   'd', 's', 'z', and 'c' for each replicate of the block.
 | 
			
		||||
 | 
			
		||||
   <_c>  is already defined: <_c=s,d,c,z>
 | 
			
		||||
   <_t>  is already defined: <_t=real,double precision,complex,double complex>
 | 
			
		||||
 | 
			
		||||
  short:
 | 
			
		||||
   <s,d,c,z>, a short form of the named, useful when no <p> appears inside
 | 
			
		||||
   a block.
 | 
			
		||||
 | 
			
		||||
  In general, '<..>' contains a comma separated list of arbitrary
 | 
			
		||||
  expressions. If these expression must contain a comma|leftarrow|rightarrow,
 | 
			
		||||
  then prepend the comma|leftarrow|rightarrow with a backslash.
 | 
			
		||||
 | 
			
		||||
  If an expression matches '\\<index>' then it will be replaced
 | 
			
		||||
  by <index>-th expression.
 | 
			
		||||
 | 
			
		||||
  Note that all '<..>' forms in a block must have the same number of
 | 
			
		||||
  comma-separated entries.
 | 
			
		||||
 | 
			
		||||
 Predefined named template rules:
 | 
			
		||||
  <prefix=s,d,c,z>
 | 
			
		||||
  <ftype=real,double precision,complex,double complex>
 | 
			
		||||
  <ftypereal=real,double precision,\\0,\\1>
 | 
			
		||||
  <ctype=float,double,complex_float,complex_double>
 | 
			
		||||
  <ctypereal=float,double,\\0,\\1>
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
__all__ = ['process_str', 'process_file']
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
routine_start_re = re.compile(r'(\n|\A)((     (\$|\*))|)\s*(subroutine|function)\b', re.I)
 | 
			
		||||
routine_end_re = re.compile(r'\n\s*end\s*(subroutine|function)\b.*(\n|\Z)', re.I)
 | 
			
		||||
function_start_re = re.compile(r'\n     (\$|\*)\s*function\b', re.I)
 | 
			
		||||
 | 
			
		||||
def parse_structure(astr):
 | 
			
		||||
    """ Return a list of tuples for each function or subroutine each
 | 
			
		||||
    tuple is the start and end of a subroutine or function to be
 | 
			
		||||
    expanded.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    spanlist = []
 | 
			
		||||
    ind = 0
 | 
			
		||||
    while True:
 | 
			
		||||
        m = routine_start_re.search(astr, ind)
 | 
			
		||||
        if m is None:
 | 
			
		||||
            break
 | 
			
		||||
        start = m.start()
 | 
			
		||||
        if function_start_re.match(astr, start, m.end()):
 | 
			
		||||
            while True:
 | 
			
		||||
                i = astr.rfind('\n', ind, start)
 | 
			
		||||
                if i==-1:
 | 
			
		||||
                    break
 | 
			
		||||
                start = i
 | 
			
		||||
                if astr[i:i+7]!='\n     $':
 | 
			
		||||
                    break
 | 
			
		||||
        start += 1
 | 
			
		||||
        m = routine_end_re.search(astr, m.end())
 | 
			
		||||
        ind = end = m and m.end()-1 or len(astr)
 | 
			
		||||
        spanlist.append((start, end))
 | 
			
		||||
    return spanlist
 | 
			
		||||
 | 
			
		||||
template_re = re.compile(r"<\s*(\w[\w\d]*)\s*>")
 | 
			
		||||
named_re = re.compile(r"<\s*(\w[\w\d]*)\s*=\s*(.*?)\s*>")
 | 
			
		||||
list_re = re.compile(r"<\s*((.*?))\s*>")
 | 
			
		||||
 | 
			
		||||
def find_repl_patterns(astr):
 | 
			
		||||
    reps = named_re.findall(astr)
 | 
			
		||||
    names = {}
 | 
			
		||||
    for rep in reps:
 | 
			
		||||
        name = rep[0].strip() or unique_key(names)
 | 
			
		||||
        repl = rep[1].replace(r'\,', '@comma@')
 | 
			
		||||
        thelist = conv(repl)
 | 
			
		||||
        names[name] = thelist
 | 
			
		||||
    return names
 | 
			
		||||
 | 
			
		||||
def find_and_remove_repl_patterns(astr):
 | 
			
		||||
    names = find_repl_patterns(astr)
 | 
			
		||||
    astr = re.subn(named_re, '', astr)[0]
 | 
			
		||||
    return astr, names
 | 
			
		||||
 | 
			
		||||
item_re = re.compile(r"\A\\(?P<index>\d+)\Z")
 | 
			
		||||
def conv(astr):
 | 
			
		||||
    b = astr.split(',')
 | 
			
		||||
    l = [x.strip() for x in b]
 | 
			
		||||
    for i in range(len(l)):
 | 
			
		||||
        m = item_re.match(l[i])
 | 
			
		||||
        if m:
 | 
			
		||||
            j = int(m.group('index'))
 | 
			
		||||
            l[i] = l[j]
 | 
			
		||||
    return ','.join(l)
 | 
			
		||||
 | 
			
		||||
def unique_key(adict):
 | 
			
		||||
    """ Obtain a unique key given a dictionary."""
 | 
			
		||||
    allkeys = list(adict.keys())
 | 
			
		||||
    done = False
 | 
			
		||||
    n = 1
 | 
			
		||||
    while not done:
 | 
			
		||||
        newkey = '__l%s' % (n)
 | 
			
		||||
        if newkey in allkeys:
 | 
			
		||||
            n += 1
 | 
			
		||||
        else:
 | 
			
		||||
            done = True
 | 
			
		||||
    return newkey
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template_name_re = re.compile(r'\A\s*(\w[\w\d]*)\s*\Z')
 | 
			
		||||
def expand_sub(substr, names):
 | 
			
		||||
    substr = substr.replace(r'\>', '@rightarrow@')
 | 
			
		||||
    substr = substr.replace(r'\<', '@leftarrow@')
 | 
			
		||||
    lnames = find_repl_patterns(substr)
 | 
			
		||||
    substr = named_re.sub(r"<\1>", substr)  # get rid of definition templates
 | 
			
		||||
 | 
			
		||||
    def listrepl(mobj):
 | 
			
		||||
        thelist = conv(mobj.group(1).replace(r'\,', '@comma@'))
 | 
			
		||||
        if template_name_re.match(thelist):
 | 
			
		||||
            return "<%s>" % (thelist)
 | 
			
		||||
        name = None
 | 
			
		||||
        for key in lnames.keys():    # see if list is already in dictionary
 | 
			
		||||
            if lnames[key] == thelist:
 | 
			
		||||
                name = key
 | 
			
		||||
        if name is None:      # this list is not in the dictionary yet
 | 
			
		||||
            name = unique_key(lnames)
 | 
			
		||||
            lnames[name] = thelist
 | 
			
		||||
        return "<%s>" % name
 | 
			
		||||
 | 
			
		||||
    substr = list_re.sub(listrepl, substr) # convert all lists to named templates
 | 
			
		||||
                                           # newnames are constructed as needed
 | 
			
		||||
 | 
			
		||||
    numsubs = None
 | 
			
		||||
    base_rule = None
 | 
			
		||||
    rules = {}
 | 
			
		||||
    for r in template_re.findall(substr):
 | 
			
		||||
        if r not in rules:
 | 
			
		||||
            thelist = lnames.get(r, names.get(r, None))
 | 
			
		||||
            if thelist is None:
 | 
			
		||||
                raise ValueError('No replicates found for <%s>' % (r))
 | 
			
		||||
            if r not in names and not thelist.startswith('_'):
 | 
			
		||||
                names[r] = thelist
 | 
			
		||||
            rule = [i.replace('@comma@', ',') for i in thelist.split(',')]
 | 
			
		||||
            num = len(rule)
 | 
			
		||||
 | 
			
		||||
            if numsubs is None:
 | 
			
		||||
                numsubs = num
 | 
			
		||||
                rules[r] = rule
 | 
			
		||||
                base_rule = r
 | 
			
		||||
            elif num == numsubs:
 | 
			
		||||
                rules[r] = rule
 | 
			
		||||
            else:
 | 
			
		||||
                print("Mismatch in number of replacements (base <%s=%s>)"
 | 
			
		||||
                      " for <%s=%s>. Ignoring." %
 | 
			
		||||
                      (base_rule, ','.join(rules[base_rule]), r, thelist))
 | 
			
		||||
    if not rules:
 | 
			
		||||
        return substr
 | 
			
		||||
 | 
			
		||||
    def namerepl(mobj):
 | 
			
		||||
        name = mobj.group(1)
 | 
			
		||||
        return rules.get(name, (k+1)*[name])[k]
 | 
			
		||||
 | 
			
		||||
    newstr = ''
 | 
			
		||||
    for k in range(numsubs):
 | 
			
		||||
        newstr += template_re.sub(namerepl, substr) + '\n\n'
 | 
			
		||||
 | 
			
		||||
    newstr = newstr.replace('@rightarrow@', '>')
 | 
			
		||||
    newstr = newstr.replace('@leftarrow@', '<')
 | 
			
		||||
    return newstr
 | 
			
		||||
 | 
			
		||||
def process_str(allstr):
 | 
			
		||||
    newstr = allstr
 | 
			
		||||
    writestr = ''
 | 
			
		||||
 | 
			
		||||
    struct = parse_structure(newstr)
 | 
			
		||||
 | 
			
		||||
    oldend = 0
 | 
			
		||||
    names = {}
 | 
			
		||||
    names.update(_special_names)
 | 
			
		||||
    for sub in struct:
 | 
			
		||||
        cleanedstr, defs = find_and_remove_repl_patterns(newstr[oldend:sub[0]])
 | 
			
		||||
        writestr += cleanedstr
 | 
			
		||||
        names.update(defs)
 | 
			
		||||
        writestr += expand_sub(newstr[sub[0]:sub[1]], names)
 | 
			
		||||
        oldend =  sub[1]
 | 
			
		||||
    writestr += newstr[oldend:]
 | 
			
		||||
 | 
			
		||||
    return writestr
 | 
			
		||||
 | 
			
		||||
include_src_re = re.compile(r"(\n|\A)\s*include\s*['\"](?P<name>[\w\d./\\]+\.src)['\"]", re.I)
 | 
			
		||||
 | 
			
		||||
def resolve_includes(source):
 | 
			
		||||
    d = os.path.dirname(source)
 | 
			
		||||
    with open(source) as fid:
 | 
			
		||||
        lines = []
 | 
			
		||||
        for line in fid:
 | 
			
		||||
            m = include_src_re.match(line)
 | 
			
		||||
            if m:
 | 
			
		||||
                fn = m.group('name')
 | 
			
		||||
                if not os.path.isabs(fn):
 | 
			
		||||
                    fn = os.path.join(d, fn)
 | 
			
		||||
                if os.path.isfile(fn):
 | 
			
		||||
                    lines.extend(resolve_includes(fn))
 | 
			
		||||
                else:
 | 
			
		||||
                    lines.append(line)
 | 
			
		||||
            else:
 | 
			
		||||
                lines.append(line)
 | 
			
		||||
    return lines
 | 
			
		||||
 | 
			
		||||
def process_file(source):
 | 
			
		||||
    lines = resolve_includes(source)
 | 
			
		||||
    return process_str(''.join(lines))
 | 
			
		||||
 | 
			
		||||
_special_names = find_repl_patterns('''
 | 
			
		||||
<_c=s,d,c,z>
 | 
			
		||||
<_t=real,double precision,complex,double complex>
 | 
			
		||||
<prefix=s,d,c,z>
 | 
			
		||||
<ftype=real,double precision,complex,double complex>
 | 
			
		||||
<ctype=float,double,complex_float,complex_double>
 | 
			
		||||
<ftypereal=real,double precision,\\0,\\1>
 | 
			
		||||
<ctypereal=float,double,\\0,\\1>
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    try:
 | 
			
		||||
        file = sys.argv[1]
 | 
			
		||||
    except IndexError:
 | 
			
		||||
        fid = sys.stdin
 | 
			
		||||
        outfile = sys.stdout
 | 
			
		||||
    else:
 | 
			
		||||
        fid = open(file, 'r')
 | 
			
		||||
        (base, ext) = os.path.splitext(file)
 | 
			
		||||
        newname = base
 | 
			
		||||
        outfile = open(newname, 'w')
 | 
			
		||||
 | 
			
		||||
    allstr = fid.read()
 | 
			
		||||
    writestr = process_str(allstr)
 | 
			
		||||
    outfile.write(writestr)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
		Reference in New Issue
	
	Block a user