packages feed

noise-0.0.1: src/Text/Noise/Error.hs

module Text.Noise.Error
( Error(..)
) where

import qualified Data.List as List
import qualified Text.Noise.SourceRange as SourceRange
import qualified Text.Parsec.Error as Parsec

class (SourceRange.HasSourceRange a) => Error a where
  message :: a -> String

instance Error Parsec.ParseError where
  message = showErrorMessages . Parsec.errorMessages

showErrorMessages :: [Parsec.Message] -> String
showErrorMessages msgs
    | null msgs = msgUnknown
    | otherwise = unwords $ map (++ ".") $ clean
                 [showSysUnExpect,showUnExpect,showExpect,showMessages]
    where
      (sysUnExpect, msgs1) = span (Parsec.SysUnExpect "" ==) msgs
      (unExpect, msgs2)    = span (Parsec.UnExpect    "" ==) msgs1
      (expect, messages)   = span (Parsec.Expect      "" ==) msgs2

      showExpect      = showMany msgExpecting expect
      showUnExpect    = showMany msgUnExpected unExpect
      showSysUnExpect | not (null unExpect) ||
                        null sysUnExpect = ""
                      | null firstMsg    = msgUnExpected ++ " " ++ msgEndOfInput
                      | otherwise        = msgUnExpected ++ " " ++ firstMsg
        where
          firstMsg  = Parsec.messageString (head sysUnExpect)

      showMessages      = showMany "" messages
      showMany pre msgs' = case clean (map Parsec.messageString msgs') of
                            [] -> ""
                            ms | null pre  -> commasOr ms
                               | otherwise -> pre ++ " " ++ commasOr ms

      commasOr []       = ""
      commasOr [m]      = m
      commasOr ms       = commaSep (init ms) ++ " " ++ msgOr ++ " " ++ last ms
      commaSep          = seperate ", " . clean

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

      clean             = List.nub . filter (not . null)

      msgOr = "or"
      msgUnknown = "Parse error"
      msgExpecting = "Expecting"
      msgUnExpected = "Unexpected"
      msgEndOfInput = "end of input"