"""Itpl, string interpolation for Python (by Ka-Ping Yee, 20 Oct 1996)"""

import sys, string
from types import StringType
from tokenize import tokenprog

ItplError = "ItplError"
class Itpl:
    def __init__(self, fmt):
        if type(fmt) != StringType:
            raise TypeError, "needs string initializer"

        namechars = 'abcdefghijklmnopqrstuvwxyz' \
            'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_';
        chunks = []
        pos = 0

        try:
            while 1:
                dollar = string.index(fmt, '$', pos)
                nextchar = fmt[dollar+1]

                if nextchar == '{':
                    chunks.append((0, fmt[pos:dollar]))
                    pos, level = dollar+2, 1
                    while level:
                        pos = pos + tokenprog.match(fmt, pos)
                        tstart, tend = tokenprog.regs[3]
                        token = fmt[tstart:tend]
                        if token == '{': level = level+1
                        elif token == '}': level = level-1
                    chunks.append((1, fmt[dollar+2:pos-1]))

                elif nextchar in namechars:
                    chunks.append((0, fmt[pos:dollar]))
                    pos = dollar + 1
                    pos = pos + tokenprog.match(fmt, pos)
                    while pos < len(fmt):
                        if fmt[pos] == '.' and \
                            pos+1 < len(fmt) and fmt[pos+1] in namechars:
                            pos = pos+1 + tokenprog.match(fmt, pos+1)
                        elif fmt[pos] in '([':
                            pos, level = pos+1, 1
                            while level:
                                pos = pos + tokenprog.match(fmt, pos)
                                tstart, tend = tokenprog.regs[3]
                                token = fmt[tstart:tend]
                                if token[0] in '([': level = level+1
                                elif token[0] in ')]': level = level-1
                        else: break
                    chunks.append((1, fmt[dollar+1:pos]))

                else:
                    chunks.append((0, fmt[pos:dollar+1]))
                    pos = dollar + 1 + (nextchar == '$')

        except TypeError:       # token regex did not match, regs[] failed
            import traceback
            traceback.print_exc()
            raise ItplError, "unfinished expression"
        except ValueError:      # index did not find a dollar sign
            pass

        if pos < len(fmt): chunks.append((0, fmt[pos:]))
        self.chunks = chunks

    def __repr__(self, prog=None):
        try: 1/0
        except: frame = sys.exc_traceback.tb_frame

        while frame.f_globals['__name__'] == __name__: frame = frame.f_back
        loc, glob = frame.f_locals, frame.f_globals

        result = []
        for live, chunk in self.chunks:
            if live: result.append(str(eval(chunk, loc, glob)))
            else: result.append(chunk)

        return string.join(result, '')

def printpl(str): print Itpl(str)
def itpl(str): return repr(Itpl(str))

class Itplfile:
    def __init__(self, file): self.file = file
    def __repr__(self): return '<interpolated ' + repr(self.file) + '>'
    def __getattr__(self, attr): return getattr(self.file, attr)
    def write(self, str): self.file.write(repr(Itpl(str)))

def filter(file=sys.stdout): return Itplfile(file)
def unfilter(ifile=None): return ifile and ifile.file or sys.stdout.file
