Repository: DesignLiquido/delegua
Pull request #537 (2023-10-29 16:36:03)

[delegua] avaliador sintático enquanto


Patch:
diff --git a/fontes/analisador-semantico/analisador-semantico.ts b/fontes/analisador-semantico/analisador-semantico.ts
index 93f46699..a786e0b4 100644
--- a/fontes/analisador-semantico/analisador-semantico.ts
+++ b/fontes/analisador-semantico/analisador-semantico.ts
@@ -78,7 +78,7 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
                     const vetor = declaracao.inicializador as Vetor;
                     if (declaracao.tipo === 'inteiro[]') {
                         const v = vetor.valores.find(v => typeof v?.valor !== 'number')
-                        if(v) {
+                        if (v) {
                             this.erro(
                                 declaracao.simbolo,
                                 `Atribuição inválida para '${declaracao.simbolo.lexema}', é esperado um vetor de 'inteiros' ou 'real'.`
@@ -87,7 +87,7 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
                     }
                     if (declaracao.tipo === 'texto[]') {
                         const v = vetor.valores.find(v => typeof v?.valor !== 'string')
-                        if(v) {
+                        if (v) {
                             this.erro(
                                 declaracao.simbolo,
                                 `Atribuição inválida para '${declaracao.simbolo.lexema}', é esperado um vetor de 'texto'.`
@@ -171,13 +171,13 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
                             `O valor passado para o parâmetro '${arg0.tipoDado.nome}' é diferente do esperado pela função.`
                         );
                     }
-                    else if (['inteiro', 'real'].includes(arg0.tipoDado?.tipo) 
-                            && typeof arg1.valor !== 'number') {
+                    else if (['inteiro', 'real'].includes(arg0.tipoDado?.tipo)
+                        && typeof arg1.valor !== 'number') {
                         this.erro(
                             expressao.entidadeChamada.simbolo,
                             `O valor passado para o parâmetro '${arg0.tipoDado.nome}' é diferente do esperado pela função.`
                         );
-                    }                    
+                    }
                 }
             }
         }
@@ -314,6 +314,21 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
     }
 
     visitarDeclaracaoEnquanto(declaracao: Enquanto) {
+        if (declaracao.condicao instanceof Variavel) {
+            const variavel = declaracao.condicao as Variavel;
+            const valor = this.variaveis[variavel.simbolo.lexema];
+            if (!valor) {
+                this.erro(
+                    declaracao.condicao.simbolo,
+                    `Variável ${declaracao.condicao.simbolo.lexema} ainda não foi declarada até este ponto.`
+                );
+            } else if (typeof(valor.valor) !== 'boolean') {
+                this.erro(
+                    declaracao.condicao.simbolo,
+                    `Esperado tipo 'lógico' na condição do 'enquanto'.`
+                );
+            }
+        }
         return Promise.resolve();
     }
 
@@ -325,7 +340,7 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
         const variaveis = declaracao.argumentos.filter(arg => arg instanceof Variavel)
 
         for (let variavel of variaveis as Variavel[]) {
-            if(!this.variaveis[variavel.simbolo.lexema]) {
+            if (!this.variaveis[variavel.simbolo.lexema]) {
                 this.erro(variavel.simbolo, `Variável '${variavel.simbolo.lexema}' não existe.`)
             }
         }
@@ -421,7 +436,7 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
 
     visitarDeclaracaoDefinicaoFuncao(declaracao: FuncaoDeclaracao) {
         for (let parametro of declaracao.funcao.parametros) {
-            if(parametro.hasOwnProperty('tipoDado') && !parametro.tipoDado.tipo) {
+            if (parametro.hasOwnProperty('tipoDado') && !parametro.tipoDado.tipo) {
                 this.erro(declaracao.simbolo, `O tipo '${parametro.tipoDado.tipoInvalido}' não é válido.`);
             }
         }


Test patch:
diff --git a/testes/analisador-semantico.test.ts b/testes/analisador-semantico.test.ts
index 72f7040f..135f9600 100644
--- a/testes/analisador-semantico.test.ts
+++ b/testes/analisador-semantico.test.ts
@@ -247,11 +247,11 @@ describe('Analisador semântico', () => {
                 const retornoLexador = lexador.mapear([
                     'var opcao = leia(\'Digite a opção desejada: \')',
                     'escolha opcao {',
-                        'caso 0:',
-                        'caso 1: // Avisar aqui que tipo de `opcao` não é o mesmo tipo do literal 1',
-                            'facaAlgumaCoisa()',
-                        'caso \'1\': // Aqui o tipo está correto, então não precisa avisar.',
-                            'facaAlgumaCoisa()',
+                    'caso 0:',
+                    'caso 1: // Avisar aqui que tipo de `opcao` não é o mesmo tipo do literal 1',
+                    'facaAlgumaCoisa()',
+                    'caso \'1\': // Aqui o tipo está correto, então não precisa avisar.',
+                    'facaAlgumaCoisa()',
                     '}',
                 ], -1);
                 const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
@@ -266,12 +266,12 @@ describe('Analisador semântico', () => {
                 const retornoLexador = lexador.mapear([
                     'var opcao = leia(\'Digite a opção desejada: \')',
                     'escolha opcao {',
-                        // 'cas:x1 ako',
-                        'caso 1: // Avisar aqui que tipo de `opcao` não é o mesmo tipo do literal 1',
-                            'facaAlgumaCoisa()',
-                        'cas:x1 ako',
-                        'caso \'1\': // Aqui o tipo está correto, então não precisa avisar.',
-                            'facaAlgumaCoisa()',
+                    // 'cas:x1 ako',
+                    'caso 1: // Avisar aqui que tipo de `opcao` não é o mesmo tipo do literal 1',
+                    'facaAlgumaCoisa()',
+                    'cas:x1 ako',
+                    'caso \'1\': // Aqui o tipo está correto, então não precisa avisar.',
+                    'facaAlgumaCoisa()',
                     '}',
                 ], -1);
                 const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
@@ -385,5 +385,82 @@ describe('Analisador semântico', () => {
                 expect(retornoAnalisadorSemantico.erros[1].mensagem).toBe('Não pode haver mais de 255 parâmetros');
             });
         });
+
+        describe('Cenários enquanto', () => {
+            describe('Cenários de sucesso', () => {
+                it('com condicional verdadeiro', () => {
+                    const retornoLexador = lexador.mapear([
+                        "enquanto verdadeiro {  ",
+                        "    escreva(\"sim\");  ",
+                        "    sustar;            ",
+                        "}                      ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(0);
+                });
+
+                it('com condicional falso', () => {
+                    const retornoLexador = lexador.mapear([
+                        "enquanto falso {  ",
+                        "    escreva(\"sim\");  ",
+                        "    sustar;            ",
+                        "}                      ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(0);
+                });
+
+                it('com variavel definida com valor inválido', () => {
+                    const retornoLexador = lexador.mapear([
+                        "const condicional = verdadeiro     ",
+                        "enquanto condicional {             ",
+                        "    escreva(\"sim\");              ",
+                        "    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', () => {
+                    const retornoLexador = lexador.mapear([
+                        "enquanto condicional {  ",
+                        "    escreva(\"sim\");   ",
+                        "    sustar;             ",
+                        "}                       ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(1);
+                });
+
+                it('com variavel definida com valor inválido', () => {
+                    const retornoLexador = lexador.mapear([
+                        "const condicional = \"invalido\"   ",
+                        "enquanto condicional {             ",
+                        "    escreva(\"sim\");              ",
+                        "    sustar;                        ",
+                        "}                                  ",
+                    ], -1);
+                    const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                    const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+
+                    expect(retornoAnalisadorSemantico).toBeTruthy();
+                    expect(retornoAnalisadorSemantico.erros).toHaveLength(1);
+                });                
+             });
+        });
     });
 });