1{-# LANGUAGE MagicHash, UnboxedTuples #-}
2#if MIN_VERSION_GLASGOW_HASKELL(8,6,0,0)
5module ProjectM36.ScriptSession where
9import Control.Exception
12import System.Directory
13import Control.Monad.IO.Class
14import System.FilePath.Glob
16import System.Info (os, arch)
17import Data.Text (Text, unpack)
21import GHC.Paths (libdir)
22#if __GLASGOW_HASKELL__ >= 800
23import GHC.LanguageExtensions
28#if __GLASGOW_HASKELL__ >= 802
33import Outputable --hiding ((<>))
36#if __GLASGOW_HASKELL__ >= 802
38#elif __GLASGOW_HASKELL__ >= 710
39import Type hiding (pprTyThing)
43import GHC.Exts (addrToAny#)
44import GHC.Ptr (Ptr(..))
47data ScriptSession = ScriptSession {
49 atomFunctionBodyType :: Type,
50 dbcFunctionBodyType :: Type
53newtype ScriptSessionError = ScriptSessionLoadError GhcException
56-- | Configure a GHC environment/session which we will use for all script compilation.
57initScriptSession :: [String] -> IO (Either ScriptSessionError ScriptSession)
58initScriptSession ghcPkgPaths = do
59 --for the sake of convenience, for developers' builds, include the local cabal sandbox package database and the cabal new-build package database
60 eHomeDir <- tryJust (guard . isDoesNotExistError) getHomeDirectory
61 let homeDir = either (const "/") id eHomeDir
62 let excHandler exc = pure $ Left (ScriptSessionLoadError exc)
63 handleGhcException excHandler $ runGhc (Just libdir) $ do
64 dflags <- getSessionDynFlags
65 let ghcVersion = projectVersion dflags
67 sandboxPkgPaths <- liftIO $ concat <$> mapM glob [
68 "./dist-newstyle/packagedb/ghc-" ++ ghcVersion,
69 ".cabal-sandbox/*ghc-" ++ ghcVersion ++ "-packages.conf.d",
70 ".stack-work/install/*/*/" ++ ghcVersion ++ "/pkgdb",
71 ".stack-work/install/*/pkgdb/", --windows stack build
72 "C:/sr/snapshots/b201cfe6/pkgdb", --windows stack build- ideally, we could run `stack path --snapshot-pkg-db, but this is sufficient to pass CI
73 homeDir </> ".stack/snapshots/*/*/" ++ ghcVersion ++ "/pkgdb",
74 homeDir </> ".cabal/store/ghc-" ++ ghcVersion ++ "/package.db"
77 let localPkgPaths = map PkgConfFile (ghcPkgPaths ++ sandboxPkgPaths)
79 let dflags' = applyGopts . applyXopts $ dflags { hscTarget = HscInterpreted ,
80 ghcLink = LinkInMemory,
81 safeHaskell = Sf_Trustworthy,
85#if __GLASGOW_HASKELL__ >= 800
86 trustFlags = map TrustPackage required_packages,
88 packageFlags = packageFlags dflags ++ packages,
89#if __GLASGOW_HASKELL__ >= 802
90 packageDBFlags = map PackageDB localPkgPaths
92 extraPkgConfs = const (localPkgPaths ++ [UserPkgConf, GlobalPkgConf])
96 applyGopts flags = foldl gopt_set flags gopts
97 applyXopts flags = foldl xopt_set flags xopts
98#if __GLASGOW_HASKELL__ >= 800
99 xopts = [OverloadedStrings, ExtendedDefaultRules, ImplicitPrelude, ScopedTypeVariables]
101 xopts = [Opt_OverloadedStrings, Opt_ExtendedDefaultRules, Opt_ImplicitPrelude, Opt_ScopedTypeVariables]
103 gopts = [] --[Opt_DistrustAllPackages, Opt_PackageTrust]
104 required_packages = ["base",
108 "unordered-containers",
114 "vector-binary-instances",
118#if __GLASGOW_HASKELL__ >= 800
119 packages = map (\m -> ExposePackage ("-package " ++ m) (PackageArg m) (ModRenaming True [])) required_packages
121 packages = map TrustPackage required_packages
123 --liftIO $ traceShowM (showSDoc dflags' (ppr packages))
124 _ <- setSessionDynFlags dflags'
125 let safeImportDecl mn mQual = ImportDecl {
126#if __GLASGOW_HASKELL__ >= 802
127 ideclSourceSrc = NoSourceText,
129 ideclSourceSrc = Nothing,
131#if MIN_VERSION_GLASGOW_HASKELL(8,6,0,0)
134 ideclName = noLoc mn,
135 ideclPkgQual = Nothing,
138 ideclImplicit = False,
139 ideclQualified = isJust mQual,
141 ideclHiding = Nothing
143 unqualifiedModules = map (\modn -> IIDecl $ safeImportDecl (mkModuleName modn) Nothing) [
147 "Data.Time.Calendar",
148 "Control.Monad.State",
150 "ProjectM36.Relation",
151 "ProjectM36.AtomFunctionError",
152 "ProjectM36.DatabaseContextFunctionError",
153 "ProjectM36.DatabaseContextFunctionUtils",
154 "ProjectM36.RelationalExpression"]
155#if __GLASGOW_HASKELL__ >= 802
156 mkModName = noLoc . mkModuleName
158 mkModName = mkModuleName
160 qualifiedModules = map (\(modn, qualNam) -> IIDecl $ safeImportDecl (mkModuleName modn) (Just (mkModName qualNam))) [
163 setContext (unqualifiedModules ++ qualifiedModules)
165 atomFuncType <- mkTypeForName "AtomFunctionBodyType"
166 dbcFuncType <- mkTypeForName "DatabaseContextFunctionBodyType"
167 pure (Right (ScriptSession env atomFuncType dbcFuncType))
169addImport :: String -> Ghc ()
170addImport moduleNam = do
172 setContext ( (IIDecl $ simpleImportDecl (mkModuleName moduleNam)) : ctx )
174showType :: DynFlags -> Type -> String
175showType dflags ty = showSDocForUser dflags alwaysQualify (pprTypeForUser ty)
177mkTypeForName :: String -> Ghc Type
178mkTypeForName name = do
179 lBodyName <- parseName name
181 [] -> error ("failed to parse " ++ name)
182 _:_:_ -> error "too many name matches"
184 mThing <- lookupName bodyName
186 Nothing -> error ("failed to find " ++ name)
187 Just (ATyCon tyCon) -> case synTyConRhs_maybe tyCon of
189 Nothing -> error (name ++ " is not a type synonym")
190 Just _ -> error ("failed to find type synonym " ++ name)
192compileScript :: Type -> Text -> Ghc (Either ScriptCompilationError a)
193compileScript funcType script = do
194 let sScript = unpack script
195 mErr <- typeCheckScript funcType script
197 Just err -> pure (Left err)
199 --catch exception here
200 --we could potentially wrap the script with Atom pattern matching so that the script doesn't have to do it, but the change to an Atom ADT should make it easier. Still, it would be nice if the script didn't have to handle a list of arguments, for example.
201 -- we can't use dynCompileExpr here because
202 Right . unsafeCoerce <$> compileExpr sScript
204typeCheckScript :: Type -> Text -> Ghc (Maybe ScriptCompilationError)
205typeCheckScript expectedType inp = do
206 dflags <- getSessionDynFlags
207 --catch exception for SyntaxError
208#if __GLASGOW_HASKELL__ >= 802
209 funcType <- GHC.exprType TM_Inst (unpack inp)
211 funcType <- GHC.exprType (unpack inp)
213 --liftIO $ putStrLn $ showType dflags expectedType ++ ":::" ++ showType dflags funcType
214 if eqType funcType expectedType then
217 pure (Just (TypeCheckCompilationError (showType dflags expectedType) (showType dflags funcType)))
219mangleSymbol :: Maybe String -> String -> String -> String
220mangleSymbol pkg module' valsym =
222 maybe "" (\p -> zEncodeString p ++ "_") pkg ++
223 zEncodeString module' ++ "_" ++ zEncodeString valsym ++ "_closure"
226type FuncName = String
228data LoadSymbolError = LoadSymbolError
230loadFunction :: ModName -> FuncName -> FilePath -> IO (Either LoadSymbolError a)
231loadFunction modName funcName objPath = do
232#if __GLASGOW_HASKELL__ >= 802
233 initObjLinker RetainCAFs
239 ptr <- lookupSymbol (mangleSymbol Nothing modName funcName)
241 Nothing -> pure (Left LoadSymbolError)
242 Just (Ptr addr) -> case addrToAny# addr of
243 (# hval #) -> pure (Right hval)
245prefixUnderscore :: String
248 ("mingw32","x86_64") -> ""
249 ("cygwin","x86_64") -> ""
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list