UNPKG

@designliquido/delegua

Version:

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

828 lines 41 kB
"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