From 135d2048fc42f0a3661364436f12d334bdfb8ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Douglas=20Gad=C3=AAlha?= Date: Tue, 30 Apr 2024 20:04:42 -0300 Subject: [PATCH] =?UTF-8?q?Corre=C3=A7=C3=A3o=20nas=20verifica=C3=A7=C3=B5?= =?UTF-8?q?es=20de=20erros=20relacionados=20a=20escopo=20e=20tipos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #196 Closes #206 Closes #207 --- .../app/tab-start/tab-start.component.html | 6 ++- .../parser/src/errors/02-vari\303\241veis.ts" | 48 ++++++++++++++++++- packages/parser/src/helpers/Escopo.ts | 35 +++++++++++++- .../parser/src/helpers/express\303\265es.ts" | 28 ++++++----- 4 files changed, 101 insertions(+), 16 deletions(-) diff --git a/packages/ide/src/app/tab-start/tab-start.component.html b/packages/ide/src/app/tab-start/tab-start.component.html index 5f7415b0..75b989b1 100644 --- a/packages/ide/src/app/tab-start/tab-start.component.html +++ b/packages/ide/src/app/tab-start/tab-start.component.html @@ -94,7 +94,11 @@

Novidades

-

30/04/2024: Melhorias de acessibilidade e ajustes na tela inicial e ícones

+

30/04/2024:

+

10/03/2024: Otimização de desempenho na análise semântica

09/03/2024: Novo domínio: portugol.dev e experimento com propagandas

diff --git "a/packages/parser/src/errors/02-vari\303\241veis.ts" "b/packages/parser/src/errors/02-vari\303\241veis.ts" index 08dd8922..33ebbb7a 100644 --- "a/packages/parser/src/errors/02-vari\303\241veis.ts" +++ "b/packages/parser/src/errors/02-vari\303\241veis.ts" @@ -15,6 +15,7 @@ import { ParaCmd, Parâmetro, ReferênciaVarExpr, + RetorneCmd, SeCmd, } from "../nodes/index.js"; @@ -37,6 +38,19 @@ export function* checarUsoEscopo(arquivo: Arquivo): Generator break; } + case Função: { + const func = nó as Função; + + escopo.funções.set(func.nome, func.retorno); + escopo.push(); + escopo.função = func.retorno; + + yield* varrerNós(nó.children); + + escopo.pop(); + break; + } + case ReferênciaVarExpr: { const ref = nó as ReferênciaVarExpr; @@ -93,7 +107,6 @@ export function* checarUsoEscopo(arquivo: Arquivo): Generator case EnquantoCmd: case EscolhaCmd: case FaçaEnquantoCmd: - case Função: case ParaCmd: { escopo.push(); yield* varrerNós(nó.children); @@ -118,6 +131,39 @@ export function* checarUsoEscopo(arquivo: Arquivo): Generator break; } + case RetorneCmd: { + const ret = nó as RetorneCmd; + + if (ret.expressão) { + yield* varrerNó(ret.expressão); + } + + if (escopo.função) { + try { + const tret = resolverResultadoExpressão(ret.expressão, escopo); + + if ( + TabelaCompatibilidadeAtribuição[escopo.função.primitivo][tret] === ResultadoCompatibilidade.INCOMPATÍVEL + ) { + yield PortugolCodeError.fromContext( + ret.ctx, + `Não é possível retornar um valor do tipo '${tret}' em uma função que retorna '${escopo.função.primitivo}'`, + ); + } + } catch (error) { + const message = error instanceof Error ? error.message : "Não foi possível resolver o tipo da expressão"; + + if (message === "TODO") { + break; + } + + yield PortugolCodeError.fromContext(ret.ctx, message); + } + } + + break; + } + default: { yield* varrerNós(nó.children); break; diff --git a/packages/parser/src/helpers/Escopo.ts b/packages/parser/src/helpers/Escopo.ts index 1ca580e8..6826ab14 100644 --- a/packages/parser/src/helpers/Escopo.ts +++ b/packages/parser/src/helpers/Escopo.ts @@ -3,6 +3,7 @@ import { Tipo, TipoPrimitivo } from "./Tipo.js"; interface IEscopo { variáveis: Map; funções: Map; + função?: Tipo; } export class Escopo { @@ -22,7 +23,11 @@ export class Escopo { } push() { - this.pilha.push({ variáveis: new Map(), funções: new Map() }); + this.pilha.push({ + variáveis: new Map(), + funções: new Map(), + função: this.atual.função, + }); } pop() { @@ -49,6 +54,14 @@ export class Escopo { return this.atual.funções; } + get função(): Tipo | undefined { + return this.atual.função; + } + + set função(tipo: Tipo) { + this.atual.função = tipo; + } + hasVariável(nome: string) { for (const escopo of this.pilha) { if (escopo.variáveis.has(nome)) { @@ -60,14 +73,32 @@ export class Escopo { } hasFunção(nome: string) { - return this.funções.has(nome); + for (const escopo of this.pilha) { + if (escopo.funções.has(nome)) { + return true; + } + } + + return false; } getVariável(nome: string) { + for (const escopo of this.pilha) { + if (escopo.variáveis.has(nome)) { + return escopo.variáveis.get(nome); + } + } + return this.variáveis.get(nome); } getFunção(nome: string) { + for (const escopo of this.pilha) { + if (escopo.funções.has(nome)) { + return escopo.funções.get(nome); + } + } + return this.funções.get(nome); } } diff --git "a/packages/parser/src/helpers/express\303\265es.ts" "b/packages/parser/src/helpers/express\303\265es.ts" index 842c6fa4..6b635bd9 100644 --- "a/packages/parser/src/helpers/express\303\265es.ts" +++ "b/packages/parser/src/helpers/express\303\265es.ts" @@ -1,14 +1,3 @@ -import { - ResultadoCompatibilidade, - TabelaCompatibilidadeBitwise, - TabelaCompatibilidadeDiferençaIgualdade, - TabelaCompatibilidadeDivisãoMultiplicaçãoSubtração, - TabelaCompatibilidadeEOu, - TabelaCompatibilidadeModulo, - TabelaCompatibilidadeSoma, -} from "./compatibilidade.js"; -import { Escopo } from "./Escopo.js"; -import { TipoPrimitivo } from "./Tipo.js"; import { Expressão } from "../nodes/Expressão.js"; import { CadeiaExpr, @@ -50,8 +39,23 @@ import { SubtraçãoExpr, VazioExpr, } from "../nodes/index.js"; +import { Escopo } from "./Escopo.js"; +import { TipoPrimitivo } from "./Tipo.js"; +import { + ResultadoCompatibilidade, + TabelaCompatibilidadeBitwise, + TabelaCompatibilidadeDiferençaIgualdade, + TabelaCompatibilidadeDivisãoMultiplicaçãoSubtração, + TabelaCompatibilidadeEOu, + TabelaCompatibilidadeModulo, + TabelaCompatibilidadeSoma, +} from "./compatibilidade.js"; + +export function resolverResultadoExpressão(expressão: Expressão | undefined, escopo: Escopo): TipoPrimitivo { + if (!expressão) { + return TipoPrimitivo.VAZIO; + } -export function resolverResultadoExpressão(expressão: Expressão, escopo: Escopo): TipoPrimitivo { switch (expressão.constructor) { case CadeiaExpr: { return TipoPrimitivo.CADEIA;