UNPKG

@designliquido/delegua

Version:

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

177 lines 9.09 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ObjetoDeleguaClasse = void 0; const excecoes_1 = require("../../excecoes"); /** * A instância de uma classe em Delégua. * Possui propriedades e métodos. Propriedades são definidas localmente. * Métodos são extraídos do descritor da classe, uma `DeleguaClasse`. */ class ObjetoDeleguaClasse { valorPadraoParaTipo(tipo) { switch (tipo) { case 'numero': return 0; case 'texto': return ''; case 'logico': return false; default: return undefined; } } constructor(classe) { this.classe = classe; this.propriedades = {}; // Inicializar propriedades herdadas do OReM (do mais genérico ao mais específico) // para que ancestrais mais próximos sobrescrevam os mais distantes. const ancestrais = classe.orem.slice(1).reverse(); for (const ancestral of ancestrais) { for (const propriedade of ancestral.propriedades) { if (propriedade.estatico) continue; if (propriedade.autoObter || propriedade.autoDefinir) { this.propriedades['_' + propriedade.nome.lexema] = this.valorPadraoParaTipo(propriedade.tipo); } else { this.propriedades[propriedade.nome.lexema] = this.valorPadraoParaTipo(propriedade.tipo); } } } // Propriedades da própria classe (têm prioridade máxima no valor padrão) for (const propriedade of classe.propriedades) { if (propriedade.estatico) continue; if (propriedade.autoObter || propriedade.autoDefinir) { this.propriedades['_' + propriedade.nome.lexema] = this.valorPadraoParaTipo(propriedade.tipo); } else { this.propriedades[propriedade.nome.lexema] = this.valorPadraoParaTipo(propriedade.tipo); } } } verificarAcessoLeitura(nome, simbolo, visitante) { var _a, _b, _c, _d, _e, _f, _g; // Percorre o OReM para encontrar a classe que declarou o membro com um modificador de acesso. let declaradorClasse = undefined; let acesso = undefined; for (const cls of this.classe.orem) { const acessoCls = (_b = (_a = cls.acessoPropriedades) === null || _a === void 0 ? void 0 : _a[nome]) !== null && _b !== void 0 ? _b : (_c = cls.acessoMetodos) === null || _c === void 0 ? void 0 : _c[nome]; if (acessoCls) { acesso = acessoCls; declaradorClasse = cls; break; } } if (!acesso || acesso === 'publico') return; const classeAtual = visitante === null || visitante === void 0 ? void 0 : visitante.classeAtualEmExecucao; if (acesso === 'privado') { if (classeAtual !== declaradorClasse) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Membro '${nome}' é privado e não pode ser acessado fora da classe '${(_d = declaradorClasse.simboloOriginal) === null || _d === void 0 ? void 0 : _d.lexema}'.`); } } else if (acesso === 'protegido') { const eAcessivel = (_f = (_e = classeAtual === null || classeAtual === void 0 ? void 0 : classeAtual.orem) === null || _e === void 0 ? void 0 : _e.includes(declaradorClasse)) !== null && _f !== void 0 ? _f : false; if (!eAcessivel) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Membro '${nome}' é protegido e não pode ser acessado fora da hierarquia da classe '${(_g = declaradorClasse.simboloOriginal) === null || _g === void 0 ? void 0 : _g.lexema}'.`); } } } async obter(simbolo, visitante) { const obtenedor = this.classe.encontrarObtenedor(simbolo.lexema); if (obtenedor) { if (!visitante) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Obtenedor '${simbolo.lexema}' requer contexto de execução.`); } const metodoObtenedor = obtenedor.funcaoPorMetodoDeClasse(this); return await metodoObtenedor.chamar(visitante, []); } // Auto-property: acessa o campo de armazenamento interno '_nome' const propAuto = this.classe.propriedades.find((p) => p.nome.lexema === simbolo.lexema); if (propAuto === null || propAuto === void 0 ? void 0 : propAuto.autoObter) { this.verificarAcessoLeitura(simbolo.lexema, simbolo, visitante); return this.propriedades['_' + simbolo.lexema]; } if (propAuto && propAuto.autoDefinir && !propAuto.autoObter) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Propriedade '${simbolo.lexema}' é somente-escrita.`); } if (this.propriedades.hasOwnProperty(simbolo.lexema)) { this.verificarAcessoLeitura(simbolo.lexema, simbolo, visitante); return this.propriedades[simbolo.lexema]; } if (Object.prototype.hasOwnProperty.call(this.classe.membrosEstaticos, simbolo.lexema)) { return await this.classe.obterEstatico(simbolo.lexema, visitante); } const metodo = this.classe.encontrarMetodo(simbolo.lexema); if (metodo) { this.verificarAcessoLeitura(simbolo.lexema, simbolo, visitante); return metodo.funcaoPorMetodoDeClasse(this); } throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Método ou propriedade "${simbolo.lexema}" não existe neste objeto.`); } obterMetodo(nomeMetodo) { const metodo = this.classe.encontrarMetodo(nomeMetodo); if (metodo) return metodo.funcaoPorMetodoDeClasse(this); throw new excecoes_1.ErroEmTempoDeExecucao(null, `Método "${nomeMetodo}" não existe neste objeto.`); } obterPropriedade(nomePropriedade) { if (this.propriedades.hasOwnProperty(nomePropriedade)) { return this.propriedades[nomePropriedade]; } throw new excecoes_1.ErroEmTempoDeExecucao(null, `Propriedade "${nomePropriedade}" não existe neste objeto.`); } async definir(simbolo, valor, visitante) { const definidor = this.classe.encontrarDefinidor(simbolo.lexema); if (definidor) { if (!visitante) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Definidor '${simbolo.lexema}' requer contexto de execução.`); } const metodoDefinidor = definidor.funcaoPorMetodoDeClasse(this); await metodoDefinidor.chamar(visitante, [{ nome: null, valor }]); return; } // Auto-property: armazena no campo interno '_nome' const propAuto = this.classe.propriedades.find((p) => p.nome.lexema === simbolo.lexema); if (propAuto === null || propAuto === void 0 ? void 0 : propAuto.autoDefinir) { this.verificarAcessoLeitura(simbolo.lexema, simbolo, visitante); this.propriedades['_' + simbolo.lexema] = valor; return; } if (propAuto && propAuto.autoObter && !propAuto.autoDefinir) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Propriedade '${simbolo.lexema}' é somente-leitura.`); } if (Object.prototype.hasOwnProperty.call(this.classe.membrosEstaticos, simbolo.lexema)) { await this.classe.definirEstatico(simbolo.lexema, valor, visitante); return; } // Verificar acesso antes da atribuição. this.verificarAcessoLeitura(simbolo.lexema, simbolo, visitante); if (this.classe.dialetoRequerDeclaracaoPropriedades && !this.propriedades.hasOwnProperty(simbolo.lexema)) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Propriedade "${simbolo.lexema}" não foi definida na declaração da classe ${this.classe.simboloOriginal.lexema}.`); } this.propriedades[simbolo.lexema] = valor; } /** * Método utilizado por Delégua para inspecionar este objeto em depuração. * @returns {string} A representação do objeto como texto. */ paraTexto() { var _a, _b; const nome = (_b = (_a = this.classe.simboloOriginal) === null || _a === void 0 ? void 0 : _a.lexema) !== null && _b !== void 0 ? _b : 'Objeto'; const nomesMetodos = Object.keys(this.classe.metodos).join(', '); const nomesPropriedades = Object.keys(this.propriedades).join(', '); return `<[ ${nome} métodos=[${nomesMetodos}] propriedades=[${nomesPropriedades}] ]>`; } /** * Método utilizado pelo VSCode para representar este objeto quando impresso. * @returns {string} A representação do objeto como texto. */ toString() { return this.paraTexto(); } } exports.ObjetoDeleguaClasse = ObjetoDeleguaClasse; //# sourceMappingURL=objeto-delegua-classe.js.map