@designliquido/delegua
Version:
Linguagem de programação simples e moderna usando português estruturado.
96 lines • 4.65 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PilhaEscoposExecucaoPitugues = void 0;
const excecoes_1 = require("../../../excecoes");
const inferenciador_1 = require("../../../inferenciador");
const pilha_escopos_execucao_1 = require("../../pilha-escopos-execucao");
/**
* Pilha de escopos de execução específica para Pituguês.
*
* Diferentemente de Delégua, Pituguês segue a regra de escopo local-first do
* Python para atribuições dentro de funções:
*
* - Fora de uma função (escopo global, laços no nível global): o comportamento
* é o padrão — a pilha é percorrida para encontrar a variável e atualizá-la,
* ou ela é criada no escopo atual caso ainda não exista.
*
* - Dentro de uma função: a atribuição é sempre resolvida dentro da cadeia de
* escopos da própria função (do topo da pilha até o escopo de tipo 'funcao'
* inclusive), sem cruzar a fronteira para escopos ancestrais (globais). Se a
* variável não for encontrada nessa cadeia, ela é criada no escopo da função
* (não no escopo de laço interno, refletindo o comportamento do Python onde
* `if`/`while`/`for` não criam namespaces próprios).
*
* Leituras continuam percorrendo toda a pilha normalmente.
*/
class PilhaEscoposExecucaoPitugues extends pilha_escopos_execucao_1.PilhaEscoposExecucao {
/**
* Retorna o índice do escopo de função mais recente na pilha, ou -1 se não
* houver nenhum (estamos no nível global).
*/
indiceFuncaoAtual() {
for (let i = this.pilha.length - 1; i >= 0; i--) {
if (this.pilha[i].tipo === 'funcao') {
return i;
}
}
return -1;
}
/**
* Atribui um valor a uma variável seguindo a semântica de escopo do Pituguês.
*
* Casos:
* 1. Atribuição indexada (`x[i] = v`) → comportamento padrão (percorre a pilha).
* 2. Fora de função → comportamento padrão com criação implícita se necessário.
* 3. Dentro de função:
* a. Variável encontrada na cadeia de escopos da função → atualiza lá.
* b. Variável não encontrada (só existe no escopo global, ou é nova) →
* cria no escopo da função (não no escopo de laço interno).
*/
atribuirVariavel(simbolo, valor, indice) {
// Caso 1 — atribuição indexada: modifica conteúdo do objeto, não a ligação.
if (indice !== undefined && indice !== null) {
return super.atribuirVariavel(simbolo, valor, indice);
}
const funcaoIndex = this.indiceFuncaoAtual();
// Caso 2 — fora de qualquer função (nível global ou laço global).
if (funcaoIndex === -1) {
for (let i = this.pilha.length - 1; i >= 0; i--) {
if (this.pilha[i].espacoMemoria.valores[simbolo.lexema] !== undefined) {
return super.atribuirVariavel(simbolo, valor);
}
}
// Variável ainda não existe: criação implícita no escopo atual.
this.definirVariavel(simbolo.lexema, valor);
return;
}
// Caso 3 — dentro de uma função.
// Percorre apenas os escopos dentro da função (do topo até funcaoIndex).
for (let i = this.pilha.length - 1; i >= funcaoIndex; i--) {
const espaco = this.pilha[i].espacoMemoria;
if (espaco.valores[simbolo.lexema] !== undefined) {
const variavel = espaco.valores[simbolo.lexema];
if (variavel.imutavel) {
throw new excecoes_1.ErroEmTempoDeExecucao(simbolo, `Constante '${simbolo.lexema}' não pode receber novos valores.`);
}
espaco.valores[simbolo.lexema] = {
valor,
tipo: variavel.tipo || (0, inferenciador_1.inferirTipoVariavel)(valor),
imutavel: false,
tipoExplicito: variavel.tipoExplicito,
};
return;
}
}
// Variável não encontrada na cadeia da função (existe só no global ou é nova).
// Cria no escopo da função (índice funcaoIndex), não no escopo de laço interno.
this.pilha[funcaoIndex].espacoMemoria.valores[simbolo.lexema] = {
valor,
tipo: (0, inferenciador_1.inferirTipoVariavel)(valor),
imutavel: false,
tipoExplicito: false,
};
}
}
exports.PilhaEscoposExecucaoPitugues = PilhaEscoposExecucaoPitugues;
//# sourceMappingURL=pilha-escopos-execucao-pitugues.js.map