[Numpy-svn] r5074 - trunk/numpy/distutils
numpy-svn at scipy.org
numpy-svn at scipy.org
Wed Apr 23 19:16:55 EDT 2008
Author: charris
Date: 2008-04-23 18:16:53 -0500 (Wed, 23 Apr 2008)
New Revision: 5074
Modified:
trunk/numpy/distutils/conv_template.py
Log:
Add true nesting of loops to the template processing. The previous attempt
wasn't very useful. Loops can now be nested within each other using
/**begin repeat1 and /**end repeat1**/ and cousins, starting with the current
tags for the outermost loops.
Modified: trunk/numpy/distutils/conv_template.py
===================================================================
--- trunk/numpy/distutils/conv_template.py 2008-04-23 20:49:48 UTC (rev 5073)
+++ trunk/numpy/distutils/conv_template.py 2008-04-23 23:16:53 UTC (rev 5074)
@@ -1,39 +1,119 @@
#!/usr/bin/python
+"""
+takes templated file .xxx.src and produces .xxx file where .xxx is
+.i or .c or .h, using the following template rules
-# 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
-# /**begin repeat on a line by itself marks the beginning of a segment of code to be repeated
-# /**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
-# 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**/
-# in the main body, the names are used.
-# Each replace will use one entry from the list of named replacements
+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.
+ 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
-def parse_structure(astr):
+# 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 = []
- # subroutines
- ind = 0
- line = 1
while 1:
- start = astr.find("/**begin repeat", ind)
+ start = astr.find(loopbeg, ind)
if start == -1:
break
start2 = astr.find("*/",start)
start2 = astr.find("\n",start2)
- fini1 = astr.find("/**end repeat**/",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))
@@ -42,18 +122,13 @@
spanlist.sort()
return spanlist
-# return n copies of substr with template replacement
-_special_names = {}
-template_re = re.compile(r"@([\w]+)@")
-named_re = re.compile(r"#\s*([\w]*)\s*=\s*([^#]*)#")
-
-parenrep = re.compile(r"[(]([^)]*?)[)]\*(\d+)")
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 conv(astr):
# replaces all occurrences of '(a,b,c)*4' in astr
@@ -65,115 +140,76 @@
for x in astr.split(',')])
return astr.split(',')
-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 = 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
+named_re = re.compile(r"#\s*([\w]*)\s*=\s*([^#]*)#")
+def parse_loop_header(loophead) :
+ """Find all named replacements in the header
-def expand_sub(substr, namestr, line):
- # find all named replacements in the various loops.
- reps = named_re.findall(namestr)
- nsubs = None
- loops = []
- names = {}
- names.update(_special_names)
+ 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.
+
+ """
+ # parse out the names and lists of values
+ names = []
+ reps = named_re.findall(loophead)
+ nsub = None
for rep in reps:
name = rep[0].strip()
vals = conv(rep[1])
size = len(vals)
- if name == "repeat" :
- names[None] = nsubs
- loops.append(names)
- nsubs = None
- names = {}
- continue
- if nsubs is None :
- nsubs = size
- elif nsubs != size :
+ if nsub is None :
+ nsub = size
+ elif nsub != size :
print name
print vals
raise ValueError, "Mismatch in number to replace"
- names[name] = vals
- names[None] = nsubs
- loops.append(names)
+ names.append((name,vals))
# generate list of dictionaries, one for each template iteration
- def merge(d1,d2) :
- tmp = d1.copy()
- tmp.update(d2)
- return tmp
+ dlist = []
+ for i in range(nsub) :
+ tmp = {}
+ for name,vals in names :
+ tmp[name] = vals[i]
+ dlist.append(tmp)
+ return dlist
- dlist = [{}]
- for d in loops :
- nsubs = d.pop(None)
- tmp = [{} for i in range(nsubs)]
- for name, item in d.items() :
- for i in range(nsubs) :
- tmp[i][name] = item[i]
- dlist = [merge(d1,d2) for d1 in dlist for d2 in tmp]
-
- # now replace all keys for each of the dictionaries
- def namerepl(match):
+replace_re = re.compile(r"@([\w]+)@")
+def parse_string(astr, env, level, line) :
+ # local function for string replacement, uses env
+ def replace(match):
name = match.group(1)
- return d[name]
+ return env[name]
- mystr = []
- header = "#line %d\n"%line
- for d in dlist :
- code = ''.join((header, template_re.sub(namerepl, substr), '\n'))
- mystr.append(code)
+ code = []
+ 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]
+ envlist = parse_loop_header(head)
+ code.append(pref)
+ for newenv in envlist :
+ newenv.update(env)
+ newcode = parse_string(text, newenv, newlevel, newline)
+ code.extend(newcode)
+ code.append(astr[oldend:])
+ else :
+ # replace keys
+ lineno = "#line %d\n" % line
+ newcode = replace_re.sub(replace, astr)
+ code.append(''.join((lineno, newcode , '\n')))
+ return code
- return mystr
-
-
-header =\
-"""
-/*
- *****************************************************************************
- ** This file was autogenerated from a template DO NOT EDIT!!!! **
- ** Changes should be made to the original source (.src) file **
- *****************************************************************************
- */
-
-"""
-
-def get_line_header(str,beg):
- extra = []
- ind = beg - 1
- char = str[ind]
- while (ind > 0) and (char != '\n'):
- extra.insert(0,char)
- ind = ind - 1
- char = str[ind]
- return ''.join(extra)
-
-def process_str(allstr):
+def process_str(astr):
code = [header]
- struct = parse_structure(allstr)
-
- # return a (sorted) list of tuples for each begin repeat section
- # each tuple is the start and end of a region to be template repeated
- oldend = 0
- for sub in struct:
- pref = allstr[oldend:sub[0]]
- head = allstr[sub[0]:sub[1]]
- text = allstr[sub[1]:sub[2]]
- line = sub[4]
- oldend = sub[3]
- code.append(pref)
- code.extend(expand_sub(text,head,line))
- code.append(allstr[oldend:])
+ code.extend(parse_string(astr, global_names, 0, 1))
return ''.join(code)
@@ -203,10 +239,27 @@
def process_file(source):
lines = resolve_includes(source)
sourcefile = os.path.normcase(source).replace("\\","\\\\")
- return ('#line 1 "%s"\n%s'
- % (sourcefile, process_str(''.join(lines))))
+ code = process_str(''.join(lines))
+ 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 = 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
+
+
if __name__ == "__main__":
try:
More information about the Numpy-svn
mailing list