packages feed

glualint-1.29.0: src/GLua/ParseError.hs

-- | This is a copy-paste-edit of Parsec's parse error rendering.
module GLua.ParseError (renderParseError) where

import Data.List (intercalate, nub)
import Text.Parsec.Error (
  Message (..),
  ParseError,
  errorMessages,
  messageString,
 )

-- | Render a parsec error
renderParseError :: ParseError -> String
renderParseError = showErrorMessages . errorMessages

-- | Modified version of the following function:
-- https://hackage.haskell.org/package/parsec/docs/src/Text.Parsec.Error.html#showErrorMessages.
--
-- At some point it would be nice to switch to another parser library (e.g. megaparsec), which has
-- more structured error types, and a nicer error rendering algorithm. Until then, this modified
-- function will do.
showErrorMessages :: [Message] -> String
showErrorMessages msgs
  | null msgs = "unknown parse error"
  | otherwise = intercalate ", " $ clean [showSysUnExpect, showUnExpect, showExpect, showMessages]
  where
    (sysUnExpect, msgs1) = span (SysUnExpect "" ==) msgs
    (unExpect, msgs2) = span (UnExpect "" ==) msgs1
    (expect, messages) = span (Expect "" ==) msgs2

    showExpect = showMany "expecting" expect
    showUnExpect = showMany "unexpected" unExpect
    showSysUnExpect
      | not (null unExpect) = ""
      | [] <- sysUnExpect = ""
      | msg : _ <- sysUnExpect, null (messageString msg) = "unexpected end of input"
      | msg : _ <- sysUnExpect = "unexpected " ++ messageString msg

    showMessages = showMany "" messages

    -- helpers
    showMany pre msgs3 = case clean (map messageString msgs3) of
      [] -> ""
      ms
        | null pre -> commasOr ms
        | otherwise -> pre ++ " " ++ commasOr ms

    commasOr [] = ""
    commasOr [m] = m
    commasOr ms = commaSep (init ms) ++ " or " ++ last ms

    commaSep = separate ", " . clean

    separate _ [] = ""
    separate _ [m] = m
    separate sep (m : ms) = m ++ sep ++ separate sep ms

    clean = nub . filter (not . null)