diff --git a/fontes/formatadores/formatador-portugol-studio.ts b/fontes/formatadores/formatador-portugol-studio.ts new file mode 100644 index 00000000..2ee586c4 --- /dev/null +++ b/fontes/formatadores/formatador-portugol-studio.ts @@ -0,0 +1,338 @@ +import { AcessoIndiceVariavel, AcessoMetodoOuPropriedade, Agrupamento, AtribuicaoPorIndice, Atribuir, Binario, Chamada, Construto, DefinirValor, Dicionario, ExpressaoRegular, FimPara, FormatacaoEscrita, FuncaoConstruto, Isto, Literal, Logico, Super, TipoDe, Unario, Variavel, Vetor } from "../construtos"; +import { Classe, Const, ConstMultiplo, Expressao, FuncaoDeclaracao, Enquanto, Escolha, Escreva, Fazer, Importar, Para, ParaCada, Se, Tente, Var, VarMultiplo, Bloco, Continua, EscrevaMesmaLinha, Leia, LeiaMultiplo, Retorna, Sustar, Declaracao, Falhar } from "../declaracoes"; +import { VisitanteComumInterface } from "../interfaces"; +import { ContinuarQuebra, RetornoQuebra, SustarQuebra } from "../quebras"; + +export class FormatadorPortugolStudio implements VisitanteComumInterface { + indentacaoAtual: number; + quebraLinha: string; + tamanhoIndentacao: number; + codigoFormatado: string; + devePularLinha: boolean; + deveIndentar: boolean; + + constructor(quebraLinha: string, tamanhoIndentacao: number = 4) { + this.quebraLinha = quebraLinha; + this.tamanhoIndentacao = tamanhoIndentacao; + + this.indentacaoAtual = 0; + this.codigoFormatado = ''; + this.devePularLinha = true; + this.deveIndentar = true; + } + + visitarDeclaracaoClasse(declaracao: Classe) { + throw new Error("Método não implementado"); + } + visitarDeclaracaoConst(declaracao: Const): Promise { + throw new Error("Método não implementado"); + } + visitarDeclaracaoConstMultiplo(declaracao: ConstMultiplo): Promise { + throw new Error("Método não implementado"); + } + visitarDeclaracaoDeAtribuicao(expressao: Atribuir) { + throw new Error("Método não implementado"); + } + + visitarDeclaracaoDeExpressao(declaracao: Expressao) { + // throw new Error("Método não implementado"); + } + + visitarDeclaracaoDefinicaoFuncao(declaracao: FuncaoDeclaracao) { + this.codigoFormatado += `${" ".repeat(this.indentacaoAtual)}funcao ${declaracao.simbolo.lexema}()${this.quebraLinha}`; + + this.codigoFormatado += `${" ".repeat(this.indentacaoAtual)}{${this.quebraLinha}`; + this.visitarExpressaoFuncaoConstruto(declaracao.funcao); + this.codigoFormatado += `${" ".repeat(this.indentacaoAtual)}}${this.quebraLinha}`; + } + + visitarDeclaracaoEnquanto(declaracao: Enquanto) { + throw new Error("Método não implementado"); + } + visitarDeclaracaoEscolha(declaracao: Escolha) { + throw new Error("Método não implementado"); + } + + visitarDeclaracaoEscreva(declaracao: Escreva) { + this.codigoFormatado += `${" ".repeat(this.indentacaoAtual)}escreva(`; + for (let argumento of declaracao.argumentos) { + this.formatarDeclaracaoOuConstruto(argumento); + } + + this.codigoFormatado += `)${this.quebraLinha}`; + } + + visitarDeclaracaoFazer(declaracao: Fazer) { + throw new Error("Método não implementado"); + } + visitarDeclaracaoImportar(declaracao: Importar) { + throw new Error("Método não implementado"); + } + visitarDeclaracaoPara(declaracao: Para): Promise { + throw new Error("Método não implementado"); + } + visitarDeclaracaoParaCada(declaracao: ParaCada): Promise { + throw new Error("Método não implementado"); + } + visitarDeclaracaoSe(declaracao: Se) { + throw new Error("Método não implementado"); + } + visitarDeclaracaoTente(declaracao: Tente) { + throw new Error("Método não implementado"); + } + visitarDeclaracaoVar(declaracao: Var): Promise { + throw new Error("Método não implementado"); + } + visitarDeclaracaoVarMultiplo(declaracao: VarMultiplo): Promise { + throw new Error("Método não implementado"); + } + visitarExpressaoAcessoIndiceVariavel(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoAcessoElementoMatriz(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoAcessoMetodo(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoAgrupamento(expressao: any): Promise { + throw new Error("Método não implementado"); + } + visitarExpressaoAtribuicaoPorIndice(expressao: any): Promise { + throw new Error("Método não implementado"); + } + visitarExpressaoAtribuicaoPorIndicesMatriz(expressao: any): Promise { + throw new Error("Método não implementado"); + } + visitarExpressaoBinaria(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoBloco(declaracao: Bloco): Promise { + throw new Error("Método não implementado"); + } + visitarExpressaoContinua(declaracao?: Continua): ContinuarQuebra { + throw new Error("Método não implementado"); + } + visitarExpressaoDeChamada(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoDefinirValor(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoDeleguaFuncao(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoDeVariavel(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoDicionario(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoExpressaoRegular(expressao: ExpressaoRegular): Promise { + throw new Error("Método não implementado"); + } + visitarDeclaracaoEscrevaMesmaLinha(declaracao: EscrevaMesmaLinha) { + throw new Error("Método não implementado"); + } + visitarExpressaoFalhar(expressao: any): Promise { + throw new Error("Método não implementado"); + } + visitarExpressaoFimPara(declaracao: FimPara) { + throw new Error("Método não implementado"); + } + visitarExpressaoFormatacaoEscrita(declaracao: FormatacaoEscrita) { + throw new Error("Método não implementado"); + } + visitarExpressaoFuncaoConstruto(expressao: FuncaoConstruto) { + this.indentacaoAtual += this.tamanhoIndentacao; + + for (let declaracaoCorpo of expressao.corpo) { + this.formatarDeclaracaoOuConstruto(declaracaoCorpo); + } + + this.indentacaoAtual -= this.tamanhoIndentacao; + } + visitarExpressaoIsto(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoLeia(expressao: Leia): Promise { + throw new Error("Método não implementado"); + } + visitarExpressaoLeiaMultiplo(expressao: LeiaMultiplo): Promise { + throw new Error("Método não implementado"); + } + + visitarExpressaoLiteral(expressao: Literal): any { + if (typeof expressao.valor === 'string') { + this.codigoFormatado += `"${expressao.valor}"`; + return; + } + + this.codigoFormatado += `${expressao.valor}`; + } + + visitarExpressaoLogica(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoRetornar(declaracao: Retorna): Promise { + throw new Error("Método não implementado"); + } + visitarExpressaoSuper(expressao: Super) { + throw new Error("Método não implementado"); + } + visitarExpressaoSustar(declaracao?: Sustar): SustarQuebra { + throw new Error("Método não implementado"); + } + visitarExpressaoTipoDe(expressao: TipoDe): Promise { + throw new Error("Método não implementado"); + } + visitarExpressaoUnaria(expressao: any) { + throw new Error("Método não implementado"); + } + visitarExpressaoVetor(expressao: any) { + throw new Error("Método não implementado"); + } + + formatarDeclaracaoOuConstruto(declaracaoOuConstruto: Declaracao | Construto): void { + switch (declaracaoOuConstruto.constructor.name) { + case 'AcessoIndiceVariavel': + this.visitarExpressaoAcessoIndiceVariavel(declaracaoOuConstruto as AcessoIndiceVariavel); + break; + case 'AcessoMetodoOuPropriedade': + this.visitarExpressaoAcessoMetodo(declaracaoOuConstruto as AcessoMetodoOuPropriedade); + break; + case 'Agrupamento': + this.visitarExpressaoAgrupamento(declaracaoOuConstruto as Agrupamento); + break; + case 'AtribuicaoPorIndice': + this.visitarExpressaoAtribuicaoPorIndice(declaracaoOuConstruto as AtribuicaoPorIndice); + break; + case 'Atribuir': + this.visitarDeclaracaoDeAtribuicao(declaracaoOuConstruto as Atribuir); + break; + case 'Binario': + this.visitarExpressaoBinaria(declaracaoOuConstruto as Binario); + break; + case 'Bloco': + this.visitarExpressaoBloco(declaracaoOuConstruto as Bloco); + break; + case 'Chamada': + this.visitarExpressaoDeChamada(declaracaoOuConstruto as Chamada); + break; + case 'Classe': + this.visitarDeclaracaoClasse(declaracaoOuConstruto as Classe); + break; + case 'Continua': + this.visitarExpressaoContinua(declaracaoOuConstruto as Continua); + break; + case 'DefinirValor': + this.visitarExpressaoDefinirValor(declaracaoOuConstruto as DefinirValor); + break; + case 'Dicionario': + this.visitarExpressaoDicionario(declaracaoOuConstruto as Dicionario); + break; + case 'Escolha': + this.visitarDeclaracaoEscolha(declaracaoOuConstruto as Escolha); + break; + case 'Enquanto': + this.visitarDeclaracaoEnquanto(declaracaoOuConstruto as Enquanto); + break; + case 'Escreva': + this.visitarDeclaracaoEscreva(declaracaoOuConstruto as Escreva); + break; + case 'Expressao': + this.visitarDeclaracaoDeExpressao(declaracaoOuConstruto as Expressao); + break; + case 'ExpressaoRegular': + this.visitarExpressaoExpressaoRegular(declaracaoOuConstruto as ExpressaoRegular); + break; + case 'Falhar': + this.visitarExpressaoFalhar(declaracaoOuConstruto as Falhar) + break; + case 'Fazer': + this.visitarDeclaracaoFazer(declaracaoOuConstruto as Fazer); + break; + case 'FuncaoConstruto': + this.visitarExpressaoFuncaoConstruto(declaracaoOuConstruto as FuncaoConstruto); + break; + case 'FuncaoDeclaracao': + this.visitarDeclaracaoDefinicaoFuncao(declaracaoOuConstruto as FuncaoDeclaracao); + break; + case 'Importar': + this.visitarDeclaracaoImportar(declaracaoOuConstruto as Importar); + break; + case 'Isto': + this.visitarExpressaoIsto(declaracaoOuConstruto as Isto); + break; + case 'Leia': + this.visitarExpressaoLeia(declaracaoOuConstruto as Leia); + break; + case 'Literal': + this.visitarExpressaoLiteral(declaracaoOuConstruto as Literal); + break; + case 'Logico': + this.visitarExpressaoLogica(declaracaoOuConstruto as Logico); + break; + case 'Para': + this.visitarDeclaracaoPara(declaracaoOuConstruto as Para); + break; + case 'ParaCada': + this.visitarDeclaracaoParaCada(declaracaoOuConstruto as ParaCada); + break; + case 'Retorna': + this.visitarExpressaoRetornar(declaracaoOuConstruto as Retorna); + break; + case 'Se': + this.visitarDeclaracaoSe(declaracaoOuConstruto as Se); + break; + case 'Super': + this.visitarExpressaoSuper(declaracaoOuConstruto as Super); + break; + case 'Sustar': + this.visitarExpressaoSustar(declaracaoOuConstruto as Sustar); + break; + case 'Tente': + this.visitarDeclaracaoTente(declaracaoOuConstruto as Tente); + break; + case 'TipoDe': + this.visitarExpressaoTipoDe(declaracaoOuConstruto as TipoDe); + break; + case 'Unario': + this.visitarExpressaoUnaria(declaracaoOuConstruto as Unario); + break; + case 'Const': + this.visitarDeclaracaoConst(declaracaoOuConstruto as Const); + break; + case 'Var': + this.visitarDeclaracaoVar(declaracaoOuConstruto as Var); + break; + case 'Variavel': + this.visitarExpressaoDeVariavel(declaracaoOuConstruto as Variavel); + break; + case 'Vetor': + this.visitarExpressaoVetor(declaracaoOuConstruto as Vetor); + break; + default: + console.log(declaracaoOuConstruto.constructor.name); + break; + } + } + + + formatar(declaracoes: Declaracao[]): string { + this.indentacaoAtual = 0; + this.codigoFormatado = `programa${this.quebraLinha}{${this.quebraLinha}`; + this.devePularLinha = true; + this.deveIndentar = true; + this.indentacaoAtual += this.tamanhoIndentacao; + + for (let declaracao of declaracoes) { + this.formatarDeclaracaoOuConstruto(declaracao); + } + + this.indentacaoAtual -= this.tamanhoIndentacao; + this.codigoFormatado += `}${this.quebraLinha}`; + + return this.codigoFormatado; + } +} \ No newline at end of file diff --git a/fontes/formatadores/index.ts b/fontes/formatadores/index.ts index f04435eb..72f662f9 100644 --- a/fontes/formatadores/index.ts +++ b/fontes/formatadores/index.ts @@ -1 +1,2 @@ export * from './formatador-delegua'; +export * from './formatador-portugol-studio'; diff --git a/testes/portugol-studio/formatador.test.ts b/testes/portugol-studio/formatador.test.ts new file mode 100644 index 00000000..f6e0a807 --- /dev/null +++ b/testes/portugol-studio/formatador.test.ts @@ -0,0 +1,31 @@ +import * as sistemaOperacional from 'os'; + +import { FormatadorPortugolStudio } from '../../fontes/formatadores'; +import { LexadorPortugolStudio } from '../../fontes/lexador/dialetos'; +import { AvaliadorSintaticoPortugolStudio } from '../../fontes/avaliador-sintatico/dialetos'; + +describe('Formatadores > Portugol Studio', () => { + const formatador = new FormatadorPortugolStudio(sistemaOperacional.EOL); + const avaliadorSintatico = new AvaliadorSintaticoPortugolStudio(); + const lexador = new LexadorPortugolStudio(); + + it('Olá mundo', () => { + const retornoLexador = lexador.mapear([ + 'programa', + '{', + ' ', + ' funcao inicio()', + ' {', + ' escreva("Olá Mundo")', + ' }', + '}' + ], -1); + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + const resultado = formatador.formatar(retornoAvaliadorSintatico.declaracoes); + const linhasResultado = resultado.split(sistemaOperacional.EOL); + + // console.log(resultado); + expect(linhasResultado).toHaveLength(8); + }); + +});