done
This commit is contained in:
		
							
								
								
									
										329
									
								
								lib/python3.11/site-packages/numpy/distutils/conv_template.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								lib/python3.11/site-packages/numpy/distutils/conv_template.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,329 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
"""
 | 
			
		||||
takes templated file .xxx.src and produces .xxx file  where .xxx is
 | 
			
		||||
.i or .c or .h, using the following template rules
 | 
			
		||||
 | 
			
		||||
/**begin repeat  -- on a line by itself marks the start of a repeated code
 | 
			
		||||
                    segment
 | 
			
		||||
/**end repeat**/ -- on a line by itself marks it's end
 | 
			
		||||
 | 
			
		||||
After the /**begin repeat and before the */, all the named templates are placed
 | 
			
		||||
these should all have the same number of replacements
 | 
			
		||||
 | 
			
		||||
Repeat blocks can be nested, with each nested block labeled with its depth,
 | 
			
		||||
i.e.
 | 
			
		||||
/**begin repeat1
 | 
			
		||||
 *....
 | 
			
		||||
 */
 | 
			
		||||
/**end repeat1**/
 | 
			
		||||
 | 
			
		||||
When using nested loops, you can optionally exclude particular
 | 
			
		||||
combinations of the variables using (inside the comment portion of the inner loop):
 | 
			
		||||
 | 
			
		||||
 :exclude: var1=value1, var2=value2, ...
 | 
			
		||||
 | 
			
		||||
This will exclude the pattern where var1 is value1 and var2 is value2 when
 | 
			
		||||
the result is being generated.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
In the main body each replace will use one entry from the list of named replacements
 | 
			
		||||
 | 
			
		||||
 Note that all #..# forms in a block must have the same number of
 | 
			
		||||
   comma-separated entries.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
    An input file containing
 | 
			
		||||
 | 
			
		||||
        /**begin repeat
 | 
			
		||||
         * #a = 1,2,3#
 | 
			
		||||
         * #b = 1,2,3#
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        /**begin repeat1
 | 
			
		||||
         * #c = ted, jim#
 | 
			
		||||
         */
 | 
			
		||||
        @a@, @b@, @c@
 | 
			
		||||
        /**end repeat1**/
 | 
			
		||||
 | 
			
		||||
        /**end repeat**/
 | 
			
		||||
 | 
			
		||||
    produces
 | 
			
		||||
 | 
			
		||||
        line 1 "template.c.src"
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         *********************************************************************
 | 
			
		||||
         **       This file was autogenerated from a template  DO NOT EDIT!!**
 | 
			
		||||
         **       Changes should be made to the original source (.src) file **
 | 
			
		||||
         *********************************************************************
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        #line 9
 | 
			
		||||
        1, 1, ted
 | 
			
		||||
 | 
			
		||||
        #line 9
 | 
			
		||||
        1, 1, jim
 | 
			
		||||
 | 
			
		||||
        #line 9
 | 
			
		||||
        2, 2, ted
 | 
			
		||||
 | 
			
		||||
        #line 9
 | 
			
		||||
        2, 2, jim
 | 
			
		||||
 | 
			
		||||
        #line 9
 | 
			
		||||
        3, 3, ted
 | 
			
		||||
 | 
			
		||||
        #line 9
 | 
			
		||||
        3, 3, jim
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
__all__ = ['process_str', 'process_file']
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
# names for replacement that are already global.
 | 
			
		||||
global_names = {}
 | 
			
		||||
 | 
			
		||||
# header placed at the front of head processed file
 | 
			
		||||
header =\
 | 
			
		||||
"""
 | 
			
		||||
/*
 | 
			
		||||
 *****************************************************************************
 | 
			
		||||
 **       This file was autogenerated from a template  DO NOT EDIT!!!!      **
 | 
			
		||||
 **       Changes should be made to the original source (.src) file         **
 | 
			
		||||
 *****************************************************************************
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
# Parse string for repeat loops
 | 
			
		||||
def parse_structure(astr, level):
 | 
			
		||||
    """
 | 
			
		||||
    The returned line number is from the beginning of the string, starting
 | 
			
		||||
    at zero. Returns an empty list if no loops found.
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    if level == 0 :
 | 
			
		||||
        loopbeg = "/**begin repeat"
 | 
			
		||||
        loopend = "/**end repeat**/"
 | 
			
		||||
    else :
 | 
			
		||||
        loopbeg = "/**begin repeat%d" % level
 | 
			
		||||
        loopend = "/**end repeat%d**/" % level
 | 
			
		||||
 | 
			
		||||
    ind = 0
 | 
			
		||||
    line = 0
 | 
			
		||||
    spanlist = []
 | 
			
		||||
    while True:
 | 
			
		||||
        start = astr.find(loopbeg, ind)
 | 
			
		||||
        if start == -1:
 | 
			
		||||
            break
 | 
			
		||||
        start2 = astr.find("*/", start)
 | 
			
		||||
        start2 = astr.find("\n", start2)
 | 
			
		||||
        fini1 = astr.find(loopend, start2)
 | 
			
		||||
        fini2 = astr.find("\n", fini1)
 | 
			
		||||
        line += astr.count("\n", ind, start2+1)
 | 
			
		||||
        spanlist.append((start, start2+1, fini1, fini2+1, line))
 | 
			
		||||
        line += astr.count("\n", start2+1, fini2)
 | 
			
		||||
        ind = fini2
 | 
			
		||||
    spanlist.sort()
 | 
			
		||||
    return spanlist
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def paren_repl(obj):
 | 
			
		||||
    torep = obj.group(1)
 | 
			
		||||
    numrep = obj.group(2)
 | 
			
		||||
    return ','.join([torep]*int(numrep))
 | 
			
		||||
 | 
			
		||||
