module Vectorise.Monad.Base (
  
  VResult(..),
  VM(..),
  
  liftDs,
  
  cantVectorise,
  maybeCantVectorise,
  maybeCantVectoriseM,
  
  emitVt, traceVt, dumpOptVt, dumpVt,
  
  noV, traceNoV,
  ensureV, traceEnsureV,
  onlyIfV,
  tryV, tryErrV,
  maybeV,  traceMaybeV,
  orElseV, orElseErrV,
  fixV,
) where
import GhcPrelude
import Vectorise.Builtins
import Vectorise.Env
import DsMonad
import TcRnMonad
import ErrUtils
import Outputable
import DynFlags
import Control.Monad
data VResult a
  = Yes GlobalEnv LocalEnv a
  | No  SDoc
newtype VM a
  = VM { runVM :: Builtins -> GlobalEnv -> LocalEnv -> DsM (VResult a) }
instance Monad VM where
  VM p >>= f = VM $ \bi genv lenv -> do
                                       r <- p bi genv lenv
                                       case r of
                                         Yes genv' lenv' x -> runVM (f x) bi genv' lenv'
                                         No reason         -> return $ No reason
instance Applicative VM where
  pure x = VM $ \_ genv lenv -> return (Yes genv lenv x)
  (<*>) = ap
instance Functor VM where
  fmap = liftM
instance MonadIO VM where
  liftIO = liftDs . liftIO
instance HasDynFlags VM where
    getDynFlags = liftDs getDynFlags
liftDs :: DsM a -> VM a
liftDs p = VM $ \_ genv lenv -> do { x <- p; return (Yes genv lenv x) }
cantVectorise :: DynFlags -> String -> SDoc -> a
cantVectorise dflags s d = pgmError
                  . showSDoc dflags
                  $ vcat [text "*** Vectorisation error ***",
                          nest 4 $ sep [text s, nest 4 d]]
maybeCantVectorise :: DynFlags -> String -> SDoc -> Maybe a -> a
maybeCantVectorise dflags s d Nothing  = cantVectorise dflags s d
maybeCantVectorise _ _ _ (Just x) = x
maybeCantVectoriseM :: (Monad m, HasDynFlags m)
                    => String -> SDoc -> m (Maybe a) -> m a
maybeCantVectoriseM s d p
  = do
      r <- p
      case r of
        Just x  -> return x
        Nothing ->
            do dflags <- getDynFlags
               cantVectorise dflags s d
emitVt :: String -> SDoc -> VM ()
emitVt herald doc
  = liftDs $ do
      dflags <- getDynFlags
      liftIO . printOutputForUser dflags alwaysQualify $
        hang (text herald) 2 doc
traceVt :: String -> SDoc -> VM ()
traceVt herald doc
  = liftDs $ traceOptIf Opt_D_dump_vt_trace $ hang (text herald) 2 doc
dumpOptVt :: DumpFlag -> String -> SDoc -> VM ()
dumpOptVt flag header doc
  = do { b <- liftDs $ doptM flag
       ; if b
         then dumpVt header doc
         else return ()
       }
dumpVt :: String -> SDoc -> VM ()
dumpVt header doc
  = do { unqual <- liftDs mkPrintUnqualifiedDs
       ; dflags <- liftDs getDynFlags
       ; liftIO $ printOutputForUser dflags unqual (mkDumpDoc header doc)
       }
noV :: SDoc -> VM a
noV reason = VM $ \_ _ _ -> return $ No reason
traceNoV :: String -> SDoc -> VM a
traceNoV s d = pprTrace s d $ noV d
ensureV :: SDoc -> Bool -> VM ()
ensureV reason  False = noV reason
ensureV _reason True  = return ()
traceEnsureV :: String -> SDoc -> Bool -> VM ()
traceEnsureV s d False = traceNoV s d
traceEnsureV _ _ True  = return ()
onlyIfV :: SDoc -> Bool -> VM a -> VM a
onlyIfV reason b p = ensureV reason b >> p
tryErrV :: VM a -> VM (Maybe a)
tryErrV (VM p) = VM $ \bi genv lenv ->
  do
    r <- p bi genv lenv
    case r of
      Yes genv' lenv' x -> return (Yes genv' lenv' (Just x))
      No reason         -> do { unqual <- mkPrintUnqualifiedDs
                              ; dflags <- getDynFlags
                              ; liftIO $
                                  printInfoForUser dflags unqual $
                                    text "Warning: vectorisation failure:" <+> reason
                              ; return (Yes genv  lenv  Nothing)
                              }
tryV :: VM a -> VM (Maybe a)
tryV (VM p) = VM $ \bi genv lenv ->
  do
    r <- p bi genv lenv
    case r of
      Yes genv' lenv' x -> return (Yes genv' lenv' (Just x))
      No _reason        -> return (Yes genv  lenv  Nothing)
maybeV :: SDoc -> VM (Maybe a) -> VM a
maybeV reason p = maybe (noV reason) return =<< p
traceMaybeV :: String -> SDoc -> VM (Maybe a) -> VM a
traceMaybeV s d p = maybe (traceNoV s d) return =<< p
orElseErrV :: VM a -> VM a -> VM a
orElseErrV p q = maybe q return =<< tryErrV p
orElseV :: VM a -> VM a -> VM a
orElseV p q = maybe q return =<< tryV p
fixV :: (a -> VM a) -> VM a
fixV f = VM (\bi genv lenv -> fixDs $ \r -> runVM (f (unYes r)) bi genv lenv )
  where
    
    
    unYes (Yes _ _ x) = x
    unYes (No reason) = pprPanic "Vectorise.Monad.Base.fixV: no result" reason