UNPKG

@designliquido/delegua

Version:

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

1,104 lines 53.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.aleatorio = aleatorio; exports.aleatorioEntre = aleatorioEntre; exports.algum = algum; exports.arredondar = arredondar; exports.clonar = clonar; exports.encontrar = encontrar; exports.encontrarIndice = encontrarIndice; exports.encontrarUltimo = encontrarUltimo; exports.encontrarUltimoIndice = encontrarUltimoIndice; exports.filtrarPor = filtrarPor; exports.incluido = incluido; exports.inteiro = inteiro; exports.longo = longo; exports.intervalo = intervalo; exports.mapear = mapear; exports.maximo = maximo; exports.minimo = minimo; exports.numero = numero; exports.ordenar = ordenar; exports.paraCada = paraCada; exports.primeiroEmCondicao = primeiroEmCondicao; exports.real = real; exports.reduzir = reduzir; exports.somar = somar; exports.tamanho = tamanho; exports.texto = texto; exports.todos = todos; exports.todosEmCondicao = todosEmCondicao; exports.tupla = tupla; exports.vetor = vetor; const excecoes_1 = require("../excecoes"); const objeto_delegua_classe_1 = require("../interpretador/estruturas/objeto-delegua-classe"); const funcao_padrao_1 = require("../interpretador/estruturas/funcao-padrao"); const descritor_tipo_classe_1 = require("../interpretador/estruturas/descritor-tipo-classe"); const estruturas_1 = require("../interpretador/estruturas"); const construtos_1 = require("../construtos"); const quebras_1 = require("../quebras"); const configTuplas = { Dupla: { Classe: construtos_1.Dupla, props: ['primeiro', 'segundo'] }, Trio: { Classe: construtos_1.Trio, props: ['primeiro', 'segundo', 'terceiro'] }, Quarteto: { Classe: construtos_1.Quarteto, props: ['primeiro', 'segundo', 'terceiro', 'quarto'] }, Quinteto: { Classe: construtos_1.Quinteto, props: ['primeiro', 'segundo', 'terceiro', 'quarto', 'quinto'] }, Sexteto: { Classe: construtos_1.Sexteto, props: ['primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', 'sexto'], }, Septeto: { Classe: construtos_1.Septeto, props: ['primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', 'sexto', 'setimo'], }, Octeto: { Classe: construtos_1.Octeto, props: ['primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', 'sexto', 'setimo', 'oitavo'], }, Noneto: { Classe: construtos_1.Noneto, props: [ 'primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', 'sexto', 'setimo', 'oitavo', 'nono', ], }, Deceto: { Classe: construtos_1.Deceto, props: [ 'primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', 'sexto', 'setimo', 'oitavo', 'nono', 'decimo', ], }, }; const mapaConstrutoresTupla = { 2: construtos_1.Dupla, 3: construtos_1.Trio, 4: construtos_1.Quarteto, 5: construtos_1.Quinteto, 6: construtos_1.Sexteto, 7: construtos_1.Septeto, 8: construtos_1.Octeto, 9: construtos_1.Noneto, 10: construtos_1.Deceto, }; const mapaPropriedadesTuplas = { Dupla: ['primeiro', 'segundo'], Trio: ['primeiro', 'segundo', 'terceiro'], Quarteto: ['primeiro', 'segundo', 'terceiro', 'quarto'], Quinteto: ['primeiro', 'segundo', 'terceiro', 'quarto', 'quinto'], Sexteto: ['primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', 'sexto'], Septeto: ['primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', 'sexto', 'setimo'], Octeto: ['primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', 'sexto', 'setimo', 'oitavo'], Noneto: [ 'primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', 'sexto', 'setimo', 'oitavo', 'nono', ], Deceto: [ 'primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', 'sexto', 'setimo', 'oitavo', 'nono', 'decimo', ], }; /** * Compara dois valores (números ou vetores). * Retorna: * > 0 se a > b * < 0 se a < b * 0 se a == b * Lança erro se os tipos forem incompatíveis. */ function compararElementosRecursivamente(a, b) { if (typeof a === 'number' && typeof b === 'number') { return a - b; } if (Array.isArray(a) && Array.isArray(b)) { const tamanho = Math.min(a.length, b.length); for (let i = 0; i < tamanho; i++) { const comparacao = compararElementosRecursivamente(a[i], b[i]); if (comparacao !== 0) return comparacao; } return a.length - b.length; } // Tipos incompatíveis (ex: comparar número com vetor) throw new Error('Tipos incompatíveis para comparação.'); } /** * Retorna um número aleatório entre 0 e 1. * @returns {Promise<number>} Número real. */ async function aleatorio(interpretador) { return Promise.resolve(Math.random()); } /** * Retorna um número aleatório de acordo com o parâmetro passado. * Mínimo(inclusivo) - Máximo(exclusivo). * @param {number} minimo O número mínimo. * @param {number} maximo O número máximo. * @returns {Promise<number>} Um número real entre os valores máximo e mínimo especificados. */ async function aleatorioEntre(interpretador, minimo, maximo) { if (arguments.length <= 1) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'A função recebe ao menos um parâmetro.')); } const valorMinimo = interpretador.resolverValor(minimo); if (arguments.length === 2) { if (typeof valorMinimo !== 'number') { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'O parâmetro deve ser um número.')); } return Math.floor(Math.random() * (0 - valorMinimo)) + valorMinimo; } if (arguments.length > 3) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'A quantidade de parâmetros máxima para esta função é 2.')); } const valorMaximo = interpretador.resolverValor(maximo); if (typeof valorMinimo !== 'number' || typeof valorMaximo !== 'number') { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Os dois parâmetros devem ser do tipo número.')); } return Promise.resolve(Math.floor(Math.random() * (valorMaximo - valorMinimo)) + valorMinimo); } /** * Verifica se algum dos elementos satisfaz à condição para por parâmetro. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} vetor Uma variável de Delégua ou um vetor nativo de JavaScript. * @param {VariavelInterface | any} funcaoPesquisa A função que ensina o método de pesquisa. * @returns {Promise<boolean>} Verdadeiro se há algum elemento no vetor com a condição. Falso caso contrário. */ async function algum(interpretador, vetor, funcaoPesquisa) { const valorVetor = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; const valorFuncaoPesquisa = funcaoPesquisa.hasOwnProperty('valor') ? funcaoPesquisa.valor : funcaoPesquisa; if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função deve ser um vetor.')); } if (valorFuncaoPesquisa.constructor !== estruturas_1.DeleguaFuncao) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O segundo parâmetro da função deve ser uma função.')); } for (let indice = 0; indice < valorVetor.length; ++indice) { if (await valorFuncaoPesquisa.chamar(interpretador, [valorVetor[indice]])) { return true; } } return false; } /** * Arredonda um número para uma quantidade específica de casas decimais. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {any} numero O número a ser arredondado. * @param {any} casasDecimais A quantidade de casas decimais para o arredondamento. * @returns {Promise<number>} O número arredondado. */ async function arredondar(interpretador, numero, casasDecimais) { const valorNumero = interpretador.resolverValor(numero); const valorCasas = interpretador.resolverValor(casasDecimais); if (numero == undefined || numero == null) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(undefined, 'Erro: arredondar() deve receber um número.', interpretador.linhaDeclaracaoAtual)); } if (typeof numero !== 'number') { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(undefined, `Erro de Tipo: arredondar() espera um número, mas recebeu '${typeof valorNumero}'.`, interpretador.linhaDeclaracaoAtual)); } const fator = Math.pow(10, valorCasas); const resultado = Math.round(valorNumero * fator) / fator; return Promise.resolve(resultado); } /** * Clona profundamente uma variável ou constante em Delégua. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} valor O valor a ser clonado. * @returns {Promise<any>} Uma cópia profunda do valor fornecido. */ async function clonar(interpretador, valor) { // Resolver o valor caso seja uma VariavelInterface // Verificar se é null/undefined antes de usar hasOwnProperty let valorResolvido; if (valor === null || valor === undefined) { valorResolvido = valor; } else if (typeof valor === 'object' && valor.hasOwnProperty('valor')) { valorResolvido = valor.valor; } else { valorResolvido = valor; } // Map para evitar referências circulares const visitados = new WeakMap(); function clonarProfundo(valorAtual) { // Valores primitivos (null, undefined, number, string, boolean) if (valorAtual === null || valorAtual === undefined) { return valorAtual; } if (typeof valorAtual !== 'object') { return valorAtual; } // Verificar se já visitamos este objeto (evitar referências circulares) if (visitados.has(valorAtual)) { return visitados.get(valorAtual); } // Arrays if (Array.isArray(valorAtual)) { const arrayClonado = []; visitados.set(valorAtual, arrayClonado); for (let i = 0; i < valorAtual.length; i++) { arrayClonado[i] = clonarProfundo(valorAtual[i]); } return arrayClonado; } // Objetos de Delégua - ObjetoDeleguaClasse if (valorAtual instanceof objeto_delegua_classe_1.ObjetoDeleguaClasse) { // Clonar propriedades do objeto const propriedadesClonadas = {}; visitados.set(valorAtual, propriedadesClonadas); for (const chave in valorAtual.propriedades) { if (valorAtual.propriedades.hasOwnProperty(chave)) { propriedadesClonadas[chave] = clonarProfundo(valorAtual.propriedades[chave]); } } // Criar novo objeto com as propriedades clonadas // Nota: A classe em si não é clonada, apenas suas propriedades const objetoClonado = new objeto_delegua_classe_1.ObjetoDeleguaClasse(valorAtual.classe); objetoClonado.propriedades = propriedadesClonadas; return objetoClonado; } // Tuplas com 11 elementos ou mais if (valorAtual instanceof construtos_1.TuplaN) { const elementosClonados = []; visitados.set(valorAtual, elementosClonados); for (let i = 0; i < valorAtual.elementos.length; i++) { elementosClonados.push(clonarProfundo(valorAtual.elementos[i])); } return new construtos_1.TuplaN(valorAtual.hashArquivo, valorAtual.linha, elementosClonados); } // Tuplas com até 10 elementos const nomeClasseTupla = valorAtual.constructor?.name; if (nomeClasseTupla && configTuplas[nomeClasseTupla]) { const config = configTuplas[nomeClasseTupla]; const argsClonados = []; visitados.set(valorAtual, argsClonados); for (const prop of config.props) { argsClonados.push(clonarProfundo(valorAtual[prop])); } return new config.Classe(...argsClonados); } // DeleguaFuncao e FuncaoPadrao - funções não são clonadas profundamente // Elas mantêm referência à mesma definição, mas isso é comportamento esperado if (valorAtual instanceof estruturas_1.DeleguaFuncao || valorAtual instanceof funcao_padrao_1.FuncaoPadrao) { return valorAtual; } // Objetos simples (plain objects) const objetoClonado = {}; visitados.set(valorAtual, objetoClonado); for (const chave in valorAtual) { if (valorAtual.hasOwnProperty(chave)) { objetoClonado[chave] = clonarProfundo(valorAtual[chave]); } } return objetoClonado; } return Promise.resolve(clonarProfundo(valorResolvido)); } /** * Encontra o primeiro elemento de um vetor cuja função de pesquisa retorne * verdadeiro na avaliação de cada elemento. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} vetor Uma variável de Delégua ou um vetor nativo de JavaScript. * @param {VariavelInterface | any} funcaoPesquisa A função que ensina o método de pesquisa. * @returns {Promise<any>} Um elemento, caso o elemento seja encontraro, ou nulo em caso contrário. */ async function encontrar(interpretador, vetor, funcaoPesquisa) { const valorVetor = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; const valorFuncaoPesquisa = funcaoPesquisa.hasOwnProperty('valor') ? funcaoPesquisa.valor : funcaoPesquisa; if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função deve ser um vetor.')); } if (valorFuncaoPesquisa.constructor !== estruturas_1.DeleguaFuncao) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O segundo parâmetro da função deve ser uma função.')); } const resultados = []; for (let indice = 0; indice < valorVetor.length; ++indice) { const resultado = await valorFuncaoPesquisa.chamar(interpretador, [valorVetor[indice]]); const valorResultado = resultado?.valorRetornado?.valor ?? resultado?.valor ?? resultado; if (valorResultado) { resultados.push(valorVetor[indice]); } } return resultados.length > 0 ? resultados : null; } /** * Encontra o índice do primeiro elemento de um vetor cuja função de pesquisa retorne * verdadeiro na avaliação de cada elemento. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} vetor Uma variável de Delégua ou um vetor nativo de JavaScript. * @param {VariavelInterface | any} funcaoPesquisa A função que ensina o método de pesquisa. * @returns {Promise<number>} O número correspondente ao índice se o elemento for encontrado, ou nulo em caso contrário. */ async function encontrarIndice(interpretador, vetor, funcaoPesquisa) { const valorVetor = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; const valorFuncaoPesquisa = funcaoPesquisa.hasOwnProperty('valor') ? funcaoPesquisa.valor : funcaoPesquisa; if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função deve ser um vetor.')); } if (valorFuncaoPesquisa.constructor !== estruturas_1.DeleguaFuncao) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O segundo parâmetro da função deve ser uma função.')); } for (let indice = 0; indice < valorVetor.length; ++indice) { if (await valorFuncaoPesquisa.chamar(interpretador, [valorVetor[indice]])) { return indice; } } return -1; } /** * Encontrar o último elemento de um vetor cuja função de pesquisa retorne * verdadeiro na avaliação de cada elemento. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} vetor Uma variável de Delégua ou um vetor nativo de JavaScript. * @param {VariavelInterface | any} funcaoPesquisa A função que ensina o método de pesquisa. * @returns {Promise<any>} O número correspondente ao índice se o elemento for encontrado, ou nulo em caso contrário. */ async function encontrarUltimo(interpretador, vetor, funcaoPesquisa) { const valorVetor = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; const valorFuncaoPesquisa = funcaoPesquisa.hasOwnProperty('valor') ? funcaoPesquisa.valor : funcaoPesquisa; if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função deve ser um vetor.')); } if (valorFuncaoPesquisa.constructor !== estruturas_1.DeleguaFuncao) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O segundo parâmetro da função deve ser uma função.')); } for (let indice = valorVetor.length - 1; indice >= 0; --indice) { if (await valorFuncaoPesquisa.chamar(interpretador, [valorVetor[indice]])) { return valorVetor[indice]; } } return null; } /** * * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} vetor Uma variável de Delégua ou um vetor nativo de JavaScript. * @param {VariavelInterface | any} funcaoPesquisa A função que ensina o método de pesquisa. * @returns {Promise<number>} O número correspondente ao índice se o elemento for encontrado, ou nulo em caso contrário. */ async function encontrarUltimoIndice(interpretador, vetor, funcaoPesquisa) { const valorVetor = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; const valorFuncaoPesquisa = funcaoPesquisa.hasOwnProperty('valor') ? funcaoPesquisa.valor : funcaoPesquisa; if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função deve ser um vetor.')); } if (valorFuncaoPesquisa.constructor !== estruturas_1.DeleguaFuncao) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O segundo parâmetro da função deve ser uma função.')); } for (let indice = valorVetor.length - 1; indice >= 0; --indice) { if (await valorFuncaoPesquisa.chamar(interpretador, [valorVetor[indice]])) { return indice; } } return -1; } /** * * @param interpretador * @param vetor * @param funcaoFiltragem * @returns */ async function filtrarPor(interpretador, vetor, funcaoFiltragem) { if (vetor === null || vetor === undefined) return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função filtrarPor() não pode ser nulo.')); const valorVetor = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; const valorFuncaoFiltragem = funcaoFiltragem.hasOwnProperty('valor') ? funcaoFiltragem.valor : funcaoFiltragem; if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função filtrarPor() deve ser um vetor.')); } if (valorFuncaoFiltragem.constructor !== estruturas_1.DeleguaFuncao) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O segundo parâmetro da função filtrarPor() deve ser uma função.')); } const resultados = []; for (let indice = 0; indice < valorVetor.length; ++indice) { const informacoesValor = await valorFuncaoFiltragem.chamar(interpretador, [ valorVetor[indice], ]); if (informacoesValor === null || informacoesValor === undefined) { continue; } const deveRetornarValor = informacoesValor.valorRetornado.valor; if (deveRetornarValor === false) continue; resultados.push(valorVetor[indice]); } return resultados; } /** * * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} vetor Uma variável de Delégua ou um vetor nativo de JavaScript. * @param valor * @returns */ async function incluido(interpretador, vetor, valor) { const valorVetor = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; const valorValor = valor.hasOwnProperty('valor') ? valor.valor : valor; if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função deve ser um vetor.')); } for (let indice = 0; indice < valorVetor.length; ++indice) { if (valorVetor[indice] == valorValor) { return true; } } return false; } function validacaoComumNumeros(interpretador, valorParaConverter) { if (isNaN(valorParaConverter)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Valor não parece ser um número. Somente números ou textos com números podem ser convertidos para inteiro.')); } if (!/^(-)?\d+(\.\d+)?$/.test(valorParaConverter)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Valor não parece estar estruturado como um número (texto vazio, falso ou não definido). Somente números ou textos com números podem ser convertidos para inteiro.')); } return null; } /** * Converte um valor em um número inteiro. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} valorParaConverter O valor a ser convertido. * @returns {Promise<any>} Uma Promise com o resultado da conversão. */ async function inteiro(interpretador, valorParaConverter) { if (valorParaConverter === null || valorParaConverter === undefined) return Promise.resolve(0); const valor = valorParaConverter.hasOwnProperty('valor') ? valorParaConverter.valor : valorParaConverter; const resultadoValidacao = validacaoComumNumeros(interpretador, valor); return resultadoValidacao || Promise.resolve(parseInt(valor)); } /** * Converte um valor em um número longo (BigInt). * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} valorParaConverter O valor a ser convertido. * @returns {Promise<any>} Uma Promise com o resultado da conversão para BigInt. */ async function longo(interpretador, valorParaConverter) { if (valorParaConverter === null || valorParaConverter === undefined) { return Promise.resolve(globalThis.BigInt(0)); } const valor = valorParaConverter.hasOwnProperty('valor') ? valorParaConverter.valor : valorParaConverter; // Se já é BigInt, retorna direto if (typeof valor === 'bigint') { return Promise.resolve(valor); } // Se é número, converte para BigInt (trunca decimais) if (typeof valor === 'number') { return Promise.resolve(globalThis.BigInt(Math.floor(valor))); } // Para strings, remove parte decimal se presente const strValue = String(valor).trim(); // Trata string vazia if (!strValue || strValue === '') { return Promise.resolve(globalThis.BigInt(0)); } // Remove parte decimal da string (ex: "3.14" -> "3") const integerPart = strValue.split('.')[0]; try { return Promise.resolve(globalThis.BigInt(integerPart)); } catch (e) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, `Não foi possível converter '${valor}' para longo. O valor deve ser um número ou texto numérico.`)); } } /** * Cria um vetor com números inteiros no intervalo especificado. * O valor inicial é inclusivo e o valor final é exclusivo. * @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<number[]>} Um vetor com os números no intervalo. */ async function intervalo(interpretador, valorInicial, valorFinal, valorPasso) { const primeiroParam = interpretador.resolverValor(valorInicial); const segundoParam = interpretador.resolverValor(valorFinal); const terceiroParam = interpretador.resolverValor(valorPasso); let inicioInteiro; let fimInteiro; let passoInteiro = 1; // intervalo(parada) - apenas um parâmetro if (segundoParam === undefined || segundoParam === null) { if (typeof primeiroParam !== 'number' || isNaN(primeiroParam)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, '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 excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Os parâmetros de início e fim devem ser do tipo número ou inteiro.')); } 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 excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'O parâmetro de passo deve ser do tipo número ou inteiro.')); } passoInteiro = Math.floor(terceiroParam); if (passoInteiro === 0) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'O passo não pode ser zero.')); } } } const resultado = []; 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); } /** * Dado um vetor e uma função de mapeamento, executa a função de mapeamento * passando como argumento cada elemento do vetor. * @param interpretador A instância do interpretador. * @param vetor O vetor * @param funcaoMapeamento A função de mapeamento. * @returns O resultado acumulado da execução da função de mapeamento. */ async function mapear(interpretador, vetor, funcaoMapeamento) { if (vetor === null || vetor === undefined) return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função mapear() não pode ser nulo.')); const valorVetor = interpretador.resolverValor(vetor); const valorFuncaoMapeamento = interpretador.resolverValor(funcaoMapeamento); const resultados = []; for (let indice = 0; indice < valorVetor.length; ++indice) { const informacoesRetorno = await valorFuncaoMapeamento.chamar(interpretador, [ valorVetor[indice], ]); if (!informacoesRetorno.hasOwnProperty('valorRetornado')) { console.warn(`Retorno inconsistente em mapear(): ${JSON.stringify(informacoesRetorno)}.`); continue; } if (!(informacoesRetorno.valorRetornado instanceof quebras_1.RetornoQuebra)) { console.warn(`mapear() finalizado com valor retornado diferente do esperado: ${JSON.stringify(informacoesRetorno)}.`); continue; } resultados.push(informacoesRetorno.valorRetornado.valor); } return resultados; } /** * Encontra o maior número dentro de um vetor. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} vetor Uma variável de Delégua ou um vetor nativo de JavaScript contendo números. * @returns {Promise<number>} O maior número encontrado no vetor. */ async function maximo(interpretador, vetor) { if (vetor === null || vetor === undefined) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O parâmetro da função maximo() não pode ser nulo.')); } const valorVetor = interpretador.resolverValor(vetor); if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O parâmetro da função maximo() deve ser um vetor.')); } if (vetor.length == 0) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O vetor não pode estar vazio.')); } let maiorValor = valorVetor[0]; try { for (let i = 1; i < valorVetor.length; i++) { const elementoAtual = valorVetor[i]; if (compararElementosRecursivamente(elementoAtual, maiorValor) > 0) { maiorValor = elementoAtual; } } } catch (erro) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Não é possível comparar elementos de tipos diferentes dentro do vetor (ex: números com vetores).')); } return Promise.resolve(maiorValor); } /** * Encontra o menor número dentro de um vetor. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} vetor Uma variável de Delégua ou um vetor nativo de JavaScript contendo números. * @returns {Promise<number>} O menor número encontrado no vetor. */ async function minimo(interpretador, vetor) { if (vetor === null || vetor === undefined) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O parâmetro da função minimo() não pode ser nulo.')); } const valorVetor = interpretador.resolverValor(vetor); if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O parâmetro da função minimo() deve ser um vetor.')); } if (valorVetor.length == 0) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O vetor não pode estar vazio.')); } let menorValor = valorVetor[0]; try { for (let i = 1; i < valorVetor.length; i++) { const elementoAtual = valorVetor[i]; if (compararElementosRecursivamente(elementoAtual, menorValor) < 0) { menorValor = elementoAtual; } } } catch (erro) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Não é possível comparar elementos de tipos diferentes dentro do vetor (ex: números com vetores).')); } return Promise.resolve(menorValor); } /** * Converte um valor em um número, com parte decimal ou não. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} valorParaConverter O valor a ser convertido. * @returns {Promise<any>} Uma Promise com o resultado da conversão. */ async function numero(interpretador, valorParaConverter) { if (valorParaConverter === null || valorParaConverter === undefined) return Promise.resolve(0); const valor = valorParaConverter.hasOwnProperty('valor') ? valorParaConverter.valor : valorParaConverter; const resultadoValidacao = validacaoComumNumeros(interpretador, valor); return resultadoValidacao || Promise.resolve(Number(valor)); } /** * * @param vetor * @returns */ async function ordenar(interpretador, vetor) { if (vetor === null || vetor === undefined) throw new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função ordenar() não pode ser nulo.'); const objeto = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; if (!Array.isArray(objeto)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Valor inválido. Objeto inserido não é um vetor.')); } let trocado; const tamanho = objeto.length; do { trocado = false; for (let i = 0; i < tamanho - 1; i++) { if (objeto[i] > objeto[i + 1]) { [objeto[i], objeto[i + 1]] = [objeto[i + 1], objeto[i]]; trocado = true; } } } while (trocado); return Promise.resolve(objeto); } /** * * @param interpretador * @param vetor * @param funcaoFiltragem * @returns */ async function paraCada(interpretador, vetor, funcaoFiltragem) { if (vetor === null || vetor === undefined) return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função paraCada() não pode ser nulo.')); const valorVetor = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; const valorFuncaoFiltragem = funcaoFiltragem.hasOwnProperty('valor') ? funcaoFiltragem.valor : funcaoFiltragem; for (let indice = 0; indice < valorVetor.length; ++indice) { await valorFuncaoFiltragem.chamar(interpretador, [valorVetor[indice]]); } } /** * * @param interpretador * @param vetor * @param funcaoFiltragem * @returns */ async function primeiroEmCondicao(interpretador, vetor, funcaoFiltragem) { if (vetor === null || vetor === undefined) return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função primeiroEmCondicao() não pode ser nulo.')); const valorVetor = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; const valorFuncaoFiltragem = funcaoFiltragem.hasOwnProperty('valor') ? funcaoFiltragem.valor : funcaoFiltragem; if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função primeiroEmCondicao() deve ser um vetor.')); } if (valorFuncaoFiltragem.constructor !== estruturas_1.DeleguaFuncao) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O segundo parâmetro da função primeiroEmCondicao() deve ser uma função.')); } for (let indice = 0; indice < valorVetor.length; ++indice) { const valorResolvido = await valorFuncaoFiltragem.chamar(interpretador, [ valorVetor[indice], ]); if (valorResolvido !== null) { return valorResolvido; } } return undefined; } /** * * @param interpretador * @param numero * @returns */ async function real(interpretador, numero) { if (numero === null || numero === undefined) return Promise.resolve(parseFloat('0')); const valor = numero.hasOwnProperty('valor') ? numero.valor : numero; if (!/^(-)?\d+(\.\d+)?$/.test(valor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Valor não parece estar estruturado como um número (texto/valor vazio, falso ou não definido). Somente números ou textos com números podem ser convertidos para real.')); } return Promise.resolve(parseFloat(valor)); } /** * * @param interpretador * @param vetor * @param funcaoReducao * @param valorInicial * @returns */ async function reduzir(interpretador, vetor, funcaoReducao, valorInicial = null) { const valorVetor = vetor.hasOwnProperty('valor') ? vetor.valor : vetor; const valorFuncaoReducao = funcaoReducao.hasOwnProperty('valor') ? funcaoReducao.valor : funcaoReducao; const valorPadrao = valorInicial.hasOwnProperty('valor') ? valorInicial.valor : valorInicial; if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro da função deve ser um vetor.')); } if (valorFuncaoReducao.constructor !== estruturas_1.DeleguaFuncao) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O segundo parâmetro da função deve ser uma função.')); } let resultado = valorPadrao; let inicio = 0; if (!resultado) { resultado = vetor[0]; inicio = 1; } for (let index = inicio; index < vetor.length; ++index) { resultado = await valorFuncaoReducao.chamar(interpretador, [resultado, vetor[index]]); } return resultado; } /** * Realiza a soma de todos os números dentro de um vetor. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} vetor Uma variável de Pituguês ou um vetor nativo de JavaScript contendo números. * @returns {Promise<number>} A soma de todos os elementos do vetor. */ async function somar(interpretador, vetor) { if (vetor === null || vetor === undefined) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O parâmetro da função somar() não pode ser nulo.')); } const valorVetor = interpretador.resolverValor(vetor); if (!Array.isArray(valorVetor)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O parâmetro da função somar() deve ser um vetor.')); } if (valorVetor.length === 0) return Promise.resolve(0); let somaDosElementos = 0; for (let elemento of valorVetor) { if (typeof elemento !== 'number' || isNaN(elemento)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'A função somar() aceita apenas vetores contendo números.')); } somaDosElementos += elemento; } return Promise.resolve(somaDosElementos); } /** * * @param objeto * @returns */ async function tamanho(interpretador, objeto) { const valorObjeto = objeto.hasOwnProperty('valor') ? objeto.valor : objeto; if (typeof valorObjeto === 'number') { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Função global tamanho() não funciona com números.')); } if (valorObjeto instanceof objeto_delegua_classe_1.ObjetoDeleguaClasse) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Função global tamanho não funciona com objetos complexos.')); } if (valorObjeto instanceof estruturas_1.DeleguaFuncao) { return Promise.resolve(valorObjeto.declaracao.parametros.length); } if (valorObjeto instanceof funcao_padrao_1.FuncaoPadrao) { return Promise.resolve(valorObjeto.valorAridade); } if (valorObjeto instanceof descritor_tipo_classe_1.DescritorTipoClasse) { const metodos = valorObjeto.metodos; let tamanho = 0; const metodoInicializacao = metodos.inicializacao; if (metodoInicializacao && !Array.isArray(metodoInicializacao) && metodoInicializacao.eInicializador) { tamanho = metodoInicializacao.declaracao.parametros.length; } else if (Array.isArray(metodoInicializacao)) { // Em caso de construtores sobrecarregados, `metodos.inicializacao` pode ser um array. // Usamos o maior número de parâmetros entre as sobrecargas que são inicializadores. for (const inicializador of metodoInicializacao) { if (inicializador && inicializador.eInicializador && inicializador.declaracao?.parametros) { const aridade = inicializador.declaracao.parametros.length; if (aridade > tamanho) { tamanho = aridade; } } } } return Promise.resolve(tamanho); } return Promise.resolve(valorObjeto.length); } /** * Transforma o valor ou variável em texto. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} valorParaConverter O valor ou variável. * @returns {Promise<string>} O valor resolvido em texto. */ async function texto(interpretador, valorParaConverter) { return Promise.resolve(`${valorParaConverter.hasOwnProperty('valor') ? valorParaConverter.valor : valorParaConverter}`); } /** * Retorna verdadeiro se todos os elementos do iterável forem truly. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} iteravel O primeiro parâmetro, qualquer dado que seja iterável (vetores, tuplas, dicionários etc.). * @returns {Promise<boolean>} Verdadeiro, se todos os valores do iterável forem Truly. */ async function todos(interpretador, iteravel) { const valorIteravel = interpretador.resolverValor(iteravel); const ehObjetoOuDicionario = valorIteravel && typeof valorIteravel === 'object' && !Array.isArray(valorIteravel); const ehIteravelNativo = valorIteravel && typeof valorIteravel[Symbol.iterator] === 'function'; if (!ehIteravelNativo && !ehObjetoOuDicionario) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }, 'Parâmetro inválido. O primeiro parâmetro deve ser um iterável.')); } const itens = ehIteravelNativo ? valorIteravel : Object.values(valorIteravel); for (const valor of itens) { const valorResolvido = interpretador.resolverValor(valor); if (!interpretador.eVerdadeiro(valorResolvido)) return false; } return true; } /** * Retorna verdadeiro se todos os elementos do primeiro parâmetro retornam verdadeiro ao * serem aplicados como argumentos da função passada como segundo parâmetro. * @param {InterpretadorInterface} interpretador A instância do interpretador. * @param {VariavelInterface | any} iteravel O primeiro parâmetro, qualquer dado que seja iterável (vetores, tuplas, dicionários etc.). * @param {VariavelInterface | any} funcaoCondicional A função que será executada com cada * valor do iterável passado como primeiro parâmetro. * @returns {Promise<boolean>} Verdadeiro, se todos os valores do iterável fazem a função passada * por parâmetro devolver verdadeiro, ou falso em caso contrário. */ async function todosEmCondicao(interpretador, iteravel, funcaoCondicional) { const simboloChamada = { linha: interpretador.linhaDeclaracaoAtual, hashArquivo: interpretador.hashArquivoDeclaracaoAtual, }; const valorIteravel = interpretador.resolverValor(iteravel); const ehObjetoOuDicionario = valorIteravel && typeof valorIteravel === 'object' && !Array.isArray(valorIteravel); const ehIteravelNativo = valorIteravel && typeof valorIteravel[Symbol.iterator] === 'function'; if (!ehIteravelNativo && !ehObjetoOuDicionario) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: interpretador.hashArquivoDeclaracaoAtual, linha: interpretador.linhaDeclaracaoAtual, }