Repository: DesignLiquido/delegua
Pull request #462 (2023-07-02 02:22:52)

#461 Melhora definição de tipos ao declarar variáveis e adiciona verificação para tipo vetor
Resolve: https://github.com/DesignLiquido/delegua/issues/461

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: 73.87%">73.9% (+0.04% 🔼)</div>  |    7473/10112   |
|                                                                           🟡                                                                           | Branches   | <div title="Base coverage is: 63.61%">63.71% (+0.11% 🔼)</div> |    2416/3792    |
|                                                                           🟡                                                                           | Functions  | 69.49%                                                         |    1100/1583    |
|                                                                           🟡                                                                           | Lines      | <div title="Base coverage is: 74.27%">74.31% (+0.04% 🔼)</div> |    7288/9808    |


## Test suite run success
643 tests passing in 49 suites.

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

Patch:
diff --git a/fontes/avaliador-sintatico/avaliador-sintatico.ts b/fontes/avaliador-sintatico/avaliador-sintatico.ts
index b1f33ba1..268881b6 100644
--- a/fontes/avaliador-sintatico/avaliador-sintatico.ts
+++ b/fontes/avaliador-sintatico/avaliador-sintatico.ts
@@ -100,9 +100,32 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
     }
 
     verificarDefinicaoTipoAtual(): string {
-        const tipos = ['inteiro', 'qualquer', 'real', 'texto', 'vazio']
+        const tipos = [
+            'inteiro',
+            'qualquer',
+            'real',
+            'texto',
+            'vazio',
+            'vetor'
+        ]
+
+        const lexema = this.simboloAtual().lexema.toLowerCase();
+        const contemTipo = tipos.find(tipo => tipo === lexema);
+
+        if(contemTipo && this.verificarTipoProximoSimbolo(tiposDeSimbolos.COLCHETE_ESQUERDO)) {
+            const tiposVetores = ['inteiro[]', 'qualquer[]', 'real[]', 'texto[]']
+            this.avancarEDevolverAnterior();
+
+            if(!this.verificarTipoProximoSimbolo(tiposDeSimbolos.COLCHETE_DIREITO)) {
+                throw this.erro(this.simbolos[this.atual], 'Esperado símbolo de fechamento do vetor \']\'.');
+            }
+
+            const contemTipoVetor = tiposVetores.find(tipo => tipo === `${lexema}[]`);
 
-        const contemTipo = tipos.find(tipo => tipo === this.simboloAtual().lexema.toLowerCase())
+            this.avancarEDevolverAnterior();
+
+            return contemTipoVetor
+        }
 
         return contemTipo;
     }
@@ -949,6 +972,46 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
         return this.declaracaoExpressao();
     }
 
