"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DescritorTipoClasse = void 0;
const excecoes_1 = require("../../excecoes");
const chamavel_1 = require("./chamavel");
const objeto_delegua_classe_1 = require("./objeto-delegua-classe");
/**
 * 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
 * de classe é criada, a referência para a instância é implementada aqui.
 */
class DescritorTipoClasse extends chamavel_1.Chamavel {
    constructor(simboloOriginal, superClasse, metodos, propriedades) {
        super();
        this.simboloOriginal = simboloOriginal;
        this.superClasse = superClasse;
        this.metodos = metodos || {};
        this.propriedades = propriedades || [];
        this.dialetoRequerDeclaracaoPropriedades = false;
    }
    encontrarMetodo(nome) {
        if (this.metodos.hasOwnProperty(nome)) {
            return this.metodos[nome];
        }
        if (this.superClasse !== null && this.superClasse !== undefined) {
            return this.superClasse.encontrarMetodo(nome);
        }
        return undefined;
    }
    encontrarPropriedade(nome) {
        if (nome in this.propriedades) {
            return this.propriedades[nome];
        }
        if (this.superClasse !== null && this.superClasse !== undefined) {
            return this.superClasse.encontrarPropriedade(nome);
        }
        if (this.dialetoRequerDeclaracaoPropriedades) {
            throw new excecoes_1.ErroEmTempoDeExecucao(this.simboloOriginal, `Propriedade "${nome}" não declarada na classe ${this.simboloOriginal.lexema}.`);
        }
        return undefined;
    }
    /**
     * Método utilizado por Delégua para representar esta classe quando impressa.
     * @returns {string} A representação da classe como texto.
     */
    paraTexto() {
        let texto = `<descritor-tipo-classe nome=${this.simboloOriginal.lexema}`;
        for (let propriedade of this.propriedades) {
            texto += ` ${propriedade.nome.lexema}`;
            if (propriedade.tipo) {
                texto += `:${propriedade.tipo}`;
            }
            texto += ' ';
        }
        texto += ' />';
        return texto;
    }
    /**
     * Método utilizado pelo VSCode para inspecionar esta classe em depuração.
     * @returns {string} A representação da classe como texto.
     */
    toString() {
        return this.paraTexto();
    }
    aridade() {
        const inicializador = this.encontrarMetodo('construtor');
        return inicializador ? inicializador.aridade() : 0;
    }
    async chamar(visitante, argumentos) {
        const instancia = new objeto_delegua_classe_1.ObjetoDeleguaClasse(this);
        const inicializador = this.encontrarMetodo('construtor');
        if (inicializador) {
            const metodoConstrutor = inicializador.funcaoPorMetodoDeClasse(instancia);
            await metodoConstrutor.chamar(visitante, argumentos);
        }
        return instancia;
    }
}
exports.DescritorTipoClasse = DescritorTipoClasse;
//# sourceMappingURL=descritor-tipo-classe.js.map