{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
module Distribution.ModuleName (
ModuleName (..),
fromString,
fromComponents,
components,
toFilePath,
main,
simple,
validModuleComponent,
) where
import Prelude ()
import Distribution.Compat.Prelude
import Distribution.Utils.ShortText
import System.FilePath ( pathSeparator )
import Distribution.Pretty
import Distribution.Parsec.Class
import Distribution.Text
import qualified Distribution.Compat.CharParsing as P
import qualified Distribution.Compat.ReadP as Parse
import qualified Text.PrettyPrint as Disp
newtype ModuleName = ModuleName ShortTextLst
deriving (Eq, Generic, Ord, Read, Show, Typeable, Data)
instance Binary ModuleName
instance NFData ModuleName where
rnf (ModuleName ms) = rnf ms
instance Pretty ModuleName where
pretty (ModuleName ms) =
Disp.hcat (intersperse (Disp.char '.') (map Disp.text $ stlToStrings ms))
instance Parsec ModuleName where
parsec = fromComponents <$> P.sepBy1 component (P.char '.')
where
component = do
c <- P.satisfy isUpper
cs <- P.munch validModuleChar
return (c:cs)
instance Text ModuleName where
parse = do
ms <- Parse.sepBy1 component (Parse.char '.')
return (ModuleName $ stlFromStrings ms)
where
component = do
c <- Parse.satisfy isUpper
cs <- Parse.munch validModuleChar
return (c:cs)
validModuleChar :: Char -> Bool
validModuleChar c = isAlphaNum c || c == '_' || c == '\''
validModuleComponent :: String -> Bool
validModuleComponent [] = False
validModuleComponent (c:cs) = isUpper c
&& all validModuleChar cs
{-# DEPRECATED simple "use ModuleName.fromString instead. This symbol will be removed in Cabal-3.0 (est. Mar 2019)." #-}
simple :: String -> ModuleName
simple str = ModuleName (stlFromStrings [str])
instance IsString ModuleName where
fromString string = fromComponents (split string)
where
split cs = case break (=='.') cs of
(chunk,[]) -> chunk : []
(chunk,_:rest) -> chunk : split rest
fromComponents :: [String] -> ModuleName
fromComponents components'
| null components' = error zeroComponents
| all validModuleComponent components' = ModuleName (stlFromStrings components')
| otherwise = error badName
where
zeroComponents = "ModuleName.fromComponents: zero components"
badName = "ModuleName.fromComponents: invalid components " ++ show components'
main :: ModuleName
main = ModuleName (stlFromStrings ["Main"])
components :: ModuleName -> [String]
components (ModuleName ms) = stlToStrings ms
toFilePath :: ModuleName -> FilePath
toFilePath = intercalate [pathSeparator] . components
data ShortTextLst = STLNil
| STLCons !ShortText !ShortTextLst
deriving (Eq, Generic, Ord, Typeable, Data)
instance NFData ShortTextLst where
rnf = flip seq ()
instance Show ShortTextLst where
showsPrec p = showsPrec p . stlToList
instance Read ShortTextLst where
readsPrec p = map (first stlFromList) . readsPrec p
instance Binary ShortTextLst where
put = put . stlToList
get = stlFromList <$> get
stlToList :: ShortTextLst -> [ShortText]
stlToList STLNil = []
stlToList (STLCons st next) = st : stlToList next
stlToStrings :: ShortTextLst -> [String]
stlToStrings = map fromShortText . stlToList
stlFromList :: [ShortText] -> ShortTextLst
stlFromList [] = STLNil
stlFromList (x:xs) = STLCons x (stlFromList xs)
stlFromStrings :: [String] -> ShortTextLst
stlFromStrings = stlFromList . map toShortText