@designliquido/delegua
Version:
Linguagem de programação simples e moderna usando português estruturado.
263 lines • 10.7 kB
JavaScript
"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"));
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();
}
converterValor(tipo, valor) {
switch (tipo) {
case 'inteiro':
return parseInt(valor);
case 'logico':
case 'lógico':
return Boolean(valor);
case 'numero':
case 'número':
return Number(valor);
case 'texto':
return String(valor);
default:
return valor;
}
}
definirConstante(nomeConstante, valor, tipo) {
const constante = this.pilha[this.pilha.length - 1].ambiente.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) {
// TODO: verificar tipo lógico e outros possíveis subtipos
let numeros = valor.some((v) => typeof v === 'number');
let textos = valor.some((v) => typeof v === 'string');
if (numeros && textos)
subtipo = delegua_1.default.QUALQUER;
else if (numeros)
subtipo = delegua_1.default.NUMERO;
else
subtipo = delegua_1.default.TEXTO;
}
elementoAlvo.subtipo = subtipo;
}
this.pilha[this.pilha.length - 1].ambiente.valores[nomeConstante] = elementoAlvo;
}
definirVariavel(nomeVariavel, valor, tipo) {
const variavel = this.pilha[this.pilha.length - 1].ambiente.valores[nomeVariavel];
let tipoVariavel;
if (variavel && variavel.hasOwnProperty('tipo')) {
tipoVariavel = variavel.tipo;
}
else if (valor && valor.constructor.name === 'DeleguaFuncao') {
tipoVariavel = 'função';
}
else if (tipo) {
tipoVariavel = tipo;
}
else {
tipoVariavel = (0, inferenciador_1.inferirTipoVariavel)(valor);
}
let elementoAlvo = {
valor: this.converterValor(tipo, valor),
tipo: tipoVariavel,
subtipo: undefined,
imutavel: false,
};
if ([delegua_1.default.VETOR, delegua_1.default.TUPLA].includes(tipoVariavel)) {
let subtipo = '';
if (valor instanceof Array) {
// TODO: verificar tipo lógico e outros possíveis subtipos
let numeros = valor.some((v) => typeof v === 'number');
let textos = valor.some((v) => typeof v === 'string');
if (numeros && textos)
subtipo = delegua_1.default.QUALQUER;
else if (numeros)
subtipo = delegua_1.default.NUMERO;
else
subtipo = delegua_1.default.TEXTO;
}
elementoAlvo.subtipo = subtipo;
}
this.pilha[this.pilha.length - 1].ambiente.valores[nomeVariavel] = elementoAlvo;
}
atribuirVariavelEm(distancia, simbolo, valor) {
const ambienteAncestral = this.pilha[this.pilha.length - distancia].ambiente;
if (ambienteAncestral.valores[simbolo.lexema].imutavel) {
throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Constante '${simbolo.lexema}' não pode receber novos valores.`);
}
ambienteAncestral.valores[simbolo.lexema] = {
valor,
tipo: (0, inferenciador_1.inferirTipoVariavel)(valor),
imutavel: false,
};
}
atribuirVariavel(simbolo, valor, indice) {
for (let i = 1; i <= this.pilha.length; i++) {
const ambiente = this.pilha[this.pilha.length - i].ambiente;
if (ambiente.valores[simbolo.lexema] !== undefined) {
const variavel = ambiente.valores[simbolo.lexema];
if (variavel.imutavel) {
throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Constante '${simbolo.lexema}' não pode receber novos valores.`);
}
const tipoInferido = variavel && variavel.hasOwnProperty('tipo') && variavel.tipo
? variavel.tipo
: (0, inferenciador_1.inferirTipoVariavel)(valor);
const tipo = tipoInferido.toLowerCase();
const valorResolvido = this.converterValor(tipo, valor);
if (indice !== undefined && indice !== null) {
if (variavel.valor instanceof Array || variavel.valor instanceof Object) {
variavel.valor[indice] = valorResolvido;
}
else {
throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, 'Variável não é um vetor ou dicionário.');
}
}
else {
ambiente.valores[simbolo.lexema] = {
valor: valorResolvido,
tipo,
imutavel: false,
};
}
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].ambiente;
return ambienteAncestral.valores[nome];
}
obterValorVariavel(simbolo) {
for (let i = 1; i <= this.pilha.length; i++) {
const ambiente = this.pilha[this.pilha.length - i].ambiente;
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].ambiente;
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 valoresAmbiente = this.pilha[this.pilha.length - i].ambiente.valores;
const vetorObjeto = Object.entries(valoresAmbiente).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 ambiente = this.pilha[this.pilha.length - 1].ambiente;
for (const [nome, corpo] of Object.entries(ambiente.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].ambiente;
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 ambiente = this.pilha[this.pilha.length - 1].ambiente;
ambiente.referencias[idFuncao] = funcao;
}
obterReferenciaFuncao(idFuncao) {
for (let i = 1; i <= this.pilha.length; i++) {
const ambiente = this.pilha[this.pilha.length - i].ambiente;
if (ambiente.referencias[idFuncao] !== undefined) {
return ambiente.referencias[idFuncao];
}
}
throw new excecoes_1.ErroEmTempoDeExecucao(new lexador_1.Simbolo('especial', idFuncao, idFuncao, -1, -1), "Referência para função não encontrada: '" + idFuncao + "'.");
}
}
exports.PilhaEscoposExecucao = PilhaEscoposExecucao;
//# sourceMappingURL=pilha-escopos-execucao.js.map