@@ -58,8 +58,14 @@ module Language.Javascript.JSaddle.Types (
5858 -- * Debugging
5959 , JSadddleHasCallStack
6060
61− -- * JavaScript Context Commands
61+ -- * Sync JSM
62+ , syncPoint
63+ , syncAfter
64+
6265#ifndef ghcjs_HOST_OS
66+ , sendCommand
67+
68+ -- * JavaScript Context Commands
6369 , MutabilityType(..)
6470 , Mutable
6571 , Immutable
@@ -89,14 +95,14 @@ import GHCJS.Nullable (Nullable(..))
8995import GHCJS.Prim.Internal (JSVal(..), JSValueRef)
9096import Data.JSString.Internal.Type (JSString(..))
9197import Control.DeepSeq (NFData(..))
92−import Control.Monad.Catch (MonadThrow, MonadCatch, MonadMask)
98+import Control.Monad.Catch (MonadThrow, MonadCatch(..), MonadMask(..))
9399import Control.Monad.Trans.Cont (ContT(..))
94100import Control.Monad.Trans.Error (Error(..), ErrorT(..))
95101import Control.Monad.Trans.Except (ExceptT(..))
96102import Control.Monad.Trans.Identity (IdentityT(..))
97103import Control.Monad.Trans.List (ListT(..))
98104import Control.Monad.Trans.Maybe (MaybeT(..))
99−import Control.Monad.Trans.Reader (ReaderT(..))
105+import Control.Monad.Trans.Reader (ReaderT(..), ask)
100106import Control.Monad.Trans.RWS.Lazy as Lazy (RWST(..))
101107import Control.Monad.Trans.RWS.Strict as Strict (RWST(..))
102108import Control.Monad.Trans.State.Lazy as Lazy (StateT(..))
@@ -158,9 +164,48 @@ data JSContextRef = JSContextRef {
158164type JSM = IO
159165#else
160166newtype JSM a = JSM { unJSM :: ReaderT JSContextRef IO a }
161− deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadCatch, MonadThrow, MonadMask)
167+ deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadThrow)
168+
169+instance MonadCatch JSM where
170+ t `catch` c = JSM (unJSM (syncAfter t) `catch` \e -> unJSM (c e))
171+
172+instance MonadMask JSM where
173+ mask a = JSM $ mask $ \unmask -> unJSM (a $ q unmask)
174+ where q :: (ReaderT JSContextRef IO a -> ReaderT JSContextRef IO a) -> JSM a -> JSM a
175+ q unmask (JSM b) = syncAfter . JSM $ unmask b
176+ uninterruptibleMask a =
177+ JSM $ uninterruptibleMask $ \unmask -> unJSM (a $ q unmask)
178+ where q :: (ReaderT JSContextRef IO a -> ReaderT JSContextRef IO a) -> JSM a -> JSM a
179+ q unmask (JSM b) = syncAfter . JSM $ unmask b
180+#endif
181+
182+-- | Forces execution of pending asyncronous code
183+syncPoint :: JSM ()
184+#ifdef ghcjs_HOST_OS
185+syncPoint = return ()
186+#else
187+syncPoint = do
188+ SyncResult <- sendCommand Sync
189+ return ()
162190#endif
163191
192+-- | Forces execution of pending asyncronous code after performing `f`
193+syncAfter :: JSM a -> JSM a
194+#ifdef ghcjs_HOST_OS
195+syncAfter = id
196+#else
197+syncAfter f = do
198+ result <- f
199+ syncPoint
200+ return result
201+#endif
202+
203+#ifndef ghcjs_HOST_OS
204+sendCommand :: Command -> JSM Result
205+sendCommand cmd = do
206+ s <- doSendCommand <$> JSM ask
207+ liftIO $ s cmd
208+#endif
164209
165210-- | Type we can give to functions that are pure when using ghcjs, but
166211-- live in JSM when using jsaddle.