Skip to content

Commit 6fedaa1

Browse files
Melhoramentos na impressão de variáveis e ações do modo LAIR.
1 parent 74d1c09 commit 6fedaa1

6 files changed

Lines changed: 299 additions & 16 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,5 @@ dist
104104
.tern-port
105105

106106
# Claude
107+
.claude/
107108
CLAUDE.md

fontes/interpretador/comum.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,8 @@ export async function visitarDeclaracaoConst(
4242
);
4343
}
4444

45-
return {
46-
tipo: declaracao.tipo,
47-
tipoExplicito: declaracao.tipoExplicito,
48-
};
45+
// Retorna o valor da constante para o modo LAIR
46+
return interpretador.pilhaEscoposExecucao.obterValorVariavel(declaracao.simbolo);
4947
}
5048

5149
export async function visitarDeclaracaoDefinicaoFuncao(

fontes/interpretador/interpretador-com-importacao.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Const, Declaracao, FuncaoDeclaracao } from '@designliquido/delegua/declaracoes';
1+
import { Const, Declaracao, FuncaoDeclaracao, Var } from '@designliquido/delegua/declaracoes';
22
import { SimboloInterface } from '@designliquido/delegua/interfaces';
33
import { Interpretador } from '@designliquido/delegua/interpretador';
44
import { AcessoMetodoOuPropriedade } from '@designliquido/delegua/construtos';
@@ -50,6 +50,14 @@ export class InterpretadorComImportacao
5050
return comum.visitarConstrutoImportarBiblioteca(this, importarBiblioteca);
5151
}
5252

53+
override async visitarDeclaracaoVar(declaracao: Var): Promise<any> {
54+
// Chama o método da classe base para fazer a declaração
55+
await super.visitarDeclaracaoVar(declaracao);
56+
57+
// Retorna o valor da variável para o modo LAIR
58+
return this.pilhaEscoposExecucao.obterValorVariavel(declaracao.simbolo);
59+
}
60+
5361
override visitarDeclaracaoConst(declaracao: Const): Promise<any> {
5462
return comum.visitarDeclaracaoConst(this, declaracao);
5563
}

fontes/maquinas-estados-lair/maquina-estados-lair-delegua.ts

Lines changed: 128 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1+
import chalk from "chalk";
12
import { colorize } from "json-colorizer";
2-
import { RetornoExecucaoInterface } from "@designliquido/delegua";
3+
import { Const, RetornoExecucaoInterface, Var } from "@designliquido/delegua";
34

45
import { FormatadorJson } from "../formatadores";
56
import { LexadorJson } from "../lexador/lexador-json";
67
import { MaquinaEstadosLairBase } from "./maquina-estados-lair-base";
78

