@designliquido/delegua
Version:
Linguagem de programação simples e moderna usando português estruturado.
257 lines • 12.5 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.InterpretadorPitugues = void 0;
const construtos_1 = require("../../../construtos");
const interpretador_1 = require("../../interpretador");
const excecoes_1 = require("../../../excecoes");
const comum = __importStar(require("./comum"));
const inferenciador_1 = require("../../../inferenciador");
const quebras_1 = require("../../../quebras");
const pilha_escopos_execucao_pitugues_1 = require("./pilha-escopos-execucao-pitugues");
class InterpretadorPitugues extends interpretador_1.Interpretador {
constructor(diretorioBase, performance = false, funcaoDeRetorno = null, funcaoDeRetornoMesmaLinha = null) {
super(diretorioBase, performance, funcaoDeRetorno, funcaoDeRetornoMesmaLinha);
// Substituir a pilha compartilhada de Delégua pela implementação específica
// de Pituguês, que aplica a semântica de escopo local-first (estilo Python).
const pilhaPitugues = new pilha_escopos_execucao_pitugues_1.PilhaEscoposExecucaoPitugues();
for (const escopo of this.pilhaEscoposExecucao.pilha) {
pilhaPitugues.empilhar(escopo);
}
this.pilhaEscoposExecucao = pilhaPitugues;
this.lancarErroPorDivisaoPorZero = true;
}
/**
* Sobrescreve `executarBloco` para marcar escopos de chamadas de função com
* `tipo: 'funcao'`. Quando `ambiente` é fornecido, a chamada vem de
* `DeleguaFuncao.chamar`, que repassa o espaço de memória dos parâmetros.
* Isso permite que `PilhaEscoposExecucaoPitugues` identifique fronteiras de
* função e aplique a semântica LEGB corretamente.
*/
async executarBloco(declaracoes, ambiente) {
if (ambiente !== undefined && ambiente !== null) {
const escopoFuncao = {
declaracoes,
declaracaoAtual: 0,
espacoMemoria: ambiente,
finalizado: false,
tipo: 'funcao',
emLacoRepeticao: false,
};
this.pilhaEscoposExecucao.empilhar(escopoFuncao);
const retorno = await this.executarUltimoEscopo();
if (retorno instanceof excecoes_1.ErroEmTempoDeExecucao) {
return Promise.reject(retorno);
}
return retorno;
}
return super.executarBloco(declaracoes, ambiente);
}
async visitarExpressaoAcessoMetodo(expressao) {
return comum.visitarExpressaoAcessoMetodo(this, expressao);
}
async visitarExpressaoAcessoMetodoOuPropriedade(expressao) {
return comum.visitarExpressaoAcessoMetodoOuPropriedade(this, expressao);
}
async visitarExpressaoAcessoPropriedade(expressao) {
return comum.visitarExpressaoAcessoPropriedade(this, expressao);
}
async visitarExpressaoAcessoIntervaloVariavel(expressao) {
return comum.visitarExpressaoAcessoIntervaloVariavel(this, expressao);
}
async visitarExpressaoTuplaN(expressao) {
return comum.visitarExpressaoTuplaN(this, expressao);
}
async visitarExpressaoDeAtribuicao(expressao) {
if (expressao.alvo.constructor === construtos_1.Variavel) {
const alvoVariavel = expressao.alvo;
try {
// Verifica se a variável existe em algum escopo.
// Se não existir, obterValorVariavel lança uma exceção.
this.pilhaEscoposExecucao.obterValorVariavel(alvoVariavel.simbolo);
}
catch (e) {
// Variável completamente nova: declaração implícita no escopo atual.
let valor = await this.avaliar(expressao.valor);
if (valor && valor.hasOwnProperty('valorRetornado')) {
valor = valor.valorRetornado;
}
const valorResolvido = this.resolverValor(valor);
this.pilhaEscoposExecucao.definirVariavel(alvoVariavel.simbolo.lexema, valorResolvido);
return valorResolvido;
}
}
// Variável já existe em algum escopo. O método atribuirVariavel de
// PilhaEscoposExecucaoPitugues decide onde escrever: se estivermos dentro
// de uma função e a variável só existir no escopo global, ela é criada
// localmente na função (semântica LEGB do Python).
return super.visitarExpressaoDeAtribuicao(expressao);
}
async visitarExpressaoAtribuicaoPorIndice(expressao) {
const objeto = await this.avaliar(expressao.objeto);
const objetoResolvido = this.resolverValor(objeto);
if (objetoResolvido instanceof construtos_1.TuplaN || objetoResolvido.tipo === 'tupla') {
throw new excecoes_1.ErroEmTempoDeExecucao(expressao.objeto.simbolo, 'Não é possível modificar uma tupla. As tuplas são estruturas de dados imutáveis.', expressao.linha);
}
return super.visitarExpressaoAtribuicaoPorIndice(expressao);
}
async visitarExpressaoAcessoIndiceVariavel(expressao) {
const objeto = await this.avaliar(expressao.entidadeChamada);
const indice = await this.avaliar(expressao.indice);
let valorIndice = this.resolverValor(indice);
const objetoResolvido = this.resolverValor(objeto);
if (objetoResolvido instanceof construtos_1.TuplaN) {
if (!Number.isInteger(valorIndice)) {
throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloFechamento, 'Índice deve ser inteiro.', expressao.linha);
}
if (valorIndice < 0 && objetoResolvido.elementos.length !== 0) {
valorIndice += objetoResolvido.elementos.length;
}
if (valorIndice < 0 || valorIndice >= objetoResolvido.elementos.length) {
throw new excecoes_1.ErroEmTempoDeExecucao(expressao.simboloFechamento, 'Índice fora do intervalo.', expressao.linha);
}
const elemento = objetoResolvido.elementos[valorIndice];
if (elemento instanceof construtos_1.Literal)
return elemento.valor;
return this.avaliar(elemento);
}
return super.visitarExpressaoAcessoIndiceVariavel(expressao);
}
async visitarExpressaoTipoDe(expressao) {
const resultado = await super.visitarExpressaoTipoDe(expressao);
if (typeof resultado === 'string')
return resultado.replace('tipo de', 'tipo');
return resultado;
}
/**
* Normaliza o valor resolvido para um array iterável.
* Converte dicionários em listas de Duplas e strings em listas de caracteres.
*/
prepararListaParaIteracao(valor, declaracao) {
let valorFinal = this.resolverValor(valor);
const ehDicionario = declaracao.vetorOuDicionario.tipo === 'dicionário';
const ehObjetoPuro = valorFinal && typeof valorFinal === 'object' && !Array.isArray(valorFinal);
if (ehDicionario || ehObjetoPuro) {
return Object.entries(valorFinal).map(([chave, valor]) => new construtos_1.Dupla(new construtos_1.Literal(declaracao.hashArquivo, declaracao.linha, chave, 'texto'), new construtos_1.Literal(declaracao.hashArquivo, declaracao.linha, valor, (0, inferenciador_1.inferirTipoVariavel)(valor))));
}
if (typeof valorFinal === 'string')
return valorFinal.split('');
if (!Array.isArray(valorFinal)) {
throw new Error("O objeto provido para 'para cada' não é iterável.");
}
return valorFinal;
}
/**
* Resolve a lógica de atribuição das variáveis no escopo.
* Suporta variáveis simples ou pares (Dupla).
*/
definirVariaveisIteracao(variavel, elemento) {
if (variavel instanceof construtos_1.Variavel) {
this.pilhaEscoposExecucao.definirVariavel(variavel.simbolo.lexema, this.resolverValor(elemento));
return;
}
if (variavel instanceof construtos_1.Dupla) {
const var1 = variavel.primeiro;
const var2 = variavel.segundo;
let v1, v2;
if (elemento instanceof construtos_1.Dupla) {
v1 = this.resolverValor(elemento.primeiro);
v2 = this.resolverValor(elemento.segundo);
}
else {
v1 = elemento[0];
v2 = elemento[1];
}
this.pilhaEscoposExecucao.definirVariavel(var1.simbolo.lexema, v1);
this.pilhaEscoposExecucao.definirVariavel(var2.simbolo.lexema, v2);
}
}
async visitarDeclaracaoParaCada(declaracao) {
let retornoExecucao;
declaracao.posicaoAtual = 0;
const valorResolvido = await this.avaliar(declaracao.vetorOuDicionario);
let listaParaIterar;
try {
listaParaIterar = this.prepararListaParaIteracao(valorResolvido, declaracao);
}
catch (erro) {
this.erros.push({
erroInterno: erro,
linha: declaracao.linha,
hashArquivo: declaracao.hashArquivo,
});
return Promise.reject(erro);
}
while (!(retornoExecucao instanceof quebras_1.Quebra) &&
declaracao.posicaoAtual < listaParaIterar.length) {
try {
const elementoAtual = listaParaIterar[declaracao.posicaoAtual];
this.definirVariaveisIteracao(declaracao.variavelIteracao, elementoAtual);
retornoExecucao = await this.executar(declaracao.corpo);
if (retornoExecucao instanceof quebras_1.SustarQuebra)
return null;
if (retornoExecucao instanceof quebras_1.ContinuarQuebra)
retornoExecucao = null;
declaracao.posicaoAtual++;
}
catch (erro) {
this.erros.push({
erroInterno: erro,
linha: declaracao.linha,
hashArquivo: declaracao.hashArquivo,
});
return Promise.reject(erro);
}
}
return retornoExecucao;
}
async visitarExpressaoRetornar(declaracao) {
var _a, _b, _c;
let valor = null;
if (declaracao.valor !== null && declaracao.valor !== undefined) {
valor = await this.avaliar(declaracao.valor);
}
const retornoQuebra = new quebras_1.RetornoQuebra(valor, declaracao.tipo);
if (retornoQuebra.valor) {
const valorResolvido = this.resolverValor(retornoQuebra.valor);
const construtorRetorno = (_c = (_b = (_a = valorResolvido === null || valorResolvido === void 0 ? void 0 : valorResolvido.constructor) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.replaceAll('_', '')) !== null && _c !== void 0 ? _c : '';
if (['DeleguaFuncao', 'ReferenciaMontao'].includes(construtorRetorno))
retornoQuebra.preservarEscopo = true;
}
return retornoQuebra;
}
}
exports.InterpretadorPitugues = InterpretadorPitugues;
//# sourceMappingURL=interpretador-pitugues.js.map