packages feed

semdoc-0.1.0: src/Text/Semdoc/EvalExpr.hs

{-# LANGUAGE NamedFieldPuns #-}
module Text.Semdoc.EvalExpr where

import           Control.Applicative  ((<$>))
import           Control.Monad        (join)
import           Debugger             (showTerm)
import           DynFlags             (ExtensionFlag (..), PkgConfRef (..),
                                       xopt_set)
import           GHC
import           GHC.Paths            (libdir)
import           MonadUtils
import           Outputable           (neverQualify, showSDocForUser)
import           Packages             (initPackages)
import           System.FilePath.Glob (glob)


data EvalInput a = EvalInput
  { inputModule :: String
  , inputStmts  :: String
  }
  deriving (Show)


addPkgDbs :: GhcMonad m => [FilePath] -> m ()
addPkgDbs fps = do
  dfs <- getSessionDynFlags
  let pkgs = map PkgConfFile fps
  let dfs' = dfs { extraPkgConfs = (pkgs ++) . extraPkgConfs dfs }
  _ <- setSessionDynFlags dfs'
  _ <- liftIO $ initPackages dfs'
  return ()


evalExpr :: Read a => [EvalInput a] -> IO [a]
evalExpr exprs = do
  pkgDbs <- join <$> mapM glob
    [ "dist/package.conf.inplace"
    , ".cabal-sandbox/*-packages.conf.d"
    , "../.cabal-sandbox/*-packages.conf.d"
    ]
  GHC.runGhc (Just libdir) $ do
    addPkgDbs pkgDbs
    dflags <- getSessionDynFlags
    _ <- setSessionDynFlags $ foldl xopt_set dflags
      { hscTarget = HscInterpreted
      , ghcLink   = LinkInMemory
      , ghcMode   = CompManager
      } [Opt_ImplicitPrelude]

    _ <- load LoadAllTargets
    mapM evalOne exprs


evalOne :: (Read a, GhcMonad m) => EvalInput a -> m a
evalOne EvalInput { inputModule, inputStmts } = do
  setContext $ map mkImportDecl
    [ ("Data.Char"       , Just "Char")
    , ("Data.List"       , Just "List")
    , ("Prelude"         , Nothing)
    , ("Text.Pandoc"     , Nothing)
    , ("Text.Printf"     , Nothing)
    , ("Text.Semdoc.Util", Nothing)
    , (inputModule       , Nothing)
    ]
  ns <- reverse <$> runDecls inputStmts
  case ns of
    n:_ -> getResult n
    _   -> fail "no declarations found"

  where
    mkImportDecl (m, n) =
      IIDecl (simpleImportDecl $ mkModuleName m)
        { ideclAs = fmap mkModuleName n
        , ideclQualified = n /= Nothing
        }


getResult :: (Read a, GhcMonad m) => Name -> m a
getResult n = do
  df <- getSessionDynFlags
  Just (AnId aid) <- lookupName n
  result <- fmap (pp df) $ showTerm =<< obtainTermFromId maxBound True aid
  --liftIO $ putStrLn result
  return $ read result

  where
    pp df = showSDocForUser df neverQualify