UNPKG

@designliquido/delegua

Version:

Linguagem de programação simples e moderna usando português estruturado.

1,033 lines 57.1 kB
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AvaliadorSintaticoPitugues = void 0;
const browser_process_hrtime_1 = __importDefault(require("browser-process-hrtime"));
const construtos_1 = require("../../construtos");
const declaracoes_1 = require("../../declaracoes");
const erro_avaliador_sintatico_1 = require("../erro-avaliador-sintatico");
const lexador_1 = require("../../lexador");
const inferenciador_1 = require("../../inferenciador");
const pilha_escopos_1 = require("../pilha-escopos");
const informacao_escopo_1 = require("../informacao-escopo");
const informacao_variavel_ou_constante_1 = require("../../informacao-variavel-ou-constante");
const pitugues_1 = __importDefault(require("../../tipos-de-simbolos/pitugues"));
const primitivas_dicionario_1 = __importDefault(require("../../bibliotecas/primitivas-dicionario"));
const primitivas_numero_1 = __importDefault(require("../../bibliotecas/primitivas-numero"));
const primitivas_texto_1 = __importDefault(require("../../bibliotecas/primitivas-texto"));
const primitivas_vetor_1 = __importDefault(require("../../bibliotecas/primitivas-vetor"));
const comum_1 = require("../comum");
/**
 * O avaliador sintático (_Parser_) é responsável por transformar os símbolos do Lexador em estruturas de alto nível.
 * Essas estruturas de alto nível são as partes que executam lógica de programação de fato.
 * Há dois grupos de estruturas de alto nível: Construtos e Declarações.
 *
 * A grande diferença entre este avaliador e os demais é a forma como são entendidos os blocos de escopo.
 * Este avaliador espera uma estrutura de pragmas, que explica quantos espaços há na frente de cada linha.
 */
class AvaliadorSintaticoPitugues {
    constructor(performance = false) {
        this.atual = 0;
        this.blocos = 0;
        this.performance = performance;
        this.escopos = [];
        this.pilhaEscopos = new pilha_escopos_1.PilhaEscopos();
        this.primitivasConhecidas = {};
        this.tiposDefinidosEmCodigo = {};
        (0, comum_1.registrarPrimitiva)(this.primitivasConhecidas, 'dicionário', primitivas_dicionario_1.default);
        (0, comum_1.registrarPrimitiva)(this.primitivasConhecidas, 'número', primitivas_numero_1.default);
        (0, comum_1.registrarPrimitiva)(this.primitivasConhecidas, 'texto', primitivas_texto_1.default);
        (0, comum_1.registrarPrimitiva)(this.primitivasConhecidas, 'vetor', primitivas_vetor_1.default);
    }
    logicaComumInferenciaTiposVariaveisEConstantes(inicializador, tipo) {
        if (tipo !== 'qualquer') {
            return tipo;
        }
        switch (inicializador.constructor.name) {
            case 'AcessoIndiceVariavel':
                const entidadeChamadaAcessoIndiceVariavel = inicializador
                    .entidadeChamada;
                // Este condicional ocorre com chamadas aninhadas. Por exemplo, `vetor[1][2]`.
                if (entidadeChamadaAcessoIndiceVariavel.constructor.name === 'AcessoIndiceVariavel') {
                    return this.logicaComumInferenciaTiposVariaveisEConstantes(entidadeChamadaAcessoIndiceVariavel, tipo);
                }
                if (entidadeChamadaAcessoIndiceVariavel.tipo.endsWith('[]')) {
                    return entidadeChamadaAcessoIndiceVariavel.tipo.slice(0, -2);
                }
                // Normalmente, `entidadeChamadaAcessoIndiceVariavel.tipo` aqui será 'vetor'.
                return 'qualquer';
            case 'Chamada':
                const entidadeChamadaChamada = inicializador.entidadeChamada;
                switch (entidadeChamadaChamada.constructor.name) {
                    case 'AcessoMetodo':
                        const entidadeChamadaAcessoMetodo = entidadeChamadaChamada;
                        return entidadeChamadaAcessoMetodo.tipoRetornoMetodo;
                    case 'AcessoMetodoOuPropriedade':
                        // Este caso ocorre quando a variável/constante é do tipo 'qualquer',
                        // e a chamada normalmente é feita para uma primitiva.
                        // A inferência, portanto, ocorre pelo uso da primitiva.
                        const entidadeChamadaAcessoMetodoOuPropriedade = entidadeChamadaChamada;
                        for (const primitiva in this.primitivasConhecidas) {
                            if (this.primitivasConhecidas[primitiva].hasOwnProperty(entidadeChamadaAcessoMetodoOuPropriedade.simbolo.lexema)) {
                                return this.primitivasConhecidas[primitiva][entidadeChamadaAcessoMetodoOuPropriedade.simbolo.lexema].tipo;
                            }
                        }
                        throw new erro_avaliador_sintatico_1.ErroAvaliadorSintatico(entidadeChamadaAcessoMetodoOuPropriedade.simbolo, `Primitiva '${entidadeChamadaAcessoMetodoOuPropriedade.simbolo.lexema}' não existe.`);
                    case 'AcessoPropriedade':
                        const entidadeChamadaAcessoPropriedade = entidadeChamadaChamada;
                        return entidadeChamadaAcessoPropriedade.tipoRetornoPropriedade;
                    case 'ArgumentoReferenciaFuncao':
                        // TODO: Voltar aqui se necessário.
                        return 'qualquer';
                    case 'ReferenciaFuncao':
                        const entidadeChamadaReferenciaFuncao = entidadeChamadaChamada;
                        return entidadeChamadaReferenciaFuncao.tipo;
                    case 'Variavel':
                        const entidadeChamadaVariavel = entidadeChamadaChamada;
                        return entidadeChamadaVariavel.tipo;
                }
                break;
            case 'FuncaoConstruto':
                const funcaoConstruto = inicializador;
                return `função<${funcaoConstruto.tipo}>`;
            case 'Leia':
                return 'texto';
            case 'Dupla':
            case 'Trio':
            case 'Quarteto':
            case 'Quinteto':
            case 'Sexteto':
            case 'Septeto':
            case 'Octeto':
            case 'Noneto':
            case 'Deceto':
                return 'tupla';
            case 'ImportarBiblioteca':
            case 'ModuloDeclaracoes':
                return 'módulo';
            default:
                return inicializador.tipo;
        }
    }
    expressaoLeia() {
        const simboloLeia = this.avancarEDevolverAnterior();
        this.consumir(pitugues_1.default.PARENTESE_ESQUERDO, "Esperado '(' antes dos valores em leia.");
        const argumentos = [];
        do {
            argumentos.push(this.expressao());
        } while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.VIRGULA));
        this.consumir(pitugues_1.default.PARENTESE_DIREITO, "Esperado ')' após os valores em leia.");
        return new construtos_1.Leia(simboloLeia, argumentos);
    }
    declaracaoDeConstantes() {
        const identificadores = [];
        let tipo = 'qualquer';
        // TODO: Desestruturação em Python não requer chaves.
        // Exemplo: const a, b, c = vetor;
        // Pensar em algo equivalente para Pituguês.
        /* if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CHAVE_ESQUERDA)) {
            return this.declaracaoDesestruturacaoConstante();
        } */
        do {
            identificadores.push(this.consumir(pitugues_1.default.IDENTIFICADOR, 'Esperado nome da constante.'));
        } while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.VIRGULA));
        // TODO: Discutir com comunidade como seria melhor fazer
        // dicas de tipos.
        /* if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.DOIS_PONTOS)) {
            tipo = this.verificarDefinicaoTipoAtual();
            this.avancarEDevolverAnterior();
        } */
        this.consumir(pitugues_1.default.IGUAL, "Esperado '=' após identificador em instrução 'constante'.");
        const inicializadores = [];
        do {
            inicializadores.push(this.expressao());
        } while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.VIRGULA));
        // TODO: Muito provavelmente, com desestruturação, essa validação
        // não será necessária.
        /* if (identificadores.length !== inicializadores.length) {
            throw this.erro(
                this.simbolos[this.atual],
                'Quantidade de identificadores à esquerda do igual é diferente da quantidade de valores à direita.'
            );
        } */
        let retorno = [];
        for (let [indice, identificador] of identificadores.entries()) {
            // Se tipo ainda não foi definido, infere.
            tipo = this.logicaComumInferenciaTiposVariaveisEConstantes(inicializadores[indice], tipo);
            this.pilhaEscopos.definirInformacoesVariavel(identificador.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(identificador.lexema, tipo));
            retorno.push(new declaracoes_1.Const(identificador, inicializadores[indice], tipo
            // TODO: Discutir decoradores com comunidade.
            // Array.from(this.pilhaDecoradores)
            ));
        }
        // this.pilhaDecoradores = [];
        return retorno;
    }
    declaracaoDeVariavel() {
        throw new Error('Método não implementado.');
    }
    declaracaoDeVariaveis() {
        const identificadores = [];
        let retorno = [];
        let tipo = 'qualquer';
        do {
            identificadores.push(this.consumir(pitugues_1.default.IDENTIFICADOR, 'Esperado nome de variável.'));
        } while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.VIRGULA));
        if (!this.verificarSeSimboloAtualEIgualA(pitugues_1.default.IGUAL)) {
            // Inicialização de variáveis sem valor.
            for (let [indice, identificador] of identificadores.entries()) {
                retorno.push(new declaracoes_1.Var(identificador, null));
            }
            this.verificarSeSimboloAtualEIgualA(pitugues_1.default.PONTO_E_VIRGULA);
            return retorno;
        }
        const inicializadores = [];
        do {
            inicializadores.push(this.expressao());
        } while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.VIRGULA));
        if (identificadores.length !== inicializadores.length) {
            throw this.erro(this.simboloAtual(), 'Quantidade de identificadores à esquerda do igual é diferente da quantidade de valores à direita.');
        }
        for (let [indice, identificador] of identificadores.entries()) {
            const inicializador = inicializadores[indice];
            tipo = this.logicaComumInferenciaTiposVariaveisEConstantes(inicializadores[indice], tipo);
            this.pilhaEscopos.definirInformacoesVariavel(identificador.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(identificador.lexema, tipo));
            retorno.push(new declaracoes_1.Var(identificador, inicializador, tipo));
        }
        return retorno;
    }
    sincronizar() {
        this.avancarEDevolverAnterior();
        while (!this.estaNoFinal()) {
            switch (this.simboloAtual().tipo) {
                case pitugues_1.default.CLASSE:
                case pitugues_1.default.FUNCAO:
                case pitugues_1.default.FUNÇÃO:
                case pitugues_1.default.VARIAVEL:
                case pitugues_1.default.PARA:
                case pitugues_1.default.SE:
                case pitugues_1.default.ENQUANTO:
                case pitugues_1.default.ESCREVA:
                case pitugues_1.default.RETORNA:
                    return;
            }
            this.avancarEDevolverAnterior();
        }
    }
    erro(simbolo, mensagemDeErro) {
        const excecao = new erro_avaliador_sintatico_1.ErroAvaliadorSintatico(simbolo, mensagemDeErro);
        this.erros.push(excecao);
        return excecao;
    }
    consumir(tipo, mensagemDeErro) {
        if (this.verificarTipoSimboloAtual(tipo))
            return this.avancarEDevolverAnterior();
        throw this.erro(this.simboloAtual(), mensagemDeErro);
    }
    verificarTipoSimboloAtual(tipo) {
        if (this.estaNoFinal())
            return false;
        return this.simboloAtual().tipo === tipo;
    }
    verificarTipoProximoSimbolo(tipo) {
        if (this.estaNoFinal())
            return false;
        return this.simbolos[this.atual + 1].tipo === tipo;
    }
    simboloAtual() {
        return this.simbolos[this.atual];
    }
    simboloAnterior() {
        return this.simbolos[this.atual - 1];
    }
    simboloNaPosicao(posicao) {
        return this.simbolos[this.atual + posicao];
    }
    estaNoFinal() {
        return this.atual >= this.simbolos.length;
    }
    avancarEDevolverAnterior() {
        if (!this.estaNoFinal())
            this.atual += 1;
        return this.simboloAnterior();
    }
    verificarSeSimboloAtualEIgualA(...argumentos) {
        for (let i = 0; i < argumentos.length; i++) {
            const tipoAtual = argumentos[i];
            if (this.verificarTipoSimboloAtual(tipoAtual)) {
                this.avancarEDevolverAnterior();
                return true;
            }
        }
        return false;
    }
    primario() {
        const simboloAtual = this.simbolos[this.atual];
        let valores = [];
        switch (simboloAtual.tipo) {
            case pitugues_1.default.COLCHETE_ESQUERDO:
                this.avancarEDevolverAnterior();
                if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.COLCHETE_DIREITO)) {
                    return new construtos_1.Vetor(this.hashArquivo, simboloAtual.linha, [], 0, 'qualquer[]');
                }
                while (!this.verificarSeSimboloAtualEIgualA(pitugues_1.default.COLCHETE_DIREITO)) {
                    const valor = this.atribuir();
                    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(this.hashArquivo, simboloAtual.linha, valores, valores.length, tipoVetor);
            case pitugues_1.default.CHAVE_ESQUERDA:
                this.avancarEDevolverAnterior();
                const chaves = [];
                if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.CHAVE_DIREITA)) {
                    return new construtos_1.Dicionario(this.hashArquivo, simboloAtual.linha, [], []);
                }
                while (!this.verificarSeSimboloAtualEIgualA(pitugues_1.default.CHAVE_DIREITA)) {
                    const chave = this.atribuir();
                    this.consumir(pitugues_1.default.DOIS_PONTOS, "Esperado ':' entre chave e valor.");
                    const valor = this.atribuir();
                    chaves.push(chave);
                    valores.push(valor);
                    if (this.simboloAtual().tipo !== pitugues_1.default.CHAVE_DIREITA) {
                        this.consumir(pitugues_1.default.VIRGULA, 'Esperado vírgula antes da próxima expressão.');
                    }
                }
                return new construtos_1.Dicionario(this.hashArquivo, simboloAtual.linha, chaves, valores);
            case pitugues_1.default.FALSO:
            case pitugues_1.default.VERDADEIRO:
                const simboloLogico = this.avancarEDevolverAnterior();
                return new construtos_1.Literal(this.hashArquivo, simboloAtual.linha, simboloLogico.tipo === pitugues_1.default.VERDADEIRO, 'lógico');
            case pitugues_1.default.FUNCAO:
            case pitugues_1.default.FUNÇÃO:
                const simboloFuncao = this.avancarEDevolverAnterior();
                const corpoDaFuncao = this.corpoDaFuncao(simboloFuncao.lexema);
                this.pilhaEscopos.definirInformacoesVariavel(simboloFuncao.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(simboloFuncao.lexema, 'função'));
                return corpoDaFuncao;
            case pitugues_1.default.IMPORTAR:
                return this.declaracaoImportar();
            case pitugues_1.default.NULO:
                this.avancarEDevolverAnterior();
                return new construtos_1.Literal(this.hashArquivo, simboloAtual.linha, null);
            case pitugues_1.default.ISTO:
                const simboloIsto = this.avancarEDevolverAnterior();
                return new construtos_1.Isto(this.hashArquivo, simboloAtual.linha, simboloIsto);
            case pitugues_1.default.LEIA:
                return this.expressaoLeia();
            case pitugues_1.default.NUMERO:
            case pitugues_1.default.TEXTO:
                const simboloLiteral = this.avancarEDevolverAnterior();
                const tipoInferido = (0, inferenciador_1.inferirTipoVariavel)(simboloLiteral.literal);
                const tipoDadosElementar = (0, inferenciador_1.tipoInferenciaParaTipoDadosElementar)(tipoInferido);
                return new construtos_1.Literal(this.hashArquivo, Number(simboloLiteral.linha), simboloLiteral.literal, tipoDadosElementar);
            case pitugues_1.default.IDENTIFICADOR:
                const simboloIdentificador = this.avancarEDevolverAnterior();
                let tipoOperando;
                if (simboloIdentificador.lexema in this.tiposDefinidosEmCodigo) {
                    tipoOperando = simboloIdentificador.lexema;
                }
                else {
                    try {
                        tipoOperando = this.pilhaEscopos.obterTipoVariavelPorNome(simboloIdentificador.lexema);
                    }
                    catch (erro) {
                        throw this.erro(simboloIdentificador, erro.message);
                    }
                }
                return new construtos_1.Variavel(this.hashArquivo, simboloIdentificador, tipoOperando);
            case pitugues_1.default.PARENTESE_ESQUERDO:
                this.avancarEDevolverAnterior();
                const expressao = this.expressao();
                this.consumir(pitugues_1.default.PARENTESE_DIREITO, "Esperado ')' após a expressão.");
                return new construtos_1.Agrupamento(this.hashArquivo, simboloAtual.linha, expressao);
            case pitugues_1.default.SUPER:
                const simboloSuper = this.avancarEDevolverAnterior();
                return new construtos_1.Super(this.hashArquivo, simboloSuper, this.superclasseAtual);
        }
        throw this.erro(this.simboloAtual(), 'Esperado expressão.');
    }
    finalizarChamada(entidadeChamada) {
        const argumentos = [];
        if (!this.verificarTipoSimboloAtual(pitugues_1.default.PARENTESE_DIREITO)) {
            do {
                if (argumentos.length >= 255) {
                    throw this.erro(this.simboloAtual(), 'Não pode haver mais de 255 argumentos.');
                }
                argumentos.push(this.expressao());
            } while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.VIRGULA));
        }
        this.consumir(pitugues_1.default.PARENTESE_DIREITO, "Esperado ')' após os argumentos.");
        return new construtos_1.Chamada(this.hashArquivo, 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(this.hashArquivo, expressao, nome);
            }
            else if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.COLCHETE_ESQUERDO)) {
                const indice = this.expressao();
                const simboloFechamento = this.consumir(pitugues_1.default.COLCHETE_DIREITO, "Esperado ']' após escrita do indice.");
                expressao = new construtos_1.AcessoIndiceVariavel(this.hashArquivo, expressao, indice, simboloFechamento);
            }
            else {
                break;
            }
        }
        return expressao;
    }
    unario() {
        if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.NEGACAO, pitugues_1.default.SUBTRACAO, pitugues_1.default.BIT_NOT)) {
            const operador = this.simboloAnterior();
            const direito = this.unario();
            return new construtos_1.Unario(this.hashArquivo, operador, direito);
        }
        return this.chamar();
    }
    exponenciacao() {
        let expressao = this.unario();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.EXPONENCIACAO)) {
            const operador = this.simboloAnterior();
            const direito = this.unario();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    multiplicar() {
        let expressao = this.exponenciacao();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.DIVISAO, pitugues_1.default.DIVISAO_INTEIRA, pitugues_1.default.MULTIPLICACAO, pitugues_1.default.MODULO)) {
            const operador = this.simboloAnterior();
            const direito = this.exponenciacao();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    adicaoOuSubtracao() {
        let expressao = this.multiplicar();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.SUBTRACAO, pitugues_1.default.ADICAO)) {
            const operador = this.simboloAnterior();
            const direito = this.multiplicar();
            expressao = new construtos_1.Binario(this.hashArquivo, 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.simboloAnterior();
            const direito = this.adicaoOuSubtracao();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    bitE() {
        let expressao = this.bitShift();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.BIT_AND)) {
            const operador = this.simboloAnterior();
            const direito = this.bitShift();
            expressao = new construtos_1.Binario(this.hashArquivo, 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.simboloAnterior();
            const direito = this.bitE();
            expressao = new construtos_1.Binario(this.hashArquivo, 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.simboloAnterior();
            const direito = this.bitOu();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    comparacaoIgualdade() {
        let expressao = this.comparar();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.DIFERENTE, pitugues_1.default.IGUAL_IGUAL)) {
            const operador = this.simboloAnterior();
            const direito = this.comparar();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    em() {
        let expressao = this.comparacaoIgualdade();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.EM)) {
            const operador = this.simboloAnterior();
            const direito = this.comparacaoIgualdade();
            expressao = new construtos_1.Logico(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    e() {
        let expressao = this.em();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.E)) {
            const operador = this.simboloAnterior();
            const direito = this.em();
            expressao = new construtos_1.Logico(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    ou() {
        let expressao = this.e();
        while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.OU)) {
            const operador = this.simboloAnterior();
            const direito = this.e();
            expressao = new construtos_1.Logico(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    atribuir() {
        const expressao = this.ou();
        if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.IGUAL) ||
            this.verificarSeSimboloAtualEIgualA(pitugues_1.default.MAIS_IGUAL)) {
            const igual = this.simboloAnterior();
            const valor = this.atribuir();
            if (expressao instanceof construtos_1.Variavel) {
                return new construtos_1.Atribuir(this.hashArquivo, expressao, valor);
            }
            if (expressao instanceof construtos_1.AcessoMetodoOuPropriedade) {
                return new construtos_1.DefinirValor(this.hashArquivo, 0, expressao.objeto, expressao.simbolo, valor);
            }
            if (expressao instanceof construtos_1.AcessoIndiceVariavel) {
                return new construtos_1.AtribuicaoPorIndice(this.hashArquivo, 0, expressao.entidadeChamada, expressao.indice, valor);
            }
            throw this.erro(igual, 'Tarefa de atribuição inválida');
        }
        return expressao;
    }
    // TODO: Depreciar.
    expressao() {
        return this.atribuir();
    }
    declaracaoEscreva() {
        const simboloAtual = this.simboloAtual();
        this.consumir(pitugues_1.default.PARENTESE_ESQUERDO, "Esperado '(' antes dos valores em escreva.");
        const argumentos = [];
        do {
            argumentos.push(this.expressao());
        } while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.VIRGULA));
        this.consumir(pitugues_1.default.PARENTESE_DIREITO, "Esperado ')' após os valores em escreva.");
        return new declaracoes_1.Escreva(Number(simboloAtual.linha), simboloAtual.hashArquivo, argumentos);
    }
    declaracaoExpressao() {
        const expressao = this.expressao();
        return new declaracoes_1.Expressao(expressao);
    }
    blocoEscopo() {
        this.pilhaEscopos.empilhar(new informacao_escopo_1.InformacaoEscopo());
        let declaracoes = [];
        let simboloAtual = this.simboloAtual();
        const simboloAnterior = this.simboloAnterior();
        // Situação 1: não tem bloco de escopo.
        //
        // Exemplo: `se verdadeiro: escreva('Alguma coisa')`.
        // Neste caso, linha do símbolo atual é igual à linha do símbolo anterior.
        if (simboloAtual.linha === simboloAnterior.linha) {
            declaracoes.push(this.resolverDeclaracaoForaDeBloco());
        }
        else {
            // Situação 2: símbolo atual fica na próxima linha.
            //
            // Verifica-se o número de espaços à esquerda da linha através dos pragmas.
            // Se número de espaços da linha do símbolo atual é menor ou igual ao número de espaços
            // da linha anterior, e bloco ainda não começou, é uma situação de erro.
            let espacosIndentacaoLinhaAtual = this.pragmas[simboloAtual.linha].espacosIndentacao;
            const espacosIndentacaoLinhaAnterior = this.pragmas[simboloAnterior.linha].espacosIndentacao;
            if (espacosIndentacaoLinhaAtual <= espacosIndentacaoLinhaAnterior) {
                throw this.erro(simboloAtual, `Indentação inconsistente na linha ${simboloAtual.linha}. ` +
                    `Esperado: >= ${espacosIndentacaoLinhaAnterior}. ` +
                    `Atual: ${espacosIndentacaoLinhaAtual}`);
            }
            // Indentação ok, é um bloco de escopo.
            // Inclui todas as declarações cujas linhas tenham o mesmo número de espaços
            // de indentação do bloco.
            // Se `simboloAtual` for definido em algum momento como indefinido,
            // Significa que o código acabou, então o bloco também acabou.
            const espacosIndentacaoBloco = espacosIndentacaoLinhaAtual;
            while (espacosIndentacaoLinhaAtual === espacosIndentacaoBloco) {
                const retornoDeclaracao = this.resolverDeclaracaoForaDeBloco();
                if (Array.isArray(retornoDeclaracao)) {
                    declaracoes = declaracoes.concat(retornoDeclaracao);
                }
                else {
                    declaracoes.push(retornoDeclaracao);
                }
                simboloAtual = this.simboloAtual();
                if (!simboloAtual)
                    break;
                espacosIndentacaoLinhaAtual = this.pragmas[simboloAtual.linha].espacosIndentacao;
            }
        }
        this.pilhaEscopos.removerUltimo();
        return declaracoes;
    }
    declaracaoEnquanto() {
        try {
            this.blocos += 1;
            const condicao = this.expressao();
            const bloco = this.resolverDeclaracao();
            return new declaracoes_1.Enquanto(condicao, bloco);
        }
        finally {
            this.blocos -= 1;
        }
    }
    declaracaoEscolha() {
        try {
            this.blocos += 1;
            const condicao = this.expressao();
            this.consumir(pitugues_1.default.DOIS_PONTOS, "Esperado ':' após 'escolha'.");
            const caminhos = [];
            let caminhoPadrao = null;
            while (!this.estaNoFinal() &&
                [pitugues_1.default.CASO, pitugues_1.default.PADRAO].includes(this.simbolos[this.atual].tipo)) {
                if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.CASO)) {
                    const caminhoCondicoes = [this.expressao()];
                    this.consumir(pitugues_1.default.DOIS_PONTOS, "Esperado ':' após o 'caso'.");
                    while (this.verificarTipoSimboloAtual(pitugues_1.default.CASO)) {
                        this.consumir(pitugues_1.default.CASO, null);
                        caminhoCondicoes.push(this.expressao());
                        this.consumir(pitugues_1.default.DOIS_PONTOS, "Esperado ':' após declaração do 'caso'.");
                    }
                    // Como dois-pontos é um símbolo usado para conferir se há um início de bloco,
                    // não podemos simplesmente chamar `this.resolverDeclaracao()` porque o dois-pontos já
                    // foi consumido na verificação.
                    // Outro problema é que, aparentemente, o Interpretador não espera um Bloco, e sim
                    // um vetor de Declaracao, o qual obtemos com `this.blocoEscopo()`.
                    const declaracoes = this.blocoEscopo();
                    caminhos.push({
                        condicoes: caminhoCondicoes,
                        declaracoes,
                    });
                }
                else if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.PADRAO)) {
                    if (caminhoPadrao !== null) {
                        const excecao = new erro_avaliador_sintatico_1.ErroAvaliadorSintatico(this.simboloAtual(), "Você só pode ter um caminho padrão em cada declaração de 'escolha'.");
                        this.erros.push(excecao);
                        throw excecao;
                    }
                    this.consumir(pitugues_1.default.DOIS_PONTOS, "Esperado ':' após declaração do 'padrao'.");
                    // Como dois-pontos é um símbolo usado para conferir se há um início de bloco,
                    // não podemos simplesmente chamar `this.resolverDeclaracao()` porque o dois-pontos já
                    // foi consumido na verificação.
                    // Outro problema é que, aparentemente, o Interpretador não espera um Bloco, e sim
                    // um vetor de Declaracao, o qual obtemos com `this.blocoEscopo()`.
                    const declaracoes = this.blocoEscopo();
                    caminhoPadrao = {
                        declaracoes,
                    };
                }
            }
            return new declaracoes_1.Escolha(condicao, caminhos, caminhoPadrao);
        }
        finally {
            this.blocos -= 1;
        }
    }
    declaracaoParaCada(simboloPara) {
        const nomeVariavelIteracao = this.consumir(pitugues_1.default.IDENTIFICADOR, "Esperado identificador de variável de iteração para instrução 'para cada'.");
        if (!this.verificarSeSimboloAtualEIgualA(pitugues_1.default.DE, pitugues_1.default.EM)) {
            throw this.erro(this.simbolos[this.atual], "Esperado palavras reservadas 'em' ou 'de' após variável de iteração em instrução 'para cada'.");
        }
        const vetor = this.expressao();
        if (!vetor.hasOwnProperty('tipo')) {
            throw this.erro(simboloPara, `Variável ou constante em 'para cada' não parece possuir um tipo iterável.`);
        }
        const tipoVetor = vetor.tipo;
        if (!tipoVetor.endsWith('[]') && !['qualquer', 'vetor'].includes(tipoVetor)) {
            throw this.erro(simboloPara, `Variável ou constante em 'para cada' não é iterável. Tipo resolvido: ${tipoVetor}.`);
        }
        this.pilhaEscopos.definirInformacoesVariavel(nomeVariavelIteracao.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(nomeVariavelIteracao.lexema, tipoVetor.slice(0, -2)));
        // TODO: Talvez não seja uma ideia melhor chamar o método de `Bloco` aqui?
        const corpo = this.resolverDeclaracao();
        return new declaracoes_1.ParaCada(this.hashArquivo, Number(simboloPara.linha), new construtos_1.Variavel(this.hashArquivo, nomeVariavelIteracao), vetor, corpo);
    }
    declaracaoParaTradicional(simboloPara) {
        let inicializador;
        if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.PONTO_E_VIRGULA)) {
            inicializador = null;
        }
        else if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.VARIAVEL)) {
            inicializador = this.declaracaoDeVariaveis();
        }
        else {
            inicializador = this.declaracaoExpressao();
        }
        let condicao = null;
        if (!this.verificarTipoSimboloAtual(pitugues_1.default.PONTO_E_VIRGULA)) {
            condicao = this.expressao();
        }
        let incrementar = null;
        if (this.simbolos[this.atual].tipo !== pitugues_1.default.DOIS_PONTOS) {
            incrementar = this.expressao();
        }
        const corpo = this.resolverDeclaracao();
        return new declaracoes_1.Para(this.hashArquivo, Number(simboloPara.linha), inicializador, condicao, incrementar, corpo);
    }
    declaracaoPara() {
        try {
            const simboloPara = this.simboloAnterior();
            this.blocos += 1;
            if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.CADA)) {
                return this.declaracaoParaCada(simboloPara);
            }
            return this.declaracaoParaTradicional(simboloPara);
        }
        catch (erro) {
            throw erro;
        }
        finally {
            this.blocos -= 1;
        }
    }
    declaracaoSe() {
        const condicao = this.expressao();
        const caminhoEntao = this.resolverDeclaracao();
        let caminhoSenao = null;
        if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.SENAO, pitugues_1.default.SENÃO)) {
            caminhoSenao = this.resolverDeclaracao();
        }
        return new declaracoes_1.Se(condicao, caminhoEntao, [], caminhoSenao);
    }
    declaracaoSustar() {
        if (this.blocos < 1) {
            throw this.erro(this.simboloAnterior(), "'sustar' deve estar dentro de um laço de repetição.");
        }
        return new declaracoes_1.Sustar(this.simboloAtual());
    }
    declaracaoContinua() {
        if (this.blocos < 1) {
            throw this.erro(this.simboloAnterior(), "'continua' precisa estar em um laço de repetição.");
        }
        return new declaracoes_1.Continua(this.simboloAtual());
    }
    declaracaoRetorna() {
        const palavraChave = this.simboloAnterior();
        let valor = null;
        if (!this.verificarTipoSimboloAtual(pitugues_1.default.PONTO_E_VIRGULA)) {
            valor = this.expressao();
        }
        return new declaracoes_1.Retorna(palavraChave, valor);
    }
    declaracaoImportar() {
        this.avancarEDevolverAnterior();
        this.consumir(pitugues_1.default.PARENTESE_ESQUERDO, "Esperado '(' após declaração.");
        const caminho = this.expressao();
        this.consumir(pitugues_1.default.PARENTESE_DIREITO, "Esperado ')' após declaração.");
        return new declaracoes_1.Importar(caminho);
    }
    declaracaoTente() {
        const simboloTente = this.simboloAnterior();
        this.consumir(pitugues_1.default.DOIS_PONTOS, "Esperado ':' após a declaração 'tente'.");
        const blocoTente = this.blocoEscopo();
        let blocoPegue = null;
        if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.PEGUE)) {
            this.consumir(pitugues_1.default.DOIS_PONTOS, "Esperado ':' após a declaração 'pegue'.");
            blocoPegue = this.blocoEscopo();
        }
        let blocoSenao = null;
        if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.SENAO, pitugues_1.default.SENÃO)) {
            this.consumir(pitugues_1.default.DOIS_PONTOS, "Esperado ':' após a declaração 'senão'.");
            blocoSenao = this.blocoEscopo();
        }
        let blocoFinalmente = null;
        if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.FINALMENTE)) {
            this.consumir(pitugues_1.default.DOIS_PONTOS, "Esperado ':' após a declaração 'pegue'.");
            blocoFinalmente = this.blocoEscopo();
        }
        return new declaracoes_1.Tente(simboloTente.hashArquivo, Number(simboloTente.linha), blocoTente, blocoPegue, blocoSenao, blocoFinalmente);
    }
    declaracaoFazer() {
        const simboloFazer = this.simboloAnterior();
        try {
            this.blocos += 1;
            const declaracaoOuBlocoFazer = this.resolverDeclaracao();
            this.consumir(pitugues_1.default.ENQUANTO, "Esperado declaração do 'enquanto' após o escopo da declaração 'fazer'.");
            const condicaoEnquanto = this.expressao();
            return new declaracoes_1.Fazer(simboloFazer.hashArquivo, Number(simboloFazer.linha), declaracaoOuBlocoFazer, condicaoEnquanto);
        }
        finally {
            this.blocos -= 1;
        }
    }
    resolverDeclaracao() {
        switch (this.simbolos[this.atual].tipo) {
            case pitugues_1.default.CONSTANTE:
                this.avancarEDevolverAnterior();
                return this.declaracaoDeConstantes();
            case pitugues_1.default.CONTINUA:
                this.avancarEDevolverAnterior();
                return this.declaracaoContinua();
            case pitugues_1.default.DOIS_PONTOS:
                this.avancarEDevolverAnterior();
                const simboloInicioBloco = this.simboloAnterior();
                return new declaracoes_1.Bloco(simboloInicioBloco.hashArquivo, Number(simboloInicioBloco.linha), this.blocoEscopo());
            case pitugues_1.default.ENQUANTO:
                this.avancarEDevolverAnterior();
                return this.declaracaoEnquanto();
            case pitugues_1.default.ESCOLHA:
                this.avancarEDevolverAnterior();
                return this.declaracaoEscolha();
            case pitugues_1.default.IMPRIMA:
            case pitugues_1.default.ESCREVA:
                this.avancarEDevolverAnterior();
                return this.declaracaoEscreva();
            case pitugues_1.default.FALHAR:
                this.avancarEDevolverAnterior();
                return this.declaracaoFalhar();
            case pitugues_1.default.FAZER:
                this.avancarEDevolverAnterior();
                return this.declaracaoFazer();
            case pitugues_1.default.PARA:
                this.avancarEDevolverAnterior();
                return this.declaracaoPara();
            case pitugues_1.default.SUSTAR:
                this.avancarEDevolverAnterior();
                return this.declaracaoSustar();
            case pitugues_1.default.SE:
                this.avancarEDevolverAnterior();
                return this.declaracaoSe();
            case pitugues_1.default.RETORNA:
                this.avancarEDevolverAnterior();
                return this.declaracaoRetorna();
            case pitugues_1.default.TENTE:
                this.avancarEDevolverAnterior();
                return this.declaracaoTente();
            case pitugues_1.default.VARIAVEL:
                this.avancarEDevolverAnterior();
                return this.declaracaoDeVariaveis();
        }
        return this.declaracaoExpressao();
    }
    funcao(tipo, construtor) {
        const simbolo = !construtor
            ? this.consumir(pitugues_1.default.IDENTIFICADOR, `Esperado nome ${tipo}.`)
            : new lexador_1.Simbolo(pitugues_1.default.CONSTRUTOR, 'construtor', null, -1, -1);
        // Se houver chamadas recursivas à função, precisamos definir um tipo
        // para ela. Vai ser atualizado após avaliação do corpo da função.
        this.pilhaEscopos.definirInformacoesVariavel(simbolo.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(simbolo.lexema, 'qualquer'));
        const corpoDaFuncao = this.corpoDaFuncao(tipo);
        const tipoDaFuncao = `função<${corpoDaFuncao.tipo}>`;
        this.pilhaEscopos.definirInformacoesVariavel(simbolo.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(simbolo.lexema, tipoDaFuncao));
        const funcaoDeclaracao = new declaracoes_1.FuncaoDeclaracao(simbolo, corpoDaFuncao, tipoDaFuncao);
        this.pilhaEscopos.registrarReferenciaFuncao(simbolo.lexema, funcaoDeclaracao);
        return funcaoDeclaracao;
    }
    logicaComumParametros() {
        const parametros = [];
        do {
            if (parametros.length >= 255) {
                throw this.erro(this.simboloAtual(), 'Função não pode ter mais de 255 parâmetros.');
            }
            const parametro = {};
            if (this.simboloAtual().tipo === pitugues_1.default.MULTIPLICACAO) {
                this.consumir(pitugues_1.default.MULTIPLICACAO, null);
                parametro.abrangencia = 'multiplo';
            }
            else {
                parametro.abrangencia = 'padrao';
            }
            parametro.nome = this.consumir(pitugues_1.default.IDENTIFICADOR, 'Esperado nome do parâmetro.');
            if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.IGUAL)) {
                parametro.valorPadrao = this.primario();
            }
            this.pilhaEscopos.definirInformacoesVariavel(parametro.nome.lexema, new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante(parametro.nome.lexema, parametro.tipoDado || 'qualquer'));
            parametros.push(parametro);
            if (parametro.abrangencia === 'multiplo')
                break;
        } while (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.VIRGULA));
        return parametros;
    }
    corpoDaFuncao(tipo) {
        this.consumir(pitugues_1.default.PARENTESE_ESQUERDO, `Esperado '(' após o nome ${tipo}.`);
        let parametros = [];
        if (!this.verificarTipoSimboloAtual(pitugues_1.default.PARENTESE_DIREITO)) {
            parametros = this.logicaComumParametros();
        }
        this.consumir(pitugues_1.default.PARENTESE_DIREITO, "Esperado ')' após parâmetros.");
        this.consumir(pitugues_1.default.DOIS_PONTOS, `Esperado ':' antes do escopo do ${tipo}.`);
        const corpo = this.blocoEscopo();
        return new construtos_1.FuncaoConstruto(this.hashArquivo, 0, parametros, corpo);
    }
    declaracaoDeClasse() {
        const simbolo = this.consumir(pitugues_1.default.IDENTIFICADOR, 'Esperado nome da classe.');
        let superClasse = null;
        if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.HERDA)) {
            const simboloSuperclasse = this.consumir(pitugues_1.default.IDENTIFICADOR, 'Esperado nome da Superclasse.');
            this.superclasseAtual = simboloSuperclasse.lexema;
            superClasse = new construtos_1.Variavel(this.hashArquivo, this.simboloAnterior());
        }
        this.consumir(pitugues_1.default.DOIS_PONTOS, "Esperado ':' antes do escopo da classe.");
        const metodos = [];
        while (!this.estaNoFinal() &&
            this.verificarSeSimboloAtualEIgualA(pitugues_1.default.CONSTRUTOR, pitugues_1.default.FUNCAO, pitugues_1.default.FUNÇÃO)) {
            metodos.push(this.funcao('método', this.simbolos[this.atual - 1].tipo === pitugues_1.default.CONSTRUTOR));
        }
        this.superclasseAtual = undefined;
        return new declaracoes_1.Classe(simbolo, superClasse, metodos);
    }
    declaracaoFalhar() {
        const simboloFalha = this.simbolos[this.atual - 1];
        const textoFalha = this.consumir(pitugues_1.default.TEXTO, 'Esperado texto para explicar falha.');
        return new declaracoes_1.Falhar(simboloFalha, textoFalha.literal);
    }
    /**
     * Consome o símbolo atual, verificando se é uma declaração de função, variável, classe
     * ou uma expressão.
     * @returns Objeto do tipo `Declaracao`.
     */
    resolverDeclaracaoForaDeBloco() {
        try {
            if ((this.verificarTipoSimboloAtual(pitugues_1.default.FUNCAO) ||
                this.verificarTipoSimboloAtual(pitugues_1.default.FUNÇÃO)) &&
                this.verificarTipoProximoSimbolo(pitugues_1.default.IDENTIFICADOR)) {
                this.avancarEDevolverAnterior();
                return this.funcao('funcao');
            }
            if (this.verificarSeSimboloAtualEIgualA(pitugues_1.default.CLASSE))
                return this.declaracaoDeClasse();
            return this.resolverDeclaracao();
        }
        catch (erro) {
            this.sincronizar();
            return null;
        }
    }
    /**
     * Inicializa o primeiro nível da pilha de escopos, normalmente com ítens da biblioteca global.
     * É separada da inicialização do avaliador sintático, pois é necessário manipular essa
     * inicialização de outra forma em `delegua-node`.
     */
    inicializarPilhaEscopos() {
        this.pilhaEscopos = new pilha_escopos_1.PilhaEscopos();
        this.pilhaEscopos.empilhar(new informacao_escopo_1.InformacaoEscopo());
        // Funções nativas de Delégua (e de Pituguês também, por enquanto)
        this.pilhaEscopos.definirInformacoesVariavel('aleatorio', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('aleatorio', 'número'));
        this.pilhaEscopos.definirInformacoesVariavel('aleatorioEntre', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('aleatorioEntre', 'número', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('minimo', 'número'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('maximo', 'número'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('algum', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('algum', 'lógico', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoPesquisa', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('encontrar', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('encontrar', 'qualquer', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoPesquisa', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('encontrarIndice', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('encontrarIndice', 'inteiro', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoPesquisa', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('encontrarUltimo', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('encontrarUltimo', 'inteiro', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoPesquisa', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('encontrarUltimoIndice', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('encontrarUltimoIndice', 'inteiro', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoPesquisa', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('filtrarPor', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('filtrarPor', 'qualquer[]', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoFiltragem', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('incluido', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('incluido', 'lógico', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valor', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('inteiro', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('inteiro', 'inteiro', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valor', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('mapear', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('mapear', 'qualquer[]', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoMapeamento', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('numero', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('número', 'número', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valorParaConverter', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('número', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('número', 'número', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valorParaConverter', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('ordenar', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('ordenar', 'qualquer[]', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoOrdenacao', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('paraCada', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('paraCada', 'qualquer[]', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoFiltragem', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('primeiroEmCondicao', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('primeiroEmCondicao', 'qualquer', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoFiltragem', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('real', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('real', 'número', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valorParaConverter', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('reduzir', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('reduzir', 'qualquer', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoReducao', 'função'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valorInicial', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('tamanho', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('tamanho', 'inteiro', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('objeto', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('texto', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('texto', 'texto', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('valorParaConverter', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('todosEmCondicao', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('todosEmCondicao', 'lógico', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('funcaoCondicional', 'função'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('tupla', new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('tupla', 'tupla', true, [
            new informacao_variavel_ou_constante_1.InformacaoVariavelOuConstante('vetor', 'qualquer[]'),
        ]));
    }
    analisar(retornoLexador, hashArquivo) {
        const inicioAnalise = (0, browser_process_hrtime_1.default)();
        this.erros = [];
        this.atual = 0;
        this.blocos = 0;
        this.escopos = [];
        this.inicializarPilhaEscopos();
        this.tiposDefinidosEmCodigo = {};
        this.hashArquivo = hashArquivo || 0;
        this.simbolos = (retornoLexador === null || retornoLexador === void 0 ? void 0 : retornoLexador.simbolos) || [];
        this.pragmas = (retornoLexador === null || retornoLexador === void 0 ? void 0 : retornoLexador.pragmas) || {};
        let declaracoes = [];
        while (!this.estaNoFinal()) {
            const retornoDeclaracao = this.resolverDeclaracaoForaDeBloco();
            if (Array.isArray(retornoDeclaracao)) {
                declaracoes = declaracoes.concat(retornoDeclaracao);
            }
            else {
                declaracoes.push(retornoDeclaracao);
            }
        }
        if (this.performance) {
            const deltaAnalise = (0, browser_process_hrtime_1.default)(inicioAnalise);
            // eslint-disable-next-line no-undef
            console.log(`[Avaliador Sintático] Tempo para análise: ${deltaAnalise[0] * 1e9 + deltaAnalise[1]}ns`);
        }
        return {
            declaracoes: declaracoes,
            erros: this.erros,
        };
    }
}
exports.AvaliadorSintaticoPitugues = AvaliadorSintaticoPitugues;
//# sourceMappingURL=avaliador-sintatico-pitugues.js.map