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
27import Outputable --hiding ((<>))
32import GHC.Exts (addrToAny#)
33import GHC.Ptr (Ptr(..))
36data ScriptSession = ScriptSession {
38 atomFunctionBodyType :: Type,
39 dbcFunctionBodyType :: Type
42newtype ScriptSessionError = ScriptSessionLoadError GhcException
45-- | Configure a GHC environment/session which we will use for all script compilation.
46initScriptSession :: [String] -> IO (Either ScriptSessionError ScriptSession)
47initScriptSession ghcPkgPaths = do
48 --for the sake of convenience, for developers' builds, include the local cabal sandbox package database and the cabal new-build package database
49 eHomeDir <- tryJust (guard . isDoesNotExistError) getHomeDirectory
50 let homeDir = either (const "/") id eHomeDir
51 let excHandler exc = pure $ Left (ScriptSessionLoadError exc)
52 handleGhcException excHandler $ runGhc (Just libdir) $ do
53 dflags <- getSessionDynFlags
54 let ghcVersion = projectVersion dflags
56 sandboxPkgPaths <- liftIO $ concat <$> mapM glob [
57 "./dist-newstyle/packagedb/ghc-" ++ ghcVersion,
58 ".cabal-sandbox/*ghc-" ++ ghcVersion ++ "-packages.conf.d",
59 ".stack-work/install/*/*/" ++ ghcVersion ++ "/pkgdb",
60 ".stack-work/install/*/pkgdb/", --windows stack build
61 "C:/sr/snapshots/b201cfe6/pkgdb", --windows stack build- ideally, we could run `stack path --snapshot-pkg-db, but this is sufficient to pass CI
62 homeDir </> ".stack/snapshots/*/*/" ++ ghcVersion ++ "/pkgdb",
63 homeDir </> ".cabal/store/ghc-" ++ ghcVersion ++ "/package.db"
66 let localPkgPaths = map PkgConfFile (ghcPkgPaths ++ sandboxPkgPaths)
68 let dflags' = applyGopts . applyXopts $ dflags { hscTarget = HscInterpreted ,
69 ghcLink = LinkInMemory,
70 safeHaskell = Sf_Trustworthy,
74#if __GLASGOW_HASKELL__ >= 800
75 trustFlags = map TrustPackage required_packages,
77 packageFlags = packageFlags dflags ++ packages,
78 extraPkgConfs = const (localPkgPaths ++ [UserPkgConf, GlobalPkgConf])
80 applyGopts flags = foldl gopt_set flags gopts
81 applyXopts flags = foldl xopt_set flags xopts
82#if __GLASGOW_HASKELL__ >= 800
83 xopts = [OverloadedStrings, ExtendedDefaultRules, ImplicitPrelude, ScopedTypeVariables]
85 xopts = [Opt_OverloadedStrings, Opt_ExtendedDefaultRules, Opt_ImplicitPrelude, Opt_ScopedTypeVariables]
87 gopts = [] --[Opt_DistrustAllPackages, Opt_PackageTrust]
88 required_packages = ["base",
92 "unordered-containers",
98 "vector-binary-instances",
102#if __GLASGOW_HASKELL__ >= 800
103 packages = map (\m -> ExposePackage ("-package " ++ m) (PackageArg m) (ModRenaming True [])) required_packages
105 packages = map TrustPackage required_packages
107 --liftIO $ traceShowM (showSDoc dflags' (ppr packages))
108 _ <- setSessionDynFlags dflags'
109 let safeImportDecl mn mQual = ImportDecl {
110 ideclSourceSrc = Nothing,
111 ideclName = noLoc mn,
112 ideclPkgQual = Nothing,
115 ideclImplicit = False,
116 ideclQualified = isJust mQual,
118 ideclHiding = Nothing
120 unqualifiedModules = map (\modn -> IIDecl $ safeImportDecl (mkModuleName modn) Nothing) [
124 "Data.Time.Calendar",
125 "Control.Monad.State",
127 "ProjectM36.Relation",
128 "ProjectM36.AtomFunctionError",
129 "ProjectM36.DatabaseContextFunctionError",
130 "ProjectM36.DatabaseContextFunctionUtils",
131 "ProjectM36.RelationalExpression"]
132 qualifiedModules = map (\(modn, qualNam) -> IIDecl $ safeImportDecl (mkModuleName modn) (Just (mkModuleName qualNam))) [
135 setContext (unqualifiedModules ++ qualifiedModules)
137 atomFuncType <- mkTypeForName "AtomFunctionBodyType"
138 dbcFuncType <- mkTypeForName "DatabaseContextFunctionBodyType"
139 pure (Right (ScriptSession env atomFuncType dbcFuncType))
141addImport :: String -> Ghc ()
142addImport moduleNam = do
144 setContext ( (IIDecl $ simpleImportDecl (mkModuleName moduleNam)) : ctx )
146showType :: DynFlags -> Type -> String
147showType dflags ty = showSDocForUser dflags alwaysQualify (pprTypeForUser ty)
149mkTypeForName :: String -> Ghc Type
150mkTypeForName name = do
151 lBodyName <- parseName name
153 [] -> error ("failed to parse " ++ name)
154 _:_:_ -> error "too many name matches"
156 mThing <- lookupName bodyName
158 Nothing -> error ("failed to find " ++ name)
159 Just (ATyCon tyCon) -> case synTyConRhs_maybe tyCon of
161 Nothing -> error (name ++ " is not a type synonym")
162 Just _ -> error ("failed to find type synonym " ++ name)
164compileScript :: Type -> Text -> Ghc (Either ScriptCompilationError a)
165compileScript funcType script = do
166 let sScript = unpack script
167 mErr <- typeCheckScript funcType script
169 Just err -> pure (Left err)
171 --catch exception here
172 --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.
173 -- we can't use dynCompileExpr here because
174 Right . unsafeCoerce <$> compileExpr sScript
176typeCheckScript :: Type -> Text -> Ghc (Maybe ScriptCompilationError)
177typeCheckScript expectedType inp = do
178 dflags <- getSessionDynFlags
179 --catch exception for SyntaxError
180 funcType <- GHC.exprType (unpack inp)
181 --liftIO $ putStrLn $ showType dflags expectedType ++ ":::" ++ showType dflags funcType
182 if eqType funcType expectedType then
185 pure (Just (TypeCheckCompilationError (showType dflags expectedType) (showType dflags funcType)))
187mangleSymbol :: Maybe String -> String -> String -> String
188mangleSymbol pkg module' valsym =
190 maybe "" (\p -> zEncodeString p ++ "_") pkg ++
191 zEncodeString module' ++ "_" ++ zEncodeString valsym ++ "_closure"
194type FuncName = String
196data LoadSymbolError = LoadSymbolError
198loadFunction :: ModName -> FuncName -> FilePath -> IO (Either LoadSymbolError a)
199loadFunction modName funcName objPath = do
203 ptr <- lookupSymbol (mangleSymbol Nothing modName funcName)
205 Nothing -> pure (Left LoadSymbolError)
206 Just (Ptr addr) -> case addrToAny# addr of
207 (# hval #) -> pure (Right hval)
209prefixUnderscore :: String
212 ("mingw32","x86_64") -> ""
213 ("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