{-# LANGUAGE CPP #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TemplateHaskell #-} {-# OPTIONS_HADDOCK hide #-} -- | -- Module : Data.Array.Accelerate.Error -- Copyright : [2009..2017] Manuel M T Chakravarty, Gabriele Keller, Trevor L. McDonell -- License : BSD3 -- -- Maintainer : Trevor L. McDonell -- Stability : experimental -- Portability : non-portable (GHC extensions) -- module Data.Array.Accelerate.Error ( internalError, boundsError, unsafeError, internalCheck, boundsCheck, unsafeCheck, indexCheck, internalWarning, boundsWarning, unsafeWarning, ) where import Data.List import Debug.Trace import Language.Haskell.TH hiding ( Unsafe ) data Check = Bounds | Unsafe | Internal -- | Issue an internal error message -- -- $internalError :: String -> String -> a -- internalError :: Q Exp internalError = appE errorQ [| Internal |] boundsError :: Q Exp boundsError = appE errorQ [| Bounds |] unsafeError :: Q Exp unsafeError = appE errorQ [| Unsafe |] -- | Throw an error if the condition evaluates to False, otherwise evaluate the -- result. -- -- $internalCheck :: String -> String -> Bool -> a -> a -- internalCheck :: Q Exp internalCheck = appE checkQ [| Internal |] boundsCheck :: Q Exp boundsCheck = appE checkQ [| Bounds |] unsafeCheck :: Q Exp unsafeCheck = appE checkQ [| Unsafe |] -- | Throw an error if the index is not in range, otherwise evaluate the result. -- -- $boundsCheck :: String -> Int -> Int -> a -> a -- indexCheck :: Q Exp indexCheck = withLocation [| \format fn i n x -> case not (doChecks Bounds) || (i >= 0 && i < n) of True -> x False -> errorWithoutStackTrace (format Bounds (call fn ("index out of bounds: " ++ show (i,n)))) x |] -- | Print a warning message if the condition evaluates to False. -- -- $internalWarning :: String -> String -> Bool -> a -> a -- internalWarning :: Q Exp internalWarning = appE warningQ [| Internal |] boundsWarning :: Q Exp boundsWarning = appE warningQ [| Bounds |] unsafeWarning :: Q Exp unsafeWarning = appE warningQ [| Unsafe |] -- Template Haskell implementation -- ------------------------------- call :: String -> String -> String call f m = concat ["(", f, "): ", m] errorQ :: Q Exp errorQ = withLocation [| \format kind fn msg -> errorWithoutStackTrace (format kind (call fn msg)) |] checkQ :: Q Exp checkQ = withLocation [| \format kind fn msg cond x -> case not (doChecks kind) || cond of True -> x False -> errorWithoutStackTrace (format kind (call fn msg)) |] warningQ :: Q Exp warningQ = withLocation [| \format kind fn msg cond x -> case not (doChecks kind) || cond of True -> x False -> trace (format kind (call fn msg)) x |] withLocation :: Q Exp -> Q Exp withLocation f = appE f (locatedMessage =<< location) locatedMessage :: Loc -> Q Exp locatedMessage loc = [| \kind msg -> message kind ($(litE (stringL (formatLoc loc))) ++ msg) |] formatLoc :: Loc -> String formatLoc loc = let file = loc_filename loc (line,col) = loc_start loc in intercalate ":" [file, show line, show col, " "] message :: Check -> String -> String message kind msg = unlines header ++ msg where header = case kind of Internal -> ["" ,"*** Internal error in package accelerate ***" ,"*** Please submit a bug report at https://github.com/AccelerateHS/accelerate/issues"] _ -> [] #if __GLASGOW_HASKELL__ < 800 errorWithoutStackTrace :: String -> a errorWithoutStackTrace = error #endif -- CPP malarky -- ----------- {-# INLINE doChecks #-} doChecks :: Check -> Bool doChecks Bounds = doBoundsChecks doChecks Unsafe = doUnsafeChecks doChecks Internal = doInternalChecks doBoundsChecks :: Bool #ifdef ACCELERATE_BOUNDS_CHECKS doBoundsChecks = True #else doBoundsChecks = False #endif doUnsafeChecks :: Bool #ifdef ACCELERATE_UNSAFE_CHECKS doUnsafeChecks = True #else doUnsafeChecks = False #endif doInternalChecks :: Bool #ifdef ACCELERATE_INTERNAL_CHECKS doInternalChecks = True #else doInternalChecks = False #endif