# Generated from java-escape by ANTLR 4.5
from antlr4 import *
from ArugulaVisitor import ArugulaVisitor
import Arugula
from Arugula import Expression
import copy
from decorator import decorator

class ArugulaCGenerator(ArugulaVisitor):
    """Walks an AST generated by ANTLR and outputs C code."""

    def __init__(self, outFile):
        """
        outFile -- String -- Name of the output file for this pass
        """
        try:
            self.outFile = open(outFile, 'w')
        except IOError as e:
            print('Could not open ' + outFile)

        # Maps identifier names to their types
        # String -> String
        self.ids = {}

        self.tempIdCounter = 0

    def nextTempId(self):
        ret = 'a' + str(self.tempIdCounter)
        self.tempIdCounter += 1
        return ret

    # Visit a parse tree produced by Arugula#prog.
    def visitProg(self, node):
        self.outFile.write('#include <stdio.h>\n')
        self.outFile.write('int main() {\n')
        self.visitChildren(node)
        self.outFile.write('}')
        self.outFile.close()


    # Visit a parse tree produced by Arugula#printExpr.
    def visitPrintExpr(self, node):
        expr = self.visit(node.getChild(0))
        if expr.type() == 'Int':
            tempId = self.nextTempId()
            self.outFile.write('int ' + tempId + ' = ' + expr.text + ';')
            self.outFile.write('printf("%d\\n", ' + tempId + ');')


    # Visit a parse tree produced by Arugula#assign.
    def visitAssign(self, node):
        identifier = node.getChild(1).getText()
        idType = node.getChild(0).getText()
        if idType in Arugula.types:
            self.ids[identifier] = idType
        else:
            raise Exception('Type: ' + idType + ' not recognized.')

        assignedExpr = self.visit(node.getChild(3))
        if idType != assignedExpr.type():
            raise Exception('Cannot assign type ' +
                            assignedExpr.type() +
                            ' to identifier of type ' + idType)
        self.outFile.write('int ' + identifier + ' = ' + assignedExpr.text + ';')

    # Visit a parse tree produced by Arugula#blank.
    def visitBlank(self, node):
        pass

    # Visit a parse tree produced by Arugula#parens.
    def visitParens(self, node):
        expr = self.visit(node.getChild(1))
        return Expression(expr.type(), '(' + expr.text + ')')

    # Visit a parse tree produced by Arugula#MulDiv.
    def visitMulDiv(self, node):
        left = self.visit(node.getChild(0))
        right = self.visit(node.getChild(2))
        operator = node.getChild(1).getText()

        if left.type() != right.type():
            raise Exception('Mismatched type on: ' + operator)

        if operator == '*':
            return Expression(left.type(), left.text + '*' + right.text)
        else:
            return Expression(left.type(), left.text + '/' + right.text)

    # Visit a parse tree produced by Arugula#AddSub.
    def visitAddSub(self, node):
        left = self.visit(node.getChild(0))
        right = self.visit(node.getChild(2))
        operator = node.getChild(1).getText()

        if left.type() != right.type():
            raise Exception('Mismatched type on: ' + operator)

        if operator == '+':
            return Expression(left.type(), left.text + '+' + right.text)
        else:
            return Expression(left.type(), left.text + '-' + right.text)


    # Visit a parse tree produced by Arugula#id.
    def visitId(self, node):
        identifier = node.getText()
        if identifier in self.ids.keys():
            return Expression(self.ids[identifier], identifier)
        raise Exception(node.getText() + ' is not bound or is not in scope.')

    # Visit a parse tree produced by Arugula#int.
    def visitInt(self, node):
        return Expression('Int', node.getText())
