Convert function.pl into C++ (well, almost) source and header.
[ginac.git] / scripts / yaptu.py
1 #!/usr/bin/env python
2 """
3 Yet Another Python Templating Utility, Version 1.2, by Alex Martelli.
4 Distributed under PSF license (http://docs.python.org/license.html).
5 """
6
7 import re
8 import sys
9
10 # utility stuff to avoid tests in the mainline code
11 class _nevermatch:
12     "Polymorphic with a regex that never matches"
13     def match(self, line):
14         return None
15 _never = _nevermatch()     # one reusable instance of it suffices
16 def identity(string, why):
17     "A do-nothing-special-to-the-input, just-return-it function"
18     return string
19 def nohandle(string):
20     "A do-nothing handler that just re-raises the exception"
21     raise
22
23 _default_rex = re.compile('@([^@]+)@')
24 _default_rbe = re.compile('\+\+\+')
25 _default_ren = re.compile('---')
26 _default_rco = re.compile('===')
27
28 # and now the real thing
29 class copier:
30     "Smart-copier (YAPTU) class"
31     def copyblock(self, i=0, last=None):
32         "Main copy method: process lines [i,last) of block"
33         def repl(match, self=self):
34             "return the eval of a found expression, for replacement"
35             # uncomment for debug:
36             # print '!!! replacing',match.group(1)
37             expr = self.preproc(match.group(1), 'eval')
38             try: return str(eval(expr, self.globals, self.locals))
39             except: return str(self.handle(expr))
40         block = self.locals['_bl']
41         if last is None: last = len(block)
42         while i<last:
43             line = block[i]
44             match = self.restat.match(line)
45             if match:   # a statement starts "here" (at line block[i])
46                 # i is the last line to _not_ process
47                 stat = match.string[match.end(0):].strip()
48                 j=i+1   # look for 'finish' from here onwards
49                 nest=1  # count nesting levels of statements
50                 while j<last:
51                     line = block[j]
52                     # first look for nested statements or 'finish' lines
53                     if self.restend.match(line):    # found a statement-end
54                         nest = nest - 1     # update (decrease) nesting
55                         if nest==0: break   # j is first line to _not_ process
56                     elif self.restat.match(line):   # found a nested statement
57                         nest = nest + 1     # update (increase) nesting
58                     elif nest==1:   # look for continuation only at this nesting
59                         match = self.recont.match(line)
60                         if match:                   # found a contin.-statement
61                             nestat = match.string[match.end(0):].strip()
62                             stat = '%s _cb(%s,%s)\n%s' % (stat,i+1,j,nestat)
63                             i=j     # again, i is the last line to _not_ process
64                     j=j+1
65                 stat = self.preproc(stat, 'exec')
66                 stat = '%s _cb(%s,%s)' % (stat,i+1,j)
67                 # for debugging, uncomment...:
68                 # print "-> Executing: {"+stat+"}"
69                 exec stat in self.globals,self.locals
70                 i=j+1
71             else:       # normal line, just copy with substitution
72                 self.ouf.write(self.regex.sub(repl,line))
73                 i=i+1
74     def __init__(self, dict={}, regex=_default_rex,
75             restat=_default_rbe, restend=_default_ren, recont=_default_rco,
76             preproc=identity, handle=nohandle, ouf=sys.stdout):
77         "Initialize self's attributes"
78         self.regex   = regex
79         self.globals = dict
80         self.locals  = { '_cb':self.copyblock }
81         self.restat  = restat
82         self.restend = restend
83         self.recont  = recont
84         self.preproc = preproc
85         self.handle  = handle
86         self.ouf     = ouf
87     def copy(self, inf=sys.stdin, block=None):
88         "Entry point: copy-with-processing a file, or a block of lines"
89         if block is None: block = inf.readlines()
90         self.locals['_bl'] = block
91         self.copyblock()
92
93