Repository: DesignLiquido/delegua
Pull request #466 (2023-07-22 19:30:06)

Valida atribuições


Patch:
diff --git a/fontes/analisador-semantico/analisador-semantico.ts b/fontes/analisador-semantico/analisador-semantico.ts
index 70e47dca..6bd37676 100644
--- a/fontes/analisador-semantico/analisador-semantico.ts
+++ b/fontes/analisador-semantico/analisador-semantico.ts
@@ -1,4 +1,4 @@
-import { Atribuir, FimPara, FormatacaoEscrita, Literal, Super, TipoDe } from '../construtos';
+import { Atribuir, FimPara, FormatacaoEscrita, Literal, Super, TipoDe, Vetor } from '../construtos';
 import {
     Bloco,
     Classe,
@@ -22,6 +22,7 @@ import {
     Tente,
     Var,
 } from '../declaracoes';
+import { SimboloInterface } from '../interfaces';
 import { AnalisadorSemanticoInterface } from '../interfaces/analisador-semantico-interface';
 import { ErroAnalisadorSemantico } from '../interfaces/erros';
 import { RetornoAnalisadorSemantico } from '../interfaces/retornos/retorno-analisador-semantico';
@@ -48,6 +49,15 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
         this.erros = [];
     }
 
+    erro(simbolo: SimboloInterface, mensagemDeErro: string): void {
+        this.erros.push({
+            simbolo: simbolo,
+            mensagem: mensagemDeErro,
+            hashArquivo: simbolo.hashArquivo,
+            linha: simbolo.linha,
+        });
+    }
+
     visitarExpressaoTipoDe(expressao: TipoDe): Promise<any> {
         return Promise.resolve();
     }
