@designliquido/delegua
Version:
Linguagem de programação simples e moderna usando português estruturado.
450 lines • 22.7 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 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