@@ -1,11 +1,12 @@
1−{-# LANGUAGE MagicHash, UnboxedTuples #-}
1+{-# LANGUAGE UnboxedTuples, KindSignatures, DataKinds #-}
2−#if MIN_VERSION_GLASGOW_HASKELL(8,6,0,0)
2+#ifdef PM36_HASKELL_SCRIPTING
3−{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE MagicHash #-}
5module ProjectM36.ScriptSession where
5module ProjectM36.ScriptSession where
7+#ifdef PM36_HASKELL_SCRIPTING
7import ProjectM36.Error
8import ProjectM36.Error
9import Control.Exception
10import Control.Exception
10import Control.Monad
11import Control.Monad
11import System.IO.Error
12import System.IO.Error
@@ -16,8 +17,6 @@ import System.FilePath
16import System.Info (os, arch)
17import System.Info (os, arch)
17import Data.Text (Text, unpack)
18import Data.Text (Text, unpack)
18import Data.Maybe
19import Data.Maybe
21import GHC.Paths (libdir)
20import GHC.Paths (libdir)
22#if __GLASGOW_HASKELL__ >= 800
21#if __GLASGOW_HASKELL__ >= 800
23import GHC.LanguageExtensions
22import GHC.LanguageExtensions
@@ -36,25 +35,41 @@ import Unsafe.Coerce
36#if __GLASGOW_HASKELL__ >= 802
35#if __GLASGOW_HASKELL__ >= 802
37import Type
36import Type
38#elif __GLASGOW_HASKELL__ >= 710
37#elif __GLASGOW_HASKELL__ >= 710
39−import Type hiding (pprTyThing)
38+import Type hiding (pprTyThing)
43import GHC.Exts (addrToAny#)
41import GHC.Exts (addrToAny#)
44import GHC.Ptr (Ptr(..))
42import GHC.Ptr (Ptr(..))
45import Encoding
43import Encoding
47data ScriptSession = ScriptSession {
47data ScriptSession = ScriptSession {
48+#ifdef PM36_HASKELL_SCRIPTING
48− hscEnv :: HscEnv,
49+ hscEnv :: HscEnv,
49 atomFunctionBodyType :: Type,
50 atomFunctionBodyType :: Type,
50 dbcFunctionBodyType :: Type
51 dbcFunctionBodyType :: Type
55+#ifdef PM36_HASKELL_SCRIPTING
53−newtype ScriptSessionError = ScriptSessionLoadError GhcException
56+data ScriptSessionError = ScriptSessionLoadError GhcException
54 deriving (Show)
58 deriving (Show)
60+data ScriptSessionError = ScriptingDisabled
64+data LoadSymbolError = LoadSymbolError
66+type FuncName = String
56-- | Configure a GHC environment/session which we will use for all script compilation.
68-- | Configure a GHC environment/session which we will use for all script compilation.
57initScriptSession :: [String] -> IO (Either ScriptSessionError ScriptSession)
69initScriptSession :: [String] -> IO (Either ScriptSessionError ScriptSession)
70+#if !defined(PM36_HASKELL_SCRIPTING)
71+initScriptSession _ = pure (Left ScriptingDisabled)
58initScriptSession ghcPkgPaths = do
73initScriptSession 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
74 --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
75 eHomeDir <- tryJust (guard . isDoesNotExistError) getHomeDirectory
@@ -65,26 +80,26 @@ initScriptSession ghcPkgPaths = do
65 let ghcVersion = projectVersion dflags
80 let ghcVersion = projectVersion dflags
67 sandboxPkgPaths <- liftIO $ concat <$> mapM glob [
82 sandboxPkgPaths <- liftIO $ concat <$> mapM glob [
68− "./dist-newstyle/packagedb/ghc-" ++ ghcVersion,
83+ --"./dist-newstyle/packagedb/ghc-" ++ ghcVersion, --rely on cabal 3's ghc.environment install: "cabal install --lib project-m36"
69 ".cabal-sandbox/*ghc-" ++ ghcVersion ++ "-packages.conf.d",
84 ".cabal-sandbox/*ghc-" ++ ghcVersion ++ "-packages.conf.d",
70 ".stack-work/install/*/*/" ++ ghcVersion ++ "/pkgdb",
85 ".stack-work/install/*/*/" ++ ghcVersion ++ "/pkgdb",
71 ".stack-work/install/*/pkgdb/", --windows stack build
86 ".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
87 "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",
88+ homeDir </> ".stack/snapshots/*/*/" ++ ghcVersion ++ "/pkgdb"
74− homeDir </> ".cabal/store/ghc-" ++ ghcVersion ++ "/package.db"
89+ --homeDir </> ".cabal/store/ghc-" ++ ghcVersion ++ "/package.db"
77 let localPkgPaths = map PkgConfFile (ghcPkgPaths ++ sandboxPkgPaths)
92 let localPkgPaths = map PkgConfFile (ghcPkgPaths ++ sandboxPkgPaths)
79− let dflags' = applyGopts . applyXopts $ dflags { hscTarget = HscInterpreted ,
94+ let dflags' = applyGopts . applyXopts $ dflags { hscTarget = HscInterpreted ,
80− ghcLink = LinkInMemory,
95+ ghcLink = LinkInMemory,
81 safeHaskell = Sf_Trustworthy,
96 safeHaskell = Sf_Trustworthy,
82 safeInfer = True,
97 safeInfer = True,
83 safeInferred = True,
98 safeInferred = True,
84 --verbosity = 3,
99 --verbosity = 3,
85−#if __GLASGOW_HASKELL__ >= 800
100+#if __GLASGOW_HASKELL__ >= 800
86 trustFlags = map TrustPackage required_packages,
101 trustFlags = map TrustPackage required_packages,
88 packageFlags = packageFlags dflags ++ packages,
103 packageFlags = packageFlags dflags ++ packages,
89#if __GLASGOW_HASKELL__ >= 802
104#if __GLASGOW_HASKELL__ >= 802
90 packageDBFlags = map PackageDB localPkgPaths
105 packageDBFlags = map PackageDB localPkgPaths
@@ -97,11 +112,11 @@ initScriptSession ghcPkgPaths = do
97 applyXopts flags = foldl xopt_set flags xopts
112 applyXopts flags = foldl xopt_set flags xopts
98#if __GLASGOW_HASKELL__ >= 800
113#if __GLASGOW_HASKELL__ >= 800
99 xopts = [OverloadedStrings, ExtendedDefaultRules, ImplicitPrelude, ScopedTypeVariables]
114 xopts = [OverloadedStrings, ExtendedDefaultRules, ImplicitPrelude, ScopedTypeVariables]
101 xopts = [Opt_OverloadedStrings, Opt_ExtendedDefaultRules, Opt_ImplicitPrelude, Opt_ScopedTypeVariables]
116 xopts = [Opt_OverloadedStrings, Opt_ExtendedDefaultRules, Opt_ImplicitPrelude, Opt_ScopedTypeVariables]
103 gopts = [] --[Opt_DistrustAllPackages, Opt_PackageTrust]
118 gopts = [] --[Opt_DistrustAllPackages, Opt_PackageTrust]
104− required_packages = ["base",
119+ required_packages = ["base",
105 "containers",
120 "containers",
107 "directory",
122 "directory",
@@ -123,13 +138,14 @@ initScriptSession ghcPkgPaths = do
123 --liftIO $ traceShowM (showSDoc dflags' (ppr packages))
138 --liftIO $ traceShowM (showSDoc dflags' (ppr packages))
124 _ <- setSessionDynFlags dflags'
139 _ <- setSessionDynFlags dflags'
125 let safeImportDecl mn mQual = ImportDecl {
140 let safeImportDecl mn mQual = ImportDecl {
126−#if __GLASGOW_HASKELL__ >= 802
141+#if __GLASGOW_HASKELL__ >= 802
127 ideclSourceSrc = NoSourceText,
142 ideclSourceSrc = NoSourceText,
129 ideclSourceSrc = Nothing,
144 ideclSourceSrc = Nothing,
131−#if MIN_VERSION_GLASGOW_HASKELL(8,6,0,0)
146+
147+#if __GLASGOW_HASKELL__ >= 806
132− ideclExt = noExt,
148+ ideclExt = NoExt,
134 ideclName = noLoc mn,
150 ideclName = noLoc mn,
135 ideclPkgQual = Nothing,
151 ideclPkgQual = Nothing,
@@ -140,6 +156,9 @@ initScriptSession ghcPkgPaths = do
140 ideclAs = mQual,
156 ideclAs = mQual,
141 ideclHiding = Nothing
157 ideclHiding = Nothing
159+#if __GLASGOW_HASKELL__ >= 806
160+ :: ImportDecl (GhcPass (c :: Pass))
143 unqualifiedModules = map (\modn -> IIDecl $ safeImportDecl (mkModuleName modn) Nothing) [
162 unqualifiedModules = map (\modn -> IIDecl $ safeImportDecl (mkModuleName modn) Nothing) [
144 "Prelude",
163 "Prelude",
145 "Data.Map",
164 "Data.Map",
@@ -156,7 +175,7 @@ initScriptSession ghcPkgPaths = do
156 mkModName = noLoc . mkModuleName
175 mkModName = noLoc . mkModuleName
158 mkModName = mkModuleName
177 mkModName = mkModuleName
160 qualifiedModules = map (\(modn, qualNam) -> IIDecl $ safeImportDecl (mkModuleName modn) (Just (mkModName qualNam))) [
179 qualifiedModules = map (\(modn, qualNam) -> IIDecl $ safeImportDecl (mkModuleName modn) (Just (mkModName qualNam))) [
161 ("Data.Text", "T")
180 ("Data.Text", "T")
@@ -169,8 +188,8 @@ initScriptSession ghcPkgPaths = do
169addImport :: String -> Ghc ()
188addImport :: String -> Ghc ()
170addImport moduleNam = do
189addImport moduleNam = do
171 ctx <- getContext
190 ctx <- getContext
172− setContext ( (IIDecl $ simpleImportDecl (mkModuleName moduleNam)) : ctx )
191+ setContext (IIDecl (simpleImportDecl (mkModuleName moduleNam)) : ctx)
174showType :: DynFlags -> Type -> String
193showType :: DynFlags -> Type -> String
175showType dflags ty = showSDocForUser dflags alwaysQualify (pprTypeForUser ty)
194showType dflags ty = showSDocForUser dflags alwaysQualify (pprTypeForUser ty)
@@ -195,41 +214,36 @@ compileScript funcType script = do
195 mErr <- typeCheckScript funcType script
214 mErr <- typeCheckScript funcType script
196 case mErr of
215 case mErr of
197 Just err -> pure (Left err)
216 Just err -> pure (Left err)
198− Nothing ->
217+ Nothing ->
199 --catch exception here
218 --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.
219 --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
220 -- we can't use dynCompileExpr here because
202 Right . unsafeCoerce <$> compileExpr sScript
221 Right . unsafeCoerce <$> compileExpr sScript
204−typeCheckScript :: Type -> Text -> Ghc (Maybe ScriptCompilationError)
223+typeCheckScript :: Type -> Text -> Ghc (Maybe ScriptCompilationError)
205typeCheckScript expectedType inp = do
224typeCheckScript expectedType inp = do
206− dflags <- getSessionDynFlags
225+ dflags <- getSessionDynFlags
207 --catch exception for SyntaxError
226 --catch exception for SyntaxError
208#if __GLASGOW_HASKELL__ >= 802
227#if __GLASGOW_HASKELL__ >= 802
209− funcType <- GHC.exprType TM_Inst (unpack inp)
228+ funcType <- GHC.exprType TM_Inst (unpack inp)
211 funcType <- GHC.exprType (unpack inp)
230 funcType <- GHC.exprType (unpack inp)
213− --liftIO $ putStrLn $ showType dflags expectedType ++ ":::" ++ showType dflags funcType
232+ --liftIO $ putStrLn $ showType dflags expectedType ++ ":::" ++ showType dflags funcType
214 if eqType funcType expectedType then
233 if eqType funcType expectedType then
215 pure Nothing
234 pure Nothing
217 pure (Just (TypeCheckCompilationError (showType dflags expectedType) (showType dflags funcType)))
236 pure (Just (TypeCheckCompilationError (showType dflags expectedType) (showType dflags funcType)))
219mangleSymbol :: Maybe String -> String -> String -> String
238mangleSymbol :: Maybe String -> String -> String -> String
220mangleSymbol pkg module' valsym =
239mangleSymbol pkg module' valsym =
221 prefixUnderscore ++
240 prefixUnderscore ++
222 maybe "" (\p -> zEncodeString p ++ "_") pkg ++
241 maybe "" (\p -> zEncodeString p ++ "_") pkg ++
223 zEncodeString module' ++ "_" ++ zEncodeString valsym ++ "_closure"
242 zEncodeString module' ++ "_" ++ zEncodeString valsym ++ "_closure"
225−type ModName = String
226−type FuncName = String
228−data LoadSymbolError = LoadSymbolError
230loadFunction :: ModName -> FuncName -> FilePath -> IO (Either LoadSymbolError a)
244loadFunction :: ModName -> FuncName -> FilePath -> IO (Either LoadSymbolError a)
231loadFunction modName funcName objPath = do
245loadFunction modName funcName objPath = do
232−#if __GLASGOW_HASKELL__ >= 802
246+#if __GLASGOW_HASKELL__ >= 802
233 initObjLinker RetainCAFs
247 initObjLinker RetainCAFs
235 initObjLinker
249 initObjLinker
@@ -241,8 +255,8 @@ loadFunction modName funcName objPath = do
241 Nothing -> pure (Left LoadSymbolError)
255 Nothing -> pure (Left LoadSymbolError)
242 Just (Ptr addr) -> case addrToAny# addr of
256 Just (Ptr addr) -> case addrToAny# addr of
243 (# hval #) -> pure (Right hval)
257 (# hval #) -> pure (Right hval)
245−prefixUnderscore :: String
259+prefixUnderscore :: String
246prefixUnderscore =
260prefixUnderscore =
247 case (os,arch) of
261 case (os,arch) of
248 ("mingw32","x86_64") -> ""
262 ("mingw32","x86_64") -> ""
@@ -251,3 +265,4 @@ prefixUnderscore =
251 ("darwin",_) -> "_"
265 ("darwin",_) -> "_"
252 ("cygwin",_) -> "_"
266 ("cygwin",_) -> "_"