@@ -74,25 +84,59 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
     }
 
     visitarDeclaracaoDeAtribuicao(expressao: Atribuir) {
-        if (!this.variaveis.hasOwnProperty(expressao.simbolo.lexema)) {
-            this.erros.push({
-                simbolo: expressao.simbolo,
-                mensagem: `Variável ${expressao.simbolo.lexema} ainda não foi declarada até este ponto.`,
-                hashArquivo: expressao.hashArquivo,
-                linha: expressao.linha,
-            });
-
+        let valor = this.variaveis[expressao.simbolo.lexema];
+        if (!valor) {
+            this.erro(expressao.simbolo, `Variável ${expressao.simbolo.lexema} ainda não foi declarada até este ponto.`)
             return Promise.resolve();
         }
 
-        if (this.variaveis[expressao.simbolo.lexema].imutavel) {
-            this.erros.push({
-                simbolo: expressao.simbolo,
-                mensagem: `Constante ${expressao.simbolo.lexema} não pode ser modificada.`,
-                hashArquivo: expressao.hashArquivo,
-                linha: expressao.linha,
-            });
+        if (valor.tipo) {            
+            if(expressao.valor instanceof Literal && valor.tipo.includes('[]')) {
+                this.erro(expressao.simbolo, `Atribuição inválida, esperado tipo '${valor.tipo}' na atribuição.`)
+                return Promise.resolve();                
+            }
+            if(expressao.valor instanceof Vetor && !valor.tipo.includes('[]')) {
+                this.erro(expressao.simbolo, `Atribuição inválida, esperado tipo '${valor.tipo}' na atribuição.`)
+                return Promise.resolve();                
+            }
+            if (expressao.valor instanceof Literal) {
+                let valorLiteral = typeof (expressao.valor as Literal).valor;
+                if (!['qualquer'].includes(valor.tipo)) {
+                    if(valorLiteral === 'string') {
+                        if(valor.tipo != 'texto') {
+                            this.erro(expressao.simbolo, `Esperado tipo '${valor.tipo}' na atribuição.`)
+                            return Promise.resolve();
+                        }
+                    }
+                    if (valorLiteral === 'number') {
+                        if (!['inteiro', 'real'].includes(valor.tipo)) {
+                            this.erro(expressao.simbolo, `Esperado tipo '${valor.tipo}' na atribuição.`)
+                            return Promise.resolve();
+                        }
+                    }
+                }
+            }
+            if (expressao.valor instanceof Vetor) {
+                let valores = (expressao.valor as Vetor).valores;
+                if (!['qualquer[]'].includes(valor.tipo)) {
+                    if (valor.tipo === 'texto[]') {
+                        if (!valores.every(v => typeof v.valor === 'string')) {
+                            this.erro(expressao.simbolo, `Esperado tipo '${valor.tipo}' na atribuição.`)
+                            return Promise.resolve();
+                        }
+                    }
+                    if (['inteiro[]', 'numero[]'].includes(valor.tipo)) {
+                        if(!valores.every(v => typeof v.valor === 'number')) {
+                            this.erro(expressao.simbolo, `Esperado tipo '${valor.tipo}' na atribuição.`)
+                            return Promise.resolve();
+                        }
+                    }
+                }
+            }
+        }
 
+        if (valor.imutavel) {
+            this.erro(expressao.simbolo, `Constante ${expressao.simbolo.lexema} não pode ser modificada.`)
             return Promise.resolve();
         }
     }


Test patch:
diff --git a/testes/analisador-semantico.test.ts b/testes/analisador-semantico.test.ts
index f0b2bdee..7ea18dc4 100644
--- a/testes/analisador-semantico.test.ts
+++ b/testes/analisador-semantico.test.ts
@@ -24,6 +24,35 @@ describe('Analisador semântico', () => {
                 expect(retornoAnalisadorSemantico.erros).toHaveLength(0);
             });
 
+            it('Sucesso - Atribuindo variável que não existe', () => {
+                const retornoLexador = lexador.mapear([
+                    "b = 1"
+                ], -1);
+                const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+    
+                expect(retornoAnalisadorSemantico).toBeTruthy();
+                expect(retornoAnalisadorSemantico.erros).toHaveLength(1);
+            });
+
+            it('Sucesso - Atribuindo tipos válidos para variáveis', () => {
+                const retornoLexador = lexador.mapear([
+                    "var a: inteiro = 1",
+                    "a = 123",
+                    "var b: texto = 'abc'",
+                    "b = 'cde'",
+                    "var f: inteiro[] = [0, 2]",
+                    "f = [3, 4]",
+                    "var g: texto[] = ['a', 'b']",
+                    "g = ['1', '2']"
+                ], -1);
+                const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+    
+                expect(retornoAnalisadorSemantico).toBeTruthy();
+                expect(retornoAnalisadorSemantico.erros).toHaveLength(0);
+            });
+
             it('Sucesso - Função com definição de tipos', () => {
                 const retornoLexador = lexador.mapear([
                     // "var a = funcao (valor1: inteiro, valor2: qualquer, valor3: texto): texto {",
@@ -57,6 +86,32 @@ describe('Analisador semântico', () => {
                 expect(retornoAnalisadorSemantico.erros).toHaveLength(1);
             });
 
+            it('Atribuindo tipos inválidos para variáveis', () => {
+                const retornoLexador = lexador.mapear([
+                    "var a: inteiro = 123",
+                    "a = 'abc'",
+                    "var b: texto = 'abc'",
+                    "b = 123",
+                    "var f: inteiro[] = [0, 2]",
+                    "f = 1",
+                    "var g: texto[] = ['a', 'b']",
+                    "g = '2'",
+                    "var h: inteiro = 1",
+                    "h = [1, 2, 3]",
+                    "var i: texto = 'abc'",
+                    "i = ['1', '2']",
+                    "var j: inteiro[] = [1, 2]",
+                    "j = ['3', '4']",
+                    "var k: texto[] = ['1', '2']",
+                    "k = [3, 4]"
+                ], -1);
+                const retornoAvaliadorSintatico = avaliadorSintatico.analisar(retornoLexador, -1);
+                const retornoAnalisadorSemantico = analisadorSemantico.analisar(retornoAvaliadorSintatico.declaracoes);
+    
+                expect(retornoAnalisadorSemantico).toBeTruthy();
+                expect(retornoAnalisadorSemantico.erros).toHaveLength(8);
+            });
+
             it.skip('Retorno vazio', () => {
                 const retornoLexador = lexador.mapear([
                     "funcao olaMundo (): vazio {",