# from __future__ import with_statement #Python 2.5 only

import antlr3
from FairPlayLexer import FairPlayLexer
from FairPlayParser import FairPlayParser
import sys
import FairPlayLexer as L
import FairPlayParser as P
from contextmanager import contextmanager

# import object_descender #For printing out generic python objects

current_indentation = 0 # Global

@contextmanager
def indent(howmuch=4):
    global current_indentation
    try:
        current_indentation += howmuch
        yield
    finally:
        current_indentation -= howmuch


operator_table = {
    "Minus" : "-"  ,
    "Plus" : "+"   ,
    "Times" : "*"  ,
    "Divide" : "/" ,
    "Leq" : "<="   ,
    "Geq" : ">="   ,
    "Eq" : "=="    ,
    "Gt" : ">"    ,
    "Lt" : "<"    ,
    "Neq" : "!="   ,
    }

def type_repr(type):
    child = type.children[0]
    if(child.token.type == L.IntArray):
        return "Bits("+expression_repr(child.children[0])+")"
    else:
        return "["+str(child)+"]NOT SUPPORTED YET"

def print_var(var):
    type = var.children[0]
    for (count, i) in enumerate(var.children[1:]):
        if count%2 == 0:
            print_indented(str(i) + " = " + type_repr(type))


def print_vars(vars):
    with indent(4):
        for i in vars.children:
            print_var(i)

def print_type_def(type):
    print "# A type called: "+str(type.children[0])
    #Make structs as classes?


def print_constant(constant):
    print(str(constant.children[0]) + " = " +
          expression_repr(constant.children[1]))


def param_list_repr(param_list):
    return ", ".join([str(i) for (index, i) in enumerate(param_list.children)
                     if index%2 == 1])


def print_indented(x):
    print " "*current_indentation + x


def expression_repr(expression):
    if(expression.token.type in
       [L.Plus,
        L.Gt,
        L.Eq,
        L.Minus,
        ]):
        return("(" + expression_repr(expression.children[0]) +
               operator_table[str(expression)]
               + expression_repr(expression.children[1]) + ")")
    elif(expression.token.type == L.IDENTIFIER):
        return lvalue_repr(expression)
    elif(expression.token.type == L.INTEGER):
        return str(expression)
    else:
        print P.tokenNames[expression.token.type], expression.token.type
        print str(expression)
        return "ERROR"


def lvalue_repr(lvalue):
    res = str(lvalue)
    for i in lvalue.children:
        if i.token.type == L.Dot:
            res += "." + expression_repr(i.children[0])
        elif i.token.type == L.ArrayIndex:
            res += ("[" + expression_repr(i.children[0])+"]")
        else:
            print "error", lvalue.token.type
    return res


def print_assignment(assignment):
    print_indented(lvalue_repr(assignment.children[0]) + " = " +
                   expression_repr(assignment.children[1]))

def print_for(for_stm):
    print_indented("for " + str(for_stm.children[0]) + " in " +
                   "range(" + expression_repr(for_stm.children[1]) + ", "+
                   expression_repr(for_stm.children[2]) + "):")
    print_statement(for_stm.children[3])

def print_if(if_stm):
    print_indented("if " + expression_repr(if_stm.children[0]) + ":")
    print_statement(if_stm.children[1])
    if(len(if_stm.children) > 2): # else part
       print_indented("else:")
       print_statement(if_stm.children[2])


def print_statement(statement):
    if statement.token.type == L.Block:
        print_body(statement)
    elif statement.token.type == L.Assignment:
        print_assignment(statement)
    elif statement.token.type == L.ForStm: # for
        print_for(statement)
    elif statement.token.type == L.IfStm: # if
        print_if(statement)
    else:
        print_indented(str(statement))


def print_body(body):
    with indent(4):
        for i in body.children:
            print_statement(i)

def print_function(function):
    print "def "+str(function.children[1]) + "(" + param_list_repr(
        function.children[2])+"):"
    print_vars(function.children[4])
    print_body(function.children[5])


def print_program(program):
    print "### Program "+str(program.children[0])
    print "# Converted from a sfdl-program"
    print "import viff.field"
    print "## Global constants:"
    for i in program.children[1].children: #constants
        print_constant(i)
    print "## Global types:"
    for i in program.children[2].children: #Types
        print_type_def(i)
    print "## Global vars:"
    for i in program.children[3].children: #Vars
        print_var(i)
    print
    for i in program.children[4].children: #Functions
        print_function(i)

def main():
    expr = open(sys.argv[1]).read()
    cStream = antlr3.StringStream(expr)
    lexer = FairPlayLexer(cStream)
    tStream = antlr3.CommonTokenStream(lexer)
    parser = FairPlayParser(tStream)
    result = parser.program()

    print_program(result.tree)

#descender = object_descender.ObjectDescender(10)
#descender.descend(result)

if __name__ == "__main__":
    main()

