Repository: DesignLiquido/delegua (ts)

Issue:
Melhorar a formatação de saída de valores não primitivos dentro de vetores
Se eu coloco valores que são funções ou dicionários dentro de um vetor e tentar fazer log acontece isso:

![image](https://github.com/DesignLiquido/delegua/assets/93893533/fa36a45c-be34-4cdd-884b-75a376fa03d0)


```
funcao retorne() {
    retorna ''
}

const dic = {
    "chave": 10
}

escreva([dic])
escreva([retorne])
```

Pull request description:
Refatoração de funções `paraTexto` e `toString` quanto a estruturas
Resolve #646 

Patch:
diff --git a/fontes/construtos/unario.ts b/fontes/construtos/unario.ts
index cf8a386b..f2a5f373 100644
--- a/fontes/construtos/unario.ts
+++ b/fontes/construtos/unario.ts
@@ -6,7 +6,7 @@ export class Unario<TTipoSimbolo extends string = string> implements Construto {
     hashArquivo: number;
 
     operador: SimboloInterface<TTipoSimbolo>;
-    operando: Construto;
+    operando: any;
     incidenciaOperador: 'ANTES' | 'DEPOIS';
 
     constructor(
diff --git a/fontes/estruturas/chamavel.ts b/fontes/estruturas/chamavel.ts
index 6628c22c..58f4d734 100644
--- a/fontes/estruturas/chamavel.ts
+++ b/fontes/estruturas/chamavel.ts
@@ -1,6 +1,6 @@
 import { ArgumentoInterface } from '../interpretador/argumento-interface';
 
-export class Chamavel {
+export abstract class Chamavel {
     valorAridade: number;
 
     aridade(): number {
diff --git a/fontes/estruturas/classe-padrao.ts b/fontes/estruturas/classe-padrao.ts
index f9f30973..fff93e9a 100644
--- a/fontes/estruturas/classe-padrao.ts
+++ b/fontes/estruturas/classe-padrao.ts
@@ -1,19 +1,32 @@
 import { Chamavel } from './chamavel';
-import { ObjetoPadrao } from './objeto-padrao';
 
 /**
  * Classe de importação de classes de bibliotecas do JavaScript.
  */
 export class ClassePadrao extends Chamavel {
     nome: string;
-    funcaoDeClasse: any;
+    // TypeScript não tem exatamente um tipo de construtor para classe.
+    // O tipo abaixo é o mais próximo que existe desse tipo.
+    funcaoDeClasse: { new(...args: any[]): any; };
 
-    constructor(nome: string, funcaoDeClasse: any) {
+    constructor(nome: string, funcaoDeClasse: { new(...args: any[]): any; }) {
         super();
         this.nome = nome;
         this.funcaoDeClasse = funcaoDeClasse;
     }
 
+    /**
+     * Método utilizado pelo VSCode para inspecionar esta classe em depuração.
+     * @returns {string} A representação da classe como texto.
+     */
+    toString(): string {
+        return `<classe-padrão ${this.nome}>`;
+    }
+
+    /**
+     * Método utilizado por Delégua para representar esta classe quando impressa.
+     * @returns {string} A representação da classe como texto.
+     */
     paraTexto(): string {
         return `<classe-padrão ${this.nome}>`;
     }
@@ -25,7 +38,7 @@ export class ClassePadrao extends Chamavel {
      * @param simbolo
      */
     chamar(argumentos: any[], simbolo: any): any {
-        const novoObjeto: any = new this.funcaoDeClasse();
+        const novoObjeto: any = new this.funcaoDeClasse(argumentos);
         return novoObjeto;
     }
 }
diff --git a/fontes/estruturas/delegua-classe.ts b/fontes/estruturas/delegua-classe.ts
index ddc90fe7..67db8813 100644
--- a/fontes/estruturas/delegua-classe.ts
+++ b/fontes/estruturas/delegua-classe.ts
@@ -61,6 +61,10 @@ export class DeleguaClasse extends Chamavel {
         return undefined;
     }
 
+    /**
+     * Método utilizado por Delégua para representar esta classe quando impressa.
+     * @returns {string} A representação da classe como texto.
+     */
     paraTexto(): string {
         let texto = `<classe ${this.simboloOriginal.lexema}`;
         for (let propriedade of this.propriedades) {
@@ -76,6 +80,10 @@ export class DeleguaClasse extends Chamavel {
         return texto;
     }
 
+    /**
+     * Método utilizado pelo VSCode para inspecionar esta classe em depuração.
+     * @returns {string} A representação da classe como texto.
+     */
     toString(): string {
         return this.paraTexto();
     }
diff --git a/fontes/estruturas/delegua-funcao.ts b/fontes/estruturas/delegua-funcao.ts
index f1ec0e95..4a09f7a9 100644
--- a/fontes/estruturas/delegua-funcao.ts
+++ b/fontes/estruturas/delegua-funcao.ts
@@ -36,6 +36,10 @@ export class DeleguaFuncao extends Chamavel {
         return this.declaracao?.parametros?.length || 0;
     }
 
+    /**
+     * Método utilizado por Delégua para representar esta função quando impressa.
+     * @returns {string} A representação da função como texto.
+     */
     paraTexto(): string {
         if (this.nome === null) return '<função>';
         let resultado = `<função ${this.nome}`;
@@ -47,6 +51,7 @@ export class DeleguaFuncao extends Chamavel {
                 parametro.tipoDado && parametro.tipoDado.tipo ? `: ${parametro.tipoDado.tipo}, ` : ', '
             }`;
         }
+        
         if (this.declaracao.parametros.length > 0) {
             parametros = `argumentos=<${parametros.slice(0, -2)}>`;
         }
@@ -60,13 +65,23 @@ export class DeleguaFuncao extends Chamavel {
         if (parametros) {
             resultado += ` ${parametros}`;
         }
+
         if (retorno) {
             resultado += ` ${retorno}`;
         }
+
         resultado += '>';
         return resultado;
     }
 
+    /**
+     * Método utilizado pelo VSCode para inspecionar esta função em depuração.
+     * @returns {string} A representação da função como texto.
+     */
+    toString(): string {
+        return this.paraTexto();
+    }
+
     async chamar(visitante: VisitanteComumInterface, argumentos: Array<ArgumentoInterface>): Promise<any> {
         const ambiente = new EspacoVariaveis();
         const parametros = this.declaracao.parametros || [];
diff --git a/fontes/estruturas/funcao-padrao.ts b/fontes/estruturas/funcao-padrao.ts
index f2fbb8a9..4c58524f 100644
--- a/fontes/estruturas/funcao-padrao.ts
+++ b/fontes/estruturas/funcao-padrao.ts
@@ -19,7 +19,19 @@ export class FuncaoPadrao extends Chamavel {
         return await this.funcao.apply(this, argumentos);
     }
 
+    /**
+     * Método utilizado por Delégua para inspecionar esta função em depuração.
+     * @returns {string} A representação da função como texto.
+     */
     paraTexto(): string {
         return '<função>';
     }
+
+    /**
+     * Método utilizado pelo VSCode para representar esta função quando impressa.
+     * @returns {string} A representação da classe como texto.
+     */
+    toString(): string {
+        return '<função>';
+    }
 }
diff --git a/fontes/estruturas/metodo-primitiva.ts b/fontes/estruturas/metodo-primitiva.ts
index f334fd1a..e3a3776d 100644
--- a/fontes/estruturas/metodo-primitiva.ts
+++ b/fontes/estruturas/metodo-primitiva.ts
@@ -15,7 +15,7 @@ export class MetodoPrimitiva extends Chamavel {
     primitiva: any;
     metodo: Function;
 
-    constructor(primitiva: any, metodo: Function, requerInterpretador: boolean = false) {
+    constructor(primitiva: any, metodo: Function) {
         super();
         this.primitiva = primitiva;
         this.metodo = metodo;
@@ -25,4 +25,20 @@ export class MetodoPrimitiva extends Chamavel {
     async chamar(interpretador: VisitanteComumInterface, argumentos: any[] = []): Promise<any> {
         return await this.metodo(interpretador, this.primitiva, ...argumentos);
     }
+
+    /**
+     * Método utilizado por Delégua para inspecionar este método em depuração.
+     * @returns {string} A representação do método como texto.
+     */
+    paraTexto(): string {
+        return `<método nome=${this.metodo} primitiva=${this.primitiva}>`;
+    }
+
+    /**
+     * Método utilizado pelo VSCode para representar este método quando impressa.
+     * @returns {string} A representação do método como texto.
+     */
+    toString(): string {
+        return this.paraTexto();
+    }
 }
diff --git a/fontes/estruturas/modulo.ts b/fontes/estruturas/modulo.ts
index 2647c9e7..286621a7 100644
--- a/fontes/estruturas/modulo.ts
+++ b/fontes/estruturas/modulo.ts
@@ -9,7 +9,19 @@ export class DeleguaModulo {
         this.componentes = {};
     }
 
+    /**
+     * Método utilizado por Delégua para inspecionar este módulo em depuração.
+     * @returns {string} A representação da função como texto.
+     */
+    paraTexto(): string {
+        return this.nome ? `<módulo ${this.nome}>` : '<módulo>';
+    }
+
+    /**
+     * Método utilizado pelo VSCode para representar este módulo quando impressa.
+     * @returns {string} A representação do módulo como texto.
+     */
     toString(): string {
-        return this.nome ? `<modulo ${this.nome}>` : '<modulo>';
+        return this.paraTexto();
     }
 }
diff --git a/fontes/estruturas/objeto-delegua-classe.ts b/fontes/estruturas/objeto-delegua-classe.ts
index e50c25a5..b6faabe3 100644
--- a/fontes/estruturas/objeto-delegua-classe.ts
+++ b/fontes/estruturas/objeto-delegua-classe.ts
@@ -47,7 +47,19 @@ export class ObjetoDeleguaClasse {
         this.propriedades[simbolo.lexema] = valor;
     }
 
+    /**
+     * Método utilizado por Delégua para inspecionar este objeto em depuração.
+     * @returns {string} A representação do objeto como texto.
+     */
     paraTexto(): string {
         return '<Objeto ' + this.classe.simboloOriginal.lexema + '>';
     }
+
+    /**
+     * Método utilizado pelo VSCode para representar este objeto quando impresso.
+     * @returns {string} A representação do objeto como texto.
+     */
+    toString(): string {
+        return this.paraTexto();
+    }
 }
diff --git a/fontes/estruturas/objeto-padrao.ts b/fontes/estruturas/objeto-padrao.ts
index 00607066..bf8ca564 100644
--- a/fontes/estruturas/objeto-padrao.ts
+++ b/fontes/estruturas/objeto-padrao.ts
@@ -1,6 +1,6 @@
 /**
  * Um objeto padrão é uma instância de uma Classe Padrão (JavaScript).
- * TODO: Marcado para depreciação na próxima versão.
+ * TODO: Marcado para depreciação em futuras versões.
  */
 export class ObjetoPadrao {
     classePadrao: string;
@@ -9,6 +9,10 @@ export class ObjetoPadrao {
         this.classePadrao = classePadrao;
     }
 
+    /**
+     * Método utilizado por Delégua para inspecionar este objeto em depuração.
+     * @returns {string} A representação do objeto como texto.
+     */
     paraTexto(): string {
         let retornoTexto = `<objeto-padrão da classe ${this.classePadrao}>\n`;
         for (const [nome, valor] of Object.entries(this)) {
@@ -17,4 +21,12 @@ export class ObjetoPadrao {
         retornoTexto += `</objeto-padrão>`;
         return retornoTexto;
     }
+
+    /**
+     * Método utilizado pelo VSCode para representar este objeto quando impresso.
+     * @returns {string} A representação do objeto como texto.
+     */
+    toString(): string {
+        return this.paraTexto();
+    }
 }
diff --git a/fontes/interpretador/interpretador-base.ts b/fontes/interpretador/interpretador-base.ts
index 76b4dc7e..94248aa1 100644
--- a/fontes/interpretador/interpretador-base.ts
+++ b/fontes/interpretador/interpretador-base.ts
@@ -1610,9 +1610,30 @@ export class InterpretadorBase implements InterpretadorInterface {
             return formato.format(objeto);
         }
 
-        if (Array.isArray(objeto)) return objeto;
+        if (Array.isArray(objeto)) {
+            let retornoVetor: string = '[';
+            for (let elemento of objeto) {
+                retornoVetor += `${this.paraTexto(elemento)},`;
+            }
+
+            retornoVetor = retornoVetor.slice(0, -1);
+            retornoVetor += ']';
+            return retornoVetor;
+        }
+
         if (objeto.valor instanceof ObjetoPadrao) return objeto.valor.paraTexto();
         if (objeto instanceof ObjetoDeleguaClasse || objeto instanceof DeleguaFuncao) return objeto.paraTexto();
+        switch (objeto.constructor.name) {
+            case 'Object':
+                if ('tipo' in objeto) {
+                    switch (objeto.tipo) {
+                        case 'dicionário':
+                            return JSON.stringify(objeto.valor);
+                        default:
+                            return objeto.valor.paraTexto();
+                    }
+                }
+        }
         if (typeof objeto === tipoDeDadosPrimitivos.OBJETO) return JSON.stringify(objeto);
 
         return objeto.toString();


Test patch:
diff --git a/testes/interpretador-com-depuracao.test.ts b/testes/interpretador/interpretador-com-depuracao.test.ts
similarity index 93%
rename from testes/interpretador-com-depuracao.test.ts
rename to testes/interpretador/interpretador-com-depuracao.test.ts
index babd97b5..bbc84593 100644
--- a/testes/interpretador-com-depuracao.test.ts
+++ b/testes/interpretador/interpretador-com-depuracao.test.ts
@@ -1,6 +1,6 @@
-import { AvaliadorSintatico } from "../fontes/avaliador-sintatico";
-import { InterpretadorComDepuracao } from "../fontes/interpretador";
-import { Lexador } from "../fontes/lexador";
+import { AvaliadorSintatico } from "../../fontes/avaliador-sintatico";
+import { InterpretadorComDepuracao } from "../../fontes/interpretador";
+import { Lexador } from "../../fontes/lexador";
 
 describe('Interpretador com Depuração', () => {
     let lexador: Lexador;
diff --git a/testes/interpretador.test.ts b/testes/interpretador/interpretador.test.ts
similarity index 98%
rename from testes/interpretador.test.ts
rename to testes/interpretador/interpretador.test.ts
index 5fdab8fd..3f4f5455 100644
--- a/testes/interpretador.test.ts
+++ b/testes/interpretador/interpretador.test.ts
@@ -1,6 +1,6 @@
-import { AvaliadorSintatico } from '../fontes/avaliador-sintatico';
-import { InterpretadorBase } from '../fontes/interpretador';
-import { Lexador } from '../fontes/lexador';
+import { AvaliadorSintatico } from '../../fontes/avaliador-sintatico';
+import { InterpretadorBase } from '../../fontes/interpretador';
+import { Lexador } from '../../fontes/lexador';
 
 describe('Interpretador', () => {
     describe('interpretar()', () => {
@@ -271,6 +271,28 @@ describe('Interpretador', () => {
 
                     expect(_saida).toBe('<função retorneAlgo>');
                 });
+
+                it('Escrita de vetor com outros objetos dentro', async () => {
+                    let saidas: string[] = [];
+                    const retornoLexador = lexador.mapear([
+                        `funcao retorne() {`,
+                        `    retorna ''`,
+                        `}`,
+                        `const dic = {`,
+                        `    "chave": 10`,
+                        `}`,
+                        `escreva([dic])`,
+                        `escreva([retorne])"`,
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+
+                    interpretador.funcaoDeRetorno = (saida: any) => {
+                        saidas.push(saida);
+                    };
+
+                    await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes);
+                    expect(saidas).toBeTruthy();
+                });
             });
 
             describe('Escolha - Caso', () => {
@@ -1105,7 +1127,7 @@ describe('Interpretador', () => {
                     const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
 
                     interpretador.funcaoDeRetorno = (saida: any) => {
-                        expect(saida).toEqual('1,2,3');
+                        expect(saida).toEqual('[1,2,3]');
                     };
 
                     const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes);
@@ -1127,7 +1149,7 @@ describe('Interpretador', () => {
                     const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
 
                     interpretador.funcaoDeRetorno = (saida: any) => {
-                        expect(saida).toEqual('Olá,mundo');
+                        expect(saida).toEqual('[Olá,mundo]');
                     };
 
                     const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes);
@@ -1146,7 +1168,7 @@ describe('Interpretador', () => {
                     const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
 
                     interpretador.funcaoDeRetorno = (saida: any) => {
-                        expect(saida).toEqual('maçã,banana,morango');
+                        expect(saida).toEqual('[maçã,banana,morango]');
                     };
 
                     const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes);
@@ -1359,8 +1381,8 @@ describe('Interpretador', () => {
 
                         expect(retornoInterpretador.erros).toHaveLength(0);
                         expect(saidas).toHaveLength(2);
-                        expect(saidas[0]).toEqual('a,b,c');
-                        expect(saidas[1]).toEqual('1,2,3');
+                        expect(saidas[0]).toEqual('[a,b,c]');
+                        expect(saidas[1]).toEqual('[1,2,3]');
                     });
                 });
 
@@ -1379,7 +1401,7 @@ describe('Interpretador', () => {
                         const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
 
                         interpretador.funcaoDeRetorno = (saida: string) => {
-                            expect(saida).toEqual('12,8,4,2');
+                            expect(saida).toEqual('[12,8,4,2]');
                         };
 
                         const retornoInterpretador = await interpretador.interpretar(