Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions fontes/bibliotecas/biblioteca-global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1508,8 +1508,20 @@ export async function tamanho(interpretador: InterpretadorInterface, objeto: any
const metodos = valorObjeto.metodos;
let tamanho = 0;

if (metodos.inicializacao && metodos.inicializacao.eInicializador) {
tamanho = metodos.inicializacao.declaracao.parametros.length;
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);
Expand Down
5 changes: 3 additions & 2 deletions fontes/bibliotecas/dialetos/pitugues/biblioteca-global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1301,8 +1301,9 @@ export async function tamanho(interpretador: InterpretadorInterface, objeto: any
const metodos = valorObjeto.metodos;
let tamanho = 0;

if (metodos.inicializacao && metodos.inicializacao.eInicializador) {
tamanho = metodos.inicializacao.declaracao.parametros.length;
const metodoInicializacao = metodos.inicializacao;
if (metodoInicializacao && !Array.isArray(metodoInicializacao) && metodoInicializacao.eInicializador) {
tamanho = metodoInicializacao.declaracao.parametros.length;
}

return Promise.resolve(tamanho);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,8 +487,9 @@ export class InterpretadorEguaClassico implements InterpretadorInterface {
if (entidadeChamada instanceof DeleguaFuncao) {
parametros = entidadeChamada.declaracao.parametros;
} else if (entidadeChamada instanceof DescritorTipoClasse) {
parametros = entidadeChamada.metodos.inicializacao
? entidadeChamada.metodos.inicializacao.declaracao.parametros
const metodoInit = entidadeChamada.metodos.inicializacao;
parametros = metodoInit && !Array.isArray(metodoInit)
? metodoInit.declaracao.parametros
: [];
} else {
parametros = [];
Expand Down Expand Up @@ -964,7 +965,7 @@ export class InterpretadorEguaClassico implements InterpretadorInterface {
this.pilhaEscoposExecucao.definirVariavel('super', superClasse);
}

const metodos = {};
const metodos: { [nome: string]: DeleguaFuncao | DeleguaFuncao[] } = {};
const definirMetodos = declaracao.metodos;
for (let i = 0; i < declaracao.metodos.length; i++) {
const metodoAtual = definirMetodos[i];
Expand All @@ -975,7 +976,15 @@ export class InterpretadorEguaClassico implements InterpretadorInterface {
undefined,
eInicializador
);
metodos[metodoAtual.simbolo.lexema] = funcao;
const nomeMetodo = metodoAtual.simbolo.lexema;
if (metodos[nomeMetodo]) {
if (!Array.isArray(metodos[nomeMetodo])) {
metodos[nomeMetodo] = [metodos[nomeMetodo] as DeleguaFuncao];
}
(metodos[nomeMetodo] as DeleguaFuncao[]).push(funcao);
} else {
metodos[nomeMetodo] = funcao;
}
}

const deleguaClasse = new DescritorTipoClasse(declaracao.simbolo, superClasse, metodos);
Expand Down
123 changes: 114 additions & 9 deletions fontes/interpretador/estruturas/descritor-tipo-classe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,35 @@ import { ErroEmTempoDeExecucao } from '../../excecoes';
import { InterpretadorInterface, SimboloInterface } from '../../interfaces';
import { Chamavel } from './chamavel';
import { DeleguaFuncao } from './delegua-funcao';
import { MetodoPolimorfico } from './metodo-polimorfico';
import { ObjetoDeleguaClasse } from './objeto-delegua-classe';

const mapaDeNormalizacao: { [chave: string]: string } = {
'numero': 'número',
'logico': 'lógico',
'funcao': 'função',
'dicionario': 'dicionário',
'modulo': 'módulo',
};

function normalizarTipo(tipo: string | undefined): string {
if (!tipo || tipo === 'qualquer') return 'qualquer';
const tipoMinusculo = tipo.toLowerCase();
return mapaDeNormalizacao[tipoMinusculo] || tipoMinusculo;
}

function assinaturasIguais(a: DeleguaFuncao, b: DeleguaFuncao): boolean {
const paramsA = a.declaracao?.parametros || [];
const paramsB = b.declaracao?.parametros || [];
if (paramsA.length !== paramsB.length) return false;
for (let i = 0; i < paramsA.length; i++) {
if (normalizarTipo(paramsA[i].tipoDado) !== normalizarTipo(paramsB[i].tipoDado)) {
return false;
}
}
return true;
}

/**
* Descritor de tipo de classe. Quando uma declaração de classe é visitada, o que
* vai para a pilha de escopos de execução é esta estrutura. Quando uma nova instância
Expand All @@ -13,15 +40,15 @@ import { ObjetoDeleguaClasse } from './objeto-delegua-classe';
export class DescritorTipoClasse extends Chamavel {
simboloOriginal: SimboloInterface;
superClasse: DescritorTipoClasse;
metodos: { [nome: string]: DeleguaFuncao };
metodos: { [nome: string]: DeleguaFuncao | DeleguaFuncao[] };
propriedades: PropriedadeClasse[];
dialetoRequerExpansaoPropriedadesEspacoMemoria: boolean;
dialetoRequerDeclaracaoPropriedades: boolean;

constructor(
simboloOriginal?: SimboloInterface,
superClasse?: DescritorTipoClasse,
metodos?: { [nome: string]: DeleguaFuncao },
metodos?: { [nome: string]: DeleguaFuncao | DeleguaFuncao[] },
propriedades?: PropriedadeClasse[]
) {
super();
Expand All @@ -32,16 +59,77 @@ export class DescritorTipoClasse extends Chamavel {
this.dialetoRequerDeclaracaoPropriedades = false;
}

encontrarMetodo(nome: string): DeleguaFuncao {
/**
* Mescla sobrecargas da classe atual com as da superclasse.
* Sobrecargas da subclasse com mesma assinatura substituem as da superclasse.
*/
private mesclarComSuperclasse(
metodosAtuais: DeleguaFuncao[],
metodosSuperclasse: DeleguaFuncao[]
): DeleguaFuncao[] {
const resultado = [...metodosAtuais];
for (const metodoSuper of metodosSuperclasse) {
const jaSobrescrito = metodosAtuais.some((m) => assinaturasIguais(m, metodoSuper));
if (!jaSobrescrito) {
resultado.push(metodoSuper);
}
}
return resultado;
}

private obterSobrecargasDaSuperclasse(nome: string): DeleguaFuncao[] {
if (!this.superClasse) return [];
const metodoSuper = this.superClasse.metodos.hasOwnProperty(nome)
? this.superClasse.metodos[nome]
: undefined;

let sobrecargasSuper: DeleguaFuncao[] = [];
if (metodoSuper) {
sobrecargasSuper = Array.isArray(metodoSuper) ? metodoSuper : [metodoSuper];
}

// Recursivamente mesclar com a superclasse da superclasse
const sobrecargasAncestral = this.superClasse.obterSobrecargasDaSuperclasse(nome);
if (sobrecargasAncestral.length > 0) {
const resultado = [...sobrecargasSuper];
for (const metodoAnc of sobrecargasAncestral) {
const jaSobrescrito = resultado.some((m) => assinaturasIguais(m, metodoAnc));
if (!jaSobrescrito) {
resultado.push(metodoAnc);
}
}
sobrecargasSuper = resultado;
}

return sobrecargasSuper;
}

encontrarMetodo(nome: string): DeleguaFuncao | MetodoPolimorfico {
let metodosAtuais: DeleguaFuncao[] = [];

if (this.metodos.hasOwnProperty(nome)) {
return this.metodos[nome];
const metodo = this.metodos[nome];
metodosAtuais = Array.isArray(metodo) ? metodo : [metodo];
}

if (this.superClasse !== null && this.superClasse !== undefined) {
return this.superClasse.encontrarMetodo(nome);
const metodosSuperclasse = this.obterSobrecargasDaSuperclasse(nome);

let todasSobrecargas: DeleguaFuncao[];
if (metodosAtuais.length > 0 && metodosSuperclasse.length > 0) {
todasSobrecargas = this.mesclarComSuperclasse(metodosAtuais, metodosSuperclasse);
} else if (metodosAtuais.length > 0) {
todasSobrecargas = metodosAtuais;
} else if (metodosSuperclasse.length > 0) {
todasSobrecargas = metodosSuperclasse;
} else {
return undefined;
}

return undefined;
if (todasSobrecargas.length === 1) {
return todasSobrecargas[0];
}

return new MetodoPolimorfico(nome, todasSobrecargas);
}

encontrarPropriedade(nome: string): PropriedadeClasse {
Expand Down Expand Up @@ -92,6 +180,9 @@ export class DescritorTipoClasse extends Chamavel {

aridade(): number {
const inicializador = this.encontrarMetodo('construtor');
if (inicializador instanceof MetodoPolimorfico) {
return inicializador.aridade();
}
return inicializador ? inicializador.aridade() : 0;
}

Expand All @@ -103,8 +194,22 @@ export class DescritorTipoClasse extends Chamavel {

const inicializador = this.encontrarMetodo('construtor');
if (inicializador) {
const metodoConstrutor = inicializador.funcaoPorMetodoDeClasse(instancia);
await metodoConstrutor.chamar(visitante, argumentos);
if (inicializador instanceof MetodoPolimorfico) {
const construtorVinculado = inicializador.funcaoPorMetodoDeClasse(instancia);
await construtorVinculado.chamar(visitante, argumentos);
} else {
// Para construtor não polimórfico, completar os argumentos
// não preenchidos com valores indefinidos.
const aridadeConstrutor = inicializador.aridade();
if (argumentos.length < aridadeConstrutor) {
const diferenca = aridadeConstrutor - argumentos.length;
for (let i = 0; i < diferenca; i++) {
argumentos.push({ nome: null, valor: null });
}
}
const metodoConstrutor = inicializador.funcaoPorMetodoDeClasse(instancia);
await metodoConstrutor.chamar(visitante, argumentos);
}
}

return instancia;
Expand Down
1 change: 1 addition & 0 deletions fontes/interpretador/estruturas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './descritor-tipo-classe';
export * from './funcao-padrao';
export * from './delegua-funcao';
export * from './metodo-primitiva';
export * from './metodo-polimorfico';
export * from './modulo';
export * from './objeto-delegua-classe';
export * from './objeto-padrao';
Expand Down
Loading
Loading