1{-# LANGUAGE MagicHash, UnboxedTuples #-}
2module ProjectM36.ScriptSession where
6import Control.Exception
10import Control.Monad.IO.Class
11import System.FilePath.Glob
13import System.Info (os, arch)
14import Data.Text (Text, unpack)
18import GHC.Paths (libdir)
19#if __GLASGOW_HASKELL__ >= 800
20import GHC.LanguageExtensions
24import Outputable --hiding ((<>))
29import GHC.Exts (addrToAny#)
30import GHC.Ptr (Ptr(..))
34data ScriptSession = ScriptSession {
36 atomFunctionBodyType :: Type,
37 dbcFunctionBodyType :: Type
40newtype ScriptSessionError = ScriptSessionLoadError GhcException
43-- | Configure a GHC environment/session which we will use for all script compilation.
44initScriptSession :: [String] -> IO (Either ScriptSessionError ScriptSession)
45initScriptSession ghcPkgPaths = do
46 --for the sake of convenience, for developers' builds, include the local cabal sandbox package database and the cabal new-build package database
47 eHomeDir <- tryJust (guard . isDoesNotExistError) getHomeDirectory
48 let homeDir = either (const "/") id eHomeDir
49 let excHandler exc = pure $ Left (ScriptSessionLoadError exc)
50 handleGhcException excHandler $ runGhc (Just libdir) $ do
51 dflags <- getSessionDynFlags
52 let ghcVersion = projectVersion dflags
54 sandboxPkgPaths <- liftIO $ concat <$> mapM glob [
55 "./dist-newstyle/packagedb/ghc-" ++ ghcVersion,
56 ".cabal-sandbox/*ghc-" ++ ghcVersion ++ "-packages.conf.d",
57 ".stack-work/install/*/*/" ++ ghcVersion ++ "/pkgdb",
58 ".stack-work/install/*/pkgdb/", --windows stack build
59 "C:/sr/snapshots/b201cfe6/pkgdb", --windows stack build- ideally, we could run `stack path --snapshot-pkg-db, but this is sufficient to pass CI
60 homeDir </> ".stack/snapshots/*/*/" ++ ghcVersion ++ "/pkgdb",
61 homeDir </> ".cabal/store/ghc-" ++ ghcVersion ++ "/package.db"
64 let localPkgPaths = map PkgConfFile (ghcPkgPaths ++ sandboxPkgPaths)
66 let dflags' = applyGopts . applyXopts $ dflags { hscTarget = HscInterpreted ,
67 ghcLink = LinkInMemory,
68 safeHaskell = Sf_Trustworthy,
72#if __GLASGOW_HASKELL__ >= 800
73 trustFlags = map TrustPackage required_packages,
75 packageFlags = packageFlags dflags ++ packages,
76 extraPkgConfs = const (localPkgPaths ++ [UserPkgConf, GlobalPkgConf])
78 applyGopts flags = foldl gopt_set flags gopts
79 applyXopts flags = foldl xopt_set flags xopts
80#if __GLASGOW_HASKELL__ >= 800
81 xopts = [OverloadedStrings, ExtendedDefaultRules, ImplicitPrelude, ScopedTypeVariables]
83 xopts = [Opt_OverloadedStrings, Opt_ExtendedDefaultRules, Opt_ImplicitPrelude, Opt_ScopedTypeVariables]
85 gopts = [] --[Opt_DistrustAllPackages, Opt_PackageTrust]
86 required_packages = ["base",
90 "unordered-containers",
96 "vector-binary-instances",
100#if __GLASGOW_HASKELL__ >= 800
101 packages = map (\m -> ExposePackage ("-package " ++ m) (PackageArg m) (ModRenaming True [])) required_packages
103 packages = map TrustPackage required_packages
105 --liftIO $ traceShowM (showSDoc dflags' (ppr packages))
106 _ <- setSessionDynFlags dflags'
107 let safeImportDecl mn mQual = ImportDecl {
108 ideclSourceSrc = Nothing,
109 ideclName = noLoc mn,
110 ideclPkgQual = Nothing,
113 ideclImplicit = False,
114 ideclQualified = isJust mQual,
116 ideclHiding = Nothing
118 unqualifiedModules = map (\modn -> IIDecl $ safeImportDecl (mkModuleName modn) Nothing) [
122 "Data.Time.Calendar",
123 "Control.Monad.State",
125 "ProjectM36.Relation",
126 "ProjectM36.AtomFunctionError",
127 "ProjectM36.DatabaseContextFunctionError",
128 "ProjectM36.DatabaseContextFunctionUtils",
129 "ProjectM36.RelationalExpression"]
130 qualifiedModules = map (\(modn, qualNam) -> IIDecl $ safeImportDecl (mkModuleName modn) (Just (mkModuleName qualNam))) [
133 setContext (unqualifiedModules ++ qualifiedModules)
135 atomFuncType <- mkTypeForName "AtomFunctionBodyType"
136 dbcFuncType <- mkTypeForName "DatabaseContextFunctionBodyType"
137 pure (Right (ScriptSession env atomFuncType dbcFuncType))
139addImport :: String -> Ghc ()
140addImport moduleNam = do
142 setContext ( (IIDecl $ simpleImportDecl (mkModuleName moduleNam)) : ctx )
144showType :: DynFlags -> Type -> String
145showType dflags ty = showSDocForUser dflags alwaysQualify (pprTypeForUser ty)
147mkTypeForName :: String -> Ghc Type
148mkTypeForName name = do
149 lBodyName <- parseName name
151 [] -> error ("failed to parse " ++ name)
152 _:_:_ -> error "too many name matches"
154 mThing <- lookupName bodyName
156 Nothing -> error ("failed to find " ++ name)
157 Just (ATyCon tyCon) -> case synTyConRhs_maybe tyCon of
159 Nothing -> error (name ++ " is not a type synonym")
160 Just _ -> error ("failed to find type synonym " ++ name)
162compileScript :: Type -> Text -> Ghc (Either ScriptCompilationError a)
163compileScript funcType script = do
164 let sScript = unpack script
165 mErr <- typeCheckScript funcType script
167 Just err -> pure (Left err)
169 --catch exception here
170 --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.
171 -- we can't use dynCompileExpr here because
172 Right . unsafeCoerce <$> compileExpr sScript
174typeCheckScript :: Type -> Text -> Ghc (Maybe ScriptCompilationError)
175typeCheckScript expectedType inp = do
176 dflags <- getSessionDynFlags
177 --catch exception for SyntaxError
178 funcType <- GHC.exprType (unpack inp)
179 --liftIO $ putStrLn $ showType dflags expectedType ++ ":::" ++ showType dflags funcType
180 if eqType funcType expectedType then
183 pure (Just (TypeCheckCompilationError (showType dflags expectedType) (showType dflags funcType)))
185mangleSymbol :: Maybe String -> String -> String -> String
186mangleSymbol pkg module' valsym =
188 maybe "" (\p -> zEncodeString p ++ "_") pkg ++
189 zEncodeString module' ++ "_" ++ zEncodeString valsym ++ "_closure"
192type FuncName = String
194data LoadSymbolError = LoadSymbolError
196loadFunction :: ModName -> FuncName -> FilePath -> IO (Either LoadSymbolError a)
197loadFunction modName funcName objPath = do
201 ptr <- lookupSymbol (mangleSymbol Nothing modName funcName)
203 Nothing -> pure (Left LoadSymbolError)
204 Just (Ptr addr) -> case addrToAny# addr of
205 (# hval #) -> pure (Right hval)
207prefixUnderscore :: String
210 ("mingw32","x86_64") -> ""
211 ("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