Repository: DesignLiquido/delegua
Pull request #275 (2023-02-11 01:10:54)

Portugol Studio: função `leia()`, primitiva de inteiro.

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

## 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: 70.16%">70.47% (+0.31% 🔼)</div> |    4044/5739    |
|                                                                           🔴                                                                           | Branches   | <div title="Base coverage is: 58.17%">58.54% (+0.38% 🔼)</div> |    1223/2089    |
|                                                                           🟡                                                                           | Functions  | <div title="Base coverage is: 70.88%">71.24% (+0.36% 🔼)</div> |     602/845     |
|                                                                           🟡                                                                           | Lines      | <div title="Base coverage is: 70.55%">70.86% (+0.31% 🔼)</div> |    3908/5515    |

<details><summary>Show new covered files 🐣</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="interpretador/dialetos/portugol-studio/interpretador-portugol-studio.ts">`...` / interpretador-portugol-studio.ts</div> | 100%       | 100%     | 100%      | 100%  |

</details>


## Test suite run success
274 tests passing in 25 suites.

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

Patch:
diff --git a/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-portugol-studio.ts b/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-portugol-studio.ts
index d5af9c8c..cc19715f 100644
--- a/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-portugol-studio.ts
+++ b/fontes/avaliador-sintatico/dialetos/avaliador-sintatico-portugol-studio.ts
@@ -1,5 +1,5 @@
 import { AcessoIndiceVariavel, AtribuicaoSobrescrita, Atribuir, Chamada, Construto, FuncaoConstruto, Literal, Variavel } from "../../construtos";
-import { Escreva, Declaracao, Se, Enquanto, Para, Escolha, Fazer, FuncaoDeclaracao, Expressao } from "../../declaracoes";
+import { Escreva, Declaracao, Se, Enquanto, Para, Escolha, Fazer, FuncaoDeclaracao, Expressao, Leia, Var } from "../../declaracoes";
 import { RetornoLexador, RetornoAvaliadorSintatico } from "../../interfaces/retornos";
 import { AvaliadorSintaticoBase } from "../avaliador-sintatico-base";
 
@@ -21,7 +21,7 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase {
         this.consumir(tiposDeSimbolos.CHAVE_ESQUERDA, "Esperada chave esquerda após expressão 'programa' para inicializar programa.");
 
         while (!this.estaNoFinal()) {
-            declaracoes.push(this.declaracao() as Declaracao);
+            declaracoes.push(this.declaracao());
         }
 
         if (this.simbolos[this.atual - 1].tipo !== tiposDeSimbolos.CHAVE_DIREITA) {
@@ -50,6 +50,10 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase {
     }
 
     primario(): Construto {
+        if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.IDENTIFICADOR)) {
+            return new Variavel(this.hashArquivo, this.simbolos[this.atual - 1]);
+        }
+
         if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.REAL, tiposDeSimbolos.CADEIA)) {
             const simboloAnterior: SimboloInterface = this.simbolos[this.atual - 1];
             return new Literal(this.hashArquivo, Number(simboloAnterior.linha), simboloAnterior.literal);
@@ -125,10 +129,15 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase {
     }
 
     blocoEscopo(): Declaracao[] {
-        const declaracoes: Array<RetornoDeclaracao> = [];
+        let declaracoes: Array<RetornoDeclaracao> = [];
 
         while (!this.verificarTipoSimboloAtual(tiposDeSimbolos.CHAVE_DIREITA) && !this.estaNoFinal()) {
-            declaracoes.push(this.declaracao());
+            const declaracaoOuVetor: any = this.declaracao();
+            if (Array.isArray(declaracaoOuVetor)) {
+                declaracoes = declaracoes.concat(declaracaoOuVetor);
+            } else {
+                declaracoes.push(declaracaoOuVetor);
+            }
         }
 
         this.consumir(tiposDeSimbolos.CHAVE_DIREITA, "Esperado '}' após o bloco.");
@@ -143,6 +152,37 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase {
         throw new Error("Método não implementado.");
     }
 
+    declaracaoInteiros(): Var[] {
+        const simboloInteiro = this.consumir(tiposDeSimbolos.INTEIRO, "");
+
+        const inicializacoes = [];
+        do {
+            const identificador = this.consumir(tiposDeSimbolos.IDENTIFICADOR, "Esperado identificador após palavra reservada 'inteiro'.");
+            inicializacoes.push(new Var(identificador, new Literal(this.hashArquivo, Number(simboloInteiro.linha), 0)));
+        } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
+
+        return inicializacoes;
+    }
+
+    /**
+     * Análise de uma declaração `leia()`. No VisuAlg, `leia()` aceita 1..N argumentos.
+     * @returns Uma declaração `Leia`.
+     */
+    declaracaoLeia(): Leia {
+        const simboloAtual = this.avancarEDevolverAnterior();
+
+        this.consumir(tiposDeSimbolos.PARENTESE_ESQUERDO, "Esperado '(' antes do argumento em instrução `leia`.");
+
+        const argumentos = [];
+        do {
+            argumentos.push(this.declaracao());
+        } while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));
+
+        this.consumir(tiposDeSimbolos.PARENTESE_DIREITO, "Esperado ')' após o argumento em instrução `leia`.");
+
+        return new Leia(simboloAtual.hashArquivo, Number(simboloAtual.linha), argumentos);
+    }
+
     declaracaoPara(): Para {
         throw new Error("Método não implementado.");
     }
