UNPKG

@designliquido/delegua

Version:

Linguagem de programação simples e moderna usando português estruturado.

459 lines 17.5 kB
"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