#!/usr/local/bin/python
# $Id: loutwr.py,v 1.3 2009/05/18 17:25:09 connolly Exp $
#

import re

BOL='\n'
INDENT='    '
LB = '{'
RB = '}'

spaceDFA = re.compile(r'[ \t\n]+')
nospaceDFA = re.compile(r'[^ \t\n"\\]+')
wordsDFA = re.compile(r'[^/|&{}#@^~\\\"\n\t]+')

class T:
    def __init__(self, target):
	self.t = target
	self.q = 0
	self.bol = 1

    def newline(self):
	if not self.bol:
	    self.t.write("\n")
	    self.bol = 1

    def unq(self):
	if self.q:
	    self.t.write('"')
	    self.q = 0
	    self.bol = 0

    def sym(self, sym):
	"""assumes sym is a lout symbol in the current context"""
	#@# should keep track of whether we just wrote a space or not!
	self.unq()
	if not self.bol: self.t.write(' ')
	self.t.write(sym + ' ')
	self.bol = 0

    def char(self, c):
	self.unq()
	self.t.write(c)
	self.bol = 0

    def do(self, item):
	if item is BOL:
	    self.newline()
	elif item is INDENT:
	    if not self.bol: raise ValueError, 'must be at BOL to indent'
	    self.t.write(INDENT)
	    self.bol = 0
	elif item is LB or item is RB:
	    self.sym(item)
	else:
	    #@# could check that this is a symbol
	    self.sym(item)

    def text(self, txt):
	while len(txt) > 0:
	    if self.q:
                w, txt, self.bol, self.q = qmode(txt)
                self.t.write(w)
	    else:
                m = spaceDFA.match(txt)
                if self.bol and m:
                    txt = txt[m.end(0):]
                else:
                    w, txt, self.bol, self.q = tmode(txt, self.bol)
                    self.t.write(w)


def qmode(txt):
    r"""return what to write, remainin text, bol, q

    >>> qmode("abc")
    ('abc', '', 0, 1)

    >>> qmode("abc def")
    ('abc', ' def', 0, 1)

    >>> qmode("   def")
    ('" ', '   def', 0, 0)

    >>> qmode(" \l")
    ('" ', ' \\l', 0, 0)

    """
    m = nospaceDFA.match(txt)
    if m:
        i = m.end(0)
        return txt[:i], txt[i:], 0, 1
    else:
        m = spaceDFA.match(txt)
        if m:
            i = m.end(0)
            spc = txt[:i]
            if "\n" in spc:
                w = '"\n'
                b = 1
            else:
                w = '" '
                b = 0
            return w, txt, b, 0
        else:
            return '\\' + txt[0], txt[1:], 0, 1


def tmode(txt, b):
    """
    >>> tmode("abc def", 1)
    ('abc def', '', 0, 0)
    """
    m = wordsDFA.match(txt)
    if m:
        i = m.end(0)
        return txt[:i], txt[i:], 0, 0
    elif txt[0] == "\n":
        if b: return "",   txt[1:], 1, 0
        else: return "\n", txt[1:], 1, 0
    elif txt[0] == "\t":
        #@# compress spaces?
        return ' ', txt[1:], 0, 0
    else:
        return '"', txt, 0, 1

def _test():
    import doctest
    doctest.testmod()

if __name__ == '__main__':
    import sys
    if '--test' in sys.argv: _test()
    else:
        l = T(sys.stdout)
        l.text(sys.stdin.read())
