Repository: DesignLiquido/delegua
Pull request #405 (2023-05-23 01:25:05)

#392 Atribuição de variaveis na mesma linha
Resolve: https://github.com/DesignLiquido/delegua/issues/392

github-actions[bot]: <!-- jest coverage report action for options with hash 781087021f8e6c43aac1e668f4520603 -->

## Coverage report 



| <div title="Status of coverage:&#10; 🟢 - ok&#10; 🟡 - slightly more than threshold&#10; 🔴 - under the threshold">St.<sup>:grey_question:</sup></div> | Category   | Percentage                                                     | Covered / Total |
| :----------------------------------------------------------------------------------------------------------------------------------------------------: | :--------- | :------------------------------------------------------------- | :-------------: |
|                                                                           🔴                                                                           | Statements | <div title="Base coverage is: 54.83%">54.88% (+0.05% 🔼)</div> |    7511/13686   |
|                                                                           🔴                                                                           | Branches   | <div title="Base coverage is: 45.16%">45.22% (+0.06% 🔼)</div> |    2286/5055    |
|                                                                           🔴                                                                           | Functions  | <div title="Base coverage is: 48.13%">47.99% (-0.15% 🔻)</div> |    1084/2259    |
|                                                                           🔴                                                                           | Lines      | <div title="Base coverage is: 54.71%">54.76% (+0.05% 🔼)</div> |    7342/13407   |


<details><summary>Show files with reduced coverage 🔻</summary>
<br/>

| <div title="Status of coverage:&#10; 🟢 - ok&#10; 🟡 - slightly more than threshold&#10; 🔴 - under the threshold">St.<sup>:grey_question:</sup></div> | File                                                                                                                              | Statements                                                     | Branches                                                       | Functions                                                      | Lines                                                          |
| :----------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------- | :------------------------------------------------------------- | :------------------------------------------------------------- | :------------------------------------------------------------- |
|                                                                           🟢                                                                           | <div title="avaliador-sintatico/avaliador-sintatico.ts">`...` / avaliador-sintatico.ts</div>                                      | <div title="Base coverage is: 93.09%">92.86% (-0.23% 🔻)</div> | <div title="Base coverage is: 82.48%">81.69% (-0.79% 🔻)</div> | <div title="Base coverage is: 94.44%">92.73% (-1.72% 🔻)</div> | <div title="Base coverage is: 93.17%">92.93% (-0.24% 🔻)</div> |
|                                                                           🟡                                                                           | <div title="avaliador-sintatico/avaliador-sintatico-base.ts">`...` / avaliador-sintatico-base.ts</div>                            | <div title="Base coverage is: 72.41%">71.19% (-1.23% 🔻)</div> | 50%                                                            | <div title="Base coverage is: 52.94%">50% (-2.94% 🔻)</div>    | <div title="Base coverage is: 72.07%">70.8% (-1.28% 🔻)</div>  |
|                                                                           🟡                                                                           | <div title="avaliador-sintatico/dialetos/avaliador-sintatico-egua-classico.ts">`...` / avaliador-sintatico-egua-classico.ts</div> | <div title="Base coverage is: 70.46%">70.12% (-0.34% 🔻)</div> | 51.4%                                                          | <div title="Base coverage is: 82%">78.85% (-3.15% 🔻)</div>    | <div title="Base coverage is: 71.28%">70.92% (-0.36% 🔻)</div> |
|                                                                           🟡                                                                           | <div title="avaliador-sintatico/dialetos/avaliador-sintatico-eguap.ts">`...` / avaliador-sintatico-eguap.ts</div>                 | <div title="Base coverage is: 73.21%">72.86% (-0.35% 🔻)</div> | 57.5%                                                          | <div title="Base coverage is: 84.31%">81.13% (-3.18% 🔻)</div> | <div title="Base coverage is: 73.48%">73.12% (-0.37% 🔻)</div> |

</details>

## Test suite run success
523 tests passing in 45 suites.

<p align="right">Report generated by <a href="https://github.com/ArtiomTr/jest-coverage-report-action">🧪jest coverage report action</a> from 786e1327ea767abd4dd435555d1efe52804828e2</p>
<!-- Sticky Pull Request Comment -->

