Repository: DesignLiquido/delegua
Pull request #543 (2023-10-31 23:37:08)

[delegua] avaliador sintático enquanto
- operações aritméticas
- função não declarada


Patch:
diff --git a/fontes/analisador-semantico/analisador-semantico.ts b/fontes/analisador-semantico/analisador-semantico.ts
index c58d05c0..f5da97e5 100644
--- a/fontes/analisador-semantico/analisador-semantico.ts
+++ b/fontes/analisador-semantico/analisador-semantico.ts
@@ -318,14 +318,20 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
     }
 
     private verificarCondicao(condicao: Construto): Promise<void> {
+        if (condicao instanceof Agrupamento) {
+            return this.verificarCondicao(condicao.expressao);
+        }
         if (condicao instanceof Variavel) {
             return this.verificarVariavel(condicao);
         }
         if (condicao instanceof Binario) {
             return this.verificarBinario(condicao);
+        }        
+        if (condicao instanceof Logico) {
+            return this.verificarLogico(condicao);
         }
-        if (condicao instanceof Agrupamento) {
-            return this.verificarAgrupamento(condicao);
+        if (condicao instanceof Chamada) {
+            return this.verificarChamada(condicao);
         }
         return Promise.resolve();
     }
@@ -349,19 +355,65 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
     private verificarBinario(binario: Binario): Promise<void> {
         this.verificarLadoBinario(binario.direita);
         this.verificarLadoBinario(binario.esquerda);
+        this.verificarOperadorBinario(binario);
         return Promise.resolve();
     }
 
-    private verificarLadoBinario(lado: any): void {
+    private verificarOperadorBinario(binario: Binario): void {
+        const operadoresMatematicos = ['ADICAO', 'SUBTRACAO', 'MULTIPLICACAO', 'DIVISAO', 'MODULO'];
+        if (operadoresMatematicos.includes(binario.operador.tipo)) {
+            if (binario.direita instanceof Variavel && binario.esquerda instanceof Variavel) {
+                const tipoDireita = typeof this.variaveis[binario.direita.simbolo.lexema]?.valor;
+                const tipoEsquerda = typeof this.variaveis[binario.esquerda.simbolo.lexema]?.valor;
+                if (tipoDireita !== tipoEsquerda) {
+                    this.erro(binario.operador, `Operação inválida, tipos diferentes.`);
+                }
+            }
+        }
+
+        if (binario.operador.tipo === 'DIVISAO') {
+            if (this.variaveis[binario.direita.simbolo.lexema]?.valor === 0) {
+                this.erro(binario.operador, `Divisão por zero.`);
+            }
+        }
+    }
+
+    private verificarLadoBinario(lado: Construto): void {
         if (lado instanceof Variavel && !this.variaveis[lado.simbolo.lexema]) {
             this.erro(
                 lado.simbolo,
                 `Variável ${lado.simbolo.lexema} ainda não foi declarada até este ponto.`
             );
+            return;
+        }
+        if (lado instanceof Binario) {
+            this.verificarBinario(lado);
+            return;
+        }
+        return;
+    }
+
+    private verificarLogico(logio: Logico): Promise<void> {
+        this.verificarLadoLogico(logio.direita);
+        this.verificarLadoLogico(logio.esquerda);
+        return Promise.resolve();
+    }
+
+    private verificarChamada(chamada: Chamada): Promise<void> {
+        let funcaoChamada = (chamada.entidadeChamada as Variavel);
+        if (!this.funcoes[funcaoChamada.simbolo.lexema]) {
+            this.erro(
+                funcaoChamada.simbolo,
+                `Chamada da função '${funcaoChamada.simbolo.lexema}' não existe.`
+            );
+            return Promise.resolve();
         }
     }
 
     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);
         }
