online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
-- ============================================================================ -- Arquivo: Main.hs -- Descrição: Arquivo principal com TODAS as operações de I/O -- Responsável: Aluno 3 (Jafte Carneiro Fagundes da Silva) -- Objetivo: Gerenciar TODA a interação com arquivos, usuário e sistema -- ============================================================================ import InventarioTipos import LogicaNegocio import IOPersistencia (Comando(..), parseComando, arquivoInventario, arquivoAuditoria) import qualified Data.Map as Map import Analise (formatarRelatorioCompleto, historicoPorItem, formatarLog) import Data.Time (getCurrentTime, UTCTime, TimeZone(..)) import System.IO (hFlush, stdout) import Control.Exception (catch, IOException) -- FUNÇÕES DE INICIALIZAÇÃO carregarInventario :: IO Inventario carregarInventario = do conteudo <- catch (readFile arquivoInventario) handleArquivoNaoExiste if null conteudo then do putStrLn "[INFO] Iniciando com inventario vazio." return emptyInventario else do putStrLn "[INFO] Inventario carregado com sucesso!" return (read conteudo :: Inventario) where handleArquivoNaoExiste :: IOException -> IO String handleArquivoNaoExiste _ = do putStrLn "[INFO] Arquivo Inventario.dat nao encontrado." return "" carregarLogs :: IO [LogEntry] carregarLogs = do conteudo <- catch (readFile arquivoAuditoria) handleArquivoNaoExiste if null conteudo then do putStrLn "[INFO] Iniciando com log de auditoria vazio." return [] else do putStrLn "[INFO] Log de auditoria carregado com sucesso!" let linhas = lines conteudo let parseLinha l = case reads l of [(log, "")] -> Just log _ -> Nothing let logsMaybe = map parseLinha linhas let logs = [log | Just log <- logsMaybe] let falhas = length linhas - length logs if falhas > 0 then putStrLn $ "[AVISO] Ignoradas " ++ show falhas ++ " linhas mal formatadas no Auditoria.log." else return () return logs where handleArquivoNaoExiste :: IOException -> IO String handleArquivoNaoExiste _ = do putStrLn "[INFO] Arquivo Auditoria.log nao encontrado." return "" -- FUNÇÕES DE PERSISTÊNCIA salvarInventario :: Inventario -> IO () salvarInventario inventario = do writeFile arquivoInventario (show inventario) putStrLn "[PERSISTENCIA] Inventario salvo em Inventario.dat" adicionarLogAuditoria :: LogEntry -> IO () adicionarLogAuditoria logEntry = do appendFile arquivoAuditoria (show logEntry ++ "\n") putStrLn "[AUDITORIA] Log registrado em Auditoria.log" -- FUNÇÕES AUXILIARES DE EXIBIÇÃO imprimirItem :: Item -> IO () imprimirItem item = do putStrLn $ " ID: " ++ itemID item putStrLn $ " Nome: " ++ nome item putStrLn $ " Quantidade: " ++ show (quantidade item) putStrLn $ " Categoria: " ++ categoria item putStrLn " ---" mostrarAjuda :: IO () mostrarAjuda = do putStrLn "\n========== COMANDOS DISPONIVEIS ==========" putStrLn "add <ID> <nome> <quantidade> <categoria>" putStrLn " - Adiciona um novo item ao inventario" putStrLn " - Exemplo: add 001 Teclado 10 Perifericos" putStrLn "" putStrLn "remove <ID> <quantidade>" putStrLn " - Remove uma quantidade de um item" putStrLn " - Exemplo: remove 001 5" putStrLn "" putStrLn "update <ID> <nova_quantidade>" putStrLn " - Atualiza a quantidade de um item" putStrLn " - Exemplo: update 001 20" putStrLn "" putStrLn "list" putStrLn " - Lista todos os itens do inventario" putStrLn "" putStrLn "report" putStrLn " - Gera relatorio de logs" putStrLn "" putStrLn "help" putStrLn " - Mostra esta mensagem de ajuda" putStrLn "" putStrLn "exit" putStrLn " - Encerra o programa" putStrLn "==========================================\n" -- PROCESSAMENTO DE COMANDOS processarComando :: Comando -> Inventario -> IO Inventario processarComando cmd inventario = do tempo <- getCurrentTime case cmd of CmdAdd idItem nomeItem qtd cat -> do let novoItem = Item { itemID = idItem , nome = nomeItem , quantidade = qtd , categoria = cat } case addItem tempo novoItem inventario of Left erro -> do putStrLn $ "\n[ERRO] " ++ erro let logEntry = LogEntry { timestamp = tempo , acao = Add , detalhes = "Falha ao adicionar item ID: " ++ idItem , status = Falha erro } adicionarLogAuditoria logEntry return inventario Right (novoInventario, logEntry) -> do putStrLn $ "\n[SUCESSO] Item adicionado: " ++ nomeItem ++ " (ID: " ++ idItem ++ ")" salvarInventario novoInventario adicionarLogAuditoria logEntry return novoInventario CmdRemove idItem qtd -> do case removeItem tempo idItem qtd inventario of Left erro -> do putStrLn $ "\n[ERRO] " ++ erro let logEntry = LogEntry { timestamp = tempo , acao = Remove , detalhes = "Falha ao remover do item ID: " ++ idItem , status = Falha erro } adicionarLogAuditoria logEntry return inventario Right (novoInventario, logEntry) -> do putStrLn $ "\n[SUCESSO] Removidas " ++ show qtd ++ " unidade(s) do item ID: " ++ idItem salvarInventario novoInventario adicionarLogAuditoria logEntry return novoInventario CmdUpdate idItem novaQtd -> do case updateQty tempo idItem novaQtd inventario of Left erro -> do putStrLn $ "\n[ERRO] " ++ erro let logEntry = LogEntry { timestamp = tempo , acao = Update , detalhes = "Falha ao atualizar item ID: " ++ idItem , status = Falha erro } adicionarLogAuditoria logEntry return inventario Right (novoInventario, logEntry) -> do putStrLn $ "\n[SUCESSO] Quantidade do item ID: " ++ idItem ++ " atualizada para " ++ show novaQtd salvarInventario novoInventario adicionarLogAuditoria logEntry return novoInventario CmdList -> do putStrLn "\n========== INVENTARIO ATUAL ==========" if Map.null inventario then putStrLn "Inventario vazio." else mapM_ imprimirItem (Map.elems inventario) putStrLn "======================================\n" return inventario CmdReport -> do putStrLn "\n[INFO] Carregando logs para gerar relatorio..." logs <- carregarLogs let tz = TimeZone { timeZoneMinutes = -180, timeZoneSummerOnly = False, timeZoneName = "BRT" } -- Gera o relatório usando o módulo Analise.hs if null logs then putStrLn "\n[INFO] Nenhum log encontrado para gerar relatorio." else do -- Gera o relatório principal putStrLn $ formatarRelatorioCompleto tz logs putStrLn "\nDigite um ID de item para ver seu historico (ou aperte o ENTER para pular):" putStr "> " hFlush stdout idInput <- getLine if null idInput then return inventario else do let historico = historicoPorItem logs idInput putStrLn $ "\n--- Historico para Item ID: " ++ idInput ++ " ---" if null historico then putStrLn "Nenhum registro encontrado para este item." else -- Imprime cada log formatado mapM_ (putStrLn . (" " ++) . formatarLog tz) historico putStrLn "---------------------------------------------" return inventario CmdHelp -> do mostrarAjuda return inventario CmdExit -> do putStrLn "\n[INFO] Encerrando o sistema..." return inventario CmdInvalido msg -> do putStrLn $ "\n[ERRO] " ++ msg putStrLn "Digite 'help' para ver os comandos disponiveis.\n" return inventario -- LOOP PRINCIPAL loopPrincipal :: Inventario -> IO () loopPrincipal inventario = do putStr "\n> " hFlush stdout input <- getLine let cmd = parseComando input if cmd == CmdExit then do putStrLn "\n[INFO] Sistema encerrado com sucesso!" putStrLn "Ate logo!\n" else do novoInventario <- processarComando cmd inventario loopPrincipal novoInventario -- FUNÇÃO MAIN - PONTO DE ENTRADA main :: IO () main = do putStrLn "\n==========================================" putStrLn " SISTEMA DE GERENCIAMENTO DE INVENTARIO" putStrLn "==========================================" putStrLn "" putStrLn "[INICIALIZACAO] Carregando dados do sistema..." inventario <- carregarInventario logs <- carregarLogs putStrLn $ "[INFO] Inventario contem " ++ show (Map.size inventario) ++ " item(ns)" putStrLn $ "[INFO] Log contem " ++ show (length logs) ++ " entrada(s)" putStrLn "" putStrLn "Digite 'help' para ver os comandos disponiveis." loopPrincipal inventario
-- ============================================================================ -- Módulo: IOPersistencia.hs -- Descrição: Funções PURAS para parsing de comandos -- Responsável: Aluno 3 (Jafte Carneiro Fagundes da Silva) -- ============================================================================ module IOPersistencia ( Comando(..) , parseComando , arquivoInventario , arquivoAuditoria ) where -- ============================================================================ -- CONSTANTES -- ============================================================================ -- Nome do arquivo de inventário (sobrescrito a cada operação) arquivoInventario :: FilePath arquivoInventario = "Inventario.dat" -- Nome do arquivo de auditoria (modo append-only) arquivoAuditoria :: FilePath arquivoAuditoria = "Auditoria.log" -- ============================================================================ -- TIPOS DE DADOS -- ============================================================================ -- ADT representando todos os comandos possíveis do sistema data Comando = CmdAdd String String Int String -- add <ID> <nome> <qtd> <categoria> | CmdRemove String Int -- remove <ID> <qtd> | CmdUpdate String Int -- update <ID> <nova_qtd> | CmdList -- list | CmdReport -- report | CmdHelp -- help | CmdExit -- exit | CmdInvalido String -- comando inválido deriving (Show, Eq) -- ============================================================================ -- PARSER DE COMANDOS -- ============================================================================ -- Transforma a entrada do usuário em um Comando -- Função pura: mesma entrada sempre produz mesma saída parseComando :: String -> Comando parseComando input = let tokens = words input in case tokens of ("add":idItem:nomeItem:qtd:cat:_) -> case reads qtd of [(quantidade, "")] -> CmdAdd idItem nomeItem quantidade (unwords (drop 4 tokens)) _ -> CmdInvalido "Quantidade invalida para comando 'add'" ("remove":idItem:qtd:_) -> case reads qtd of [(quantidade, "")] -> CmdRemove idItem quantidade _ -> CmdInvalido "Quantidade invalida para comando 'remove'" ("update":idItem:qtd:_) -> case reads qtd of [(quantidade, "")] -> CmdUpdate idItem quantidade _ -> CmdInvalido "Quantidade invalida para comando 'update'" ["list"] -> CmdList ["report"] -> CmdReport ["help"] -> CmdHelp ["exit"] -> CmdExit [] -> CmdInvalido "Comando vazio" _ -> CmdInvalido ("Comando desconhecido: " ++ unwords tokens)
-- Módulo: LogicaNegocio.hs -- Implementa a lógica de negócio pura do sistema de inventário -- Responsável: Aluno 2 module LogicaNegocio ( ResultadoOperacao , addItem , removeItem , updateQty ) where import InventarioTipos import qualified Data.Map as Map import Data.Time (UTCTime) type ResultadoOperacao = (Inventario, LogEntry) -- | Adiciona um item ao inventário. -- Retorna Left com mensagem de erro se falhar. -- Retorna Right com inventário atualizado e log de sucesso. addItem :: UTCTime -> Item -> Inventario -> Either String ResultadoOperacao addItem tempo novoItem inventario | quantidade novoItem < 0 = Left "Quantidade deve ser maior ou igual a zero" | Map.member (itemID novoItem) inventario = Left "Item com ID ja existe no inventario" | otherwise = let inventarioNovo = Map.insert (itemID novoItem) novoItem inventario logEntry = LogEntry { timestamp = tempo , acao = Add , detalhes = "Adicionado item '" ++ nome novoItem ++ "' (ID: " ++ itemID novoItem ++ ") com quantidade " ++ show (quantidade novoItem) ++ " na categoria " ++ categoria novoItem , status = Sucesso } in Right (inventarioNovo, logEntry) -- | Remove uma quantidade de um item do inventário. -- Retorna Left com mensagem de erro se falhar. -- Retorna Right com inventário atualizado e log de sucesso. removeItem :: UTCTime -> String -> Int -> Inventario -> Either String ResultadoOperacao removeItem tempo idItem qtdRemover inventario | qtdRemover <= 0 = Left "Quantidade a remover deve ser maior que zero" | otherwise = case Map.lookup idItem inventario of Nothing -> Left "Item nao encontrado no inventario" Just itemAtual | quantidade itemAtual < qtdRemover -> Left "Estoque insuficiente" | otherwise -> let novaQuantidade = quantidade itemAtual - qtdRemover itemAtualizado = itemAtual { quantidade = novaQuantidade } inventarioNovo = Map.insert idItem itemAtualizado inventario logEntry = LogEntry { timestamp = tempo , acao = Remove , detalhes = "Removidas " ++ show qtdRemover ++ " unidades do item '" ++ nome itemAtual ++ "' (ID: " ++ idItem ++ ")" , status = Sucesso } in Right (inventarioNovo, logEntry) -- | Atualiza a quantidade de um item no inventário. -- Retorna Left com mensagem de erro se falhar. -- Retorna Right com inventário atualizado e log de sucesso. updateQty :: UTCTime -> String -> Int -> Inventario -> Either String ResultadoOperacao updateQty tempo idItem novaQtd inventario | novaQtd < 0 = Left "Quantidade deve ser maior ou igual a zero" | otherwise = case Map.lookup idItem inventario of Nothing -> Left "Item nao encontrado no inventario" Just itemAtual -> let itemAtualizado = itemAtual { quantidade = novaQtd } inventarioNovo = Map.insert idItem itemAtualizado inventario logEntry = LogEntry { timestamp = tempo , acao = Update , detalhes = "Atualizada quantidade do item '" ++ nome itemAtual ++ "' (ID: " ++ idItem ++ ") para " ++ show novaQtd , status = Sucesso } in Right (inventarioNovo, logEntry)
-- Módulo: InventarioTipos.hs -- Descrição: Define os tipos de dados do sistema de inventário module InventarioTipos ( Item(..) , Inventario , AcaoLog(..) , StatusLog(..) , LogEntry(..) , emptyInventario , exemploItem , exemploLog ) where -- Importações import Data.Map (Map) import qualified Data.Map as Map import Data.Time (UTCTime) -- Definição dos Tipos de Dados -- Tipo: Item -- Descrição: Representa um item no inventário data Item = Item { itemID :: String , nome :: String , quantidade :: Int , categoria :: String } deriving (Show, Read, Eq) -- Tipo: Inventario -- Descrição: Representa o inventário como um mapa de itens -- Implementação: Map usando itemID como chave e Item como valor type Inventario = Map String Item -- Função auxiliar para criar um inventário vazio emptyInventario :: Inventario emptyInventario = Map.empty -- Tipo: AcaoLog (ADT) -- Descrição: Tipo algébrico para representar as diferentes ações do sistema data AcaoLog = Add | Remove | Update | QueryFail deriving (Show, Read, Eq) -- Tipo: StatusLog (ADT) -- Descrição: Tipo algébrico para representar o resultado de uma operação data StatusLog = Sucesso | Falha String deriving (Show, Read, Eq) -- Tipo: LogEntry -- Descrição: Representa uma entrada de log no sistema data LogEntry = LogEntry { timestamp :: UTCTime , acao :: AcaoLog , detalhes :: String , status :: StatusLog } deriving (Show, Read, Eq) -- Exemplos de uso e validação -- Exemplo de criação de um Item exemploItem :: Item exemploItem = Item { itemID = "001" , nome = "Teclado Mecanico" , quantidade = 15 , categoria = "Perifericos" } -- Exemplo de criação de LogEntry exemploLog :: UTCTime -> LogEntry exemploLog tempo = LogEntry { timestamp = tempo , acao = Add , detalhes = "Adicionado item 001 - Teclado Mecanico" , status = Sucesso }
-- Módulo: Analise.hs -- Responsável: Aluno 4 (Ângelo Piovezan Jorgeto) -- Objetivo: Funções puras para análise e geração de relatórios de logs. module Analise ( logsDeErro , historicoPorItem , itemMaisMovimentado , formatarRelatorioCompleto , formatarLog ) where -- Importações import InventarioTipos import Data.List (group, sort, sortBy, filter, find, tails, isPrefixOf, drop, isInfixOf) import Data.Maybe (mapMaybe) import Data.Ord (comparing, Down(..)) import Data.Time (TimeZone, utcToZonedTime, formatTime) import Data.Time.Format (defaultTimeLocale) -- ============================================= -- Funções de Análise Puras -- ============================================= -- Filtra a lista de logs, retornando apenas aqueles com status 'Falha' logsDeErro :: [LogEntry] -> [LogEntry] logsDeErro = filter (ehFalha . status) where ehFalha :: StatusLog -> Bool ehFalha (Falha _) = True ehFalha Sucesso = False -- Filtra logs que mencionam um ID de item específico historicoPorItem :: [LogEntry] -> String -> [LogEntry] historicoPorItem logs idAlvo = let marcador1 = "ID: " ++ idAlvo marcador2 = "(ID: " ++ idAlvo in filter (\log -> (marcador1 `isInfixOf` detalhes log) || (marcador2 `isInfixOf` detalhes log)) logs -- Encontra o itemID com mais logs de SUCESSO itemMaisMovimentado :: [LogEntry] -> String itemMaisMovimentado logs = let ids = mapMaybe extractSuccessItemID logs in case ids of [] -> "Nenhuma movimentacao de sucesso registrada." _ -> let groupedIDs = group (sort ids) sortedGroups = sortBy (comparing (Down . length)) groupedIDs in case sortedGroups of ((topID:_):_) -> let count = length (filter (== topID) ids) in topID ++ " (com " ++ show count ++ " movimentacoes)" _ -> "Erro interno de analise de logs." -- Helper para extrair ItemID de logs de Sucesso extractSuccessItemID :: LogEntry -> Maybe String extractSuccessItemID log | status log /= Sucesso = Nothing | otherwise = let details = detalhes log marker = "(ID: " in case find (isPrefixOf marker) (tails details) of Just match -> Just $ takeWhile (/= ')') (drop (length marker) match) Nothing -> Nothing -- ============================================= -- Funções de Formatação de Relatório -- ============================================= -- Converte um LogEntry em uma String formatada para exibição formatarLog :: TimeZone -> LogEntry -> String formatarLog tz log = let zonedTime = utcToZonedTime tz (timestamp log) formattedTime = formatTime defaultTimeLocale "%Y-%m-%d %H:%M:%S" zonedTime in "[" ++ formattedTime ++ "] " ++ "[" ++ show (acao log) ++ "] " ++ "[" ++ formatarStatus (status log) ++ "] " ++ detalhes log where formatarStatus Sucesso = "SUCESSO" formatarStatus (Falha msg) = "FALHA: " ++ msg -- Cria o texto completo do relatório para ser impresso pelo módulo de IO formatarRelatorioCompleto :: TimeZone -> [LogEntry] -> String formatarRelatorioCompleto tz logs = let total = length logs erros = logsDeErro logs totalErros = length erros itemTop = itemMaisMovimentado logs in unlines [ "========== RELATORIO DE ANALISE DE LOGS ==========" , "" , "** Sumario Geral **" , "Total de entradas de log: " ++ show total , "Total de operacoes com falha: " ++ show totalErros , "Item mais movimentado (com sucesso): " ++ itemTop , "" , "---" , "" , "** Detalhe de Logs de Erro (" ++ show totalErros ++ ") **" , if null erros then "Nenhum erro registrado." else unlines (map ((" " ++) . formatarLog tz) erros) , "====================================================" ]

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue