content: {-# LANGUAGE DeriveDataTypeable #-}
  {-# LANGUAGE DeriveGeneric #-}
  
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  Distribution.ModuleName
  -- Copyright   :  Duncan Coutts 2008
  -- License     :  BSD3
  --
  -- Maintainer  :  cabal-devel@haskell.org
  -- Portability :  portable
  --
  -- Data type for Haskell module names.
  
  module Distribution.ModuleName (
          ModuleName,
          fromString,
          components,
          toFilePath,
          main,
          simple,
    ) where
  
  import Distribution.Text
           ( Text(..) )
  
  import Data.Binary (Binary)
  import qualified Data.Char as Char
           ( isAlphaNum, isUpper )
  import Data.Data (Data)
  import Data.Typeable (Typeable)
  import qualified Distribution.Compat.ReadP as Parse
  import qualified Text.PrettyPrint as Disp
  import Data.List
           ( intercalate, intersperse )
  import GHC.Generics (Generic)
  import System.FilePath
           ( pathSeparator )
  
  -- | A valid Haskell module name.
  --
  newtype ModuleName = ModuleName [String]
    deriving (Eq, Generic, Ord, Read, Show, Typeable, Data)
  
  instance Binary ModuleName
  
  instance Text ModuleName where
    disp (ModuleName ms) =
      Disp.hcat (intersperse (Disp.char '.') (map Disp.text ms))
  
    parse = do
      ms <- Parse.sepBy1 component (Parse.char '.')
      return (ModuleName ms)
  
      where
        component = do
          c  <- Parse.satisfy Char.isUpper
          cs <- Parse.munch validModuleChar
          return (c:cs)
  
  validModuleChar :: Char -> Bool
  validModuleChar c = Char.isAlphaNum c || c == '_' || c == '\''
  
  validModuleComponent :: String -> Bool
  validModuleComponent []     = False
  validModuleComponent (c:cs) = Char.isUpper c
                             && all validModuleChar cs
  
  {-# DEPRECATED simple "use ModuleName.fromString instead" #-}
  simple :: String -> ModuleName
  simple str = ModuleName [str]
  
  -- | Construct a 'ModuleName' from a valid module name 'String'.
  --
  -- This is just a convenience function intended for valid module strings. It is
  -- an error if it is used with a string that is not a valid module name. If you
  -- are parsing user input then use 'Distribution.Text.simpleParse' instead.
  --
  fromString :: String -> ModuleName
  fromString string
    | all validModuleComponent components' = ModuleName components'
    | otherwise                            = error badName
  
    where
      components' = split string
      badName     = "ModuleName.fromString: invalid module name " ++ show string
  
      split cs = case break (=='.') cs of
        (chunk,[])     -> chunk : []
        (chunk,_:rest) -> chunk : split rest
  
  -- | The module name @Main@.
  --
  main :: ModuleName
  main = ModuleName ["Main"]
  
  -- | The individual components of a hierarchical module name. For example
  --
  -- > components (fromString "A.B.C") = ["A", "B", "C"]
  --
  components :: ModuleName -> [String]
  components (ModuleName ms) = ms
  
  -- | Convert a module name to a file path, but without any file extension.
  -- For example:
  --
  -- > toFilePath (fromString "A.B.C") = "A/B/C"
  --
  toFilePath :: ModuleName -> FilePath
  toFilePath = intercalate [pathSeparator] . components
  