"Fossies" - the Fresh Open Source Software Archive

Member "numpy-1.16.4/numpy/distutils/from_template.py" (27 May 2019, 7979 Bytes) of package /linux/misc/numpy-1.16.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "from_template.py" see the Fossies "Dox" file reference documentation.

    1 #!/usr/bin/env 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-separated 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 from __future__ import division, absolute_import, print_function
   49 
   50 __all__ = ['process_str', 'process_file']
   51 
   52 import os
   53 import sys
   54 import re
   55 
   56 routine_start_re = re.compile(r'(\n|\A)((     (\$|\*))|)\s*(subroutine|function)\b', re.I)
   57 routine_end_re = re.compile(r'\n\s*end\s*(subroutine|function)\b.*(\n|\Z)', re.I)
   58 function_start_re = re.compile(r'\n     (\$|\*)\s*function\b', re.I)
   59 
   60 def parse_structure(astr):
   61     """ Return a list of tuples for each function or subroutine each
   62     tuple is the start and end of a subroutine or function to be
   63     expanded.
   64     """
   65 
   66     spanlist = []
   67     ind = 0
   68     while True:
   69         m = routine_start_re.search(astr, ind)
   70         if m is None:
   71             break
   72         start = m.start()
   73         if function_start_re.match(astr, start, m.end()):
   74             while True:
   75                 i = astr.rfind('\n', ind, start)
   76                 if i==-1:
   77                     break
   78                 start = i
   79                 if astr[i:i+7]!='\n     $':
   80                     break
   81         start += 1
   82         m = routine_end_re.search(astr, m.end())
   83         ind = end = m and m.end()-1 or len(astr)
   84         spanlist.append((start, end))
   85     return spanlist
   86 
   87 template_re = re.compile(r"<\s*(\w[\w\d]*)\s*>")
   88 named_re = re.compile(r"<\s*(\w[\w\d]*)\s*=\s*(.*?)\s*>")
   89 list_re = re.compile(r"<\s*((.*?))\s*>")
   90 
   91 def find_repl_patterns(astr):
   92     reps = named_re.findall(astr)
   93     names = {}
   94     for rep in reps:
   95         name = rep[0].strip() or unique_key(names)
   96         repl = rep[1].replace(r'\,', '@comma@')
   97         thelist = conv(repl)
   98         names[name] = thelist
   99     return names
  100 
  101 def find_and_remove_repl_patterns(astr):
  102     names = find_repl_patterns(astr)
  103     astr = re.subn(named_re, '', astr)[0]
  104     return astr, 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 = list(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(r'\>', '@rightarrow@')
  134     substr = substr.replace(r'\<', '@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(r'\,', '@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 r not in rules:
  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 r not in names 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." %
  176                       (base_rule, ','.join(rules[base_rule]), r, thelist))
  177     if not rules:
  178         return substr
  179 
  180     def namerepl(mobj):
  181         name = mobj.group(1)
  182         return rules.get(name, (k+1)*[name])[k]
  183 
  184     newstr = ''
  185     for k in range(numsubs):
  186         newstr += template_re.sub(namerepl, substr) + '\n\n'
  187 
  188     newstr = newstr.replace('@rightarrow@', '>')
  189     newstr = newstr.replace('@leftarrow@', '<')
  190     return newstr
  191 
  192 def process_str(allstr):
  193     newstr = allstr
  194     writestr = ''
  195 
  196     struct = parse_structure(newstr)
  197 
  198     oldend = 0
  199     names = {}
  200     names.update(_special_names)
  201     for sub in struct:
  202         cleanedstr, defs = find_and_remove_repl_patterns(newstr[oldend:sub[0]])
  203         writestr += cleanedstr
  204         names.update(defs)
  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:
  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 def main():
  248     try:
  249         file = sys.argv[1]
  250     except IndexError:
  251         fid = sys.stdin
  252         outfile = sys.stdout
  253     else:
  254         fid = open(file, 'r')
  255         (base, ext) = os.path.splitext(file)
  256         newname = base
  257         outfile = open(newname, 'w')
  258 
  259     allstr = fid.read()
  260     writestr = process_str(allstr)
  261     outfile.write(writestr)
  262 
  263 if __name__ == "__main__":
  264     main()