descript-lang-0.2.0.0: src/Descript/Misc/Build/Read/Parse/Error.hs
module Descript.Misc.Build.Read.Parse.Error
( RangedErrorMsg (..)
, RangedError (..)
, ParseError
, ParseResult
, ParseResultT
, splitParseError
, parseErrorSummary
) where
import Descript.Misc.Build.Read.Parse.Loc
import Descript.Misc.Build.Read.File
import Descript.Misc.Loc
import Descript.Misc.Error
import Descript.Misc.Summary
import qualified Text.Megaparsec.Error as Parsec
import qualified Text.Megaparsec.Pos as Parsec
import Data.Maybe
import Core.Data.List
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.Set as Set
data RangedErrorMsg
= RangedErrorMsg
{ itemRange :: Range
, itemMsg :: String
} deriving (Eq, Ord, Read, Show)
data RangedError
= RangedError
{ errorRange :: Range
, rangedErrorExpected :: String
, rangedErrorActual :: String
} deriving (Eq, Ord, Read, Show)
type ParseError t = Parsec.ParseError t RangedError
type ParseResult a = Result (ParseError Char) a
type ParseResultT u a = ResultT (ParseError Char) u a
instance Parsec.ShowErrorComponent RangedError where
showErrorComponent (RangedError _ expected actual)
= "expected " ++ expected ++ ", got " ++ actual
instance Summary RangedError where
summary x = summary (errorRange x) ++ ": " ++ Parsec.showErrorComponent x
-- | Takes components with ranges ('RangedError's) and describes them
-- with their ranges, takes all other components and describes them
-- together with the range starting and ending at the general error's
-- position.
splitParseError :: (Ord a, Parsec.ShowToken a)
=> ParseError a
-> [RangedErrorMsg]
splitParseError err@(Parsec.TrivialError (gpos :| _) _ _) =
[ RangedErrorMsg
{ itemRange = singletonRange $ posToLoc gpos
, itemMsg = Parsec.parseErrorTextPretty err
}
]
splitParseError (Parsec.FancyError (gpos :| _) items)
= errItemsGenMsg gpos items' ?: errItemRangedMsgs items'
where items' = Set.toList items
errItemsGenMsg :: Parsec.SourcePos
-> [Parsec.ErrorFancy RangedError]
-> Maybe RangedErrorMsg
errItemsGenMsg gpos
= fmap (mkGenRangedMsg gpos . msgToStr)
. foldMap (fmap strToMsg . errItemGenMsg)
errItemGenMsg :: Parsec.ErrorFancy RangedError
-> Maybe String
errItemGenMsg (Parsec.ErrorCustom _) = Nothing
errItemGenMsg err = Just $ Parsec.showErrorComponent err
errItemRangedMsgs :: [Parsec.ErrorFancy RangedError] -> [RangedErrorMsg]
errItemRangedMsgs = mapMaybe errItemRangedMsg
errItemRangedMsg :: Parsec.ErrorFancy RangedError -> Maybe RangedErrorMsg
errItemRangedMsg (Parsec.ErrorCustom rangedErr)
= Just $ rangedErrMsg rangedErr
errItemRangedMsg _ = Nothing
rangedErrMsg :: RangedError -> RangedErrorMsg
rangedErrMsg err
= RangedErrorMsg
{ itemRange = errorRange err
, itemMsg = Parsec.showErrorComponent err
}
mkGenRangedMsg :: Parsec.SourcePos -> String -> RangedErrorMsg
mkGenRangedMsg gpos desc
= RangedErrorMsg
{ itemRange = singletonRange $ posToLoc gpos
, itemMsg = desc
}
-- | Summarizes a parse error in a larger context (e.g. build error).
parseErrorSummary :: SFile -> ParseError Char -> String
parseErrorSummary file err = "parse error: " ++ summaryF file err