89
export class MaquinaEstadosLairDelegua extends MaquinaEstadosLairBase {
9-
lexadorJson: LexadorJson;
10-
formatadorJson: FormatadorJson;
11-
linhas: string[];
1210
escoposAbertos: number;
1311

1412
constructor(
@@ -19,6 +17,85 @@ export class MaquinaEstadosLairDelegua extends MaquinaEstadosLairBase {
1917
this.escoposAbertos = 0;
2018
}
2119

20+
/**
21+
* Verifica se um valor é um tipo simples (número, texto, lógico, nulo)
22+
*/
23+
private ehTipoSimples(valorRetornado: any): boolean {
24+
if (!valorRetornado) return false;
25+
26+
const tipo = valorRetornado.tipo;
27+
const valorReal = valorRetornado.valor;
28+
29+
// Tipos simples: número, texto, lógico, nulo
30+
if (tipo === 'número' || tipo === 'texto' || tipo === 'lógico') {
31+
return true;
32+
}
33+
34+
if (valorReal === null || valorReal === undefined) {
35+
return true;
36+
}
37+
38+
return false;
39+
}
40+
41+
/**
42+
* Formata um valor simples para exibição amigável no LAIR
43+
*/
44+
private formatarValorSimples(valorRetornado: any): string {
45+
const tipo = valorRetornado?.tipo || 'desconhecido';
46+
const valorReal = valorRetornado?.valor;
47+
48+
if (tipo === 'texto') {
49+
return chalk.green(`"${valorReal}"`);
50+
}
51+
52+
if (tipo === 'número') {
53+
return chalk.cyan(String(valorReal));
54+
}
55+
56+
if (tipo === 'lógico') {
57+
return chalk.yellow(String(valorReal));
58+
}
59+
60+
if (valorReal === null || valorReal === undefined) {
61+
return chalk.gray('nulo');
62+
}
63+
64+
return String(valorReal);
65+
}
66+
67+
/**
68+
* Detecta se é uma declaração de variável e retorna informações sobre ela
69+
*/
70+
private detectarDeclaracaoVariavel(declaracoes: any[]): {
71+
ehDeclaracao: boolean;
72+
nomeVariavel?: string;
73+
valor?: any;
74+
tipo?: string;
75+
} {
76+
if (!declaracoes || declaracoes.length === 0) {
77+
return { ehDeclaracao: false };
78+
}
79+
80+
const primeiraDeclaracao = declaracoes[0];
81+
82+
// Verifica se é uma declaração Var ou Const
83+
if (primeiraDeclaracao.constructor === Var ||
84+
primeiraDeclaracao.constructor === Const) {
85+
const simbolo = primeiraDeclaracao.simbolo;
86+
const inicializador = primeiraDeclaracao.inicializador;
87+
88+
return {
89+
ehDeclaracao: true,
90+
nomeVariavel: simbolo?.lexema,
91+
valor: inicializador,
92+
tipo: primeiraDeclaracao.constructor === Const ? 'const' : 'var'
93+
};
94+
}
95+
96+
return { ehDeclaracao: false };
97+
}
98+
2299
async executarOuAcumular(linha: string): Promise<any> {
23100
// Algoritmo: detectar chave aberta na linha sem fechamento.
24101
this.linhas.push(linha);
@@ -36,14 +113,55 @@ export class MaquinaEstadosLairDelegua extends MaquinaEstadosLairBase {
36113
this.interfaceLeitura.prompt();
37114
return;
38115
} else {
39-
const { resultado } = await this.executarLinhas(this.linhas);
40-
if (resultado && resultado.length) {
41-
const resultadoLexacao = this.lexadorJson.getTokens(resultado[0]);
42-
const resultadoFormatacao =
43-
this.formatadorJson.formatar(resultadoLexacao);
44-
this.funcaoDeRetorno(colorize(resultadoFormatacao));
116+
const retornoExecucao: any = await this.executarLinhas(this.linhas);
117+
const { resultado, declaracoes } = retornoExecucao;
118+
119+
// Detecta se é uma declaração de variável
120+
const infoDeclaracao = this.detectarDeclaracaoVariavel(declaracoes);
121+
122+
if (infoDeclaracao.ehDeclaracao && resultado && resultado.length > 0) {
123+
// É uma declaração de variável - mostra mensagem amigável
124+
const primeiroResultado = resultado[0];
125+
const valorRetornado = primeiroResultado?.valorRetornado || primeiroResultado;
126+
const nomeVar = infoDeclaracao.nomeVariavel;
127+
const tipoVar = valorRetornado?.tipo || 'desconhecido';
128+
129+
let valorFormatado: string;
130+
if (this.ehTipoSimples(valorRetornado)) {
131+
valorFormatado = this.formatarValorSimples(valorRetornado);
132+
} else {
133+
// Para objetos/dicionários, mostra apenas "dicionário" ou similar
134+
valorFormatado = chalk.magenta(`{...} (${tipoVar})`);
135+
}
136+
137+
const mensagem = chalk.dim(`(criada variável ${chalk.bold(nomeVar)} com o valor ${valorFormatado})`);
138+
this.funcaoDeRetorno(mensagem);
139+
} else if (resultado && resultado.length > 0) {
140+
// É uma expressão - verifica se é tipo simples ou complexo
141+
const primeiroResultado = resultado[0];
142+
const valorRetornado = primeiroResultado?.valorRetornado || primeiroResultado;
143+
144+
if (this.ehTipoSimples(valorRetornado)) {
145+
// Para tipos simples, mostra de forma amigável
146+
const valorFormatado = this.formatarValorSimples(valorRetornado);
147+
this.funcaoDeRetorno(valorFormatado);
148+
} else {
149+
// Para objetos/dicionários, mostra apenas o valor interno sem metadados
150+
const valorReal = valorRetornado?.valor;
151+
if (valorReal !== undefined && valorReal !== null) {
152+
this.funcaoDeRetorno(colorize(JSON.stringify(valorReal, null, 2)));
153+
} else {
154+
// Padrão para o formato original se não conseguir extrair o valor
155+
const resultadoLexacao = this.lexadorJson.getTokens(primeiroResultado);
156+
const resultadoFormatacao = this.formatadorJson.formatar(resultadoLexacao);
157+
this.funcaoDeRetorno(colorize(resultadoFormatacao));
158+
}
159+
}
45160
}
46161

162+
// Limpa as linhas acumuladas
163+
this.linhas = [];
164+
47165
this.interfaceLeitura.setPrompt("\ndelegua> ");
48166
this.interfaceLeitura.prompt();
49167
}

fontes/nucleo-execucao.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,9 +555,14 @@ export class NucleoExecucao
555555
return { resultado: [] } as RetornoExecucaoInterface;
556556
}
557557

558-
return await this.executar(retornoAvaliadorSintatico.declaracoes,
558+
const retorno = await this.executar(retornoAvaliadorSintatico.declaracoes,
559559
true
560560
);
561+
562+
// Adicionamos as declarações ao retorno para que a máquina de estados LAIR possa usá-las
563+
(retorno as any).declaracoes = retornoAvaliadorSintatico.declaracoes;
564+
565+
return retorno;
561566
}
562567

563568
/**

testes/nucleo-execucao.test.ts

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,4 +348,157 @@ tente {
348348
expect(nucleoExecucao.dialetos['pitugues']).toBe('Pituguês');
349349
});
350350
});
351+
352+
describe('Modo LAIR - Declaração de variáveis', () => {
353+
it('Deve retornar valor ao declarar variável numérica', async () => {
354+
const nucleoExecucao = new NucleoExecucao('0.1');
355+
nucleoExecucao.configurarDialeto();
356+
357+
const resultado = await nucleoExecucao.executarLinhas(['var a = 1']);
358+
359+
expect(resultado.resultado).toBeDefined();
360+
expect(resultado.resultado.length).toBeGreaterThan(0);
361+
const valorResultado = resultado.resultado[0] as any;
362+
expect(valorResultado).toHaveProperty('valorRetornado');
363+
expect(valorResultado.valorRetornado).toHaveProperty('valor', 1);
364+
expect(valorResultado.valorRetornado).toHaveProperty('tipo', 'número');
365+
});
366+
367+
it('Deve retornar valor ao declarar variável textual', async () => {
368+
const nucleoExecucao = new NucleoExecucao('0.1');
369+
nucleoExecucao.configurarDialeto();
370+
371+
const resultado = await nucleoExecucao.executarLinhas(['var nome = "João"']);
372+
373+
expect(resultado.resultado).toBeDefined();
374+
expect(resultado.resultado.length).toBeGreaterThan(0);
375+
const valorResultado = resultado.resultado[0] as any;
376+
expect(valorResultado).toHaveProperty('valorRetornado');
377+
expect(valorResultado.valorRetornado).toHaveProperty('valor', 'João');
378+
expect(valorResultado.valorRetornado).toHaveProperty('tipo', 'texto');
379+
});
380+
381+
it('Deve retornar valor ao declarar variável lógica', async () => {
382+
const nucleoExecucao = new NucleoExecucao('0.1');
383+
nucleoExecucao.configurarDialeto();
384+
385+
const resultado = await nucleoExecucao.executarLinhas(['var ativo = verdadeiro']);
386+
387+
expect(resultado.resultado).toBeDefined();
388+
expect(resultado.resultado.length).toBeGreaterThan(0);
389+
const valorResultado = resultado.resultado[0] as any;
390+
expect(valorResultado).toHaveProperty('valorRetornado');
391+
expect(valorResultado.valorRetornado).toHaveProperty('valor', true);
392+
expect(valorResultado.valorRetornado).toHaveProperty('tipo', 'lógico');
393+
});
394+
395+
it('Deve retornar valor ao declarar variável com dicionário', async () => {
396+
const nucleoExecucao = new NucleoExecucao('0.1');
397+
nucleoExecucao.configurarDialeto();
398+
399+
const resultado = await nucleoExecucao.executarLinhas(['var dados = {"nome": "João", "idade": 30}']);
400+
401+
expect(resultado.resultado).toBeDefined();
402+
expect(resultado.resultado.length).toBeGreaterThan(0);
403+
const valorResultado = resultado.resultado[0] as any;
404+
expect(valorResultado).toHaveProperty('valorRetornado');
405+
expect(valorResultado.valorRetornado).toHaveProperty('valor');
406+
expect(valorResultado.valorRetornado.valor).toHaveProperty('nome', 'João');
407+
expect(valorResultado.valorRetornado.valor).toHaveProperty('idade', 30);
408+
expect(valorResultado.valorRetornado).toHaveProperty('tipo', 'dicionário');
409+
});
410+
411+
it('Deve retornar valor ao declarar constante numérica', async () => {
412+
const nucleoExecucao = new NucleoExecucao('0.1');
413+
nucleoExecucao.configurarDialeto();
414+
415+
const resultado = await nucleoExecucao.executarLinhas(['const PI = 3.14']);
416+
417+
expect(resultado.resultado).toBeDefined();
418+
expect(resultado.resultado.length).toBeGreaterThan(0);
419+
const valorResultado = resultado.resultado[0] as any;
420+
expect(valorResultado).toHaveProperty('valorRetornado');
421+
expect(valorResultado.valorRetornado).toHaveProperty('valor', 3.14);
422+
expect(valorResultado.valorRetornado).toHaveProperty('tipo', 'número');
423+
});
424+
});
425+
426+
describe('Modo LAIR - Inspeção de variáveis', () => {
427+
it('Deve retornar estrutura completa ao inspecionar variável numérica', async () => {
428+
const nucleoExecucao = new NucleoExecucao('0.1');
429+
nucleoExecucao.configurarDialeto();
430+
// Ativa modo LAIR para manter contexto entre chamadas
431+
(nucleoExecucao.avaliadorSintatico as any).modoLair = true;
432+
433+
await nucleoExecucao.executarLinhas(['var a = 42']);
434+
const resultado = await nucleoExecucao.executarLinhas(['a']);
435+
436+
expect(resultado.resultado).toBeDefined();
437+
expect(resultado.resultado.length).toBeGreaterThan(0);
438+
expect(resultado.resultado[0]).toHaveProperty('valorRetornado');
439+
expect(resultado.resultado[0].valorRetornado).toHaveProperty('valor', 42);
440+
expect(resultado.resultado[0].valorRetornado).toHaveProperty('tipo', 'número');
441+
});
442+
443+
it('Deve retornar estrutura completa ao inspecionar variável textual', async () => {
444+
const nucleoExecucao = new NucleoExecucao('0.1');
445+
nucleoExecucao.configurarDialeto();
446+
// Ativa modo LAIR para manter contexto entre chamadas
447+
(nucleoExecucao.avaliadorSintatico as any).modoLair = true;
448+
449+
await nucleoExecucao.executarLinhas(['var mensagem = "Olá mundo"']);
450+
const resultado = await nucleoExecucao.executarLinhas(['mensagem']);
451+
452+
expect(resultado.resultado).toBeDefined();
453+
expect(resultado.resultado.length).toBeGreaterThan(0);
454+
expect(resultado.resultado[0]).toHaveProperty('valorRetornado');
455+
expect(resultado.resultado[0].valorRetornado).toHaveProperty('valor', 'Olá mundo');
456+
expect(resultado.resultado[0].valorRetornado).toHaveProperty('tipo', 'texto');
457+
});
458+
459+
it('Deve retornar estrutura completa ao inspecionar variável lógica', async () => {
460+
const nucleoExecucao = new NucleoExecucao('0.1');
461+
nucleoExecucao.configurarDialeto();
462+
// Ativa modo LAIR para manter contexto entre chamadas
463+
(nucleoExecucao.avaliadorSintatico as any).modoLair = true;
464+
465+
await nucleoExecucao.executarLinhas(['var ativo = falso']);
466+
const resultado = await nucleoExecucao.executarLinhas(['ativo']);
467+
468+
expect(resultado.resultado).toBeDefined();
469+
expect(resultado.resultado.length).toBeGreaterThan(0);
470+
expect(resultado.resultado[0]).toHaveProperty('valorRetornado');
471+
expect(resultado.resultado[0].valorRetornado).toHaveProperty('valor', false);
472+
expect(resultado.resultado[0].valorRetornado).toHaveProperty('tipo', 'lógico');
473+
});
474+
475+
it('Deve retornar estrutura completa ao inspecionar dicionário', async () => {
476+
const nucleoExecucao = new NucleoExecucao('0.1');
477+
nucleoExecucao.configurarDialeto();
478+
// Ativa modo LAIR para manter contexto entre chamadas
479+
(nucleoExecucao.avaliadorSintatico as any).modoLair = true;
480+
481+
await nucleoExecucao.executarLinhas(['var pessoa = {"nome": "Maria", "idade": 25}']);
482+
const resultado = await nucleoExecucao.executarLinhas(['pessoa']);
483+
484+
expect(resultado.resultado).toBeDefined();
485+
expect(resultado.resultado.length).toBeGreaterThan(0);
486+
expect(resultado.resultado[0]).toHaveProperty('valorRetornado');
487+
expect(resultado.resultado[0].valorRetornado).toHaveProperty('valor');
488+
expect(resultado.resultado[0].valorRetornado.valor).toHaveProperty('nome', 'Maria');
489+
expect(resultado.resultado[0].valorRetornado.valor).toHaveProperty('idade', 25);
490+
expect(resultado.resultado[0].valorRetornado).toHaveProperty('tipo', 'dicionário');
491+
});
492+
493+
it('Deve retornar declarações junto com resultado', async () => {
494+
const nucleoExecucao = new NucleoExecucao('0.1');
495+
nucleoExecucao.configurarDialeto();
496+
497+
const resultado: any = await nucleoExecucao.executarLinhas(['var x = 10']);
498+
499+
expect(resultado).toHaveProperty('declaracoes');
500+
expect(resultado.declaracoes).toBeDefined();
501+
expect(resultado.declaracoes.length).toBeGreaterThan(0);
502+
});
503+
});
351504
});

0 commit comments

Comments
 (0)