#!/usr/bin/env python

"""
A simple lolcode interpreter.

Author: Steve Losh (still.life@gmail.com)
"""

import sys
import traceback
from sjlol_func import evaluate, global_symbols
from sjlol_parser import parse
from optparse import OptionParser

VERSION = "1.1"
LOLCODE_VERSION = "1.0"

def _makeCommandlineParser():
    p = OptionParser("usage: %prog [options] [source.lol]\n\n"+
                     "If no source file is given the program will work in "+
                     "interactive mode.")
    p.add_option("-t", "--tree",
                 dest="tree", action="store_true", default=False,
                 help="output the parse tree.")
    p.add_option("-d", "--debug",
                 dest="debug", action="store_true", default=False,
                 help="output more debugging information on a crash")
    p.add_option("-v", "--version",
                 dest="version", action="store_true", default=False,
                 help="output the version information and exit")
    return p


def _parse_and_evaluate(s, options):
    """This parses and evaluates the given code."""
    parse_tree = parse(s)
    
    if options.tree:
        print "Parse Tree:\n", 80*'-'
        def printNode(node, indent):
            if type(node) == list:
                for n in node:
                    printNode(n, indent)
            else:
                print indent*'   ', node[0].__name__
                for parameter in node[1:]:
                    if type(parameter) == list or type(parameter) == tuple:
                        printNode(parameter, indent + 1)
                    else:
                        print (indent + 1) * '   ', parameter
        printNode(parse_tree, 0)
        print 80*'-'
    
    evaluate(parse_tree)


def _print_version():
    print "sjlol version: %s" % VERSION
    print "built for lolcode version: %s" % LOLCODE_VERSION


def _main():
    p = _makeCommandlineParser()
    (options, args) = p.parse_args()
    
    s = ''
    
    if options.version:
        _print_version()
        return
    
    if (len(args) == 1):
        s = ''.join(open(args[0]))
        try:
            _parse_and_evaluate(s, options)
        except Exception, e:
            if options.debug:
                traceback.print_exc()
            else:
                print "An error occurred:", e.__class__.__name__
    else:
        _print_version()
        print "Use LOAD <source.lol> to run a source file, or type in a program.\n"
        while True:
            try:
                i = raw_input("lol> ")
                s = s + i + "\n"
                
                # LOAD filename.lol will load in and parse a source file.
                # Otherwise the input should be a program block.
                if i.strip().startswith("LOAD"):
                    input_file = open(i.split()[1])
                    s = "\n".join(input_file.readlines())
                    input_file.close()
                elif "HAI" in i and "KTHXBYE" not in i:
                    while True:
                        i = raw_input("...> ")
                        s = s + i + "\n"
                        if "KTHXBYE" in i:
                            break
                try:
                    _parse_and_evaluate(s, options)
                except Exception, e:
                    if options.debug:
                        traceback.print_exc()
                    else:
                        print "An error occurred:", e.__class__.__name__
                
                # We need to reset the symbol table after each program block
                # so that variables don't carry over between blocks.
                global_symbols.reset()
                s = ''
            except EOFError:
                sys.exit()


if __name__ == "__main__":
    _main()

# eof