"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.aleatorio = aleatorio;
exports.aleatorio_entre = aleatorio_entre;
exports.algum = algum;
exports.arredondar = arredondar;
exports.encontrar = encontrar;
exports.encontrar_indice = encontrar_indice;
exports.encontrar_ultimo = encontrar_ultimo;
exports.encontrar_ultimo_indice = encontrar_ultimo_indice;
exports.filtrar_por = filtrar_por;
exports.incluido = incluido;
exports.inteiro = inteiro;
exports.intervalo = intervalo;
exports.mapear = mapear;
exports.maximo = maximo;
exports.minimo = minimo;
exports.numero = numero;
exports.ordenar = ordenar;
exports.para_cada = para_cada;
exports.primeiro_em_condicao = primeiro_em_condicao;
exports.real = real;
exports.reduzir = reduzir;
exports.somar = somar;
exports.tamanho = tamanho;
exports.texto = texto;
exports.todos = todos;
exports.todos_em_condicao = todos_em_condicao;
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");
/**
 * 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 aleatorio_entre(interpretador, minimo, maximo) {
    if (arguments.length <= 0) {
        return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({
            hashArquivo: interpretador.hashArquivoDeclaracaoAtual,
            linha: interpretador.linhaDeclaracaoAtual,
        }, 'A função recebe ao menos um parâmetro.'));
    }
    const valorMinimo = minimo.hasOwnProperty('valor')
        ? minimo.valor
        : 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 = maximo.hasOwnProperty('valor')
        ? maximo.valor
        : 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(null, 'Erro: arredondar() deve receber um número.', interpretador.linhaDeclaracaoAtual));
    }
    if (typeof numero !== 'number') {
        return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(null, `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);
}
/**
 * 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.'));
    }
    for (let indice = 0; indice < valorVetor.length; ++indice) {
        if (await valorFuncaoPesquisa.chamar(interpretador, [valorVetor[indice]])) {
            return valorVetor[indice];
        }
    }
    return 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 encontrar_indice(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 encontrar_ultimo(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 encontrar_ultimo_indice(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 null;
}
/**
 *
 * @param interpretador
 * @param vetor
 * @param funcaoFiltragem
 * @returns
 */
async function filtrar_por(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 validacao_comum_numeros(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 = validacao_comum_numeros(interpretador, valor);
    return resultadoValidacao || Promise.resolve(parseInt(valor));
}
/**
 * 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 Pituguês 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 Pituguês 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 = validacao_comum_numeros(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 para_cada(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 = interpretador.resolverValor(vetor);
    const valorFuncaoFiltragem = interpretador.resolverValor(funcaoFiltragem);
    for (let indice = 0; indice < valorVetor.length; ++indice) {
        await valorFuncaoFiltragem.chamar(interpretador, [valorVetor[indice]]);
    }
}
/**
 *
 * @param interpretador
 * @param vetor
 * @param funcaoFiltragem
 * @returns
 */
async function primeiro_em_condicao(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 = interpretador.resolverValor(vetor);
    const valorFuncaoFiltragem = interpretador.resolverValor(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.name !== '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 && valorInicial.hasOwnProperty && 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.name !== '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.'));
    }
    // Se não houver valor inicial e vetor vazio, não é possível reduzir
    if ((valorPadrao === null || valorPadrao === undefined) &&
        (!Array.isArray(valorVetor) || valorVetor.length === 0)) {
        return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({
            hashArquivo: interpretador.hashArquivoDeclaracaoAtual,
            linha: interpretador.linhaDeclaracaoAtual,
        }, 'Não é possível reduzir um vetor vazio sem valor inicial.'));
    }
    let resultado = valorPadrao;
    let inicio = 0;
    if (resultado === null || resultado === undefined) {
        resultado = valorVetor[0];
        inicio = 1;
    }
    for (let index = inicio; index < valorVetor.length; ++index) {
        resultado = await valorFuncaoReducao.chamar(interpretador, [resultado, valorVetor[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;
        }
        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 vetor 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 todos_em_condicao(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,
        }, 'Parâmetro inválido. O primeiro parâmetro deve ser um iterável.'));
    }
    const valorFuncao = interpretador.resolverValor(funcaoCondicional);
    const naoEhUmaFuncao = !(valorFuncao instanceof estruturas_1.DeleguaFuncao || valorFuncao instanceof funcao_padrao_1.FuncaoPadrao);
    if (!valorFuncao || naoEhUmaFuncao) {
        return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({
            hashArquivo: interpretador.hashArquivoDeclaracaoAtual,
            linha: interpretador.linhaDeclaracaoAtual,
        }, 'Parâmetro inválido. O segundo parâmetro deve ser uma função.'));
    }
    const itens = ehIteravelNativo ? valorIteravel : Object.values(valorIteravel);
    for (const valor of itens) {
        const resultadoChamada = await valorFuncao.chamar(interpretador, [valor], simboloChamada);
        const resultadoResolvido = interpretador.resolverValor(resultadoChamada);
        if (!interpretador.eVerdadeiro(resultadoResolvido))
            return false;
    }
    return true;
}
/**
 * Transforma um vetor de elementos em uma tupla de N elementos, sendo N a
 * largura do vetor.
 * @param {InterpretadorInterface} interpretador A instância do interpretador.
 * @param {VariavelInterface | any[]} vetor O vetor.
 * @returns A tupla resolvida.
 */
async function tupla(interpretador, vetor) {
    const valorVetor = interpretador.resolverValor(vetor);
    if (!Array.isArray(valorVetor)) {
        return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({
            hashArquivo: interpretador.hashArquivoDeclaracaoAtual,
            linha: interpretador.linhaDeclaracaoAtual,
        }, 'Argumento de função nativa `tupla` não parece ser um vetor.'));
    }
    const elementos = valorVetor.map((item) => {
        const valorResolvido = interpretador.resolverValor(item);
        const literal = new construtos_1.Literal(interpretador.hashArquivoDeclaracaoAtual, interpretador.linhaDeclaracaoAtual, valorResolvido);
        if (typeof valorResolvido === 'string') {
            literal.paraTextoSaida = () => `'${valorResolvido}'`;
        }
        return literal;
    });
    return new construtos_1.TuplaN(interpretador.hashArquivoDeclaracaoAtual, interpretador.linhaDeclaracaoAtual, elementos);
}
async function vetor(interpretador, tupla) {
    const objetoTupla = interpretador.resolverValor(tupla);
    if (!(objetoTupla instanceof construtos_1.TuplaN)) {
        return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({
            hashArquivo: interpretador.hashArquivoDeclaracaoAtual,
            linha: interpretador.linhaDeclaracaoAtual,
        }, 'Argumento de função nativa `vetor` não parece ser uma tupla.'));
    }
    const resultado = objetoTupla.elementos.map((elemento) => interpretador.resolverValor(elemento));
    return Promise.resolve(resultado);
}
//# sourceMappingURL=biblioteca-global.js.map