parenrep = re.compile(r"\(([^)]*)\)\*(\d+)")
 | 
			
		||||
plainrep = re.compile(r"([^*]+)\*(\d+)")
 | 
			
		||||
def parse_values(astr):
 | 
			
		||||
    # replaces all occurrences of '(a,b,c)*4' in astr
 | 
			
		||||
    # with 'a,b,c,a,b,c,a,b,c,a,b,c'. Empty braces generate
 | 
			
		||||
    # empty values, i.e., ()*4 yields ',,,'. The result is
 | 
			
		||||
    # split at ',' and a list of values returned.
 | 
			
		||||
    astr = parenrep.sub(paren_repl, astr)
 | 
			
		||||
    # replaces occurrences of xxx*3 with xxx, xxx, xxx
 | 
			
		||||
    astr = ','.join([plainrep.sub(paren_repl, x.strip())
 | 
			
		||||
                     for x in astr.split(',')])
 | 
			
		||||
    return astr.split(',')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
stripast = re.compile(r"\n\s*\*?")
 | 
			
		||||
named_re = re.compile(r"#\s*(\w*)\s*=([^#]*)#")
 | 
			
		||||
exclude_vars_re = re.compile(r"(\w*)=(\w*)")
 | 
			
		||||
exclude_re = re.compile(":exclude:")
 | 
			
		||||
