Repository: DesignLiquido/delegua
Pull request #544 (2023-11-01 12:59:05)

[delegua] analisador semantico para tipo de


Patch:
diff --git a/fontes/analisador-semantico/analisador-semantico.ts b/fontes/analisador-semantico/analisador-semantico.ts
index f5da97e5..c5ec3ecb 100644
--- a/fontes/analisador-semantico/analisador-semantico.ts
+++ b/fontes/analisador-semantico/analisador-semantico.ts
@@ -120,6 +120,20 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
     }
 
     visitarExpressaoTipoDe(expressao: TipoDe): Promise<any> {
+        return this.verificarTipoDe(expressao.valor);
+    }
+
+    private verificarTipoDe(valor: Construto): Promise<any> {
+        if (valor instanceof Binario ) {
+            this.verificarTipoDe(valor.direita);
+            this.verificarTipoDe(valor.esquerda);
+        }
+        if (valor instanceof Agrupamento) {
+            return this.verificarTipoDe(valor.expressao);
+        }
+        if (valor instanceof Variavel) {
+            return this.verificarVariavel(valor);
+        }
         return Promise.resolve();
     }
 
@@ -322,11 +336,11 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
             return this.verificarCondicao(condicao.expressao);
         }
         if (condicao instanceof Variavel) {
-            return this.verificarVariavel(condicao);
+            return this.verificarVariavelBinaria(condicao);
         }
         if (condicao instanceof Binario) {
             return this.verificarBinario(condicao);
-        }        
+        }
         if (condicao instanceof Logico) {
             return this.verificarLogico(condicao);
         }
@@ -336,17 +350,24 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
         return Promise.resolve();
     }
 
-    private verificarVariavel(variavel: Variavel): Promise<void> {
+    private verificarVariavelBinaria(variavel: Variavel): Promise<void> {
+        this.verificarVariavel(variavel);
         const variavelHipotetica = this.variaveis[variavel.simbolo.lexema];
-        if (!variavelHipotetica) {
+        if (variavelHipotetica && !(variavelHipotetica.valor instanceof Binario) && (typeof variavelHipotetica.valor !== 'boolean')) {
             this.erro(
                 variavel.simbolo,
-                `Variável ${variavel.simbolo.lexema} ainda não foi declarada até este ponto.`
+                `Esperado tipo 'lógico' na condição do 'enquanto'.`
             );
-        } else if (!(variavelHipotetica.valor instanceof Binario) && (typeof variavelHipotetica.valor !== 'boolean')) {
+        }
+        return Promise.resolve();
+    }
+
+    private verificarVariavel(variavel: Variavel): Promise<void> {
+        const variavelHipotetica = this.variaveis[variavel.simbolo.lexema];
+        if (!variavelHipotetica) {
             this.erro(
                 variavel.simbolo,
-                `Esperado tipo 'lógico' na condição do 'enquanto'.`
+                `Variável ${variavel.simbolo.lexema} ainda não foi declarada até este ponto.`
             );
         }
         return Promise.resolve();
@@ -410,28 +431,13 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
         }
     }
 
-    private verificarAgrupamento(agrupamento: Agrupamento): Promise<void> {
-        if (agrupamento.expressao instanceof Chamada) {
-            return this.verificarChamada(agrupamento.expressao);
-        }
-        if (agrupamento.expressao instanceof Binario) {
-            return this.verificarBinario(agrupamento.expressao);
-        }
-        if (agrupamento.expressao instanceof Logico) {
-            this.verificarLadoLogico(agrupamento.expressao.direita);
-            this.verificarLadoLogico(agrupamento.expressao.esquerda);
-        }
-        return Promise.resolve();
-    }
-
     private verificarLadoLogico(lado: any): void {
         if (lado instanceof Variavel) {
             let variavel = lado as Variavel;
-            this.verificarVariavel(variavel)
+            this.verificarVariavelBinaria(variavel)
         }
     }
 
-
     visitarDeclaracaoImportar(declaracao: Importar) {
         return Promise.resolve();
     }
diff --git a/fontes/interpretador/interpretador-base.ts b/fontes/interpretador/interpretador-base.ts
index d5ae1193..87bc97e2 100644
--- a/fontes/interpretador/interpretador-base.ts
+++ b/fontes/interpretador/interpretador-base.ts
@@ -163,7 +163,8 @@ export class InterpretadorBase implements InterpretadorInterface {
             tipoDe instanceof Binario ||
             tipoDe instanceof TipoDe ||
             tipoDe instanceof Unario ||
-            tipoDe instanceof Variavel
+            tipoDe instanceof Variavel ||
+            tipoDe instanceof Agrupamento
         ) {
             tipoDe = await this.avaliar(tipoDe);
             return tipoDe.tipo || inferirTipoVariavel(tipoDe);


Test patch:
diff --git a/testes/analisador-semantico.test.ts b/testes/analisador-semantico.test.ts
index 51e8a819..dc0062f6 100644
--- a/testes/analisador-semantico.test.ts
+++ b/testes/analisador-semantico.test.ts
@@ -654,5 +654,67 @@ describe('Analisador semântico', () => {
                 });                
             });
         });
+
+        describe('Cenários tipo de', () => {
+            describe('Cenários de sucesso', () => {
+                it('com variável definida com valor válido', () => {
+                    const retornoLexador = lexador.mapear([
+                        "const condicional = verdadeiro     ",
+                        "tipo de condicional                ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(0);
+                });
+
+                it('tipo de com variável definida e agrupamento', () => {
+                    const retornoLexador = lexador.mapear([
+                        "const a = 1      ",
+                        "const b = 2      ",
+                        "tipo de (a + b)  ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(0);
+                });
+            });
+
+            describe('Cenários de falha', () => {
+
+                it('tipo de com variável não definida', () => {
+                    const retornoLexador = lexador.mapear([
+                        "tipo de condicional                ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(1);
+                });
+
+                it('tipo de com variável não definida e agrupamento', () => {
+                    const retornoLexador = lexador.mapear([
+                        "tipo de (a)  ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(1);
+                });
+
+                it('tipo de binario com variável não definida e agrupamento', () => {
+                    const retornoLexador = lexador.mapear([
+                        "const a = 1      ",
+                        "tipo de (a + b)  ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(1);
+                });
+            });
+
+        });
     });
 });
diff --git a/testes/interpretador.test.ts b/testes/interpretador.test.ts
index 3fdbbc21..5241a332 100644
--- a/testes/interpretador.test.ts
+++ b/testes/interpretador.test.ts
@@ -315,6 +315,23 @@ describe('Interpretador', () => {
                     expect(retornoInterpretador.erros).toHaveLength(0);
                 });
 
+                it ('Tipo de com agrupamento', async () => {
+                    const retornoLexador = lexador.mapear([
+                        'var a = 1',
+                        'var b = tipo de (a)',
+                        'escreva(b)',
+                    ], -1);
+                    interpretador.funcaoDeRetorno = (saida: any) => {
+                        expect(saida).toEqual("número");
+                    };
+    
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+
+                    const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes);
+
+                    expect(retornoInterpretador.erros).toHaveLength(0);
+                });
+
                 it('Ordem lexicográfica de textos', async () => {
                     const saidasMensagens = [
                         'verdadeiro',