UNPKG

@designliquido/delegua

Version:

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

340 lines 15.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PilhaEscoposExecucao = void 0; const estruturas_1 = require("./estruturas"); const excecoes_1 = require("../excecoes"); const lexador_1 = require("../lexador"); const inferenciador_1 = require("../inferenciador"); const delegua_1 = __importDefault(require("../tipos-de-dados/delegua")); const tiposNumericos = ['inteiro', 'número', 'numero', 'real', 'longo']; const tiposLogicos = ['logico', 'lógico']; class PilhaEscoposExecucao { constructor() { this.pilha = []; } empilhar(item) { this.pilha.push(item); } eVazio() { return this.pilha.length === 0; } elementos() { return this.pilha.length; } naPosicao(posicao) { return this.pilha[posicao]; } topoDaPilha() { if (this.eVazio()) throw new Error('Pilha vazia.'); return this.pilha[this.pilha.length - 1]; } removerUltimo() { if (this.eVazio()) throw new Error('Pilha vazia.'); return this.pilha.pop(); } tiposCompativeis(tipoVariavel, tipoValor) { if (tipoVariavel === tipoValor) return true; if (tiposNumericos.includes(tipoVariavel) && tiposNumericos.includes(tipoValor)) return true; if (tiposLogicos.includes(tipoVariavel) && tiposLogicos.includes(tipoValor)) return true; return false; } converterValor(tipo, valor) { switch (tipo) { case 'inteiro': return parseInt(valor); case 'longo': // Converte para BigInt if (typeof valor === 'bigint') return valor; if (typeof valor === 'number') return BigInt(Math.floor(valor)); // Para strings, remove parte decimal antes de converter const strValue = String(valor).split('.')[0].trim(); return BigInt(strValue || '0'); case 'logico': case 'lógico': return Boolean(valor); case 'numero': case 'número': // Não converter objetos (ex: instâncias de classe de sobrecarga de operador) // para número, pois resultaria em NaN. if (typeof valor === 'object' && valor !== null) { return valor; } return Number(valor); case 'texto': return String(valor); default: return valor; } } definirConstante(nomeConstante, valor, tipo) { const constante = this.pilha[this.pilha.length - 1].espacoMemoria.valores[nomeConstante]; let tipoConstante; if (constante && constante.hasOwnProperty('tipo')) { tipoConstante = constante.tipo; } else if (tipo) { tipoConstante = tipo; } else { tipoConstante = (0, inferenciador_1.inferirTipoVariavel)(valor); } let elementoAlvo = { valor: this.converterValor(tipo, valor), tipo: tipoConstante, subtipo: undefined, imutavel: true, }; if ([delegua_1.default.VETOR, delegua_1.default.TUPLA].includes(tipoConstante)) { let subtipo = ''; if (valor instanceof Array) { const numeros = valor.some((v) => typeof v === 'number'); const textos = valor.some((v) => typeof v === 'string'); const logicos = valor.some((v) => typeof v === 'boolean'); const tiposDistintos = [numeros, textos, logicos].filter(Boolean).length; if (tiposDistintos > 1) subtipo = delegua_1.default.QUALQUER; else if (numeros) subtipo = delegua_1.default.NUMERO; else if (logicos) subtipo = delegua_1.default.LOGICO; else if (textos) subtipo = delegua_1.default.TEXTO; else subtipo = delegua_1.default.QUALQUER; } elementoAlvo.subtipo = subtipo; } this.pilha[this.pilha.length - 1].espacoMemoria.valores[nomeConstante] = elementoAlvo; } definirVariavel(nomeVariavel, valor, tipo, tipoExplicito) { const variavel = this.pilha[this.pilha.length - 1].espacoMemoria.valores[nomeVariavel]; let tipoVariavel; let subtipo = undefined; if (variavel && variavel.hasOwnProperty('tipo')) { tipoVariavel = variavel.tipo; } else if (valor && valor.constructor === estruturas_1.DeleguaFuncao) { tipoVariavel = 'função'; if (tipo !== undefined) { tipoVariavel = `função<${tipo}>`; subtipo = tipo; } } else if (tipo) { tipoVariavel = tipo; } else { tipoVariavel = (0, inferenciador_1.inferirTipoVariavel)(valor); } let elementoAlvo = { valor: this.converterValor(tipoVariavel, valor), tipo: tipoVariavel, subtipo: subtipo, imutavel: false, tipoExplicito: tipoExplicito || false, }; if ([delegua_1.default.VETOR, delegua_1.default.TUPLA].includes(tipoVariavel)) { let subtipo = ''; if (valor instanceof Array) { const numeros = valor.some((v) => typeof v === 'number'); const textos = valor.some((v) => typeof v === 'string'); const logicos = valor.some((v) => typeof v === 'boolean'); const tiposDistintos = [numeros, textos, logicos].filter(Boolean).length; if (tiposDistintos > 1) subtipo = delegua_1.default.QUALQUER; else if (numeros) subtipo = delegua_1.default.NUMERO; else if (logicos) subtipo = delegua_1.default.LOGICO; else if (textos) subtipo = delegua_1.default.TEXTO; else subtipo = delegua_1.default.QUALQUER; } elementoAlvo.subtipo = subtipo; } this.pilha[this.pilha.length - 1].espacoMemoria.valores[nomeVariavel] = elementoAlvo; } atribuirVariavelEm(distancia, simbolo, valor) { const espacoMemoriaAncestral = this.pilha[this.pilha.length - distancia].espacoMemoria; const variavel = espacoMemoriaAncestral.valores[simbolo.lexema]; if (variavel.imutavel) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Constante '${simbolo.lexema}' não pode receber novos valores.`); } if (variavel.tipoExplicito && variavel.tipo !== 'qualquer') { const tipoDoValor = (0, inferenciador_1.inferirTipoVariavel)(valor); if (!this.tiposCompativeis(variavel.tipo, tipoDoValor)) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Variável '${simbolo.lexema}' é do tipo '${variavel.tipo}' e não pode receber um valor do tipo '${tipoDoValor}'.`); } } espacoMemoriaAncestral.valores[simbolo.lexema] = { valor, tipo: variavel.tipo === 'nulo' && !variavel.tipoExplicito ? (0, inferenciador_1.inferirTipoVariavel)(valor) : variavel.tipo || (0, inferenciador_1.inferirTipoVariavel)(valor), imutavel: false, tipoExplicito: variavel.tipoExplicito, }; } atribuirVariavel(simbolo, valor, indice) { for (let i = 1; i <= this.pilha.length; i++) { const espacoMemoria = this.pilha[this.pilha.length - i].espacoMemoria; if (espacoMemoria.valores[simbolo.lexema] !== undefined) { const variavel = espacoMemoria.valores[simbolo.lexema]; if (variavel.imutavel) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Constante '${simbolo.lexema}' não pode receber novos valores.`); } if (variavel.tipoExplicito && variavel.tipo !== 'qualquer') { const tipoDoValor = (0, inferenciador_1.inferirTipoVariavel)(valor); if (!this.tiposCompativeis(variavel.tipo, tipoDoValor)) { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Variável '${simbolo.lexema}' é do tipo '${variavel.tipo}' e não pode receber um valor do tipo '${tipoDoValor}'.`); } } const tipoAtual = variavel && variavel.hasOwnProperty('tipo') ? variavel.tipo : null; const deveLiberarTipo = tipoAtual === 'nulo' && !variavel.tipoExplicito; const tipoInferido = tipoAtual && !deveLiberarTipo ? tipoAtual : (0, inferenciador_1.inferirTipoVariavel)(valor); const tipo = (tipoInferido || 'objeto').toLowerCase(); const valorResolvido = this.converterValor(tipo, valor); if (indice !== undefined && indice !== null) { let variavelValor = variavel.valor; if (variavelValor instanceof Array || variavelValor instanceof Object) { variavelValor[indice] = valorResolvido; } else { throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, 'Variável não é um vetor ou dicionário.'); } } else { espacoMemoria.valores[simbolo.lexema] = { valor: valorResolvido, tipo, imutavel: false, tipoExplicito: variavel.tipoExplicito, }; } return; } } throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, "Variável não definida '" + simbolo.lexema + "'."); } obterEscopoPorTipo(tipo) { for (let i = 1; i <= this.pilha.length; i++) { const escopoAtual = this.pilha[this.pilha.length - i]; if (escopoAtual.tipo === tipo) { return escopoAtual; } } return undefined; } obterVariavelEm(distancia, nome) { const ambienteAncestral = this.pilha[this.pilha.length - distancia].espacoMemoria; return ambienteAncestral.valores[nome]; } obterValorVariavel(simbolo) { for (let i = 1; i <= this.pilha.length; i++) { const ambiente = this.pilha[this.pilha.length - i].espacoMemoria; if (ambiente.valores[simbolo.lexema] !== undefined) { return ambiente.valores[simbolo.lexema]; } } throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, "Variável não definida: '" + simbolo.lexema + "'."); } obterVariavelPorNome(nome) { for (let i = 1; i <= this.pilha.length; i++) { const ambiente = this.pilha[this.pilha.length - i].espacoMemoria; if (ambiente.valores[nome] !== undefined) { return ambiente.valores[nome]; } } throw new excecoes_1.ErroEmTempoDeExecucao(new lexador_1.Simbolo('especial', nome, nome, -1, -1), "Variável não definida: '" + nome + "'."); } /** * Método usado pelo depurador para obter todas as variáveis definidas. */ obterTodasVariaveis(todasVariaveis = []) { for (let i = 1; i <= this.pilha.length - 1; i++) { const valoresEspacoMemoria = this.pilha[this.pilha.length - i].espacoMemoria.valores; const vetorObjeto = Object.entries(valoresEspacoMemoria).map((chaveEValor, indice) => ({ nome: chaveEValor[0], valor: chaveEValor[1].valor, tipo: chaveEValor[1].tipo, imutavel: chaveEValor[1].imutavel, })); todasVariaveis = todasVariaveis.concat(vetorObjeto); } return todasVariaveis; } /** * Obtém todas as funções declaradas ou por código-fonte, ou pelo desenvolvedor * em console, do último escopo. */ obterTodasDeleguaFuncao() { const retorno = {}; const espacoMemoria = this.pilha[this.pilha.length - 1].espacoMemoria; for (const [nome, corpo] of Object.entries(espacoMemoria.valores)) { const corpoValor = corpo.hasOwnProperty('valor') ? corpo.valor : corpo; if (corpoValor instanceof estruturas_1.DeleguaFuncao) { retorno[nome] = corpoValor; } } return retorno; } /** * Obtém todas as declarações de classe do último escopo. * @returns */ obterTodasDeclaracoesClasse() { const retorno = {}; const ambiente = this.pilha[this.pilha.length - 1].espacoMemoria; for (const [nome, corpo] of Object.entries(ambiente.valores)) { const corpoValor = corpo.hasOwnProperty('valor') ? corpo.valor : corpo; if (corpoValor instanceof estruturas_1.DescritorTipoClasse) { retorno[nome] = corpoValor; } } return retorno; } registrarReferenciaFuncao(idFuncao, funcao) { const espacoMemoriaAtual = this.pilha[this.pilha.length - 1].espacoMemoria; espacoMemoriaAtual.referenciasFuncoes[idFuncao] = funcao; } obterReferenciaFuncao(idFuncao) { for (let i = 1; i <= this.pilha.length; i++) { const espacoMemoria = this.pilha[this.pilha.length - i].espacoMemoria; if (espacoMemoria.referenciasFuncoes[idFuncao] !== undefined) { return espacoMemoria.referenciasFuncoes[idFuncao]; } } throw new excecoes_1.ErroEmTempoDeExecucao(new lexador_1.Simbolo('especial', idFuncao, idFuncao, -1, -1), "Referência para função não encontrada: '" + idFuncao + "'."); } registrarReferenciaMontao(endereco) { const espacoMemoria = this.pilha[this.pilha.length - 1].espacoMemoria; espacoMemoria.enderecosMontao.add(endereco); } migrarReferenciaMontaoParaEscopoDeVariavel(nomeVariavel, enderecoMontao) { // TODO: Normalmente uma referência a ser migrada está sempre no último escopo. // Conferir se é sempre este o caso. const ultimoEspacoMemoria = this.pilha[this.pilha.length - 1].espacoMemoria; ultimoEspacoMemoria.enderecosMontao.delete(enderecoMontao); for (let i = 1; i <= this.pilha.length; i++) { const espacoMemoria = this.pilha[this.pilha.length - i].espacoMemoria; if (espacoMemoria.valores[nomeVariavel] !== undefined) { espacoMemoria.enderecosMontao.add(enderecoMontao); break; } } // TODO: Devemos emitir erro em algum momento? } } exports.PilhaEscoposExecucao = PilhaEscoposExecucao; //# sourceMappingURL=pilha-escopos-execucao.js.map