@@ -188,6 +228,10 @@ export class AvaliadorSintaticoPortugolStudio extends AvaliadorSintaticoBase {
                 return this.declaracaoEscreva();
             case tiposDeSimbolos.FUNCAO:
                 return this.funcao('funcao');
+            case tiposDeSimbolos.INTEIRO:
+                return this.declaracaoInteiros();
+            case tiposDeSimbolos.LEIA:
+                return this.declaracaoLeia();
             case tiposDeSimbolos.PROGRAMA:
             case tiposDeSimbolos.CHAVE_DIREITA:
                 this.avancarEDevolverAnterior();
diff --git a/fontes/interpretador/dialetos/index.ts b/fontes/interpretador/dialetos/index.ts
index 61cacd66..f88f0a70 100644
--- a/fontes/interpretador/dialetos/index.ts
+++ b/fontes/interpretador/dialetos/index.ts
@@ -1,3 +1,4 @@
 export * from './egua-classico';
+export * from './portugol-studio/interpretador-portugol-studio';
 export * from './visualg/interpretador-visualg';
 export * from './visualg/interpretador-visualg-com-depuracao';
diff --git a/fontes/interpretador/dialetos/portugol-studio/interpretador-portugol-studio.ts b/fontes/interpretador/dialetos/portugol-studio/interpretador-portugol-studio.ts
new file mode 100644
index 00000000..dc372b23
--- /dev/null
+++ b/fontes/interpretador/dialetos/portugol-studio/interpretador-portugol-studio.ts
@@ -0,0 +1,33 @@
+import { Variavel } from "../../../construtos";
+import { Leia } from "../../../declaracoes";
+import { InterpretadorBase } from "../../interpretador-base";
+
+export class InterpretadorPortugolStudio extends InterpretadorBase {
+    constructor(
+        diretorioBase: string,
+        performance = false,
+        funcaoDeRetorno: Function = null
+    ) {
+        super(diretorioBase, performance, funcaoDeRetorno);
+    }
+
+    /**
+     * Execução da leitura de valores da entrada configurada no
+     * início da aplicação.
+     * @param expressao Expressão do tipo Leia
+     * @returns Promise com o resultado da leitura.
+     */
+    async visitarExpressaoLeia(expressao: Leia): Promise<any> {
+        const mensagem = '> ';
+        for (let argumento of expressao.argumentos) {
+            const promessaLeitura: Function = () => new Promise((resolucao) =>
+                this.interfaceEntradaSaida.question(mensagem, (resposta: any) => {
+                    resolucao(resposta);
+                })
+            );
+
+            const valorLido = await promessaLeitura();
+            this.pilhaEscoposExecucao.definirVariavel((<Variavel>argumento).simbolo.lexema, valorLido);
+        }
+    }
+}
\ No newline at end of file
diff --git a/fontes/lexador/dialetos/palavras-reservadas/portugol-studio.ts b/fontes/lexador/dialetos/palavras-reservadas/portugol-studio.ts
index eac8e668..54e5bf24 100644
--- a/fontes/lexador/dialetos/palavras-reservadas/portugol-studio.ts
+++ b/fontes/lexador/dialetos/palavras-reservadas/portugol-studio.ts
@@ -3,5 +3,7 @@ import tiposDeSimbolos from '../../../tipos-de-simbolos/portugol-studio';
 export default {
     escreva: tiposDeSimbolos.ESCREVA,
     funcao: tiposDeSimbolos.FUNCAO,
+    inteiro: tiposDeSimbolos.INTEIRO,
+    leia: tiposDeSimbolos.LEIA,
     programa: tiposDeSimbolos.PROGRAMA,
 }
\ No newline at end of file
diff --git a/fontes/tipos-de-simbolos/portugol-studio.ts b/fontes/tipos-de-simbolos/portugol-studio.ts
index b1079d1d..be03216e 100644
--- a/fontes/tipos-de-simbolos/portugol-studio.ts
+++ b/fontes/tipos-de-simbolos/portugol-studio.ts
@@ -14,6 +14,8 @@ export default {
     IDENTIFICADOR: 'IDENTIFICADOR',
     IGUAL: 'IGUAL',
     IGUAL_IGUAL: 'IGUAL_IGUAL',
+    INTEIRO: 'INTEIRO',
+    LEIA: 'LEIA',
     MAIOR: 'MAIOR',
     MAIOR_IGUAL: 'MAIOR_IGUAL',
     MENOR: 'MENOR',


Test patch:
diff --git a/testes/portugol-studio/avaliador-sintatico.test.ts b/testes/portugol-studio/avaliador-sintatico.test.ts
index 1769f8db..2e755fdb 100644
--- a/testes/portugol-studio/avaliador-sintatico.test.ts
+++ b/testes/portugol-studio/avaliador-sintatico.test.ts
@@ -13,47 +13,68 @@ describe('Avaliador sintático (Portugol Studio)', () => {
             avaliadorSintatico = new AvaliadorSintaticoPortugolStudio();
         });
 
-        it('Sucesso - Olá Mundo', () => {
-            const retornoLexador = lexador.mapear(
-                [
+        describe('Casos de Sucesso', () => {
+            it('Sucesso - Olá Mundo', () => {
+                const retornoLexador = lexador.mapear(
+                    [
+                        'programa',
+                        '{',
+                        '    funcao inicio()',
+                        '    {',
+                        '        escreva("Olá Mundo")',
+                        '    }',
+                        '}'
+                    ],
+                    -1
+                );
+                const retornoAvaliadorSintatico =
+                    avaliadorSintatico.analisar(retornoLexador);
+    
+                expect(retornoAvaliadorSintatico).toBeTruthy();
+                expect(retornoAvaliadorSintatico.declaracoes).toHaveLength(2);
+            });
+
+            it('Sucesso - Leia', () => {
+                const retornoLexador = lexador.mapear([
                     'programa',
                     '{',
-                    '   ', 
                     '    funcao inicio()',
                     '    {',
-                    '        escreva("Olá Mundo")',
+                    '        inteiro numero1, numero2, numero3, numero4, numero5',
+                    '        leia(numero1, numero2, numero3, numero4, numero5)',
+                    '        escreva(numero1 + numero2 + numero3 + numero4 + numero5)',
                     '    }',
                     '}'
-                ],
-                -1
-            );
-            const retornoAvaliadorSintatico =
-                avaliadorSintatico.analisar(retornoLexador);
-
-            expect(retornoAvaliadorSintatico).toBeTruthy();
-            expect(retornoAvaliadorSintatico.declaracoes).toHaveLength(2);
+                ], -1);
+    
+                const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador);
+    
+                expect(retornoAvaliadorSintatico).toBeTruthy();
+                expect(retornoAvaliadorSintatico.declaracoes.length).toBeGreaterThan(0);
+            });
         });
 
-        it('Falha - Função `inicio()` não definida', () => {
-            const retornoLexador = lexador.mapear(
-                [
-                    'programa',
-                    '{',
-                    '   ', 
-                    '    funcao teste()',
-                    '    {',
-                    '        escreva("Olá Mundo")',
-                    '    }',
-                    '}'
-                ],
-                -1
-            );
-
-            const t = () => {
-                avaliadorSintatico.analisar(retornoLexador);
-            };
-
-            expect(t).toThrow(ErroAvaliadorSintatico);
+        describe('Casos de Falha', () => {
+            it('Falha - Função `inicio()` não definida', () => {
+                const retornoLexador = lexador.mapear(
+                    [
+                        'programa',
+                        '{',
+                        '    funcao teste()',
+                        '    {',
+                        '        escreva("Olá Mundo")',
+                        '    }',
+                        '}'
+                    ],
+                    -1
+                );
+    
+                const t = () => {
+                    avaliadorSintatico.analisar(retornoLexador);
+                };
+    
+                expect(t).toThrow(ErroAvaliadorSintatico);
+            });
         });
     });
 });
diff --git a/testes/portugol-studio/interpretador.test.ts b/testes/portugol-studio/interpretador.test.ts
index ffe70063..8882300c 100644
--- a/testes/portugol-studio/interpretador.test.ts
+++ b/testes/portugol-studio/interpretador.test.ts
@@ -1,17 +1,17 @@
 import { AvaliadorSintaticoPortugolStudio } from '../../fontes/avaliador-sintatico/dialetos';
-import { InterpretadorBase } from '../../fontes/interpretador';
 import { LexadorPortugolStudio } from '../../fontes/lexador/dialetos';
+import { InterpretadorPortugolStudio } from '../../fontes/interpretador/dialetos';
 
 describe('Interpretador', () => {
     describe('interpretar()', () => {
         let lexador: LexadorPortugolStudio;
         let avaliadorSintatico: AvaliadorSintaticoPortugolStudio;
-        let interpretador: InterpretadorBase;
+        let interpretador: InterpretadorPortugolStudio;
 
         beforeEach(() => {
             lexador = new LexadorPortugolStudio();
             avaliadorSintatico = new AvaliadorSintaticoPortugolStudio();
-            interpretador = new InterpretadorBase(process.cwd());
+            interpretador = new InterpretadorPortugolStudio(process.cwd());
         });
 
         describe('Cenários de sucesso', () => {
@@ -32,6 +32,34 @@ describe('Interpretador', () => {
 
                 expect(retornoInterpretador.erros).toHaveLength(0);
             });
+
+            it('Sucesso - Leia', async () => {
+                // Aqui vamos simular a resposta para cinco variáveis de `leia()`.
+                const respostas = [1, 2, 3, 4, 5];
+                interpretador.interfaceEntradaSaida = {
+                    question: (mensagem: string, callback: Function) => {
+                        callback(respostas.pop());
+                    }
+                };
+
+                const retornoLexador = lexador.mapear([
+                    'programa',
+                    '{',
+                    '    funcao inicio()',
+                    '    {',
+                    '        inteiro numero1, numero2, numero3, numero4, numero5',
+                    '        leia(numero1, numero2, numero3, numero4, numero5)',
+                    '        escreva(numero1 + numero2 + numero3 + numero4 + numero5)',
+                    '    }',
+                    '}'
+                ], -1);
+
+                const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador);
+
+                const retornoInterpretador = await interpretador.interpretar(retornoAvaliadorSintatico.declaracoes);
+
+                expect(retornoInterpretador.erros).toHaveLength(0);
+            });
         });
     });
 });