@designliquido/delegua
Version:
Linguagem de programação simples e moderna usando português estruturado.
828 lines • 41 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.TradutorMermaidJs = void 0;
const construtos_1 = require("../construtos");
const declaracoes_1 = require("../declaracoes");
const mermaid_1 = require("./mermaid");
const delegua_1 = __importDefault(require("../tipos-de-simbolos/delegua"));
/**
* [MermaidJs](https://mermaid.js.org/) é uma especificação que nos permite
* criar fluxogramas através de uma notação por texto.
*
* Este tradutor converte estruturas da avaliação sintática em um fluxograma
* compatível com o MermaidJs.
*
* Diferentemente de outros tradutores, este não trabalha diretamente com `string`s.
* Construtos sim devolvem `string`s, mas declarações devolvem um vetor de
* `VerticeFluxograma`.
* @see VerticeFluxograma
*/
class TradutorMermaidJs {
visitarDeclaracaoCabecalhoPrograma(declaracao) {
throw new Error('Método não implementado.');
}
async visitarDeclaracaoClasse(declaracao) {
const nomeClasse = declaracao.simbolo.lexema;
const superClasse = declaracao.superClasse
? declaracao.superClasse.simbolo?.lexema || declaracao.superClasse.nome?.lexema
: undefined;
const linha = declaracao.linha;
// Cria arestas de entrada e saída para a classe
const rotulo = declaracao.estrangeira ? 'Classe Estrangeira' : 'Classe';
const textoInicio = `Classe${nomeClasse}Inicio[Início: ${rotulo} ${nomeClasse}]`;
const arestaInicial = new mermaid_1.ArestaFluxograma(declaracao, textoInicio);
const textoFim = `Classe${nomeClasse}Fim[Fim: ${rotulo} ${nomeClasse}]`;
const arestaFinal = new mermaid_1.ArestaFluxograma(declaracao, textoFim);
// Cria o subgrafo da classe
const subgrafo = new mermaid_1.SubgrafoClasse(nomeClasse, linha, arestaInicial, arestaFinal, superClasse);
// Salva o estado anterior
const anterioresAntes = [...this.anteriores];
// Processa métodos
if (declaracao.metodos && declaracao.metodos.length > 0) {
for (const metodoDeclaracao of declaracao.metodos) {
const nomeMetodo = metodoDeclaracao.simbolo.lexema;
const linhaMetodo = metodoDeclaracao.linha;
const ehConstrutor = nomeMetodo === 'construtor' || nomeMetodo === 'iniciar';
// Cria arestas de entrada e saída para o método
const textoInicioMetodo = `Metodo${nomeMetodo}${nomeClasse}Inicio[Início: ${nomeMetodo}()]`;
const arestaInicialMetodo = new mermaid_1.ArestaFluxograma(metodoDeclaracao, textoInicioMetodo);
const textoFimMetodo = `Metodo${nomeMetodo}${nomeClasse}Fim[Fim: ${nomeMetodo}()]`;
const arestaFinalMetodo = new mermaid_1.ArestaFluxograma(metodoDeclaracao, textoFimMetodo);
// Cria o subgrafo do método
const subgrafoMetodo = new mermaid_1.SubgrafoMetodo(nomeMetodo, nomeClasse, linhaMetodo, arestaInicialMetodo, arestaFinalMetodo, ehConstrutor);
// Traduz o corpo do método
this.anteriores = [arestaInicialMetodo];
if (metodoDeclaracao.funcao.corpo && metodoDeclaracao.funcao.corpo.length > 0) {
for (const declaracaoCorpo of metodoDeclaracao.funcao.corpo) {
const verticesCorpo = await declaracaoCorpo.aceitar(this);
subgrafoMetodo.vertices = subgrafoMetodo.vertices.concat(verticesCorpo);
}
}
// Conecta o último vértice do corpo ao fim do método
if (this.anteriores.length > 0) {
for (const anterior of this.anteriores) {
subgrafoMetodo.vertices.push(new mermaid_1.VerticeFluxograma(anterior, arestaFinalMetodo));
}
}
// Adiciona o método ao subgrafo da classe
if (ehConstrutor) {
subgrafo.construtor = subgrafoMetodo;
}
else {
subgrafo.metodos.push(subgrafoMetodo);
}
}
}
// Restaura o estado anterior
this.anteriores = anterioresAntes;
// Armazena o subgrafo da classe
this.declaracoesClasses[nomeClasse] = subgrafo;
return Promise.resolve([]);
}
async visitarDeclaracaoComentario(declaracao) {
return Promise.resolve('');
}
async visitarDeclaracaoConst(declaracao) {
let texto = `Linha${declaracao.linha}(variável: ${declaracao.simbolo.lexema}`;
texto += await this.logicaComumTraducaoVarEConst(declaracao, texto);
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
const vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
return Promise.resolve(vertices);
}
visitarDeclaracaoConstMultiplo(declaracao) {
throw new Error('Método não implementado.');
}
async visitarDeclaracaoDeExpressao(declaracao) {
// Verifica se é uma chamada de função
if (declaracao.expressao.constructor === construtos_1.Chamada) {
const chamada = declaracao.expressao;
const verticesChamada = await this.traduzirChamadaFuncao(declaracao, chamada);
if (verticesChamada.length > 0) {
return Promise.resolve(verticesChamada);
}
}
// Se não for uma chamada de função ou não for uma função conhecida,
// trata como expressão normal
let texto = `Linha${declaracao.linha}(`;
const textoConstruto = await declaracao.expressao.aceitar(this);
texto += textoConstruto + ')';
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
const vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
return Promise.resolve(vertices);
}
async visitarDeclaracaoDefinicaoFuncao(declaracao) {
const nomeFuncao = declaracao.simbolo.lexema;
const linha = declaracao.linha;
// Cria arestas de entrada e saída para a função
const textoInicio = `Func${nomeFuncao}Inicio[Início: ${nomeFuncao}()]`;
const arestaInicial = new mermaid_1.ArestaFluxograma(declaracao, textoInicio);
const textoFim = `Func${nomeFuncao}Fim[Fim: ${nomeFuncao}()]`;
const arestaFinal = new mermaid_1.ArestaFluxograma(declaracao, textoFim);
// Cria o subgrafo da função
const subgrafo = new mermaid_1.SubgrafoFuncao(nomeFuncao, linha, arestaInicial, arestaFinal);
// Salva o estado atual de anteriores
const anterioresAntes = [...this.anteriores];
this.anteriores = [arestaInicial];
// Processa o corpo da função
if (declaracao.funcao.corpo && declaracao.funcao.corpo.length > 0) {
for (const declaracaoCorpo of declaracao.funcao.corpo) {
const verticesCorpo = await declaracaoCorpo.aceitar(this);
subgrafo.vertices = subgrafo.vertices.concat(verticesCorpo);
}
}
// Conecta o fim do corpo à aresta final
if (this.anteriores.length > 0) {
for (const anterior of this.anteriores) {
subgrafo.vertices.push(new mermaid_1.VerticeFluxograma(anterior, arestaFinal));
}
}
// Restaura o estado anterior
this.anteriores = anterioresAntes;
// Armazena o subgrafo
this.declaracoesFuncoes[nomeFuncao] = subgrafo;
// Não adiciona ao fluxo principal
return Promise.resolve([]);
}
async visitarDeclaracaoEnquanto(declaracao) {
let texto = `Linha${declaracao.linha}(enquanto `;
const condicao = await declaracao.condicao.aceitar(this);
texto += condicao + ')';
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
let vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
// Corpo, normalmente um `Bloco`.
const verticesCorpo = await declaracao.corpo.aceitar(this);
vertices = vertices.concat(verticesCorpo);
const ultimaArestaCorpo = verticesCorpo[verticesCorpo.length - 1].destino;
const verticeLaco = new mermaid_1.VerticeFluxograma(ultimaArestaCorpo, aresta);
vertices.push(verticeLaco);
return Promise.resolve(vertices);
}
async visitarDeclaracaoEscolha(declaracao) {
let texto = `Linha${declaracao.linha}(escolha um caminho pelo valor de `;
const textoIdentificadorOuLiteral = await declaracao.identificadorOuLiteral.aceitar(this);
texto += textoIdentificadorOuLiteral + ')';
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
let vertices = this.logicaComumConexaoArestas(aresta);
const arestasCaminho = [];
for (const caminho of declaracao.caminhos) {
arestasCaminho.push(await this.logicaComumCaminhoEscolha(declaracao, caminho, caminho.condicoes[0].linha, textoIdentificadorOuLiteral, false));
}
if (declaracao.caminhoPadrao) {
arestasCaminho.push(await this.logicaComumCaminhoEscolha(declaracao, declaracao.caminhoPadrao, declaracao.caminhoPadrao.declaracoes[0].linha - 1, textoIdentificadorOuLiteral, true));
}
for (const conjunto of Object.values(arestasCaminho)) {
const verticeEscolhaECaminho = new mermaid_1.VerticeFluxograma(aresta, conjunto.caminho);
vertices.push(verticeEscolhaECaminho);
vertices = vertices.concat(conjunto.declaracoesCaminho);
this.anteriores.push(conjunto.declaracoesCaminho[conjunto.declaracoesCaminho.length - 1].destino);
}
return Promise.resolve(vertices);
}
async visitarDeclaracaoEscreva(declaracao) {
let texto = `Linha${declaracao.linha}(escreva: `;
for (const argumento of declaracao.argumentos) {
const valor = await argumento.aceitar(this);
texto += valor + ', ';
}
texto = texto.slice(0, -2);
texto += ')';
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
const vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
return Promise.resolve(vertices);
}
visitarDeclaracaoEscrevaMesmaLinha(declaracao) {
throw new Error('Método não implementado.');
}
async visitarDeclaracaoFazer(declaracao) {
const texto = `Linha${declaracao.linha}(fazer)`;
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
let vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
// Corpo, normalmente um `Bloco`.
const verticesCorpo = await declaracao.caminhoFazer.aceitar(this);
vertices = vertices.concat(verticesCorpo);
const ultimaArestaCorpo = verticesCorpo[verticesCorpo.length - 1].destino;
const condicao = await declaracao.condicaoEnquanto.aceitar(this);
let textoEnquanto = `Linha${declaracao.condicaoEnquanto.linha}(enquanto ${condicao})`;
const arestaEnquanto = new mermaid_1.ArestaFluxograma(declaracao, textoEnquanto);
const verticeEnquanto = new mermaid_1.VerticeFluxograma(ultimaArestaCorpo, arestaEnquanto);
vertices.push(verticeEnquanto);
const verticeCondicaoComFazer = new mermaid_1.VerticeFluxograma(arestaEnquanto, aresta);
vertices.push(verticeCondicaoComFazer);
this.anteriores.pop();
this.anteriores.push(arestaEnquanto);
return Promise.resolve(vertices);
}
visitarDeclaracaoInicioAlgoritmo(declaracao) {
throw new Error('Método não implementado.');
}
async visitarDeclaracaoParaCada(declaracao) {
const textoVariavelIteracao = await declaracao.variavelIteracao.aceitar(this);
let texto = `Linha${declaracao.linha}(para cada ${textoVariavelIteracao} em `;
const textoVariavelIterada = await declaracao.vetorOuDicionario.aceitar(this);
texto += textoVariavelIterada + ')';
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
let vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
// Corpo, normalmente um `Bloco`.
const verticesCorpo = await declaracao.corpo.aceitar(this);
vertices = vertices.concat(verticesCorpo);
const ultimaArestaCorpo = verticesCorpo[verticesCorpo.length - 1].destino;
vertices.push(new mermaid_1.VerticeFluxograma(ultimaArestaCorpo, aresta));
return Promise.resolve(vertices);
}
async visitarDeclaracaoPara(declaracao) {
let texto = `Linha${declaracao.linha}(para `;
if (declaracao.inicializador) {
for (const declaracaoInicializadora of declaracao.inicializador) {
// Normalmente é `Var`.
const declaracaoVar = declaracaoInicializadora;
const valorInicializacao = await declaracaoVar.inicializador.aceitar(this);
texto += `uma variável ${declaracaoVar.simbolo.lexema} inicializada com ${valorInicializacao}, `;
}
texto = texto.slice(0, -2);
}
texto += ')';
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
let vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
// Condição
const textoCondicao = await declaracao.condicao.aceitar(this);
const textoArestaCondicao = `Linha${declaracao.linha}Condicao{se ${textoCondicao}}`;
const arestaCondicao = new mermaid_1.ArestaFluxograma(declaracao, textoArestaCondicao);
vertices = vertices.concat(this.logicaComumConexaoArestas(arestaCondicao));
this.anteriores.push(arestaCondicao);
this.ultimaDicaVertice = 'Sim';
// Corpo, normalmente um `Bloco`.
const verticesCorpo = await declaracao.corpo.aceitar(this);
vertices = vertices.concat(verticesCorpo);
// Incremento
const ultimaArestaCorpo = verticesCorpo[verticesCorpo.length - 1].destino;
const textoIncremento = await declaracao.incrementar.aceitar(this);
const arestaIncremento = new mermaid_1.ArestaFluxograma(declaracao, `Linha${declaracao.linha}Incremento(${textoIncremento})`);
const verticeIncremento = new mermaid_1.VerticeFluxograma(ultimaArestaCorpo, arestaIncremento);
vertices.push(verticeIncremento);
const verticeLaco = new mermaid_1.VerticeFluxograma(arestaIncremento, arestaCondicao);
vertices.push(verticeLaco);
// Configura a condição como anterior
this.anteriores.pop();
this.anteriores.push(arestaCondicao);
this.ultimaDicaVertice = 'Não';
return Promise.resolve(vertices);
}
async visitarDeclaracaoSe(declaracao) {
let texto = `Linha${declaracao.linha}{se `;
const condicao = await declaracao.condicao.aceitar(this);
texto += condicao;
texto += `}`;
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
let vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
this.ultimaDicaVertice = 'Sim';
// Caminho então, normalmente um `Bloco`.
const verticesEntao = await declaracao.caminhoEntao.aceitar(this);
vertices = vertices.concat(verticesEntao);
const ultimaArestaEntao = verticesEntao.length > 0 ? verticesEntao[verticesEntao.length - 1].destino : aresta;
if (declaracao.caminhoSenao) {
this.anteriores = [];
// Verifica se é "senão se" ou apenas "senão"
const ehSenaoSe = declaracao.caminhoSenao.constructor === declaracoes_1.Se;
if (ehSenaoSe) {
// Para "senão se", conecta diretamente ao próximo condicional sem nó intermediário
this.anteriores.push(aresta);
this.ultimaDicaVertice = 'Não';
}
else {
// Para "senão" simples, cria o nó intermediário
const arestaSenao = new mermaid_1.ArestaFluxograma(declaracao, `Linha${declaracao.caminhoSenao.linha}(senão)`);
vertices.push(new mermaid_1.VerticeFluxograma(aresta, arestaSenao, 'Não'));
this.anteriores.push(arestaSenao);
}
const verticesSenao = await declaracao.caminhoSenao.aceitar(this);
vertices = vertices.concat(verticesSenao);
}
this.anteriores.push(ultimaArestaEntao);
return Promise.resolve(vertices);
}
async visitarDeclaracaoTendoComo(declaracao) {
const textoVariavelIteracao = await declaracao.inicializacaoVariavel.aceitar(this);
let texto = `Linha${declaracao.linha}(tendo ${textoVariavelIteracao} como `;
texto += declaracao.simboloVariavel.lexema + ')';
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
let vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
// Corpo, normalmente um `Bloco`.
const verticesCorpo = await declaracao.corpo.aceitar(this);
vertices = vertices.concat(verticesCorpo);
const ultimaArestaCorpo = verticesCorpo[verticesCorpo.length - 1].destino;
vertices.push(new mermaid_1.VerticeFluxograma(ultimaArestaCorpo, aresta));
return Promise.resolve(vertices);
}
async visitarDeclaracaoTente(declaracao) {
const texto = `Linha${declaracao.linha}(tente)`;
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
let vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
// Caminho tente (try)
const verticesTente = [];
for (const declaracaoTente of declaracao.caminhoTente) {
const verticesDeclaracao = await declaracaoTente.aceitar(this);
verticesTente.push(...verticesDeclaracao);
}
vertices = vertices.concat(verticesTente);
const ultimaArestaTente = verticesTente.length > 0 ? verticesTente[verticesTente.length - 1].destino : aresta;
const anterioresAposTente = [];
// Caminho pegue (catch) - se existir
if (declaracao.caminhoPegue) {
this.anteriores = [aresta];
const arestaPegue = new mermaid_1.ArestaFluxograma(declaracao, `Linha${declaracao.linha}Pegue(pegue)`);
vertices.push(new mermaid_1.VerticeFluxograma(aresta, arestaPegue, 'Erro'));
this.anteriores.push(arestaPegue);
const verticesPegue = [];
if (Array.isArray(declaracao.caminhoPegue)) {
for (const declaracaoPegue of declaracao.caminhoPegue) {
const verticesDeclaracao = await declaracaoPegue.aceitar(this);
verticesPegue.push(...verticesDeclaracao);
}
}
vertices = vertices.concat(verticesPegue);
const ultimaArestaPegue = verticesPegue.length > 0
? verticesPegue[verticesPegue.length - 1].destino
: arestaPegue;
anterioresAposTente.push(ultimaArestaPegue);
}
// Caminho senão (else) - se existir
if (declaracao.caminhoSenao && declaracao.caminhoSenao.length > 0) {
this.anteriores = [ultimaArestaTente];
const arestaSenao = new mermaid_1.ArestaFluxograma(declaracao, `Linha${declaracao.linha}Senao(senão - sem erro)`);
vertices.push(new mermaid_1.VerticeFluxograma(ultimaArestaTente, arestaSenao, 'Sucesso'));
this.anteriores.push(arestaSenao);
const verticesSenao = [];
for (const declaracaoSenao of declaracao.caminhoSenao) {
const verticesDeclaracao = await declaracaoSenao.aceitar(this);
verticesSenao.push(...verticesDeclaracao);
}
vertices = vertices.concat(verticesSenao);
const ultimaArestaSenao = verticesSenao.length > 0
? verticesSenao[verticesSenao.length - 1].destino
: arestaSenao;
anterioresAposTente.push(ultimaArestaSenao);
}
else {
// Se não há senão, o caminho de sucesso também continua
anterioresAposTente.push(ultimaArestaTente);
}
// Caminho finalmente (finally) - se existir
if (declaracao.caminhoFinalmente && declaracao.caminhoFinalmente.length > 0) {
this.anteriores = anterioresAposTente;
const arestaFinalmente = new mermaid_1.ArestaFluxograma(declaracao, `Linha${declaracao.linha}Finalmente(finalmente)`);
vertices = vertices.concat(this.logicaComumConexaoArestas(arestaFinalmente));
this.anteriores.push(arestaFinalmente);
const verticesFinalmente = [];
for (const declaracaoFinalmente of declaracao.caminhoFinalmente) {
const verticesDeclaracao = await declaracaoFinalmente.aceitar(this);
verticesFinalmente.push(...verticesDeclaracao);
}
vertices = vertices.concat(verticesFinalmente);
}
else {
// Se não há finalmente, os anteriores são os caminhos após tente
this.anteriores = anterioresAposTente;
}
return Promise.resolve(vertices);
}
visitarDeclaracaoTextoDocumentacao(declaracao) {
throw new Error('Método não implementado.');
}
async visitarDeclaracaoVar(declaracao) {
let texto = `Linha${declaracao.linha}(variável: ${declaracao.simbolo.lexema}`;
texto += await this.logicaComumTraducaoVarEConst(declaracao, texto);
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
const vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
return Promise.resolve(vertices);
}
visitarDeclaracaoVarMultiplo(declaracao) {
throw new Error('Método não implementado.');
}
async visitarExpressaoDeAtribuicao(expressao) {
const textoAlvo = await expressao.alvo.aceitar(this);
const textoValor = await expressao.valor.aceitar(this);
return Promise.resolve(`${textoAlvo} recebe: ${textoValor}`);
}
async visitarExpressaoAcessoIndiceVariavel(expressao) {
const textoIndice = await expressao.indice.aceitar(this);
return Promise.resolve(`no índice ${textoIndice}`);
}
visitarExpressaoAcessoIntervaloVariavel(expressao) {
throw new Error('Método não implementado.');
}
visitarExpressaoAcessoElementoMatriz(expressao) {
throw new Error('Método não implementado.');
}
async visitarExpressaoAcessoMetodo(expressao) {
return Promise.resolve(`método ${expressao.nomeMetodo}`);
}
async visitarExpressaoAcessoMetodoOuPropriedade(expressao) {
return Promise.resolve(`método ou propriedade ${expressao.simbolo.lexema}`);
}
async visitarExpressaoAcessoPropriedade(expressao) {
return Promise.resolve(`propriedade ${expressao.nomePropriedade}`);
}
async visitarExpressaoAgrupamento(expressao) {
return await expressao.expressao.aceitar(this);
}
async visitarExpressaoArgumentoReferenciaFuncao(expressao) {
const nomeFuncao = expressao.simboloFuncao.lexema;
return Promise.resolve(`referência à função ${nomeFuncao}`);
}
async visitarExpressaoAtribuicaoPorIndice(expressao) {
const textoObjeto = await expressao.objeto.aceitar(this);
const textoIndice = await expressao.indice.aceitar(this);
const textoValor = await expressao.valor.aceitar(this);
return Promise.resolve(`${textoObjeto} no índice ${textoIndice} recebe: ${textoValor}`);
}
visitarExpressaoAtribuicaoPorIndicesMatriz(expressao) {
throw new Error('Método não implementado.');
}
async visitarExpressaoBinaria(expressao) {
const operandoEsquerdo = await expressao.esquerda.aceitar(this);
const operandoDireito = await expressao.direita.aceitar(this);
switch (expressao.operador.tipo) {
case delegua_1.default.ADICAO:
return Promise.resolve(`somar ${operandoEsquerdo} e ${operandoDireito}`);
case delegua_1.default.SUBTRACAO:
return Promise.resolve(`subtrair ${operandoDireito} de ${operandoEsquerdo}`);
case delegua_1.default.MULTIPLICACAO:
return Promise.resolve(`multiplicar ${operandoEsquerdo} por ${operandoDireito}`);
case delegua_1.default.DIVISAO:
return Promise.resolve(`dividir ${operandoEsquerdo} por ${operandoDireito}`);
case delegua_1.default.MODULO:
return Promise.resolve(`resto de ${operandoEsquerdo} dividido por ${operandoDireito}`);
case delegua_1.default.MENOR:
return Promise.resolve(`${operandoEsquerdo} for menor que ${operandoDireito}`);
case delegua_1.default.MENOR_IGUAL:
return Promise.resolve(`${operandoEsquerdo} for menor ou igual a ${operandoDireito}`);
case delegua_1.default.MAIOR:
return Promise.resolve(`${operandoEsquerdo} for maior que ${operandoDireito}`);
case delegua_1.default.MAIOR_IGUAL:
return Promise.resolve(`${operandoEsquerdo} for maior ou igual a ${operandoDireito}`);
case delegua_1.default.IGUAL_IGUAL:
return Promise.resolve(`${operandoEsquerdo} for igual a ${operandoDireito}`);
case delegua_1.default.DIFERENTE:
return Promise.resolve(`${operandoEsquerdo} for diferente de ${operandoDireito}`);
}
return Promise.resolve('');
}
async visitarExpressaoBloco(bloco) {
let vertices = [];
for (const declaracao of bloco.declaracoes) {
const verticesDeclaracao = await declaracao.aceitar(this);
vertices = vertices.concat(verticesDeclaracao);
}
return Promise.resolve(vertices);
}
async visitarExpressaoComentario(expressao) {
return Promise.resolve('');
}
async visitarExpressaoContinua(declaracao) {
const texto = `Linha${declaracao.linha}(continua)`;
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
const vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
return Promise.resolve(vertices);
}
async visitarExpressaoDeChamada(expressao) {
const textoEntidadeChamada = await expressao.entidadeChamada.aceitar(this);
let texto = `chamada a ${textoEntidadeChamada}`;
if (expressao.argumentos.length > 0) {
texto += `, com argumentos: `;
for (const argumento of expressao.argumentos) {
const textoArgumento = await argumento.aceitar(this);
texto += `${textoArgumento}, `;
}
texto = texto.slice(0, -2);
}
else {
texto += `, sem argumentos`;
}
return Promise.resolve(texto);
}
async visitarExpressaoDefinirValor(expressao) {
const textoObjeto = await expressao.objeto.aceitar(this);
const textoValor = await expressao.valor.aceitar(this);
return Promise.resolve(`${expressao.nome.lexema} em ${textoObjeto} recebe ${textoValor}`);
}
async visitarExpressaoFuncaoConstruto(expressao) {
let texto = 'função anônima';
if (expressao.parametros && expressao.parametros.length > 0) {
const parametros = expressao.parametros.map((p) => p.nome.lexema).join(', ');
texto += `(${parametros})`;
}
else {
texto += '()';
}
return Promise.resolve(texto);
}
async visitarExpressaoDeVariavel(expressao) {
return Promise.resolve(expressao.simbolo.lexema);
}
async visitarExpressaoDicionario(expressao) {
let texto = `dicionário`;
if (expressao.chaves.length > 0) {
texto += `, com `;
for (const [chave, indice] of Object.entries(expressao.chaves)) {
texto += `chave ${chave} definida com o valor ${expressao.valores[0]}`;
}
}
else {
texto += ' vazio';
}
return Promise.resolve(texto);
}
async visitarExpressaoExpressaoRegular(expressao) {
// Representa a expressão regular como texto para o fluxograma
const padraoRegex = expressao.valor ? String(expressao.valor) : expressao.simbolo.lexema;
return Promise.resolve(`expressão regular: /${padraoRegex}/`);
}
async visitarExpressaoFalhar(expressao) {
let texto = `Linha${expressao.linha}(falhar`;
if (expressao.explicacao) {
const textoExplicacao = await expressao.explicacao.aceitar(this);
texto += `: ${textoExplicacao}`;
}
texto += ')';
const aresta = new mermaid_1.ArestaFluxograma(expressao, texto);
const vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
return Promise.resolve(vertices);
}
visitarExpressaoFimPara(declaracao) {
throw new Error('Método não implementado.');
}
async visitarExpressaoFormatacaoEscrita(declaracao) {
const textoExpressao = await declaracao.expressao.aceitar(this);
let formato = textoExpressao;
// Adiciona informações de formatação se especificadas
const partes = [textoExpressao];
if (declaracao.espacos > 0) {
partes.push(`${declaracao.espacos} espaços`);
}
if (declaracao.casasDecimais > 0) {
partes.push(`${declaracao.casasDecimais} casas decimais`);
}
if (partes.length > 1) {
formato = `${partes[0]} (${partes.slice(1).join(', ')})`;
}
return Promise.resolve(formato);
}
async visitarExpressaoIsto(expressao) {
return Promise.resolve('this');
}
async visitarExpressaoLeia(expressao) {
let texto = 'leia da entrada';
if (expressao.argumentos && expressao.argumentos.length > 0) {
const textoArgumento = await expressao.argumentos[0].aceitar(this);
texto += `, imprimindo antes: \\'${textoArgumento}\\'`;
}
return Promise.resolve(texto);
}
async visitarExpressaoLiteral(expressao) {
switch (expressao.tipo) {
case 'lógico':
return Promise.resolve(expressao.valor ? 'verdadeiro' : 'falso');
case 'texto':
return Promise.resolve(`\\'${expressao.valor}\\'`);
default:
return Promise.resolve(String(expressao.valor));
}
}
async visitarExpressaoLogica(expressao) {
const operandoEsquerdo = await expressao.esquerda.aceitar(this);
const operandoDireito = await expressao.direita.aceitar(this);
switch (expressao.operador.tipo) {
case delegua_1.default.E:
return Promise.resolve(`${operandoEsquerdo} e ${operandoDireito}`);
case delegua_1.default.OU:
return Promise.resolve(`${operandoEsquerdo} ou ${operandoDireito}`);
}
return Promise.resolve('');
}
async visitarExpressaoReferenciaFuncao(expressao) {
const nomeFuncao = expressao.simboloFuncao.lexema;
return Promise.resolve(`@${nomeFuncao}`);
}
async visitarExpressaoRetornar(expressao) {
let texto = `Linha${expressao.linha}(retorna`;
if (expressao.valor) {
texto += `: ${await expressao.valor.aceitar(this)}`;
}
texto += ')';
const aresta = new mermaid_1.ArestaFluxograma(expressao, texto);
const vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
return Promise.resolve(vertices);
}
async visitarExpressaoSeparador(expressao) {
return Promise.resolve(`${expressao.conteudo} `);
}
async visitarExpressaoSuper(expressao) {
return Promise.resolve('super');
}
async visitarExpressaoSustar(declaracao) {
const texto = `Linha${declaracao.linha}(sustar)`;
const aresta = new mermaid_1.ArestaFluxograma(declaracao, texto);
const vertices = this.logicaComumConexaoArestas(aresta);
this.anteriores.push(aresta);
return Promise.resolve(vertices);
}
async visitarExpressaoTupla(expressao) {
// Tupla base pode ter um único valor
if (expressao.valor !== undefined) {
return Promise.resolve(`tupla(${expressao.valor})`);
}
// Se não houver valor, tupla vazia
return Promise.resolve('tupla()');
}
async visitarExpressaoTuplaN(expressao) {
const valores = [];
for (const elemento of expressao.elementos) {
const valorTraduzido = await elemento.aceitar(this);
valores.push(valorTraduzido);
}
return Promise.resolve(`tupla(${valores.join(', ')})`);
}
visitarExpressaoTipoDe(expressao) {
throw new Error('Método não implementado.');
}
async visitarExpressaoUnaria(expressao) {
const textoOperando = await expressao.operando.aceitar(this);
let textoOperador = '';
switch (expressao.operador.tipo) {
case delegua_1.default.INCREMENTAR:
textoOperador = `incrementar ${textoOperando} em 1`;
break;
case delegua_1.default.DECREMENTAR:
textoOperador = `decrementar ${textoOperando} de 1`;
break;
}
switch (expressao.incidenciaOperador) {
case 'ANTES':
return Promise.resolve(`${textoOperador}, devolver valor de ${textoOperando}`);
case 'DEPOIS':
return Promise.resolve(`devolver valor de ${textoOperando}, ${textoOperador}`);
}
}
async visitarExpressaoVetor(expressao) {
let texto = `vetor: `;
for (const elemento of expressao.valores) {
texto += await elemento.aceitar(this);
}
return Promise.resolve(texto);
}
async visitarExpressaoMorsa(expressao) {
const variavel = await expressao.variavel.aceitar(this);
const valor = await expressao.valor.aceitar(this);
return `${variavel} := ${valor}`;
}
/**
* Traduz uma declaração de Expressao que contém uma chamada de função,
* criando os vértices necessários para conectar ao subgrafo da função.
*/
async traduzirChamadaFuncao(declaracaoExpressao, chamada) {
// Verifica se é uma chamada a uma função conhecida
if (chamada.entidadeChamada.constructor === construtos_1.Variavel) {
const variavel = chamada.entidadeChamada;
const nomeFuncao = variavel.simbolo.lexema;
if (this.declaracoesFuncoes[nomeFuncao]) {
const subgrafo = this.declaracoesFuncoes[nomeFuncao];
let vertices = [];
// Conecta do fluxo atual para a entrada da função
const textoPreChamada = `Linha${declaracaoExpressao.linha}(${await chamada.aceitar(this)})`;
const arestaPreChamada = new mermaid_1.ArestaFluxograma(declaracaoExpressao, textoPreChamada);
vertices = vertices.concat(this.logicaComumConexaoArestas(arestaPreChamada));
// Conecta a pré-chamada ao início da função
vertices.push(new mermaid_1.VerticeFluxograma(arestaPreChamada, subgrafo.arestaInicial));
// A saída da função volta para o fluxo principal
this.anteriores = [subgrafo.arestaFinal];
return Promise.resolve(vertices);
}
}
// Se não for uma função conhecida, trata como expressão normal
return Promise.resolve([]);
}
logicaComumConexaoArestas(aresta) {
const vertices = [];
while (this.anteriores.length > 0) {
const anterior = this.anteriores.shift();
let textoVertice = undefined;
if (this.ultimaDicaVertice) {
textoVertice = String(this.ultimaDicaVertice);
this.ultimaDicaVertice = undefined;
}
vertices.push(new mermaid_1.VerticeFluxograma(anterior, aresta, textoVertice));
}
return vertices;
}
async logicaComumCaminhoEscolha(declaracaoEscolha, caminhoEscolha, linha, textoIdentificadorOuLiteral, caminhoPadrao) {
let textoCaso = '';
if (!caminhoPadrao) {
textoCaso = `caso ${textoIdentificadorOuLiteral} seja igual a `;
for (const condicao of caminhoEscolha.condicoes) {
const textoCondicao = await condicao.aceitar(this);
textoCaso += `${textoCondicao} ou `;
}
textoCaso = textoCaso.slice(0, -4);
textoCaso += ':';
}
else {
textoCaso = `caso ${textoIdentificadorOuLiteral} tenha qualquer outro valor:`;
}
let textoCaminho = `Linha${linha}(${textoCaso})`;
const arestaCondicaoCaminho = new mermaid_1.ArestaFluxograma(declaracaoEscolha, textoCaminho);
this.anteriores.push(arestaCondicaoCaminho);
let verticesResolvidos = [];
for (const declaracaoCaminho of caminhoEscolha.declaracoes) {
const verticesDeclaracoes = await declaracaoCaminho.aceitar(this);
verticesResolvidos = verticesResolvidos.concat(verticesDeclaracoes);
this.anteriores.pop();
this.anteriores.push(verticesDeclaracoes[verticesDeclaracoes.length - 1].destino);
}
this.anteriores.pop();
return Promise.resolve({
caminho: arestaCondicaoCaminho,
declaracoesCaminho: verticesResolvidos,
});
}
async logicaComumTraducaoVarEConst(declaracaoVarOuConst, textoInicial) {
let adicional = '';
if (declaracaoVarOuConst.inicializador) {
adicional += `, iniciada com: ${await declaracaoVarOuConst.inicializador.aceitar(this)}`;
}
adicional += ')';
return Promise.resolve(adicional);
}
/**
* Ponto de entrada para a tradução de declarações em um fluxograma
* no formato MermaidJs.
* @param {Declaracao[]} declaracoes As declarações a serem traduzidas.
* @returns {string} Texto no formato MermaidJs representando o fluxograma.
*/
async traduzir(declaracoes) {
this.anteriores = [];
this.vertices = [];
let resultado = 'graph TD;\n';
this.indentacaoAtual = 4;
this.declaracoesFuncoes = {};
this.declaracoesClasses = {};
for (const declaracao of declaracoes) {
this.vertices = this.vertices.concat(await declaracao.aceitar(this));
}
// Renderiza os subgrafos de funções
if (Object.keys(this.declaracoesFuncoes).length > 0) {
for (const [nomeFuncao, subgrafo] of Object.entries(this.declaracoesFuncoes)) {
resultado += ` subgraph ${nomeFuncao}["Função: ${nomeFuncao}()"]\n`;
// Renderiza os vértices da função
for (const vertice of subgrafo.vertices) {
resultado += ' ' + vertice.paraTexto();
}
resultado += ` end\n`;
}
}
// Renderiza os subgrafos de classes
if (Object.keys(this.declaracoesClasses).length > 0) {
for (const [nomeClasse, subgrafo] of Object.entries(this.declaracoesClasses)) {
resultado += subgrafo.paraTexto();
}
}
if (this.vertices.length === 0 && this.anteriores.length === 0) {
resultado += ` Vazio;\n`;
}
if (this.vertices.length > 0) {
for (const vertice of this.vertices) {
resultado += vertice.paraTexto();
}
}
if (this.anteriores.length > 0) {
while (this.anteriores.length > 0) {
const anterior = this.anteriores.shift();
let seta = '-->';
if (this.ultimaDicaVertice) {
seta = `-->|${this.ultimaDicaVertice}|`;
this.ultimaDicaVertice = undefined;
}
resultado += ` ${anterior.texto}${seta}Fim;\n`;
}
}
return resultado;
}
}
exports.TradutorMermaidJs = TradutorMermaidJs;
//# sourceMappingURL=tradutor-mermaidjs.js.map