
import os
if os.environ.has_key('REQUEST_METHOD'):
    # we're running as a CGI script
    import cgitb; cgitb.enable()
    running_as_cgi = True
else:
    running_as_cgi = False            

from parser8 import *

import sys, string
count = 0
def tick():
   global count
   if count > 25: sys.exit(0)
   count += 1


is_global_cache = {}
def is_global(s):
    try: return is_global_cache[s]
    except KeyError:
        is_global_cache[s] = (':' in s) or (s[0] not in string.lowercase)
        return is_global_cache[s]


_m = {}
def evaluate(expr):
    if type(expr) is tuple:
        fn = evaluate(expr[0]); arg = evaluate(expr[1])
        if not (fn is expr[0] and arg is expr[1]): expr = (fn, arg)

    while True:
        for pat, repl in lib:
            _m.clear()
            m = match(pat, expr, _m)
            if not (m is None): expr = substitute(repl, m); break
        else:
            return expr
            

def substitute(expr, m):
    if expr in m: return m[expr]
    elif type(expr) is tuple: 
        fn = substitute(expr[0], m); arg = substitute(expr[1], m)
        if not (fn is expr[0] and arg is expr[1]): expr = (fn, arg)
    return expr


def match(pattern, value, m):
    if type(pattern) is str:
        if is_global(pattern):
            if pattern == value: return m
            else: return None
        else:
            m[pattern] = value
            return m
    else:
        #assert type(pattern) is tuple and len(pattern) == 2, \
        #       "Not a pattern: %r" % pattern
        if type(value) is str: return None
        m = match(pattern[0], value[0], m)
        if not (m is None): m = match(pattern[0], value[0], m)
        return m



#data = eval(open('data6.txt').read())
#lib = [('exp:data', fromPython(data))]
lib = []


for (eq, ((cons1, pat), ((cons2, repl), nil))) \
        in parse_file(open('lib8.toy').read()):
    assert (eq, cons1, cons2, nil) == ('=', 'lc:cons', 'lc:cons', 'c:nil')
    lib.append((pat, repl))
    
    
if len(sys.argv) > 1 and sys.argv[1]:
    code = open(sys.argv[1]).read()
else:
    code = ''' "Hello, world!" '''
    
parsed = parse_item(PushbackIterator(code))


#assert parsed[0] in ('hx:page', 'hx:update')
#assert parsed[1][0] == 'c:list'
#
#global_params = {}
#for li, name, default in parsed[1][1:]:
#    assert li == 'c:list'
#    global_params[name.s] = default.s


#if running_as_cgi:
#    import cgi
#    fields = cgi.FieldStorage()
#    for key in global_params:
#        global_params[key] = fields.getfirst(key, global_params[key])
#else:
#    for i in range(2, len(sys.argv), 2):
#        assert sys.argv[i][0] == '-'
#        name = sys.argv[i][1:]
#        assert sys.argv[i+1][0] != '-'
#        val = sys.argv[i+1]
#        global_params[name] = val

#for k in global_params: global_params[k] = [ch for ch in global_params[k]]


#newdata, page = toPython(evaluate(parsed, global_params))

#print "Content-type: text/html\r\n\r\n",
#print page

def toPython(expr):
    if expr == 'c:nil': return []
    elif expr in ('Z', 'O'): return 0
    elif expr == 'I': return 1
    elif type(expr) != tuple: assert False, "cannot convert: %r" % expr
    
    fn = expr[0]
    if type(fn) is tuple:
        assert fn[0] == 'lc:cons', "cannot convert: %r" % (expr,)
        return [toPython(fn[1])] + toPython(expr[1])
    
    args = toPython(expr[1])
    if fn == 'c:str':
        assert len(args) == 1
        return ''.join([chr(i) for i in args[0]])
    elif fn == '&':
        rest, bit = args
        return 2*rest + bit
    
    assert False, "cannot convert: %r" % (expr,)

print "parsed"
print toPython(evaluate(parsed))

#if newdata != data:
#    if (not running_as_cgi) or os.environ['REQUEST_METHOD'] == 'POST':
#        out = repr(newdata)
#        open('data6.txt', 'w').write(out)
#    else:
#        print "<hr>\n\n<h1>New data:</h1>\n\n<p>%r</p>" % newdata
