packages feed

simple-parser-0.12.0: src/SimpleParser/Interactive.hs

{-# LANGUAGE OverloadedStrings #-}

module SimpleParser.Interactive
  ( ErrorStyle (..)
  , renderInteractive
  , parseInteractiveStyle
  , parseInteractive
  ) where

import Data.Foldable (toList)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import qualified Data.Text.Lazy.IO as TLIO
import Errata (Errata (..), prettyErrors)
import Errata.Styles (fancyPointer, fancyStyle)
import SimpleParser.Errata (LinePosExplainable, errataParseError)
import SimpleParser.Explain (Explainable, buildAllParseErrorExplanations, explainParseError)
import SimpleParser.Input (matchEnd)
import SimpleParser.Parser (Parser, runParser)
import SimpleParser.Result (ParseErrorBundle (..), ParseResult (..), ParseSuccess (..))
import SimpleParser.Stream (LinePosStream, newLinePosStream)
import qualified Text.Builder as TB

data ErrorStyle =
    ErrorStyleErrata
  | ErrorStyleExplain
  deriving stock (Eq, Show)

renderInteractive :: (LinePosExplainable l s e) => ErrorStyle -> String -> Maybe (ParseResult l s e a) -> IO ()
renderInteractive errStyle input = \case
  Nothing ->
    putStrLn "No result"
  Just (ParseResultError (ParseErrorBundle es)) ->
    case errStyle of
      ErrorStyleErrata ->
        let blocks = fmap (errataParseError fancyStyle fancyPointer "<interactive>") (toList es)
            errata = Errata Nothing blocks Nothing
            pretty = prettyErrors input [errata]
        in TLIO.putStrLn pretty
      ErrorStyleExplain ->
        let b = buildAllParseErrorExplanations (fmap explainParseError (toList es))
        in TIO.putStrLn (TB.run ("Errors:\n" <> b))
  Just (ParseResultSuccess _) ->
    putStrLn "Success"

parseInteractiveStyle :: (s ~ LinePosStream Text, Explainable l s e) => ErrorStyle -> Parser l s e a -> String -> IO (Maybe a)
parseInteractiveStyle errStyle parser input = do
  let mres = runParser (parser <* matchEnd) (newLinePosStream (T.pack input))
  renderInteractive errStyle input mres
  let res = case mres of { Just (ParseResultSuccess (ParseSuccess _ a)) -> Just a; _ -> Nothing }
  pure res

parseInteractive :: (s ~ LinePosStream Text, Explainable l s e) => Parser l s e a -> String -> IO (Maybe a)
parseInteractive = parseInteractiveStyle ErrorStyleErrata