UNPKG

@designliquido/delegua

Version:

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

970 lines 53.2 kB
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AvaliadorSintaticoPrisma = void 0;
const browser_process_hrtime_1 = __importDefault(require("browser-process-hrtime"));
const construtos_1 = require("../../construtos");
const declaracoes_1 = require("../../declaracoes");
const avaliador_sintatico_base_1 = require("../avaliador-sintatico-base");
const erro_avaliador_sintatico_1 = require("../erro-avaliador-sintatico");
const inferenciador_1 = require("../../inferenciador");
const pilha_escopos_1 = require("../pilha-escopos");
const informacao_escopo_1 = require("../informacao-escopo");
const comum_1 = require("../comum");
const informacao_elemento_sintatico_1 = require("../../informacao-elemento-sintatico");
const lexador_1 = require("../../lexador");
const prisma_1 = __importDefault(require("../../tipos-de-simbolos/prisma"));
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"));
/**
 * 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.
 *
 * Este avaliador sintático é específico para o dialeto Prisma da linguagem Delégua.
 */
class AvaliadorSintaticoPrisma extends avaliador_sintatico_base_1.AvaliadorSintaticoBase {
    constructor(performance = false) {
        super();
        this.atual = 0;
        this.blocos = 0;
        this.performance = performance;
        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);
    }
    sincronizar() {
        this.avancarEDevolverAnterior();
        while (!this.estaNoFinal()) {
            switch (this.simbolos[this.atual].tipo) {
                case prisma_1.default.CLASSE:
                case prisma_1.default.FUNCAO:
                case prisma_1.default.FUNÇÃO:
                case prisma_1.default.LOCAL:
                case prisma_1.default.PARA:
                case prisma_1.default.SE:
                case prisma_1.default.ENQUANTO:
                case prisma_1.default.IMPRIMA:
                case prisma_1.default.RETORNE:
                    return;
            }
            this.avancarEDevolverAnterior();
        }
    }
    consumir(tipo, mensagemDeErro) {
        if (this.verificarTipoSimboloAtual(tipo))
            return this.avancarEDevolverAnterior();
        let simboloErro = this.simbolos[this.atual];
        if (this.simbolos.length === 0) {
            simboloErro = {
                hashArquivo: this.hashArquivo,
                linha: 1,
            };
        }
        else if (this.atual >= this.simbolos.length) {
            simboloErro = this.simbolos[this.simbolos.length - 1];
        }
        throw this.erro(simboloErro, mensagemDeErro);
    }
    simboloNaPosicao(posicao) {
        return this.simbolos[this.atual + posicao];
    }
    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;
    }
    async primario() {
        var _a;
        const simboloAtual = this.simbolos[this.atual];
        let valores = [];
        switch (simboloAtual.tipo) {
            case prisma_1.default.COLCHETE_ESQUERDO:
                this.avancarEDevolverAnterior();
                switch (this.simbolos[this.atual].tipo) {
                    case prisma_1.default.COLCHETE_ESQUERDO: // Texto multilinhas
                        return this.construtoTextoMultilinhas();
                    default:
                        throw this.erro(simboloAtual, 'Terminar.');
                }
            case prisma_1.default.CHAVE_ESQUERDA:
                // Prisma tem o conceito de tabela, que não é exatamente um dicionário, mas é próximo.
                // Aqui, vamos tratar como dicionário para simplificar.
                this.avancarEDevolverAnterior();
                const chaves = [];
                if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.CHAVE_DIREITA)) {
                    return new construtos_1.Dicionario(this.hashArquivo, simboloAtual.linha, [], []);
                }
                let indice = 1;
                do {
                    let chave;
                    if (this.verificarTipoSimboloAtual(prisma_1.default.IDENTIFICADOR) &&
                        ((_a = this.simbolos[this.atual + 1]) === null || _a === void 0 ? void 0 : _a.tipo) === prisma_1.default.IGUAL) {
                        // Chave nomeada: {nome = "João"}
                        const chaveIdentificador = this.avancarEDevolverAnterior();
                        this.avancarEDevolverAnterior(); // consume IGUAL
                        chave = new construtos_1.Literal(this.hashArquivo, simboloAtual.linha, chaveIdentificador.lexema);
                    }
                    else {
                        chave = new construtos_1.Literal(this.hashArquivo, simboloAtual.linha, String(indice));
                    }
                    const valor = await this.ou();
                    chaves.push(chave);
                    valores.push(valor);
                    indice++;
                } while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.VIRGULA));
                this.consumir(prisma_1.default.CHAVE_DIREITA, `Esperado fechamento de chave em tabela.`);
                return new construtos_1.Dicionario(this.hashArquivo, simboloAtual.linha, chaves, valores);
            case prisma_1.default.FALSO:
            case prisma_1.default.VERDADEIRO:
                const simboloLogico = this.avancarEDevolverAnterior();
                return new construtos_1.Literal(this.hashArquivo, simboloAtual.linha, simboloLogico.tipo === prisma_1.default.VERDADEIRO, 'lógico');
            case prisma_1.default.FUNCAO:
            case prisma_1.default.FUNÇÃO:
                const simboloFuncao = this.avancarEDevolverAnterior();
                const corpoDaFuncao = await this.corpoDaFuncao(simboloFuncao.lexema);
                this.pilhaEscopos.definirInformacoesVariavel(simboloFuncao.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(simboloFuncao.lexema, 'função'));
                return corpoDaFuncao;
            case prisma_1.default.IMPORTAR:
                return this.expressaoImportar();
            case prisma_1.default.NULO:
                this.avancarEDevolverAnterior();
                return new construtos_1.Literal(this.hashArquivo, simboloAtual.linha, null);
            case prisma_1.default.ISTO:
                const simboloIsto = this.avancarEDevolverAnterior();
                return new construtos_1.Isto(this.hashArquivo, simboloAtual.linha, simboloIsto);
            case prisma_1.default.LEIA:
                return this.expressaoLeia();
            case prisma_1.default.NUMERO:
            case prisma_1.default.TEXTO:
                const simboloLiteral = this.avancarEDevolverAnterior();
                const tipoInferido = (0, inferenciador_1.inferirTipoVariavel)(simboloLiteral.literal);
                return new construtos_1.Literal(this.hashArquivo, Number(simboloLiteral.linha), simboloLiteral.literal, tipoInferido);
            case prisma_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 prisma_1.default.PARENTESE_ESQUERDO:
                this.avancarEDevolverAnterior();
                const expressao = await this.expressao();
                this.consumir(prisma_1.default.PARENTESE_DIREITO, "Esperado ')' após a expressão.");
                return new construtos_1.Agrupamento(this.hashArquivo, simboloAtual.linha, expressao);
            case prisma_1.default.SUPER:
                const simboloSuper = this.avancarEDevolverAnterior();
                return new construtos_1.Super(this.hashArquivo, simboloSuper, this.superclasseAtual);
        }
        throw this.erro(this.simbolos[this.atual], 'Esperado expressão.');
    }
    async expressaoImportar() {
        this.avancarEDevolverAnterior();
        this.consumir(prisma_1.default.PARENTESE_ESQUERDO, "Esperado '(' após declaração.");
        const caminho = await this.expressao();
        this.consumir(prisma_1.default.PARENTESE_DIREITO, "Esperado ')' após declaração.");
        return new construtos_1.ImportarComoConstruto(caminho);
    }
    /**
     * Construto para texto multilinhas.
     * @returns
     */
    construtoTextoMultilinhas() {
        const segundoColchete = this.consumir(prisma_1.default.COLCHETE_ESQUERDO, "Esperado '[' antes do texto multilinhas.");
        let texto = '';
        let linha = segundoColchete.linha;
        while (!this.verificarSeSimboloAtualEIgualA(prisma_1.default.COLCHETE_DIREITO)) {
            texto += this.simbolos[this.atual].lexema + ' ';
            if (this.simbolos[this.atual].linha !== linha) {
                texto += '\n';
                linha = this.simbolos[this.atual].linha;
            }
            this.avancarEDevolverAnterior();
        }
        this.consumir(prisma_1.default.COLCHETE_DIREITO, "Esperado ']' após o texto multilinhas.");
        return new construtos_1.Literal(this.hashArquivo, segundoColchete.linha, texto);
    }
    async expressaoLeia() {
        const simboloLeia = this.avancarEDevolverAnterior();
        this.consumir(prisma_1.default.PARENTESE_ESQUERDO, "Esperado '(' antes dos valores em leia.");
        const argumentos = [];
        if (!this.verificarTipoSimboloAtual(prisma_1.default.PARENTESE_DIREITO)) {
            do {
                argumentos.push(await this.expressao());
            } while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.VIRGULA));
        }
        this.consumir(prisma_1.default.PARENTESE_DIREITO, "Esperado ')' após os valores em leia.");
        return new construtos_1.Leia(simboloLeia, argumentos);
    }
    async finalizarChamada(entidadeChamada) {
        const argumentos = [];
        if (!this.verificarTipoSimboloAtual(prisma_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(await this.expressao());
            } while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.VIRGULA));
        }
        this.consumir(prisma_1.default.PARENTESE_DIREITO, "Esperado ')' após os argumentos.");
        return new construtos_1.Chamada(this.hashArquivo, entidadeChamada, argumentos);
    }
    async chamar() {
        let expressao = await this.primario();
        while (true) {
            if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.PARENTESE_ESQUERDO)) {
                expressao = await this.finalizarChamada(expressao);
            }
            else if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.PONTO)) {
                const nome = this.consumir(prisma_1.default.IDENTIFICADOR, "Esperado nome do método após '.'.");
                expressao = new construtos_1.AcessoMetodoOuPropriedade(this.hashArquivo, expressao, nome);
            }
            else if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.COLCHETE_ESQUERDO)) {
                const indice = await this.expressao();
                const simboloFechamento = this.consumir(prisma_1.default.COLCHETE_DIREITO, "Esperado ']' após escrita do indice.");
                expressao = new construtos_1.AcessoIndiceVariavel(this.hashArquivo, expressao, indice, simboloFechamento);
            }
            else {
                break;
            }
        }
        return expressao;
    }
    async unario() {
        if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.NEGACAO, prisma_1.default.SUBTRACAO, prisma_1.default.BIT_NOT, prisma_1.default.NAO, prisma_1.default.COMPRIMENTO)) {
            const operador = this.simboloAnterior();
            const direito = await this.unario();
            return new construtos_1.Unario(this.hashArquivo, operador, direito);
        }
        return await this.chamar();
    }
    async exponenciacao() {
        let expressao = await this.unario();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.EXPONENCIACAO)) {
            const operador = this.simboloAnterior();
            const direito = await this.unario();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async multiplicar() {
        let expressao = await this.exponenciacao();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.DIVISAO, prisma_1.default.DIVISAO_INTEIRA, prisma_1.default.MULTIPLICACAO, prisma_1.default.MODULO)) {
            const operador = this.simboloAnterior();
            const direito = await this.exponenciacao();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async adicaoOuSubtracao() {
        let expressao = await this.multiplicar();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.SUBTRACAO, prisma_1.default.ADICAO)) {
            const operador = this.simboloAnterior();
            const direito = await this.multiplicar();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async concatenacao() {
        let expressao = await this.adicaoOuSubtracao();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.CONCATENACAO)) {
            const operador = this.simboloAnterior();
            const direito = await this.adicaoOuSubtracao();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async bitShift() {
        let expressao = await this.concatenacao();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.MENOR_MENOR, prisma_1.default.MAIOR_MAIOR)) {
            const operador = this.simboloAnterior();
            const direito = await this.adicaoOuSubtracao();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async bitE() {
        let expressao = await this.bitShift();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.BIT_AND)) {
            const operador = this.simboloAnterior();
            const direito = await this.bitShift();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async bitOu() {
        let expressao = await this.bitE();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.BIT_OR, prisma_1.default.BIT_XOR)) {
            const operador = this.simboloAnterior();
            const direito = await this.bitE();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async comparar() {
        let expressao = await this.bitOu();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.MAIOR, prisma_1.default.MAIOR_IGUAL, prisma_1.default.MENOR, prisma_1.default.MENOR_IGUAL)) {
            const operador = this.simboloAnterior();
            const direito = await this.bitOu();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async comparacaoIgualdade() {
        let expressao = await this.comparar();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.DIFERENTE, prisma_1.default.IGUAL_IGUAL)) {
            const operador = this.simboloAnterior();
            const direito = await this.comparar();
            expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async em() {
        let expressao = await this.comparacaoIgualdade();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.EM)) {
            const operador = this.simboloAnterior();
            const direito = await this.comparacaoIgualdade();
            expressao = new construtos_1.Logico(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async e() {
        let expressao = await this.em();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.E)) {
            const operador = this.simboloAnterior();
            const direito = await this.em();
            expressao = new construtos_1.Logico(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async ou() {
        let expressao = await this.e();
        while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.OU)) {
            const operador = this.simboloAnterior();
            const direito = await this.e();
            expressao = new construtos_1.Logico(this.hashArquivo, expressao, operador, direito);
        }
        return expressao;
    }
    async ternario() {
        let expressaoOuCondicao = await this.ou();
        if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.INTERROGACAO)) {
            const operador = this.simboloAnterior();
            const caminhoEntao = await this.e();
            this.consumir(prisma_1.default.OU, "Esperado palavra reservada 'ou' após caminho positivo em operador ternário.");
            const caminhoSenao = await this.ternario();
            expressaoOuCondicao = new construtos_1.SeTernario(this.hashArquivo, expressaoOuCondicao, caminhoEntao, operador, caminhoSenao);
        }
        return expressaoOuCondicao;
    }
    async atribuir() {
        const expressao = await this.ternario();
        if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.IGUAL) ||
            this.verificarSeSimboloAtualEIgualA(prisma_1.default.MAIS_IGUAL)) {
            const igual = this.simboloAnterior();
            const valor = await 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;
    }
    async expressao() {
        return await this.atribuir();
    }
    async declaracaoEscreva() {
        const simboloEscreva = this.simboloAnterior();
        this.consumir(prisma_1.default.PARENTESE_ESQUERDO, "Esperado '(' antes dos valores em imprima.");
        const argumentos = [];
        if (!this.verificarTipoSimboloAtual(prisma_1.default.PARENTESE_DIREITO)) {
            do {
                argumentos.push(await this.expressao());
            } while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.VIRGULA));
        }
        this.consumir(prisma_1.default.PARENTESE_DIREITO, "Esperado ')' após os valores em imprima.");
        this.verificarSeSimboloAtualEIgualA(prisma_1.default.PONTO_E_VIRGULA);
        return new declaracoes_1.Escreva(Number(simboloEscreva.linha), simboloEscreva.hashArquivo, argumentos);
    }
    async declaracaoExpressao() {
        const expressao = await this.expressao();
        return new declaracoes_1.Expressao(expressao);
    }
    async blocoEscopo() {
        this.pilhaEscopos.empilhar(new informacao_escopo_1.InformacaoEscopo());
        let declaracoes = [];
        while (!this.verificarTipoSimboloAtual(prisma_1.default.FIM) && !this.estaNoFinal()) {
            const retornoDeclaracao = await this.resolverDeclaracaoForaDeBloco();
            if (Array.isArray(retornoDeclaracao)) {
                declaracoes = declaracoes.concat(retornoDeclaracao);
            }
            else {
                declaracoes.push(retornoDeclaracao);
            }
        }
        this.consumir(prisma_1.default.FIM, "Esperado 'fim' após o bloco.");
        this.pilhaEscopos.removerUltimo();
        return declaracoes.filter((d) => d);
    }
    async declaracaoDeLocal() {
        const identificador = this.consumir(prisma_1.default.IDENTIFICADOR, 'Esperado nome de variável.');
        let inicializador = null;
        if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.IGUAL)) {
            inicializador = await this.expressao();
        }
        this.consumir(prisma_1.default.PONTO_E_VIRGULA, "Esperado ';' após declaração de variável.");
        // Para Prisma, mantemos a tipagem inferida de forma simples por enquanto.
        const tipo = 'qualquer';
        this.pilhaEscopos.definirInformacoesVariavel(identificador.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(identificador.lexema, tipo));
        return new declaracoes_1.Var(identificador, inicializador, tipo);
    }
    async declaracaoEnquanto() {
        try {
            this.blocos += 1;
            const condicao = await this.expressao();
            const bloco = (await this.resolverDeclaracao());
            return new declaracoes_1.Enquanto(condicao, bloco);
        }
        finally {
            this.blocos -= 1;
        }
    }
    async declaracaoEscolha() {
        try {
            this.blocos += 1;
            const condicao = await this.expressao();
            const caminhos = [];
            let caminhoPadrao = null;
            while (!this.verificarTipoSimboloAtual(prisma_1.default.FIM) && !this.estaNoFinal()) {
                if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.CASO)) {
                    const caminhoCondicoes = [await this.expressao()];
                    while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.CASO)) {
                        caminhoCondicoes.push(await this.expressao());
                    }
                    this.consumir(prisma_1.default.ENTAO, "Esperado palavra reservada 'entao' ou 'então' após valor do 'caso'.");
                    const declaracoes = [];
                    while (!this.estaNoFinal() &&
                        ![
                            prisma_1.default.CASO,
                            prisma_1.default.PADRAO,
                            prisma_1.default.FIM,
                        ].includes(this.simbolos[this.atual].tipo)) {
                        declaracoes.push(await this.resolverDeclaracaoForaDeBloco());
                    }
                    caminhos.push({
                        condicoes: caminhoCondicoes,
                        declaracoes: declaracoes.filter((d) => d),
                    });
                }
                else if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.PADRAO)) {
                    if (caminhoPadrao !== null) {
                        const excecao = new erro_avaliador_sintatico_1.ErroAvaliadorSintatico(this.simbolos[this.atual], "Você só pode ter um 'padrao' em cada declaração de 'escolha'.");
                        this.erros.push(excecao);
                        throw excecao;
                    }
                    this.consumir(prisma_1.default.ENTAO, "Esperado palavra reservada 'entao' ou 'então' após declaração do 'padrao'.");
                    const declaracoes = [];
                    while (!this.estaNoFinal() &&
                        ![
                            prisma_1.default.CASO,
                            prisma_1.default.PADRAO,
                            prisma_1.default.FIM,
                        ].includes(this.simbolos[this.atual].tipo)) {
                        declaracoes.push(await this.resolverDeclaracaoForaDeBloco());
                    }
                    caminhoPadrao = {
                        condicoes: [],
                        declaracoes: declaracoes.filter((d) => d),
                    };
                }
                else {
                    throw this.erro(this.simbolos[this.atual], "Esperado 'caso', 'padrao' ou 'fim' em declaração 'escolha'.");
                }
            }
            this.consumir(prisma_1.default.FIM, "Esperado palavra-chave 'fim' para fechamento de declaração 'escolha'.");
            return new declaracoes_1.Escolha(condicao, caminhos, caminhoPadrao);
        }
        finally {
            this.blocos -= 1;
        }
    }
    async declaracaoSe() {
        const simboloSe = this.simbolos[this.atual];
        const condicao = await this.expressao();
        this.consumir(prisma_1.default.ENTAO, "Esperado palavra reservada 'entao' ou 'então' após condição em declaração 'se'.");
        const declaracoes = [];
        do {
            declaracoes.push(await this.resolverDeclaracaoForaDeBloco());
        } while (!this.estaNoFinal() &&
            ![prisma_1.default.SENAO, prisma_1.default.SENÃO, prisma_1.default.FIM].includes(this.simbolos[this.atual].tipo));
        let caminhoSenao = null;
        let fimConsumidoNoCaminhoSenao = false;
        if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.SENAO, prisma_1.default.SENÃO)) {
            const simboloSenao = this.simbolos[this.atual - 1];
            if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.SE)) {
                caminhoSenao = await this.declaracaoSe();
                fimConsumidoNoCaminhoSenao = true;
            }
            else {
                const declaracoesSenao = [];
                do {
                    declaracoesSenao.push(await this.resolverDeclaracaoForaDeBloco());
                } while (![prisma_1.default.FIM].includes(this.simbolos[this.atual].tipo));
                caminhoSenao = new declaracoes_1.Bloco(this.hashArquivo, Number(simboloSenao.linha), declaracoesSenao.filter((d) => d));
            }
        }
        if (!fimConsumidoNoCaminhoSenao) {
            this.consumir(prisma_1.default.FIM, "Esperado palavra-chave 'fim' para fechamento de declaração 'se'.");
        }
        return new declaracoes_1.Se(condicao, new declaracoes_1.Bloco(this.hashArquivo, Number(simboloSe.linha), declaracoes.filter((d) => d)), [], caminhoSenao);
    }
    async declaracaoTente() {
        const simboloTente = this.simboloAnterior();
        const blocoTente = [];
        while (!this.estaNoFinal() &&
            ![
                prisma_1.default.PEGUE,
                prisma_1.default.FINALMENTE,
                prisma_1.default.FIM,
            ].includes(this.simbolos[this.atual].tipo)) {
            blocoTente.push(await this.resolverDeclaracaoForaDeBloco());
        }
        let blocoPegue = null;
        if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.PEGUE)) {
            const declaracoesPegue = [];
            while (!this.estaNoFinal() &&
                ![prisma_1.default.FINALMENTE, prisma_1.default.FIM].includes(this.simbolos[this.atual].tipo)) {
                declaracoesPegue.push(await this.resolverDeclaracaoForaDeBloco());
            }
            blocoPegue = declaracoesPegue.filter((d) => d);
        }
        let blocoFinalmente = null;
        if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.FINALMENTE)) {
            const declaracoesFinalmente = [];
            while (!this.estaNoFinal() && !this.verificarTipoSimboloAtual(prisma_1.default.FIM)) {
                declaracoesFinalmente.push(await this.resolverDeclaracaoForaDeBloco());
            }
            blocoFinalmente = declaracoesFinalmente.filter((d) => d);
        }
        this.consumir(prisma_1.default.FIM, "Esperado palavra-chave 'fim' para fechamento de declaração 'tente'.");
        return new declaracoes_1.Tente(simboloTente.hashArquivo, Number(simboloTente.linha), blocoTente.filter((d) => d), blocoPegue, null, blocoFinalmente);
    }
    async declaracaoQuebre() {
        if (this.blocos < 1) {
            throw this.erro(this.simboloAnterior(), "'quebre' deve estar dentro de um laço de repetição.");
        }
        this.consumir(prisma_1.default.PONTO_E_VIRGULA, "Esperado ';' após 'quebre'.");
        return new declaracoes_1.Sustar(this.simbolos[this.atual]);
    }
    declaracaoContinua() {
        if (this.blocos < 1) {
            throw this.erro(this.simboloAnterior(), "'continua' precisa estar em um laço de repetição.");
        }
        this.consumir(prisma_1.default.PONTO_E_VIRGULA, "Esperado ';' após 'continua'.");
        return new declaracoes_1.Continua(this.simbolos[this.atual]);
    }
    async declaracaoRetorna() {
        const palavraChave = this.simboloAnterior();
        let valor = null;
        if (!this.verificarTipoSimboloAtual(prisma_1.default.PONTO_E_VIRGULA)) {
            valor = await this.expressao();
        }
        this.consumir(prisma_1.default.PONTO_E_VIRGULA, "Esperado ';' após valor de retorno.");
        return new declaracoes_1.Retorna(palavraChave, valor);
    }
    async declaracaoImportar() {
        this.avancarEDevolverAnterior();
        this.consumir(prisma_1.default.PARENTESE_ESQUERDO, "Esperado '(' após declaração.");
        const caminho = await this.expressao();
        this.consumir(prisma_1.default.PARENTESE_DIREITO, "Esperado ')' após declaração.");
        return new declaracoes_1.Importar(caminho);
    }
    async corpoDaFuncao(tipo) {
        const parenteseEsquerdo = this.consumir(prisma_1.default.PARENTESE_ESQUERDO, `Esperado '(' após o nome ${tipo}.`);
        let parametros = [];
        if (!this.verificarTipoSimboloAtual(prisma_1.default.PARENTESE_DIREITO)) {
            parametros = await this.logicaComumParametros();
        }
        this.consumir(prisma_1.default.PARENTESE_DIREITO, "Esperado ')' após parâmetros.");
        let tipoRetorno = 'qualquer';
        if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.SETA)) {
            tipoRetorno = 'qualquer'; // Simplificado por enquanto
        }
        const corpo = await this.blocoEscopo();
        return new construtos_1.FuncaoConstruto(this.hashArquivo, 0, parametros, corpo, tipoRetorno, false);
    }
    async logicaComumParametros() {
        const parametros = [];
        do {
            if (parametros.length >= 255) {
                throw this.erro(this.simbolos[this.atual], 'Função não pode ter mais de 255 parâmetros.');
            }
            const parametro = {};
            parametro.abrangencia = 'padrao';
            parametro.nome = this.consumir(prisma_1.default.IDENTIFICADOR, 'Esperado nome do parâmetro.');
            if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.IGUAL)) {
                parametro.valorPadrao = await this.primario();
            }
            this.pilhaEscopos.definirInformacoesVariavel(parametro.nome.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(parametro.nome.lexema, parametro.tipoDado || 'qualquer'));
            parametros.push(parametro);
        } while (this.verificarSeSimboloAtualEIgualA(prisma_1.default.VIRGULA));
        return parametros;
    }
    async funcao(tipo) {
        const simbolo = this.consumir(prisma_1.default.IDENTIFICADOR, `Esperado nome ${tipo}.`);
        this.pilhaEscopos.definirInformacoesVariavel(simbolo.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(simbolo.lexema, 'qualquer'));
        const corpoDaFuncao = await this.corpoDaFuncao(tipo);
        const tipoDaFuncao = `função<${corpoDaFuncao.tipo}>`;
        this.pilhaEscopos.definirInformacoesVariavel(simbolo.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(simbolo.lexema, tipoDaFuncao));
        const funcaoDeclaracao = new declaracoes_1.FuncaoDeclaracao(simbolo, corpoDaFuncao, tipoDaFuncao);
        this.pilhaEscopos.registrarReferenciaFuncao(simbolo.lexema, funcaoDeclaracao);
        return funcaoDeclaracao;
    }
    async resolverDeclaracao() {
        const simboloAtual = this.simbolos[this.atual];
        switch (simboloAtual.tipo) {
            case prisma_1.default.CONTINUA:
                this.avancarEDevolverAnterior();
                return this.declaracaoContinua();
            case prisma_1.default.PONTO_E_VIRGULA:
                // Ignora ponto e vírgula supérfluo
                this.avancarEDevolverAnterior();
                return null;
            case prisma_1.default.ENTAO:
            case prisma_1.default.INICIO:
            case prisma_1.default.FAZER:
                const simboloInicioBloco = this.avancarEDevolverAnterior();
                return new declaracoes_1.Bloco(simboloInicioBloco.hashArquivo, Number(simboloInicioBloco.linha), await this.blocoEscopo());
            case prisma_1.default.ENQUANTO:
                this.avancarEDevolverAnterior();
                return await this.declaracaoEnquanto();
            case prisma_1.default.ESCOLHA:
                this.avancarEDevolverAnterior();
                return await this.declaracaoEscolha();
            case prisma_1.default.IDENTIFICADOR:
                const proximoSimbolo = this.simbolos[this.atual + 1];
                if (proximoSimbolo && proximoSimbolo.tipo === prisma_1.default.IGUAL) {
                    return await this.declaracaoOuAtribuicaoVariaveis();
                }
                // Avaliar como expressão normal, sair do `switch`.
                break;
            case prisma_1.default.IMPRIMA:
                this.avancarEDevolverAnterior();
                return await this.declaracaoEscreva();
            case prisma_1.default.PARA:
                return await this.declaracaoPara();
            case prisma_1.default.QUEBRE:
                this.avancarEDevolverAnterior();
                return this.declaracaoQuebre();
            case prisma_1.default.SE:
                this.avancarEDevolverAnterior();
                return await this.declaracaoSe();
            case prisma_1.default.RETORNE:
                this.avancarEDevolverAnterior();
                return await this.declaracaoRetorna();
            case prisma_1.default.TENTE:
                this.avancarEDevolverAnterior();
                return await this.declaracaoTente();
            case prisma_1.default.LOCAL:
                this.avancarEDevolverAnterior();
                return await this.declaracaoDeLocal();
        }
        return await this.declaracaoExpressao();
    }
    async declaracaoOuAtribuicaoVariaveis() {
        const identificador = this.avancarEDevolverAnterior();
        this.consumir(prisma_1.default.IGUAL, "Esperado '=' após identificador.");
        if (this.estaNoFinal()) {
            throw this.erro(this.simboloAnterior(), 'Esperado valor após o símbolo de igual.');
        }
        const valor = await this.expressao();
        const tipo = this.logicaComumInferenciaTiposVariaveisEConstantes(valor, 'qualquer');
        if (this.pilhaEscopos.variavelJaDefinida(identificador.lexema)) {
            return new declaracoes_1.Expressao(new construtos_1.Atribuir(identificador.hashArquivo, new construtos_1.Variavel(identificador.hashArquivo, identificador), valor));
        }
        const retornoVar = new declaracoes_1.Var(identificador, valor, tipo);
        // Pelo manual de Prisma, variáveis implícitas estão sempre no escopo global.
        retornoVar.escopo = 'global';
        return retornoVar;
    }
    /**
     * Segundo o manual de Prisma, os tipos válidos para a linguagem são:
     *  número, string , tabela, funcao , userdata, boolean, nulo.
     * @param inicializador O construto do inicializador.
     * @param tipoPrevio Se há um tipo prévio definido. `qualquer` não é válido em Prisma:
     *                   O tipo sempre resolve para algum outro.
     * @returns O tipo inferido.
     */
    logicaComumInferenciaTiposVariaveisEConstantes(inicializador, tipoPrevio) {
        if (tipoPrevio !== 'qualquer') {
            return tipoPrevio;
        }
        switch (inicializador.constructor) {
            case construtos_1.Literal:
                return inicializador.tipo;
            // TODO: Terminar
            default:
                console.log(inicializador.constructor.name);
        }
    }
    async declaracaoParaCada(simboloPara) {
        const variavelIteracao = this.consumir(prisma_1.default.IDENTIFICADOR, "Esperado identificador de variável após 'para cada'.");
        this.consumir(prisma_1.default.EM, "Esperado palavra reservada 'em' após variável de iteração.");
        const vetorOuDicionario = await this.expressao();
        this.consumir(prisma_1.default.INICIO, `espera-se 'inicio' proximo a '${this.simbolos[this.atual].lexema}'.`);
        this.pilhaEscopos.definirInformacoesVariavel(variavelIteracao.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(variavelIteracao.lexema, 'qualquer'));
        const declaracoesBlocoParaCada = [];
        while (!this.estaNoFinal() && !this.verificarTipoSimboloAtual(prisma_1.default.FIM)) {
            declaracoesBlocoParaCada.push(await this.resolverDeclaracaoForaDeBloco());
        }
        this.consumir(prisma_1.default.FIM, "Esperado 'fim' após bloco do para cada.");
        const corpo = new declaracoes_1.Bloco(this.hashArquivo, Number(simboloPara.linha) + 1, declaracoesBlocoParaCada.filter((d) => d));
        return new declaracoes_1.ParaCada(this.hashArquivo, Number(simboloPara.linha), new construtos_1.Variavel(this.hashArquivo, variavelIteracao, 'qualquer'), vetorOuDicionario, corpo);
    }
    async declaracaoPara() {
        try {
            this.blocos += 1;
            const simboloPara = this.avancarEDevolverAnterior();
            if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.CADA)) {
                return await this.declaracaoParaCada(simboloPara);
            }
            const variavelIteracao = this.consumir(prisma_1.default.IDENTIFICADOR, "Esperado identificador de variável após 'para'.");
            this.consumir(prisma_1.default.IGUAL, `'=' or 'em' esperado próximo a '${this.simbolos[this.atual].lexema}'.`);
            const literalOuVariavelInicio = await this.adicaoOuSubtracao();
            this.consumir(prisma_1.default.VIRGULA, `Espera-se '=' próximo a '${this.simbolos[this.atual].lexema}'.`);
            const literalOuVariavelFim = await this.adicaoOuSubtracao();
            let operadorCondicao = new lexador_1.Simbolo(prisma_1.default.MENOR_IGUAL, '<=', null, Number(simboloPara.linha), this.hashArquivo);
            let passo = new construtos_1.Literal(this.hashArquivo, Number(simboloPara.linha), 1);
            if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.VIRGULA)) {
                passo = await this.adicaoOuSubtracao();
            }
            if (!this.verificarSeSimboloAtualEIgualA(prisma_1.default.INICIO, prisma_1.default.FAZER)) {
                throw this.erro(this.simbolos[this.atual], `espera-se 'inicio' ou 'fazer' proximo a '${this.simbolos[this.atual].lexema}'.`);
            }
            // Aqui já é seguro inicializar a variável.
            this.pilhaEscopos.definirInformacoesVariavel(variavelIteracao.lexema, new informacao_elemento_sintatico_1.InformacaoElementoSintatico(variavelIteracao.lexema, 'inteiro'));
            const declaracoesBlocoPara = [];
            let simboloAtualBlocoPara = this.simbolos[this.atual];
            while (simboloAtualBlocoPara.tipo !== prisma_1.default.FIM) {
                declaracoesBlocoPara.push(await this.resolverDeclaracaoForaDeBloco());
                simboloAtualBlocoPara = this.simbolos[this.atual];
            }
            this.avancarEDevolverAnterior(); // fim
            const corpo = new declaracoes_1.Bloco(this.hashArquivo, Number(simboloPara.linha) + 1, declaracoesBlocoPara.filter((d) => d));
            const para = new declaracoes_1.Para(this.hashArquivo, Number(simboloPara.linha), 
            // Inicialização: declara a variável de iteração.
            new declaracoes_1.Var(variavelIteracao, literalOuVariavelInicio, 'inteiro'), 
            // Condição.
            new construtos_1.Binario(this.hashArquivo, new construtos_1.Variavel(this.hashArquivo, variavelIteracao, 'inteiro'), operadorCondicao, literalOuVariavelFim), 
            // Incremento simples.
            new construtos_1.Atribuir(this.hashArquivo, new construtos_1.Variavel(this.hashArquivo, variavelIteracao, 'inteiro'), new construtos_1.Binario(this.hashArquivo, new construtos_1.Variavel(this.hashArquivo, variavelIteracao, 'inteiro'), new lexador_1.Simbolo(prisma_1.default.ADICAO, '+', null, Number(simboloPara.linha), this.hashArquivo), passo)), corpo);
            return para;
        }
        finally {
            this.blocos -= 1;
        }
    }
    async resolverDeclaracaoForaDeBloco() {
        try {
            if ((this.verificarTipoSimboloAtual(prisma_1.default.FUNCAO) ||
                this.verificarTipoSimboloAtual(prisma_1.default.FUNÇÃO)) &&
                this.verificarTipoProximoSimbolo(prisma_1.default.IDENTIFICADOR)) {
                this.avancarEDevolverAnterior();
                return await this.funcao('funcao');
            }
            if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.CLASSE))
                return await this.declaracaoDeClasse();
            return await this.resolverDeclaracao();
        }
        catch (erro) {
            this.sincronizar();
            this.erros.push(erro);
            return null;
        }
    }
    async metodoClassePrisma(construtor) {
        const simbolo = construtor
            ? new lexador_1.Simbolo(prisma_1.default.CONSTRUTOR, 'construtor', null, Number(this.simboloAnterior().linha), this.hashArquivo)
            : this.consumir(prisma_1.default.IDENTIFICADOR, 'Esperado nome do método.');
        this.consumir(prisma_1.default.PARENTESE_ESQUERDO, "Esperado '(' após nome do método.");
        let parametros = [];
        if (!this.verificarTipoSimboloAtual(prisma_1.default.PARENTESE_DIREITO)) {
            parametros = await this.logicaComumParametros();
        }
        this.consumir(prisma_1.default.PARENTESE_DIREITO, "Esperado ')' após parâmetros.");
        this.consumir(prisma_1.default.CHAVE_ESQUERDA, "Esperado '{' antes do corpo do método.");
        const declaracoesCorpo = [];
        while (!this.estaNoFinal() && !this.verificarTipoSimboloAtual(prisma_1.default.CHAVE_DIREITA)) {
            declaracoesCorpo.push(await this.resolverDeclaracaoForaDeBloco());
        }
        this.consumir(prisma_1.default.CHAVE_DIREITA, "Esperado '}' após o corpo do método.");
        const corpoDaFuncao = new construtos_1.FuncaoConstruto(this.hashArquivo, Number(simbolo.linha), parametros, declaracoesCorpo.filter((d) => d), 'qualquer', false);
        const tipoDaFuncao = `função<${corpoDaFuncao.tipo}>`;
        return new declaracoes_1.FuncaoDeclaracao(simbolo, corpoDaFuncao, tipoDaFuncao);
    }
    propriedadesDeclaradasEmMetodo(metodo) {
        const propriedades = [];
        const nomesPropriedades = new Set();
        for (const declaracao of metodo.funcao.corpo) {
            if (!(declaracao instanceof declaracoes_1.Expressao)) {
                continue;
            }
            if (!(declaracao.expressao instanceof construtos_1.DefinirValor)) {
                continue;
            }
            if (!(declaracao.expressao.objeto instanceof construtos_1.Isto)) {
                continue;
            }
            const nomePropriedade = declaracao.expressao.nome.lexema;
            if (nomesPropriedades.has(nomePropriedade)) {
                continue;
            }
            nomesPropriedades.add(nomePropriedade);
            propriedades.push(new declaracoes_1.PropriedadeClasse(declaracao.expressao.nome, 'qualquer'));
        }
        return propriedades;
    }
    async declaracaoDeClasse() {
        const simbolo = this.consumir(prisma_1.default.IDENTIFICADOR, 'Esperado nome da classe.');
        let superClasse = null;
        if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.PARENTESE_ESQUERDO)) {
            const simboloSuperclasse = this.consumir(prisma_1.default.IDENTIFICADOR, 'Esperado nome da Superclasse.');
            this.superclasseAtual = simboloSuperclasse.lexema;
            superClasse = new construtos_1.Variavel(this.hashArquivo, this.simboloAnterior());
            this.consumir(prisma_1.default.PARENTESE_DIREITO, "Esperado ')' após declaração.");
        }
        this.consumir(prisma_1.default.CHAVE_ESQUERDA, "Esperado '{' antes do escopo da classe.");
        const metodos = [];
        while (!this.estaNoFinal() &&
            (this.verificarTipoSimboloAtual(prisma_1.default.CONSTRUTOR) ||
                this.verificarTipoSimboloAtual(prisma_1.default.FUNCAO) ||
                this.verificarTipoSimboloAtual(prisma_1.default.FUNÇÃO))) {
            if (this.verificarSeSimboloAtualEIgualA(prisma_1.default.CONSTRUTOR)) {
                metodos.push(await this.metodoClassePrisma(true));
                continue;
            }
            this.verificarSeSimboloAtualEIgualA(prisma_1.default.FUNCAO, prisma_1.default.FUNÇÃO);
            metodos.push(await this.metodoClassePrisma(false));
        }
        this.consumir(prisma_1.default.CHAVE_DIREITA, "Esperado '}' após métodos da classe.");
        const propriedades = [];
        const nomesPropriedades = new Set();
        for (const metodo of metodos) {
            const propriedadesDoMetodo = this.propriedadesDeclaradasEmMetodo(metodo);
            for (const propriedade of propriedadesDoMetodo) {
                if (nomesPropriedades.has(propriedade.nome.lexema)) {
                    continue;
                }
                nomesPropriedades.add(propriedade.nome.lexema);
                propriedades.push(propriedade);
            }
        }
        this.superclasseAtual = undefined;
        const definicaoClasse = new declaracoes_1.Classe(simbolo, superClasse ? [superClasse] : [], metodos, propriedades);
        this.tiposDefinidosEmCodigo[definicaoClasse.simbolo.lexema] = definicaoClasse;
        return definicaoClasse;
    }
    inicializarPilhaEscopos() {
        this.pilhaEscopos = new pilha_escopos_1.PilhaEscopos();
        this.pilhaEscopos.empilhar(new informacao_escopo_1.InformacaoEscopo());
        // Registrar funções nativas (built-ins) do Prisma no escopo do parser
        // para evitar erros de variável não definida durante análise semântica
        this.pilhaEscopos.definirInformacoesVariavel('tipo', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('tipo', 'função', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('valor', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('poe', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('poe', 'função', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('valores', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('tamanho', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('tamanho', 'número', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('objeto', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('pares', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('pares', 'tabela', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('tabela', 'tabela'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('ipares', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('ipares', 'tabela', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('tabela', 'tabela'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('convnumero', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('convnumero', 'número', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('valor', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('convstring', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('convstring', 'texto', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('valor', 'qualquer'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('aleatorio', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('aleatorio', 'função', true, []));
        this.pilhaEscopos.definirInformacoesVariavel('aleatorio_entre', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('aleatorio_entre', 'número', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('minimo', 'número'),
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('maximo', 'número'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('coletelixo', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('coletelixo', 'número', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('acao', 'texto'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('piso', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('piso', 'número', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('n', 'número'),
        ]));
        this.pilhaEscopos.definirInformacoesVariavel('teto', new informacao_elemento_sintatico_1.InformacaoElementoSintatico('teto', 'número', true, [
            new informacao_elemento_sintatico_1.InformacaoElementoSintatico('n', 'número'),
        ]));
    }
    async analisar(retornoLexador, hashArquivo) {
        const inicioAnalise = (0, browser_process_hrtime_1.default)();
        this.erros = [];
        this.atual = 0;
        this.blocos = 0;
        this.inicializarPilhaEscopos();
        this.tiposDefinidosEmCodigo = {};
        this.hashArquivo = hashArquivo || 0;
        this.simbolos = (retornoLexador === null || retornoLexador === void 0 ? void 0 : retornoLexador.simbolos) || [];
        let declaracoes = [];
        while (!this.estaNoFinal()) {
            const retornoDeclaracao = await this.resolverDeclaracaoForaDeBloco();
            if (Array.isArray(retornoDeclaracao)) {
                declaracoes = declaracoes.concat(retornoDeclaracao);
            }
            else if (retornoDeclaracao !== null) {
                declaracoes.push(retornoDeclaracao);
            }
        }
        if (this.performance) {
            const deltaAnalise = (0, browser_process_hrtime_1.default)(inicioAnalise);
            console.log(`[Avaliador Sintático] Tempo para análise: ${deltaAnalise[0] * 1e9 + deltaAnalise[1]}ns`);
        }
        return {
            declaracoes: declaracoes,
            erros: this.erros,
        };
    }
}
exports.AvaliadorSintaticoPrisma = AvaliadorSintaticoPrisma;
//# sourceMappingURL=avaliador-sintatico-prisma.js.map