descript-lang-0.2.0.0: src/Descript/Misc/Build/Read/File/DepError.hs
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
module Descript.Misc.Build.Read.File.DepError
( AnonDepError (..)
, TagdDepError (..)
, GenDepResult
, GenDepResultT
, GenDirtyDep
, GenDirtyDepT
, mapDirtyDepdAnn
, guardCycle
, guardCycleT
, guardPromoteCycle
, guardPromoteCycleT
) where
import Descript.Misc.Build.Read.File.Depd
import Descript.Misc.Build.Read.File.Scope
import Descript.Misc.Error
import Descript.Misc.Ann
import Descript.Misc.Summary
import Core.Data.String
import Core.Control.Monad.Trans
-- | An error encountered trying to load a dependency. Doesn't specify
-- the dependency's scope (must be inferred).
data AnonDepError
= DepNotExist [String]
| DepNotReadable
| DepNotBuild String
| DepCycles [RelScope]
deriving (Eq, Ord, Read, Show)
-- | An error encountered trying to load a dependency. Specifies the
-- dependency's scope.
data TagdDepError an
= TagdDepError
{ tagdDepErrorAnn :: an
, tagdDepErrorScope :: AbsScope
, tagdDepError :: AnonDepError
} deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)
-- | The result of trying to load a dependency with no fallback.
type GenDepResult a = Result AnonDepError a
-- | The result of trying to load a dependency with no fallback (stacked).
type GenDepResultT u a = ResultT AnonDepError u a
-- | The result of trying to load dependencies with fallback.
type GenDirtyDep an a = Dirty (TagdDepError an) a
-- | The result of trying to load dependencies with fallback (stacked).
type GenDirtyDepT an u a = DirtyT (TagdDepError an) u a
instance Ann TagdDepError where
getAnn = tagdDepErrorAnn
instance SummaryWithAnn TagdDepError where
baseSummary (TagdDepError _ scope err)
= anonDepErrorSummary suffix (Just scope) err
where suffix = " - " ++ summary scope
instance (AnnSummary an) => Summary (TagdDepError an) where
summary = summaryWithAnn
instance Summary AnonDepError where
summary = anonDepErrorSummary "" Nothing
-- | Transforms the annotations within the @DirtyDepd@. Annotations are
-- in the value and errors associated with the dependency, but \not\ the
-- dependency itself.
mapDirtyDepdAnn :: (Functor a)
=> (an1 -> an2)
-> GenDepd (GenDirtyDep an1 d) (a an1)
-> GenDepd (GenDirtyDep an2 d) (a an2)
mapDirtyDepdAnn f (Depd ddep x)
= Depd (mapWarnings (fmap f) ddep) (f <$> x)
anonDepErrorSummary :: String
-> Maybe AbsScope
-> AnonDepError
-> String
anonDepErrorSummary sufx _ (DepNotExist paths)
= unlines
( ("couldn't find module" ++ sufx ++ ", tried:")
: map indentBullet paths )
anonDepErrorSummary sufx _ DepNotReadable = "couldn't read module" ++ sufx
anonDepErrorSummary sufx _ (DepNotBuild msg)
= "couldn't build module" ++ sufx ++ ":\n" ++ msg
anonDepErrorSummary _ optScope (DepCycles relInters)
= unlines
( "module depends on this module, forming a cycle:"
: map indentBullet interSums )
where interSums
= reverse
$ case optScope of
Nothing -> map summary relInters
Just scope -> map summary $ scanr (flip anchorScopeSib) scope relInters
-- | Fails with 'DepCycles' if adding the given dependency to the given
-- chain of dependencies creates a cycle (if the chain contains the
-- dependency).
guardCycle :: RelScope -> [RelScope] -> GenDepResult ()
guardCycle new dpds
| new `elem` dpds = Failure $ DepCycles $ new : dpds
| otherwise = Success ()
-- | Hoisted 'guardCycle' for convenience.
guardCycleT :: (Monad u) => RelScope -> [RelScope] -> GenDepResultT u ()
guardCycleT new = hoist . guardCycle new
-- | Fails if one of the dependency "errors" is a 'DepCycles'. Typically
-- because data with other dependency errors is still interpreted for
-- more errors, but 'DepCycles' errors generate redundant messages
-- later, so when they're encountered, resolution immediately fails.
guardPromoteCycle :: [TagdDepError an] -> GenDepResult ()
guardPromoteCycle [] = Success ()
guardPromoteCycle (x : xs) = guardPromoteCycle1 x >> guardPromoteCycle xs
guardPromoteCycle1 :: TagdDepError an -> GenDepResult ()
guardPromoteCycle1 terr
= case tagdDepError terr of
DepCycles inters -> Failure $ DepCycles inters
_ -> Success ()
-- | Hoisted 'guardPromoteCycle' for convenience.
guardPromoteCycleT :: (Monad u) => [TagdDepError an] -> GenDepResultT u ()
guardPromoteCycleT = hoist . guardPromoteCycle