"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,
        });
    }
    /**
    * 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;
        }
        // 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