"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TradutorJavaScript = void 0;
const construtos_1 = require("../construtos");
const declaracoes_1 = require("../declaracoes");
const delegua_1 = __importDefault(require("../tipos-de-simbolos/delegua"));
/**
 * Esse tradutor traduz para JavaScript sem módulos, o que significa que
 * instruções em Delégua como `leia()` e `importar()` não são suportadas.
 * O tradutor levantará mensagem de alerta toda vez que essas instruções são encontradas.
 */
class TradutorJavaScript {
    constructor() {
        this.indentacao = 0;
        this.dicionarioConstrutos = {
            AcessoIndiceVariavel: this.traduzirExpressaoAcessoIndiceVariavel.bind(this),
            AcessoMetodo: this.traduzirExpressaoAcessoMetodo.bind(this),
            AcessoMetodoOuPropriedade: this.traduzirExpressaoAcessoMetodoOuPropriedade.bind(this),
            AcessoPropriedade: this.traduzirExpressaoAcessoPropriedade.bind(this),
            Agrupamento: this.traduzirConstrutoAgrupamento.bind(this),
            ArgumentoReferenciaFuncao: this.traduzirExpressaoArgumentoReferenciaFuncao.bind(this),
            AtribuicaoPorIndice: this.traduzirExpressaoAtribuicaoPorIndice.bind(this),
            Atribuir: this.traduzirConstrutoAtribuir.bind(this),
            Binario: this.traduzirConstrutoBinario.bind(this),
            ComentarioComoConstruto: this.traduzirDeclaracaoComentario.bind(this),
            Chamada: this.traduzirConstrutoChamada.bind(this),
            DefinirValor: this.traduzirConstrutoDefinirValor.bind(this),
            Dicionario: this.traduzirConstrutoDicionario.bind(this),
            FuncaoConstruto: this.traduzirFuncaoConstruto.bind(this),
            ImportarComoConstruto: this.traduzirExpressaoImportar.bind(this),
            Isto: () => 'this',
            Leia: this.traduzirExpressaoLeia.bind(this),
            Literal: this.traduzirConstrutoLiteral.bind(this),
            Logico: this.traduzirExpressaoLogica.bind(this),
            ReferenciaFuncao: this.traduzirExpressaoReferenciaFuncao.bind(this),
            Separador: this.traduzirConstrutoSeparador.bind(this),
            SeTernario: this.traduzirConstrutoSeTernario.bind(this),
            TipoDe: this.traduzirConstrutoTipoDe.bind(this),
            Unario: this.traduzirConstrutoUnario.bind(this),
            Variavel: this.traduzirConstrutoVariavel.bind(this),
            Vetor: this.traduzirConstrutoVetor.bind(this),
        };
        this.dicionarioDeclaracoes = {
            Bloco: this.traduzirDeclaracaoBloco.bind(this),
            Classe: this.traduzirDeclaracaoClasse.bind(this),
            Const: this.traduzirDeclaracaoConst.bind(this),
            Comentario: this.traduzirDeclaracaoComentario.bind(this),
            Continua: () => 'continue',
            Enquanto: this.traduzirDeclaracaoEnquanto.bind(this),
            Escolha: this.traduzirDeclaracaoEscolha.bind(this),
            Escreva: this.traduzirDeclaracaoEscreva.bind(this),
            Expressao: this.traduzirDeclaracaoExpressao.bind(this),
            Fazer: this.traduzirDeclaracaoFazer.bind(this),
            Falhar: this.traduzirDeclaracaoFalhar.bind(this),
            FuncaoDeclaracao: this.traduzirDeclaracaoFuncao.bind(this),
            Importar: this.traduzirDeclaracaoImportar.bind(this),
            Para: this.traduzirDeclaracaoPara.bind(this),
            ParaCada: this.traduzirDeclaracaoParaCada.bind(this),
            Retorna: this.traduzirDeclaracaoRetorna.bind(this),
            Se: this.traduzirDeclaracaoSe.bind(this),
            Sustar: () => 'break',
            Tente: this.traduzirDeclaracaoTente.bind(this),
            Var: this.traduzirDeclaracaoVar.bind(this),
        };
    }
    traduzirSimboloOperador(operador) {
        switch (operador.tipo) {
            case delegua_1.default.ADICAO:
                return '+';
            case delegua_1.default.BIT_AND:
                return '&';
            case delegua_1.default.BIT_OR:
                return '|';
            case delegua_1.default.BIT_XOR:
                return '^';
            case delegua_1.default.BIT_NOT:
                return '~';
            case delegua_1.default.DIFERENTE:
                return '!==';
            case delegua_1.default.DIVISAO:
                return '/';
            case delegua_1.default.E:
                return '&&';
            case delegua_1.default.EXPONENCIACAO:
                return '**';
            case delegua_1.default.IGUAL:
                return '=';
            case delegua_1.default.IGUAL_IGUAL:
                return '===';
            case delegua_1.default.MAIOR:
                return '>';
            case delegua_1.default.MAIOR_IGUAL:
                return '>=';
            case delegua_1.default.MENOR:
                return '<';
            case delegua_1.default.MENOR_IGUAL:
                return '<=';
            case delegua_1.default.MODULO:
                return '%';
            case delegua_1.default.MULTIPLICACAO:
                return '*';
            case delegua_1.default.OU:
                return '||';
            case delegua_1.default.SUBTRACAO:
                return '-';
        }
    }
    traduzirFuncaoOuMetodo(nomeMetodo, objetoResolvido, argumentos) {
        const argumentosResolvidos = [];
        for (const argumento of argumentos) {
            const argumentoResolvido = this.dicionarioConstrutos[argumento.constructor.name](argumento);
            argumentosResolvidos.push(argumentoResolvido);
        }
        let textoArgumentos = argumentosResolvidos.reduce((atual, proximo) => (atual += proximo + ', '), '');
        textoArgumentos = textoArgumentos.slice(0, -2);
        switch (nomeMetodo) {
            case 'adicionar':
            case 'empilhar':
                return `${objetoResolvido}.push(${textoArgumentos})`;
            case 'fatiar':
                return `${objetoResolvido}.slice(${argumentos[0]}, ${argumentos[1]})`;
            case 'inclui':
                return `${objetoResolvido}.includes(${argumentosResolvidos[0]})`;
            case 'inverter':
                return `${objetoResolvido}.toReversed()`;
            case 'juntar':
                return `${argumentosResolvidos[0]}.join(${objetoResolvido})`;
            case 'maiusculo':
                return `${objetoResolvido}.toUpperCase()`;
            case 'mapear':
                return `${objetoResolvido}.map(${this.traduzirFuncaoAnonimaParaLambda(argumentos[0])})`;
            case 'minusculo':
                return `${objetoResolvido}.toLowerCase()`;
            case 'ordenar':
                return `${objetoResolvido}.sort()`;
            case 'remover':
                return `delete ${objetoResolvido}[${argumentosResolvidos[0]}]`;
            case 'removerPrimeiro':
                return `${objetoResolvido}.shift()`;
            case 'removerUltimo':
                return `${objetoResolvido}.pop()`;
            case 'somar':
                return `${objetoResolvido}.reduce((acumulador, valorAtual) => acumulador + valorAtual, 0)`;
            case 'tamanho':
                return `${objetoResolvido}.length`;
        }
        return `${objetoResolvido}.${nomeMetodo}(${textoArgumentos}))`;
    }
    traduzirConstrutoAgrupamento(agrupamento) {
        return this.dicionarioConstrutos[agrupamento.constructor.name](agrupamento.expressao || agrupamento);
    }
    traduzirConstrutoAtribuir(atribuir) {
        var _a;
        let resultado = this.dicionarioConstrutos[atribuir.alvo.constructor.name](atribuir.alvo);
        const operador = ((_a = atribuir.simboloOperador) === null || _a === void 0 ? void 0 : _a.lexema) || '=';
        // Em Delégua, atribuições com operações embutidas devolvem um construto `Binario` no valor
        // por várias razões, sendo a mais importante delas a lógica de interpretação.
        let valorResolvido = '';
        if (atribuir.simboloOperador && atribuir.valor.constructor === construtos_1.Binario) {
            valorResolvido = this.dicionarioConstrutos[atribuir.valor.direita.constructor.name](atribuir.valor.direita);
        }
        else {
            valorResolvido = this.dicionarioConstrutos[atribuir.valor.constructor.name](atribuir.valor);
        }
        resultado += ` ${operador} ` + valorResolvido;
        return resultado;
    }
    traduzirConstrutoBinario(binario) {
        let resultado = '';
        if (binario.esquerda.constructor === construtos_1.Agrupamento) {
            const agrupamento = binario.esquerda;
            resultado +=
                '(' +
                    this.dicionarioConstrutos[agrupamento.constructor.name](binario.esquerda) +
                    ')';
        }
        else
            resultado += this.dicionarioConstrutos[binario.esquerda.constructor.name](binario.esquerda);
        let operador = this.traduzirSimboloOperador(binario.operador);
        resultado += ` ${operador} `;
        if (binario.direita.constructor.name === 'Agrupamento')
            resultado +=
                '(' +
                    this.dicionarioConstrutos[binario.direita.constructor.name](binario.direita) +
                    ')';
        else
            resultado += this.dicionarioConstrutos[binario.direita.constructor.name](binario.direita);
        return resultado;
    }
    traduzirConstrutoChamada(chamada) {
        let resultado = '';
        const retorno = `${this.dicionarioConstrutos[chamada.entidadeChamada.constructor.name](chamada.entidadeChamada, chamada.argumentos)}`;
        resultado += retorno;
        return resultado;
    }
    traduzirDeclaracaoComentario(comentario) {
        let resultado = '';
        if (comentario.multilinha) {
            resultado += `/*`;
            for (let linhaComentario of comentario.conteudo) {
                resultado += `${linhaComentario}\n`;
            }
            resultado += `*/`;
        }
        else {
            resultado += `// ${comentario.conteudo}`;
        }
        return resultado;
    }
    traduzirConstrutoDefinirValor(definirValor) {
        let resultado = '';
        if (definirValor.objeto instanceof construtos_1.Isto) {
            resultado = 'this.' + definirValor.nome.lexema + ' = ';
        }
        resultado += definirValor.valor.simbolo.lexema;
        return resultado;
    }
    traduzirConstrutoDicionario(dicionario) {
        let resultado = '{';
        for (let i = 0; i < dicionario.chaves.length; i++) {
            if (dicionario.esSpread && dicionario.esSpread[i]) {
                resultado += '...';
                resultado +=
                    this.dicionarioConstrutos[dicionario.valores[i].constructor.name](dicionario.valores[i]) + ',';
            }
            else {
                resultado += this.dicionarioConstrutos[dicionario.chaves[i].constructor.name](dicionario.chaves[i]);
                resultado += ':';
                resultado +=
                    this.dicionarioConstrutos[dicionario.valores[i].constructor.name](dicionario.valores[i]) + ',';
            }
        }
        resultado += '}';
        return resultado;
    }
    traduzirConstrutoLiteral(literal) {
        if (typeof literal.valor === 'string') {
            const possuiInterpolacao = /\$\{(verdadeiro|falso|nulo)\}/.test(literal.valor);
            const valor = literal.valor.replace(/\$\{(verdadeiro|falso|nulo)\}/g, (_, match) => {
                switch (match) {
                    case 'verdadeiro':
                        return '${true}';
                    case 'falso':
                        return '${false}';
                    case 'nulo':
                        return '${null}';
                    default:
                        return match;
                }
            });
            return possuiInterpolacao ? `\`${valor}\`` : `'${literal.valor}'`;
        }
        return String(literal.valor);
    }
    traduzirConstrutoVariavel(variavel, argumentos) {
        const argumentosResolvidos = [];
        const argumentosValidados = argumentos || [];
        for (const argumento of argumentosValidados) {
            const argumentoResolvido = this.dicionarioConstrutos[argumento.constructor.name](argumento);
            argumentosResolvidos.push(argumentoResolvido);
        }
        let textoArgumentos = argumentosResolvidos.reduce((atual, proximo) => (atual += proximo + ', '), '');
        textoArgumentos = textoArgumentos.slice(0, -2);
        switch (variavel.simbolo.lexema) {
            case 'texto':
                return `String(${textoArgumentos})`;
            default:
                const buscaClasseCorrespondente = this.declaracoesDeClasses.filter((d) => d.simbolo.lexema === variavel.simbolo.lexema);
                if (buscaClasseCorrespondente.length === 0 && argumentosValidados.length === 0) {
                    return `${variavel.simbolo.lexema}`;
                }
                if (buscaClasseCorrespondente.length > 0) {
                    return `new ${variavel.simbolo.lexema}(${textoArgumentos})`;
                }
                return `${variavel.simbolo.lexema}(${textoArgumentos})`;
        }
    }
    logicaComumBlocoEscopo(declaracoes) {
        let resultado = '{\n';
        this.indentacao += 4;
        if (typeof declaracoes[Symbol.iterator] === 'function') {
            for (const declaracaoOuConstruto of declaracoes) {
                resultado += ' '.repeat(this.indentacao);
                const nomeConstrutor = declaracaoOuConstruto.constructor.name;
                if (this.dicionarioConstrutos.hasOwnProperty(nomeConstrutor)) {
                    resultado += this.dicionarioConstrutos[nomeConstrutor](declaracaoOuConstruto);
                }
                else {
                    resultado += this.dicionarioDeclaracoes[nomeConstrutor](declaracaoOuConstruto);
                }
                resultado += '\n';
            }
        }
        this.indentacao -= 4;
        resultado += ' '.repeat(this.indentacao) + '}\n';
        return resultado;
    }
    traduzirDeclaracaoBloco(declaracaoBloco) {
        return this.logicaComumBlocoEscopo(declaracaoBloco.declaracoes);
    }
    logicaTraducaoMetodoClasse(metodoClasse) {
        this.indentacao += 4;
        let resultado = ' '.repeat(this.indentacao);
        resultado +=
            metodoClasse.simbolo.lexema === 'construtor'
                ? 'constructor('
                : metodoClasse.simbolo.lexema + '(';
        for (let parametro of metodoClasse.funcao.parametros) {
            resultado += parametro.nome.lexema + ', ';
        }
        if (metodoClasse.funcao.parametros.length > 0) {
            resultado = resultado.slice(0, -2);
        }
        resultado += ') ';
        resultado += this.logicaComumBlocoEscopo(metodoClasse.funcao.corpo);
        resultado += ' '.repeat(this.indentacao) + '\n';
        this.indentacao -= 4;
        return resultado;
    }
    traduzirDeclaracaoClasse(declaracaoClasse) {
        let resultado = 'export class ';
        if (declaracaoClasse.superClasse)
            resultado += `${declaracaoClasse.simbolo.lexema} extends ${declaracaoClasse.superClasse.simbolo.lexema} {\n`;
        else
            resultado += declaracaoClasse.simbolo.lexema + ' {\n';
        for (let metodo of declaracaoClasse.metodos) {
            resultado += this.logicaTraducaoMetodoClasse(metodo);
        }
        resultado += '}';
        return resultado;
    }
    traduzirDeclaracaoEnquanto(declaracaoEnquanto) {
        let resultado = 'while (';
        resultado +=
            this.dicionarioConstrutos[declaracaoEnquanto.condicao.constructor.name](declaracaoEnquanto.condicao) + ') ';
        resultado += this.dicionarioDeclaracoes[declaracaoEnquanto.corpo.constructor.name](declaracaoEnquanto.corpo);
        return resultado;
    }
    logicaComumCaminhosEscolha(caminho) {
        let resultado = '';
        this.indentacao += 4;
        resultado += ' '.repeat(this.indentacao);
        if (caminho.condicoes && caminho.condicoes.length > 0) {
            for (let condicao of caminho.condicoes) {
                resultado +=
                    'case ' +
                        this.dicionarioConstrutos[condicao.constructor.name](condicao) +
                        ':\n';
                resultado += ' '.repeat(this.indentacao);
            }
        }
        else {
            resultado += 'default:\n';
            resultado += ' '.repeat(this.indentacao);
        }
        for (let declaracao of caminho.declaracoes) {
            resultado += ' '.repeat(this.indentacao + 4);
            switch (declaracao.constructor.name) {
                case 'Retorna':
                    const declaracaoRetorna = declaracao;
                    resultado +=
                        'return ' +
                            this.dicionarioConstrutos[declaracaoRetorna.valor.constructor.name](declaracaoRetorna.valor);
                    break;
                default:
                    resultado +=
                        this.dicionarioDeclaracoes[declaracao.constructor.name](declaracao) + '\n';
                    break;
            }
        }
        resultado += ' '.repeat(this.indentacao + 4);
        resultado += 'break' + '\n';
        this.indentacao -= 4;
        return resultado;
    }
    traduzirDeclaracaoEscolha(declaracaoEscolha) {
        let resultado = 'switch (';
        resultado +=
            this.dicionarioConstrutos[declaracaoEscolha.identificadorOuLiteral.constructor.name](declaracaoEscolha.identificadorOuLiteral) + ') {\n';
        for (let caminho of declaracaoEscolha.caminhos) {
            resultado += this.logicaComumCaminhosEscolha(caminho);
        }
        if (declaracaoEscolha.caminhoPadrao) {
            resultado += ' '.repeat(4);
            resultado += 'default:\n';
            resultado += this.logicaComumCaminhosEscolha(declaracaoEscolha.caminhoPadrao);
        }
        resultado += '}\n';
        return resultado;
    }
    traduzirDeclaracaoEscreva(declaracaoEscreva) {
        let resultado = 'console.log(';
        for (const argumento of declaracaoEscreva.argumentos) {
            const valor = this.dicionarioConstrutos[argumento.constructor.name](argumento);
            resultado += valor + ', ';
        }
        resultado = resultado.slice(0, -2);
        resultado += ')';
        return resultado;
    }
    traduzirDeclaracaoExpressao(declaracaoExpressao) {
        return this.dicionarioConstrutos[declaracaoExpressao.expressao.constructor.name](declaracaoExpressao.expressao);
    }
    traduzirDeclaracaoFazer(declaracaoFazer) {
        let resultado = 'do ';
        resultado += this.dicionarioDeclaracoes[declaracaoFazer.caminhoFazer.constructor.name](declaracaoFazer.caminhoFazer);
        resultado +=
            'while (' +
                this.dicionarioConstrutos[declaracaoFazer.condicaoEnquanto.constructor.name](declaracaoFazer.condicaoEnquanto) +
                ') ';
        return resultado;
    }
    traduzirDeclaracaoFuncao(declaracaoFuncao) {
        let resultado = 'function ';
        resultado += declaracaoFuncao.simbolo.lexema + ' (';
        for (const parametro of declaracaoFuncao.funcao.parametros) {
            resultado += parametro.nome.lexema + ', ';
        }
        if (declaracaoFuncao.funcao.parametros.length > 0) {
            resultado = resultado.slice(0, -2);
        }
        resultado += ') ';
        resultado += this.logicaComumBlocoEscopo(declaracaoFuncao.funcao.corpo);
        return resultado;
    }
    traduzirDeclaracaoImportar(declaracaoImportar) {
        return `'importar() não é suportado por este padrão de JavaScript'`;
    }
    traduzirExpressaoLeia(declaracaoLeia) {
        return `'leia() não é suportado por este padrão de JavaScript.'`;
    }
    traduzirDeclaracaoParaCada(declaracaoParaCada) {
        const variavelIteracao = this.dicionarioConstrutos[declaracaoParaCada.variavelIteracao.constructor.name](declaracaoParaCada.variavelIteracao);
        let resultado = `for (let ${variavelIteracao} of `;
        resultado +=
            this.dicionarioConstrutos[declaracaoParaCada.vetorOuDicionario.constructor.name](declaracaoParaCada.vetorOuDicionario) + ') ';
        resultado += this.dicionarioDeclaracoes[declaracaoParaCada.corpo.constructor.name](declaracaoParaCada.corpo);
        return resultado;
    }
    traduzirDeclaracaoPara(declaracaoPara) {
        let resultado = 'for (';
        if (declaracaoPara.inicializador.constructor.name === 'Array') {
            resultado +=
                this.dicionarioDeclaracoes[declaracaoPara.inicializador[0].constructor.name](declaracaoPara.inicializador[0], false) + '; ';
        }
        else {
            resultado +=
                this.dicionarioDeclaracoes[declaracaoPara.inicializador.constructor.name](declaracaoPara.inicializador, false) + '; ';
        }
        resultado +=
            this.dicionarioConstrutos[declaracaoPara.condicao.constructor.name](declaracaoPara.condicao) + '; ';
        resultado +=
            this.dicionarioConstrutos[declaracaoPara.incrementar.constructor.name](declaracaoPara.incrementar) + ') ';
        resultado += this.dicionarioDeclaracoes[declaracaoPara.corpo.constructor.name](declaracaoPara.corpo);
        return resultado;
    }
    traduzirDeclaracaoRetorna(declaracaoRetorna) {
        let resultado = 'return ';
        const nomeConstrutor = declaracaoRetorna.valor.constructor.name;
        return (resultado += this.dicionarioConstrutos[nomeConstrutor](declaracaoRetorna === null || declaracaoRetorna === void 0 ? void 0 : declaracaoRetorna.valor));
    }
    traduzirDeclaracaoSe(declaracaoSe) {
        let resultado = 'if (';
        const condicao = this.dicionarioConstrutos[declaracaoSe.condicao.constructor.name](declaracaoSe.condicao);
        resultado += condicao;
        resultado += ')';
        resultado += this.dicionarioDeclaracoes[declaracaoSe.caminhoEntao.constructor.name](declaracaoSe.caminhoEntao);
        if (declaracaoSe.caminhoSenao !== null) {
            resultado += ' '.repeat(this.indentacao);
            resultado += 'else ';
            const se = declaracaoSe === null || declaracaoSe === void 0 ? void 0 : declaracaoSe.caminhoSenao;
            if (se === null || se === void 0 ? void 0 : se.caminhoEntao) {
                resultado += 'if (';
                resultado += this.dicionarioConstrutos[se.condicao.constructor.name](se.condicao);
                resultado += ')';
                resultado += this.dicionarioDeclaracoes[se.caminhoEntao.constructor.name](se.caminhoEntao);
                resultado += ' '.repeat(this.indentacao);
                if (se === null || se === void 0 ? void 0 : se.caminhoSenao) {
                    resultado += 'else ';
                    resultado += this.dicionarioDeclaracoes[se.caminhoSenao.constructor.name](se.caminhoSenao);
                    return resultado;
                }
            }
            resultado += this.dicionarioDeclaracoes[declaracaoSe.caminhoSenao.constructor.name](declaracaoSe.caminhoSenao);
        }
        return resultado;
    }
    traduzirDeclaracaoTente(declaracaoTente) {
        let resultado = 'try {\n';
        this.indentacao += 4;
        resultado += ' '.repeat(this.indentacao);
        for (let condicao of declaracaoTente.caminhoTente) {
            resultado += this.dicionarioDeclaracoes[condicao.constructor.name](condicao) + '\n';
            resultado += ' '.repeat(this.indentacao);
        }
        resultado += '}';
        if (declaracaoTente.caminhoPegue !== null) {
            resultado += '\ncatch {\n';
            resultado += ' '.repeat(this.indentacao);
            if (Array.isArray(declaracaoTente.caminhoPegue)) {
                for (let declaracao of declaracaoTente.caminhoPegue) {
                    resultado +=
                        this.dicionarioDeclaracoes[declaracao.constructor.name](declaracao) + '\n';
                }
            }
            else {
                for (let corpo of declaracaoTente.caminhoPegue.corpo) {
                    resultado += this.dicionarioDeclaracoes[corpo.constructor.name](corpo) + '\n';
                }
            }
            resultado += ' '.repeat(this.indentacao);
            resultado += '}';
        }
        if (declaracaoTente.caminhoFinalmente !== null) {
            resultado += '\nfinally {\n';
            for (let finalmente of declaracaoTente.caminhoFinalmente) {
                resultado +=
                    this.dicionarioDeclaracoes[finalmente.constructor.name](finalmente) + '\n';
            }
            resultado += ' '.repeat(this.indentacao);
            resultado += '}';
        }
        return resultado;
    }
    traduzirDeclaracaoConst(declaracaoConst) {
        let resultado = 'const ';
        resultado += declaracaoConst.simbolo.lexema;
        if (!(declaracaoConst === null || declaracaoConst === void 0 ? void 0 : declaracaoConst.inicializador))
            resultado += ';';
        else {
            resultado += ' = ';
            if (this.dicionarioConstrutos[declaracaoConst.inicializador.constructor.name]) {
                resultado += this.dicionarioConstrutos[declaracaoConst.inicializador.constructor.name](declaracaoConst.inicializador);
            }
            else {
                resultado += this.dicionarioDeclaracoes[declaracaoConst.inicializador.constructor.name](declaracaoConst.inicializador);
            }
            resultado += ';';
        }
        return resultado;
    }
    traduzirDeclaracaoVar(declaracaoVar, adicionarPontoEVirgula = true) {
        let resultado = 'let ';
        resultado += declaracaoVar.simbolo.lexema;
        if (!(declaracaoVar === null || declaracaoVar === void 0 ? void 0 : declaracaoVar.inicializador) && adicionarPontoEVirgula)
            resultado += ';';
        else {
            resultado += ' = ';
            resultado += this.dicionarioConstrutos[declaracaoVar.inicializador.constructor.name](declaracaoVar.inicializador);
            if (adicionarPontoEVirgula)
                resultado += ';';
        }
        return resultado;
    }
    // TODO: Talvez terminar (ou remover, sei lá).
    traduzirFuncaoAnonimaParaLambda(argumento) {
        return '';
    }
    traduzirExpressaoAcessoMetodoVetor(objeto, nomeMetodo, argumentos) {
        const objetoResolvido = this.dicionarioConstrutos[objeto.constructor.name](objeto);
        const argumentosResolvidos = [];
        for (const argumento of argumentos) {
            const argumentoResolvido = this.dicionarioConstrutos[argumento.constructor.name](argumento);
            argumentosResolvidos.push(argumentoResolvido);
        }
        switch (nomeMetodo) {
            case 'adicionar':
            case 'empilhar':
                let textoArgumentos = argumentosResolvidos.reduce((atual, proximo) => (atual += proximo + ', '), '');
                textoArgumentos = textoArgumentos.slice(0, -2);
                return `${objetoResolvido}.push(${textoArgumentos})`;
            case 'fatiar':
                return `${objetoResolvido}[${argumentos[0]}:${argumentos[1]}]`;
            case 'inclui':
                return `${argumentos[0]} in ${objetoResolvido}`;
            case 'inverter':
                return `reversed(${objetoResolvido})`;
            case 'juntar':
                return `${argumentos[0]}.join(${objetoResolvido})`;
            case 'mapear':
                return `list(map(${this.traduzirFuncaoAnonimaParaLambda(argumentos[0])}), ${objetoResolvido})`;
            case 'ordenar':
                return `${objetoResolvido}.sort()`;
            case 'remover':
                return `del ${objetoResolvido}[${argumentos[0]}]`;
            case 'removerPrimeiro':
                return `del ${objetoResolvido}[0]`;
            case 'removerUltimo':
                return `del ${objetoResolvido}[-1]`;
            case 'somar':
                return `sum(${objetoResolvido})`;
            case 'tamanho':
                return `len(${objetoResolvido})`;
        }
    }
    traduzirExpressaoAcessoMetodo(acessoMetodo, argumentos) {
        switch (acessoMetodo.objeto.constructor.name) {
            case 'Isto':
                return `this.${acessoMetodo.nomeMetodo}`;
            case 'Variavel':
                let objetoVariavel = acessoMetodo.objeto;
                return this.traduzirFuncaoOuMetodo(acessoMetodo.nomeMetodo, objetoVariavel.simbolo.lexema, argumentos);
            case 'Vetor':
                return this.traduzirExpressaoAcessoMetodoVetor(acessoMetodo.objeto, acessoMetodo.nomeMetodo, argumentos);
            default:
                const objetoResolvido = this.dicionarioConstrutos[acessoMetodo.objeto.constructor.name](acessoMetodo.objeto);
                return `${objetoResolvido}.${acessoMetodo.nomeMetodo}`;
        }
    }
    traduzirExpressaoAcessoMetodoOuPropriedade(acessoMetodo, argumentos) {
        if (acessoMetodo.objeto instanceof construtos_1.Variavel) {
            let objetoVariavel = acessoMetodo.objeto;
            return `${this.traduzirFuncaoOuMetodo(acessoMetodo.simbolo.lexema, objetoVariavel.simbolo.lexema, argumentos)}`;
        }
        return `this.${acessoMetodo.simbolo.lexema}`;
    }
    traduzirExpressaoAcessoPropriedade(acessoMetodo, argumentos) {
        if (acessoMetodo.objeto instanceof construtos_1.Variavel) {
            let objetoVariavel = acessoMetodo.objeto;
            return `${this.traduzirFuncaoOuMetodo(objetoVariavel.simbolo.lexema, acessoMetodo.nomePropriedade, argumentos)}`;
        }
        return `this.${acessoMetodo.nomePropriedade}`;
    }
    traduzirFuncaoConstruto(funcaoConstruto) {
        let resultado = 'function(';
        for (const parametro of funcaoConstruto.parametros) {
            resultado += parametro.nome.lexema + ', ';
        }
        if (funcaoConstruto.parametros.length > 0) {
            resultado = resultado.slice(0, -2);
        }
        resultado += ') ';
        resultado += this.logicaComumBlocoEscopo(funcaoConstruto.corpo);
        return resultado;
    }
    traduzirExpressaoLogica(logico) {
        let direita = this.dicionarioConstrutos[logico.direita.constructor.name](logico.direita);
        let operador = this.traduzirSimboloOperador(logico.operador);
        let esquerda = this.dicionarioConstrutos[logico.esquerda.constructor.name](logico.esquerda);
        return `${direita} ${operador} ${esquerda}`;
    }
    // TODO: Eliminar o soft cast para `any`.
    traduzirExpressaoAtribuicaoPorIndice(AtribuicaoPorIndice) {
        var _a, _b;
        let resultado = '';
        resultado += AtribuicaoPorIndice.objeto.simbolo.lexema + '[';
        resultado +=
            this.dicionarioConstrutos[AtribuicaoPorIndice.indice.constructor.name](AtribuicaoPorIndice.indice) + ']';
        resultado += ' = ';
        if ((_b = (_a = AtribuicaoPorIndice === null || AtribuicaoPorIndice === void 0 ? void 0 : AtribuicaoPorIndice.valor) === null || _a === void 0 ? void 0 : _a.simbolo) === null || _b === void 0 ? void 0 : _b.lexema) {
            resultado += `${AtribuicaoPorIndice.valor.simbolo.lexema}`;
        }
        else {
            resultado += this.dicionarioConstrutos[AtribuicaoPorIndice.valor.constructor.name](AtribuicaoPorIndice.valor);
        }
        return resultado;
    }
    traduzirExpressaoAcessoIndiceVariavel(acessoIndiceVariavel) {
        let resultado = '';
        resultado += this.dicionarioConstrutos[acessoIndiceVariavel.entidadeChamada.constructor.name](acessoIndiceVariavel.entidadeChamada);
        resultado += `[${this.dicionarioConstrutos[acessoIndiceVariavel.indice.constructor.name](acessoIndiceVariavel.indice)}]`;
        return resultado;
    }
    traduzirExpressaoArgumentoReferenciaFuncao(argumentoReferenciaFuncao, argumentos) {
        const argumentosResolvidos = [];
        for (const argumento of argumentos) {
            const argumentoResolvido = this.dicionarioConstrutos[argumento.constructor.name](argumento);
            argumentosResolvidos.push(argumentoResolvido);
        }
        let textoArgumentos = argumentosResolvidos.reduce((atual, proximo) => (atual += proximo + ', '), '');
        textoArgumentos = textoArgumentos.slice(0, -2);
        return `${argumentoReferenciaFuncao.simboloFuncao.lexema}(${textoArgumentos})`;
    }
    traduzirExpressaoImportar(_) {
        return `'importar() não é suportado por este padrão de JavaScript'`;
    }
    traduzirExpressaoReferenciaFuncao(referenciaFuncao, argumentos) {
        const argumentosResolvidos = [];
        for (const argumento of argumentos) {
            const argumentoResolvido = this.dicionarioConstrutos[argumento.constructor.name](argumento);
            argumentosResolvidos.push(argumentoResolvido);
        }
        let textoArgumentos = argumentosResolvidos.reduce((atual, proximo) => (atual += proximo + ', '), '');
        textoArgumentos = textoArgumentos.slice(0, -2);
        return `${referenciaFuncao.simboloFuncao.lexema}(${textoArgumentos})`;
    }
    traduzirConstrutoSeparador(separador) {
        return `${separador.conteudo} `;
    }
    traduzirConstrutoSeTernario(seTernario) {
        let resultado = '';
        resultado += this.dicionarioConstrutos[seTernario.condicao.constructor.name](seTernario.condicao);
        resultado += ' ? ';
        resultado += this.dicionarioConstrutos[seTernario.expressaoSe.constructor.name](seTernario.expressaoSe);
        resultado += ' : ';
        resultado += this.dicionarioConstrutos[seTernario.expressaoSenao.constructor.name](seTernario.expressaoSenao);
        return resultado;
    }
    traduzirConstrutoTipoDe(tipoDe) {
        let resultado = 'typeof ';
        if (!tipoDe.valor)
            resultado += tipoDe.valor; // Qual o sentido disso?
        else if (typeof tipoDe.valor === 'string')
            resultado += `'${tipoDe.valor}'`;
        else if (typeof tipoDe.valor === 'number')
            resultado += tipoDe.valor;
        else {
            // Talvez isso seja uma péssima ideia.
            // Pensar em algo melhor.
            let alvoTipoDe = String(this.dicionarioConstrutos[tipoDe.valor.constructor.name](tipoDe.valor));
            if (alvoTipoDe.startsWith('new')) {
                alvoTipoDe = alvoTipoDe.slice(4, -2);
            }
            resultado += `${alvoTipoDe}`;
        }
        return resultado;
    }
    traduzirConstrutoVetor(vetor) {
        if (!vetor.valores.length) {
            return '[]';
        }
        let resultado = '[';
        for (let valor of vetor.valores) {
            resultado += `${this.dicionarioConstrutos[valor.constructor.name](valor)}`;
        }
        resultado += ']';
        return resultado;
    }
    traduzirConstrutoUnario(unario) {
        var _a, _b;
        let resultado = '';
        if ([delegua_1.default.INCREMENTAR, delegua_1.default.DECREMENTAR].includes(unario.operador.tipo)) {
            resultado += (_a = unario.operando.valor) !== null && _a !== void 0 ? _a : unario.operando.simbolo.lexema;
            resultado += unario.operador.tipo === delegua_1.default.INCREMENTAR ? '++' : '--';
        }
        else {
            resultado += this.traduzirSimboloOperador(unario.operador);
            resultado += (_b = unario.operando.valor) !== null && _b !== void 0 ? _b : unario.operando.simbolo.lexema;
        }
        return resultado;
    }
    traduzirDeclaracaoFalhar(falhar) {
        const explicacao = this.dicionarioConstrutos[falhar.explicacao.constructor.name](falhar.explicacao);
        return `throw ${explicacao}`;
    }
    traduzir(declaracoes) {
        let resultado = '';
        this.declaracoesDeClasses = declaracoes.filter((declaracao) => declaracao instanceof declaracoes_1.Classe);
        for (const declaracao of declaracoes) {
            resultado += `${this.dicionarioDeclaracoes[declaracao.constructor.name](declaracao)} \n`;
        }
        return resultado;
    }
}
exports.TradutorJavaScript = TradutorJavaScript;
//# sourceMappingURL=tradutor-javascript.js.map