"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MicroAvaliadorSintaticoPitugues = void 0;
const construtos_1 = require("../../construtos");
const declaracoes_1 = require("../../declaracoes");
const micro_avaliador_sintatico_base_1 = require("../micro-avaliador-sintatico-base");
const inferenciador_1 = require("../../inferenciador");
const pitugues_1 = __importDefault(require("../../tipos-de-simbolos/pitugues"));
/**
 * O MicroAvaliadorSintatico funciona apenas dentro de interpolações de texto.
 */
class MicroAvaliadorSintaticoPitugues extends micro_avaliador_sintatico_base_1.MicroAvaliadorSintaticoBase {
    primario() {
        const simboloAtual = this.simbolos[this.atual];
        switch (simboloAtual.tipo) {
            // TODO: Verificar se vamos usar isso.
            /* case tiposDeSimbolos.CHAVE_ESQUERDA:
                this.avancarEDevolverAnterior();
                const chaves = [];
                valores = [];

                if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CHAVE_DIREITA)) {
                    return new Dicionario(-1, Number(this.linha), [], []);
                }

                while (!this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CHAVE_DIREITA)) {
                    const chave = this.atribuir();
                    this.consumir(tiposDeSimbolos.DOIS_PONTOS, "Esperado ':' entre chave e valor.");
                    const valor = this.atribuir();

                    chaves.push(chave);
                    valores.push(valor);

                    if (this.simbolos[this.atual].tipo !== tiposDeSimbolos.CHAVE_DIREITA) {
                        this.consumir(tiposDeSimbolos.VIRGULA, 'Esperado vírgula antes da próxima expressão.');
                    }
                }

                return new Dicionario(-1, Number(this.linha), chaves, valores); */
            // TODO: Verificar se vamos usar isso.
            case pitugues_1.default.COLCHETE_ESQUERDO:
                this.avancarEDevolverAnterior();
                const valores = [];
                if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.COLCHETE_DIREITO)) {
                    return new construtos_1.Vetor(-1, Number(this.linha), []);
                }
                while (!this.verificarSeSimboloAtualEIgualA(pitugues_1.default.COLCHETE_DIREITO)) {
                    const valor = this.declaracao();
                    valores.push(valor);
                    if (this.simbolos[this.atual].tipo !== pitugues_1.default.COLCHETE_DIREITO) {
                        this.consumir(pitugues_1.default.VIRGULA, 'Esperado vírgula antes da próxima expressão.');
                    }
                }
                const tipoVetor = (0, inferenciador_1.inferirTipoVariavel)(valores);
                return new construtos_1.Vetor(-1, Number(this.linha), valores, tipoVetor);
            case pitugues_1.default.FALSO:
                this.avancarEDevolverAnterior();
                return new construtos_1.Literal(-1, Number(this.linha), false);
            case pitugues_1.default.NULO:
                this.avancarEDevolverAnterior();
                return new construtos_1.Literal(-1, Number(this.linha), null);
            case pitugues_1.default.NUMERO:
            case pitugues_1.default.TEXTO:
                const simboloNumeroTexto = this.avancarEDevolverAnterior();
                const tipoInferido = (0, inferenciador_1.inferirTipoVariavel)(simboloNumeroTexto.literal);
                return new construtos_1.Literal(-1, Number(this.linha), simboloNumeroTexto.literal, tipoInferido);
            case pitugues_1.default.IDENTIFICADOR:
                const simboloIdentificador = this.avancarEDevolverAnterior();
                return new construtos_1.Variavel(-1, simboloIdentificador);
            case pitugues_1.default.PARENTESE_ESQUERDO:
                this.avancarEDevolverAnterior();
                const expressao = this.ou();
                this.consumir(pitugues_1.default.PARENTESE_DIREITO, "Esperado ')' após a expressão.");
                return new construtos_1.Agrupamento(-1, Number(this.linha), expressao);
            case pitugues_1.default.VERDADEIRO:
                this.avancarEDevolverAnterior();
                return new construtos_1.Literal(-1, Number(this.linha), true);
        }
        throw this.erro(this.simbolos[this.atual], 'Esperado expressão.');
    }
    finalizarChamada(entidadeChamada) {
        const argumentos = [];
        if (!this.verificarTipoSimboloAtual(pitugues_1.default.PARENTESE_DIREITO)) {
            do {
                if (argumentos.length >= 255) {
                    throw this.erro(this.simbolos[this.atual], 'Não pode haver mais de 255 argumentos.');
                }
                argumentos.push(this.ou());
            } while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.VIRGULA));
        }
        this.consumir(pitugues_1.default.PARENTESE_DIREITO, "Esperado ')' após os argumentos.");
        return new construtos_1.Chamada(-1, entidadeChamada, argumentos);
    }
    chamar() {
        let expressao = this.primario();
        while (true) {
            if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.PARENTESE_ESQUERDO)) {
                expressao = this.finalizarChamada(expressao);
            }
            else if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.PONTO)) {
                const nome = this.consumir(pitugues_1.default.IDENTIFICADOR, "Esperado nome do método após '.'.");
                expressao = new construtos_1.AcessoMetodoOuPropriedade(-1, expressao, nome);
            }
            else if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.COLCHETE_ESQUERDO)) {
                const indice = this.ou();
                const simboloFechamento = this.consumir(pitugues_1.default.COLCHETE_DIREITO, "Esperado ']' após escrita do indice.");
                expressao = new construtos_1.AcessoIndiceVariavel(-1, expressao, indice, simboloFechamento);
            }
            else {
                break;
            }
        }
        return expressao;
    }
    multiplicar() {
        let expressao = this.exponenciacao();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.MULTIPLICACAO, pitugues_1.default.DIVISAO, pitugues_1.default.MODULO, pitugues_1.default.DIVISAO_INTEIRA)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.exponenciacao();
            expressao = new construtos_1.Binario(-1, expressao, operador, direito);
        }
        return expressao;
    }
    unario() {
        if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.NEGACAO, pitugues_1.default.SUBTRACAO, pitugues_1.default.BIT_NOT)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.unario();
            return new construtos_1.Unario(-1, operador, direito, 'ANTES');
        }
        return this.chamar();
    }
    exponenciacao() {
        let expressao = this.unario();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.EXPONENCIACAO)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.exponenciacao();
            expressao = new construtos_1.Binario(-1, expressao, operador, direito);
        }
        return expressao;
    }
    adicaoOuSubtracao() {
        let expressao = this.multiplicar();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.ADICAO, pitugues_1.default.SUBTRACAO)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.multiplicar();
            expressao = new construtos_1.Binario(-1, expressao, operador, direito);
        }
        return expressao;
    }
    bitShift() {
        let expressao = this.adicaoOuSubtracao();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.MENOR_MENOR, pitugues_1.default.MAIOR_MAIOR)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.adicaoOuSubtracao();
            expressao = new construtos_1.Binario(-1, expressao, operador, direito);
        }
        return expressao;
    }
    bitE() {
        let expressao = this.bitShift();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.BIT_AND)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.bitShift();
            expressao = new construtos_1.Binario(-1, expressao, operador, direito);
        }
        return expressao;
    }
    bitOu() {
        let expressao = this.bitE();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.BIT_OR, pitugues_1.default.BIT_XOR)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.bitE();
            expressao = new construtos_1.Binario(-1, expressao, operador, direito);
        }
        return expressao;
    }
    comparar() {
        let expressao = this.bitOu();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.MAIOR, pitugues_1.default.MAIOR_IGUAL, pitugues_1.default.MENOR, pitugues_1.default.MENOR_IGUAL)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.bitOu();
            expressao = new construtos_1.Binario(-1, expressao, operador, direito);
        }
        return expressao;
    }
    em() {
        let expressao = this.comparacaoIgualdade();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.EM)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.comparacaoIgualdade();
            expressao = new construtos_1.Logico(-1, expressao, operador, direito);
        }
        return expressao;
    }
    e() {
        let expressao = this.em();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.E)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.em();
            expressao = new construtos_1.Logico(-1, expressao, operador, direito);
        }
        return expressao;
    }
    ou() {
        let expressao = this.e();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.OU)) {
            const operador = this.simbolos[this.atual - 1];
            const direito = this.e();
            expressao = new construtos_1.Logico(-1, expressao, operador, direito);
        }
        return expressao;
    }
    atribuir() {
        return this.ou();
    }
    expressao() {
        return this.atribuir();
    }
    analisar(retornoLexador, linha) {
        this.erros = [];
        this.atual = 0;
        this.linha = linha;
        this.simbolos = (retornoLexador === null || retornoLexador === void 0 ? void 0 : retornoLexador.simbolos) || [];
        const declaracoes = [];
        while (this.atual < this.simbolos.length) {
            const expressao = this.expressao();
            declaracoes.push(new declaracoes_1.Expressao(expressao));
        }
        return {
            declaracoes: declaracoes,
            erros: this.erros,
        };
    }
}
exports.MicroAvaliadorSintaticoPitugues = MicroAvaliadorSintaticoPitugues;
//# sourceMappingURL=micro-avaliador-sintatico-pitugues.js.map