#!/usr/bin/env python
# -*- encoding: utf-8 -*-

import crianza
import crianza.compiler
import optparse
import sys

def options():
    opt = optparse.OptionParser("Usage: %prog [option(s)] [file(s])",
            version="%prog " + crianza.__version__)

    opt.add_option("-d", "--dump", dest="dump",
        help="Dump machine code and exit.",
        action="store_true", default=False)

    opt.add_option("-v", "--verbose", dest="verbose",
        help="Enable verbose output.",
        action="store_true", default=False)

    opt.add_option("-x", dest="optimize",
        help="Do not optimize program.",
        action="store_false", default=True)

    opt.add_option("-r", "--repl", dest="repl",
        help="Enter REPL.",
        action="store_true", default=False)

    opt.disable_interspersed_args()
    return opt

def print_code(vm, ops_per_line=10):
    def to_str(op):
        if crianza.compiler.is_embedded_push(op):
            op = crianza.compiler.get_embedded_push_value(op)

        if crianza.isstring(op):
            return repr(op)[1:-1]
        elif callable(op):
            return crianza.lookup(op)
        else:
            return str(op)

    for addr, op in enumerate(vm.code):
        if (addr % ops_per_line) == 0 and (addr+1) < len(vm.code):
            if addr > 0:
                sys.stdout.write("\n")
            sys.stdout.write("%0*d  " % (max(8, len(str(len(vm.code)))), addr))
        sys.stdout.write("%s " % (to_str(op)))
    sys.stdout.write("\n")

def parse_and_run(file, opts):
    code = crianza.compile(
            crianza.parse(file),
            silent=not opts.verbose,
            ignore_errors=False,
            optimize=opts.optimize)

    machine = crianza.Machine(code)

    if not opts.dump:
        machine.run()
    else:
        print_code(machine)

def main():
    def run(file, opts):
        try:
            parse_and_run(file, opts)
        except crianza.MachineError, e:
            print("Runtime error: %s" % e)
            sys.exit(1)
        except crianza.CompileError, e:
            print("Compilation error: %s" % e)
            sys.exit(1)
        except crianza.ParseError, e:
            print("Parser error: %s" % e)
            sys.exit(1)

    opt = options()
    (opts, args) = opt.parse_args()

    if opts.repl:
        crianza.repl()
        sys.exit(0)

    if len(args) == 0:
        opt.print_help()
        sys.exit(1)

    for name in args:
        if name=="-":
            run(sys.stdin, opts)
        else:
            with open(name, "rt") as file:
                run(file, opts)

if __name__ == "__main__":
    try:
        main()
        sys.exit(0)
    except KeyboardInterrupt:
        pass