Patch:
diff --git a/fontes/avaliador-sintatico/avaliador-sintatico-base.ts b/fontes/avaliador-sintatico/avaliador-sintatico-base.ts
index 1b72afd0..bf5c95e3 100644
--- a/fontes/avaliador-sintatico/avaliador-sintatico-base.ts
+++ b/fontes/avaliador-sintatico/avaliador-sintatico-base.ts
@@ -1,6 +1,7 @@
 import { Binario, Chamada, Construto, FuncaoConstruto, Logico, Unario } from '../construtos';
 import {
     Classe,
+    Const,
     Continua,
     Declaracao,
     Enquanto,
@@ -37,6 +38,14 @@ export abstract class AvaliadorSintaticoBase implements AvaliadorSintaticoInterf
     atual: number;
     blocos: number;
 
+    declaracaoDeConstantes(): Const[] {
+        throw new Error("Método não implementado.");
+    }
+    
+    declaracaoDeVariaveis(): Var[] {
+        throw new Error("Método não implementado.");
+    }
+
     consumir(tipo: string, mensagemDeErro: string): SimboloInterface {
         if (this.verificarTipoSimboloAtual(tipo)) return this.avancarEDevolverAnterior();
         throw this.erro(this.simbolos[this.atual], mensagemDeErro);
diff --git a/fontes/avaliador-sintatico/avaliador-sintatico.ts b/fontes/avaliador-sintatico/avaliador-sintatico.ts
index 2db4ac7f..6fd1923f 100644
--- a/fontes/avaliador-sintatico/avaliador-sintatico.ts
+++ b/fontes/avaliador-sintatico/avaliador-sintatico.ts
@@ -73,6 +73,10 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
         this.erros = [];
         this.performance = performance;
     }
+    
+    declaracaoDeVariavel(): Var {
+        throw new Error("Método não implementado.");
+    }
 
     erro(simbolo: SimboloInterface, mensagemDeErro: string): ErroAvaliadorSintatico {
         const excecao = new ErroAvaliadorSintatico(simbolo, mensagemDeErro);
@@ -556,10 +560,15 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
     }
 
     blocoEscopo(): Array<RetornoDeclaracao> {
-        const declaracoes: Array<RetornoDeclaracao> = [];
+        let declaracoes: Array<RetornoDeclaracao> = [];
 
         while (!this.verificarTipoSimboloAtual(tiposDeSimbolos.CHAVE_DIREITA) && !this.estaNoFinal()) {
-            declaracoes.push(this.declaracao());
+            const retornoDeclaracao = this.declaracao();
+            if (Array.isArray(retornoDeclaracao)) {
+                declaracoes = declaracoes.concat(retornoDeclaracao);
+            } else {
+                declaracoes.push(retornoDeclaracao as Declaracao);
+            }
         }
 
         this.consumir(tiposDeSimbolos.CHAVE_DIREITA, "Esperado '}' após o bloco.");
@@ -625,9 +634,9 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
         if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA)) {
             inicializador = null;
         } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VARIAVEL)) {
-            inicializador = this.declaracaoDeVariavel();
+            inicializador = this.declaracaoDeVariaveis();
         } else if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CONSTANTE)) {
-            inicializador = this.declaracaoDeConstante();
+            inicializador = this.declaracaoDeConstantes();
         } else {
             inicializador = this.declaracaoExpressao();
         }
@@ -929,33 +938,72 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
      * Caso símbolo atual seja `var`, devolve uma declaração de variável.
      * @returns Um Construto do tipo Var.
      */