+    verificarTipoAtribuido(tipo: string, inicializador: any) {
+        if(tipo) {
+            if(['vetor', 'qualquer[]', 'inteiro[]', 'texto[]'].includes(tipo)) {
+                if(inicializador instanceof Vetor) {
+                    const vetor = inicializador as Vetor;
+                    if(tipo === 'inteiro[]') {
+                        for(let elemento of vetor.valores) {
+                            if(typeof elemento.valor !== 'number') {
+                                throw this.erro(this.simboloAtual(), "Atribuição inválida, é espero um vetor de \'inteiros\' ou \'real\'.");
+                            }
+                        }
+                    }
+                    if(tipo === 'texto[]'){
+                        for(let elemento of vetor.valores) {
+                            if(typeof elemento.valor !== 'string') {
+                                throw this.erro(this.simboloAtual(), "Atribuição inválida, é espero um vetor de texto.");
+                            }
+                        }
+                    }
+                } else {
+                    throw this.erro(this.simboloAtual(), "Atribuição inválida, é espero um vetor de elementos.");
+                }
+            }
+
+            if(inicializador instanceof Literal) {
+                const literal = inicializador as Literal;
+                if(tipo === 'texto') {
+                    if(typeof literal.valor !== 'string') {
+                        throw this.erro(this.simboloAtual(), "Atribuição inválida, é espero um texto.");
+                    }
+                }
+                if(['inteiro', 'real'].includes(tipo)) {
+                    if(typeof literal.valor !== 'number') {
+                        throw this.erro(this.simboloAtual(), "Atribuição inválida, é espero um número.");
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Caso símbolo atual seja `var`, devolve uma declaração de variável.
      * @returns Um Construto do tipo Var.
@@ -956,22 +1019,24 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
     declaracaoDeVariaveis(): any {
         const identificadores: SimboloInterface[] = [];
         let retorno: Declaracao[] = [];
+        let tipo: any = null;
 
         do {
             identificadores.push(this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado nome da variável.'));
         } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
 
         if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.DOIS_PONTOS)) {
-            const tipos = ['inteiro', 'real', 'texto']
-            if (!tipos.includes(this.simboloAtual().lexema)) {
-                throw this.erro(this.simboloAtual(), "Tipo definido na variável é inválido.");
+            const tipoVariavel = this.verificarDefinicaoTipoAtual();
+            if (!tipoVariavel) {
+                throw this.erro(this.simboloAtual(), "Tipo definido na variável não é válido.");
             }
+            tipo = tipoVariavel;
             this.avancarEDevolverAnterior();
         }
 
         if (!this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IGUAL)) {
             for (let [indice, identificador] of identificadores.entries()) {
-                retorno.push(new Var(identificador, null));
+                retorno.push(new Var(identificador, null, tipo));
             }
             this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
             return retorno;
@@ -989,7 +1054,12 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
         }
 
         for (let [indice, identificador] of identificadores.entries()) {
-            retorno.push(new Var(identificador, inicializadores[indice]));
+
+            const inicializador = inicializadores[indice];
+
+            this.verificarTipoAtribuido(tipo, inicializador);
+
+            retorno.push(new Var(identificador, inicializador, tipo));
         }
 
         this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
@@ -1003,16 +1073,18 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
      */
     declaracaoDeConstantes(): any {
         const identificadores: SimboloInterface[] = [];
+        let tipo: any = null;
 
         do {
             identificadores.push(this.consumir(tiposDeSimbolos.IDENTIFICADOR, 'Esperado nome da constante.'));
         } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
 
         if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.DOIS_PONTOS)) {
-            const tipos = ['inteiro', 'real', 'texto']
-            if (!tipos.includes(this.simboloAtual().lexema)) {
-                throw this.erro(this.simboloAtual(), "Tipo definido na variável é inválido.");
+            const tipoConstante = this.verificarDefinicaoTipoAtual();
+            if (!tipoConstante) {
+                throw this.erro(this.simboloAtual(), "Tipo definido na constante não é válido.");
             }
+            tipo = tipoConstante;
             this.avancarEDevolverAnterior();
         }
 
@@ -1029,7 +1101,12 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface {
 
         let retorno: Declaracao[] = [];
         for (let [indice, identificador] of identificadores.entries()) {
-            retorno.push(new Const(identificador, inicializadores[indice]));
+
+            const inicializador = inicializadores[indice];
+
+            this.verificarTipoAtribuido(tipo, inicializador);
+
+            retorno.push(new Const(identificador, inicializadores[indice], tipo));
         }
 
         this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
diff --git a/fontes/interfaces/tipos-dados-interface.ts b/fontes/interfaces/tipos-dados-interface.ts
index 150b7979..a95581e2 100644
--- a/fontes/interfaces/tipos-dados-interface.ts
+++ b/fontes/interfaces/tipos-dados-interface.ts
@@ -1,12 +1,19 @@
 export type TiposDadosInterface =
-    | 'texto'
-    | 'numero'
+    | 'dicionário'
+    | 'função'
+    | 'inteiro'
+    | 'inteiro[]'
     | 'longo'
     | 'lógico'
-    | 'nulo'
-    | 'vetor'
     | 'módulo'
-    | 'dicionário'
-    | 'função'
+    | 'nulo'
+    | 'numero'
+    | 'qualquer'
+    | 'qualquer[]'
+    | 'real'
+    | 'real[]'
     | 'símbolo'
+    | 'texto'
+    | 'texto[]'
+    | 'vetor'
     | undefined;


Test patch:
diff --git a/testes/avaliador-sintatico.test.ts b/testes/avaliador-sintatico.test.ts
index 81e7b9b3..9a1d7472 100644
--- a/testes/avaliador-sintatico.test.ts
+++ b/testes/avaliador-sintatico.test.ts
@@ -18,12 +18,19 @@ describe('Avaliador sintático', () => {
             it('Sucesso - Definição Tipo Variável', () => {
                 const retornoLexador = lexador.mapear([
                     "var t: texto = \"Variável com tipo\"",
-                    "const n: inteiro = 10"
+                    "const n: inteiro = 10",
+                    "var v1: texto[] = [\'oi\']",
+                    "var v2: inteiro[] = [1]",
+                    "const a: vetor = ['1', '2', '3']",
+                    "const b: vetor = [1, 2, 3]",
+                    "const c: qualquer[] = [1, 2, 3]",
+                    "const d: qualquer[] = [1, '2', 3, 'Olá Mundo']",
+                    "const f: qualquer = [1, '2', 3, 'Olá Mundo']",
                 ], -1);
                 const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
     
                 expect(retornoAvaliadorSintatico).toBeTruthy();
-                expect(retornoAvaliadorSintatico.declaracoes).toHaveLength(2);
+                expect(retornoAvaliadorSintatico.declaracoes).toHaveLength(9);
             });
     
             it('Sucesso - Vetor vazio', () => {
@@ -260,6 +267,17 @@ describe('Avaliador sintático', () => {
                     expect(retornoAvaliadorSintatico).toBeTruthy();
                     expect(retornoAvaliadorSintatico.erros[0].message).toBe('O tipo \'algum\' não é válido.');
                 });
+
+                it('Função com retorno de vetor', () => {
+                    const retornoLexador = lexador.mapear([
+                        "funcao executar(): texto[] {",
+                        "   retorna [\"1\", \"2\"]",
+                        "}",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+    
+                    expect(retornoAvaliadorSintatico).toBeTruthy();
+                });
             });
     
             it('Declaração `tente`', () => {
diff --git a/testes/interpretador.test.ts b/testes/interpretador.test.ts
index 56202e06..5926c787 100644
--- a/testes/interpretador.test.ts
+++ b/testes/interpretador.test.ts
@@ -21,7 +21,14 @@ describe('Interpretador', () => {
                         "var a = 1",
                         "variavel b = 2",
                         "variável c = 3",
-                        "var a1, a2, a3 = 1, 2, 3"
+                        "var a1, a2, a3 = 1, 2, 3",
+                        "var bb1, bb2, bb3: vetor = [1, 2, 3], ['1', '2', '3'], ['Olá Mundo!']",
+
+                        "const aa = 1",
+                        "constante bb = 2",
+                        "fixo cc = 3",
+                        "const aa1, aa2, aa3 = 1, 2, 3",
+                        "const bb1, bb2, bb3: vetor = [1, 2, 3], ['1', '2', '3'], ['Olá Mundo!']",
                     ], -1);
                     const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);