Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Melhorias gerais no Avaliador Semântico - Delégua #515

Merged
merged 7 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions fontes/analisador-semantico/analisador-semantico.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,49 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
});
}

verificarTipoAtribuido(declaracao: Var | Const) {
if (declaracao.tipo) {
if (['vetor', 'qualquer[]', 'inteiro[]', 'texto[]'].includes(declaracao.tipo)) {
if (declaracao.inicializador instanceof Vetor) {
const vetor = declaracao.inicializador as Vetor;
if (declaracao.tipo === 'inteiro[]') {
const v = vetor.valores.find(v => typeof v?.valor !== 'number')
if(v) {
this.erro(
declaracao.simbolo,
`Atribuição inválida para '${declaracao.simbolo.lexema}', é esperado um vetor de 'inteiros' ou 'real'.`
);
}
}
if (declaracao.tipo === 'texto[]') {
const v = vetor.valores.find(v => typeof v?.valor !== 'string')
if(v) {
this.erro(
declaracao.simbolo,
`Atribuição inválida para '${declaracao.simbolo.lexema}', é esperado um vetor de 'texto'.`
);
}
}
} else {
this.erro(declaracao.simbolo, `Atribuição inválida para '${declaracao.simbolo.lexema}', é esperado um vetor de elementos.`);
}
}
if (declaracao.inicializador instanceof Literal) {
const literal = declaracao.inicializador as Literal;
if (declaracao.tipo === 'texto') {
if (typeof literal.valor !== 'string') {
this.erro(declaracao.simbolo, `Atribuição inválida para '${declaracao.simbolo.lexema}', é esperado um 'texto'.`);
}
}
if (['inteiro', 'real'].includes(declaracao.tipo)) {
if (typeof literal.valor !== 'number') {
this.erro(declaracao.simbolo, `Atribuição inválida '${declaracao.simbolo.lexema}', é esperado um 'número'.`);
}
}
}
}
}

visitarExpressaoTipoDe(expressao: TipoDe): Promise<any> {
return Promise.resolve();
}
Expand Down Expand Up @@ -223,6 +266,9 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
}

