- Temporary ->
- return (dflags', output_fn)
- _other ->
- do final_fn <- get_output_fn stop_phase maybe_loc
- when (final_fn /= output_fn) $
- copy dflags ("Copying `" ++ output_fn ++ "' to `" ++ final_fn
- ++ "'") output_fn final_fn
- return (dflags', final_fn)
-
-
-
-pipeLoop :: DynFlags -> Phase -> Phase
- -> FilePath -> String -> Suffix
- -> (Phase -> Maybe ModLocation -> IO FilePath)
- -> Maybe ModLocation
- -> IO (DynFlags, FilePath, Maybe ModLocation)
-
-pipeLoop dflags phase stop_phase
- input_fn orig_basename orig_suff
- orig_get_output_fn maybe_loc
-
- | phase `eqPhase` stop_phase -- All done
- = return (dflags, input_fn, maybe_loc)
-
- | not (phase `happensBefore` stop_phase)
- -- Something has gone wrong. We'll try to cover all the cases when
- -- this could happen, so if we reach here it is a panic.
- -- eg. it might happen if the -C flag is used on a source file that
- -- has {-# OPTIONS -fasm #-}.
- = panic ("pipeLoop: at phase " ++ show phase ++
- " but I wanted to stop at phase " ++ show stop_phase)
-
- | otherwise
- = do { (next_phase, dflags', maybe_loc, output_fn)
- <- runPhase phase stop_phase dflags orig_basename
- orig_suff input_fn orig_get_output_fn maybe_loc
- ; pipeLoop dflags' next_phase stop_phase output_fn
- orig_basename orig_suff orig_get_output_fn maybe_loc }
+ Temporary ->
+ return (dflags', output_fn)
+ _other ->
+ do final_fn <- get_output_fn dflags' stop_phase maybe_loc
+ when (final_fn /= output_fn) $ do
+ let msg = ("Copying `" ++ output_fn ++"' to `" ++ final_fn ++ "'")
+ line_prag = Just ("{-# LINE 1 \"" ++ input_fn ++ "\" #-}\n")
+ copyWithHeader dflags msg line_prag output_fn final_fn
+ return (dflags', final_fn)
+
+-- -----------------------------------------------------------------------------
+-- The pipeline uses a monad to carry around various bits of information
+
+-- PipeEnv: invariant information passed down
+data PipeEnv = PipeEnv {
+ stop_phase :: Phase, -- ^ Stop just before this phase
+ src_basename :: String, -- ^ basename of original input source
+ src_suffix :: String, -- ^ its extension
+ output_spec :: PipelineOutput -- ^ says where to put the pipeline output
+ }
+
+-- PipeState: information that might change during a pipeline run
+data PipeState = PipeState {
+ hsc_env :: HscEnv,
+ -- ^ only the DynFlags change in the HscEnv. The DynFlags change
+ -- at various points, for example when we read the OPTIONS_GHC
+ -- pragmas in the Cpp phase.
+ maybe_loc :: Maybe ModLocation,
+ -- ^ the ModLocation. This is discovered during compilation,
+ -- in the Hsc phase where we read the module header.
+ maybe_stub_o :: Maybe FilePath
+ -- ^ the stub object. This is set by the Hsc phase if a stub
+ -- object was created. The stub object will be joined with
+ -- the main compilation object using "ld -r" at the end.
+ }
+
+getPipeEnv :: CompPipeline PipeEnv
+getPipeEnv = P $ \env state -> return (state, env)
+
+getPipeState :: CompPipeline PipeState
+getPipeState = P $ \_env state -> return (state, state)
+
+getDynFlags :: CompPipeline DynFlags
+getDynFlags = P $ \_env state -> return (state, hsc_dflags (hsc_env state))
+
+setDynFlags :: DynFlags -> CompPipeline ()
+setDynFlags dflags = P $ \_env state ->
+ return (state{hsc_env= (hsc_env state){ hsc_dflags = dflags }}, ())
+
+setModLocation :: ModLocation -> CompPipeline ()
+setModLocation loc = P $ \_env state ->
+ return (state{ maybe_loc = Just loc }, ())
+
+setStubO :: FilePath -> CompPipeline ()
+setStubO stub_o = P $ \_env state ->
+ return (state{ maybe_stub_o = Just stub_o }, ())
+
+newtype CompPipeline a = P { unP :: PipeEnv -> PipeState -> IO (PipeState, a) }
+
+instance Monad CompPipeline where
+ return a = P $ \_env state -> return (state, a)
+ P m >>= k = P $ \env state -> do (state',a) <- m env state
+ unP (k a) env state'
+
+io :: IO a -> CompPipeline a
+io m = P $ \_env state -> do a <- m; return (state, a)
+
+phaseOutputFilename :: Phase{-next phase-} -> CompPipeline FilePath
+phaseOutputFilename next_phase = do
+ PipeEnv{stop_phase, src_basename, output_spec} <- getPipeEnv
+ PipeState{maybe_loc, hsc_env} <- getPipeState
+ let dflags = hsc_dflags hsc_env
+ io $ getOutputFilename stop_phase output_spec
+ src_basename dflags next_phase maybe_loc
+
+-- ---------------------------------------------------------------------------
+-- outer pipeline loop
+
+-- | pipeLoop runs phases until we reach the stop phase
+pipeLoop :: Phase -> FilePath -> CompPipeline FilePath
+pipeLoop phase input_fn = do
+ PipeEnv{stop_phase} <- getPipeEnv
+ PipeState{hsc_env} <- getPipeState
+ case () of
+ _ | phase `eqPhase` stop_phase -- All done
+ -> return input_fn
+
+ | not (phase `happensBefore` stop_phase)
+ -- Something has gone wrong. We'll try to cover all the cases when
+ -- this could happen, so if we reach here it is a panic.
+ -- eg. it might happen if the -C flag is used on a source file that
+ -- has {-# OPTIONS -fasm #-}.
+ -> panic ("pipeLoop: at phase " ++ show phase ++
+ " but I wanted to stop at phase " ++ show stop_phase)
+
+ | otherwise
+ -> do io $ debugTraceMsg (hsc_dflags hsc_env) 4
+ (ptext (sLit "Running phase") <+> ppr phase)
+ dflags <- getDynFlags
+ (next_phase, output_fn) <- runPhase phase input_fn dflags
+ pipeLoop next_phase output_fn
+
+-- -----------------------------------------------------------------------------
+-- In each phase, we need to know into what filename to generate the
+-- output. All the logic about which filenames we generate output
+-- into is embodied in the following function.