module Safe.Plus
( callerFile
, callerLine
, callerLocation
, safeDigitToInt
, safeRead
, readNoteVerbose
, safeFromJust
, safeFromJustNote
, safeHead
, safeTail
, safeInit
, safeLast
, safeMaximum
, safeMinimum
, safeHeadNote
, safeFromRight
, fromRightNote
, safeFromLeft
, fromLeftNote
, safeAtArray
, atArrayNote
, safeAt
, safeError
, safeFail
, safeUndef
)
where
import Data.Array.IArray
import Data.Char
import Data.Monoid
import GHC.Stack
import GHC.Stack.Plus
import Safe
safeDigitToInt :: Monad m => Char -> m Int
safeDigitToInt c
| isDigit c = return $ ord c ord '0'
| c >= 'a' && c <= 'f' = return $ ord c ord 'a' + 10
| c >= 'A' && c <= 'F' = return $ ord c ord 'A' + 10
| otherwise = safeFail ("Char.safeDigitToInt: not a digit " ++ show c)
safeUndef :: (HasCallStack) => a
safeUndef = safeError "undefined!"
safeRead :: (HasCallStack, Read a) => String -> a
safeRead = readNoteVerbose callerLocation
readNoteVerbose :: Read a => String -> String -> a
readNoteVerbose msg s =
case [x | (x,t) <- reads s, ("","") <- lex t] of
[x] -> x
[] -> error $ "Prelude.read: no parse, " ++ msg ++ ", on " ++ prefix
_ -> error $ "Prelude.read: ambiguous parse, " ++ msg ++ ", on " ++ prefix
where
prefix = '\"' : a ++ if null b then "\"" else "..."
where (a,b) = splitAt 1024 s
safeFromJust :: (HasCallStack) => Maybe a -> a
safeFromJust = Safe.fromJustNote callerLocation
safeFromJustNote :: (HasCallStack) => String -> Maybe a -> a
safeFromJustNote s = Safe.fromJustNote (callerLocation ++ ": " ++ s)
safeFail :: (HasCallStack, Monad m) => String -> m a
safeFail x = fail (callerLocation ++ ": FAIL: " ++ x)
safeHead :: (HasCallStack) => [a] -> a
safeHead = Safe.headNote callerLocation
safeTail :: (HasCallStack) => [a] -> [a]
safeTail = Safe.tailNote callerLocation
safeInit :: (HasCallStack) => [a] -> [a]
safeInit = Safe.initNote callerLocation
safeLast :: (HasCallStack) => [a] -> a
safeLast = Safe.lastNote callerLocation
safeMaximum :: (HasCallStack, Ord a) => [a] -> a
safeMaximum = Safe.maximumNote callerLocation
safeMinimum :: (HasCallStack, Ord a) => [a] -> a
safeMinimum = Safe.minimumNote callerLocation
safeHeadNote :: (HasCallStack) => String -> [a] -> a
safeHeadNote x = Safe.headNote (callerLocation ++ ": " ++ x)
safeFromRight :: (HasCallStack) => Either a b -> b
safeFromRight = fromRightNote callerLocation
fromRightNote :: String -> Either a b -> b
fromRightNote msg (Left _) = error $ "fromRight got a left value: " ++ msg
fromRightNote _ (Right x) = x
safeFromLeft :: (HasCallStack) => Either a b -> a
safeFromLeft = fromLeftNote callerLocation
fromLeftNote :: String -> Either a b -> a
fromLeftNote msg (Right _) = safeError $ "fromLeft got a right value: " ++ msg
fromLeftNote _ (Left x) = x
safeAtArray :: (HasCallStack, IArray a e, Ix i, Show i) => a i e -> i -> e
safeAtArray = atArrayNote callerLocation
atArrayNote :: (IArray a e, Ix i, Show i) => String -> a i e -> i -> e
atArrayNote msg array index
| inRange arrayBounds index = array ! index
| otherwise =
error $ concat
[ "lookup at index ", show index, " in an array was outside of its bounds "
, show arrayBounds, ": ", msg
]
where
arrayBounds = bounds array
safeAt :: (HasCallStack) => [a] -> Int -> a
safeAt = Safe.atNote callerLocation
safeError :: (HasCallStack) => String -> a
safeError err = error $ callerLocation <> ": " <> err