def visitSimpleVarSpec(self, simpleVarSpec):
        #print('visitSimpleVarSpec')
        variavel = simpleVarSpec.IdentifierList.accept(self)
        tipo = simpleVarSpec.ExpressionList.accept(self)

        if (type(tipo) is not list):
            tipo = [tipo]
        if (len(variavel) != len(tipo)):
            simpleVarSpec.accept(self.printer)
            print('\n\t[Erro]:', len(variavel), 'variaveis mas', len(tipo),
                  'valores')
        else:
            for x in range(len(variavel)):
                if (st.getBindable(variavel[x]) == None):
                    if (tipo[x] not in st.TiposPrimitivos):
                        tipoAux = st.getBindable(tipo[x])
                        if (tipoAux == None):
                            simpleVarSpec.accept(self.printer)
                            print('\n\t[ERRO]: Atribuicao nao compativel')
                        else:
                            st.addVar(variavel[x], tipoAux[st.TYPE])
                    else:
                        st.addVar(variavel[x], tipo[x])
                else:
                    simpleVarSpec.accept(self.printer)
                    print('\n\t[Erro]:', variavel[x], 'redefinida neste bloco')
    def visitExpressionDiferente(self, expressionDiferente):
        #print('visitExpressionDiferente')
        tipoExp1 = expressionDiferente.Expr2.accept(self)
        tipoExp2 = expressionDiferente.Expr3.accept(self)

        tipoExp1 = st.getNewType(tipoExp1)
        tipoExp2 = st.getNewType(tipoExp2)

        if (tipoExp1 not in st.TiposPrimitivos):
            tipoExp1 = st.getBindable(tipoExp1)
            if (tipoExp1 != None):
                tipoExp1 = tipoExp1[st.TYPE]

        if (tipoExp2 not in st.TiposPrimitivos):
            tipoExp2 = st.getBindable(tipoExp1)
            if (tipoExp2 != None):
                tipoExp2 = tipoExp2[st.TYPE]

        c = coercion(tipoExp1, tipoExp2)
        if (c == None):
            expressionDiferente.accept(self.printer)
            print('\n\t[Erro]: Comparação invalida. A expressao ', end='')
            expressionDiferente.Expr2.accept(self.printer)
            print(' eh do tipo', tipoExp1, 'enquanto a expressao ', end='')
            expressionDiferente.Expr3.accept(self.printer)
            print(' eh do tipo', tipoExp2,
                  'quando deveriam ser do mesmo tipo\n')
        return c
    def visitListTypeExp(self, listTypeExp):
        #print('visitListTypeExp')
        variaveis = listTypeExp.IdentifierList.accept(self)
        tipo = st.getNewType(listTypeExp.Type)

        for indice in range(len(variaveis)):
            if (st.getBindable(variaveis[indice]) == None):
                st.addVar(variaveis[indice], tipo)
            else:
                listTypeExp.accept(self.printer)
                print('\n\t[ERRO]:', variaveis[indice],
                      'redefinida neste bloco')

        expressao = listTypeExp.ExpressionList.accept(self)

        if (type(expressao) is not list):
            if (expressao in st.TiposPrimitivos and expressao != tipo):
                listTypeExp.accept(self.printer)
                print(
                    '\n\t[ERRO]: Atribuicao nao compativel com o tipo declarado'
                )
            elif (expressao != tipo):
                expressao = st.getBindable(expressao)
                if (None == expressao or expressao[st.TYPE] != tipo):
                    listTypeExp.accept(self.printer)
                    print(
                        '\n\t[ERRO]: Atribuicao nao compativel com o tipo declarado'
                    )
        else:
            for ind in range(len(expressao)):
                if (expressao[ind] != tipo):
                    listTypeExp.accept(self.printer)
                    print('\n\t[ERRO]: Atribuicao nao compativel')
                    break
    def visitListIdExp(self, listIdExp):
        #print('visitListIdExp')
        idList = listIdExp.IdentifierList.accept(self)
        expList = listIdExp.ExpressionList.accept(self)

        if (type(expList) is not list):
            expList = [expList]

        if (len(idList) != len(expList)):
            listIdExp.accept(self.printer)
            print('[Erro]: ', len(idList), 'constantes mas', len(expList),
                  'valores')
        else:
            for i in range(len(idList)):
                if (st.getBindable(idList[i]) == None):
                    if (expList[i] not in st.TiposPrimitivos):
                        expAux = st.getBindable(expList[i])
                        if (expAux == None):
                            listIdExp.accept(self.printer)
                            print('\n\t[ERRO]: Atribuicao nao compativel')
                        else:
                            st.addVar(idList[i], expList[st.TYPE])
                            st.symbolTable[-1][idList[i]][st.CONST] = 'const'
                    else:
                        st.addVar(idList[i], expList[i])
                        st.symbolTable[-1][idList[i]][st.CONST] = 'const'
                else:
                    listIdExp.accept(self.printer)
                    print('\n\t[Erro]:', idList[i], 'redefinida neste bloco')
    def visitClassicVarSpec(self, classicVarSpec):
        #print('visitClassicVarSpec')
        variaveis = classicVarSpec.IdentifierList.accept(self)
        tipo = classicVarSpec.Type

        tipo = st.getNewType(tipo)
        if (tipo == None):
            classicVarSpec.accept(self.printer)
            print('\n\t[ERRO] Tipo indefinido')

        for k in range(len(variaveis)):
            if (st.getBindable(variaveis[k]) == None):
                st.addVar(variaveis[k], tipo)
            else:
                classicVarSpec.accept(self.printer)
                print('\n\t[Erro]:', variaveis[k], 'redefinida neste bloco')

        expressao = classicVarSpec.ExpressionList.accept(self)

        if (type(expressao) != type([])):
            if (expressao != tipo):
                classicVarSpec.accept(self.printer)
                print(
                    '\n\t[Erro]: Atribuicao nao compativel com o tipo declarado'
                )
        else:
            for i in range(len(expressao)):
                if (expressao[i] != tipo):
                    classicVarSpec.accept(self.printer)
                    print(
                        '\n\t[Erro]: Atribuicao nao compativel com o tipo declarado'
                    )
                    break
    def visitAssignOp(self, assignOp):
        #print('visitAssignOp')
        listaExp = assignOp.ExpressionList.accept(self)  # lado esquerdo

        listaExp1 = assignOp.ExpressionList1.accept(self)  # lado direito

        if (listaExp not in st.TiposPrimitivos):
            bindable = st.getBindable(listaExp)
            if (st.CONST in bindable):
                assignOp.accept(self.printer)
                print('\n\t[Erro]: Atribuicao invalida de constante')
        if (listaExp1 not in st.TiposPrimitivos):
            bindable = st.getBindable(listaExp1)
            if (bindable != None):
                if (st.TYPE in bindable):
                    listaExp1 = bindable[st.TYPE]
                if (listaExp != listaExp1):
                    assignOp.accept(self.printer)
                    print('\n\t[Erro]: Tipo de atribuicao invalida')
            else:
                assignOp.accept(self.printer)
                print('\n\t[Erro]: Erro de atribuicao')
    def visitExpReturn(self, expReturn):
        #print('visitExpReturn')
        tipoExp = expReturn.ExpressionList.accept(self)

        if (tipoExp not in st.TiposPrimitivos and tipoExp != None):
            tipoExp = st.getBindable(tipoExp)
            if (tipoExp != None):
                tipoExp = tipoExp[st.TYPE]

        # Volta ao escopo que tem o tipo de retorno.
        for indice in reversed(range(len(st.symbolTable))):
            scope = st.symbolTable[indice][st.SCOPE]
            bindable = st.getBindable(scope)
            if (bindable != None):
                break

        if (tipoExp != bindable[st.TYPE]):
            expReturn.accept(self.printer)
            print('\n\t[Erro]: O retorno da funcao',
                  scope,
                  'eh do tipo',
                  bindable[st.TYPE],
                  end='')
            print(' no entanto, o retorno passado foi do tipo', tipoExp, '\n')
 def visitPrintNumberID(self, printNumberID):
     #print('visitPrintNumberID')
     if (isinstance(printNumberID.numberOrId, int)):
         return st.INT
     elif (printNumberID.numberOrId == 'true'
           or printNumberID.numberOrId == 'false'):
         return st.BOOL
     elif (printNumberID.numberOrId[0] == '\"'):
         return st.STRING
     else:
         idName = st.getBindable(printNumberID.numberOrId)
         if (idName != None):
             if (st.CONST in idName):
                 return printNumberID.numberOrId
             return idName[st.TYPE]
         return printNumberID.numberOrId
    def visitSimpleCallFunc(self, simpleCallFunc):
        #print('visitSimpleCallFunc')
        idFunc = simpleCallFunc.ID
        bindable = st.getBindable(idFunc)
        params = []
        for i in range(1, len(bindable[st.PARAMS]), 2):
            params.append(bindable[st.PARAMS][i])

        paramsCall = simpleCallFunc.ExpressionList.accept(self)

        if (type(paramsCall) is not list):
            paramsCall = [paramsCall]

        if (params != paramsCall):
            simpleCallFunc.accept(self.printer)
            print('\n\t[Erro]: Parametros incompativeis')

        return bindable[st.TYPE]
 def visitCallParenFunc(self, callParenFunc):
     #print('visitCallParenFunc')
     idFunc = callParenFunc.ID
     bindable = st.getBindable(idFunc)
     return bindable[st.TYPE]