visitarDeclaracaoConst(declaracao: Const): Promise<any> {

this.verificarTipoAtribuido(declaracao);

if (this.variaveis.hasOwnProperty(declaracao.simbolo.lexema)) {
this.erros.push({
simbolo: declaracao.simbolo,
Expand All @@ -245,6 +291,9 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
}

visitarDeclaracaoVar(declaracao: Var): Promise<any> {

this.verificarTipoAtribuido(declaracao);

this.variaveis[declaracao.simbolo.lexema] = {
imutavel: false,
tipo: declaracao.tipo,
Expand Down Expand Up @@ -286,6 +335,47 @@ export class AnalisadorSemantico implements AnalisadorSemanticoInterface {
}

visitarDeclaracaoDefinicaoFuncao(declaracao: FuncaoDeclaracao) {
for (let parametro of declaracao.funcao.parametros) {
if(parametro.hasOwnProperty('tipoDado') && !parametro.tipoDado.tipo) {
this.erro(declaracao.simbolo, `O tipo '${parametro.tipoDado.nome}' não é válido.`);
}
}

let tipoRetornoFuncao = declaracao.funcao.tipoRetorno;
if (tipoRetornoFuncao) {
let funcaoContemRetorno = declaracao.funcao.corpo.find((c) => c instanceof Retorna) as Retorna;
if (funcaoContemRetorno) {
if (tipoRetornoFuncao === 'vazio') {
this.erro(declaracao.simbolo, `A função não pode ter nenhum tipo de retorno.`);
return Promise.resolve();
}

const tipoValor = typeof funcaoContemRetorno.valor.valor;
if (!['qualquer'].includes(tipoRetornoFuncao)) {
if (tipoValor === 'string') {
if (tipoRetornoFuncao != 'texto') {
this.erro(
declaracao.simbolo,
`Esperado retorno do tipo '${tipoRetornoFuncao}' dentro da função.`
);
}
}
if (tipoValor === 'number') {
if (!['inteiro', 'real'].includes(tipoRetornoFuncao)) {
this.erro(
declaracao.simbolo,
`Esperado retorno do tipo '${tipoRetornoFuncao}' dentro da função.`
);
}
}
}
} else {
if (tipoRetornoFuncao !== 'vazio') {
this.erro(declaracao.simbolo, `Esperado retorno do tipo '${tipoRetornoFuncao}' dentro da função.`);
}
}
}

return Promise.resolve();
}

Expand Down
127 changes: 15 additions & 112 deletions fontes/avaliador-sintatico/avaliador-sintatico.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import tiposDeSimbolos from '../tipos-de-simbolos/delegua';
import hrtime from 'browser-process-hrtime';

import { AvaliadorSintaticoInterface, ParametroInterface, SimboloInterface } from '../interfaces';
import {
AvaliadorSintaticoInterface,
ParametroInterface,
SimboloInterface,
} from '../interfaces';
import {
AcessoMetodo as AcessoMetodo,
Agrupamento,
Expand Down Expand Up @@ -100,7 +104,7 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface<SimboloIn
return this.simbolos[this.atual + 1].tipo === tipo;
}

verificarDefinicaoTipoAtual(): string {
verificarDefinicaoTipoAtual(): TiposDadosInterface {
const tipos = ['inteiro', 'qualquer', 'real', 'texto', 'vazio', 'vetor'];

const lexema = this.simboloAtual().lexema.toLowerCase();
Expand All @@ -118,20 +122,16 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface<SimboloIn

this.avancarEDevolverAnterior();

return contemTipoVetor;
return contemTipoVetor as TiposDadosInterface;
}

return contemTipo;
return contemTipo as TiposDadosInterface;
}

simboloAtual(): SimboloInterface {
return this.simbolos[this.atual];
}

simboloAnterior(): SimboloInterface {
return this.simbolos[this.atual - 1];
}

estaNoFinal(): boolean {
return this.atual === this.simbolos.length;
}
Expand Down Expand Up @@ -984,52 +984,6 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface<SimboloIn
return this.declaracaoExpressao();
}

verificarTipoAtribuido(tipo: string, inicializador: any) {
if (tipo) {
if (['vetor', 'qualquer[]', 'inteiro[]', 'texto[]'].includes(tipo)) {
if (inicializador instanceof Vetor) {
const vetor = inicializador as Vetor;
if (tipo === 'inteiro[]') {
for (let elemento of vetor.valores) {
if (typeof elemento.valor !== 'number') {
throw this.erro(
this.simboloAtual(),
"Atribuição inválida, é esperado um vetor de 'inteiros' ou 'real'."
);
}
}
}
if (tipo === 'texto[]') {
for (let elemento of vetor.valores) {
if (typeof elemento.valor !== 'string') {
throw this.erro(
this.simboloAtual(),
"Atribuição inválida, é esperado um vetor de 'texto'."
);
}
}
}
} else {
throw this.erro(this.simboloAtual(), 'Atribuição inválida, é esperado um vetor de elementos.');
}
}

if (inicializador instanceof Literal) {
const literal = inicializador as Literal;
if (tipo === 'texto') {
if (typeof literal.valor !== 'string') {
throw this.erro(this.simboloAtual(), "Atribuição inválida, é esperado um 'texto'.");
}
}
if (['inteiro', 'real'].includes(tipo)) {
if (typeof literal.valor !== 'number') {
throw this.erro(this.simboloAtual(), "Atribuição inválida, é esperado um 'número'.");
}
}
}
}
}

/**
* Caso símbolo atual seja `var`, devolve uma declaração de variável.
* @returns Um Construto do tipo Var.
Expand All @@ -1044,11 +998,7 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface<SimboloIn
} while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));

if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.DOIS_PONTOS)) {
const tipoVariavel = this.verificarDefinicaoTipoAtual();
if (!tipoVariavel) {
throw this.erro(this.simboloAtual(), 'Tipo definido na variável não é válido.');
}
tipo = tipoVariavel;
tipo = this.verificarDefinicaoTipoAtual();
this.avancarEDevolverAnterior();
}

Expand All @@ -1073,11 +1023,7 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface<SimboloIn
}

for (let [indice, identificador] of identificadores.entries()) {
const inicializador = inicializadores[indice];

this.verificarTipoAtribuido(tipo, inicializador);

retorno.push(new Var(identificador, inicializador, tipo));
retorno.push(new Var(identificador, inicializadores[indice], tipo));
}

this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.PONTO_E_VIRGULA);
Expand All @@ -1098,11 +1044,7 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface<SimboloIn
} while (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.VIRGULA));

if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.DOIS_PONTOS)) {
const tipoConstante = this.verificarDefinicaoTipoAtual();
if (!tipoConstante) {
throw this.erro(this.simboloAtual(), 'Tipo definido na constante não é válido.');
}
tipo = tipoConstante;
tipo = this.verificarDefinicaoTipoAtual();
this.avancarEDevolverAnterior();
}

Expand All @@ -1122,10 +1064,6 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface<SimboloIn

let retorno: Declaracao[] = [];
for (let [indice, identificador] of identificadores.entries()) {
const inicializador = inicializadores[indice];

this.verificarTipoAtribuido(tipo, inicializador);

retorno.push(new Const(identificador, inicializadores[indice], tipo));
}

Expand Down Expand Up @@ -1174,13 +1112,11 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface<SimboloIn

if (this.verificarSeSimboloAtualEIgualA(tiposDeSimbolos.DOIS_PONTOS)) {
let tipoDadoParametro = this.verificarDefinicaoTipoAtual();

if (!tipoDadoParametro) {
this.erro(this.simboloAtual(), `O tipo '${this.simboloAtual().lexema}' não é válido.`);
} else {
parametro.tipo = tipoDadoParametro as TiposDadosInterface;
this.avancarEDevolverAnterior();
parametro.tipoDado = {
nome: this.simboloAtual().lexema,
tipo: tipoDadoParametro
}
this.avancarEDevolverAnterior();
}

parametros.push(parametro as ParametroInterface);
Expand Down Expand Up @@ -1218,39 +1154,6 @@ export class AvaliadorSintatico implements AvaliadorSintaticoInterface<SimboloIn

const corpo = this.blocoEscopo();

if (tipoRetorno) {
let funcaoContemRetorno = corpo.find((c) => c instanceof Retorna) as Retorna;
if (funcaoContemRetorno) {
if (tipoRetorno === 'vazio') {
throw this.erro(this.simboloAtual(), `A função não pode ter nenhum tipo de retorno.`);
}

const tipoValor = typeof funcaoContemRetorno.valor.valor;
if (!['qualquer'].includes(tipoRetorno)) {
if (tipoValor === 'string') {
if (tipoRetorno != 'texto') {
this.erro(
this.simboloAtual(),
`Esperado retorno do tipo '${tipoRetorno}' dentro da função.`
);
}
}
if (tipoValor === 'number') {
if (!['inteiro', 'real'].includes(tipoRetorno)) {
this.erro(
this.simboloAtual(),
`Esperado retorno do tipo '${tipoRetorno}' dentro da função.`
);
}
}
}
} else {
if (tipoRetorno !== 'vazio') {
this.erro(this.simboloAtual(), `Esperado retorno do tipo '${tipoRetorno}' dentro da função.`);
}
}
}

return new FuncaoConstruto(this.hashArquivo, Number(parenteseEsquerdo.linha), parametros, corpo, tipoRetorno);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -712,8 +712,11 @@ export class AvaliadorSintaticoBirl extends AvaliadorSintaticoBase {
};

const tipo = this.resolveTipo(this.simbolos[this.atual].tipo);

parametro.tipo = this.resolveSimboloInterfaceParaTiposDadosInterface(tipo);
const resolucaoTipo = this.resolveSimboloInterfaceParaTiposDadosInterface(tipo);
parametro.tipoDado = {
nome: this.simbolos[this.atual].lexema,
tipo: resolucaoTipo
}
this.avancarEDevolverAnterior();
parametro.nome = this.simbolos[this.atual];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,11 @@ export class AvaliadorSintaticoPotigol extends AvaliadorSintaticoBase {
);

const tipoParametro = simbolos[indice];
parametro.tipo = this.tiposPotigolParaDelegua[tipoParametro.lexema];
const resolucaoTipo = this.tiposPotigolParaDelegua[tipoParametro.lexema];
parametro.tipoDado = {
nome: simbolos[indice - 2].lexema,
tipo: resolucaoTipo
}
tipagemDefinida = true;
}

Expand Down
6 changes: 5 additions & 1 deletion fontes/interfaces/parametro-interface.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { SimboloInterface } from './simbolo-interface';
import { TiposDadosInterface } from './tipos-dados-interface';

interface TipoDadoParametroInterface {
nome: string;
tipo: TiposDadosInterface;
}
export interface ParametroInterface {
abrangencia: 'padrao' | 'multiplo';
nome: SimboloInterface;
tipo?: TiposDadosInterface;
tipoDado?: TipoDadoParametroInterface;
valorPadrao?: any;
referencia?: boolean;
}
2 changes: 1 addition & 1 deletion fontes/tradutores/tradutor-assemblyscript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ export class TradutorAssemblyScript {
traduzirFuncaoConstruto(funcaoConstruto: FuncaoConstruto): string {
let resultado = 'function(';
for (const parametro of funcaoConstruto.parametros) {
const tipoParametro = this.resolveTipoDeclaracaoVarEContante(parametro.tipo);
const tipoParametro = this.resolveTipoDeclaracaoVarEContante(parametro.tipoDado.tipo);
resultado += `${parametro.nome.lexema}${tipoParametro}, `;
}

Expand Down
Loading
Loading