@designliquido/delegua
Version:
Linguagem de programação simples e moderna usando português estruturado.
287 lines • 13.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.visitarExpressaoAcessoMetodo = visitarExpressaoAcessoMetodo;
exports.visitarExpressaoAcessoMetodoOuPropriedade = visitarExpressaoAcessoMetodoOuPropriedade;
exports.visitarExpressaoAcessoPropriedade = visitarExpressaoAcessoPropriedade;
exports.resolverInterpolacoes = resolverInterpolacoes;
exports.visitarExpressaoAcessoIntervaloVariavel = visitarExpressaoAcessoIntervaloVariavel;
exports.visitarExpressaoTuplaN = visitarExpressaoTuplaN;
const construtos_1 = require("../../../construtos");
const inferenciador_1 = require("../../../inferenciador");
const quebras_1 = require("../../../quebras");
const estruturas_1 = require("../../estruturas");
const excecoes_1 = require("../../../excecoes");
const primitivas_dicionario_1 = __importDefault(require("../../../bibliotecas/dialetos/pitugues/primitivas-dicionario"));
const primitivas_numero_1 = __importDefault(require("../../../bibliotecas/dialetos/pitugues/primitivas-numero"));
const primitivas_texto_1 = __importDefault(require("../../../bibliotecas/dialetos/pitugues/primitivas-texto"));
const primitivas_vetor_1 = __importDefault(require("../../../bibliotecas/dialetos/pitugues/primitivas-vetor"));
const primitivas_tupla_1 = __importDefault(require("../../../bibliotecas/dialetos/pitugues/primitivas-tupla"));
const primitivos_1 = __importDefault(require("../../../tipos-de-dados/primitivos"));
async function visitarExpressaoAcessoMetodo(interpretador, expressao) {
const nomeObjeto = interpretador.resolverNomeObjectoAcessado(expressao.objeto);
let variavelObjeto = await interpretador.avaliar(expressao.objeto);
// Este caso acontece quando há encadeamento de métodos.
// Por exemplo, `objeto1.metodo1().metodo2()`.
// Como `RetornoQuebra` também possui `valor`, precisamos extrair o
// valor dele primeiro.
if (variavelObjeto.constructor && variavelObjeto.constructor === quebras_1.RetornoQuebra) {
variavelObjeto = variavelObjeto.valor;
}
const objeto = interpretador.resolverValor(variavelObjeto);
if (objeto instanceof estruturas_1.ObjetoDeleguaClasse) {
return objeto.obterMetodo(expressao.nomeMetodo) || null;
}
let tipoObjeto = variavelObjeto.tipo;
if (tipoObjeto === null || tipoObjeto === undefined) {
tipoObjeto = (0, inferenciador_1.inferirTipoVariavel)(variavelObjeto);
}
if (Array.isArray(objeto)) {
tipoObjeto = 'vetor';
}
else if (objeto instanceof construtos_1.TuplaN || objeto.constructor.name === 'TuplaN') {
tipoObjeto = 'tupla';
}
else if (objeto.constructor === Object) {
tipoObjeto = 'dicionário';
}
else if (objeto.constructor === String) {
tipoObjeto = 'texto';
}
const primitiva = resolverPrimitiva(interpretador, tipoObjeto, expressao.nomeMetodo);
if (primitiva) {
return new estruturas_1.MetodoPrimitiva(nomeObjeto, objeto, primitiva.implementacao, expressao.nomeMetodo, tipoObjeto);
}
// Casos em que o objeto possui algum outro tipo que não o de objeto simples.
// Normalmente executam quando uma biblioteca é importada, e estamos tentando
// obter alguma propriedade ou método desse objeto.
if (typeof objeto[expressao.nomeMetodo] === primitivos_1.default.FUNCAO ||
typeof objeto[expressao.nomeMetodo] === primitivos_1.default.OBJETO) {
return objeto[expressao.nomeMetodo];
}
// A partir daqui, presume-se que o objeto é uma das estruturas
// de Delégua.
if (objeto instanceof estruturas_1.DeleguaModulo) {
return objeto.componentes[expressao.nomeMetodo] || null;
}
if (objeto.hasOwnProperty && objeto.hasOwnProperty(expressao.nomeMetodo)) {
return objeto[expressao.nomeMetodo];
}
return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({
hashArquivo: interpretador.hashArquivoDeclaracaoAtual,
linha: interpretador.linhaDeclaracaoAtual,
}, `Método para objeto ou primitiva não encontrado: ${expressao.nomeMetodo}.`, expressao.linha));
}
/**
* Casos que ocorrem aqui:
*
* - Quando o método ou propriedade é ou 'qualquer', ou vetor
* de 'qualquer' ('qualquer[]'), e uma primitiva é usada.
* - Quando o objeto é uma classe definida em código.
* @param {AcessoMetodoOuPropriedade} expressao A expressão de acesso a método ou propriedade.
* @returns A primitiva encontrada.
*/
async function visitarExpressaoAcessoMetodoOuPropriedade(interpretador, expressao) {
const nomeObjeto = interpretador.resolverNomeObjectoAcessado(expressao.objeto);
let variavelObjeto = await interpretador.avaliar(expressao.objeto);
// Este caso acontece quando há encadeamento de métodos.
// Por exemplo, `objeto1.metodo1().metodo2()`.
// Como `RetornoQuebra` também possui `valor`, precisamos extrair o
// valor dele primeiro.
if (variavelObjeto.constructor === quebras_1.RetornoQuebra) {
const retornoQuebra = variavelObjeto;
variavelObjeto = retornoQuebra.valor;
}
const objeto = interpretador.resolverValor(variavelObjeto, true);
if (objeto instanceof estruturas_1.ObjetoDeleguaClasse) {
return await objeto.obter(expressao.simbolo, interpretador);
}
let tipoObjeto = variavelObjeto.tipo;
if (tipoObjeto === null || tipoObjeto === undefined) {
tipoObjeto = (0, inferenciador_1.inferirTipoVariavel)(variavelObjeto);
}
if (Array.isArray(objeto)) {
tipoObjeto = 'vetor';
}
else if (objeto instanceof construtos_1.TuplaN || objeto.constructor.name === 'TuplaN') {
tipoObjeto = 'tupla';
}
else if (objeto.constructor === Object) {
tipoObjeto = 'dicionário';
}
else if (objeto.constructor === String) {
tipoObjeto = 'texto';
}
const primitiva = resolverPrimitiva(interpretador, tipoObjeto, expressao.simbolo.lexema);
if (primitiva) {
return new estruturas_1.MetodoPrimitiva(nomeObjeto, objeto, primitiva.implementacao, expressao.simbolo.lexema, tipoObjeto);
}
// Fallback para propriedades simples do objeto
if (objeto.hasOwnProperty && objeto.hasOwnProperty(expressao.simbolo.lexema)) {
return objeto[expressao.simbolo.lexema];
}
// Último caso: objeto simples, sem construtor, sem protótipo. Exemplo: {'a': 1, 'b': 2}
if (typeof objeto[expressao.simbolo.lexema] !== 'undefined') {
return objeto[expressao.simbolo.lexema];
}
return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(null, `Método ou propriedade para objeto ou primitiva não encontrado: ${expressao.simbolo.lexema}.`, expressao.linha));
}
async function visitarExpressaoAcessoPropriedade(interpretador, expressao) {
const nomeObjeto = interpretador.resolverNomeObjectoAcessado(expressao.objeto);
let variavelObjeto = await interpretador.avaliar(expressao.objeto);
// Este caso acontece quando há encadeamento de métodos.
// Por exemplo, `objeto1.metodo1().metodo2()`.
// Como `RetornoQuebra` também possui `valor`, precisamos extrair o
// valor dele primeiro.
if (variavelObjeto.constructor && variavelObjeto.constructor === quebras_1.RetornoQuebra) {
variavelObjeto = variavelObjeto.valor;
}
const objeto = interpretador.resolverValor(variavelObjeto);
if (objeto instanceof estruturas_1.ObjetoDeleguaClasse) {
return objeto.obterMetodo(expressao.nomePropriedade) || null;
}
let tipoObjeto = variavelObjeto.tipo;
if (tipoObjeto === null || tipoObjeto === undefined) {
tipoObjeto = (0, inferenciador_1.inferirTipoVariavel)(variavelObjeto);
}
if (Array.isArray(objeto)) {
tipoObjeto = 'vetor';
}
else if (objeto instanceof construtos_1.TuplaN || objeto.constructor.name === 'TuplaN') {
tipoObjeto = 'tupla';
}
else if (objeto.constructor === Object) {
tipoObjeto = 'dicionário';
}
else if (objeto.constructor === String) {
tipoObjeto = 'texto';
}
const primitiva = resolverPrimitiva(interpretador, tipoObjeto, expressao.nomePropriedade);
if (primitiva) {
return new estruturas_1.MetodoPrimitiva(nomeObjeto, objeto, primitiva.implementacao, expressao.nomePropriedade, tipoObjeto);
}
// Casos em que o objeto possui algum outro tipo que não o de objeto simples.
// Normalmente executam quando uma biblioteca é importada, e estamos tentando
// obter alguma propriedade ou método desse objeto.
if (typeof objeto[expressao.nomePropriedade] === primitivos_1.default.FUNCAO ||
typeof objeto[expressao.nomePropriedade] === primitivos_1.default.OBJETO) {
return objeto[expressao.nomePropriedade];
}
// A partir daqui, presume-se que o objeto é uma das estruturas
// de Delégua.
if (objeto instanceof estruturas_1.DeleguaModulo) {
return objeto.componentes[expressao.nomePropriedade] || null;
}
return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(null, `Propriedade para objeto ou primitiva não encontrado: ${expressao.nomePropriedade}.`, expressao.linha));
}
async function resolverInterpolacoes(interpretador, textoOriginal, linha) {
const regexInterpolacao = /\$\{[a-zA-Z_][a-zA-Z0-9_]*\}/g;
const variaveis = textoOriginal.match(regexInterpolacao);
if (!variaveis)
return [];
const resultadosAvaliacaoSintatica = variaveis.map((s) => {
// s tem a forma "${identificador}" — removemos apenas os dois primeiros e o último caractere
const expressaoInterpolacao = s.slice(2, -1);
let microLexador = interpretador.microLexador.mapear(expressaoInterpolacao);
const resultadoMicroAvaliadorSintatico = interpretador.microAvaliadorSintatico.analisar(microLexador, linha);
return {
expressaoInterpolacao,
resultadoMicroAvaliadorSintatico,
};
});
const resolucoesPromises = await Promise.all(resultadosAvaliacaoSintatica
.flatMap((r) => r.resultadoMicroAvaliadorSintatico.declaracoes)
.map((d) => interpretador.avaliar(d)));
return resolucoesPromises.map((item, indice) => ({
expressaoInterpolacao: resultadosAvaliacaoSintatica[indice].expressaoInterpolacao,
valor: item,
}));
}
async function visitarExpressaoAcessoIntervaloVariavel(interpretador, expressao) {
const resultadoEntidade = await interpretador.avaliar(expressao.entidadeChamada);
const objeto = interpretador.resolverValor(resultadoEntidade);
let tamanho = 0;
let itens;
const ehTexto = typeof objeto === 'string';
if (objeto instanceof construtos_1.TuplaN) {
itens = objeto.elementos;
tamanho = objeto.elementos.length;
}
else if (Array.isArray(objeto) || ehTexto) {
itens = objeto;
tamanho = objeto.length;
}
else {
throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloFechamento, 'Acesso por intervalo só é suportado em vetores, textos e tuplas.', expressao.linha);
}
let passo = 1;
if (expressao.indicePasso) {
const resPasso = await interpretador.avaliar(expressao.indicePasso);
passo = interpretador.resolverValor(resPasso);
}
if (passo === 0) {
throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloFechamento, 'O passo do fatiamento não pode ser zero.', expressao.linha);
}
let inicio = passo > 0 ? 0 : tamanho - 1;
if (expressao.indiceInicio) {
const resInicio = await interpretador.avaliar(expressao.indiceInicio);
inicio = interpretador.resolverValor(resInicio);
if (inicio < 0)
inicio = tamanho + inicio;
}
let fim = passo > 0 ? tamanho : -1;
if (expressao.indiceFim) {
const resFim = await interpretador.avaliar(expressao.indiceFim);
fim = interpretador.resolverValor(resFim);
if (fim < 0)
fim = tamanho + fim;
}
// Lógica de fatiamento para suportar "passo", pois o TypeScript não suporta nativamente
const resultadoFatiado = [];
if (passo > 0) {
for (let i = inicio; i < fim; i += passo) {
if (i >= 0 && i < tamanho) {
resultadoFatiado.push(itens[i]);
}
}
}
else {
for (let i = inicio; i > fim; i += passo) {
if (i >= 0 && i < tamanho) {
resultadoFatiado.push(itens[i]);
}
}
}
if (objeto instanceof construtos_1.TuplaN) {
return new construtos_1.TuplaN(objeto.hashArquivo, objeto.linha, resultadoFatiado);
}
if (ehTexto)
return resultadoFatiado.join('');
return resultadoFatiado;
}
async function visitarExpressaoTuplaN(interpretador, expressao) {
const elementos = [];
for (let i = 0; i < expressao.elementos.length; i++) {
const res = await interpretador.avaliar(expressao.elementos[i]);
elementos.push(interpretador.resolverValor(res));
}
const elementosComoConstrutos = elementos.map((valor) => new construtos_1.Literal(expressao.hashArquivo, expressao.linha, valor));
return new construtos_1.TuplaN(expressao.hashArquivo, expressao.linha, elementosComoConstrutos);
}
function resolverPrimitiva(interpretador, tipo, nomeMetodo) {
const viaMapa = interpretador.obterPrimitiva?.(tipo, nomeMetodo);
if (viaMapa)
return viaMapa;
const modulos = {
dicionário: primitivas_dicionario_1.default,
número: primitivas_numero_1.default,
numero: primitivas_numero_1.default,
texto: primitivas_texto_1.default,
vetor: primitivas_vetor_1.default,
tupla: primitivas_tupla_1.default,
};
return modulos[tipo]?.[nomeMetodo] ?? undefined;
}
//# sourceMappingURL=comum.js.map