UNPKG

@designliquido/delegua

Version:

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

657 lines 32.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Interpretador = void 0; const construtos_1 = require("../construtos"); const estruturas_1 = require("./estruturas"); const interpretador_base_1 = require("./interpretador-base"); const inferenciador_1 = require("../inferenciador"); const excecoes_1 = require("../excecoes"); const quebras_1 = require("../quebras"); const montao_1 = require("./montao"); const primitivas_dicionario_1 = __importDefault(require("../bibliotecas/primitivas-dicionario")); const primitivas_numero_1 = __importDefault(require("../bibliotecas/primitivas-numero")); const primitivas_texto_1 = __importDefault(require("../bibliotecas/primitivas-texto")); const primitivas_vetor_1 = __importDefault(require("../bibliotecas/primitivas-vetor")); const primitivos_1 = __importDefault(require("../tipos-de-dados/primitivos")); const delegua_1 = __importDefault(require("../tipos-de-dados/delegua")); /** * O interpretador de Delégua. */ class Interpretador extends interpretador_base_1.InterpretadorBase { constructor(diretorioBase, performance = false, funcaoDeRetorno = null, funcaoDeRetornoMesmaLinha = null) { super(diretorioBase, performance, funcaoDeRetorno, funcaoDeRetornoMesmaLinha); this.montao = new montao_1.Montao(); } resolverReferenciaMontao(referenciaMontao) { const valorMontao = this.montao.obterReferencia(this.hashArquivoDeclaracaoAtual, this.linhaDeclaracaoAtual, referenciaMontao.endereco); return valorMontao; } resolverValor(objeto) { if (objeto === null || objeto === undefined) { return objeto; } if (Array.isArray(objeto)) { const vetorResolvido = []; for (const elemento of objeto) { vetorResolvido.push(this.resolverValor(elemento)); } return vetorResolvido; } if (objeto instanceof estruturas_1.ReferenciaMontao) { return this.resolverReferenciaMontao(objeto); } if (objeto.hasOwnProperty('valor')) { if (Array.isArray(objeto.valor)) { return this.resolverValor(objeto.valor); } if (objeto.valor instanceof estruturas_1.ReferenciaMontao) { return this.resolverReferenciaMontao(objeto.valor); } return objeto.valor; } return objeto; } paraTexto(objeto) { if (objeto === null || objeto === undefined) return delegua_1.default.NULO; if (typeof objeto === primitivos_1.default.BOOLEANO) { return objeto ? 'verdadeiro' : 'falso'; } if (objeto.valor instanceof estruturas_1.ObjetoPadrao) return objeto.valor.paraTexto(); if (objeto instanceof estruturas_1.ObjetoDeleguaClasse || objeto instanceof estruturas_1.DeleguaFuncao || typeof objeto.paraTexto === 'function') return objeto.paraTexto(); if (objeto instanceof quebras_1.RetornoQuebra) { if (typeof objeto.valor === 'boolean') return objeto.valor ? 'verdadeiro' : 'falso'; } if (objeto instanceof Date) { const formato = Intl.DateTimeFormat('pt', { dateStyle: 'full', timeStyle: 'full', }); return formato.format(objeto); } if (Array.isArray(objeto)) { let retornoVetor = '['; for (let elemento of objeto) { if (typeof elemento === 'object') { retornoVetor += `${JSON.stringify(elemento)}, `; continue; } retornoVetor += typeof elemento === 'string' ? `'${elemento}', ` : `${this.paraTexto(elemento)}, `; } if (retornoVetor.length > 1) { retornoVetor = retornoVetor.slice(0, -2); } retornoVetor += ']'; return retornoVetor; } switch (objeto.constructor.name) { case 'Object': if ('tipo' in objeto) { switch (objeto.tipo) { case 'dicionário': return JSON.stringify(objeto.valor); default: return objeto.valor; } } } if (typeof objeto === primitivos_1.default.OBJETO) { const objetoEscrita = {}; for (const propriedade in objeto) { let valor = objeto[propriedade]; if (typeof valor === primitivos_1.default.BOOLEANO) { valor = valor ? 'verdadeiro' : 'falso'; } if (valor instanceof estruturas_1.ReferenciaMontao) { valor = this.resolverValor(valor); } objetoEscrita[propriedade] = valor; } return JSON.stringify(objetoEscrita); } return objeto.toString(); } async avaliacaoDeclaracaoVarOuConst(declaracao) { let valorOuOutraVariavel = null; if (declaracao.inicializador !== null) { valorOuOutraVariavel = await this.avaliar(declaracao.inicializador); } let valorFinal = null; if (valorOuOutraVariavel !== null && valorOuOutraVariavel !== undefined) { valorFinal = this.resolverValor(valorOuOutraVariavel); } return valorFinal; } async avaliarArgumentosEscreva(argumentos) { let formatoTexto = ''; for (const argumento of argumentos) { const resultadoAvaliacao = await this.avaliar(argumento); let valor = this.resolverValor(resultadoAvaliacao); formatoTexto += `${this.paraTexto(valor)} `; } return formatoTexto.trimEnd(); } visitarDeclaracaoDefinicaoFuncao(declaracao) { const funcao = new estruturas_1.DeleguaFuncao(declaracao.simbolo.lexema, declaracao.funcao); // TODO: Depreciar essa abordagem a favor do uso por referências. this.pilhaEscoposExecucao.definirVariavel(declaracao.simbolo.lexema, funcao); this.pilhaEscoposExecucao.registrarReferenciaFuncao(declaracao.id, funcao); } async visitarExpressaoAcessoIndiceVariavel(expressao) { const promises = await Promise.all([ this.avaliar(expressao.entidadeChamada), this.avaliar(expressao.indice), ]); const variavelObjeto = promises[0]; const indice = promises[1]; const objeto = this.resolverValor(variavelObjeto); let valorIndice = this.resolverValor(indice); if (Array.isArray(objeto)) { if (!Number.isInteger(valorIndice)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloFechamento, 'Somente inteiros podem ser usados para indexar um vetor.', expressao.linha)); } if (valorIndice < 0 && objeto.length !== 0) { while (valorIndice < 0) { valorIndice += objeto.length; } } if (valorIndice >= objeto.length) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloFechamento, 'Índice do vetor fora do intervalo.', expressao.linha)); } return objeto[valorIndice]; } if (objeto instanceof construtos_1.Vetor) { return objeto.valores[valorIndice]; } if (objeto.constructor === Object || objeto instanceof estruturas_1.ObjetoDeleguaClasse || objeto instanceof estruturas_1.DeleguaFuncao || objeto instanceof estruturas_1.DescritorTipoClasse || objeto instanceof estruturas_1.DeleguaModulo) { if (objeto[valorIndice] === 0) return 0; return objeto[valorIndice] || null; } if (typeof objeto === primitivos_1.default.TEXTO) { if (!Number.isInteger(valorIndice)) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloFechamento, 'Somente inteiros podem ser usados para indexar um vetor.', expressao.linha)); } if (valorIndice < 0 && objeto.length !== 0) { while (valorIndice < 0) { valorIndice += objeto.length; } } if (valorIndice >= objeto.length) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloFechamento, 'Índice fora do tamanho.', expressao.linha)); } return objeto.charAt(valorIndice); } return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: this.hashArquivoDeclaracaoAtual, linha: this.linhaDeclaracaoAtual, }, 'Somente listas, dicionários, classes e objetos podem ter seus valores indexados.', expressao.linha)); } async visitarExpressaoAcessoMetodo(expressao) { let variavelObjeto = await this.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.name === 'RetornoQuebra') { variavelObjeto = variavelObjeto.valor; } const objeto = this.resolverValor(variavelObjeto); if (objeto.constructor.name === 'ObjetoDeleguaClasse') { return objeto.obterMetodo(expressao.nomeMetodo) || null; } // Objeto simples do JavaScript, ou dicionário de Delégua. if (objeto.constructor === Object) { if (expressao.nomeMetodo in primitivas_dicionario_1.default) { const metodoDePrimitivaDicionario = primitivas_dicionario_1.default[expressao.nomeMetodo].implementacao; return new estruturas_1.MetodoPrimitiva(objeto, metodoDePrimitivaDicionario); } return objeto[expressao.nomeMetodo] || null; } // 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. // Caso 1: Função tradicional do JavaScript. if (typeof objeto[expressao.nomeMetodo] === primitivos_1.default.FUNCAO) { return objeto[expressao.nomeMetodo]; } // Caso 2: Objeto tradicional do JavaScript. if (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; } let tipoObjeto = variavelObjeto.tipo; if (tipoObjeto === null || tipoObjeto === undefined) { tipoObjeto = (0, inferenciador_1.inferirTipoVariavel)(variavelObjeto); } // Como internamente um dicionário de Delégua é simplesmente um objeto de // JavaScript, as primitivas de dicionário, especificamente, são tratadas // mais acima. switch (tipoObjeto) { case delegua_1.default.INTEIRO: case delegua_1.default.NUMERO: case delegua_1.default.NÚMERO: const metodoDePrimitivaNumero = primitivas_numero_1.default[expressao.nomeMetodo].implementacao; if (metodoDePrimitivaNumero) { return new estruturas_1.MetodoPrimitiva(objeto, metodoDePrimitivaNumero); } break; case delegua_1.default.TEXTO: const metodoDePrimitivaTexto = primitivas_texto_1.default[expressao.nomeMetodo].implementacao; if (metodoDePrimitivaTexto) { return new estruturas_1.MetodoPrimitiva(objeto, metodoDePrimitivaTexto); } break; case delegua_1.default.VETOR: case delegua_1.default.VETOR_NUMERO: case delegua_1.default.VETOR_NÚMERO: case delegua_1.default.VETOR_TEXTO: const metodoDePrimitivaVetor = primitivas_vetor_1.default[expressao.nomeMetodo].implementacao; if (metodoDePrimitivaVetor) { return new estruturas_1.MetodoPrimitiva(objeto, metodoDePrimitivaVetor); } break; } return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao({ hashArquivo: this.hashArquivoDeclaracaoAtual, linha: this.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 visitarExpressaoAcessoMetodoOuPropriedade(expressao) { let variavelObjeto = await this.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.name === 'RetornoQuebra') { variavelObjeto = variavelObjeto.valor; } const objeto = this.resolverValor(variavelObjeto); if (objeto.constructor.name === 'ObjetoDeleguaClasse') { return objeto.obter(expressao.simbolo); } // Objeto simples do JavaScript, ou dicionário de Delégua. if (objeto.constructor === Object) { if (expressao.simbolo.lexema in primitivas_dicionario_1.default) { const metodoDePrimitivaDicionario = primitivas_dicionario_1.default[expressao.simbolo.lexema].implementacao; return new estruturas_1.MetodoPrimitiva(objeto, metodoDePrimitivaDicionario); } return objeto[expressao.simbolo.lexema]; } // A partir daqui, presume-se que o objeto é uma das estruturas // de Delégua. if (objeto instanceof estruturas_1.DeleguaModulo) { return objeto.componentes[expressao.simbolo.lexema] || null; } let tipoObjeto = variavelObjeto.tipo; if (tipoObjeto === null || tipoObjeto === undefined) { tipoObjeto = (0, inferenciador_1.inferirTipoVariavel)(variavelObjeto); } // Como internamente um dicionário de Delégua é simplesmente um objeto de // JavaScript, as primitivas de dicionário, especificamente, são tratadas // mais acima. switch (tipoObjeto) { case delegua_1.default.INTEIRO: case delegua_1.default.NUMERO: case delegua_1.default.NÚMERO: const metodoDePrimitivaNumero = primitivas_numero_1.default[expressao.simbolo.lexema].implementacao; if (metodoDePrimitivaNumero) { return new estruturas_1.MetodoPrimitiva(objeto, metodoDePrimitivaNumero); } break; case delegua_1.default.TEXTO: const metodoDePrimitivaTexto = primitivas_texto_1.default[expressao.simbolo.lexema].implementacao; if (metodoDePrimitivaTexto) { return new estruturas_1.MetodoPrimitiva(objeto, metodoDePrimitivaTexto); } break; case delegua_1.default.VETOR: case delegua_1.default.VETOR_INTEIRO: case delegua_1.default.VETOR_LOGICO: case delegua_1.default.VETOR_LÓGICO: case delegua_1.default.VETOR_NUMERO: case delegua_1.default.VETOR_NÚMERO: case delegua_1.default.VETOR_QUALQUER: case delegua_1.default.VETOR_TEXTO: const metodoDePrimitivaVetor = primitivas_vetor_1.default[expressao.simbolo.lexema].implementacao; if (metodoDePrimitivaVetor) { return new estruturas_1.MetodoPrimitiva(objeto, metodoDePrimitivaVetor); } break; } // Último caso válido: objeto de uma classe JavaScript que possua a propriedade. // Exemplos: classes de LinConEs, como `RetornoComando`, ou bibliotecas globais com objetos próprios. if (objeto.hasOwnProperty(expressao.simbolo.lexema) || 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 visitarExpressaoAcessoPropriedade(expressao) { let variavelObjeto = await this.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.name === 'RetornoQuebra') { variavelObjeto = variavelObjeto.valor; } const objeto = this.resolverValor(variavelObjeto); // Outro caso que `instanceof` simplesmente não funciona para casos em Liquido, // então testamos também o nome do construtor. if (objeto instanceof estruturas_1.ObjetoDeleguaClasse || objeto.constructor.name === 'ObjetoDeleguaClasse') { return objeto.obterMetodo(expressao.nomePropriedade) || null; } // Objeto simples do JavaScript, ou dicionário de Delégua. if (objeto.constructor === Object) { if (expressao.nomePropriedade in primitivas_dicionario_1.default) { const metodoDePrimitivaDicionario = primitivas_dicionario_1.default[expressao.nomePropriedade].implementacao; return new estruturas_1.MetodoPrimitiva(objeto, metodoDePrimitivaDicionario); } return objeto[expressao.nomePropriedade] || null; } // 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. // Caso 1: Função tradicional do JavaScript. if (typeof objeto[expressao.nomePropriedade] === primitivos_1.default.FUNCAO) { return objeto[expressao.nomePropriedade]; } // Caso 2: Objeto tradicional do JavaScript. if (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; } let tipoObjeto = variavelObjeto.tipo; if (tipoObjeto === null || tipoObjeto === undefined) { tipoObjeto = (0, inferenciador_1.inferirTipoVariavel)(variavelObjeto); } return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(null, `Propriedade para objeto ou primitiva não encontrado: ${expressao.nomePropriedade}.`, expressao.linha)); } async visitarExpressaoArgumentoReferenciaFuncao(expressao) { const deleguaFuncao = this.pilhaEscoposExecucao.obterVariavelPorNome(expressao.simboloFuncao.lexema); return deleguaFuncao; } async visitarExpressaoAtribuicaoPorIndice(expressao) { const promises = await Promise.all([ this.avaliar(expressao.objeto), this.avaliar(expressao.indice), this.avaliar(expressao.valor), ]); let objeto = promises[0]; let indice = promises[1]; const valor = promises[2]; if (objeto.tipo === delegua_1.default.TUPLA) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(expressao.objeto.simbolo.lexema, 'Não é possível modificar uma tupla. As tuplas são estruturas de dados imutáveis.', expressao.linha)); } objeto = this.resolverValor(objeto); indice = this.resolverValor(indice); // Se o valor é uma referência ao montão, e o índice que a recebe é // de uma variável/constante que vive num escopo superior, a referência // precisa ser transferida para o escopo correspondente. if (valor instanceof estruturas_1.ReferenciaMontao) { // TODO: Terminar const nomeVariavel = expressao.objeto.simbolo.lexema; if (this.pilhaEscoposExecucao.obterVariavelEm(1, nomeVariavel) === undefined) { this.pilhaEscoposExecucao.migrarReferenciaMontaoParaEscopoDeVariavel(nomeVariavel, valor.endereco); } } if (Array.isArray(objeto)) { if (indice < 0 && objeto.length !== 0) { while (indice < 0) { indice += objeto.length; } } while (objeto.length < indice) { objeto.push(null); } objeto[indice] = valor; } else if (objeto.constructor === Object || objeto instanceof estruturas_1.ObjetoDeleguaClasse || objeto instanceof estruturas_1.DeleguaFuncao || objeto instanceof estruturas_1.DescritorTipoClasse || objeto instanceof estruturas_1.DeleguaModulo) { objeto[indice] = valor; } else { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(expressao.objeto.nome, 'Somente listas, dicionários, classes e objetos podem ser mudados por índice.', expressao.linha)); } } /** * Execução de uma expressão de atribuição. * @param expressao A expressão. * @returns O valor atribuído. */ async visitarExpressaoDeAtribuicao(expressao) { const valor = await this.avaliar(expressao.valor); const valorResolvido = this.resolverValor(valor); let indice = null; if (expressao.indice) { indice = await this.avaliar(expressao.indice); } switch (expressao.alvo.constructor.name) { case 'Variavel': const alvoVariavel = expressao.alvo; const variavelResolvida = this.pilhaEscoposExecucao.obterValorVariavel(alvoVariavel.simbolo); if (variavelResolvida.valor instanceof estruturas_1.ReferenciaMontao) { const referenciaMontao = this.montao.obterReferencia(this.hashArquivoDeclaracaoAtual, this.linhaDeclaracaoAtual, variavelResolvida.valor.endereco); referenciaMontao[indice] = valorResolvido; } else { this.pilhaEscoposExecucao.atribuirVariavel(alvoVariavel.simbolo, valorResolvido, indice); } break; case 'AcessoMetodoOuPropriedade': // Nunca será método aqui: apenas propriedade. const alvoPropriedade = expressao.alvo; const variavelObjeto = await this.avaliar(alvoPropriedade.objeto); const objeto = this.resolverValor(variavelObjeto); const valor = await this.avaliar(expressao.valor); if (objeto.constructor.name === 'ObjetoDeleguaClasse') { const objetoDeleguaClasse = objeto; objetoDeleguaClasse.definir(alvoPropriedade.simbolo, valor); } else { // Se cair aqui, provavelmente `objeto.constructor.name` é 'Object'. objeto[alvoPropriedade.simbolo.lexema] = valor; } break; default: throw new excecoes_1.ErroEmTempoDeExecucao(null, `Atribuição com caso faltante: ${expressao.alvo.constructor.name}.`); } return valorResolvido; } async visitarExpressaoDefinirValor(expressao) { const variavelObjeto = await this.avaliar(expressao.objeto); const objeto = this.resolverValor(variavelObjeto); if (objeto.constructor.name !== 'ObjetoDeleguaClasse' && objeto.constructor !== Object) { return Promise.reject(new excecoes_1.ErroEmTempoDeExecucao(expressao.nome, 'Somente instâncias e dicionários podem possuir campos.', expressao.linha)); } const valor = await this.avaliar(expressao.valor); const valorResolvido = this.resolverValor(valor); if (objeto.constructor.name === 'ObjetoDeleguaClasse') { objeto.definir(expressao.nome, valorResolvido); return valorResolvido; } if (objeto.constructor === Object) { objeto[expressao.nome.lexema] = valorResolvido; } } /** * Dicionários em Delégua são passados por referência, portanto, são * armazenados no montão. */ async visitarExpressaoDicionario(expressao) { const dicionario = {}; for (let i = 0; i < expressao.chaves.length; i++) { const promises = await Promise.all([ this.avaliar(expressao.chaves[i]), this.avaliar(expressao.valores[i]), ]); if (typeof promises[0] === 'boolean') { const chaveLogico = promises[0] === true ? 'verdadeiro' : 'falso'; dicionario[chaveLogico] = promises[1]; continue; } dicionario[promises[0]] = this.resolverValor(promises[1]); } const enderecoDicionarioMontao = this.montao.adicionarReferencia(dicionario); this.pilhaEscoposExecucao.registrarReferenciaMontao(enderecoDicionarioMontao); return new estruturas_1.ReferenciaMontao(enderecoDicionarioMontao); } async visitarExpressaoReferenciaFuncao(expressao) { const deleguaFuncao = this.pilhaEscoposExecucao.obterReferenciaFuncao(expressao.idFuncao); return deleguaFuncao; } async visitarExpressaoRetornar(declaracao) { let valor = null; if (declaracao.valor !== null && declaracao.valor !== undefined) { valor = await this.avaliar(declaracao.valor); } const retornoQuebra = new quebras_1.RetornoQuebra(valor); // Se o retorno for uma função anônima, o escopo precisa ser preservado. // Como quebras matam o topo da pilha de escopos, precisamos dizer // para a finalização para copiar as variáveis para o escopo de baixo. if (retornoQuebra.valor) { const construtorRetorno = retornoQuebra.valor.constructor.name.replaceAll('_', ''); if (construtorRetorno === 'DeleguaFuncao') { retornoQuebra.preservarEscopo = true; } } return retornoQuebra; } async visitarExpressaoTipoDe(expressao) { let valorTipoDe = expressao.valor; switch (valorTipoDe.constructor.name) { case 'AcessoIndiceVariavel': case 'Agrupamento': case 'Binario': case 'Chamada': case 'Dicionario': case 'Unario': valorTipoDe = await this.avaliar(valorTipoDe); if (valorTipoDe instanceof estruturas_1.ReferenciaMontao) { valorTipoDe = this.montao.obterReferencia(this.hashArquivoDeclaracaoAtual, this.linhaDeclaracaoAtual, valorTipoDe.endereco); } return valorTipoDe.tipo || (0, inferenciador_1.inferirTipoVariavel)(valorTipoDe); case 'AcessoMetodo': const acessoMetodo = valorTipoDe; return `método<${acessoMetodo.tipoRetornoMetodo}>`; case 'AcessoPropriedade': const acessoPropriedade = valorTipoDe; return acessoPropriedade.tipoRetornoPropriedade; case 'AcessoMetodoOuPropriedade': // TODO: Deve ser removido mais futuramente. // Apenas `AcessoMetodo` e `AcessoPropriedade` devem funcionar aqui. throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simbolo, 'Não deveria cair aqui.'); case 'Escreva': return 'função<vazio>'; case 'Leia': return 'função<texto>'; case 'Literal': const tipoLiteral = valorTipoDe; return tipoLiteral.tipo; case 'TipoDe': const alvoTipoDe = await this.avaliar(valorTipoDe); return `tipo de<${alvoTipoDe}>`; case 'Variavel': return valorTipoDe.tipo; case 'Vetor': return (0, inferenciador_1.inferirTipoVariavel)(valorTipoDe === null || valorTipoDe === void 0 ? void 0 : valorTipoDe.valores); default: return (0, inferenciador_1.inferirTipoVariavel)(valorTipoDe); } } /** * Executa o último escopo empilhado no topo na pilha de escopos do interpretador. * Esse método pega exceções, mas apenas as devolve. * * O tratamento das exceções é feito de acordo com o bloco chamador. * Por exemplo, em `tente ... pegue ... finalmente`, a exceção é capturada e tratada. * Em outros blocos, pode ser desejável ter o erro em tela. * @param manterAmbiente Se verdadeiro, ambiente do topo da pilha de escopo é copiado para o ambiente imediatamente abaixo. * @returns O resultado da execução do escopo, se houver. */ async executarUltimoEscopo(manterAmbiente = false) { const ultimoEscopo = this.pilhaEscoposExecucao.topoDaPilha(); let retornoExecucao; try { for (; !(retornoExecucao instanceof quebras_1.Quebra) && ultimoEscopo.declaracaoAtual < ultimoEscopo.declaracoes.length; ultimoEscopo.declaracaoAtual++) { const declaracaoAtual = ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual]; this.linhaDeclaracaoAtual = declaracaoAtual.linha; this.hashArquivoDeclaracaoAtual = declaracaoAtual.hashArquivo; retornoExecucao = await this.executar(declaracaoAtual); } return retornoExecucao; } catch (erro) { const declaracaoAtual = ultimoEscopo.declaracoes[ultimoEscopo.declaracaoAtual]; if (!this.emDeclaracaoTente) { this.erros.push({ erroInterno: erro, linha: declaracaoAtual.linha, hashArquivo: declaracaoAtual.hashArquivo, }); } else { return Promise.reject(erro); } } finally { const escopoFinalizado = this.pilhaEscoposExecucao.removerUltimo(); const escopoAnterior = this.pilhaEscoposExecucao.topoDaPilha(); this.montao.excluirReferencias(...escopoFinalizado.espacoMemoria.enderecosMontao); if (manterAmbiente || (retornoExecucao && retornoExecucao.preservarEscopo === true)) { escopoAnterior.espacoMemoria.valores = Object.assign(escopoAnterior.espacoMemoria.valores, ultimoEscopo.espacoMemoria.valores); } } } /** * Método que efetivamente inicia o processo de interpretação. * @param declaracoes Um vetor de declarações gerado pelo Avaliador Sintático. * @param manterAmbiente Se ambiente de execução (variáveis, classes, etc.) deve ser mantido. Normalmente usado * pelo modo REPL (LAIR). * @returns Um objeto com o resultado da interpretação. */ async interpretar(declaracoes, manterAmbiente) { this.montao = new montao_1.Montao(); return super.interpretar(declaracoes, manterAmbiente); } } exports.Interpretador = Interpretador; //# sourceMappingURL=interpretador.js.map