-    declaracaoDeVariavel(): Var {
-        const simbolo: SimboloInterface = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado nome de variável.');
+    declaracaoDeVariaveis(): any {
+        const identificadores: SimboloInterface[] = [];
+        let retorno: Declaracao[] = [];
+
+        do {
+            identificadores.push(this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado nome de variável.'));
+        } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
 
-        let inicializador = null;
-        if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) {
-            inicializador = this.expressao();
+        if (!this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) {
+            for (let [indice, identificador] of identificadores.entries()) {
+                retorno.push(new Var(identificador, null));
+            }
+            this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
+            return retorno;
+        }
+
+        //this.consumir(tiposDeSimbolos.IGUAL, "Esperado '=' após identificador em instrução 'var'.");
+
+        const inicializadores = [];
+        do {
+            inicializadores.push(this.expressao());
+        } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
+
+        if (identificadores.length !== inicializadores.length) {
+            throw this.erro(this.simboloAtual(), "Quantidade de identificadores à esquerda do igual é diferente da quantidade de valores à direita.");
+        }
+
+        for (let [indice, identificador] of identificadores.entries()) {
+            retorno.push(new Var(identificador, inicializadores[indice]));
         }
 
-        // Ponto-e-vírgula é opcional aqui.
         this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
-        return new Var(simbolo, inicializador);
+
+        return retorno;
     }
 
     /**
      * Caso símbolo atual seja `const, constante ou fixo`, devolve uma declaração de const.
      * @returns Um Construto do tipo Const.
      */
-    declaracaoDeConstante(): Const {
-        const simbolo: SimboloInterface = this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado nome de constante.');
+    declaracaoDeConstantes(): any {
+        const identificadores: SimboloInterface[] = [];
+
+        do {
+            identificadores.push(this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado nome de variável.'));
+        } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
 
-        let inicializador = null;
-        if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) {
-            inicializador = this.expressao();
+        this.consumir(tiposDeSimbolos.IGUAL, "Esperado '=' após identificador em instrução 'var'.");
+
+        const inicializadores = [];
+        do {
+            inicializadores.push(this.expressao());
+        } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
+
+        if (identificadores.length !== inicializadores.length) {
+            throw this.erro(this.simboloAtual(), "Quantidade de identificadores à esquerda do igual é diferente da quantidade de valores à direita.");
+        }
+
+        let retorno: Declaracao[] = [];
+        for (let [indice, identificador] of identificadores.entries()) {
+            retorno.push(new Const(identificador, inicializadores[indice]));
         }
 
         this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
-        return new Const(simbolo, inicializador);
+
+        return retorno;
     }
 
     funcao(tipo: string): FuncaoDeclaracao {
@@ -1052,8 +1100,8 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
                 this.avancarEDevolverAnterior();
                 return this.funcao('funcao');
             }
-            if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VARIAVEL)) return this.declaracaoDeVariavel();
-            if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CONSTANTE)) return this.declaracaoDeConstante();
+            if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VARIAVEL)) return this.declaracaoDeVariaveis();
+            if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CONSTANTE)) return this.declaracaoDeConstantes();
             if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.CLASSE)) return this.declaracaoDeClasse();
 
             return this.resolverDeclaracao();
@@ -1101,9 +1149,14 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
         this.hashArquivo = hashArquivo || 0;
         this.simbolos = retornoLexador?.simbolos || [];
 
-        const declaracoes: Declaracao[] = [];
+        let declaracoes: Declaracao[] = [];
         while (!this.estaNoFinal()) {
-            declaracoes.push(this.declaracao() as Declaracao);
+            const retornoDeclaracao = this.declaracao();
+            if (Array.isArray(retornoDeclaracao)) {
+                declaracoes = declaracoes.concat(retornoDeclaracao);
+            } else {
+                declaracoes.push(retornoDeclaracao as Declaracao);
+            }
         }
 
         if (this.performance) {
diff --git a/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-egua-classico.ts b/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-egua-classico.ts
index 8b35059c..9a62b10e 100644
--- a/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-egua-classico.ts
+++ b/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-egua-classico.ts
@@ -39,6 +39,7 @@ import {
     Tente,
     Var,
     Leia,
+    Const,
 } from '../../declaracoes';
 
 import { RetornoAvaliadorSintatico } from '../../interfaces/retornos/retorno-avaliador-sintatico';
@@ -67,6 +68,14 @@ export class AvaliadorSintaticoEguaClassico implements AvaliadorSintaticoInterfa
         this.atual = 0;
         this.blocos = 0;
     }
