Repository: DesignLiquido/delegua (ts)

Issue:
Não é possível traduzir operadores de incremento e decremento para JS ou Python
```js
var frase = ''
frase += "oi"

escreva(frase)

```

![Image](https://github.com/user-attachments/assets/da8f029c-e327-4851-b49d-814949f66f0c)

![Image](https://github.com/user-attachments/assets/c348e391-2dfe-4652-a7f5-1fc4c657d4cc)

Pull request:
Soma com incremento corrigida para tradutores Python e JS.
Resolve #713 

Patch:
diff --git a/fontes/avaliador-sintatico/avaliador-sintatico.ts b/fontes/avaliador-sintatico/avaliador-sintatico.ts
index d5576212..71bed581 100644
--- a/fontes/avaliador-sintatico/avaliador-sintatico.ts
+++ b/fontes/avaliador-sintatico/avaliador-sintatico.ts
@@ -792,10 +792,10 @@ export class AvaliadorSintatico
         ) {
             if (expressao.esquerda instanceof AcessoIndiceVariavel) {
                 const entidade = expressao.esquerda as AcessoIndiceVariavel;
-                return new Atribuir(this.hashArquivo, entidade.entidadeChamada, expressao, entidade.indice);
+                return new Atribuir(this.hashArquivo, entidade.entidadeChamada, expressao.direita, entidade.indice);
             }
 
-            return new Atribuir(this.hashArquivo, expressao.esquerda, expressao);
+            return new Atribuir(this.hashArquivo, expressao.esquerda, expressao.direita, undefined, expressao.operador);
         } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) {
             const igual = this.simbolos[this.atual - 1];
             const valor = this.expressao();
diff --git a/fontes/construtos/atribuir.ts b/fontes/construtos/atribuir.ts
index ec57ce3c..e65be134 100644
--- a/fontes/construtos/atribuir.ts
+++ b/fontes/construtos/atribuir.ts
@@ -4,14 +4,14 @@ import { Construto } from './construto';
 /**
  * Construto de atribuição de um valor a um símbolo.
  */
-export class Atribuir implements Construto {
+export class Atribuir<TTipoSimbolo extends string = string> implements Construto {
     linha: number;
     hashArquivo: number;
 
-    indice?: Construto;
-
     alvo: Construto;
+    indice?: Construto;
     valor: any;
+    simboloOperador?: SimboloInterface<TTipoSimbolo>;
 
     constructor(
         hashArquivo: number,
@@ -19,7 +19,8 @@ export class Atribuir implements Construto {
         valor: any,
         // indice so é usado para variaveis de vetores
         // TODO: criar alguma validaçao para garantir que `indice` só seja passado para variáveis de vetores
-        indice?: Construto
+        indice?: Construto,
+        simboloOperador?: SimboloInterface<TTipoSimbolo>
     ) {
         this.linha = Number(alvo.linha);
         this.hashArquivo = hashArquivo;
@@ -30,6 +31,10 @@ export class Atribuir implements Construto {
         if (indice !== undefined) {
             this.indice = indice;
         }
+
+        if (simboloOperador !== undefined) {
+            this.simboloOperador = simboloOperador;
+        }
     }
 
     async aceitar(visitante: VisitanteComumInterface): Promise<any> {
diff --git a/fontes/lexador/lexador.ts b/fontes/lexador/lexador.ts
index d8cb5c48..cb088937 100644
--- a/fontes/lexador/lexador.ts
+++ b/fontes/lexador/lexador.ts
@@ -255,10 +255,10 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
                 this.inicioSimbolo = this.atual;
                 this.avancar();
                 if (this.simboloAtual() === '=') {
-                    this.adicionarSimbolo(tiposDeSimbolos.MENOS_IGUAL);
+                    this.adicionarSimbolo(tiposDeSimbolos.MENOS_IGUAL, '-=');
                     this.avancar();
                 } else if (this.simboloAtual() === '-') {
-                    this.adicionarSimbolo(tiposDeSimbolos.DECREMENTAR);
+                    this.adicionarSimbolo(tiposDeSimbolos.DECREMENTAR, '--');
                     this.avancar();
                 } else {
                     this.adicionarSimbolo(tiposDeSimbolos.SUBTRACAO);
@@ -269,10 +269,10 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
                 this.inicioSimbolo = this.atual;
                 this.avancar();
                 if (this.simboloAtual() === '=') {
-                    this.adicionarSimbolo(tiposDeSimbolos.MAIS_IGUAL);
+                    this.adicionarSimbolo(tiposDeSimbolos.MAIS_IGUAL, '+=');
                     this.avancar();
                 } else if (this.simboloAtual() === '+') {
-                    this.adicionarSimbolo(tiposDeSimbolos.INCREMENTAR);
+                    this.adicionarSimbolo(tiposDeSimbolos.INCREMENTAR, '++');
                     this.avancar();
                 } else {
                     this.adicionarSimbolo(tiposDeSimbolos.ADICAO);
@@ -290,7 +290,7 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
                 switch (this.simboloAtual()) {
                     case '=':
                         this.avancar();
-                        this.adicionarSimbolo(tiposDeSimbolos.MODULO_IGUAL);
+                        this.adicionarSimbolo(tiposDeSimbolos.MODULO_IGUAL, '%=');
                         break;
                     default:
                         this.adicionarSimbolo(tiposDeSimbolos.MODULO);
@@ -304,11 +304,11 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
                 switch (this.simboloAtual()) {
                     case '*':
                         this.avancar();
-                        this.adicionarSimbolo(tiposDeSimbolos.EXPONENCIACAO);
+                        this.adicionarSimbolo(tiposDeSimbolos.EXPONENCIACAO, '**');
                         break;
                     case '=':
                         this.avancar();
-                        this.adicionarSimbolo(tiposDeSimbolos.MULTIPLICACAO_IGUAL);
+                        this.adicionarSimbolo(tiposDeSimbolos.MULTIPLICACAO_IGUAL, '*=');
                         break;
                     default:
                         this.adicionarSimbolo(tiposDeSimbolos.MULTIPLICACAO);
@@ -319,7 +319,7 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
             case '!':
                 this.avancar();
                 if (this.simboloAtual() === '=') {
-                    this.adicionarSimbolo(tiposDeSimbolos.DIFERENTE);
+                    this.adicionarSimbolo(tiposDeSimbolos.DIFERENTE, '!=');
                     this.avancar();
                 } else {
                     this.adicionarSimbolo(tiposDeSimbolos.NEGACAO);
@@ -329,7 +329,7 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
             case '=':
                 this.avancar();
                 if (this.simboloAtual() === '=') {
-                    this.adicionarSimbolo(tiposDeSimbolos.IGUAL_IGUAL);
+                    this.adicionarSimbolo(tiposDeSimbolos.IGUAL_IGUAL, '==');
                     this.avancar();
                 } else {
                     this.adicionarSimbolo(tiposDeSimbolos.IGUAL);
@@ -365,10 +365,10 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
             case '<':
                 this.avancar();
                 if (this.simboloAtual() === '=') {
-                    this.adicionarSimbolo(tiposDeSimbolos.MENOR_IGUAL);
+                    this.adicionarSimbolo(tiposDeSimbolos.MENOR_IGUAL, '<=');
                     this.avancar();
                 } else if (this.simboloAtual() === '<') {
-                    this.adicionarSimbolo(tiposDeSimbolos.MENOR_MENOR);
+                    this.adicionarSimbolo(tiposDeSimbolos.MENOR_MENOR, '<<');
                     this.avancar();
                 } else {
                     this.adicionarSimbolo(tiposDeSimbolos.MENOR);
@@ -378,10 +378,10 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
             case '>':
                 this.avancar();
                 if (this.simboloAtual() === '=') {
-                    this.adicionarSimbolo(tiposDeSimbolos.MAIOR_IGUAL);
+                    this.adicionarSimbolo(tiposDeSimbolos.MAIOR_IGUAL, '>=');
                     this.avancar();
                 } else if (this.simboloAtual() === '>') {
-                    this.adicionarSimbolo(tiposDeSimbolos.MAIOR_MAIOR);
+                    this.adicionarSimbolo(tiposDeSimbolos.MAIOR_MAIOR, '>>');
                     this.avancar();
                 } else {
                     this.adicionarSimbolo(tiposDeSimbolos.MAIOR);
@@ -398,7 +398,7 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
                         this.comentarioMultilinha();
                         break;
                     case '=':
-                        this.adicionarSimbolo(tiposDeSimbolos.DIVISAO_IGUAL);
+                        this.adicionarSimbolo(tiposDeSimbolos.DIVISAO_IGUAL, '/=');
                         this.avancar();
                         break;
                     default:
@@ -413,7 +413,7 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
                 this.avancar();
                 switch (this.simboloAtual()) {
                     case '=':
-                        this.adicionarSimbolo(tiposDeSimbolos.DIVISAO_INTEIRA_IGUAL);
+                        this.adicionarSimbolo(tiposDeSimbolos.DIVISAO_INTEIRA_IGUAL, '\\=');
                         this.avancar();
                         break;
                     default:
@@ -423,7 +423,7 @@ export class Lexador implements LexadorInterface<SimboloInterface> {
 
                 break;
 
-            // Esta sessão ignora espaços em branco na tokenização.
+            // Esta sessão ignora espaços em branco (ou similares) na tokenização.
 
             case ' ':
             case '\0':
diff --git a/fontes/tradutores/tradutor-javascript.ts b/fontes/tradutores/tradutor-javascript.ts
index bf71f4ac..639d732b 100644
--- a/fontes/tradutores/tradutor-javascript.ts
+++ b/fontes/tradutores/tradutor-javascript.ts
@@ -140,7 +140,8 @@ export class TradutorJavaScript implements TradutorInterface<Declaracao> {
 
     traduzirConstrutoAtribuir(atribuir: Atribuir): string {
         let resultado = this.dicionarioConstrutos[atribuir.alvo.constructor.name](atribuir.alvo);
-        resultado += ' = ' + this.dicionarioConstrutos[atribuir.valor.constructor.name](atribuir.valor);
+        const operador = atribuir.simboloOperador?.lexema || '=';
+        resultado += ` ${operador} ` + this.dicionarioConstrutos[atribuir.valor.constructor.name](atribuir.valor);
         return resultado;
     }
 
diff --git a/fontes/tradutores/tradutor-python.ts b/fontes/tradutores/tradutor-python.ts
index ea3ae289..8c62e070 100644
--- a/fontes/tradutores/tradutor-python.ts
+++ b/fontes/tradutores/tradutor-python.ts
@@ -218,7 +218,8 @@ export class TradutorPython implements TradutorInterface<Declaracao> {
 
     traduzirConstrutoAtribuir(atribuir: Atribuir): string {
         let resultado = this.dicionarioConstrutos[atribuir.alvo.constructor.name](atribuir.alvo);
-        resultado += ' = ' + this.dicionarioConstrutos[atribuir.valor.constructor.name](atribuir.valor);
+        const operador = atribuir.simboloOperador?.lexema || '=';
+        resultado += ` ${operador} ` + this.dicionarioConstrutos[atribuir.valor.constructor.name](atribuir.valor);
         return resultado;
     }
 


Test patch:
diff --git a/testes/tradutores/tradutor-javascript.test.ts b/testes/tradutores/tradutor-javascript.test.ts
index 177d573c..7bd01ae5 100644
--- a/testes/tradutores/tradutor-javascript.test.ts
+++ b/testes/tradutores/tradutor-javascript.test.ts
@@ -82,8 +82,8 @@ describe('Tradutor Delégua -> JavaScript', () => {
             const retornoLexador = lexador.mapear(
                 [
                     'escreva({',
-                    '\'chave 1\': \'valor\',',
-                    '\'chave 2\': 2,',
+                    '  \'chave 1\': \'valor\',',
+                    '  \'chave 2\': 2,',
                     '})',
                 ],
                 -1
@@ -876,6 +876,25 @@ describe('Tradutor Delégua -> JavaScript', () => {
             );
         });
 
+        it('Soma com incremento', () => {
+            const retornoLexador = lexador.mapear(
+                [
+                    `var frase = ''`,
+                    `frase += "oi"`,
+                    `escreva(frase)`
+                ],
+                -1
+            );
+    
+            const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+            const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+    
+            expect(resultado).toBeTruthy();
+            expect(resultado).toMatch(/let frase = ''/i);
+            expect(resultado).toMatch(/frase \+= 'oi'/i);
+            expect(resultado).toMatch(/console\.log\(frase\)/i);
+        });
+
         it('chamada de função com parametros -> function', () => {
             const codigo = [
                 'funcao minhaFuncao(a, b, c) { }', 
diff --git a/testes/tradutores/tradutor-python.test.ts b/testes/tradutores/tradutor-python.test.ts
index 09151259..f08a6772 100644
--- a/testes/tradutores/tradutor-python.test.ts
+++ b/testes/tradutores/tradutor-python.test.ts
@@ -116,6 +116,25 @@ describe('Tradutor Delégua -> Python', () => {
         expect(resultado).toMatch(/2 \* 2/i);
     });
 
+    it('Soma com incremento', () => {
+        const retornoLexador = lexador.mapear(
+            [
+                `var frase = ''`,
+                `frase += "oi"`,
+                `escreva(frase)`
+            ],
+            -1
+        );
+
+        const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+        const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
+
+        expect(resultado).toBeTruthy();
+        expect(resultado).toMatch(/frase = ''/i);
+        expect(resultado).toMatch(/frase \+= 'oi'/i);
+        expect(resultado).toMatch(/print\(frase\)/i);
+    });
+
     it('Escreva verdadeiro e falso com operadores lógicos', () => {
         const retornoLexador = lexador.mapear(
             [
@@ -132,7 +151,6 @@ describe('Tradutor Delégua -> Python', () => {
         );
 
         const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
-
         const resultado = tradutor.traduzir(retornoAvaliadorSintatico.declaracoes);
 
         expect(resultado).toBeTruthy();
@@ -150,7 +168,7 @@ describe('Tradutor Delégua -> Python', () => {
         const retornoLexador = lexador.mapear(
             [
                 'funcao olaMundo () {',
-                'escreva(\'Olá Mundo!!!\')',
+                '    escreva(\'Olá Mundo!!!\')',
                 '}',
             ],
             -1
@@ -169,7 +187,7 @@ describe('Tradutor Delégua -> Python', () => {
         const retornoLexador = lexador.mapear(
             [
                 'funcao olaMundo (textoQualquer) {',
-                'escreva(\'Olá Mundo!!!\', textoQualquer)',
+                '    escreva(\'Olá Mundo!!!\', textoQualquer)',
                 '}',
             ],
             -1