UNPKG

@designliquido/delegua

Version:

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

450 lines 22.7 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 delegua_1 = __importDefault(require("../tipos-de-simbolos/delegua")); class ArestaFluxograma { constructor(declaracao, texto) { this.declaracao = declaracao; this.texto = texto; } } class VerticeFluxograma { constructor(origem, destino, texto) { this.origem = origem; this.destino = destino; this.texto = texto; } paraTexto() { const seta = this.texto ? `-->|${this.texto}|` : '-->'; return ` ${this.origem.texto}${seta}${this.destino.texto};\n`; } } /** * [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 { constructor() { this.dicionarioConstrutos = { AcessoIndiceVariavel: this.traduzirConstrutoAcessoIndiceVariavel.bind(this), AcessoMetodo: this.traduzirConstrutoAcessoMetodo.bind(this), AcessoMetodoOuPropriedade: this.traduzirConstrutoAcessoMetodoOuPropriedade.bind(this), AcessoPropriedade: this.traduzirConstrutoAcessoPropriedade.bind(this), Agrupamento: this.traduzirConstrutoAgrupamento.bind(this), Atribuir: this.traduzirConstrutoAtribuir.bind(this), Binario: this.traduzirConstrutoBinario.bind(this), Chamada: this.traduzirConstrutoChamada.bind(this), Comentario: () => '', DefinirValor: this.traduzirConstrutoDefinirValor.bind(this), Dicionario: this.traduzirConstrutoDicionario.bind(this), FuncaoConstruto: this.traduzirFuncaoConstruto.bind(this), Isto: () => 'this', Leia: this.traduzirConstrutoLeia.bind(this), Literal: this.traduzirConstrutoLiteral.bind(this), Unario: this.traduzirConstrutoUnario.bind(this), Variavel: this.traduzirConstrutoVariavel.bind(this), Vetor: this.traduzirConstrutoVetor.bind(this), }; this.dicionarioDeclaracoes = { Bloco: this.traduzirDeclaracaoBloco.bind(this), Const: this.traduzirDeclaracaoConst.bind(this), Enquanto: this.traduzirDeclaracaoEnquanto.bind(this), Escolha: this.traduzirDeclaracaoEscolha.bind(this), Expressao: this.traduzirDeclaracaoExpressao.bind(this), Escreva: this.traduzirDeclaracaoEscreva.bind(this), Fazer: this.traduzirDeclaracaoFazerEnquanto.bind(this), Para: this.traduzirDeclaracaoPara.bind(this), ParaCada: this.traduzirDeclaracaoParaCada.bind(this), Se: this.traduzirDeclaracaoSe.bind(this), Var: this.traduzirDeclaracaoVar.bind(this), }; } traduzirConstrutoAcessoIndiceVariavel(acessoIndiceVariavel) { const textoIndice = this.dicionarioConstrutos[acessoIndiceVariavel.indice.constructor.name](acessoIndiceVariavel.indice); return `no índice ${textoIndice}`; } traduzirConstrutoAcessoMetodo(acessoMetodo) { return `método ${acessoMetodo.nomeMetodo}`; } traduzirConstrutoAcessoMetodoOuPropriedade(acessoMetodoOuPropriedade) { return `método ou propriedade ${acessoMetodoOuPropriedade.simbolo.lexema}`; } traduzirConstrutoAcessoPropriedade(acessoPropriedade) { return `propriedade ${acessoPropriedade.nomePropriedade}`; } traduzirConstrutoAgrupamento(agrupamento) { return this.dicionarioConstrutos[agrupamento.expressao.constructor.name](agrupamento.expressao); } traduzirConstrutoAtribuir(atribuir) { const textoAlvo = this.dicionarioConstrutos[atribuir.alvo.constructor.name](atribuir.alvo); const textoValor = this.dicionarioConstrutos[atribuir.valor.constructor.name](atribuir.valor); return `${textoAlvo} recebe: ${textoValor}`; } traduzirConstrutoBinario(binario) { const operandoEsquerdo = this.dicionarioConstrutos[binario.esquerda.constructor.name](binario.esquerda); const operandoDireito = this.dicionarioConstrutos[binario.direita.constructor.name](binario.direita); switch (binario.operador.tipo) { case delegua_1.default.ADICAO: return `somar ${operandoEsquerdo} e ${operandoDireito}`; case delegua_1.default.MENOR: return `${operandoEsquerdo} for menor que ${operandoDireito}`; } return ''; } traduzirConstrutoChamada(chamada) { const textoEntidadeChamada = this.dicionarioConstrutos[chamada.entidadeChamada.constructor.name](chamada.entidadeChamada); let texto = `chamada a ${textoEntidadeChamada}`; if (chamada.argumentos.length > 0) { texto += `, com argumentos: `; for (const argumento of chamada.argumentos) { const textoArgumento = this.dicionarioConstrutos[argumento.constructor.name](argumento); texto += `${textoArgumento}, `; } texto = texto.slice(0, -2); } else { texto += `, sem argumentos`; } return texto; } traduzirConstrutoDefinirValor(definirValor) { const textoObjeto = this.dicionarioConstrutos[definirValor.objeto.constructor.name](definirValor.objeto); const textoValor = this.dicionarioConstrutos[definirValor.valor.constructor.name](definirValor.valor); return `${definirValor.nome.lexema} em ${textoObjeto} recebe ${textoValor}`; } traduzirConstrutoDicionario(dicionario) { let texto = `dicionário`; if (dicionario.chaves.length > 0) { texto += `, com `; for (const [chave, indice] of Object.entries(dicionario.chaves)) { texto += `chave ${chave} definida com o valor ${dicionario.valores[0]}`; } } else { texto += ' vazio'; } return texto; } traduzirFuncaoConstruto(funcaoConstruto) { return `função`; } traduzirConstrutoLeia(leia) { let texto = 'leia da entrada'; if (leia.argumentos && leia.argumentos.length > 0) { const textoArgumento = this.dicionarioConstrutos[leia.argumentos[0].constructor.name](leia.argumentos[0]); texto += `, imprimindo antes: \\'${textoArgumento}\\'`; } return texto; } traduzirConstrutoLiteral(literal) { switch (literal.tipo) { case 'lógico': return literal.valor ? 'verdadeiro' : 'falso'; case 'texto': return `\\'${literal.valor}\\'`; default: return literal.valor; } } traduzirConstrutoUnario(unario) { const textoOperando = this.dicionarioConstrutos[unario.operando.constructor.name](unario.operando); let textoOperador = ''; switch (unario.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 (unario.incidenciaOperador) { case 'ANTES': return `${textoOperador}, devolver valor de ${textoOperando}`; case 'DEPOIS': return `devolver valor de ${textoOperando}, ${textoOperador}`; } } traduzirConstrutoVariavel(variavel) { return variavel.simbolo.lexema; } traduzirConstrutoVetor(vetor) { let texto = `vetor: `; for (const elemento of vetor.valores) { // Na grande maioria dos casos, cada elemento é um construto. const textoValor = this.dicionarioConstrutos[elemento.constructor.name](elemento); texto += `${textoValor}, `; } texto = texto.slice(0, -2); return texto; } 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 VerticeFluxograma(anterior, aresta, textoVertice)); } return vertices; } traduzirDeclaracaoBloco(declaracaoBloco) { let vertices = []; for (const declaracao of declaracaoBloco.declaracoes) { const verticesDeclaracao = this.dicionarioDeclaracoes[declaracao.constructor.name](declaracao); vertices = vertices.concat(verticesDeclaracao); } return vertices; } traduzirDeclaracaoConst(declaracaoConst) { let texto = `Linha${declaracaoConst.linha}(variável: ${declaracaoConst.simbolo.lexema}`; texto += this.logicaComumTraducaoVarEConst(declaracaoConst, texto); const aresta = new ArestaFluxograma(declaracaoConst, texto); const vertices = this.logicaComumConexaoArestas(aresta); this.anteriores.push(aresta); return vertices; } traduzirDeclaracaoEnquanto(declaracaoEnquanto) { let texto = `Linha${declaracaoEnquanto.linha}(enquanto `; const condicao = this.dicionarioConstrutos[declaracaoEnquanto.condicao.constructor.name](declaracaoEnquanto.condicao); texto += condicao + ')'; const aresta = new ArestaFluxograma(declaracaoEnquanto, texto); let vertices = this.logicaComumConexaoArestas(aresta); this.anteriores.push(aresta); // Corpo, normalmente um `Bloco`. const verticesCorpo = this.dicionarioDeclaracoes[declaracaoEnquanto.corpo.constructor.name](declaracaoEnquanto.corpo); vertices = vertices.concat(verticesCorpo); const ultimaArestaCorpo = verticesCorpo[verticesCorpo.length - 1].destino; const verticeLaco = new VerticeFluxograma(ultimaArestaCorpo, aresta); vertices.push(verticeLaco); return vertices; } logicaComumCaminhoEscolha(declaracaoEscolha, caminhoEscolha, linha, textoIdentificadorOuLiteral, caminhoPadrao) { let textoCaso = ''; if (!caminhoPadrao) { textoCaso = `caso ${textoIdentificadorOuLiteral} seja igual a `; for (const condicao of caminhoEscolha.condicoes) { const textoCondicao = this.dicionarioConstrutos[condicao.constructor.name](condicao); 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 ArestaFluxograma(declaracaoEscolha, textoCaminho); this.anteriores.push(arestaCondicaoCaminho); let verticesResolvidos = []; for (const declaracaoCaminho of caminhoEscolha.declaracoes) { const verticesDeclaracoes = this.dicionarioDeclaracoes[declaracaoCaminho.constructor.name](declaracaoCaminho); verticesResolvidos = verticesResolvidos.concat(verticesDeclaracoes); this.anteriores.pop(); this.anteriores.push(verticesDeclaracoes[verticesDeclaracoes.length - 1].destino); } this.anteriores.pop(); return { caminho: arestaCondicaoCaminho, declaracoesCaminho: verticesResolvidos, }; } traduzirDeclaracaoEscolha(declaracaoEscolha) { let texto = `Linha${declaracaoEscolha.linha}(escolha um caminho pelo valor de `; const textoIdentificadorOuLiteral = this.dicionarioConstrutos[declaracaoEscolha.identificadorOuLiteral.constructor.name](declaracaoEscolha.identificadorOuLiteral); texto += textoIdentificadorOuLiteral + ')'; const aresta = new ArestaFluxograma(declaracaoEscolha, texto); let vertices = this.logicaComumConexaoArestas(aresta); const arestasCaminho = []; for (const caminho of declaracaoEscolha.caminhos) { arestasCaminho.push(this.logicaComumCaminhoEscolha(declaracaoEscolha, caminho, caminho.condicoes[0].linha, textoIdentificadorOuLiteral, false)); } if (declaracaoEscolha.caminhoPadrao) { arestasCaminho.push(this.logicaComumCaminhoEscolha(declaracaoEscolha, declaracaoEscolha.caminhoPadrao, declaracaoEscolha.caminhoPadrao.declaracoes[0].linha - 1, textoIdentificadorOuLiteral, true)); } for (const conjunto of Object.values(arestasCaminho)) { const verticeEscolhaECaminho = new VerticeFluxograma(aresta, conjunto.caminho); vertices.push(verticeEscolhaECaminho); vertices = vertices.concat(conjunto.declaracoesCaminho); this.anteriores.push(conjunto.declaracoesCaminho[conjunto.declaracoesCaminho.length - 1].destino); } return vertices; } traduzirDeclaracaoEscreva(declaracaoEscreva) { let texto = `Linha${declaracaoEscreva.linha}(escreva: `; for (const argumento of declaracaoEscreva.argumentos) { const valor = this.dicionarioConstrutos[argumento.constructor.name](argumento); texto += valor + ', '; } texto = texto.slice(0, -2); texto += ')'; const aresta = new ArestaFluxograma(declaracaoEscreva, texto); const vertices = this.logicaComumConexaoArestas(aresta); this.anteriores.push(aresta); return vertices; } traduzirDeclaracaoExpressao(declaracaoExpressao) { let texto = `Linha${declaracaoExpressao.linha}(`; const textoConstruto = this.dicionarioConstrutos[declaracaoExpressao.expressao.constructor.name](declaracaoExpressao.expressao); texto += textoConstruto + ')'; const aresta = new ArestaFluxograma(declaracaoExpressao, texto); const vertices = this.logicaComumConexaoArestas(aresta); this.anteriores.push(aresta); return vertices; } traduzirDeclaracaoFazerEnquanto(declaracaoFazerEnquanto) { const texto = `Linha${declaracaoFazerEnquanto.linha}(fazer)`; const aresta = new ArestaFluxograma(declaracaoFazerEnquanto, texto); let vertices = this.logicaComumConexaoArestas(aresta); this.anteriores.push(aresta); // Corpo, normalmente um `Bloco`. const verticesCorpo = this.dicionarioDeclaracoes[declaracaoFazerEnquanto.caminhoFazer.constructor.name](declaracaoFazerEnquanto.caminhoFazer); vertices = vertices.concat(verticesCorpo); const ultimaArestaCorpo = verticesCorpo[verticesCorpo.length - 1].destino; const condicao = this.dicionarioConstrutos[declaracaoFazerEnquanto.condicaoEnquanto.constructor.name](declaracaoFazerEnquanto.condicaoEnquanto); let textoEnquanto = `Linha${declaracaoFazerEnquanto.condicaoEnquanto.linha}(enquanto ${condicao})`; const arestaEnquanto = new ArestaFluxograma(declaracaoFazerEnquanto, textoEnquanto); const verticeEnquanto = new VerticeFluxograma(ultimaArestaCorpo, arestaEnquanto); vertices.push(verticeEnquanto); const verticeCondicaoComFazer = new VerticeFluxograma(arestaEnquanto, aresta); vertices.push(verticeCondicaoComFazer); this.anteriores.pop(); this.anteriores.push(arestaEnquanto); return vertices; } traduzirDeclaracaoPara(declaracaoPara) { let texto = `Linha${declaracaoPara.linha}(para `; if (declaracaoPara.inicializador) { for (const declaracaoInicializadora of declaracaoPara.inicializador) { // Normalmente é `Var`. const declaracaoVar = declaracaoInicializadora; const valorInicializacao = this.dicionarioConstrutos[declaracaoVar.inicializador.constructor.name](declaracaoVar.inicializador); texto += `uma variável ${declaracaoVar.simbolo.lexema} inicializada com ${valorInicializacao}, `; } texto = texto.slice(0, -2); } texto += ')'; const aresta = new ArestaFluxograma(declaracaoPara, texto); let vertices = this.logicaComumConexaoArestas(aresta); this.anteriores.push(aresta); // Condição const textoCondicao = this.dicionarioConstrutos[declaracaoPara.condicao.constructor.name](declaracaoPara.condicao); const textoArestaCondicao = `Linha${declaracaoPara.linha}Condicao{se ${textoCondicao}}`; const arestaCondicao = new ArestaFluxograma(declaracaoPara, textoArestaCondicao); vertices = vertices.concat(this.logicaComumConexaoArestas(arestaCondicao)); this.anteriores.push(arestaCondicao); this.ultimaDicaVertice = 'Sim'; // Corpo, normalmente um `Bloco`. const verticesCorpo = this.dicionarioDeclaracoes[declaracaoPara.corpo.constructor.name](declaracaoPara.corpo); vertices = vertices.concat(verticesCorpo); // Incremento const ultimaArestaCorpo = verticesCorpo[verticesCorpo.length - 1].destino; const textoIncremento = this.dicionarioConstrutos[declaracaoPara.incrementar.constructor.name](declaracaoPara.incrementar); const arestaIncremento = new ArestaFluxograma(declaracaoPara, `Linha${declaracaoPara.linha}Incremento(${textoIncremento})`); const verticeIncremento = new VerticeFluxograma(ultimaArestaCorpo, arestaIncremento); vertices.push(verticeIncremento); const verticeLaco = new VerticeFluxograma(arestaIncremento, arestaCondicao); vertices.push(verticeLaco); // Configura a condição como anterior this.anteriores.pop(); this.anteriores.push(arestaCondicao); this.ultimaDicaVertice = 'Não'; return vertices; } traduzirDeclaracaoParaCada(declaracaoParaCada) { let texto = `Linha${declaracaoParaCada.linha}(para cada ${declaracaoParaCada.nomeVariavelIteracao} em `; const textoVariavelIterada = this.dicionarioConstrutos[declaracaoParaCada.vetor.constructor.name](declaracaoParaCada.vetor); texto += textoVariavelIterada + ')'; const aresta = new ArestaFluxograma(declaracaoParaCada, texto); let vertices = this.logicaComumConexaoArestas(aresta); this.anteriores.push(aresta); // Corpo, normalmente um `Bloco`. const verticesCorpo = this.dicionarioDeclaracoes[declaracaoParaCada.corpo.constructor.name](declaracaoParaCada.corpo); vertices = vertices.concat(verticesCorpo); const ultimaArestaCorpo = verticesCorpo[verticesCorpo.length - 1].destino; vertices.push(new VerticeFluxograma(ultimaArestaCorpo, aresta)); return vertices; } traduzirDeclaracaoSe(declaracaoSe) { let texto = `Linha${declaracaoSe.linha}{se `; const condicao = this.dicionarioConstrutos[declaracaoSe.condicao.constructor.name](declaracaoSe.condicao); texto += condicao; texto += `}`; const aresta = new ArestaFluxograma(declaracaoSe, texto); let vertices = this.logicaComumConexaoArestas(aresta); this.anteriores.push(aresta); this.ultimaDicaVertice = 'Sim'; // Caminho então, normalmente um `Bloco`. const verticesEntao = this.dicionarioDeclaracoes[declaracaoSe.caminhoEntao.constructor.name](declaracaoSe.caminhoEntao); vertices = vertices.concat(verticesEntao); const ultimaArestaEntao = verticesEntao[verticesEntao.length - 1].destino; if (declaracaoSe.caminhoSenao) { this.anteriores = []; const arestaSenao = new ArestaFluxograma(declaracaoSe, `Linha${declaracaoSe.caminhoSenao.linha}(senão)`); vertices.push(new VerticeFluxograma(aresta, arestaSenao, 'Não')); this.anteriores.push(arestaSenao); const verticesSenao = this.dicionarioDeclaracoes[declaracaoSe.caminhoSenao.constructor.name](declaracaoSe.caminhoSenao); vertices = vertices.concat(verticesSenao); } this.anteriores.push(ultimaArestaEntao); return vertices; } logicaComumTraducaoVarEConst(declaracaoVarOuConst, textoInicial) { if (declaracaoVarOuConst.inicializador) { textoInicial += `, iniciada com: ${this.dicionarioConstrutos[declaracaoVarOuConst.inicializador.constructor.name](declaracaoVarOuConst.inicializador)}`; } textoInicial += ')'; return textoInicial; } traduzirDeclaracaoVar(declaracaoVar) { let texto = `Linha${declaracaoVar.linha}(variável: ${declaracaoVar.simbolo.lexema}`; texto += this.logicaComumTraducaoVarEConst(declaracaoVar, texto); const aresta = new ArestaFluxograma(declaracaoVar, texto); const vertices = this.logicaComumConexaoArestas(aresta); this.anteriores.push(aresta); return vertices; } traduzir(declaracoes) { this.anteriores = []; this.vertices = []; let resultado = 'graph TD;\n'; for (const declaracao of declaracoes) { this.vertices = this.vertices.concat(this.dicionarioDeclaracoes[declaracao.constructor.name](declaracao)); } 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