+    
+    declaracaoDeConstantes(): Const[] {
+        throw new Error('Método não implementado.');
+    }
+
+    declaracaoDeVariaveis(): Var[] {
+        throw new Error('Método não implementado.');
+    }
 
     declaracaoLeia(): Leia {
         throw new Error('Método não implementado.');
diff --git a/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-eguap.ts b/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-eguap.ts
index e3f37523..cae085d5 100644
--- a/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-eguap.ts
+++ b/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-eguap.ts
@@ -39,6 +39,7 @@ import {
     Bloco,
     Sustar,
     Leia,
+    Const,
 } from '../../declaracoes';
 
 import { AvaliadorSintaticoInterface, SimboloInterface } from '../../interfaces';
@@ -76,6 +77,14 @@ export class AvaliadorSintaticoEguaP implements AvaliadorSintaticoInterface {
         this.performance = performance;
         this.escopos = [];
     }
+    
+    declaracaoDeConstantes(): Const[] {
+        throw new Error("Método não implementado.");
+    }
+
+    declaracaoDeVariaveis(): Var[] {
+        throw new Error("Método não implementado.");
+    }
 
     sincronizar(): void {
         this.avancarEDevolverAnterior();
diff --git a/fontes/interfaces/avaliador-sintatico-interface.ts b/fontes/interfaces/avaliador-sintatico-interface.ts
index f20fb225..c5a8e92e 100644
--- a/fontes/interfaces/avaliador-sintatico-interface.ts
+++ b/fontes/interfaces/avaliador-sintatico-interface.ts
@@ -3,6 +3,7 @@ import { RetornoAvaliadorSintatico } from './retornos/retorno-avaliador-sintatic
 import { Construto, FuncaoConstruto } from '../construtos';
 import {
     Classe,
+    Const,
     Continua,
     Enquanto,
     Escolha,
@@ -70,6 +71,8 @@ export interface AvaliadorSintaticoInterface {
     declaracaoTente(): Tente;
     declaracaoFazer(): Fazer;
     resolverDeclaracao(): any;
+    declaracaoDeConstantes(): Const[];
+    declaracaoDeVariaveis(): Var[];
     declaracaoDeVariavel(): Var;
     funcao(tipo: string): FuncaoDeclaracao;
     corpoDaFuncao(tipo: string): FuncaoConstruto;
diff --git a/fontes/interpretador/interpretador-base.ts b/fontes/interpretador/interpretador-base.ts
index f037fb69..df7f11bf 100644
--- a/fontes/interpretador/interpretador-base.ts
+++ b/fontes/interpretador/interpretador-base.ts
@@ -618,8 +618,9 @@ export class InterpretadorBase implements InterpretadorInterface {
     }
 
     async visitarDeclaracaoPara(declaracao: Para): Promise<any> {
-        if (declaracao.inicializador !== null) {
-            await this.avaliar(declaracao.inicializador);
+        const declaracaoInicializador = declaracao.inicializador?.length ? declaracao.inicializador[0] : declaracao.inicializador;
+        if (declaracaoInicializador !== null) {
+            await this.avaliar(declaracaoInicializador);
         }
 
         let retornoExecucao: any;
diff --git a/fontes/tradutores/tradutor-javascript.ts b/fontes/tradutores/tradutor-javascript.ts
index d1359a6d..44203876 100644
--- a/fontes/tradutores/tradutor-javascript.ts
+++ b/fontes/tradutores/tradutor-javascript.ts
@@ -383,7 +383,7 @@ export class TradutorJavaScript implements TradutorInterface {
     traduzirDeclaracaoPara(declaracaoPara: Para): string {
         let resultado = 'for (';
         resultado +=
-            this.dicionarioDeclaracoes[declaracaoPara.inicializador.constructor.name](declaracaoPara.inicializador) +
+            this.dicionarioDeclaracoes[declaracaoPara.inicializador[0].constructor.name](declaracaoPara.inicializador[0]) +
             ' ';
 
         resultado += !resultado.includes(';') ? ';' : '';


Test patch:
diff --git a/testes/interpretador.test.ts b/testes/interpretador.test.ts
index 846d8ce2..adad49b1 100644
--- a/testes/interpretador.test.ts
+++ b/testes/interpretador.test.ts
@@ -21,7 +21,8 @@ describe('Interpretador', () => {
                     const retornoLexador = lexador.mapear([
                         "var a = 1",
                         "variavel b = 2",
-                        "variável c = 3"
+                        "variável c = 3",
+                        "var a1, a2, a3 = 1, 2, 3"
                     ], -1);
                     const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
 
@@ -34,7 +35,8 @@ describe('Interpretador', () => {
                     const retornoLexador = lexador.mapear([
                         "const a = 1",
                         "constante b = \"b\"",
-                        "fixo c = 3"
+                        "fixo c = 3",
+                        "const a1, a2, a3 = 1, 2, 3"
                     ], -1);
                     const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);