@designliquido/delegua
Version:
Linguagem de programação simples e moderna usando português estruturado.
266 lines • 11.2 kB
JavaScript
"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 {
erro(simbolo, mensagemDeErro) {
const excecao = new erro_avaliador_sintatico_1.ErroAvaliadorSintatico(simbolo, mensagemDeErro);
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) {
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.consumir(comum_1.default.MULTIPLICACAO, null);
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