{-# LANGUAGE GADTs #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
module GHC.Runtime.Interpreter.JS
( spawnJSInterp
, jsLinkRts
, jsLinkInterp
, jsLinkObject
, jsLinkObjects
, jsLoadFile
, jsRunServer
, mkExportedModFuns
)
where
import GHC.Prelude
import GHC.Runtime.Interpreter.Types
import GHC.Runtime.Interpreter.Process
import GHC.Runtime.Utils
import GHCi.Message
import GHC.StgToJS.Linker.Types
import GHC.StgToJS.Linker.Linker
import GHC.StgToJS.Types
import GHC.StgToJS.Object
import GHC.Unit.Env
import GHC.Unit.Types
import GHC.Unit.State
import GHC.Utils.Logger
import GHC.Utils.TmpFs
import GHC.Utils.Panic
import GHC.Utils.Error (logInfo)
import GHC.Utils.Outputable (text)
import GHC.Data.FastString
import Control.Concurrent
import Control.Monad
import System.Process
import System.IO
import System.FilePath
import Data.IORef
import qualified Data.Set as Set
import qualified Data.ByteString as B
import Foreign.C.String
startTHRunnerProcess :: FilePath -> NodeJsSettings -> IO (Handle,InterpProcess)
startTHRunnerProcess :: FilePath -> NodeJsSettings -> IO (Handle, InterpProcess)
startTHRunnerProcess FilePath
interp_js NodeJsSettings
settings = do
IORef Handle
interp_in <- Handle -> IO (IORef Handle)
forall a. a -> IO (IORef a)
newIORef Handle
forall a. HasCallStack => a
undefined
let createProc :: CreateProcess -> IO ProcessHandle
createProc CreateProcess
cp = do
let cp' :: CreateProcess
cp' = CreateProcess
cp
{ std_in = CreatePipe
, std_out = Inherit
, std_err = Inherit
}
(Maybe Handle
mb_in, Maybe Handle
_mb_out, Maybe Handle
_mb_err, ProcessHandle
hdl) <- CreateProcess
-> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
createProcess CreateProcess
cp'
case Maybe Handle
mb_in of
Maybe Handle
Nothing -> FilePath -> IO ()
forall a. HasCallStack => FilePath -> a
panic FilePath
"startTHRunnerProcess: expected stdin for interpreter"
Just Handle
i -> IORef Handle -> Handle -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef Handle
interp_in Handle
i
ProcessHandle -> IO ProcessHandle
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ProcessHandle
hdl
(ProcessHandle
hdl, Handle
rh, Handle
wh) <- (CreateProcess -> IO ProcessHandle)
-> FilePath
-> [FilePath]
-> [FilePath]
-> IO (ProcessHandle, Handle, Handle)
runWithPipes CreateProcess -> IO ProcessHandle
createProc (NodeJsSettings -> FilePath
nodeProgram NodeJsSettings
settings)
[FilePath
interp_js]
(NodeJsSettings -> [FilePath]
nodeExtraArgs NodeJsSettings
settings)
Handle
std_in <- IORef Handle -> IO Handle
forall a. IORef a -> IO a
readIORef IORef Handle
interp_in
IORef (Maybe ByteString)
lo_ref <- Maybe ByteString -> IO (IORef (Maybe ByteString))
forall a. a -> IO (IORef a)
newIORef Maybe ByteString
forall a. Maybe a
Nothing
let pipe :: Pipe
pipe = Pipe { pipeRead :: Handle
pipeRead = Handle
rh, pipeWrite :: Handle
pipeWrite = Handle
wh, pipeLeftovers :: IORef (Maybe ByteString)
pipeLeftovers = IORef (Maybe ByteString)
lo_ref }
let proc :: InterpProcess
proc = InterpProcess
{ interpHandle :: ProcessHandle
interpHandle = ProcessHandle
hdl
, interpPipe :: Pipe
interpPipe = Pipe
pipe
}
(Handle, InterpProcess) -> IO (Handle, InterpProcess)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Handle
std_in, InterpProcess
proc)
spawnJSInterp :: JSInterpConfig -> IO (ExtInterpInstance JSInterpExtra)
spawnJSInterp :: JSInterpConfig -> IO (ExtInterpInstance JSInterpExtra)
spawnJSInterp JSInterpConfig
cfg = do
let logger :: Logger
logger= JSInterpConfig -> Logger
jsInterpLogger JSInterpConfig
cfg
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Logger -> Int -> Bool
logVerbAtLeast Logger
logger Int
2) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
Logger -> SDoc -> IO ()
logInfo Logger
logger (FilePath -> SDoc
forall doc. IsLine doc => FilePath -> doc
text FilePath
"Spawning JS interpreter")
let tmpfs :: TmpFs
tmpfs = JSInterpConfig -> TmpFs
jsInterpTmpFs JSInterpConfig
cfg
tmp_dir :: TempDir
tmp_dir = JSInterpConfig -> TempDir
jsInterpTmpDir JSInterpConfig
cfg
logger :: Logger
logger = JSInterpConfig -> Logger
jsInterpLogger JSInterpConfig
cfg
codegen_cfg :: StgToJSConfig
codegen_cfg = JSInterpConfig -> StgToJSConfig
jsInterpCodegenCfg JSInterpConfig
cfg
unit_env :: UnitEnv
unit_env = JSInterpConfig -> UnitEnv
jsInterpUnitEnv JSInterpConfig
cfg
finder_opts :: FinderOpts
finder_opts = JSInterpConfig -> FinderOpts
jsInterpFinderOpts JSInterpConfig
cfg
finder_cache :: FinderCache
finder_cache = JSInterpConfig -> FinderCache
jsInterpFinderCache JSInterpConfig
cfg
(Handle
std_in, InterpProcess
proc) <- FilePath -> NodeJsSettings -> IO (Handle, InterpProcess)
startTHRunnerProcess (JSInterpConfig -> FilePath
jsInterpScript JSInterpConfig
cfg) (JSInterpConfig -> NodeJsSettings
jsInterpNodeConfig JSInterpConfig
cfg)
MVar JSState
js_state <- JSState -> IO (MVar JSState)
forall a. a -> IO (MVar a)
newMVar (JSState
{ jsLinkState :: LinkPlan
jsLinkState = LinkPlan
emptyLinkPlan
, jsServerStarted :: Bool
jsServerStarted = Bool
False
})
UnitId
ghci_unit_id <- case UnitState -> PackageName -> Maybe UnitId
lookupPackageName (HasDebugCallStack => UnitEnv -> UnitState
UnitEnv -> UnitState
ue_units UnitEnv
unit_env) (FastString -> PackageName
PackageName (FilePath -> FastString
fsLit FilePath
"ghci")) of
Maybe UnitId
Nothing -> FilePath -> IO UnitId
forall a. FilePath -> IO a
cmdLineErrorIO FilePath
"JS interpreter: couldn't find \"ghci\" package"
Just UnitId
i -> UnitId -> IO UnitId
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure UnitId
i
let extra :: JSInterpExtra
extra = JSInterpExtra
{ instStdIn :: Handle
instStdIn = Handle
std_in
, instJSState :: MVar JSState
instJSState = MVar JSState
js_state
, instFinderCache :: FinderCache
instFinderCache = FinderCache
finder_cache
, instFinderOpts :: FinderOpts
instFinderOpts = FinderOpts
finder_opts
, instGhciUnitId :: UnitId
instGhciUnitId = UnitId
ghci_unit_id
}
MVar [HValueRef]
pending_frees <- [HValueRef] -> IO (MVar [HValueRef])
forall a. a -> IO (MVar a)
newMVar []
let inst :: ExtInterpInstance JSInterpExtra
inst = ExtInterpInstance
{ instProcess :: InterpProcess
instProcess = InterpProcess
proc
, instPendingFrees :: MVar [HValueRef]
instPendingFrees = MVar [HValueRef]
pending_frees
, instExtra :: JSInterpExtra
instExtra = JSInterpExtra
extra
}
Logger
-> TmpFs
-> TempDir
-> StgToJSConfig
-> UnitEnv
-> ExtInterpInstance JSInterpExtra
-> IO ()
jsLinkRts Logger
logger TmpFs
tmpfs TempDir
tmp_dir StgToJSConfig
codegen_cfg UnitEnv
unit_env ExtInterpInstance JSInterpExtra
inst
Logger
-> TmpFs
-> TempDir
-> StgToJSConfig
-> UnitEnv
-> ExtInterpInstance JSInterpExtra
-> IO ()
jsLinkInterp Logger
logger TmpFs
tmpfs TempDir
tmp_dir StgToJSConfig
codegen_cfg UnitEnv
unit_env ExtInterpInstance JSInterpExtra
inst
ExtInterpInstance JSInterpExtra -> IO ()
jsRunServer ExtInterpInstance JSInterpExtra
inst
ExtInterpInstance JSInterpExtra
-> IO (ExtInterpInstance JSInterpExtra)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ExtInterpInstance JSInterpExtra
inst
jsLinkRts :: Logger -> TmpFs -> TempDir -> StgToJSConfig -> UnitEnv -> ExtInterpInstance JSInterpExtra -> IO ()
jsLinkRts :: Logger
-> TmpFs
-> TempDir
-> StgToJSConfig
-> UnitEnv
-> ExtInterpInstance JSInterpExtra
-> IO ()
jsLinkRts Logger
logger TmpFs
tmpfs TempDir
tmp_dir StgToJSConfig
cfg UnitEnv
unit_env ExtInterpInstance JSInterpExtra
inst = do
let link_cfg :: JSLinkConfig
link_cfg = JSLinkConfig
{ lcNoStats :: Bool
lcNoStats = Bool
True
, lcNoRts :: Bool
lcNoRts = Bool
False
, lcCombineAll :: Bool
lcCombineAll = Bool
False
, lcForeignRefs :: Bool
lcForeignRefs = Bool
False
, lcNoJSExecutables :: Bool
lcNoJSExecutables = Bool
True
, lcNoHsMain :: Bool
lcNoHsMain = Bool
True
}
let link_spec :: LinkSpec
link_spec = LinkSpec
{ lks_unit_ids :: [UnitId]
lks_unit_ids = [UnitId
rtsUnitId, UnitId
baseUnitId, UnitId
primUnitId]
, lks_obj_files :: [LinkedObj]
lks_obj_files = [LinkedObj]
forall a. Monoid a => a
mempty
, lks_obj_root_filter :: ExportedFun -> Bool
lks_obj_root_filter = Bool -> ExportedFun -> Bool
forall a b. a -> b -> a
const Bool
False
, lks_extra_roots :: Set ExportedFun
lks_extra_roots = Set ExportedFun
forall a. Monoid a => a
mempty
, lks_extra_js :: [FilePath]
lks_extra_js = [FilePath]
forall a. Monoid a => a
mempty
}
let finder_opts :: FinderOpts
finder_opts = JSInterpExtra -> FinderOpts
instFinderOpts (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst)
finder_cache :: FinderCache
finder_cache = JSInterpExtra -> FinderCache
instFinderCache (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst)
LinkPlan
link_plan <- StgToJSConfig
-> UnitEnv -> LinkSpec -> FinderOpts -> FinderCache -> IO LinkPlan
computeLinkDependencies StgToJSConfig
cfg UnitEnv
unit_env LinkSpec
link_spec FinderOpts
finder_opts FinderCache
finder_cache
Logger
-> TmpFs
-> TempDir
-> JSLinkConfig
-> StgToJSConfig
-> ExtInterpInstance JSInterpExtra
-> LinkPlan
-> IO ()
jsLinkPlan Logger
logger TmpFs
tmpfs TempDir
tmp_dir JSLinkConfig
link_cfg StgToJSConfig
cfg ExtInterpInstance JSInterpExtra
inst LinkPlan
link_plan
jsLinkInterp :: Logger -> TmpFs -> TempDir -> StgToJSConfig -> UnitEnv -> ExtInterpInstance JSInterpExtra -> IO ()
jsLinkInterp :: Logger
-> TmpFs
-> TempDir
-> StgToJSConfig
-> UnitEnv
-> ExtInterpInstance JSInterpExtra
-> IO ()
jsLinkInterp Logger
logger TmpFs
tmpfs TempDir
tmp_dir StgToJSConfig
cfg UnitEnv
unit_env ExtInterpInstance JSInterpExtra
inst = do
let link_cfg :: JSLinkConfig
link_cfg = JSLinkConfig
{ lcNoStats :: Bool
lcNoStats = Bool
True
, lcNoRts :: Bool
lcNoRts = Bool
True
, lcCombineAll :: Bool
lcCombineAll = Bool
False
, lcForeignRefs :: Bool
lcForeignRefs = Bool
False
, lcNoJSExecutables :: Bool
lcNoJSExecutables = Bool
True
, lcNoHsMain :: Bool
lcNoHsMain = Bool
True
}
let is_root :: p -> Bool
is_root p
_ = Bool
True
let ghci_unit_id :: UnitId
ghci_unit_id = JSInterpExtra -> UnitId
instGhciUnitId (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst)
let unit_map :: UnitInfoMap
unit_map = UnitState -> UnitInfoMap
unitInfoMap (HasDebugCallStack => UnitEnv -> UnitState
UnitEnv -> UnitState
ue_units UnitEnv
unit_env)
[UnitId]
dep_units <- MaybeErr UnitErr [UnitId] -> IO [UnitId]
forall a. MaybeErr UnitErr a -> IO a
mayThrowUnitErr (MaybeErr UnitErr [UnitId] -> IO [UnitId])
-> MaybeErr UnitErr [UnitId] -> IO [UnitId]
forall a b. (a -> b) -> a -> b
$ UnitInfoMap
-> [(UnitId, Maybe UnitId)] -> MaybeErr UnitErr [UnitId]
closeUnitDeps UnitInfoMap
unit_map [(UnitId
ghci_unit_id,Maybe UnitId
forall a. Maybe a
Nothing)]
let units :: [UnitId]
units = [UnitId]
dep_units [UnitId] -> [UnitId] -> [UnitId]
forall a. [a] -> [a] -> [a]
++ [UnitId
ghci_unit_id]
let root_deps :: Set ExportedFun
root_deps = [ExportedFun] -> Set ExportedFun
forall a. Ord a => [a] -> Set a
Set.fromList ([ExportedFun] -> Set ExportedFun)
-> [ExportedFun] -> Set ExportedFun
forall a b. (a -> b) -> a -> b
$ UnitId -> FastString -> [FastString] -> [ExportedFun]
mkExportedFuns UnitId
ghci_unit_id (FilePath -> FastString
fsLit FilePath
"GHCi.Server") [FilePath -> FastString
fsLit FilePath
"defaultServer"]
let link_spec :: LinkSpec
link_spec = LinkSpec
{ lks_unit_ids :: [UnitId]
lks_unit_ids = [UnitId]
units
, lks_obj_files :: [LinkedObj]
lks_obj_files = [LinkedObj]
forall a. Monoid a => a
mempty
, lks_obj_root_filter :: ExportedFun -> Bool
lks_obj_root_filter = ExportedFun -> Bool
forall {p}. p -> Bool
is_root
, lks_extra_roots :: Set ExportedFun
lks_extra_roots = Set ExportedFun
root_deps
, lks_extra_js :: [FilePath]
lks_extra_js = [FilePath]
forall a. Monoid a => a
mempty
}
let finder_cache :: FinderCache
finder_cache = JSInterpExtra -> FinderCache
instFinderCache (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst)
finder_opts :: FinderOpts
finder_opts = JSInterpExtra -> FinderOpts
instFinderOpts (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst)
LinkPlan
link_plan <- StgToJSConfig
-> UnitEnv -> LinkSpec -> FinderOpts -> FinderCache -> IO LinkPlan
computeLinkDependencies StgToJSConfig
cfg UnitEnv
unit_env LinkSpec
link_spec FinderOpts
finder_opts FinderCache
finder_cache
Logger
-> TmpFs
-> TempDir
-> JSLinkConfig
-> StgToJSConfig
-> ExtInterpInstance JSInterpExtra
-> LinkPlan
-> IO ()
jsLinkPlan Logger
logger TmpFs
tmpfs TempDir
tmp_dir JSLinkConfig
link_cfg StgToJSConfig
cfg ExtInterpInstance JSInterpExtra
inst LinkPlan
link_plan
jsLinkObjects :: Logger -> TmpFs -> TempDir -> StgToJSConfig -> UnitEnv -> ExtInterpInstance JSInterpExtra -> [FilePath] -> (ExportedFun -> Bool) -> IO ()
jsLinkObjects :: Logger
-> TmpFs
-> TempDir
-> StgToJSConfig
-> UnitEnv
-> ExtInterpInstance JSInterpExtra
-> [FilePath]
-> (ExportedFun -> Bool)
-> IO ()
jsLinkObjects Logger
logger TmpFs
tmpfs TempDir
tmp_dir StgToJSConfig
cfg UnitEnv
unit_env ExtInterpInstance JSInterpExtra
inst [FilePath]
objs ExportedFun -> Bool
is_root = do
let link_cfg :: JSLinkConfig
link_cfg = JSLinkConfig
{ lcNoStats :: Bool
lcNoStats = Bool
True
, lcNoRts :: Bool
lcNoRts = Bool
True
, lcCombineAll :: Bool
lcCombineAll = Bool
False
, lcForeignRefs :: Bool
lcForeignRefs = Bool
False
, lcNoJSExecutables :: Bool
lcNoJSExecutables = Bool
True
, lcNoHsMain :: Bool
lcNoHsMain = Bool
True
}
let units :: [UnitId]
units = UnitState -> [UnitId]
preloadUnits (HasDebugCallStack => UnitEnv -> UnitState
UnitEnv -> UnitState
ue_units UnitEnv
unit_env)
[UnitId] -> [UnitId] -> [UnitId]
forall a. [a] -> [a] -> [a]
++ [UnitId
thUnitId]
let link_spec :: LinkSpec
link_spec = LinkSpec
{ lks_unit_ids :: [UnitId]
lks_unit_ids = [UnitId]
units
, lks_obj_files :: [LinkedObj]
lks_obj_files = (FilePath -> LinkedObj) -> [FilePath] -> [LinkedObj]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FilePath -> LinkedObj
ObjFile [FilePath]
objs
, lks_obj_root_filter :: ExportedFun -> Bool
lks_obj_root_filter = ExportedFun -> Bool
is_root
, lks_extra_roots :: Set ExportedFun
lks_extra_roots = Set ExportedFun
forall a. Monoid a => a
mempty
, lks_extra_js :: [FilePath]
lks_extra_js = [FilePath]
forall a. Monoid a => a
mempty
}
let finder_opts :: FinderOpts
finder_opts = JSInterpExtra -> FinderOpts
instFinderOpts (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst)
finder_cache :: FinderCache
finder_cache = JSInterpExtra -> FinderCache
instFinderCache (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst)
LinkPlan
link_plan <- StgToJSConfig
-> UnitEnv -> LinkSpec -> FinderOpts -> FinderCache -> IO LinkPlan
computeLinkDependencies StgToJSConfig
cfg UnitEnv
unit_env LinkSpec
link_spec FinderOpts
finder_opts FinderCache
finder_cache
Logger
-> TmpFs
-> TempDir
-> JSLinkConfig
-> StgToJSConfig
-> ExtInterpInstance JSInterpExtra
-> LinkPlan
-> IO ()
jsLinkPlan Logger
logger TmpFs
tmpfs TempDir
tmp_dir JSLinkConfig
link_cfg StgToJSConfig
cfg ExtInterpInstance JSInterpExtra
inst LinkPlan
link_plan
jsLinkObject :: Logger -> TmpFs -> TempDir -> StgToJSConfig -> UnitEnv -> ExtInterpInstance JSInterpExtra -> FilePath -> [ExportedFun] -> IO ()
jsLinkObject :: Logger
-> TmpFs
-> TempDir
-> StgToJSConfig
-> UnitEnv
-> ExtInterpInstance JSInterpExtra
-> FilePath
-> [ExportedFun]
-> IO ()
jsLinkObject Logger
logger TmpFs
tmpfs TempDir
tmp_dir StgToJSConfig
cfg UnitEnv
unit_env ExtInterpInstance JSInterpExtra
inst FilePath
obj [ExportedFun]
roots = do
let is_root :: ExportedFun -> Bool
is_root ExportedFun
f = ExportedFun -> Set ExportedFun -> Bool
forall a. Ord a => a -> Set a -> Bool
Set.member ExportedFun
f ([ExportedFun] -> Set ExportedFun
forall a. Ord a => [a] -> Set a
Set.fromList [ExportedFun]
roots)
let objs :: [FilePath]
objs = [FilePath
obj]
Logger
-> TmpFs
-> TempDir
-> StgToJSConfig
-> UnitEnv
-> ExtInterpInstance JSInterpExtra
-> [FilePath]
-> (ExportedFun -> Bool)
-> IO ()
jsLinkObjects Logger
logger TmpFs
tmpfs TempDir
tmp_dir StgToJSConfig
cfg UnitEnv
unit_env ExtInterpInstance JSInterpExtra
inst [FilePath]
objs ExportedFun -> Bool
is_root
jsLinkPlan :: Logger -> TmpFs -> TempDir -> JSLinkConfig -> StgToJSConfig -> ExtInterpInstance JSInterpExtra -> LinkPlan -> IO ()
jsLinkPlan :: Logger
-> TmpFs
-> TempDir
-> JSLinkConfig
-> StgToJSConfig
-> ExtInterpInstance JSInterpExtra
-> LinkPlan
-> IO ()
jsLinkPlan Logger
logger TmpFs
tmpfs TempDir
tmp_dir JSLinkConfig
link_cfg StgToJSConfig
cfg ExtInterpInstance JSInterpExtra
inst LinkPlan
link_plan = do
LinkPlan
old_plan <- JSState -> LinkPlan
jsLinkState (JSState -> LinkPlan) -> IO JSState -> IO LinkPlan
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MVar JSState -> IO JSState
forall a. MVar a -> IO a
readMVar (JSInterpExtra -> MVar JSState
instJSState (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst))
let (LinkPlan
diff_plan, LinkPlan
total_plan) = LinkPlan -> LinkPlan -> (LinkPlan, LinkPlan)
incrementLinkPlan LinkPlan
old_plan LinkPlan
link_plan
FilePath
tmp_out <- Logger -> TmpFs -> TempDir -> IO FilePath
newTempSubDir Logger
logger TmpFs
tmpfs TempDir
tmp_dir
IO () -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ JSLinkConfig
-> StgToJSConfig -> Logger -> FilePath -> LinkPlan -> IO ()
jsLink JSLinkConfig
link_cfg StgToJSConfig
cfg Logger
logger FilePath
tmp_out LinkPlan
diff_plan
let filenames :: [FilePath]
filenames
| JSLinkConfig -> Bool
lcNoRts JSLinkConfig
link_cfg = [FilePath
"lib.js", FilePath
"out.js"]
| Bool
otherwise = [FilePath
"rts.js", FilePath
"lib.js", FilePath
"out.js"]
let files :: [FilePath]
files = (FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath
tmp_out FilePath -> FilePath -> FilePath
</>) [FilePath]
filenames
let all_js :: FilePath
all_js = FilePath
tmp_out FilePath -> FilePath -> FilePath
</> FilePath
"all.js"
let all_files :: [FilePath]
all_files = FilePath
all_js FilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
: [FilePath]
files
FilePath -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile FilePath
all_js IOMode
WriteMode ((Handle -> IO ()) -> IO ()) -> (Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Handle
h -> do
let cpy :: FilePath -> IO ()
cpy FilePath
i = FilePath -> IO ByteString
B.readFile FilePath
i IO ByteString -> (ByteString -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Handle -> ByteString -> IO ()
B.hPut Handle
h
(FilePath -> IO ()) -> [FilePath] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ FilePath -> IO ()
cpy [FilePath]
files
TmpFs -> TempFileLifetime -> [FilePath] -> IO ()
addFilesToClean TmpFs
tmpfs TempFileLifetime
TFL_CurrentModule [FilePath]
all_files
Bool
server_started <- JSState -> Bool
jsServerStarted (JSState -> Bool) -> IO JSState -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MVar JSState -> IO JSState
forall a. MVar a -> IO a
readMVar (JSInterpExtra -> MVar JSState
instJSState (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst))
if Bool
server_started
then ExtInterpInstance JSInterpExtra -> Message () -> IO ()
forall d. ExtInterpInstance d -> Message () -> IO ()
sendMessageNoResponse ExtInterpInstance JSInterpExtra
inst (Message () -> IO ()) -> Message () -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> Message ()
LoadObj FilePath
all_js
else ExtInterpInstance JSInterpExtra -> FilePath -> IO ()
jsLoadFile ExtInterpInstance JSInterpExtra
inst FilePath
all_js
MVar JSState -> (JSState -> IO JSState) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ (JSInterpExtra -> MVar JSState
instJSState (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst)) ((JSState -> IO JSState) -> IO ())
-> (JSState -> IO JSState) -> IO ()
forall a b. (a -> b) -> a -> b
$ \JSState
state -> JSState -> IO JSState
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure JSState
state { jsLinkState = total_plan }
jsSendCommand :: ExtInterpInstance JSInterpExtra -> String -> IO ()
jsSendCommand :: ExtInterpInstance JSInterpExtra -> FilePath -> IO ()
jsSendCommand ExtInterpInstance JSInterpExtra
inst FilePath
cmd = FilePath -> IO ()
send_cmd FilePath
cmd
where
extra :: JSInterpExtra
extra = ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst
handle :: Handle
handle = JSInterpExtra -> Handle
instStdIn JSInterpExtra
extra
send_cmd :: FilePath -> IO ()
send_cmd FilePath
s = do
FilePath -> (CStringLen -> IO ()) -> IO ()
forall a. FilePath -> (CStringLen -> IO a) -> IO a
withCStringLen FilePath
s \(Ptr CChar
p,Int
n) -> Handle -> Ptr CChar -> Int -> IO ()
forall a. Handle -> Ptr a -> Int -> IO ()
hPutBuf Handle
handle Ptr CChar
p Int
n
Handle -> IO ()
hFlush Handle
handle
jsLoadFile :: ExtInterpInstance JSInterpExtra -> FilePath -> IO ()
jsLoadFile :: ExtInterpInstance JSInterpExtra -> FilePath -> IO ()
jsLoadFile ExtInterpInstance JSInterpExtra
inst FilePath
path = ExtInterpInstance JSInterpExtra -> FilePath -> IO ()
jsSendCommand ExtInterpInstance JSInterpExtra
inst (FilePath
"LOAD " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
path FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"\n")
jsRunServer :: ExtInterpInstance JSInterpExtra -> IO ()
jsRunServer :: ExtInterpInstance JSInterpExtra -> IO ()
jsRunServer ExtInterpInstance JSInterpExtra
inst = do
let ghci_unit_id :: UnitId
ghci_unit_id = JSInterpExtra -> UnitId
instGhciUnitId (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst)
let zghci_unit_id :: FilePath
zghci_unit_id = FastZString -> FilePath
zString (FastString -> FastZString
zEncodeFS (UnitId -> FastString
unitIdFS UnitId
ghci_unit_id))
ExtInterpInstance JSInterpExtra -> FilePath -> IO ()
jsSendCommand ExtInterpInstance JSInterpExtra
inst (FilePath
"RUN_SERVER " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
zghci_unit_id FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"\n")
MVar JSState -> (JSState -> IO JSState) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ (JSInterpExtra -> MVar JSState
instJSState (ExtInterpInstance JSInterpExtra -> JSInterpExtra
forall c. ExtInterpInstance c -> c
instExtra ExtInterpInstance JSInterpExtra
inst)) ((JSState -> IO JSState) -> IO ())
-> (JSState -> IO JSState) -> IO ()
forall a b. (a -> b) -> a -> b
$ \JSState
state -> JSState -> IO JSState
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure JSState
state { jsServerStarted = True }