UNPKG

@designliquido/delegua

Version:

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

177 lines 7.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MetodoPolimorfico = void 0; const inferenciador_1 = require("../../inferenciador"); const excecoes_1 = require("../../excecoes"); const chamavel_1 = require("./chamavel"); const tiposNumericos = ['inteiro', 'número', 'real', 'longo']; const mapaDeNormalizacao = { numero: 'número', logico: 'lógico', funcao: 'função', dicionario: 'dicionário', modulo: 'módulo', }; function normalizarTipo(tipo) { if (!tipo || tipo === 'qualquer') return 'qualquer'; const tipoMinusculo = tipo.toLowerCase(); return mapaDeNormalizacao[tipoMinusculo] || tipoMinusculo; } function tiposCompativeisParaDespacho(tipoParametro, tipoArgumento) { const paramNorm = normalizarTipo(tipoParametro); const argNorm = normalizarTipo(tipoArgumento); if (paramNorm === 'qualquer') return 1; if (paramNorm === argNorm) return 3; if (tiposNumericos.includes(paramNorm) && tiposNumericos.includes(argNorm)) return 2; return -1; } /** * Proxy que encapsula múltiplas sobrecargas de um mesmo método, * resolvendo qual sobrecarga chamar em tempo de execução com base * nos tipos dos argumentos fornecidos. */ class MetodoPolimorfico extends chamavel_1.Chamavel { constructor(nome, sobrecargas, instancia) { super(); this.nome = nome; this.sobrecargas = sobrecargas; this.instancia = instancia; } aridade() { let maxAridade = 0; for (const sobrecarga of this.sobrecargas) { const a = sobrecarga.aridade(); if (a > maxAridade) maxAridade = a; } return maxAridade; } contarParametrosObrigatorios(sobrecarga) { const parametros = sobrecarga.declaracao?.parametros || []; let obrigatorios = 0; for (const p of parametros) { if (p.abrangencia === 'multiplo') break; if (p.valorPadrao === undefined) { obrigatorios++; } } return obrigatorios; } temParametroEspalhado(sobrecarga) { const parametros = sobrecarga.declaracao?.parametros || []; return parametros.some((p) => p.abrangencia === 'multiplo'); } resolverSobrecarga(argumentos) { const numArgs = argumentos.length; let melhorPontuacao = -1; let melhorSobrecarga = undefined; for (const sobrecarga of this.sobrecargas) { const parametros = sobrecarga.declaracao?.parametros || []; const aridade = sobrecarga.aridade(); const minParams = this.contarParametrosObrigatorios(sobrecarga); const temEspalhado = this.temParametroEspalhado(sobrecarga); // Verificar se a quantidade de argumentos é compatível if (temEspalhado) { if (numArgs < minParams) continue; } else { if (numArgs < minParams || numArgs > aridade) continue; } let pontuacao = 0; let compativel = true; for (let i = 0; i < numArgs && i < parametros.length; i++) { const parametro = parametros[i]; if (parametro.abrangencia === 'multiplo') { // Parâmetros espalhados aceitam qualquer coisa pontuacao += 1; break; } let valorArgumento = argumentos[i] && argumentos[i].hasOwnProperty('valor') ? argumentos[i].valor : argumentos[i]; // Se o valor é uma VariavelInterface, extrair o valor real if (valorArgumento && typeof valorArgumento === 'object' && valorArgumento.hasOwnProperty('valor') && valorArgumento.hasOwnProperty('tipo')) { valorArgumento = valorArgumento.valor; } const tipoArgumento = (0, inferenciador_1.inferirTipoVariavel)(valorArgumento); const resultado = tiposCompativeisParaDespacho(parametro.tipoDado, tipoArgumento); if (resultado < 0) { compativel = false; break; } pontuacao += resultado; } if (!compativel) continue; if (pontuacao > melhorPontuacao) { melhorPontuacao = pontuacao; melhorSobrecarga = sobrecarga; } } if (!melhorSobrecarga) { const tiposArgs = argumentos.map((a) => { let val = a && a.hasOwnProperty('valor') ? a.valor : a; if (val && typeof val === 'object' && val.hasOwnProperty('valor') && val.hasOwnProperty('tipo')) { val = val.valor; } return normalizarTipo((0, inferenciador_1.inferirTipoVariavel)(val)); }); const assinaturas = this.sobrecargas.map((s) => { const params = s.declaracao?.parametros || []; const tipos = params.map((p) => p.tipoDado || 'qualquer'); return `${this.nome}(${tipos.join(', ')})`; }); throw new excecoes_1.ErroEmTempoDeExecucao(this.instancia?.classe.simboloOriginal, `Nenhuma sobrecarga do método "${this.nome}" corresponde aos argumentos fornecidos (${tiposArgs.join(', ')}). ` + `Sobrecargas disponíveis: ${assinaturas.join('; ')}.`); } return melhorSobrecarga; } async chamar(visitante, argumentos) { const sobrecarga = this.resolverSobrecarga(argumentos); // Completar os argumentos não preenchidos com valores indefinidos // para a sobrecarga selecionada. const aridadeSobrecarga = sobrecarga.aridade(); if (argumentos.length < aridadeSobrecarga) { const diferenca = aridadeSobrecarga - argumentos.length; for (let i = 0; i < diferenca; i++) { argumentos.push({ nome: null, valor: null }); } } // Vincular a instância se existir let funcaoParaChamar = sobrecarga; if (this.instancia !== undefined) { funcaoParaChamar = sobrecarga.funcaoPorMetodoDeClasse(this.instancia); } return await funcaoParaChamar.chamar(visitante, argumentos); } funcaoPorMetodoDeClasse(instancia) { const sobrecargasVinculadas = this.sobrecargas.map((s) => s.funcaoPorMetodoDeClasse(instancia)); return new MetodoPolimorfico(this.nome, sobrecargasVinculadas, instancia); } paraTexto() { const assinaturas = this.sobrecargas.map((s) => { const params = s.declaracao?.parametros || []; const tipos = params.map((p) => `${p.nome.lexema}: ${p.tipoDado || 'qualquer'}`); return `${this.nome}(${tipos.join(', ')})`; }); return `<método-polimórfico nome=${this.nome} sobrecargas=[${assinaturas.join('; ')}] />`; } toString() { return this.paraTexto(); } } exports.MetodoPolimorfico = MetodoPolimorfico; //# sourceMappingURL=metodo-polimorfico.js.map