def parse_loop_header(loophead) :
 | 
			
		||||
    """Find all named replacements in the header
 | 
			
		||||
 | 
			
		||||
    Returns a list of dictionaries, one for each loop iteration,
 | 
			
		||||
    where each key is a name to be substituted and the corresponding
 | 
			
		||||
    value is the replacement string.
 | 
			
		||||
 | 
			
		||||
    Also return a list of exclusions.  The exclusions are dictionaries
 | 
			
		||||
     of key value pairs. There can be more than one exclusion.
 | 
			
		||||
     [{'var1':'value1', 'var2', 'value2'[,...]}, ...]
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    # Strip out '\n' and leading '*', if any, in continuation lines.
 | 
			
		||||
    # This should not effect code previous to this change as
 | 
			
		||||
    # continuation lines were not allowed.
 | 
			
		||||
    loophead = stripast.sub("", loophead)
 | 
			
		||||
    # parse out the names and lists of values
 | 
			
		||||
    names = []
 | 
			
		||||
    reps = named_re.findall(loophead)
 | 
			
		||||
    nsub = None
 | 
			
		||||
    for rep in reps:
 | 
			
		||||
        name = rep[0]
 | 
			
		||||
        vals = parse_values(rep[1])
 | 
			
		||||
        size = len(vals)
 | 
			
		||||
        if nsub is None :
 | 
			
		||||
            nsub = size
 | 
			
		||||
        elif nsub != size :
 | 
			
		||||
            msg = "Mismatch in number of values, %d != %d\n%s = %s"
 | 
			
		||||
            raise ValueError(msg % (nsub, size, name, vals))
 | 
			
		||||
        names.append((name, vals))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # Find any exclude variables
 | 
			
		||||
    excludes = []
 | 
			
		||||
 | 
			
		||||
    for obj in exclude_re.finditer(loophead):
 | 
			
		||||
        span = obj.span()
 | 
			
		||||
        # find next newline
 | 
			
		||||
        endline = loophead.find('\n', span[1])
 | 
			
		||||
        substr = loophead[span[1]:endline]
 | 
			
		||||
        ex_names = exclude_vars_re.findall(substr)
 | 
			
		||||
        excludes.append(dict(ex_names))
 | 
			
		||||
 | 
			
		||||
    # generate list of dictionaries, one for each template iteration
 | 
			
		||||
    dlist = []
 | 
			
		||||
    if nsub is None :
 | 
			
		||||
        raise ValueError("No substitution variables found")
 | 
			
		||||
    for i in range(nsub):
 | 
			
		||||
        tmp = {name: vals[i] for name, vals in names}
 | 
			
		||||
        dlist.append(tmp)
 | 
			
		||||
    return dlist
 | 
			
		||||
 | 
			
		||||
replace_re = re.compile(r"@(\w+)@")
 | 
			
		||||
def parse_string(astr, env, level, line) :
 | 
			
		||||
    lineno = "#line %d\n" % line
 | 
			
		||||
 | 
			
		||||
    # local function for string replacement, uses env
 | 
			
		||||
    def replace(match):
 | 
			
		||||
        name = match.group(1)
 | 
			
		||||
        try :
 | 
			
		||||
            val = env[name]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            msg = 'line %d: no definition of key "%s"'%(line, name)
 | 
			
		||||
            raise ValueError(msg) from None
 | 
			
		||||
        return val
 | 
			
		||||
 | 
			
		||||
    code = [lineno]
 | 
			
		||||
    struct = parse_structure(astr, level)
 | 
			
		||||
    if struct :
 | 
			
		||||
        # recurse over inner loops
 | 
			
		||||
        oldend = 0
 | 
			
		||||
        newlevel = level + 1
 | 
			
		||||
        for sub in struct:
 | 
			
		||||
            pref = astr[oldend:sub[0]]
 | 
			
		||||
            head = astr[sub[0]:sub[1]]
 | 
			
		||||
            text = astr[sub[1]:sub[2]]
 | 
			
		||||
            oldend = sub[3]
 | 
			
		||||
            newline = line + sub[4]
 | 
			
		||||
            code.append(replace_re.sub(replace, pref))
 | 
			
		||||
            try :
 | 
			
		||||
                envlist = parse_loop_header(head)
 | 
			
		||||
            except ValueError as e:
 | 
			
		||||
                msg = "line %d: %s" % (newline, e)
 | 
			
		||||
                raise ValueError(msg)
 | 
			
		||||
            for newenv in envlist :
 | 
			
		||||
                newenv.update(env)
 | 
			
		||||
                newcode = parse_string(text, newenv, newlevel, newline)
 | 
			
		||||
                code.extend(newcode)
 | 
			
		||||
        suff = astr[oldend:]
 | 
			
		||||
        code.append(replace_re.sub(replace, suff))
 | 
			
		||||
    else :
 | 
			
		||||
        # replace keys
 | 
			
		||||
        code.append(replace_re.sub(replace, astr))
 | 
			
		||||
    code.append('\n')
 | 
			
		||||
    return ''.join(code)
 | 
			
		||||
 | 
			
		||||
def process_str(astr):
 | 
			
		||||
    code = [header]
 | 
			
		||||
    code.extend(parse_string(astr, global_names, 0, 1))
 | 
			
		||||
    return ''.join(code)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
include_src_re = re.compile(r"(\n|\A)#include\s*['\"]"
 | 
			
		||||
                            r"(?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)
 | 
			
		||||
    sourcefile = os.path.normcase(source).replace("\\", "\\\\")
 | 
			
		||||
    try:
 | 
			
		||||
        code = process_str(''.join(lines))
 | 
			
		||||
    except ValueError as e:
 | 
			
		||||
        raise ValueError('In "%s" loop at %s' % (sourcefile, e)) from None
 | 
			
		||||
    return '#line 1 "%s"\n%s' % (sourcefile, code)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def unique_key(adict):
 | 
			
		||||
    # this obtains a unique key given a dictionary
 | 
			
		||||
    # currently it works by appending together n of the letters of the
 | 
			
		||||
    #   current keys and increasing n until a unique key is found
 | 
			
		||||
    # -- not particularly quick
 | 
			
		||||
    allkeys = list(adict.keys())
 | 
			
		||||
    done = False
 | 
			
		||||
    n = 1
 | 
			
		||||
    while not done:
 | 
			
		||||
        newkey = "".join([x[:n] for x in allkeys])
 | 
			
		||||
        if newkey in allkeys:
 | 
			
		||||
            n += 1
 | 
			
		||||
        else:
 | 
			
		||||
            done = True
 | 
			
		||||
    return newkey
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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()
 | 
			
		||||
    try:
 | 
			
		||||
        writestr = process_str(allstr)
 | 
			
		||||
    except ValueError as e:
 | 
			
		||||
        raise ValueError("In %s loop at %s" % (file, e)) from None
 | 
			
		||||
 | 
			
		||||
    outfile.write(writestr)
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
		Reference in New Issue
	
	Block a user