UNPKG

@designliquido/delegua

Version:

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

275 lines 11.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AvaliadorSintaticoBase = void 0; const construtos_1 = require("../construtos"); const declaracoes_1 = require("../declaracoes"); const erro_avaliador_sintatico_1 = require("./erro-avaliador-sintatico"); const comum_1 = __importDefault(require("../tipos-de-simbolos/comum")); /** * O Avaliador Sintático Base é uma tentativa de mapear métodos em comum * entre todos os outros Avaliadores Sintáticos. Depende de um dicionário * de tipos de símbolos comuns entre todos os dialetos. */ class AvaliadorSintaticoBase { constructor() { this.simbolos = []; this.erros = []; this.hashArquivo = -1; this.atual = 0; this.blocos = 0; } erro(simbolo, mensagemDeErro, codigoDiagnostico, simboloRelacionado) { const excecao = new erro_avaliador_sintatico_1.ErroAvaliadorSintatico(simbolo, mensagemDeErro, codigoDiagnostico, simboloRelacionado); return excecao; } 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); } simboloAnterior() { if (this.atual === 0) { throw new Error('Este é o primeiro símbolo da sequência vinda do Lexador.'); } return this.simbolos[this.atual - 1]; } verificarTipoSimboloAtual(tipo) { if (this.estaNoFinal()) return false; return this.simbolos[this.atual].tipo === tipo; } verificarTipoProximoSimbolo(tipo) { if (this.atual + 1 >= this.simbolos.length) return false; return this.simbolos[this.atual + 1].tipo === tipo; } estaNoFinal() { return this.atual === this.simbolos.length; } avancarEDevolverAnterior() { if (!this.estaNoFinal()) this.atual += 1; return this.simbolos[this.atual - 1]; } 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 declaracaoBloco() { const simboloInicioBloco = this.consumir(comum_1.default.CHAVE_ESQUERDA, "Esperado '{' para abertura de bloco."); return new declaracoes_1.Bloco(simboloInicioBloco.hashArquivo, Number(simboloInicioBloco.linha), await this.blocoEscopo()); } async finalizarChamada(entidadeChamada) { const argumentos = []; if (!this.verificarTipoSimboloAtual(comum_1.default.PARENTESE_DIREITO)) { do { // `apply()` em JavaScript aceita até 255 parâmetros. 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(comum_1.default.VIRGULA)); } this.consumir(comum_1.default.PARENTESE_DIREITO, "Esperado ')' após os argumentos."); return new construtos_1.Chamada(this.hashArquivo, entidadeChamada, argumentos); } async unario() { if (this.verificarSeSimboloAtualEIgualA(comum_1.default.NEGACAO, comum_1.default.SUBTRACAO)) { const operador = this.simbolos[this.atual - 1]; const direito = await this.unario(); return Promise.resolve(new construtos_1.Unario(this.hashArquivo, operador, direito, 'ANTES')); } return await this.chamar(); } /** * A exponenciacão é uma exceção na ordem de avaliação (resolve primeiro à direita). * Por isso `direito` chama `exponenciacao()`, e não `unario()`. * @returns {Binario} A expressão binária na forma do construto `Binario`. */ async exponenciacao() { let expressao = await this.unario(); while (this.verificarSeSimboloAtualEIgualA(comum_1.default.EXPONENCIACAO)) { const operador = this.simbolos[this.atual - 1]; const direito = await this.exponenciacao(); expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito); } return expressao; } async multiplicar() { let expressao = await this.exponenciacao(); while (this.verificarSeSimboloAtualEIgualA(comum_1.default.DIVISAO, comum_1.default.DIVISAO_INTEIRA, comum_1.default.MULTIPLICACAO, comum_1.default.MODULO)) { const operador = this.simbolos[this.atual - 1]; 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(comum_1.default.SUBTRACAO, comum_1.default.ADICAO)) { const operador = this.simbolos[this.atual - 1]; const direito = await this.multiplicar(); expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito); } return expressao; } /** * Este método é usado por Delégua e alguns dialetos de Portugol que possuem declarações * de múltiplas variáveis na mesma linha. */ declaracaoDeVariaveis() { throw new Error('Método não implementado.'); } async comparar() { let expressao = await this.adicaoOuSubtracao(); while (this.verificarSeSimboloAtualEIgualA(comum_1.default.MAIOR, comum_1.default.MAIOR_IGUAL, comum_1.default.MENOR, comum_1.default.MENOR_IGUAL)) { const operador = this.simbolos[this.atual - 1]; const direito = await this.adicaoOuSubtracao(); expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito); } return expressao; } async comparacaoIgualdade() { let expressao = await this.comparar(); while (this.verificarSeSimboloAtualEIgualA(comum_1.default.DIFERENTE, comum_1.default.IGUAL, comum_1.default.IGUAL_IGUAL)) { const operador = this.simbolos[this.atual - 1]; const direito = await this.comparar(); expressao = new construtos_1.Binario(this.hashArquivo, expressao, operador, direito); } return expressao; } async e() { let expressao = await this.comparacaoIgualdade(); while (this.verificarSeSimboloAtualEIgualA(comum_1.default.E)) { const operador = this.simbolos[this.atual - 1]; const direito = await this.comparacaoIgualdade(); expressao = new construtos_1.Logico(this.hashArquivo, expressao, operador, direito); } return expressao; } async ou() { let expressao = await this.e(); while (this.verificarSeSimboloAtualEIgualA(comum_1.default.OU)) { const operador = this.simbolos[this.atual - 1]; const direito = await this.e(); expressao = new construtos_1.Logico(this.hashArquivo, expressao, operador, direito); } return expressao; } /** * Processa tuplas, que são expressões separadas por vírgula entre parênteses. * Se não houver vírgula, retorna apenas a expressão simples. */ async tupla() { let expressao = await this.ou(); // Se não há vírgula, retorna a expressão simples if (!this.verificarSeSimboloAtualEIgualA(comum_1.default.VIRGULA)) { return expressao; } // Se há vírgula, então é uma tupla const elementos = [expressao]; do { if (this.verificarTipoSimboloAtual(comum_1.default.PARENTESE_DIREITO)) { break; } elementos.push(await this.ou()); } while (this.verificarSeSimboloAtualEIgualA(comum_1.default.VIRGULA)); return new construtos_1.TuplaN(this.hashArquivo, expressao.linha, elementos); } async expressao() { return await this.atribuir(); } async funcao(tipo) { // Avançar `função` ou `funcao`. this.avancarEDevolverAnterior(); const nomeFuncao = this.consumir(comum_1.default.IDENTIFICADOR, `Esperado nome ${tipo}.`); const corpo = await this.corpoDaFuncao(tipo); return new declaracoes_1.FuncaoDeclaracao(nomeFuncao, corpo); } 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 = {}; if (this.simbolos[this.atual].tipo === comum_1.default.MULTIPLICACAO) { this.avancarEDevolverAnterior(); parametro.abrangencia = 'multiplo'; } else { parametro.abrangencia = 'padrao'; } parametro.nome = this.consumir(comum_1.default.IDENTIFICADOR, 'Esperado nome do parâmetro.'); if (this.verificarSeSimboloAtualEIgualA(comum_1.default.IGUAL)) { parametro.valorPadrao = await this.primario(); } parametros.push(parametro); if (parametro.abrangencia === 'multiplo') break; } while (this.verificarSeSimboloAtualEIgualA(comum_1.default.VIRGULA)); return parametros; } /** * Os métodos a seguir só devem ser implementados se o dialeto * em questão realmente possui a funcionalidade, e devem levantar * erro em caso contrário. */ bitShift() { throw new Error('Método não implementado.'); } bitE() { throw new Error('Método não implementado.'); } bitOu() { throw new Error('Método não implementado.'); } declaracaoContinua() { throw new Error('Método não implementado.'); } declaracaoDeClasse() { throw new Error('Método não implementado.'); } declaracaoDeVariavel() { throw new Error('Método não implementado.'); } declaracaoExpressao(simboloAnterior) { throw new Error('Método não implementado.'); } declaracaoRetorna() { throw new Error('Método não implementado.'); } declaracaoSustar() { throw new Error('Método não implementado.'); } declaracaoTente() { throw new Error('Método não implementado.'); } em() { throw new Error('Método não implementado.'); } resolverDeclaracao() { throw new Error('Método não implementado.'); } } exports.AvaliadorSintaticoBase = AvaliadorSintaticoBase; //# sourceMappingURL=avaliador-sintatico-base.js.map