{-# LANGUAGE PatternSynonyms #-}

module GHC.Types.SourceFile
   ( HscSource(HsBootFile, HsigFile, ..)
   , HsBootOrSig(..)
   , hscSourceToIsBoot
   , isHsBootOrSig
   , isHsBootFile, isHsigFile
   , hscSourceString
   )
where

import GHC.Prelude
import GHC.Utils.Binary
import GHC.Unit.Types

{- Note [HscSource types]
~~~~~~~~~~~~~~~~~~~~~~~~~
There are three types of source file for Haskell code:

     * HsSrcFile is an ordinary hs file which contains code,

     * HsBootFile is an hs-boot file, which is used to break
       recursive module imports (there will always be an
       HsSrcFile associated with it), and

     * HsigFile is an hsig file, which contains only type
       signatures and is used to specify signatures for
       modules.

Syntactically, hs-boot files and hsig files are quite similar: they
only include type signatures and must be associated with an
actual HsSrcFile.  isHsBootOrSig allows us to abstract over code
which is indifferent to which.  However, there are some important
differences, mostly owing to the fact that hsigs are proper
modules (you `import Sig` directly) whereas HsBootFiles are
temporary placeholders (you `import {-# SOURCE #-} Mod).
When we finish compiling the true implementation of an hs-boot,
we replace the HomeModInfo with the real HsSrcFile.  An HsigFile, on the
other hand, is never replaced (in particular, we *cannot* use the
HomeModInfo of the original HsSrcFile backing the signature, since it
will export too many symbols.)

Additionally, while HsSrcFile is the only Haskell file
which has *code*, we do generate .o files for HsigFile, because
this is how the recompilation checker figures out if a file
needs to be recompiled.  These are fake object files which
should NOT be linked against.
-}

data HsBootOrSig
  = HsBoot -- ^ .hs-boot file
  | Hsig   -- ^ .hsig file
   deriving (HsBootOrSig -> HsBootOrSig -> Bool
(HsBootOrSig -> HsBootOrSig -> Bool)
-> (HsBootOrSig -> HsBootOrSig -> Bool) -> Eq HsBootOrSig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: HsBootOrSig -> HsBootOrSig -> Bool
== :: HsBootOrSig -> HsBootOrSig -> Bool
$c/= :: HsBootOrSig -> HsBootOrSig -> Bool
/= :: HsBootOrSig -> HsBootOrSig -> Bool
Eq, Eq HsBootOrSig
Eq HsBootOrSig =>
(HsBootOrSig -> HsBootOrSig -> Ordering)
-> (HsBootOrSig -> HsBootOrSig -> Bool)
-> (HsBootOrSig -> HsBootOrSig -> Bool)
-> (HsBootOrSig -> HsBootOrSig -> Bool)
-> (HsBootOrSig -> HsBootOrSig -> Bool)
-> (HsBootOrSig -> HsBootOrSig -> HsBootOrSig)
-> (HsBootOrSig -> HsBootOrSig -> HsBootOrSig)
-> Ord HsBootOrSig
HsBootOrSig -> HsBootOrSig -> Bool
HsBootOrSig -> HsBootOrSig -> Ordering
HsBootOrSig -> HsBootOrSig -> HsBootOrSig
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: HsBootOrSig -> HsBootOrSig -> Ordering
compare :: HsBootOrSig -> HsBootOrSig -> Ordering
$c< :: HsBootOrSig -> HsBootOrSig -> Bool
< :: HsBootOrSig -> HsBootOrSig -> Bool
$c<= :: HsBootOrSig -> HsBootOrSig -> Bool
<= :: HsBootOrSig -> HsBootOrSig -> Bool
$c> :: HsBootOrSig -> HsBootOrSig -> Bool
> :: HsBootOrSig -> HsBootOrSig -> Bool
$c>= :: HsBootOrSig -> HsBootOrSig -> Bool
>= :: HsBootOrSig -> HsBootOrSig -> Bool
$cmax :: HsBootOrSig -> HsBootOrSig -> HsBootOrSig
max :: HsBootOrSig -> HsBootOrSig -> HsBootOrSig
$cmin :: HsBootOrSig -> HsBootOrSig -> HsBootOrSig
min :: HsBootOrSig -> HsBootOrSig -> HsBootOrSig
Ord, Int -> HsBootOrSig -> ShowS
[HsBootOrSig] -> ShowS
HsBootOrSig -> String
(Int -> HsBootOrSig -> ShowS)
-> (HsBootOrSig -> String)
-> ([HsBootOrSig] -> ShowS)
-> Show HsBootOrSig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> HsBootOrSig -> ShowS
showsPrec :: Int -> HsBootOrSig -> ShowS
$cshow :: HsBootOrSig -> String
show :: HsBootOrSig -> String
$cshowList :: [HsBootOrSig] -> ShowS
showList :: [HsBootOrSig] -> ShowS
Show)

data HscSource
   -- | .hs file
   = HsSrcFile
   -- | .hs-boot or .hsig file
   | HsBootOrSig !HsBootOrSig
   deriving (HscSource -> HscSource -> Bool
(HscSource -> HscSource -> Bool)
-> (HscSource -> HscSource -> Bool) -> Eq HscSource
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: HscSource -> HscSource -> Bool
== :: HscSource -> HscSource -> Bool
$c/= :: HscSource -> HscSource -> Bool
/= :: HscSource -> HscSource -> Bool
Eq, Eq HscSource
Eq HscSource =>
(HscSource -> HscSource -> Ordering)
-> (HscSource -> HscSource -> Bool)
-> (HscSource -> HscSource -> Bool)
-> (HscSource -> HscSource -> Bool)
-> (HscSource -> HscSource -> Bool)
-> (HscSource -> HscSource -> HscSource)
-> (HscSource -> HscSource -> HscSource)
-> Ord HscSource
HscSource -> HscSource -> Bool
HscSource -> HscSource -> Ordering
HscSource -> HscSource -> HscSource
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: HscSource -> HscSource -> Ordering
compare :: HscSource -> HscSource -> Ordering
$c< :: HscSource -> HscSource -> Bool
< :: HscSource -> HscSource -> Bool
$c<= :: HscSource -> HscSource -> Bool
<= :: HscSource -> HscSource -> Bool
$c> :: HscSource -> HscSource -> Bool
> :: HscSource -> HscSource -> Bool
$c>= :: HscSource -> HscSource -> Bool
>= :: HscSource -> HscSource -> Bool
$cmax :: HscSource -> HscSource -> HscSource
max :: HscSource -> HscSource -> HscSource
$cmin :: HscSource -> HscSource -> HscSource
min :: HscSource -> HscSource -> HscSource
Ord, Int -> HscSource -> ShowS
[HscSource] -> ShowS
HscSource -> String
(Int -> HscSource -> ShowS)
-> (HscSource -> String)
-> ([HscSource] -> ShowS)
-> Show HscSource
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> HscSource -> ShowS
showsPrec :: Int -> HscSource -> ShowS
$cshow :: HscSource -> String
show :: HscSource -> String
$cshowList :: [HscSource] -> ShowS
showList :: [HscSource] -> ShowS
Show)

{-# COMPLETE HsSrcFile, HsBootFile, HsigFile #-}
pattern HsBootFile, HsigFile :: HscSource
pattern $mHsBootFile :: forall {r}. HscSource -> ((# #) -> r) -> ((# #) -> r) -> r
$bHsBootFile :: HscSource
HsBootFile = HsBootOrSig HsBoot
pattern $mHsigFile :: forall {r}. HscSource -> ((# #) -> r) -> ((# #) -> r) -> r
$bHsigFile :: HscSource
HsigFile   = HsBootOrSig Hsig

-- | Tests if an 'HscSource' is a boot file, primarily for constructing elements
-- of 'BuildModule'. We conflate signatures and modules because they are bound
-- in the same namespace; only boot interfaces can be disambiguated with
-- `import {-# SOURCE #-}`.
hscSourceToIsBoot :: HscSource -> IsBootInterface
hscSourceToIsBoot :: HscSource -> IsBootInterface
hscSourceToIsBoot HscSource
HsBootFile = IsBootInterface
IsBoot
hscSourceToIsBoot HscSource
_ = IsBootInterface
NotBoot

instance Binary HscSource where
    put_ :: BinHandle -> HscSource -> IO ()
put_ BinHandle
bh HscSource
HsSrcFile = BinHandle -> Word8 -> IO ()
putByte BinHandle
bh Word8
0
    put_ BinHandle
bh HscSource
HsBootFile = BinHandle -> Word8 -> IO ()
putByte BinHandle
bh Word8
1
    put_ BinHandle
bh HscSource
HsigFile = BinHandle -> Word8 -> IO ()
putByte BinHandle
bh Word8
2
    get :: BinHandle -> IO HscSource
get BinHandle
bh = do
        Word8
h <- BinHandle -> IO Word8
getByte BinHandle
bh
        case Word8
h of
            Word8
0 -> HscSource -> IO HscSource
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return HscSource
HsSrcFile
            Word8
1 -> HscSource -> IO HscSource
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return HscSource
HsBootFile
            Word8
_ -> HscSource -> IO HscSource
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return HscSource
HsigFile

hscSourceString :: HscSource -> String
hscSourceString :: HscSource -> String
hscSourceString HscSource
HsSrcFile  = String
""
hscSourceString HscSource
HsBootFile = String
"[boot]"
hscSourceString HscSource
HsigFile   = String
"[sig]"

-- See Note [HscSource types]
isHsBootOrSig :: HscSource -> Bool
isHsBootOrSig :: HscSource -> Bool
isHsBootOrSig (HsBootOrSig HsBootOrSig
_) = Bool
True
isHsBootOrSig HscSource
HsSrcFile       = Bool
False

isHsBootFile :: HscSource -> Bool
isHsBootFile :: HscSource -> Bool
isHsBootFile HscSource
HsBootFile = Bool
True
isHsBootFile HscSource
_          = Bool
False

isHsigFile :: HscSource -> Bool
isHsigFile :: HscSource -> Bool
isHsigFile HscSource
HsigFile = Bool
True
isHsigFile HscSource
_        = Bool
False