diff --git a/fontes/avaliador-sintatico/avaliador-sintatico.ts b/fontes/avaliador-sintatico/avaliador-sintatico.ts index 84ee1870..f9408925 100644 --- a/fontes/avaliador-sintatico/avaliador-sintatico.ts +++ b/fontes/avaliador-sintatico/avaliador-sintatico.ts @@ -3601,7 +3601,8 @@ export class AvaliadorSintatico 'intervalo', new InformacaoElementoSintatico('intervalo', 'inteiro[]', true, [ new InformacaoElementoSintatico('valorInicial', 'qualquer'), - new InformacaoElementoSintatico('valorFinal', 'qualquer'), + new InformacaoElementoSintatico('valorFinal', 'qualquer', false), + new InformacaoElementoSintatico('valorPasso', 'qualquer', false), ]) ); this.pilhaEscopos.definirInformacoesVariavel( diff --git a/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.ts b/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.ts index e11e26bc..10c609a0 100644 --- a/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.ts +++ b/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-pitugues.ts @@ -2301,7 +2301,8 @@ export class AvaliadorSintaticoPitugues 'intervalo', new InformacaoElementoSintatico('intervalo', 'inteiro[]', true, [ new InformacaoElementoSintatico('valorInicial', 'qualquer'), - new InformacaoElementoSintatico('valorFinal', 'qualquer'), + new InformacaoElementoSintatico('valorFinal', 'qualquer', false), + new InformacaoElementoSintatico('valorPasso', 'qualquer', false), ]) ); this.pilhaEscopos.definirInformacoesVariavel( diff --git a/fontes/bibliotecas/biblioteca-global.ts b/fontes/bibliotecas/biblioteca-global.ts index 1acbcb94..8715d9aa 100644 --- a/fontes/bibliotecas/biblioteca-global.ts +++ b/fontes/bibliotecas/biblioteca-global.ts @@ -810,47 +810,98 @@ export async function longo( * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | number} valorInicial O valor inicial (inclusivo). * @param {VariavelInterface | number} valorFinal O valor final (exclusivo). + * @param {VariavelInterface | number} valorPasso O valor do passo. * @returns {Promise} Um vetor com os números no intervalo. */ export async function intervalo( interpretador: InterpretadorInterface, valorInicial: VariavelInterface | number, - valorFinal: VariavelInterface | number + valorFinal?: VariavelInterface | number, + valorPasso?: VariavelInterface | number, ): Promise { - const inicio = interpretador.resolverValor(valorInicial); - const fim = interpretador.resolverValor(valorFinal); + const primeiroParam = interpretador.resolverValor(valorInicial); + const segundoParam = interpretador.resolverValor(valorFinal); + const terceiroParam = interpretador.resolverValor(valorPasso); - if (typeof inicio !== 'number' || typeof fim !== 'number') { - return Promise.reject( - new ErroEmTempoDeExecucao( - { - hashArquivo: interpretador.hashArquivoDeclaracaoAtual, - linha: interpretador.linhaDeclaracaoAtual, - } as SimboloInterface, - 'Os dois parâmetros devem ser do tipo número ou inteiro.' - ) - ); - } + let inicioInteiro: number; + let fimInteiro: number; + let passoInteiro: number = 1; - if (isNaN(inicio) || isNaN(fim)) { - return Promise.reject( - new ErroEmTempoDeExecucao( - { - hashArquivo: interpretador.hashArquivoDeclaracaoAtual, - linha: interpretador.linhaDeclaracaoAtual, - } as SimboloInterface, - 'Os dois parâmetros devem ser do tipo número ou inteiro.' - ) - ); + // intervalo(parada) - apenas um parâmetro + if (segundoParam === undefined || segundoParam === null) { + if (typeof primeiroParam !== 'number' || isNaN(primeiroParam)) { + return Promise.reject( + new ErroEmTempoDeExecucao( + { + hashArquivo: interpretador.hashArquivoDeclaracaoAtual, + linha: interpretador.linhaDeclaracaoAtual, + } as SimboloInterface, + 'O parâmetro deve ser do tipo número ou inteiro.' + ) + ); + } + + inicioInteiro = 0; + fimInteiro = Math.floor(primeiroParam); } + // intervalo(inicio, parada) ou intervalo(inicio, parada, passo) + else { + if (typeof primeiroParam !== 'number' || isNaN(primeiroParam) || + typeof segundoParam !== 'number' || isNaN(segundoParam)) { + return Promise.reject( + new ErroEmTempoDeExecucao( + { + hashArquivo: interpretador.hashArquivoDeclaracaoAtual, + linha: interpretador.linhaDeclaracaoAtual, + } as SimboloInterface, + 'Os parâmetros de início e fim devem ser do tipo número ou inteiro.' + ) + ); + } - // Remove a parte decimal se houver - const inicioInteiro = Math.floor(inicio); - const fimInteiro = Math.floor(fim); + inicioInteiro = Math.floor(primeiroParam); + fimInteiro = Math.floor(segundoParam); + + // Se há um terceiro parâmetro (passo) + if (terceiroParam !== undefined && terceiroParam !== null) { + if (typeof terceiroParam !== 'number' || isNaN(terceiroParam)) { + return Promise.reject( + new ErroEmTempoDeExecucao( + { + hashArquivo: interpretador.hashArquivoDeclaracaoAtual, + linha: interpretador.linhaDeclaracaoAtual, + } as SimboloInterface, + 'O parâmetro de passo deve ser do tipo número ou inteiro.' + ) + ); + } + + passoInteiro = Math.floor(terceiroParam); + if (passoInteiro === 0) { + return Promise.reject( + new ErroEmTempoDeExecucao( + { + hashArquivo: interpretador.hashArquivoDeclaracaoAtual, + linha: interpretador.linhaDeclaracaoAtual, + } as SimboloInterface, + 'O passo não pode ser zero.' + ) + ); + } + } + } const resultado = []; - for (let i = inicioInteiro; i < fimInteiro; i++) { - resultado.push(i); + + if (passoInteiro > 0) { + for (let i = inicioInteiro; i < fimInteiro; i += passoInteiro) { + resultado.push(i); + } + } else { + // Parâmetro passo sendo um número negativo + for (let i = inicioInteiro; i > fimInteiro; i += passoInteiro) { + resultado.push(i); + } } return Promise.resolve(resultado); diff --git a/fontes/bibliotecas/dialetos/pitugues/biblioteca-global.ts b/fontes/bibliotecas/dialetos/pitugues/biblioteca-global.ts index 5e85b07a..37a2f985 100644 --- a/fontes/bibliotecas/dialetos/pitugues/biblioteca-global.ts +++ b/fontes/bibliotecas/dialetos/pitugues/biblioteca-global.ts @@ -587,47 +587,98 @@ export async function inteiro( * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | number} valorInicial O valor inicial (inclusivo). * @param {VariavelInterface | number} valorFinal O valor final (exclusivo). + * @param {VariavelInterface | number} valorPasso O valor do passo. * @returns {Promise} Um vetor com os números no intervalo. */ export async function intervalo( interpretador: InterpretadorInterface, valorInicial: VariavelInterface | number, - valorFinal: VariavelInterface | number + valorFinal?: VariavelInterface | number, + valorPasso?: VariavelInterface | number, ): Promise { - const inicio = interpretador.resolverValor(valorInicial); - const fim = interpretador.resolverValor(valorFinal); + const primeiroParam = interpretador.resolverValor(valorInicial); + const segundoParam = interpretador.resolverValor(valorFinal); + const terceiroParam = interpretador.resolverValor(valorPasso); - if (typeof inicio !== 'number' || typeof fim !== 'number') { - return Promise.reject( - new ErroEmTempoDeExecucao( - { - hashArquivo: interpretador.hashArquivoDeclaracaoAtual, - linha: interpretador.linhaDeclaracaoAtual, - } as SimboloInterface, - 'Os dois parâmetros devem ser do tipo número ou inteiro.' - ) - ); - } + let inicioInteiro: number; + let fimInteiro: number; + let passoInteiro: number = 1; - if (isNaN(inicio) || isNaN(fim)) { - return Promise.reject( - new ErroEmTempoDeExecucao( - { - hashArquivo: interpretador.hashArquivoDeclaracaoAtual, - linha: interpretador.linhaDeclaracaoAtual, - } as SimboloInterface, - 'Os dois parâmetros devem ser do tipo número ou inteiro.' - ) - ); + // intervalo(parada) - apenas um parâmetro + if (segundoParam === undefined || segundoParam === null) { + if (typeof primeiroParam !== 'number' || isNaN(primeiroParam)) { + return Promise.reject( + new ErroEmTempoDeExecucao( + { + hashArquivo: interpretador.hashArquivoDeclaracaoAtual, + linha: interpretador.linhaDeclaracaoAtual, + } as SimboloInterface, + 'O parâmetro deve ser do tipo número ou inteiro.' + ) + ); + } + + inicioInteiro = 0; + fimInteiro = Math.floor(primeiroParam); } + // intervalo(inicio, parada) ou intervalo(inicio, parada, passo) + else { + if (typeof primeiroParam !== 'number' || isNaN(primeiroParam) || + typeof segundoParam !== 'number' || isNaN(segundoParam)) { + return Promise.reject( + new ErroEmTempoDeExecucao( + { + hashArquivo: interpretador.hashArquivoDeclaracaoAtual, + linha: interpretador.linhaDeclaracaoAtual, + } as SimboloInterface, + 'Os parâmetros de início e fim devem ser do tipo número ou inteiro.' + ) + ); + } - // Remove a parte decimal se houver - const inicioInteiro = Math.floor(inicio); - const fimInteiro = Math.floor(fim); + inicioInteiro = Math.floor(primeiroParam); + fimInteiro = Math.floor(segundoParam); + + // Se há um terceiro parâmetro (passo) + if (terceiroParam !== undefined && terceiroParam !== null) { + if (typeof terceiroParam !== 'number' || isNaN(terceiroParam)) { + return Promise.reject( + new ErroEmTempoDeExecucao( + { + hashArquivo: interpretador.hashArquivoDeclaracaoAtual, + linha: interpretador.linhaDeclaracaoAtual, + } as SimboloInterface, + 'O parâmetro de passo deve ser do tipo número ou inteiro.' + ) + ); + } + + passoInteiro = Math.floor(terceiroParam); + if (passoInteiro === 0) { + return Promise.reject( + new ErroEmTempoDeExecucao( + { + hashArquivo: interpretador.hashArquivoDeclaracaoAtual, + linha: interpretador.linhaDeclaracaoAtual, + } as SimboloInterface, + 'O passo não pode ser zero.' + ) + ); + } + } + } const resultado = []; - for (let i = inicioInteiro; i < fimInteiro; i++) { - resultado.push(i); + + if (passoInteiro > 0) { + for (let i = inicioInteiro; i < fimInteiro; i += passoInteiro) { + resultado.push(i); + } + } else { + // Parâmetro passo sendo um número negativo + for (let i = inicioInteiro; i > fimInteiro; i += passoInteiro) { + resultado.push(i); + } } return Promise.resolve(resultado); diff --git a/fontes/interpretador/comum.ts b/fontes/interpretador/comum.ts index 972de578..4f348e08 100644 --- a/fontes/interpretador/comum.ts +++ b/fontes/interpretador/comum.ts @@ -56,7 +56,7 @@ export function carregarBibliotecasGlobais(pilhaEscoposExecucao: PilhaEscoposExe pilhaEscoposExecucao.definirVariavel('longo', new FuncaoPadrao(1, bibliotecaGlobal.longo)); - pilhaEscoposExecucao.definirVariavel('intervalo', new FuncaoPadrao(2, bibliotecaGlobal.intervalo)); + pilhaEscoposExecucao.definirVariavel('intervalo', new FuncaoPadrao(3, bibliotecaGlobal.intervalo)); pilhaEscoposExecucao.definirVariavel('mapear', new FuncaoPadrao(2, bibliotecaGlobal.mapear)); diff --git a/testes/interpretador/interpretador.test.ts b/testes/interpretador/interpretador.test.ts index ae40ad2d..2fec711d 100644 --- a/testes/interpretador/interpretador.test.ts +++ b/testes/interpretador/interpretador.test.ts @@ -1005,6 +1005,48 @@ describe('Interpretador', () => { expect(_saida).toBeTruthy(); expect(_saida).toBe('[0, 1, 2]'); }); + + it('Chamada a função nativa intervalo sem início definido', async () => { + let _saida: string = ''; + + const retornoLexador = lexador.mapear( + [ + 'escreva(intervalo(10))' + ], + -1 + ); + const retornoAvaliadorSintatico = await avaliadorSintatico.analisar(retornoLexador, -1); + + interpretador.funcaoDeRetorno = (saida: any) => { + _saida = saida; + }; + + await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + + expect(_saida).toBeTruthy(); + expect(_saida).toBe('[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'); + }); + + it('Chamada a função nativa intervalo com passo definido', async () => { + let _saida: string = ''; + + const retornoLexador = lexador.mapear( + [ + 'escreva(intervalo(0, 10, 2))' + ], + -1 + ); + const retornoAvaliadorSintatico = await avaliadorSintatico.analisar(retornoLexador, -1); + + interpretador.funcaoDeRetorno = (saida: any) => { + _saida = saida; + }; + + await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes); + + expect(_saida).toBeTruthy(); + expect(_saida).toBe('[0, 2, 4, 6, 8]'); + }); }); describe('Conversões entre tipos', () => {