@@ -444,7 +496,7 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
         this.variaveis[declaracao.simbolo.lexema] = {
             imutavel: false,
             tipo: declaracao.tipo,
-            valor: declaracao.inicializador?.valor || declaracao.inicializador
+            valor: declaracao.inicializador !== null ? declaracao.inicializador.valor !== undefined ? declaracao.inicializador.valor : declaracao.inicializador : undefined
         };
 
         return Promise.resolve();


Test patch:
diff --git a/testes/analisador-semantico.test.ts b/testes/analisador-semantico.test.ts
index d75e58ac..51e8a819 100644
--- a/testes/analisador-semantico.test.ts
+++ b/testes/analisador-semantico.test.ts
@@ -488,6 +488,36 @@ describe('Analisador semântico', () => {
                     expect(retornoAnalisadorSemantico.erros).toHaveLength(0);
                 });
 
+                it('sucesso - verificar operações aritméticas', () => {
+                    const retornoLexador = lexador.mapear([
+                        "var x = 1;                           ",
+                        "var y = 2;                           ",
+                        "enquanto (x + y < 10) {sustar;}      ",
+                        "enquanto (x - y < 10) {sustar;}      ",
+                        "enquanto (x * y < 10) {sustar;}      ",
+                        "enquanto (x / y < 10) {sustar;}      ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(0);
+                });
+
+                it('sucesso - verificar função declarada', () => {
+                    const retornoLexador = lexador.mapear([
+                          "funcao funcaoExistente() {       ",
+                          "  retorna verdadeiro;            ",
+                          "}                                ",
+                          "enquanto (funcaoExistente()) {   ",
+                          "    escreva('teste');            ",
+                          "    sustar;                      ",
+                          "}                                ",
+                    ], -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('com condicional não declarada', () => {
@@ -547,7 +577,7 @@ describe('Analisador semântico', () => {
                     expect(retornoAnalisadorSemantico.erros).toHaveLength(1);
                 });
 
-                it('falha - verificar valores lógicos nas operações binárias', () => {
+                it('falha - verificar valores lógicos nas operações binárias e agrupamento', () => {
                     const retornoLexador = lexador.mapear([
                         "var x = 5;                         ",
                         "var y = 10;                        ",
@@ -562,6 +592,66 @@ describe('Analisador semântico', () => {
                     expect(retornoAnalisadorSemantico).toBeTruthy();
                     expect(retornoAnalisadorSemantico.erros).toHaveLength(2);
                 });
+
+                it('falha - verificar valores lógicos nas operações binárias sem agrupamento', () => {
+                    const retornoLexador = lexador.mapear([
+                        "var x = 5;                         ",
+                        "var y = 10;                        ",
+                        "enquanto x e y {                   ",
+                        "    escreva(\"sim\");              ",
+                        "    sustar;                        ",
+                        "}                                  ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(2);
+                });
+
+                it('falha - verificar operações aritméticas', () => {
+                    const retornoLexador = lexador.mapear([
+                        "var x = 'texto';                   ",
+                        "var y = 2;                         ",
+                        "enquanto (x + y < 10) {sustar;}    ",
+                        "enquanto (x - y < 10) {sustar;}    ",
+                        "enquanto (x * y < 10) {sustar;}    ",
+                        "enquanto (x / y < 10) {sustar;}    ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(4);
+                });
+
+                it('falha - verificar operação divisão por zero', () => {
+                    const retornoLexador = lexador.mapear([
+                        "var x = 3;                        ",
+                        "var y = 0;                         ",
+                        "enquanto (x / y < 10) {sustar;}    ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(1);
+                });
+
+                it('falha - verificar função não declarada', () => {
+                    const retornoLexador = lexador.mapear([
+                        "enquanto (funcaoNaoExistente()) {",
+                        "   escreva('teste');",
+                        "   sustar;",
+                        "}",
+                        "enquanto funcaoNaoExistente() {",
+                        "   escreva('teste');",
+                        "   sustar;",
+                        "}",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(2);
+                });                
             });
         });
     });