From a7c6e40ff76b3e79ad93751cbb5f5d8fa22d983b Mon Sep 17 00:00:00 2001 From: "Pablo T. de Vargas" Date: Sat, 28 Oct 2023 21:54:37 -0300 Subject: [PATCH] =?UTF-8?q?WIP:=20[potigol]=20-=20implementa=C3=A7=C3=A3o?= =?UTF-8?q?=20qual=5Ftipo=20(#528)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 2 +- .../potigol/avaliador-sintatico-potigol.ts | 23 +++++- fontes/construtos/index.ts | 1 + fontes/construtos/qual-tipo.ts | 24 ++++++ .../interpretador-interface-potigol.ts | 7 ++ .../interpretador-egua-classico.ts | 5 ++ .../egua-classico/resolvedor/resolvedor.ts | 10 ++- .../interpretador-portugol-ipt.ts | 6 +- .../dialetos/potigol/inferenciador.ts | 5 +- .../dialetos/potigol/interpretador-potigol.ts | 28 ++++++- fontes/interpretador/interpretador-base.ts | 5 ++ .../dialetos/palavras-reservadas/potigol.ts | 1 + fontes/tipos-de-simbolos/potigol.ts | 1 + testes/interpretador.test.ts | 16 ++++ testes/potigol/avaliador-sintatico.test.ts | 2 +- testes/potigol/interpretador.test.ts | 81 +++++++++++++++++-- 16 files changed, 197 insertions(+), 20 deletions(-) create mode 100644 fontes/construtos/qual-tipo.ts create mode 100644 fontes/interfaces/interpretador-interface-potigol.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index da2c0409..85e4e026 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -724,7 +724,7 @@ "runtimeArgs": [ "--inspect-brk", "${workspaceRoot}/node_modules/jest/bin/jest.js", - "potigol/interpretador.test.ts", + "potigol/avaliador-sintatico.test.ts", "--runInBand" ], "skipFiles": [ diff --git a/fontes/avaliador-sintatico/dialetos/potigol/avaliador-sintatico-potigol.ts b/fontes/avaliador-sintatico/dialetos/potigol/avaliador-sintatico-potigol.ts index 5ee80c6f..9c3b6efa 100644 --- a/fontes/avaliador-sintatico/dialetos/potigol/avaliador-sintatico-potigol.ts +++ b/fontes/avaliador-sintatico/dialetos/potigol/avaliador-sintatico-potigol.ts @@ -13,6 +13,7 @@ import { FuncaoConstruto, Isto, Literal, + QualTipo, Unario, Variavel, Vetor, @@ -409,9 +410,21 @@ export class AvaliadorSintaticoPotigol extends AvaliadorSintaticoBase { } expressao = this.finalizarChamada(expressao); } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO)) { - const nome = this.consumir(tiposDeSimbolos.IDENTIFICADOR, "Esperado nome do método após '.'."); - const variavelMetodo = new Variavel(expressao.hashArquivo, (expressao as any).simbolo); - expressao = new AcessoMetodo(this.hashArquivo, variavelMetodo, nome); + if (this.verificarTipoSimboloAtual(tiposDeSimbolos.QUAL_TIPO)) { + const identificador = this.simbolos[this.atual - 2]; + const simbolo = this.simbolos[this.atual]; + const valor = expressao ? expressao : identificador.lexema; + this.avancarEDevolverAnterior(); + return new QualTipo( + this.hashArquivo, + simbolo, + valor + ); + } else { + const nome = this.consumir(tiposDeSimbolos.IDENTIFICADOR, "Esperado nome do método após '.'."); + const variavelMetodo = new Variavel(expressao.hashArquivo, (expressao as any).simbolo); + expressao = new AcessoMetodo(this.hashArquivo, variavelMetodo, nome); + } } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.COLCHETE_ESQUERDO)) { const indice = this.expressao(); const simboloFechamento = this.consumir( @@ -449,10 +462,14 @@ export class AvaliadorSintaticoPotigol extends AvaliadorSintaticoBase { const argumentos: Construto[] = []; + this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_ESQUERDO) + do { argumentos.push(this.expressao()); } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA)); + this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PARENTESE_DIREITO) + return new Escreva(Number(simboloAtual.linha), simboloAtual.hashArquivo, argumentos); } diff --git a/fontes/construtos/index.ts b/fontes/construtos/index.ts index e0914ff2..9850d26e 100644 --- a/fontes/construtos/index.ts +++ b/fontes/construtos/index.ts @@ -22,3 +22,4 @@ export * from './tipo-de'; export * from './unario'; export * from './variavel'; export * from './vetor'; +export * from './qual-tipo'; \ No newline at end of file diff --git a/fontes/construtos/qual-tipo.ts b/fontes/construtos/qual-tipo.ts new file mode 100644 index 00000000..f3365781 --- /dev/null +++ b/fontes/construtos/qual-tipo.ts @@ -0,0 +1,24 @@ +import { SimboloInterface } from '../interfaces'; +import { InterpretadorInterfacePotigol } from '../interfaces/interpretador-interface-potigol'; +import { Construto } from './construto'; + + +export class QualTipo implements Construto { + linha: number; + hashArquivo: number; + valor: any; + + simbolo: SimboloInterface; + + constructor(hashArquivo: number, simbolo: SimboloInterface, valor: any) { + this.linha = Number(simbolo.linha); + this.hashArquivo = hashArquivo; + this.valor = valor; + this.simbolo = simbolo; + } + + async aceitar(visitante: InterpretadorInterfacePotigol): Promise { + return Promise.resolve(visitante.visitarExpressaoQualTipo(this)); + } +} + diff --git a/fontes/interfaces/interpretador-interface-potigol.ts b/fontes/interfaces/interpretador-interface-potigol.ts new file mode 100644 index 00000000..b4fc386a --- /dev/null +++ b/fontes/interfaces/interpretador-interface-potigol.ts @@ -0,0 +1,7 @@ +import { QualTipo } from '../construtos'; + +import { VisitanteComumInterface } from './visitante-comum-interface'; + +export interface InterpretadorInterfacePotigol extends VisitanteComumInterface { + visitarExpressaoQualTipo(expressao: QualTipo): Promise; +} diff --git a/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts b/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts index a37cd048..2d4bf7c0 100644 --- a/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts +++ b/fontes/interpretador/dialetos/egua-classico/interpretador-egua-classico.ts @@ -15,6 +15,7 @@ import { FimPara, FormatacaoEscrita, Literal, + QualTipo, Super, TipoDe, Variavel, @@ -98,6 +99,10 @@ export class InterpretadorEguaClassico implements InterpretadorInterface { throw new Error('Método não implementado.'); } + visitarExpressaoQualTipo(expressao: QualTipo): Promise { + throw new Error('Método não implementado.'); + } + visitarExpressaoFalhar(expressao: any): Promise { throw new Error('Método não implementado.'); } diff --git a/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts b/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts index ae418711..2ae31449 100644 --- a/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts +++ b/fontes/interpretador/dialetos/egua-classico/resolvedor/resolvedor.ts @@ -1,4 +1,4 @@ -import { AcessoMetodo, Construto, ExpressaoRegular, FimPara, FormatacaoEscrita, Super, TipoDe, Variavel } from '../../../../construtos'; +import { AcessoMetodo, Construto, ExpressaoRegular, FimPara, FormatacaoEscrita, QualTipo, Super, TipoDe, Variavel } from '../../../../construtos'; import { Bloco, Const, @@ -75,15 +75,19 @@ export class ResolvedorEguaClassico implements ResolvedorInterface, Interpretado this.classeAtual = TipoClasse.NENHUM; this.cicloAtual = TipoClasse.NENHUM; } - + visitarExpressaoExpressaoRegular(expressao: ExpressaoRegular): Promise { throw new Error('Método não implementado.'); } - + visitarExpressaoTipoDe(expressao: TipoDe): Promise { throw new Error('Método não implementado.'); } + visitarExpressaoQualTipo(expressao: QualTipo): Promise { + throw new Error('Método não implementado.'); + } + visitarExpressaoFalhar(expressao: any): Promise { throw new Error('Método não implementado.'); } diff --git a/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts b/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts index 49a575c9..c9d3ef7e 100644 --- a/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts +++ b/fontes/interpretador/dialetos/portugol-ipt/interpretador-portugol-ipt.ts @@ -1,4 +1,4 @@ -import { Atribuir, Construto, ExpressaoRegular, FimPara, FormatacaoEscrita, Literal, Super, TipoDe, Variavel } from '../../../construtos'; +import { Atribuir, Construto, ExpressaoRegular, FimPara, FormatacaoEscrita, Literal, QualTipo, Super, TipoDe, Variavel } from '../../../construtos'; import { Bloco, Classe, @@ -81,6 +81,10 @@ export class InterpretadorPortugolIpt implements InterpretadorInterface { throw new Error('Método não implementado.'); } + visitarExpressaoQualTipo(expressao: QualTipo): Promise { + throw new Error('Método não implementado.'); + } + visitarExpressaoFalhar(expressao: any): Promise { throw new Error('Método não implementado.'); } diff --git a/fontes/interpretador/dialetos/potigol/inferenciador.ts b/fontes/interpretador/dialetos/potigol/inferenciador.ts index 2e740e73..b53e00d6 100644 --- a/fontes/interpretador/dialetos/potigol/inferenciador.ts +++ b/fontes/interpretador/dialetos/potigol/inferenciador.ts @@ -4,7 +4,8 @@ export function inferirTipoVariavel(variavel: string | number | Array | boo case 'string': return 'Texto'; case 'number': - return 'Número'; + if (variavel.toString().indexOf('.') > -1) return 'Real'; + return 'Inteiro'; case 'bigint': return 'Longo'; case 'boolean': @@ -12,7 +13,7 @@ export function inferirTipoVariavel(variavel: string | number | Array | boo case 'undefined': return 'Nulo'; case 'object': - if (Array.isArray(variavel)) return 'vetor'; + if (Array.isArray(variavel)) return 'Lista'; if (variavel === null) return 'nulo'; if (variavel.constructor.name === 'DeleguaModulo') return 'módulo'; return 'Dicionário'; diff --git a/fontes/interpretador/dialetos/potigol/interpretador-potigol.ts b/fontes/interpretador/dialetos/potigol/interpretador-potigol.ts index d0279589..82cffbf3 100644 --- a/fontes/interpretador/dialetos/potigol/interpretador-potigol.ts +++ b/fontes/interpretador/dialetos/potigol/interpretador-potigol.ts @@ -1,15 +1,17 @@ import { InterpretadorBase } from '../../interpretador-base'; import { registrarBibliotecaGlobalPotigol } from '../../../bibliotecas/dialetos/potigol/biblioteca-global'; -import { AcessoMetodo } from '../../../construtos'; +import { AcessoMetodo, Binario, ConstanteOuVariavel, Literal, QualTipo, Unario, Variavel } from '../../../construtos'; import * as comum from './comum'; import { ObjetoPadrao } from '../../../estruturas'; +import { inferirTipoVariavel } from './inferenciador'; +import { InterpretadorInterfacePotigol } from '../../../interfaces/interpretador-interface-potigol'; /** * Uma implementação do interpretador de Potigol. */ -export class InterpretadorPotigol extends InterpretadorBase { +export class InterpretadorPotigol extends InterpretadorBase implements InterpretadorInterfacePotigol { constructor( diretorioBase: string, performance = false, @@ -55,4 +57,26 @@ export class InterpretadorPotigol extends InterpretadorBase { async visitarExpressaoAcessoMetodo(expressao: AcessoMetodo): Promise { return comum.visitarExpressaoAcessoMetodo(this, expressao); } + + async visitarExpressaoQualTipo(expressao: QualTipo): Promise { + let qualTipo = expressao.valor; + + if (expressao?.valor instanceof ConstanteOuVariavel) { + const nome = expressao?.valor.simbolo.lexema + qualTipo = this.pilhaEscoposExecucao.topoDaPilha().ambiente.valores[nome].valor + } + + if ( + qualTipo instanceof Binario || + qualTipo instanceof Literal || + qualTipo instanceof QualTipo || + qualTipo instanceof Unario || + qualTipo instanceof Variavel + ) { + qualTipo = await this.avaliar(qualTipo); + return qualTipo.tipo || inferirTipoVariavel(qualTipo); + } + + return inferirTipoVariavel(qualTipo?.valores || qualTipo); + } } diff --git a/fontes/interpretador/interpretador-base.ts b/fontes/interpretador/interpretador-base.ts index 906f6c85..d5ae1193 100644 --- a/fontes/interpretador/interpretador-base.ts +++ b/fontes/interpretador/interpretador-base.ts @@ -55,6 +55,7 @@ import { FormatacaoEscrita, Literal, Logico, + QualTipo, Super, TipoDe, Unario, @@ -171,6 +172,10 @@ export class InterpretadorBase implements InterpretadorInterface { return inferirTipoVariavel(tipoDe?.valores || tipoDe); } + async visitarExpressaoQualTipo(expressao: QualTipo): Promise { + throw new Error('Método não implementado.'); + } + visitarExpressaoFalhar(expressao: Falhar): Promise { throw new ErroEmTempoDeExecucao(expressao.simbolo, expressao.explicacao, expressao.linha); } diff --git a/fontes/lexador/dialetos/palavras-reservadas/potigol.ts b/fontes/lexador/dialetos/palavras-reservadas/potigol.ts index 9f065573..377d05d7 100644 --- a/fontes/lexador/dialetos/palavras-reservadas/potigol.ts +++ b/fontes/lexador/dialetos/palavras-reservadas/potigol.ts @@ -42,4 +42,5 @@ export const palavrasReservadas = { tipo: tiposDeSimbolos.TIPO, var: tiposDeSimbolos.VARIAVEL, verdadeiro: tiposDeSimbolos.VERDADEIRO, + qual_tipo: tiposDeSimbolos.QUAL_TIPO, }; diff --git a/fontes/tipos-de-simbolos/potigol.ts b/fontes/tipos-de-simbolos/potigol.ts index e0d79cc9..76b38fc6 100644 --- a/fontes/tipos-de-simbolos/potigol.ts +++ b/fontes/tipos-de-simbolos/potigol.ts @@ -59,4 +59,5 @@ export default { VERDADEIRO: 'VERDADEIRO', VARIAVEL: 'VARIAVEL', VIRGULA: 'VIRGULA', + QUAL_TIPO: 'QUAL_TIPO', }; diff --git a/testes/interpretador.test.ts b/testes/interpretador.test.ts index 3ff8ab24..1a5b06c4 100644 --- a/testes/interpretador.test.ts +++ b/testes/interpretador.test.ts @@ -224,6 +224,22 @@ describe('Interpretador', () => { expect(retornoInterpretador.erros).toHaveLength(0); }); + it('Tipo de número', async () => { + const retornoLexador = lexador.mapear([ + "escreva(tipo de 123)", + ], -1); + + interpretador.funcaoDeRetorno = (saida: any) => { + expect(saida).toEqual("número"); + }; + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + + const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + + expect(retornoInterpretador.erros).toHaveLength(0); + }); + it('Ordem lexicográfica de textos', async () => { const retornoLexador = lexador.mapear([ "escreva('batata' > 'arroz')", diff --git a/testes/potigol/avaliador-sintatico.test.ts b/testes/potigol/avaliador-sintatico.test.ts index 1c73505d..f4819c00 100644 --- a/testes/potigol/avaliador-sintatico.test.ts +++ b/testes/potigol/avaliador-sintatico.test.ts @@ -40,7 +40,7 @@ describe('Avaliador sintático', () => { const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); expect(retornoAvaliadorSintatico).toBeTruthy(); - expect(retornoAvaliadorSintatico.declaracoes).toHaveLength(1); + expect(retornoAvaliadorSintatico.declaracoes).toHaveLength(2); }); it('Sucesso - Mod e Div', () => { diff --git a/testes/potigol/interpretador.test.ts b/testes/potigol/interpretador.test.ts index 5b24f12b..f36b44fc 100644 --- a/testes/potigol/interpretador.test.ts +++ b/testes/potigol/interpretador.test.ts @@ -45,24 +45,71 @@ describe('Interpretador', () => { }); }); - describe('Declaração de lista', () => { - it('Dado em vetor, escreva deve imprirmir o vetor', async () => { + describe('qual_tipo', () => { + it('Dado um inteiro, escreva qual_tipo deve retornar Inteiro', async () => { const retornoLexador = lexador.mapear([ - 'a = [3, 4]', - 'escreva (a)' + 'a = 3', + 'escreva(a.qual_tipo)' ], -1); // Substitua a função de saída interpretador.funcaoDeRetorno = (saida: any) => { - expect(saida).toEqual('[3, 4]'); + expect(saida).toEqual("Inteiro"); }; const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); expect(retornoInterpretador.erros).toHaveLength(0); }); - - it.skip('WIP: Dado em vetor, escreva qual_tipo deve imprirmir Lista', async () => { + + it('Dado um inteiro, escreva qual_tipo deve retornar Inteiro 2', async () => { + const retornoLexador = lexador.mapear([ + 'escreva(3.qual_tipo)' + ], -1); + + // Substitua a função de saída + interpretador.funcaoDeRetorno = (saida: any) => { + expect(saida).toEqual("Inteiro"); + }; + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + expect(retornoInterpretador.erros).toHaveLength(0); + }); + + it('Dado um real, escreva qual_tipo deve retornar Real', async () => { + const retornoLexador = lexador.mapear([ + 'a = 3.1', + 'escreva(a.qual_tipo)' + ], -1); + + // Substitua a função de saída + interpretador.funcaoDeRetorno = (saida: any) => { + expect(saida).toEqual("Real"); + }; + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + expect(retornoInterpretador.erros).toHaveLength(0); + }); + + it('Dado uma variável, escreva qual_tipo deve atribuir Inteiro', async () => { + const retornoLexador = lexador.mapear([ + 'a = 3.qual_tipo', + 'escreva(a)' + ], -1); + + // Substitua a função de saída + interpretador.funcaoDeRetorno = (saida: any) => { + expect(saida).toEqual("Inteiro"); + }; + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + expect(retornoInterpretador.erros).toHaveLength(0); + }); + + it('Dado um vetor, escreva qual_tipo deve imprirmir Lista', async () => { const retornoLexador = lexador.mapear([ 'a = [3, 4]', 'escreva (a.qual_tipo)' @@ -77,6 +124,26 @@ describe('Interpretador', () => { const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); expect(retornoInterpretador.erros).toHaveLength(0); }); + }); + + describe('Declaração de lista', () => { + it('Dado um vetor, escreva deve imprirmir o vetor', async () => { + const retornoLexador = lexador.mapear([ + 'a = [3, 4]', + 'escreva (a)' + ], -1); + + // Substitua a função de saída + interpretador.funcaoDeRetorno = (saida: any) => { + expect(saida).toEqual('[3, 4]'); + }; + + const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1); + const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + expect(retornoInterpretador.erros).toHaveLength(0); + }); + + }) }); });