summaryrefslogtreecommitdiff
path: root/conv_template.py
diff options
context:
space:
mode:
authorcookedm <cookedm@localhost>2006-07-06 16:57:20 +0000
committercookedm <cookedm@localhost>2006-07-06 16:57:20 +0000
commit6782a92fd1a7625ee48f6b2946a7d7149ab28a77 (patch)
tree177a92f0673655b58b247e663477af06ac1192b6 /conv_template.py
parent216f071ab060a6f08c22666aea33f7095f079d1e (diff)
downloadnumpy-6782a92fd1a7625ee48f6b2946a7d7149ab28a77.tar.gz
Branch numpy.distutils to distutils-revamp
Diffstat (limited to 'conv_template.py')
-rw-r--r--conv_template.py208
1 files changed, 208 insertions, 0 deletions
diff --git a/conv_template.py b/conv_template.py
new file mode 100644
index 000000000..37baf47b7
--- /dev/null
+++ b/conv_template.py
@@ -0,0 +1,208 @@
+#!/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
+
+# /**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
+
+# in the main body, the names are used.
+# 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.
+
+__all__ = ['process_str', 'process_file']
+
+import string,os,sys
+if sys.version[:3]>='2.3':
+ import re
+else:
+ import pre as re
+ False = 0
+ True = 1
+
+
+def parse_structure(astr):
+ spanlist = []
+ # subroutines
+ ind = 0
+ line = 1
+ while 1:
+ start = astr.find("/**begin repeat", ind)
+ if start == -1:
+ break
+ start2 = astr.find("*/",start)
+ start2 = astr.find("\n",start2)
+ fini1 = astr.find("/**end repeat**/",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
+
+# return n copies of substr with template replacement
+_special_names = {}
+
+template_re = re.compile(r"@([\w]+)@")
+named_re = re.compile(r"#([\w]*)=([^#]*?)#")
+
+parenrep = re.compile(r"[(]([^)]*?)[)]\*(\d+)")
+def paren_repl(obj):
+ torep = obj.group(1)
+ numrep = obj.group(2)
+ return ','.join([torep]*int(numrep))
+
+plainrep = re.compile(r"([^*]+)\*(\d+)")
+
+def conv(astr):
+ # replaces all occurrences of '(a,b,c)*4' in astr
+ # with 'a,b,c,a,b,c,a,b,c,a,b,c'
+ astr = parenrep.sub(paren_repl,astr)
+ # replaces occurences of xxx*3 with xxx, xxx, xxx
+ astr = ','.join([plainrep.sub(paren_repl,x.strip()) for x in astr.split(',')])
+ return astr
+
+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
+
+def namerepl(match):
+ global _names, _thissub
+ name = match.group(1)
+ return _names[name][_thissub]
+
+def expand_sub(substr, namestr, line):
+ global _names, _thissub
+ # find all named replacements
+ reps = named_re.findall(namestr)
+ _names = {}
+ _names.update(_special_names)
+ numsubs = None
+ for rep in reps:
+ name = rep[0].strip()
+ thelist = conv(rep[1])
+ _names[name] = thelist
+
+ # make lists out of string entries in name dictionary
+ for name in _names.keys():
+ entry = _names[name]
+ entrylist = entry.split(',')
+ _names[name] = entrylist
+ num = len(entrylist)
+ if numsubs is None:
+ numsubs = num
+ elif (numsubs != num):
+ print namestr
+ print substr
+ raise ValueError, "Mismatch in number to replace"
+
+ # now replace all keys for each of the lists
+ mystr = ''
+ for k in range(numsubs):
+ _thissub = k
+ mystr += ("#line %d\n%s\n\n"
+ % (line, template_re.sub(namerepl, substr)))
+ return mystr
+
+
+_head = \
+"""/* 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):
+ newstr = allstr
+ writestr = _head
+
+ struct = parse_structure(newstr)
+ # 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:
+ writestr += newstr[oldend:sub[0]]
+ expanded = expand_sub(newstr[sub[1]:sub[2]],
+ newstr[sub[0]:sub[1]], sub[4])
+ writestr += expanded
+ oldend = sub[3]
+
+
+ writestr += newstr[oldend:]
+ return writestr
+
+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)
+ fid = open(source)
+ lines = []
+ for line in fid.readlines():
+ 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):
+ print 'Including file',fn
+ lines.extend(resolve_includes(fn))
+ else:
+ lines.append(line)
+ else:
+ lines.append(line)
+ fid.close()
+ return lines
+
+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))))
+
+if __name__ == "__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)