module GHC.Types.Target
   ( Target(..)
   , TargetId(..)
   , InputFileBuffer
   , pprTarget
   , pprTargetId
   )
where

import GHC.Prelude
import GHC.Driver.Phases ( Phase )
import GHC.Unit
import GHC.Data.StringBuffer ( StringBuffer )
import GHC.Utils.Outputable

import Data.Time

-- | A compilation target.
--
-- A target may be supplied with the actual text of the
-- module.  If so, use this instead of the file contents (this
-- is for use in an IDE where the file hasn't been saved by
-- the user yet).
--
-- These fields are strict because Targets are long lived.
data Target
  = Target {
      targetId           :: !TargetId, -- ^ module or filename
      targetAllowObjCode :: !Bool,     -- ^ object code allowed?
      targetUnitId       :: !UnitId,   -- ^ id of the unit this target is part of
      targetContents     :: !(Maybe (InputFileBuffer, UTCTime))
      -- ^ Optional in-memory buffer containing the source code GHC should
      -- use for this target instead of reading it from disk.
      --
      -- Since GHC version 8.10 modules which require preprocessors such as
      -- Literate Haskell or CPP to run are also supported.
      --
      -- If a corresponding source file does not exist on disk this will
      -- result in a 'SourceError' exception if @targetId = TargetModule _@
      -- is used. However together with @targetId = TargetFile _@ GHC will
      -- not complain about the file missing.
    }

data TargetId
  = TargetModule !ModuleName
        -- ^ A module name: search for the file
  | TargetFile !FilePath !(Maybe Phase)
        -- ^ A filename: preprocess & parse it to find the module name.
        -- If specified, the Phase indicates how to compile this file
        -- (which phase to start from).  Nothing indicates the starting phase
        -- should be determined from the suffix of the filename.
  deriving Eq

type InputFileBuffer = StringBuffer


pprTarget :: Target -> SDoc
pprTarget Target { targetUnitId = uid, targetId = id, targetAllowObjCode = obj } =
    (if obj then empty else char '*') <> ppr uid <> colon <> pprTargetId id

instance Outputable Target where
    ppr = pprTarget

pprTargetId :: TargetId -> SDoc
pprTargetId (TargetModule m) = ppr m
pprTargetId (TargetFile f _) = text f

instance Outputable TargetId where
    ppr = pprTargetId

