@designliquido/delegua
Version:
Linguagem de programação simples e moderna usando português estruturado.
459 lines • 17.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AnalisadorSemanticoBase = void 0;
const construtos_1 = require("../construtos");
const declaracoes_1 = require("../declaracoes");
const interfaces_1 = require("../interfaces");
/**
* Essa classe só existe para eliminar redundância entre todos os analisadores
* semânticos. Por padrão, quando um método não é implementado, ao invés de dar erro,
* simplesmente passa por ele (`return Promise.resolve()`).
*/
class AnalisadorSemanticoBase {
diagnosticoJaExiste(simbolo, mensagem) {
return this.diagnosticos.some((d) => d.linha === simbolo.linha &&
d.mensagem === mensagem &&
d.simbolo.lexema === simbolo.lexema);
}
erro(simbolo, mensagem) {
if (this.diagnosticoJaExiste(simbolo, mensagem)) {
return;
}
this.diagnosticos.push({
simbolo: simbolo,
mensagem: mensagem,
hashArquivo: simbolo.hashArquivo,
linha: simbolo.linha,
severidade: interfaces_1.DiagnosticoSeveridade.ERRO,
});
}
aviso(simbolo, mensagem) {
if (this.diagnosticoJaExiste(simbolo, mensagem)) {
return;
}
this.diagnosticos.push({
simbolo: simbolo,
mensagem: mensagem,
hashArquivo: simbolo.hashArquivo,
linha: simbolo.linha,
severidade: interfaces_1.DiagnosticoSeveridade.AVISO,
});
}
sugestao(simbolo, mensagem, correcoes) {
var _a, _b;
if (this.diagnosticoJaExiste(simbolo, mensagem)) {
return;
}
this.diagnosticos.push({
simbolo: simbolo,
mensagem: mensagem,
hashArquivo: simbolo.hashArquivo,
linha: simbolo.linha,
severidade: interfaces_1.DiagnosticoSeveridade.SUGESTAO,
colunaInicio: (_a = correcoes[0]) === null || _a === void 0 ? void 0 : _a.colunaInicio,
colunaFim: (_b = correcoes[0]) === null || _b === void 0 ? void 0 : _b.colunaFim,
correcoes: correcoes,
});
}
comparacaoArgumentosContraParametrosFuncao(simboloFuncao, parametros, argumentos) {
if (parametros.length !== argumentos.length) {
this.erro(simboloFuncao, `Função '${simboloFuncao.lexema}' espera ${parametros.length} parâmetros. Atual: ${argumentos.length}.`);
}
for (let [indice, parametro] of parametros.entries()) {
const argumento = argumentos[indice];
if (argumento) {
// Usando `obterTipoExpressao` para resolver adequadamente o tipo do argumento,
// independentemente de ser um `Literal` (tipo já resolvido), `Variavel` (tipo inferido do
// escopo), `Binario`, `Agrupamento`, ou qualquer outro construto (retorna `null` quando
// o tipo não pode ser determinado em tempo de compilação).
const tipoArgumento = this.obterTipoExpressao(argumento);
// Validar apenas quando ambos os lados têm um tipo específico e determinável.
// Ignorar quando `tipoArgumento` é nulo (por exemplo, resultado de `Chamada`) ou `qualquer`,
// evitando falsos positivos para expressões cujo tipo é desconhecido em tempo de compilação.
if (tipoArgumento && tipoArgumento !== 'qualquer' && parametro.tipoDado) {
if (parametro.tipoDado === 'texto' && tipoArgumento !== 'texto') {
this.erro(simboloFuncao, `O valor passado para o parâmetro '${parametro.nome.lexema}' (${parametro.tipoDado}) é diferente do esperado pela função (${tipoArgumento}).`);
}
else if (['inteiro', 'número', 'real'].includes(parametro.tipoDado)) {
// Delegua suporta conversões implícitas entre tipos numéricos, mas não
// entre texto e número.
if (!['inteiro', 'número', 'real'].includes(tipoArgumento)) {
this.erro(simboloFuncao, `O valor passado para o parâmetro '${parametro.nome.lexema}' (${parametro.tipoDado}) é diferente do esperado pela função (${tipoArgumento}).`);
}
}
}
}
}
}
/**
* Obtém o tipo de uma expressão (pode ser Literal, Variavel, Binario, Leia, etc)
*/
obterTipoExpressao(expressao) {
if (expressao instanceof construtos_1.Literal) {
return expressao.tipo;
}
if (expressao instanceof construtos_1.Variavel) {
const variavel = this.gerenciadorEscopos.buscar(expressao.simbolo.lexema);
return (variavel === null || variavel === void 0 ? void 0 : variavel.tipo) || null;
}
if (expressao instanceof construtos_1.Binario) {
// Para binários, tentamos inferir o tipo baseado nos operandos
return this.inferirTipoBinario(expressao);
}
if (expressao instanceof construtos_1.Logico) {
// Operadores lógicos sempre retornam tipo lógico
return 'lógico';
}
if (expressao instanceof construtos_1.Agrupamento) {
return this.obterTipoExpressao(expressao.expressao);
}
if (expressao instanceof construtos_1.Leia) {
// leia() sempre retorna texto
return 'texto';
}
return null;
}
/**
* Infere o tipo de resultado de uma operação binária
*/
inferirTipoBinario(binario) {
const operadoresMatematicos = ['ADICAO', 'SUBTRACAO', 'MULTIPLICACAO', 'DIVISAO', 'MODULO'];
const operadoresComparacao = [
'MAIOR',
'MAIOR_IGUAL',
'MENOR',
'MENOR_IGUAL',
'IGUAL',
'DIFERENTE',
];
// Operadores de comparação sempre retornam lógico
if (operadoresComparacao.includes(binario.operador.tipo)) {
return 'lógico';
}
const tipoEsquerda = this.obterTipoExpressao(binario.esquerda);
const tipoDireita = this.obterTipoExpressao(binario.direita);
if (!tipoEsquerda || !tipoDireita) {
return null;
}
if (operadoresMatematicos.includes(binario.operador.tipo)) {
const tiposNumericos = ['inteiro', 'número', 'real'];
if (tiposNumericos.includes(tipoEsquerda) && tiposNumericos.includes(tipoDireita)) {
// Se um dos lados é 'real', o resultado é 'real'
if (tipoEsquerda === 'real' || tipoDireita === 'real') {
return 'real';
}
return 'número';
}
// Concatenação de textos
if (tipoEsquerda === 'texto' || tipoDireita === 'texto') {
return 'texto';
}
}
return 'qualquer';
}
/**
* Marca as variáveis usadas em uma expressão.
*/
marcarVariaveisUsadasEmExpressao(expressao) {
if (expressao instanceof construtos_1.Variavel) {
this.gerenciadorEscopos.marcarComoUsada(expressao.simbolo.lexema);
return;
}
if (expressao instanceof construtos_1.Binario) {
this.marcarVariaveisUsadasEmExpressao(expressao.esquerda);
this.marcarVariaveisUsadasEmExpressao(expressao.direita);
return;
}
if (expressao instanceof construtos_1.Agrupamento) {
this.marcarVariaveisUsadasEmExpressao(expressao.expressao);
return;
}
if (expressao instanceof construtos_1.Chamada) {
this.marcarVariaveisUsadasEmExpressao(expressao.entidadeChamada);
for (const arg of expressao.argumentos) {
this.marcarVariaveisUsadasEmExpressao(arg);
}
return;
}
if (expressao instanceof construtos_1.AcessoMetodo ||
expressao instanceof construtos_1.AcessoMetodoOuPropriedade ||
expressao instanceof construtos_1.AcessoPropriedade) {
this.marcarVariaveisUsadasEmExpressao(expressao.objeto);
return;
}
if (expressao instanceof construtos_1.Logico) {
this.marcarVariaveisUsadasEmExpressao(expressao.esquerda);
this.marcarVariaveisUsadasEmExpressao(expressao.direita);
return;
}
if (expressao instanceof construtos_1.Unario) {
this.marcarVariaveisUsadasEmExpressao(expressao.operando);
return;
}
if (expressao instanceof construtos_1.AcessoIndiceVariavel) {
this.marcarVariaveisUsadasEmExpressao(expressao.entidadeChamada);
this.marcarVariaveisUsadasEmExpressao(expressao.indice);
return;
}
if (expressao instanceof construtos_1.AjudaComoConstruto) {
if (expressao.valor) {
this.marcarVariaveisUsadasEmExpressao(expressao.valor);
}
return;
}
// TODO: Adicionar outros tipos de expressões conforme necessário.
}
/**
* Analisa se todos os caminhos retornam
* @returns true se todos os caminhos retornam, false caso contrário
*/
todosOsCaminhosRetornam(declaracoes) {
return this.verificarBlocoRetorna(declaracoes);
}
verificarBlocoRetorna(declaracoes) {
for (let i = 0; i < declaracoes.length; i++) {
const declaracao = declaracoes[i];
if (declaracao instanceof declaracoes_1.Retorna) {
return true;
}
if (declaracao instanceof declaracoes_1.Se) {
const todosOsCaminhosSe = this.verificarSeRetorna(declaracao);
if (todosOsCaminhosSe) {
return true;
}
}
if (declaracao instanceof declaracoes_1.Escolha) {
const todosOsCaminhosEscolha = this.verificarEscolhaRetorna(declaracao);
if (todosOsCaminhosEscolha) {
return true;
}
}
}
return false;
}
verificarSeRetorna(declaracaoSe) {
var _a, _b;
const caminhoEntaoResolvido = declaracaoSe.caminhoEntao;
const entaoRetorna = this.verificarBlocoRetorna(caminhoEntaoResolvido.declaracoes);
const caminhoSenaoResolvido = declaracaoSe.caminhoSenao;
if (!caminhoSenaoResolvido || ((_a = caminhoSenaoResolvido.declaracoes) === null || _a === void 0 ? void 0 : _a.length) === 0) {
return false;
}
if (caminhoSenaoResolvido instanceof declaracoes_1.Se &&
((_b = caminhoSenaoResolvido.caminhoEntao.declaracoes) === null || _b === void 0 ? void 0 : _b.length) === 1) {
const senaoSeRetorna = this.verificarSeRetorna(caminhoSenaoResolvido);
return entaoRetorna && senaoSeRetorna;
}
const senaoRetorna = this.verificarBlocoRetorna(declaracaoSe.caminhoSenao.declaracoes);
return entaoRetorna && senaoRetorna;
}
verificarEscolhaRetorna(declaracaoEscolha) {
let temPadrao = false;
// Verifica se todos os caminhos retornam
for (let caminho of declaracaoEscolha.caminhos) {
const caminhoRetorna = this.verificarBlocoRetorna(caminho.declaracoes);
if (!caminhoRetorna) {
return false;
}
// Verifica se há um caso padrão
if (caminho.condicoes.length === 0) {
temPadrao = true;
}
}
// Se não há caso padrão, não podemos garantir que todos os caminhos retornam
return temPadrao;
}
visitarDeclaracaoTextoDocumentacao(declaracao) {
return Promise.resolve();
}
visitarExpressaoAcessoIntervaloVariavel(expressao) {
return Promise.resolve();
}
visitarExpressaoTuplaN(expressao) {
return Promise.resolve();
}
visitarExpressaoComentario(expressao) {
// Comentários não afetam a análise semântica, então não faz nada.
return Promise.resolve();
}
visitarExpressaoSeparador(expressao) {
// Separadores não afetam a análise semântica, então não faz nada.
return Promise.resolve();
}
adicionarDiagnostico(simbolo, mensagem, severidade = interfaces_1.DiagnosticoSeveridade.AVISO) {
this.diagnosticos.push({
simbolo: simbolo,
mensagem: mensagem,
hashArquivo: simbolo.hashArquivo,
linha: simbolo.linha,
severidade: severidade,
});
}
visitarExpressaoArgumentoReferenciaFuncao(expressao) {
return Promise.resolve();
}
visitarExpressaoReferenciaFuncao(expressao) {
return Promise.resolve();
}
visitarExpressaoAcessoMetodo(expressao) {
return Promise.resolve();
}
visitarExpressaoAcessoPropriedade(expressao) {
return Promise.resolve();
}
visitarDeclaracaoCabecalhoPrograma(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoClasse(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoComentario(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoConst(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoConstMultiplo(declaracao) {
return Promise.resolve();
}
visitarExpressaoDeAtribuicao(expressao) {
return Promise.resolve();
}
visitarDeclaracaoDeExpressao(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoDefinicaoFuncao(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoEnquanto(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoEscolha(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoEscreva(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoFazer(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoImportar(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoInicioAlgoritmo(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoPara(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoParaCada(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoSe(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoTendoComo(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoTente(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoVar(declaracao) {
return Promise.resolve();
}
visitarDeclaracaoVarMultiplo(declaracao) {
return Promise.resolve();
}
visitarExpressaoAcessoIndiceVariavel(expressao) {
return Promise.resolve();
}
visitarExpressaoAcessoElementoMatriz(expressao) {
return Promise.resolve();
}
visitarExpressaoAcessoMetodoOuPropriedade(expressao) {
return Promise.resolve();
}
visitarExpressaoAgrupamento(expressao) {
return Promise.resolve();
}
visitarExpressaoAtribuicaoPorIndice(expressao) {
return Promise.resolve();
}
visitarExpressaoAtribuicaoPorIndicesMatriz(expressao) {
return Promise.resolve();
}
visitarExpressaoBinaria(expressao) {
return Promise.resolve();
}
visitarExpressaoBloco(declaracao) {
return Promise.resolve();
}
visitarExpressaoContinua(declaracao) {
return null;
}
visitarExpressaoDeChamada(expressao) {
return Promise.resolve();
}
visitarExpressaoDefinirValor(expressao) {
return Promise.resolve();
}
visitarExpressaoFuncaoConstruto(expressao) {
return Promise.resolve();
}
visitarExpressaoDeVariavel(expressao) {
return Promise.resolve();
}
visitarExpressaoDicionario(expressao) {
return Promise.resolve();
}
visitarExpressaoExpressaoRegular(expressao) {
return;
}
visitarDeclaracaoEscrevaMesmaLinha(declaracao) {
return Promise.resolve();
}
visitarExpressaoFalhar(expressao) {
return Promise.resolve();
}
visitarExpressaoFimPara(declaracao) {
return Promise.resolve();
}
visitarExpressaoFormatacaoEscrita(declaracao) {
return Promise.resolve();
}
visitarExpressaoIsto(expressao) {
return Promise.resolve();
}
visitarExpressaoLeia(expressao) {
return Promise.resolve();
}
visitarExpressaoLiteral(expressao) {
return Promise.resolve();
}
visitarExpressaoLogica(expressao) {
return Promise.resolve();
}
visitarExpressaoRetornar(declaracao) {
return;
}
visitarExpressaoSuper(expressao) {
return Promise.resolve();
}
visitarExpressaoSustar(declaracao) {
return null;
}
visitarExpressaoTupla(expressao) {
return Promise.resolve();
}
visitarExpressaoTipoDe(expressao) {
return Promise.resolve();
}
visitarExpressaoUnaria(expressao) {
return Promise.resolve();
}
visitarExpressaoVetor(expressao) {
return Promise.resolve();
}
}
exports.AnalisadorSemanticoBase = AnalisadorSemanticoBase;
//# sourceMappingURL=analisador-semantico-base.js.map