File: Errors.hs

package info (click to toggle)
haskell-shake 0.13.2%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 888 kB
  • ctags: 127
  • sloc: haskell: 6,388; makefile: 35; ansic: 25; sh: 2
file content (132 lines) | stat: -rw-r--r-- 5,504 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
{-# LANGUAGE DeriveDataTypeable, PatternGuards, RecordWildCards #-}

-- | Errors seen by the user
module Development.Shake.Errors(
    ShakeException(..),
    errorStructured, err,
    errorNoRuleToBuildType, errorRuleTypeMismatch, errorIncompatibleRules,
    errorMultipleRulesMatch, errorRuleRecursion, errorNoApply,
    ) where

import Control.Arrow
import Control.Exception
import Data.Typeable
import Data.List


err :: String -> a
err msg = error $ "Development.Shake: Internal error, please report to Neil Mitchell (" ++ msg ++ ")"

alternatives = let (*) = (,) in
    ["_rule_" * "oracle"
    ,"_Rule_" * "Oracle"
    ,"_key_" * "question"
    ,"_Key_" * "Question"
    ,"_result_" * "answer"
    ,"_Result_" * "Answer"
    ,"_rule/defaultRule_" * "addOracle"
    ,"_apply_" * "askOracle"]


errorStructured :: String -> [(String, Maybe String)] -> String -> a
errorStructured msg args hint = error $ unlines $
        [msg ++ ":"] ++
        ["  " ++ a ++ [':' | a /= ""] ++ replicate (as - length a + 2) ' ' ++ b | (a,b) <- args2] ++
        [hint | hint /= ""]
    where
        as = maximum $ 0 : map (length . fst) args2
        args2 = [(a,b) | (a,Just b) <- args]



structured :: Bool -> String -> [(String, Maybe String)] -> String -> a
structured alt msg args hint = errorStructured (f msg) (map (first f) args) (f hint)
    where
        f = filter (/= '_') . (if alt then g else id)
        g xs | (a,b):_ <- filter (\(a,b) -> a `isPrefixOf` xs) alternatives = b ++ g (drop (length a) xs)
        g (x:xs) = x : g xs
        g [] = []


errorNoRuleToBuildType :: TypeRep -> Maybe String -> Maybe TypeRep -> a
errorNoRuleToBuildType tk k tv = structured (specialIsOracleKey tk)
    "Build system error - no _rule_ matches the _key_ type"
    [("_Key_ type", Just $ show tk)
    ,("_Key_ value", k)
    ,("_Result_ type", fmap show tv)]
    "Either you are missing a call to _rule/defaultRule_, or your call to _apply_ has the wrong _key_ type"

errorRuleTypeMismatch :: TypeRep -> Maybe String -> TypeRep -> TypeRep -> a
errorRuleTypeMismatch tk k tvReal tvWant = structured (specialIsOracleKey tk)
    "Build system error - _rule_ used at the wrong _result_ type"
    [("_Key_ type", Just $ show tk)
    ,("_Key_ value", k)
    ,("_Rule_ _result_ type", Just $ show tvReal)
    ,("Requested _result_ type", Just $ show tvWant)]
    "Either the function passed to _rule/defaultRule_ has the wrong _result_ type, or the result of _apply_ is used at the wrong type"

errorIncompatibleRules :: TypeRep -> TypeRep -> TypeRep -> a
errorIncompatibleRules tk tv1 tv2 = if specialIsOracleKey tk then errorDuplicateOracle tk Nothing [tv1,tv2] else errorStructured
    "Build system error - rule has multiple result types"
    [("Key type", Just $ show tk)
    ,("First result type", Just $ show tv1)
    ,("Second result type", Just $ show tv2)]
    "A function passed to rule/defaultRule has the wrong result type"

errorMultipleRulesMatch :: TypeRep -> String -> Int -> a
errorMultipleRulesMatch tk k count
    | specialIsOracleKey tk = if count == 0 then err $ "no oracle match for " ++ show tk else errorDuplicateOracle tk (Just k) []
    | otherwise = errorStructured
    ("Build system error - key matches " ++ (if count == 0 then "no" else "multiple") ++ " rules")
    [("Key type",Just $ show tk)
    ,("Key value",Just k)
    ,("Rules matched",Just $ show count)]
    (if count == 0 then "Either add a rule that produces the above key, or stop requiring the above key"
     else "Modify your rules/defaultRules so only one can produce the above key")

errorRuleRecursion :: Maybe TypeRep -> Maybe String -> a
errorRuleRecursion tk k = errorStructured -- may involve both rules and oracle, so report as a rule
    "Build system error - recursion detected"
    [("Key type",fmap show tk)
    ,("Key value",k)]
    "Rules may not be recursive"

errorDuplicateOracle :: TypeRep -> Maybe String -> [TypeRep] -> a
errorDuplicateOracle tk k tvs = errorStructured
    "Build system error - duplicate oracles for the same question type"
    ([("Question type",Just $ show tk)
     ,("Question value",k)] ++
     [("Answer type " ++ show i, Just $ show tv) | (i,tv) <- zip [1..] tvs])
    "Only one call to addOracle is allowed per question type"

errorNoApply :: TypeRep -> Maybe String -> String -> a
errorNoApply tk k msg = structured (specialIsOracleKey tk)
    "Build system error - cannot currently call _apply_"
    [("Reason", Just msg)
    ,("_Key_ type", Just $ show tk)
    ,("_Key_ value", k)]
    "Move the _apply_ call earlier/later"


-- Should be in Special, but then we get an import cycle
specialIsOracleKey :: TypeRep -> Bool
specialIsOracleKey t = con == "OracleQ"
    where con = show $ fst $ splitTyConApp t


-- | Error representing all expected exceptions thrown by Shake.
--   Problems when executing rules will be raising using this exception type.
data ShakeException = ShakeException
        {shakeExceptionTarget :: String -- ^ The target that was being built when the exception occured.
        ,shakeExceptionStack :: [String]  -- ^ The stack of targets, where the 'shakeExceptionTarget' is last.
        ,shakeExceptionInner :: SomeException -- ^ The underlying exception that was raised.
        }
    deriving Typeable

instance Exception ShakeException

instance Show ShakeException where
    show ShakeException{..} = unlines $
        "Error when running Shake build system:" :
        map ("* " ++) shakeExceptionStack ++
        [show shakeExceptionInner]