packages feed

jsaddle 0.2.1.0 → 0.3.0.0

raw patch · 17 files changed

+1447/−887 lines, 17 filesdep +QuickCheckdep +doctestdep +ghcjs-primdep −hsloggerdep ~gtkdep ~gtk3dep ~lens

Dependencies added: QuickCheck, doctest, ghcjs-prim, vector

Dependencies removed: hslogger

Dependency ranges changed: gtk, gtk3, lens, text, transformers

Files

jsaddle.cabal view
@@ -1,85 +1,95 @@ name: jsaddle-version: 0.2.1.0+version: 0.3.0.0 cabal-version: >=1.10+build-type: Simple license: MIT license-file: LICENSE maintainer: Hamish Mackenzie <Hamish.K.Mackenzie@googlemail.com> synopsis: High level interface for webkit-javascriptcore-description: This package provides an EDSL for calling JavaScript code using-             the JavaScriptCore engine and low level Haskell bindings-             in the webkit-javascriptcore library <https://github.com/ghcjs/webkit-javascriptcore>.-author: Hamish Mackenzie-data-dir: ""+description:+    This package provides an EDSL for calling JavaScript code using+    the JavaScriptCore engine and low level Haskell bindings+    in the webkit-javascriptcore library <https://github.com/ghcjs/webkit-javascriptcore>. category: Web, Javascript-build-type: Simple+author: Hamish Mackenzie -Source-Repository head-  type:         git-  location:     https://github.com/ghcjs/jsaddle+source-repository head+    type: git+    location: https://github.com/ghcjs/jsaddle  flag gtk3-    Description: Use GTK3 rather than GTK2-    Default: True--flag jsffi-    description: Use JavaScriptFFI extension for GHCJS JavaScript output-    default: True--flag webkit-    description: Use WebKitGtk and JavaScriptCore for GHCJS output-    default: False+    description:+        Use GTK3 rather than GTK2  library-    if impl(ghcjs) && flag(jsffi)-        cpp-options: -DUSE_JAVASCRIPTFFI-        build-depends: ghcjs-base -    if !impl(ghcjs) || flag(webkit)-        cpp-options: -DUSE_WEBKIT+    if impl(ghcjs -any)+        build-depends:+            ghcjs-base -any,+            ghcjs-prim -any+    else         if flag(gtk3)-            build-depends: webkitgtk3 >=0.13.0.0 && <0.15,-                           webkitgtk3-javascriptcore >=0.13.0.0 && <0.14+            build-depends:+                gtk3 >=0.14.2 && <0.15,+                webkitgtk3 >=0.13.0.0 && <0.15,+                webkitgtk3-javascriptcore >=0.13.0.0 && <0.14         else-            build-depends: webkit >=0.13.0.0 && <0.15,-                           webkit-javascriptcore >=0.13.0.0 && <0.14--    build-depends: template-haskell -any, base <5, lens >=3.8.5 && <4.13,-                   text >=0.11.2.3 && <1.3, transformers >=0.3.0.0 && <0.5--    exposed-modules: Language.Javascript.JSaddle-                     Language.Javascript.JSaddle.Arguments Language.Javascript.JSaddle.Classes-                     Language.Javascript.JSaddle.Evaluate Language.Javascript.JSaddle.Exception-                     Language.Javascript.JSaddle.Monad-                     Language.Javascript.JSaddle.Object Language.Javascript.JSaddle.Properties-                     Language.Javascript.JSaddle.String Language.Javascript.JSaddle.Value-                     Language.Javascript.JSaddle.Types-    exposed: True-    buildable: True+            build-depends:+                gtk >=0.14.2 && <0.15,+                webkit >=0.13.0.0 && <0.15,+                webkit-javascriptcore >=0.13.0.0 && <0.14+        build-depends:+            glib -any+    exposed-modules:+        Language.Javascript.JSaddle+        Language.Javascript.JSaddle.Arguments+        Language.Javascript.JSaddle.Classes+        Language.Javascript.JSaddle.Evaluate+        Language.Javascript.JSaddle.Exception+        Language.Javascript.JSaddle.Monad+        Language.Javascript.JSaddle.Native+        Language.Javascript.JSaddle.Object+        Language.Javascript.JSaddle.Properties+        Language.Javascript.JSaddle.String+        Language.Javascript.JSaddle.Value+        Language.Javascript.JSaddle.Types+        Language.Javascript.JSaddle.Test+    build-depends:+        template-haskell -any,+        base <5,+        lens >=3.8.5 && <4.14,+        text >=0.11.2.3 && <1.3,+        transformers >=0.3.0.0 && <0.5     default-language: Haskell2010     hs-source-dirs: src-    other-modules: Language.Javascript.JSaddle.PropRef+    ghc-options: -ferror-spans  test-suite test-tool-    if flag(jsffi)++    if impl(ghcjs -any)         buildable: False     else-        buildable: True--    if impl(ghcjs) && flag(jsffi)-        cpp-options: -DUSE_JAVASCRIPTFFI-        build-depends: ghcjs-base--    if !impl(ghcjs) || flag(webkit)-        cpp-options: -DUSE_WEBKIT-        build-depends: glib         if flag(gtk3)-            build-depends: gtk3, webkitgtk3, webkitgtk3-javascriptcore+            build-depends:+                gtk3 -any,+                webkitgtk3 -any,+                webkitgtk3-javascriptcore -any         else-            build-depends: gtk, webkit, webkit-javascriptcore--    build-depends: template-haskell, base, lens, text,-                   transformers, hslogger, jsaddle+            build-depends:+                gtk -any,+                webkit -any,+                webkit-javascriptcore -any+        build-depends:+            glib -any     type: exitcode-stdio-1.0-    main-is: TestJSaddle.hs+    main-is: DocTest.hs+    build-depends:+        QuickCheck -any,+        base -any,+        doctest -any,+        vector >=0.11.0.0 && <0.12,+        text >=0.11.2.3 && <1.3,+        jsaddle -any     default-language: Haskell2010     hs-source-dirs: tests+    ghc-options: -ferror-spans
src/Language/Javascript/JSaddle.hs view
@@ -18,11 +18,11 @@   --   with JavaScript the EDSL has   --   --   * /Weakish typing/ - type classes are used to convert to JSValueRef-  --   and JSObjectRef types+  --   and Object types   --   --   * /Strict evaluation/ - function in the 'JSM' monad can be passed in   --   place of a value and will evaluated and converted to JSValueRef or-  --   JSObjectRef and then passed on to JavaScript+  --   Object and then passed on to JavaScript   --   --   JSaddle should be used to write wrappers for JavaScript libraries that provide   --   more type safety.@@ -52,6 +52,8 @@     module JSaddle ) where +import Language.Javascript.JSaddle.Types as JSaddle+import Language.Javascript.JSaddle.Classes as JSaddle import Language.Javascript.JSaddle.Monad as JSaddle import Language.Javascript.JSaddle.Exception as JSaddle import Language.Javascript.JSaddle.Value as JSaddle
src/Language/Javascript/JSaddle/Arguments.hs view
@@ -13,46 +13,70 @@ -----------------------------------------------------------------------------  module Language.Javascript.JSaddle.Arguments (-    MakeArgRefs(..)+    MakeArgs(..) ) where  import Language.Javascript.JSaddle.Classes-       (MakeValueRef(..), MakeValueRef, MakeArgRefs(..), MakeArgRefs)+       (ToJSVal(..)) import Language.Javascript.JSaddle.Monad (JSM)+import Language.Javascript.JSaddle.Types (JSVal) -instance MakeArgRefs arg => MakeArgRefs (JSM arg) where-    makeArgRefs arg = arg >>= makeArgRefs+-- | Anything that can be used to make a list of JavaScript value+--   references for use as function arguments+class MakeArgs this where+    makeArgs :: this -> JSM [JSVal] -instance MakeValueRef arg => MakeArgRefs [arg] where-    makeArgRefs = mapM makeValueRef+instance MakeArgs arg => MakeArgs (JSM arg) where+    makeArgs arg = arg >>= makeArgs+    {-# INLINE makeArgs #-} -instance (MakeValueRef arg1, MakeValueRef arg2) => MakeArgRefs (arg1, arg2) where-    makeArgRefs (arg1, arg2) = do-        rarg1 <- makeValueRef arg1-        rarg2 <- makeValueRef arg2+instance ToJSVal arg => MakeArgs [arg] where+    makeArgs = mapM toJSVal+    {-# INLINE makeArgs #-}++instance (ToJSVal arg1, ToJSVal arg2) => MakeArgs (arg1, arg2) where+    makeArgs (arg1, arg2) = do+        rarg1 <- toJSVal arg1+        rarg2 <- toJSVal arg2         return [rarg1, rarg2]+    {-# INLINE makeArgs #-} -instance (MakeValueRef arg1, MakeValueRef arg2, MakeValueRef arg3) => MakeArgRefs (arg1, arg2, arg3) where-    makeArgRefs (arg1, arg2, arg3) = do-        rarg1 <- makeValueRef arg1-        rarg2 <- makeValueRef arg2-        rarg3 <- makeValueRef arg3+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3) => MakeArgs (arg1, arg2, arg3) where+    makeArgs (arg1, arg2, arg3) = do+        rarg1 <- toJSVal arg1+        rarg2 <- toJSVal arg2+        rarg3 <- toJSVal arg3         return [rarg1, rarg2, rarg3]+    {-# INLINE makeArgs #-} -instance (MakeValueRef arg1, MakeValueRef arg2, MakeValueRef arg3, MakeValueRef arg4) => MakeArgRefs (arg1, arg2, arg3, arg4) where-    makeArgRefs (arg1, arg2, arg3, arg4) = do-        rarg1 <- makeValueRef arg1-        rarg2 <- makeValueRef arg2-        rarg3 <- makeValueRef arg3-        rarg4 <- makeValueRef arg4+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4) => MakeArgs (arg1, arg2, arg3, arg4) where+    makeArgs (arg1, arg2, arg3, arg4) = do+        rarg1 <- toJSVal arg1+        rarg2 <- toJSVal arg2+        rarg3 <- toJSVal arg3+        rarg4 <- toJSVal arg4         return [rarg1, rarg2, rarg3, rarg4]+    {-# INLINE makeArgs #-} -instance (MakeValueRef arg1, MakeValueRef arg2, MakeValueRef arg3, MakeValueRef arg4, MakeValueRef arg5) => MakeArgRefs (arg1, arg2, arg3, arg4, arg5) where-    makeArgRefs (arg1, arg2, arg3, arg4, arg5) = do-        rarg1 <- makeValueRef arg1-        rarg2 <- makeValueRef arg2-        rarg3 <- makeValueRef arg3-        rarg4 <- makeValueRef arg4-        rarg5 <- makeValueRef arg5+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4, ToJSVal arg5) => MakeArgs (arg1, arg2, arg3, arg4, arg5) where+    makeArgs (arg1, arg2, arg3, arg4, arg5) = do+        rarg1 <- toJSVal arg1+        rarg2 <- toJSVal arg2+        rarg3 <- toJSVal arg3+        rarg4 <- toJSVal arg4+        rarg5 <- toJSVal arg5         return [rarg1, rarg2, rarg3, rarg4, rarg5]+    {-# INLINE makeArgs #-}+++instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4, ToJSVal arg5, ToJSVal arg6) => MakeArgs (arg1, arg2, arg3, arg4, arg5, arg6) where+    makeArgs (arg1, arg2, arg3, arg4, arg5, arg6) = do+        rarg1 <- toJSVal arg1+        rarg2 <- toJSVal arg2+        rarg3 <- toJSVal arg3+        rarg4 <- toJSVal arg4+        rarg5 <- toJSVal arg5+        rarg6 <- toJSVal arg6+        return [rarg1, rarg2, rarg3, rarg4, rarg5, rarg6]+    {-# INLINE makeArgs #-} 
src/Language/Javascript/JSaddle/Classes.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeSynonymInstances #-} ----------------------------------------------------------------------------- -- -- Module      :  Language.Javascript.JSaddle.Classes@@ -14,39 +16,32 @@  module Language.Javascript.JSaddle.Classes (   -- * Type classes to convert Haskell data to JavaScript-    MakeValueRef(..)-  , MakeStringRef(..)-  , MakeArgRefs(..)-  , MakeObjectRef(..)-  , MakePropRef(..)+    ToJSVal(..)+  , ToJSString(..)+  , MakeObject(..) ) where -import Control.Monad.IO.Class (MonadIO) import Language.Javascript.JSaddle.Types-       (JSObjectRef, JSStringRef, JSValueRef)-import Language.Javascript.JSaddle.Monad (JSM)-import Language.Javascript.JSaddle.PropRef (JSPropRef)+       (JSM, Object(..), JSString, JSVal)  -- | Anything that can be used to make a JavaScript value reference-class MakeValueRef a where-    makeValueRef :: a -> JSM JSValueRef+class ToJSVal a where+    toJSVal :: a -> JSM JSVal  -- | Anything that can be used to make a JavaScript string reference-class MakeStringRef a where-    makeStringRef :: a -> JSStringRef---- | Anything that can be used to make a list of JavaScript value---   references for use as function arguments-class MakeArgRefs this where-    makeArgRefs :: this -> JSM [JSValueRef]+class ToJSVal a => ToJSString a where+    toJSString :: a -> JSString  -- | Anything that can be used to make a JavaScript object reference-class MakeObjectRef this where-    makeObjectRef :: this -> JSM JSObjectRef---- | Anything that can be used to make a JavaScript property reference-class MakePropRef this where-    makePropRef :: this -> JSM JSPropRef+class MakeObject this where+    makeObject :: this -> JSM Object +instance ToJSVal Object where+    toJSVal (Object r) = return r+    {-# INLINE toJSVal #-} +-- | If we already have a Object we are fine+instance MakeObject Object where+    makeObject = return+    {-# INLINE makeObject #-} 
src/Language/Javascript/JSaddle/Evaluate.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE CPP #-}-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)+{-# LANGUAGE FlexibleInstances #-}+#ifdef ghcjs_HOST_OS {-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI #-} #endif -----------------------------------------------------------------------------@@ -22,58 +23,66 @@  import Control.Monad.Trans.Reader (ask) import Control.Monad.IO.Class (MonadIO(..))-import Language.Javascript.JSaddle.Types-       (JSStringRef, JSValueRef, JSObjectRef,-        JSValueRefRef)-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)+import Language.Javascript.JSaddle.Types (JSVal)+#ifdef ghcjs_HOST_OS import GHCJS.Types (nullRef)+import GHCJS.Marshal.Pure (pFromJSVal)+import Language.Javascript.JSaddle.Types (JSString) #else import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase        (jsevaluatescript)-import Foreign (nullPtr)+import Language.Javascript.JSaddle.Native+       (makeNewJSVal, withObject, withJSString) #endif import Language.Javascript.JSaddle.Exception (rethrow)-import Language.Javascript.JSaddle.Value ()-import Language.Javascript.JSaddle.Object ()+import Language.Javascript.JSaddle.String (nullJSString)+import Language.Javascript.JSaddle.Object (nullObject) import Language.Javascript.JSaddle.Classes-       (MakeObjectRef(..), MakeStringRef(..))+       (MakeObject(..), ToJSString(..)) import Language.Javascript.JSaddle.Monad (JSM) +-- $setup+-- >>> import Language.Javascript.JSaddle.Test (testJSaddle)+-- >>> import Language.Javascript.JSaddle.Value (valToText)+-- >>> import Language.Javascript.JSaddle.Object (global, array, (!))+-- >>> import Language.Javascript.JSaddle.Monad (catch)+-- >>> import Language.Javascript.JSaddle.Exception (JSException(..))  -- | Evaluates a script (like eval in java script).  Unlike 'eval' this function lets you --   specify a source URL and starting line number for beter error information. -- -- >>> testJSaddle $ (evaluateScript "\n\n{" global "FileName" 53 >>= valToText) `catch` \(JSException e) -> array (e,e!"sourceURL", e!"line") >>= valToText -- SyntaxError: Expected token '}',FileName,55-evaluateScript :: (MakeStringRef script, MakeObjectRef this, MakeStringRef url)+evaluateScript :: (ToJSString script, MakeObject this, ToJSString url)                => script         -- ^ JavaScript to evaluate                -> this                -> url                -> Int            -- ^ The Line number of the first line of the script-               -> JSM JSValueRef-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)-evaluateScript script this url line = liftIO $ js_eval (makeStringRef script)+               -> JSM JSVal+#ifdef ghcjs_HOST_OS+evaluateScript script this url line = liftIO $ js_eval (toJSString script)+{-# INLINE evaluateScript #-} foreign import javascript unsafe "$r = eval($1);"-    js_eval :: JSStringRef -> IO JSValueRef-#elif defined(USE_WEBKIT)+    js_eval :: JSString -> IO JSVal+#else evaluateScript script this url line = do     gctxt <- ask-    thisr <- makeObjectRef this-    rethrow $ liftIO . jsevaluatescript gctxt (makeStringRef script) thisr (makeStringRef url) line-#else-evaluateScript = undefined+    rthis <- makeObject this+    result <-+        withJSString (toJSString script) $ \script' ->+            withObject rthis $ \this' ->+                withJSString (toJSString url) $ \url' ->+                    rethrow $ liftIO . jsevaluatescript gctxt script' this' url' line+    makeNewJSVal result+{-# INLINE evaluateScript #-} #endif  -- | Evaluates a script (like eval in java script) -- -- >>> testJSaddle $ eval "1+1" -- 2-eval :: MakeStringRef script+eval :: ToJSString script      => script         -- ^ JavaScript to evaluate-     -> JSM JSValueRef-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-eval script = evaluateScript script (nullRef::JSObjectRef) (nullRef::JSStringRef) 1-#else-eval script = evaluateScript script (nullPtr::JSObjectRef) (nullPtr::JSStringRef) 1-#endif-+     -> JSM JSVal+eval script = evaluateScript script nullObject nullJSString 1+{-# INLINE eval #-}
src/Language/Javascript/JSaddle/Exception.hs view
@@ -18,18 +18,18 @@  import qualified Control.Exception as E (throwIO, Exception) import Language.Javascript.JSaddle.Types-       (JSValueRefRef, JSValueRef)+       (MutableJSArray, JSVal) import Data.Typeable (Typeable) import Language.Javascript.JSaddle.Monad (catchval, JSM) import Control.Monad.IO.Class (MonadIO(..))-import Data.Text (Text) -data JSException = JSException JSValueRef deriving (Show, Typeable)+newtype JSException = JSException JSVal deriving (Typeable) +instance Show JSException where show _ = "JSException" instance E.Exception JSException  -- | Catch JavaScript exceptions and rethrow Haskell ones-rethrow :: (JSValueRefRef -> JSM a) -> JSM a+rethrow :: (MutableJSArray -> JSM a) -> JSM a rethrow f = f `catchval` \e ->     liftIO . E.throwIO $ JSException e 
src/Language/Javascript/JSaddle/Monad.hs view
@@ -13,27 +13,32 @@  module Language.Javascript.JSaddle.Monad (   -- * Types-    JSM(..)+    JSM   , JSContextRef    -- * Running JSaddle given a DOM Window   , runJSaddle-  , runJSaddle_    -- * Exception Handling   , catchval   , catch+  , bracket++  -- * GUI thread support+  , postGUIAsyncJS+  , postGUISyncJS ) where -import Prelude hiding (catch)+import Prelude hiding (catch, read) import Control.Monad.Trans.Reader (runReaderT, ask, ReaderT(..)) import Language.Javascript.JSaddle.Types-       (JSValueRefRef, JSValueRef, JSContextRef)+       (JSM, JSVal, MutableJSArray, JSContextRef) import Control.Monad.IO.Class (MonadIO(..))-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)+#ifdef ghcjs_HOST_OS import GHCJS.Types (isUndefined, isNull)-import GHCJS.Foreign (newArray, indexArray)+import qualified JavaScript.Array as Array (create, read) #else+import Language.Javascript.JSaddle.Native (makeNewJSVal) import Foreign (nullPtr, alloca) import Foreign.Storable (Storable(..)) import Graphics.UI.Gtk.WebKit.Types@@ -42,18 +47,9 @@        (webViewGetMainFrame) import Graphics.UI.Gtk.WebKit.JavaScriptCore.WebFrame        (webFrameGetGlobalContext)+import Graphics.UI.Gtk.General.General (postGUIAsync, postGUISync) #endif-import qualified Control.Exception as E (Exception, catch)---- | The @JSM@ monad keeps track of the JavaScript context.------ Given a @JSM@ function and a 'JSContextRef' you can run the--- function like this...------ > runReaderT jsmFunction javaScriptContext------ For an example of how to set up WebKitGTK+ see tests/TestJSaddle.hs-type JSM = ReaderT JSContextRef IO+import qualified Control.Exception as E (Exception, catch, bracket)  -- | Wrapped version of 'E.catch' that runs in a MonadIO that works --   a bit better with 'JSM'@@ -64,15 +60,27 @@ t `catch` c = do     r <- ask     liftIO (runReaderT t r `E.catch` \e -> runReaderT (c e) r)+{-# INLINE catch #-} --- | Handle JavaScriptCore functions that take a JSValueRefRef in order+-- | Wrapped version of 'E.bracket' that runs in a MonadIO that works+--   a bit better with 'JSM'+bracket :: MonadIO m => ReaderT r IO a -> (a -> ReaderT r IO b) -> (a -> ReaderT r IO c) -> ReaderT r m c+bracket aquire release f = do+    r <- ask+    liftIO $ E.bracket+        (runReaderT aquire r)+        (\x -> runReaderT (release x) r)+        (\x -> runReaderT (f x) r)+{-# INLINE bracket #-}++-- | Handle JavaScriptCore functions that take a MutableJSArray in order --   to throw exceptions.-catchval :: (JSValueRefRef -> JSM a) -> (JSValueRef -> JSM a) -> JSM a+catchval :: (MutableJSArray -> JSM a) -> (JSVal -> JSM a) -> JSM a catchval f catcher = do-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-    pexc <- liftIO newArray+#ifdef ghcjs_HOST_OS+    pexc   <- liftIO Array.create     result <- f pexc-    exc <- liftIO $ indexArray 0 pexc+    exc    <- liftIO $ Array.read 0 pexc     if isUndefined exc || isNull exc         then return result         else catcher exc@@ -84,10 +92,10 @@         exc <- liftIO $ peek pexc         if exc == nullPtr             then return result-            else catcher exc+            else makeNewJSVal exc >>= catcher #endif -#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)+#ifdef ghcjs_HOST_OS runJSaddle :: w -> JSM a -> IO a runJSaddle _ f = runReaderT f () #else@@ -96,5 +104,25 @@     gctxt <- webViewGetMainFrame webView >>= webFrameGetGlobalContext     runReaderT f gctxt #endif+{-# INLINE runJSaddle #-} -runJSaddle_ w f = runJSaddle w f >> return ()+postGUIAsyncJS :: JSM () -> JSM ()+#ifdef ghcjs_HOST_OS+postGUIAsyncJS = id+#else+postGUIAsyncJS f = do+    r <- ask+    liftIO . postGUIAsync $ runReaderT f r+#endif+{-# INLINE postGUIAsyncJS #-}++postGUISyncJS :: JSM a -> JSM a+#ifdef ghcjs_HOST_OS+postGUISyncJS = id+#else+postGUISyncJS f = do+    r <- ask+    liftIO . postGUISync $ runReaderT f r+#endif+{-# INLINE postGUISyncJS #-}+
+ src/Language/Javascript/JSaddle/Native.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE CPP #-}+-----------------------------------------------------------------------------+--+-- Module      :  Language.Javascript.JSaddle.Native+-- Copyright   :  (c) Hamish Mackenzie+-- License     :  MIT+--+-- Maintainer  :  Hamish Mackenzie <Hamish.K.Mackenzie@googlemail.com>+--+-- |+--+-----------------------------------------------------------------------------++module Language.Javascript.JSaddle.Native (+#if !defined(ghcjs_HOST_OS)+    makeNewJSVal+  , makeNewJSString+  , wrapJSString+  , withJSVal+  , withJSVals+  , withObject+  , withJSString+  , withToJSVal+#endif+) where++#if !defined(ghcjs_HOST_OS)+import Control.Monad.Trans.Reader (ask)+import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase+       (JSObjectRef, OpaqueJSString, JSStringRef, OpaqueJSContext,+        OpaqueJSValue, JSValueRef)+import Foreign.ForeignPtr+       (touchForeignPtr, FinalizerPtr, newForeignPtr, FinalizerEnvPtr,+        newForeignPtrEnv, ForeignPtr)+import Control.Monad.IO.Class (MonadIO, MonadIO(..))+import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef+       (jsvalueprotect)+import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef+       (jsstringretain)+import Language.Javascript.JSaddle.Types+       (JSM, JSString, Object(..), JSVal)+import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)+import Language.Javascript.JSaddle.Classes (ToJSVal(..), ToJSVal)++makeNewJSVal :: JSValueRef -> JSM (ForeignPtr OpaqueJSValue)+makeNewJSVal val = do+    ctx <- ask+    liftIO $ do+        jsvalueprotect ctx val+        newForeignPtrEnv jsValueUnprotect ctx val++foreign import ccall unsafe "&JSValueUnprotect"+  jsValueUnprotect :: FinalizerEnvPtr OpaqueJSContext OpaqueJSValue++makeNewJSString :: MonadIO m => JSStringRef -> m (ForeignPtr OpaqueJSString)+makeNewJSString s =+    liftIO $ do+        s' <- jsstringretain s+        newForeignPtr jsStringRelease s'++wrapJSString :: MonadIO m => JSStringRef -> m (ForeignPtr OpaqueJSString)+wrapJSString s = liftIO $ newForeignPtr jsStringRelease s++foreign import ccall unsafe "&JSStringRelease"+  jsStringRelease :: FinalizerPtr OpaqueJSString++withJSVal :: MonadIO m => JSVal -> (JSValueRef -> m a) -> m a+withJSVal v f =+ do result <- f (unsafeForeignPtrToPtr v)+    liftIO $ touchForeignPtr v+    return result++withJSVals :: MonadIO m => [JSVal] -> ([JSValueRef] -> m a) -> m a+withJSVals v f =+ do result <- f (map unsafeForeignPtrToPtr v)+    liftIO $ mapM_ touchForeignPtr v+    return result++withObject :: MonadIO m => Object -> (JSObjectRef -> m a) -> m a+withObject (Object o) f = do+    result <- f (unsafeForeignPtrToPtr o)+    liftIO $ touchForeignPtr o+    return result++withJSString :: MonadIO m => JSString -> (JSStringRef -> m a) -> m a+withJSString v f =+ do result <- f (unsafeForeignPtrToPtr v)+    liftIO $ touchForeignPtr v+    return result++withToJSVal :: ToJSVal val => val -> (JSValueRef -> JSM a) -> JSM a+withToJSVal val f = do+    v <- toJSVal val+    withJSVal v f+{-# INLINE withToJSVal #-}+#endif+
src/Language/Javascript/JSaddle/Object.hs view
@@ -3,10 +3,11 @@ {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE Rank2Types #-}+#ifdef ghcjs_HOST_OS {-# LANGUAGE ForeignFunctionInterface #-}-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT) {-# LANGUAGE JavaScriptFFI #-} #endif+{-# OPTIONS_GHC -fno-warn-orphans #-} ----------------------------------------------------------------------------- -- -- Module      :  Language.Javascript.JSaddle.Object@@ -20,14 +21,15 @@ -----------------------------------------------------------------------------  module Language.Javascript.JSaddle.Object (-    JSObjectRef-  , MakeObjectRef(..)+    Object+  , MakeObject(..)    -- * Property lookup   , (!)   , (!!)   , js-  , JSF(..)+  , jss+  , JSF   , jsf   , js0   , js1@@ -36,20 +38,31 @@   , js4   , js5   , jsg+  , jsgf+  , jsg0+  , jsg1+  , jsg2+  , jsg3+  , jsg4+  , jsg5    -- * Setting the value of a property   , (<#)+  , (<##)    -- * Calling JavaSctipt   , (#)+  , (##)   , new   , call   , obj    -- * Calling Haskell From JavaScript+  , Function(..)   , function+  , freeFunction   , fun-  , JSCallAsFunction(..)+  , JSCallAsFunction   -- ** Object Constructors    -- | There is no good way to support calling haskell code as a JavaScript@@ -68,97 +81,110 @@    -- * Enumerating Properties   , propertyNames+  , properties    -- * Low level   , objCallAsFunction   , objCallAsConstructor+  , nullObject ) where +import Control.Applicative import Prelude hiding ((!!)) import Language.Javascript.JSaddle.Types-       (JSPropertyNameArrayRef, JSStringRef, JSObjectRef, JSValueRefRef,-        JSValueRef, JSContextRef, Index)-import Foreign.C.Types (CSize(..), CULong(..), CUInt(..), CULLong(..))-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-import GHCJS.Types (nullRef, castRef, JSArray, JSFun)-import GHCJS.Foreign (newObj, toArray, fromArray, syncCallback2, ForeignRetention(..))+       (JSPropertyNameArray, JSString, Object(..), MutableJSArray,+        JSVal, Index)+import Foreign.C.Types (CSize(..), CULong(..))+#ifdef ghcjs_HOST_OS+import GHCJS.Types (nullRef, jsval)+import GHCJS.Foreign.Callback+       (releaseCallback, syncCallback2, OnBlocked(..), Callback)+import GHCJS.Marshal.Pure (pFromJSVal)+import JavaScript.Array (JSArray)+import qualified JavaScript.Array as Array (toListIO, fromListIO)+import JavaScript.Array.Internal (SomeJSArray(..))+import qualified JavaScript.Object as Object (create) import Control.Monad (liftM)-import Control.Applicative ((<$>))+import Data.Coerce (coerce) #else import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef        (jsobjectmake, jspropertynamearraygetnameatindex,         jspropertynamearraygetcount, jsobjectcopypropertynames,-        jsobjectsetpropertyatindex, jsobjectgetpropertyatindex,         jsobjectcallasconstructor, jsobjectmakearray,-        jsobjectcallasfunction, jsobjectgetproperty, jsobjectsetproperty,-        JSPropertyAttributes, JSObjectCallAsFunctionCallback,+        jsobjectcallasfunction,+        JSObjectCallAsFunctionCallback,         jsobjectmakefunctionwithcallback, JSObjectCallAsFunctionCallback') import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef        (jsvaluemakeundefined) import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSContextRef        (jscontextgetglobalobject) import Foreign (peekArray, nullPtr, withArrayLen)+import Foreign.Ptr (freeHaskellFunPtr)+import Language.Javascript.JSaddle.Native+       (makeNewJSVal, wrapJSString, withJSVals, withObject, withJSString,+        withToJSVal)+import System.IO.Unsafe (unsafePerformIO)+import Foreign.ForeignPtr (newForeignPtr_) #endif import Language.Javascript.JSaddle.Exception (rethrow) import Language.Javascript.JSaddle.Value-       (JSUndefined, valMakeUndefined, valToObject)-import Language.Javascript.JSaddle.PropRef (JSPropRef(..))+       (JSUndefined, valToObject) import Language.Javascript.JSaddle.Classes-       (MakeValueRef(..), MakeStringRef(..), MakeArgRefs(..), MakePropRef(..),-        MakeObjectRef(..))+       (ToJSVal(..), ToJSString(..), MakeObject(..))+import Language.Javascript.JSaddle.Arguments (MakeArgs(..)) import Language.Javascript.JSaddle.Monad        (JSM) import Control.Monad.Trans.Reader (runReaderT, ask) import Control.Monad.IO.Class (MonadIO(..)) import qualified Control.Exception as E (catch) import Control.Exception (SomeException)-import qualified Data.Text as T (pack) import Foreign.Storable (Storable(..)) import Language.Javascript.JSaddle.Properties-import Control.Lens-       (IndexPreservingGetter, to, (^.))-import Language.Javascript.JSaddle.String (textToStr)+import Control.Lens (IndexPreservingGetter, to)+import Language.Javascript.JSaddle.String (nullJSString)+import Data.Text (Text) --- | If we already have a JSObjectRef we are fine-instance MakeObjectRef JSObjectRef where-    makeObjectRef = return+-- $setup+-- >>> import Language.Javascript.JSaddle.Test (testJSaddle)+-- >>> import Language.Javascript.JSaddle.Evaluate (eval)+-- >>> import Language.Javascript.JSaddle.Value (val)+-- >>> import Control.Lens.Operators ((^.)) --- | JSObjectRef can be made by evaluating a function in 'JSM' as long---   as it returns something we can make into a JSObjectRef.-instance MakeObjectRef v => MakeObjectRef (JSM v) where-    makeObjectRef v = v >>= makeObjectRef+-- | Object can be made by evaluating a fnction in 'JSM' as long+--   as it returns something we can make into a Object.+instance MakeObject v => MakeObject (JSM v) where+    makeObject v = v >>= makeObject+    {-# INLINE makeObject #-} --- | Lookup a property based on its name.  This function just constructs a JSPropRef---   the lookup is delayed until we use the JSPropRef.  This makes it a bit lazy compared---   to JavaScript's @.@ operator.+-- | Lookup a property based on its name. -- -- >>> testJSaddle $ eval "'Hello World'.length" -- >>> testJSaddle $ val "Hello World" ! "length" -- 11-(!) :: (MakeObjectRef this, MakeStringRef name)-    => this          -- ^ Object to look on-    -> name          -- ^ Name of the property to find-    -> JSM JSPropRef -- ^ Property reference+(!) :: (MakeObject this, ToJSString name)+    => this           -- ^ Object to look on+    -> name           -- ^ Name of the property to find+    -> JSM JSVal -- ^ Property reference this ! name = do-    rthis <- makeObjectRef this-    return (JSPropRef rthis rname)+    rthis <- makeObject this+    rethrow $ objGetPropertyByName rthis rname   where-    rname = makeStringRef name+    rname = toJSString name+{-# INLINE (!) #-} --- | Lookup a property based on its index.  This function just constructs a JSPropRef---   the lookup is delayed until we use the JSPropRef.  This makes it a bit lazy compared---   to JavaScript's @[]@ operator.+-- | Lookup a property based on its index. -- -- >>> testJSaddle $ eval "'Hello World'[6]" -- >>> testJSaddle $ val "Hello World" !! 6 -- W-(!!) :: (MakeObjectRef this)-     => this          -- ^ Object to look on-     -> Index         -- ^ Index of the property to lookup-     -> JSM JSPropRef -- ^ Property reference+(!!) :: (MakeObject this)+     => this           -- ^ Object to look on+     -> Index          -- ^ Index of the property to lookup+     -> JSM JSVal -- ^ Property reference this !! index = do-    rthis <- makeObjectRef this-    return (JSPropIndexRef rthis index)+    rthis <- makeObject this+    rethrow $ objGetPropertyAtIndex rthis index+{-# INLINE (!!) #-}  -- | Makes a getter for a particular property name. --@@ -167,33 +193,48 @@ -- >>> testJSaddle $ eval "'Hello World'.length" -- >>> testJSaddle $ val "Hello World" ^. js "length" -- 11-js :: (MakeObjectRef s, MakeStringRef name)+js :: (MakeObject s, ToJSString name)    => name          -- ^ Name of the property to find-   -> IndexPreservingGetter s (JSM JSPropRef)+   -> IndexPreservingGetter s (JSM JSVal) js name = to (!name)+{-# INLINE js #-} --- | Java script function applications have this type-type JSF = MakeObjectRef o => IndexPreservingGetter o (JSM JSValueRef)+-- | Makes a setter for a particular property name.+--+-- > jss name = to (<#name)+--+-- >>> testJSaddle $ eval "'Hello World'.length"+-- >>> testJSaddle $ val "Hello World" ^. js "length"+-- 11+jss :: (ToJSString name, ToJSVal val)+   => name          -- ^ Name of the property to find+   -> val+   -> forall o . MakeObject o => IndexPreservingGetter o (JSM ())+jss name val = to (\o -> o <# name $ val)+{-# INLINE jss #-}  -- | Handy way to call a function ----- > jsf name = js name . to (# args)+-- > jsf name = to (\o -> o # name $ args) -- -- >>> testJSaddle $ val "Hello World" ^. jsf "indexOf" ["World"] -- 6-jsf :: (MakeStringRef name, MakeArgRefs args) => name -> args -> JSF-jsf name args = function . to (# args)-    where-        function = js name+jsf :: (ToJSString name, MakeArgs args) => name -> args -> JSF+jsf name args = to (\o -> o # name $ args)+{-# INLINE jsf #-} +-- | Java script function applications have this type+type JSF = forall o . MakeObject o => IndexPreservingGetter o (JSM JSVal)+ -- | Handy way to call a function that expects no arguments -- -- > js0 name = jsf name () -- -- >>> testJSaddle $ val "Hello World" ^. js0 "toLowerCase" -- hello world-js0 :: (MakeStringRef name) => name -> JSF+js0 :: (ToJSString name) => name -> JSF js0 name = jsf name ()+{-# INLINE js0 #-}  -- | Handy way to call a function that expects one argument --@@ -201,29 +242,34 @@ -- -- >>> testJSaddle $ val "Hello World" ^. js1 "indexOf" "World" -- 6-js1 :: (MakeStringRef name, MakeValueRef a0) => name -> a0 -> JSF+js1 :: (ToJSString name, ToJSVal a0) => name -> a0 -> JSF js1 name a0 = jsf name [a0]+{-# INLINE js1 #-}  -- | Handy way to call a function that expects two arguments-js2 :: (MakeStringRef name, MakeValueRef a0, MakeValueRef a1) => name -> a0 -> a1 -> JSF+js2 :: (ToJSString name, ToJSVal a0, ToJSVal a1) => name -> a0 -> a1 -> JSF js2 name a0 a1 = jsf name (a0, a1)+{-# INLINE js2 #-}  -- | Handy way to call a function that expects three arguments-js3 :: (MakeStringRef name, MakeValueRef a0, MakeValueRef a1, MakeValueRef a2)+js3 :: (ToJSString name, ToJSVal a0, ToJSVal a1, ToJSVal a2)     => name -> a0 -> a1 -> a2 -> JSF js3 name a0 a1 a2 = jsf name (a0, a1, a2)+{-# INLINE js3 #-}  -- | Handy way to call a function that expects four arguments-js4 :: (MakeStringRef name, MakeValueRef a0, MakeValueRef a1, MakeValueRef a2,-        MakeValueRef a3)+js4 :: (ToJSString name, ToJSVal a0, ToJSVal a1, ToJSVal a2,+        ToJSVal a3)     => name -> a0 -> a1 -> a2 -> a3 -> JSF js4 name a0 a1 a2 a3 = jsf name (a0, a1, a2, a3)+{-# INLINE js4 #-}  -- | Handy way to call a function that expects five arguments-js5 :: (MakeStringRef name, MakeValueRef a0, MakeValueRef a1, MakeValueRef a2,-        MakeValueRef a3, MakeValueRef a4)+js5 :: (ToJSString name, ToJSVal a0, ToJSVal a1, ToJSVal a2,+        ToJSVal a3, ToJSVal a4)     => name -> a0 -> a1 -> a2 -> a3 -> a4 -> JSF js5 name a0 a1 a2 a3 a4 = jsf name (a0, a1, a2, a3, a4)+{-# INLINE js5 #-}   -- | Handy way to get and hold onto a reference top level javascript@@ -231,82 +277,175 @@ -- >>> testJSaddle $ eval "w = console; w.log('Hello World')" -- >>> testJSaddle $ do w <- jsg "console"; w ^. js "log" # ["Hello World"] -- 11-jsg :: MakeStringRef a => a -> JSM JSPropRef+jsg :: ToJSString a => a -> JSM JSVal jsg name = global ! name+{-# INLINE jsg #-} +-- | Handy way to call a function+--+-- > jsgf name = jsg name . to (# args)+--+-- >>> testJSaddle $ eval "globalFunc = function(x) {x.length}"+-- >>> testJSaddle $ jsgf "globalFunc" ["World"]+-- 6+jsgf :: (ToJSString name, MakeArgs args) => name -> args -> JSM JSVal+jsgf name = global # name+{-# INLINE jsgf #-}++-- | Handy way to call a function that expects no arguments+--+-- > jsg0 name = jsgf name ()+--+-- >>> testJSaddle $ jsg0 "globalFunc"+-- hello world+jsg0 :: (ToJSString name) => name -> JSM JSVal+jsg0 name = jsgf name ()+{-# INLINE jsg0 #-}++-- | Handy way to call a function that expects one argument+--+-- > jsg1 name a0 = jsgf name [a0]+--+-- >>> testJSaddle $ jsg1 "globalFunc" "World"+-- 6+jsg1 :: (ToJSString name, ToJSVal a0) => name -> a0 -> JSM JSVal+jsg1 name a0 = jsgf name [a0]+{-# INLINE jsg1 #-}++-- | Handy way to call a function that expects two arguments+jsg2 :: (ToJSString name, ToJSVal a0, ToJSVal a1) => name -> a0 -> a1 -> JSM JSVal+jsg2 name a0 a1 = jsgf name (a0, a1)+{-# INLINE jsg2 #-}++-- | Handy way to call a function that expects three arguments+jsg3 :: (ToJSString name, ToJSVal a0, ToJSVal a1, ToJSVal a2)+    => name -> a0 -> a1 -> a2 -> JSM JSVal+jsg3 name a0 a1 a2 = jsgf name (a0, a1, a2)+{-# INLINE jsg3 #-}++-- | Handy way to call a function that expects four arguments+jsg4 :: (ToJSString name, ToJSVal a0, ToJSVal a1, ToJSVal a2,+        ToJSVal a3)+    => name -> a0 -> a1 -> a2 -> a3 -> JSM JSVal+jsg4 name a0 a1 a2 a3 = jsgf name (a0, a1, a2, a3)+{-# INLINE jsg4 #-}++-- | Handy way to call a function that expects five arguments+jsg5 :: (ToJSString name, ToJSVal a0, ToJSVal a1, ToJSVal a2,+        ToJSVal a3, ToJSVal a4)+    => name -> a0 -> a1 -> a2 -> a3 -> a4 -> JSM JSVal+jsg5 name a0 a1 a2 a3 a4 = jsgf name (a0, a1, a2, a3, a4)+{-# INLINE jsg5 #-}+ -- | Call a JavaScript function -- -- >>> testJSaddle $ eval "'Hello World'.indexOf('World')"--- >>> testJSaddle $ val "Hello World" ! "indexOf" # ["World"]+-- >>> testJSaddle $ val "Hello World" # "indexOf" $ ["World"] -- 6 infixr 2 #-(#) :: (MakePropRef prop, MakeArgRefs args)-    => prop -> args -> JSM JSValueRef-prop # args = do-    rprop <- makePropRef prop-    (this, f) <- objGetProperty' rprop-    rethrow $ objCallAsFunction f this args+(#) :: (MakeObject this, ToJSString name, MakeArgs args)+    => this -> name -> args -> JSM JSVal+(#) this name args = do+    rthis <- makeObject this+    f <- rethrow $ objGetPropertyByName rthis name+    f' <- valToObject f+    rethrow $ objCallAsFunction f' rthis args+{-# INLINE (#) #-}  -- | Call a JavaScript function --+-- >>> testJSaddle $ eval "something[6]('World')"+-- >>> testJSaddle $ val something ## 6 ["World"]+infixr 2 ##+(##) :: (MakeObject this, MakeArgs args)+    => this -> Index -> args -> JSM JSVal+(##) this index args = do+    rthis <- makeObject this+    f <- rethrow $ objGetPropertyAtIndex rthis index+    f' <- valToObject f+    rethrow $ objCallAsFunction f' rthis args+{-# INLINE (##) #-}++-- | Set a JavaScript property+-- -- >>> testJSaddle $ eval "var j = {}; j.x = 1; j.x"--- >>> testJSaddle $ do {j <- eval "({})"; j!"x" <# 1; j!"x"}+-- >>> testJSaddle $ do {j <- eval "({})"; j <# "x" 1; j!"x"} -- 1-infixr 0 <#-(<#) :: (MakePropRef prop, MakeValueRef val)-     => prop          -- ^ Property to set-     -> val           -- ^ Value to set it to-     -> JSM JSPropRef -- ^ Reference to the property set-prop <# val = do-    p <- makePropRef prop-    objSetProperty p val-    return p+infixr 1 <#+(<#) :: (MakeObject this, ToJSString name, ToJSVal val)+     => this           -- ^ Object to set the property on+     -> name           -- ^ Name of the property to set+     -> val            -- ^ Value to set it to+     -> JSM ()+(<#) this name val = do+    rthis <- makeObject this+    rethrow $ objSetPropertyByName rthis name val 0+{-# INLINE (<#) #-} +-- | Set a JavaScript property+--+-- >>> testJSaddle $ eval "var j = {}; j[6] = 1; j[6]"+-- >>> testJSaddle $ do {j <- eval "({})"; j <## 6 1; j!!6}+-- 1+infixr 1 <##+(<##) :: (MakeObject this, ToJSVal val)+     => this           -- ^ Object to set the property on+     -> Index          -- ^ Index of the property to set+     -> val            -- ^ Value to set it to+     -> JSM ()+(<##) this index val = do+    rthis <- makeObject this+    rethrow $ objSetPropertyAtIndex rthis index val+{-# INLINE (<##) #-}+ -- | Use this to create a new JavaScript object -- -- If you pass more than 7 arguments to a constructor for a built in -- JavaScript type (like Date) then this function will fail. ----- >>> testJSaddle $ new "Date" (2013, 1, 1)+-- >>> testJSaddle $ new (jsg "Date") (2013, 1, 1) -- Fri Feb 01 2013 00:00:00 GMT+1300 (NZDT)-new :: (MakeObjectRef constructor, MakeArgRefs args)+new :: (MakeObject constructor, MakeArgs args)     => constructor     -> args-    -> JSM JSValueRef+    -> JSM JSVal new constructor args = do-    f <- makeObjectRef constructor+    f <- makeObject constructor     rethrow $ objCallAsConstructor f args+{-# INLINE new #-}  -- | Call function with a given @this@.  In most cases you should use '#'. -- -- >>> testJSaddle $ eval "(function(){return this;}).apply('Hello', [])" -- >>> testJSaddle $ do { test <- eval "(function(){return this;})"; call test (val "Hello") () } -- Hello-call :: (MakeObjectRef function, MakeObjectRef this, MakeArgRefs args)-    => function -> this -> args -> JSM JSValueRef-call function this args = do-    rfunction <- makeObjectRef function-    rthis     <- makeObjectRef this+call :: (MakeObject f, MakeObject this, MakeArgs args)+    => f -> this -> args -> JSM JSVal+call f this args = do+    rfunction <- makeObject f+    rthis     <- makeObject this     rethrow $ objCallAsFunction rfunction rthis args+{-# INLINE call #-}  -- | Make an empty object using the default constuctor -- -- >>> testJSaddle $ eval "var a = {}; a.x = 'Hello'; a.x" -- >>> testJSaddle $ do { a <- obj; a ^. js "x" <# "Hello"; a ^. js "x" } -- Hello-obj :: JSM JSObjectRef-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-obj = liftIO $ newObj+obj :: JSM Object+#ifdef ghcjs_HOST_OS+obj = liftIO Object.create #else obj = do     gctxt <- ask-    liftIO $ jsobjectmake gctxt nullPtr nullPtr+    Object <$> (liftIO (jsobjectmake gctxt nullPtr nullPtr) >>= makeNewJSVal) #endif+{-# INLINE obj #-}  -- | Type used for Haskell functions called from JavaScript.-type JSCallAsFunction = JSValueRef      -- ^ Function object-                     -> JSValueRef      -- ^ this-                     -> [JSValueRef]    -- ^ Function arguments+type JSCallAsFunction = JSVal      -- ^ Function object+                     -> JSVal      -- ^ this+                     -> [JSVal]    -- ^ Function arguments                      -> JSM JSUndefined -- ^ Only 'JSUndefined' can be returned because                                         --   the function may need to be executed in a                                         --   different thread.  If you need to get a@@ -322,73 +461,98 @@ -- undefined fun :: JSCallAsFunction -> JSCallAsFunction fun = id+{-# INLINE fun #-} -#if (!defined(ghcjs_HOST_OS) || !defined(USE_JAVASCRIPTFFI)) && defined(USE_WEBKIT)+#if !defined(ghcjs_HOST_OS) foreign import ccall "wrapper"   mkJSObjectCallAsFunctionCallback :: JSObjectCallAsFunctionCallback' -> IO JSObjectCallAsFunctionCallback #endif +#ifdef ghcjs_HOST_OS+type HaskellCallback = Callback (JSVal -> JSVal -> IO ())+#else+type HaskellCallback = JSObjectCallAsFunctionCallback+#endif++data Function = Function {functionCallback :: HaskellCallback, functionObject :: Object}+ -- ^ Make a JavaScript function object that wraps a Haskell function.-function :: MakeStringRef name+function :: ToJSString name          => name             -- ^ Name of the function          -> JSCallAsFunction -- ^ Haskell function to call-         -> JSM JSObjectRef  -- ^ Returns a JavaScript function object that will+         -> JSM Function       -- ^ Returns a JavaScript function object that will                              --   call the Haskell one when it is called-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)+#ifdef ghcjs_HOST_OS function name f = liftIO $ do-    callback <- syncCallback2 AlwaysRetain True $ \this args -> do-        rargs <- fromArray args+    callback <- syncCallback2 ContinueAsync $ \this args -> do+        rargs <- Array.toListIO (coerce args)         runReaderT (f this this rargs) () -- TODO pass function object through-    makeFunctionWithCallback (makeStringRef name) callback+    Function callback <$> makeFunctionWithCallback (toJSString name) callback foreign import javascript unsafe "$r = function () { $2(this, arguments); }"-    makeFunctionWithCallback :: JSStringRef -> JSFun (JSValueRef -> JSValueRefRef -> IO ()) -> IO JSObjectRef-#elif defined(USE_WEBKIT)+    makeFunctionWithCallback :: JSString -> Callback (JSVal -> JSVal -> IO ()) -> IO Object+#else function name f = do     gctxt <- ask-    callback <- liftIO $ mkJSObjectCallAsFunctionCallback wrap-    liftIO $ jsobjectmakefunctionwithcallback gctxt (makeStringRef name) callback+    callback <- liftIO $ mkJSObjectCallAsFunctionCallback (wrap gctxt)+    withJSString (toJSString name) $ \name' ->+        Function callback . Object <$>+            (liftIO (jsobjectmakefunctionwithcallback gctxt name' callback) >>= makeNewJSVal)   where-    wrap ctx fobj this argc argv exception = do-            args <- peekArray (fromIntegral argc) argv-            (`runReaderT` ctx) $-                f fobj this args >>= makeValueRef-      `E.catch` \(e :: SomeException) -> do-            str <- runReaderT (makeValueRef . T.pack $ show e) ctx-            poke exception str-            jsvaluemakeundefined ctx+    wrap gctxt _ctx fobj' this' argc argv exception = do+            args' <- peekArray (fromIntegral argc) argv+            (`runReaderT` gctxt) $ do+                fobj <- makeNewJSVal fobj'+                this <- makeNewJSVal this'+                args <- mapM makeNewJSVal args'+                f fobj this args+                liftIO $ jsvaluemakeundefined gctxt+      `E.catch` \(e :: SomeException) ->+            (`runReaderT` gctxt) $ do+                withToJSVal (show e) $ liftIO . poke exception+                liftIO $ jsvaluemakeundefined gctxt+#endif++freeFunction :: MonadIO m => Function -> m ()+freeFunction (Function callback _) = liftIO $+#ifdef ghcjs_HOST_OS+    releaseCallback callback #else-function  = undefined+    freeHaskellFunPtr callback #endif +instance ToJSVal Function where+    toJSVal (Function _ f) = toJSVal f+    {-# INLINE toJSVal #-}+ -- | A callback to Haskell can be used as a JavaScript value.  This will create --   an anonymous JavaScript function object.  Use 'function' to create one with --   a name.-instance MakeValueRef JSCallAsFunction where-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-    makeValueRef = function (nullRef:: JSStringRef)-#else-    makeValueRef = function (nullPtr:: JSStringRef)-#endif+instance ToJSVal JSCallAsFunction where+    toJSVal f = functionObject <$> function nullJSString f >>= toJSVal+    {-# INLINE toJSVal #-} -instance MakeArgRefs JSCallAsFunction where-    makeArgRefs f = do-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-        rarg <- function (nullRef:: JSStringRef) f-#else-        rarg <- function (nullPtr:: JSStringRef) f-#endif+instance MakeArgs JSCallAsFunction where+    makeArgs f = do+        rarg <- functionObject <$> function nullJSString f >>= toJSVal         return [rarg]+    {-# INLINE makeArgs #-} -makeArray :: MakeArgRefs args => args -> JSValueRefRef -> JSM JSObjectRef-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-makeArray args exceptions = makeArgRefs args >>= liftM castRef . liftIO . toArray+makeArray :: MakeArgs args => args -> MutableJSArray -> JSM Object+#ifdef ghcjs_HOST_OS+makeArray args exceptions = do+    rargs <- makeArgs args+    liftIO $ Object . jsval <$> Array.fromListIO rargs #else makeArray args exceptions = do     gctxt <- ask-    rargs <- makeArgRefs args-    liftIO $ withArrayLen rargs $ \ len ptr ->-        jsobjectmakearray gctxt (fromIntegral len) ptr exceptions+    rargs <- makeArgs args+    result <-+        withJSVals rargs $ \rargs' ->+            liftIO $ withArrayLen rargs' $ \ len ptr ->+                jsobjectmakearray gctxt (fromIntegral len) ptr exceptions+    Object <$> makeNewJSVal result #endif+{-# INLINE makeArray #-}  -- | Make an JavaScript array from a list of values --@@ -398,96 +562,146 @@ -- >>> testJSaddle $ eval "['Hello', null, undefined, true, 1]" -- >>> testJSaddle $ array ("Hello", JSNull, (), True, 1.0::Double) -- Hello,,,true,1-array :: MakeArgRefs args => args -> JSM JSObjectRef+array :: MakeArgs args => args -> JSM Object array = rethrow . makeArray +-- Make an array out of various lists+instance ToJSVal [JSVal] where+    toJSVal = toJSVal . array+    {-# INLINE toJSVal #-}++instance ToJSVal [JSM JSVal] where+    toJSVal = toJSVal . array+    {-# INLINE toJSVal #-}++instance ToJSVal [Double] where+    toJSVal = toJSVal . array+    {-# INLINE toJSVal #-}++instance ToJSVal [Float] where+    toJSVal = toJSVal . array+    {-# INLINE toJSVal #-}++instance ToJSVal [Int] where+    toJSVal = toJSVal . array+    {-# INLINE toJSVal #-}++instance ToJSVal [JSString] where+    toJSVal = toJSVal . array+    {-# INLINE toJSVal #-}++instance ToJSVal [String] where+    toJSVal = toJSVal . array+    {-# INLINE toJSVal #-}++instance ToJSVal [Text] where+    toJSVal = toJSVal . array+    {-# INLINE toJSVal #-}++instance ToJSVal [Bool] where+    toJSVal = toJSVal . array+    {-# INLINE toJSVal #-}+ -- | JavaScript's global object-global :: JSM JSObjectRef-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)+global :: JSM Object+#ifdef ghcjs_HOST_OS global = liftIO js_window+{-# INLINE global #-} foreign import javascript unsafe "$r = window"-    js_window :: IO JSObjectRef-#elif defined(USE_WEBKIT)-global = ask >>= (liftIO . jscontextgetglobalobject)+    js_window :: IO Object #else-global = undefined+global = do+    gctxt <- ask+    result <- liftIO $ jscontextgetglobalobject gctxt+    Object <$> makeNewJSVal result+{-# INLINE global #-} #endif  -- | Get an array containing the property names present on a given object-#if (!defined(ghcjs_HOST_OS) || !defined(USE_JAVASCRIPTFFI)) && defined(USE_WEBKIT)-copyPropertyNames :: MakeObjectRef this => this -> JSM JSPropertyNameArrayRef+#if !defined(ghcjs_HOST_OS)+copyPropertyNames :: MakeObject this => this -> JSM JSPropertyNameArray copyPropertyNames this = do     gctxt <- ask-    rthis <- makeObjectRef this-    liftIO $ jsobjectcopypropertynames gctxt rthis+    this' <- makeObject this+    withObject this' $ \rthis ->+        liftIO $ jsobjectcopypropertynames gctxt rthis+{-# INLINE copyPropertyNames #-}  -- | Get the number of names in a property name array-propertyNamesCount :: MonadIO m => JSPropertyNameArrayRef -> m CSize+propertyNamesCount :: MonadIO m => JSPropertyNameArray -> m CSize propertyNamesCount names = liftIO $ jspropertynamearraygetcount names+{-# INLINE propertyNamesCount #-}  -- | Get a name out of a property name array-propertyNamesAt :: MonadIO m => JSPropertyNameArrayRef -> CSize -> m JSStringRef-propertyNamesAt names index = liftIO $ jspropertynamearraygetnameatindex names index+propertyNamesAt :: MonadIO m => JSPropertyNameArray -> CSize -> m JSString+propertyNamesAt names index = liftIO $ jspropertynamearraygetnameatindex names index >>= wrapJSString+{-# INLINE propertyNamesAt #-}  -- | Convert property array to a list-propertyNamesList :: MonadIO m => JSPropertyNameArrayRef -> m [JSStringRef]+propertyNamesList :: MonadIO m => JSPropertyNameArray -> m [JSString] propertyNamesList names = do     count <- propertyNamesCount names     mapM (propertyNamesAt names) $ enumFromTo 0 (count - 1)+{-# INLINE propertyNamesList #-} #endif  -- | Get a list containing the property names present on a given object-propertyNames :: MakeObjectRef this => this -> JSM [JSStringRef]-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)-propertyNames this = makeObjectRef this >>= liftIO . js_propertyNames >>= liftIO . fromArray+propertyNames :: MakeObject this => this -> JSM [JSString]+#ifdef ghcjs_HOST_OS+propertyNames this = makeObject this >>= liftIO . js_propertyNames >>= liftIO . (fmap (map pFromJSVal)) . Array.toListIO+{-# INLINE propertyNames #-} foreign import javascript unsafe "$r = []; h$forIn($1, function(n){$r.push(n);})"-    js_propertyNames :: JSObjectRef -> IO (JSArray a)-#elif defined(USE_WEBKIT)-propertyNames this = copyPropertyNames this >>= propertyNamesList+    js_propertyNames :: Object -> IO JSArray #else-propertyNames = undefined+propertyNames this = copyPropertyNames this >>= propertyNamesList+{-# INLINE propertyNames #-} #endif  -- | Get a list containing references to all the  properties present on a given object-properties :: MakeObjectRef this => this -> JSM [JSPropRef]+properties :: MakeObject this => this -> JSM [JSVal] properties this = propertyNames this >>= mapM (this !)  -- | Call a JavaScript object as function.  Consider using '#'.-objCallAsFunction :: MakeArgRefs args-                  => JSObjectRef-                  -> JSObjectRef+objCallAsFunction :: MakeArgs args+                  => Object+                  -> Object                   -> args-                  -> JSValueRefRef-                  -> JSM JSValueRef-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)-objCallAsFunction function this args exceptions = do-    rargs <- makeArgRefs args >>= liftIO . toArray-    liftIO $ js_apply function this rargs exceptions+                  -> MutableJSArray+                  -> JSM JSVal+#ifdef ghcjs_HOST_OS+objCallAsFunction f this args exceptions = do+    rargs <- makeArgs args >>= liftIO . Array.fromListIO+    liftIO $ js_apply f this rargs exceptions+{-# INLINE objCallAsFunction #-} foreign import javascript unsafe "try { $r = $1.apply($2, $3) } catch(e) { $4[0] = e }"-    js_apply :: JSObjectRef -> JSObjectRef -> JSValueRefRef -> JSValueRefRef -> IO JSValueRef-#elif defined(USE_WEBKIT)-objCallAsFunction function this args exceptions = do-    gctxt <- ask-    rargs <- makeArgRefs args-    liftIO $ withArrayLen rargs $ \ largs pargs ->-        jsobjectcallasfunction gctxt function this (fromIntegral largs) pargs exceptions+    js_apply :: Object -> Object -> MutableJSArray -> MutableJSArray -> IO JSVal #else-objCallAsFunction = undefined+objCallAsFunction f this args exceptions = do+    gctxt <- ask+    rargs <- makeArgs args+    result <-+        withObject f $ \rfunction ->+            withObject this $ \rthis ->+                withJSVals rargs $ \rargs' ->+                    liftIO $ withArrayLen rargs' $ \ largs pargs ->+                        jsobjectcallasfunction gctxt rfunction rthis (fromIntegral largs) pargs exceptions+    makeNewJSVal result+{-# INLINE objCallAsFunction #-} #endif  -- | Call a JavaScript object as a constructor. Consider using 'new'. -- -- If you pass more than 7 arguments to a constructor for a built in -- JavaScript type (like Date) then this function will fail.-objCallAsConstructor :: MakeArgRefs args-                     => JSObjectRef+objCallAsConstructor :: MakeArgs args+                     => Object                      -> args-                     -> JSValueRefRef-                     -> JSM JSValueRef-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)-objCallAsConstructor function args exceptions = do-    rargs <- makeArgRefs args >>= liftIO . toArray-    liftIO $ js_new function rargs exceptions+                     -> MutableJSArray+                     -> JSM JSVal+#ifdef ghcjs_HOST_OS+objCallAsConstructor f args exceptions = do+    rargs <- makeArgs args >>= liftIO . Array.fromListIO+    liftIO $ js_new f rargs exceptions foreign import javascript unsafe "\     try {\         switch($2.length) {\@@ -515,17 +729,25 @@     catch(e) {\         $3[0] = e;\     }"-    js_new :: JSObjectRef -> JSValueRefRef -> JSValueRefRef -> IO JSValueRef-#elif defined(USE_WEBKIT)-objCallAsConstructor function args exceptions = do-    gctxt <- ask-    rargs <- makeArgRefs args-    liftIO $ withArrayLen rargs $ \ largs pargs ->-        jsobjectcallasconstructor gctxt function (fromIntegral largs) pargs exceptions+    js_new :: Object -> MutableJSArray -> MutableJSArray -> IO JSVal #else-objCallAsConstructor = undefined+objCallAsConstructor f args exceptions = do+    gctxt <- ask+    rargs <- makeArgs args+    result <-+        withObject f $ \rfunction ->+            withJSVals rargs $ \rargs' ->+                liftIO $ withArrayLen rargs' $ \ largs pargs ->+                    jsobjectcallasconstructor gctxt rfunction (fromIntegral largs) pargs exceptions+    makeNewJSVal result #endif +nullObject :: Object+#ifdef ghcjs_HOST_OS+nullObject = Object nullRef+#else+nullObject = Object . unsafePerformIO $ newForeignPtr_ nullPtr+#endif   
− src/Language/Javascript/JSaddle/PropRef.hs
@@ -1,25 +0,0 @@------------------------------------------------------------------------------------ Module      :  Language.Javascript.JSaddle.PropRef--- Copyright   :  (c) Hamish Mackenzie--- License     :  MIT------ Maintainer  :  Hamish Mackenzie <Hamish.K.Mackenzie@googlemail.com>------ | Implements a reference to a property-----------------------------------------------------------------------------------module Language.Javascript.JSaddle.PropRef (-    JSPropRef(..)-) where--import Language.Javascript.JSaddle.Types-       (JSStringRef, JSObjectRef, Index)---- | A reference to a property.---   Implemented as a reference to an object and something to find the property.-data JSPropRef = JSPropRef JSObjectRef JSStringRef -- ^ Object and property name.-               | JSPropIndexRef JSObjectRef Index  -- ^ Object and property index.--
src/Language/Javascript/JSaddle/Properties.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeSynonymInstances #-}-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)+#ifdef ghcjs_HOST_OS {-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI #-} #endif -----------------------------------------------------------------------------@@ -21,176 +21,118 @@ -----------------------------------------------------------------------------  module Language.Javascript.JSaddle.Properties (-  -- * Propery Reference-    JSPropRef(..)-  , MakePropRef(..)-   -- * Getting Property Values-  , objGetPropertyByName+    objGetPropertyByName   , objGetPropertyAtIndex-  , objGetProperty-  , objGetProperty'   -- * Setting Property Values   , objSetPropertyByName   , objSetPropertyAtIndex-  , objSetProperty ) where -import Control.Applicative ((<$>))-import Language.Javascript.JSaddle.PropRef (JSPropRef(..)) import Language.Javascript.JSaddle.Classes-       (MakePropRef(..), MakeObjectRef(..), MakeValueRef(..),-        MakeArgRefs(..), MakeStringRef(..))+       (ToJSVal(..), ToJSString(..)) import Language.Javascript.JSaddle.Monad (JSM) import Language.Javascript.JSaddle.Types-       (JSValueRefRef, JSObjectRef, JSPropertyAttributes,-        Index(..), JSStringRef)-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)+       (MutableJSArray, Object(..), JSPropertyAttributes,+        Index)+#ifdef ghcjs_HOST_OS+import Language.Javascript.JSaddle.Types (JSString) #else import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef        (jsobjectgetpropertyatindex, jsobjectgetproperty,-        jsobjectsetpropertyatindex, jsobjectsetproperty,-        JSPropertyAttributes)+        jsobjectsetpropertyatindex, jsobjectsetproperty)+import Language.Javascript.JSaddle.Native+       (makeNewJSVal, withObject, withJSString, withToJSVal) #endif import Control.Monad.Trans.Reader (ask) import Control.Monad.IO.Class (MonadIO(..))-import Language.Javascript.JSaddle.Exception (rethrow)-import Language.Javascript.JSaddle.Value (JSValueRef)+import Language.Javascript.JSaddle.Value (JSVal) import Language.Javascript.JSaddle.Arguments () import Language.Javascript.JSaddle.String () --- | If we already have a JSPropRef we are fine-instance MakePropRef JSPropRef where-    makePropRef = return---- | JSPropRef can be made by evaluating a function in 'JSM' as long---   as it returns something we can make into a JSPropRef.-instance MakePropRef prop => MakePropRef (JSM prop) where-    makePropRef prop = prop >>= makePropRef---- | We can use a property as an object.-instance MakeObjectRef JSPropRef where-    makeObjectRef = objGetProperty---- | We can use a property as a value.-instance MakeValueRef JSPropRef where-    makeValueRef = objGetProperty---- | We can pass a property as the only paramter to a function.-instance MakeArgRefs JSPropRef where-    makeArgRefs p = do-        rarg <- objGetProperty p-        return [rarg]- -- | Get a property value given the object and the name of the property.-objGetPropertyByName :: MakeStringRef name-                     => JSObjectRef    -- ^ object to find the property on.+objGetPropertyByName :: ToJSString name+                     => Object         -- ^ object to find the property on.                      -> name           -- ^ name of the property.-                     -> JSValueRefRef  -- ^ exception if one is raised.-                     -> JSM JSValueRef -- ^ returns the property value.-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)-objGetPropertyByName this name = liftIO . js_tryGetProp (makeStringRef name) this+                     -> MutableJSArray -- ^ exception if one is raised.+                     -> JSM JSVal      -- ^ returns the property value.+#ifdef ghcjs_HOST_OS+objGetPropertyByName this name = liftIO . js_tryGetProp (toJSString name) this+{-# INLINE objGetPropertyByName #-} foreign import javascript unsafe "try { $r=$2[$1] } catch(e) { $3[0] = e }"-    js_tryGetProp :: JSStringRef -> JSObjectRef -> JSValueRefRef -> IO JSValueRef-#elif defined(USE_WEBKIT)+    js_tryGetProp :: JSString -> Object -> MutableJSArray -> IO JSVal+#else objGetPropertyByName this name exceptions = do     gctxt <- ask-    liftIO $ jsobjectgetproperty gctxt this (makeStringRef name) exceptions-#else-objGetPropertyByName = undefined+    withObject this $ \rthis ->+        withJSString (toJSString name) $ \name' ->+            (liftIO $ jsobjectgetproperty gctxt rthis name' exceptions) >>= makeNewJSVal+{-# INLINE objGetPropertyByName #-} #endif  -- | Get a property value given the object and the index of the property.-objGetPropertyAtIndex :: JSObjectRef    -- ^ object to find the property on.+objGetPropertyAtIndex :: Object         -- ^ object to find the property on.                       -> Index          -- ^ index of the property.-                      -> JSValueRefRef  -- ^ exception if one is raised.-                      -> JSM JSValueRef -- ^ returns the property value.-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)+                      -> MutableJSArray -- ^ exception if one is raised.+                      -> JSM JSVal      -- ^ returns the property value.+#ifdef ghcjs_HOST_OS objGetPropertyAtIndex this index = liftIO . js_tryIndex index this+{-# INLINE objGetPropertyAtIndex #-} foreign import javascript unsafe "try { $r=$2[$1] } catch(e) { $3[0] = e }"-    js_tryIndex :: Index -> JSObjectRef -> JSValueRefRef -> IO JSValueRef-#elif defined(USE_WEBKIT)+    js_tryIndex :: Index -> Object -> MutableJSArray -> IO JSVal+#else objGetPropertyAtIndex this index exceptions = do     gctxt <- ask-    liftIO $ jsobjectgetpropertyatindex gctxt this index exceptions-#else-objGetPropertyAtIndex = undefined+    withObject this $ \rthis ->+        (liftIO $ jsobjectgetpropertyatindex gctxt rthis index exceptions) >>= makeNewJSVal+{-# INLINE objGetPropertyAtIndex #-} #endif --- | Gets the value of a property given a 'JSPropRef'.-objGetProperty :: JSPropRef      -- ^ property reference.-               -> JSM JSValueRef -- ^ returns the property value.-objGetProperty (JSPropRef      this name ) =-    rethrow $ objGetPropertyByName  this name-objGetProperty (JSPropIndexRef this index) =-    rethrow $ objGetPropertyAtIndex this index---- | This version of 'objGetProperty' is handy when you also need to perform.---   another operation on the object the property is on.-objGetProperty' :: JSPropRef                     -- ^ property reference.-                -> JSM (JSObjectRef, JSValueRef) -- ^ returns the object and property value.-objGetProperty' (JSPropRef this name) = do-    p <- rethrow $ objGetPropertyByName this name-    return (this, p)-objGetProperty' (JSPropIndexRef this index) = do-    p <- rethrow $ objGetPropertyAtIndex this index-    return (this, p)-- -- | Set a property value given the object and the name of the property.-objSetPropertyByName :: (MakeStringRef name, MakeValueRef val)-                     => JSObjectRef          -- ^ object to set the property on.+objSetPropertyByName :: (ToJSString name, ToJSVal val)+                     => Object               -- ^ object to set the property on.                      -> name                 -- ^ name of the property.                      -> val                  -- ^ new value to set the property to.                      -> JSPropertyAttributes -- ^ property attributes to give the property.-                     -> JSValueRefRef        -- ^ exception if one is raised.+                     -> MutableJSArray       -- ^ exception if one is raised.                      -> JSM ()-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)+#ifdef ghcjs_HOST_OS objSetPropertyByName this name val attributes exceptions = do-    vref <- makeValueRef val-    liftIO $ js_trySetProp (makeStringRef name) this vref exceptions+    vref <- toJSVal val+    liftIO $ js_trySetProp (toJSString name) this vref exceptions+{-# INLINE objSetPropertyByName #-} foreign import javascript unsafe "try { $2[$1]=$3 } catch(e) { $4[0] = e }"-    js_trySetProp :: JSStringRef -> JSObjectRef -> JSValueRef -> JSValueRefRef -> IO ()-#elif defined(USE_WEBKIT)+    js_trySetProp :: JSString -> Object -> JSVal -> MutableJSArray -> IO ()+#else objSetPropertyByName this name val attributes exceptions = do     gctxt <- ask-    vref <- makeValueRef val-    liftIO $ jsobjectsetproperty gctxt this (makeStringRef name) vref attributes exceptions-#else-objSetPropertyByName = undefined+    withObject this $ \rthis ->+        withJSString (toJSString name) $ \name' ->+        withToJSVal val $ \rval ->+            liftIO $ jsobjectsetproperty gctxt rthis name' rval attributes exceptions+{-# INLINE objSetPropertyByName #-} #endif  -- | Set a property value given the object and the index of the property.-objSetPropertyAtIndex :: (MakeValueRef val)-                      => JSObjectRef    -- ^ object to find property on.+objSetPropertyAtIndex :: (ToJSVal val)+                      => Object         -- ^ object to find property on.                       -> Index          -- ^ index of the property.                       -> val            -- ^ new value to set the property to.-                      -> JSValueRefRef  -- ^ exception if one is raised.+                      -> MutableJSArray -- ^ exception if one is raised.                       -> JSM ()-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)+#ifdef ghcjs_HOST_OS objSetPropertyAtIndex this index val exceptions = do-    vref <- makeValueRef val+    vref <- toJSVal val     liftIO $ js_trySetAtIndex index this vref exceptions+{-# INLINE objSetPropertyAtIndex #-} foreign import javascript unsafe "try { $2[$1]=$3 } catch(e) { $4[0] = e }"-    js_trySetAtIndex :: Index -> JSObjectRef -> JSValueRef -> JSValueRefRef -> IO ()-#elif defined(USE_WEBKIT)+    js_trySetAtIndex :: Index -> Object -> JSVal -> MutableJSArray -> IO ()+#else objSetPropertyAtIndex this index val exceptions = do     gctxt <- ask-    vref <- makeValueRef val-    liftIO $ jsobjectsetpropertyatindex gctxt this index vref exceptions-#else-objSetPropertyAtIndex = undefined+    withObject this $ \rthis ->+        withToJSVal val $ \rval ->+            liftIO $ jsobjectsetpropertyatindex gctxt rthis index rval exceptions+{-# INLINE objSetPropertyAtIndex #-} #endif---- | Sets the value of a property given a 'JSPropRef'.-objSetProperty :: (MakeValueRef val)-               => JSPropRef -- ^ property reference.-               -> val       -- ^ new value to set the property to.-               -> JSM ()-objSetProperty (JSPropRef      this name ) val = rethrow $ objSetPropertyByName  this name  val 0-objSetProperty (JSPropIndexRef this index) val = rethrow $ objSetPropertyAtIndex this index val---- 
src/Language/Javascript/JSaddle/String.hs view
@@ -14,61 +14,63 @@ -----------------------------------------------------------------------------  module Language.Javascript.JSaddle.String (-    JSStringRef-  , MakeStringRef(..)+    JSString+  , ToJSString(..)    -- * Data.Text helpers   , strToText   , textToStr+  , nullJSString ) where  import Data.Text (Text)-import qualified Data.Text as T (unpack, pack) import Control.Monad.IO.Class (MonadIO(..))-import Language.Javascript.JSaddle.Types (JSStringRef)-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-import GHCJS.Foreign (fromJSString, toJSString)+import Language.Javascript.JSaddle.Types (JSString)+#ifdef ghcjs_HOST_OS+import Data.JSString.Text (textFromJSString, textToJSString)+import GHCJS.Marshal.Internal (PFromJSVal(..))+import GHCJS.Types (nullRef) #else import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef        (jsstringcreatewithcharacters, jsstringgetcharactersptr,-        jsstringgetlength, jsstringcreatewithutf8cstring)-#endif+        jsstringgetlength)+import Language.Javascript.JSaddle.Native (makeNewJSString, withJSString)+import System.IO.Unsafe (unsafePerformIO)+import Foreign.ForeignPtr (newForeignPtr_)+import Foreign.Ptr (nullPtr) import qualified Data.Text.Foreign as T (fromPtr) import Foreign (castPtr) import Data.Text.Foreign (useAsPtr)-import Language.Javascript.JSaddle.Classes (MakeStringRef(..))-import System.IO.Unsafe (unsafePerformIO)---- | If we already have a JSStringRef we are fine-instance MakeStringRef JSStringRef where-    makeStringRef = id--instance MakeStringRef Text where-    makeStringRef = textToStr--instance MakeStringRef String where-    makeStringRef = textToStr . T.pack+#endif+import Language.Javascript.JSaddle.Classes (ToJSString(..))  -- | Convert a JavaScript string to a Haskell 'Text'-strToText :: MonadIO m => JSStringRef -> m Text-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-strToText = return . fromJSString+strToText :: MonadIO m => JSString -> m Text+#ifdef ghcjs_HOST_OS+strToText = return . textFromJSString #else-strToText jsstring = liftIO $ do+strToText jsstring' = liftIO $ withJSString jsstring' $ \jsstring -> do     l <- jsstringgetlength jsstring     p <- jsstringgetcharactersptr jsstring     T.fromPtr (castPtr p) (fromIntegral l) #endif+{-# INLINE strToText #-}  -- | Convert a Haskell 'Text' to a JavaScript string-textToStr :: Text -> JSStringRef-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-textToStr = toJSString+textToStr :: Text -> JSString+#ifdef ghcjs_HOST_OS+textToStr = textToJSString #else textToStr text = unsafePerformIO $     useAsPtr text $ \p l ->-        jsstringcreatewithcharacters (castPtr p) (fromIntegral l)+        jsstringcreatewithcharacters (castPtr p) (fromIntegral l) >>= makeNewJSString #endif-+{-# INLINE textToStr #-} +nullJSString :: JSString+#ifdef ghcjs_HOST_OS+nullJSString = pFromJSVal nullRef+#else+nullJSString = unsafePerformIO $ newForeignPtr_ nullPtr+#endif 
+ src/Language/Javascript/JSaddle/Test.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE RecordWildCards #-}+-----------------------------------------------------------------------------+--+-- Module      :  TestJSC+-- Copyright   :  (c) Hamish Mackenzie+-- License     :  MIT+--+-- Maintainer  :  Hamish Mackenzie <Hamish.K.Mackenzie@googlemail.com>+--+-- |+--+-----------------------------------------------------------------------------++module Language.Javascript.JSaddle.Test (+    testJSaddle+  , showJSaddle+  , listWindowProperties+) where++import Control.Applicative+import Prelude hiding((!!), catch)+import Graphics.UI.Gtk+       (Window, widgetDestroy, postGUIAsync, postGUISync, widgetShowAll,+        mainGUI, mainQuit, on, objectDestroy, containerAdd, scrolledWindowNew,+        windowSetPosition, windowSetDefaultSize, timeoutAddFull, windowNew,+        initGUI)+import Control.Concurrent+       (tryTakeMVar, forkIO, newMVar, putMVar, takeMVar, newEmptyMVar,+        yield)+import System.Glib.MainLoop (priorityLow)+import Graphics.UI.Gtk.General.Enums (WindowPosition(..))+import Graphics.UI.Gtk.WebKit.WebView+       (webViewGetMainFrame, webViewNew)+import System.IO.Unsafe (unsafePerformIO)+import Control.Monad.Trans.Reader (runReaderT)+import Graphics.UI.Gtk.WebKit.JavaScriptCore.WebFrame+       (webFrameGetGlobalContext)+import Language.Javascript.JSaddle+import qualified Data.Text as T+import Control.Monad.IO.Class (MonadIO(..))+import Control.Monad (forM, when)+import Control.Lens.Getter ((^.))+import Data.Monoid ((<>))+import Control.Concurrent.MVar (MVar)++data TestState = TestState { jsContext :: JSContextRef, window :: Window }++state :: MVar (Maybe TestState)+state = unsafePerformIO $ newMVar Nothing+{-# NOINLINE state #-}++done :: MVar ()+done = unsafePerformIO newEmptyMVar+{-# NOINLINE done #-}++-- >>> testJSaddle $ ((global ^. js "console" . js "log") # ["Hello"])+testJSaddle :: ToJSVal val => JSM val -> IO ()+testJSaddle = testJSaddle' False++-- >>> showJSaddle $ eval "document.body.innerHTML = 'Test'"+showJSaddle :: ToJSVal val => JSM val -> IO ()+showJSaddle = testJSaddle' True++debugLog :: String -> IO ()+debugLog = putStrLn++testJSaddle' :: ToJSVal val => Bool -> JSM val -> IO ()+testJSaddle' showWindow f = do+    debugLog "taking done"+    _ <- tryTakeMVar done+    debugLog "taking state"+    mbState <- takeMVar state+    TestState {..} <- case mbState of+        Nothing -> do+            debugLog "newState"+            newState <- newEmptyMVar+            debugLog "fork"+            _ <- forkIO $ do+                debugLog "initGUI"+                _ <- initGUI+                debugLog "windowNew"+                window <- windowNew+                debugLog "timeoutAdd"+                _ <- timeoutAddFull (yield >> return True) priorityLow 10+                windowSetDefaultSize window 900 600+                windowSetPosition window WinPosCenter+                scrollWin <- scrolledWindowNew Nothing Nothing+                webView <- webViewNew+                window `containerAdd` scrollWin+                scrollWin `containerAdd` webView+                _ <- on window objectDestroy $ do+                    debugLog "onDestroy"+                    _ <- tryTakeMVar state+                    debugLog "put state"+                    putMVar state Nothing+                    debugLog "mainQuit"+                    mainQuit+                    debugLog "put done"+                    putMVar done ()+                    return ()+                debugLog "get context"+                jsContext <- webViewGetMainFrame webView >>= webFrameGetGlobalContext+                debugLog "put initial state"+                putMVar newState TestState {..}+                debugLog "maybe show"+                when showWindow $ widgetShowAll window+                debugLog "mainGUI"+                mainGUI+                debugLog "mainGUI exited"+            takeMVar newState+        Just s@TestState {..} -> do+            debugLog "maybe show (2)"+            when showWindow . postGUISync $ widgetShowAll window+            return s+    x <- postGUISync $ runReaderT ((f >>= valToText >>= liftIO . putStrLn . T.unpack)+            `catch` \ (JSException e) -> valToText e >>= liftIO . putStrLn . T.unpack) jsContext+    debugLog "put state"+    putMVar state $ Just TestState {..}+    return x++listWindowProperties :: IO ()+listWindowProperties = testJSaddle $ T.pack . show <$> do+  window <- jsg "window"+  names <- propertyNames window+  forM names $ \name -> do+        v <- window ^. js name >>= valToText+        n <- strToText name+        return (n, v)+    `catch`+        \(JSException e) -> do+            n <- strToText name+            msg <- valToText e+            return (n, T.pack " error " <> msg)+++++++++
src/Language/Javascript/JSaddle/Types.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE CPP, FlexibleInstances #-}+{-# LANGUAGE CPP                   #-}+{-# LANGUAGE FlexibleInstances     #-} ----------------------------------------------------------------------------- -- -- Module      :  Language.Javascript.JSaddle.Properties@@ -12,42 +13,57 @@ -----------------------------------------------------------------------------  module Language.Javascript.JSaddle.Types (-    JSValueRef(..)-  , JSValueRefRef(..)-  , JSObjectRef(..)-  , JSPropertyNameArrayRef(..)-  , JSPropertyAttributes(..)-  , JSContextRef(..)-  , JSStringRef(..)-  , Index(..)+    JSVal+  , MutableJSArray+  , Object(..)+  , JSPropertyNameArray+  , JSPropertyAttributes+  , JSContextRef+  , JSString+  , Index+  , Nullable(..)+  , JSM ) where -#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)+import Control.Monad.Trans.Reader (ReaderT(..))+#ifdef ghcjs_HOST_OS import GHCJS.Types+import JavaScript.Object.Internal (Object(..))+import JavaScript.Array (MutableJSArray) import Data.Word (Word(..))+import GHCJS.Nullable (Nullable(..)) #else+import Foreign.ForeignPtr (ForeignPtr) import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase-       (JSValueRef, JSValueRefRef, JSObjectRef, JSStringRef,-        JSContextRef, JSPropertyNameArrayRef)+       (OpaqueJSString, JSValueRefRef,+        JSContextRef, JSPropertyNameArrayRef, OpaqueJSValue) import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSObjectRef (JSPropertyAttributes) import Foreign.C (CUInt(..)) #endif -#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-data ValueOrObject-data Object-data PropertyNameArray-type JSValueRef    = JSRef ValueOrObject-type JSValueRefRef = JSArray ValueOrObject-type JSObjectRef   = JSRef ValueOrObject-type JSPropertyNameArrayRef = JSRef PropertyNameArray+#ifdef ghcjs_HOST_OS+newtype JSPropertyNameArray = JSPropertyNameArray { unJSPropertyNameArrayRef :: JSVal } type JSPropertyAttributes = Word type JSContextRef  = ()-type JSStringRef   = JSString type Index         = Int--instance Show (JSRef ValueOrObject)-instance Eq (JSRef ValueOrObject) #else+type JSVal = ForeignPtr OpaqueJSValue+type MutableJSArray = JSValueRefRef+type JSPropertyNameArray = JSPropertyNameArrayRef type Index = CUInt+newtype Object = Object (ForeignPtr OpaqueJSValue)+type JSString = ForeignPtr OpaqueJSString+newtype Nullable a = Nullable a #endif++-- | The @JSM@ monad keeps track of the JavaScript context.+--+-- Given a @JSM@ function and a 'JSContextRef' you can run the+-- function like this...+--+-- > runReaderT jsmFunction javaScriptContext+--+-- For an example of how to set up WebKitGTK+ see tests/TestJSaddle.hs+type JSM = ReaderT JSContextRef IO++
src/Language/Javascript/JSaddle/Value.hs view
@@ -2,9 +2,11 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeSynonymInstances #-}-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)+{-# LANGUAGE LambdaCase #-}+#ifdef ghcjs_HOST_OS {-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI #-} #endif+{-# OPTIONS_GHC -fno-warn-orphans #-} ----------------------------------------------------------------------------- -- -- Module      :  Language.Javascript.JSaddle.Value@@ -31,16 +33,15 @@  module Language.Javascript.JSaddle.Value (   -- * JavaScript value references-    JSValueRef-  , MakeValueRef(..)+    JSVal+  , ToJSVal(..)    -- * Haskell types for JavaScript values   , JSNull(..)-  , JSUndefined(..)-  , JSBool(..)-  , JSNumber(..)-  , JSString(..)+  , JSUndefined+  , JSString   , JSValue(..)+  , showJSValue    -- * Converting JavaScript values   , valToBool@@ -53,68 +54,92 @@   -- * Make JavaScript values from Haskell ones   , val   , valMakeNull+  , valIsNull   , valMakeUndefined+  , valIsUndefined+  , maybeNullOrUndefined+  , maybeNullOrUndefined'   , valMakeBool   , valMakeNumber   , valMakeString -  -- * Conver to and from JSValue+  -- * Convert to and from JSValue   , deRefVal   , valMakeRef+  , strictEqual+  , instanceOf ) where +import Control.Applicative import Prelude hiding (catch) import Language.Javascript.JSaddle.Types-       (JSValueRefRef, JSObjectRef, JSStringRef, JSValueRef)-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-import GHCJS.Types (castRef, JSRef(..))-import GHCJS.Foreign (toJSBool, fromJSBool', jsNull, jsUndefined, toJSString)-import GHCJS.Marshal (toJSRef)+       (Object(..), JSString, JSVal)+#ifdef ghcjs_HOST_OS+import Language.Javascript.JSaddle.Types+       (MutableJSArray)+import GHCJS.Types (JSVal(..), isNull, isUndefined)+import GHCJS.Foreign (toJSBool, isTruthy, jsNull, jsUndefined)+import qualified GHCJS.Marshal as GHCJS (toJSVal)+import GHCJS.Marshal.Pure (pToJSVal)+import Data.JSString.Text (textToJSString) #else import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef-       (jsvaluecreatejsonstring, JSType(..), jsvaluegettype,-        jsvaluemakestring, jsvaluemakenumber, jsvaluemakeboolean,-        jsvaluemakeundefined, jsvaluemakenull, jsvaluetoobject,-        jsvaluetostringcopy, jsvaluetonumber, jsvaluetoboolean)-import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef-       (jsstringgetcharactersptr, jsstringgetlength)+       (jsvalueisinstanceofconstructor, jsvaluecreatejsonstring,+        JSType(..), jsvaluegettype, jsvaluemakestring, jsvaluemakenumber,+        jsvaluemakeboolean, jsvaluemakeundefined, jsvaluemakenull,+        jsvaluetoobject, jsvaluetostringcopy, jsvaluetonumber,+        jsvaluetoboolean, jsvalueisnull, jsvalueisundefined,+        jsvalueisstrictequal)+import Language.Javascript.JSaddle.Native+       (makeNewJSVal, wrapJSString, withJSVal, withObject, withJSString,+        withToJSVal) #endif-import Language.Javascript.JSaddle.Monad (JSM, catchval)+import Language.Javascript.JSaddle.Monad (JSM) import Language.Javascript.JSaddle.Exception (rethrow) import Control.Monad.Trans.Reader (ask)-import Control.Monad.IO.Class (MonadIO, MonadIO(..))-import qualified Data.Text.Foreign as T (fromPtr)-import Foreign (castPtr)-import Data.Text.Foreign (useAsPtr)-import Control.Applicative ((<$>))+import Control.Monad.IO.Class (MonadIO(..)) import Data.Text (Text) import qualified Data.Text as T (pack) import Language.Javascript.JSaddle.Classes-       (MakeObjectRef(..), MakeStringRef(..), MakeValueRef(..),-        MakeArgRefs(..))+       (MakeObject(..), ToJSString(..), ToJSVal(..)) import Language.Javascript.JSaddle.String (strToText, textToStr)-import Language.Javascript.JSaddle.Arguments ()-import Data.Word (Word)+import Language.Javascript.JSaddle.Arguments (MakeArgs(..))+import Data.Word (Word32, Word, Word64)+import Data.Int (Int32, Int64) +-- $setup+-- >>> import Language.Javascript.JSaddle.Test (testJSaddle)+-- >>> import Language.Javascript.JSaddle.Monad (catch)+-- >>> import Language.Javascript.JSaddle.Exception (JSException(..))+ data JSNull      = JSNull -- ^ Type that represents a value that can only be null.                           --   Haskell of course has no null so we are adding this type. type JSUndefined = ()     -- ^ A type that can only be undefined in JavaScript.  Using ()                           --   because functions in JavaScript that have no return, impicitly                           --   return undefined.-type JSBool      = Bool   -- ^ JavaScript boolean values map the 'Bool' haskell type.-type JSNumber    = Double -- ^ A number in JavaScript maps nicely to 'Double'.-type JSString    = Text   -- ^ JavaScript strings can be represented with the Haskell 'Text' type.+-- type JSBool      = Bool   -- ^ JavaScript boolean values map the 'Bool' haskell type.+-- type JSNumber    = Double -- ^ A number in JavaScript maps nicely to 'Double'.+-- type JSString    = Text   -- ^ JavaScript strings can be represented with the Haskell 'Text' type.  -- | An algebraic data type that can represent a JavaScript value.  Any JavaScriptCore---   'JSValueRef' can be converted into this type.+--   'JSVal' can be converted into this type. data JSValue = ValNull                   -- ^ null              | ValUndefined              -- ^ undefined-             | ValBool      JSBool       -- ^ true or false-             | ValNumber    JSNumber     -- ^ a number-             | ValString    JSString     -- ^ a string-             | ValObject    JSObjectRef  -- ^ an object-             deriving(Show, Eq)+             | ValBool      Bool         -- ^ true or false+             | ValNumber    Double       -- ^ a number+             | ValString    Text         -- ^ a string+             | ValObject    Object       -- ^ an object +-- | Show a JSValue but just say "object" if the value is a JavaScript object.+showJSValue :: JSValue -> String+showJSValue ValNull         = "null"+showJSValue ValUndefined    = "undefined"+showJSValue (ValBool True)  = "true"+showJSValue (ValBool False) = "false"+showJSValue (ValNumber x)   = show x+showJSValue (ValString s)   = show s+showJSValue (ValObject _)   = "object"+ -- | Given a JavaScript value get its boolean value. --   All values in JavaScript convert to bool. --@@ -134,15 +159,16 @@ -- false -- >>> testJSaddle $ valToBool "1" -- true-valToBool :: MakeValueRef val => val -> JSM JSBool-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-valToBool val = fromJSBool' <$> makeValueRef val+valToBool :: ToJSVal value => value -> JSM Bool+#ifdef ghcjs_HOST_OS+valToBool value = isTruthy <$> toJSVal value #else-valToBool val = do+valToBool value = do     gctxt <- ask-    rval <- makeValueRef val-    liftIO $ jsvaluetoboolean gctxt rval+    withToJSVal value $ \rval ->+        liftIO $ jsvaluetoboolean gctxt rval #endif+{-# INLINE valToBool #-}  -- | Given a JavaScript value get its numeric value. --   May throw JSException.@@ -163,17 +189,17 @@ -- 0.0 -- >>> testJSaddle $ show <$> valToNumber "1" -- 1.0-valToNumber :: MakeValueRef val => val -> JSM JSNumber-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)-valToNumber val = jsrefToNumber <$> makeValueRef val-foreign import javascript unsafe "$r = Number($1);" jsrefToNumber :: JSRef a -> Double-#elif defined(USE_WEBKIT)-valToNumber val = do-    gctxt <- ask-    rval <- makeValueRef val-    rethrow $ liftIO . jsvaluetonumber gctxt rval+valToNumber :: ToJSVal value => value -> JSM Double+#ifdef ghcjs_HOST_OS+valToNumber value = jsrefToNumber <$> toJSVal value+{-# INLINE valToNumber #-}+foreign import javascript unsafe "$r = Number($1);" jsrefToNumber :: JSVal -> Double #else-valToNumber = undefined+valToNumber value = do+    gctxt <- ask+    withToJSVal value $ \rval ->+        rethrow $ liftIO . jsvaluetonumber gctxt rval+{-# INLINE valToNumber #-} #endif  -- | Given a JavaScript value get its string value (as a JavaScript string).@@ -195,17 +221,17 @@ -- -- >>> testJSaddle $ valToStr "1" >>= strToText -- 1-valToStr :: MakeValueRef val => val -> JSM JSStringRef-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)-valToStr val = jsrefToString <$> makeValueRef val-foreign import javascript unsafe "$r = $1.toString();" jsrefToString :: JSRef a -> JSStringRef-#elif defined(USE_WEBKIT)-valToStr val = do-    gctxt <- ask-    rval <- makeValueRef val-    rethrow $ liftIO . jsvaluetostringcopy gctxt rval+valToStr :: ToJSVal value => value -> JSM JSString+#ifdef ghcjs_HOST_OS+valToStr value = jsrefToString <$> toJSVal value+{-# INLINE valToStr #-}+foreign import javascript unsafe "$r = $1.toString();" jsrefToString :: JSVal -> JSString #else-valToStr = undefined+valToStr value = do+    gctxt <- ask+    withToJSVal value $ \rval ->+        rethrow (liftIO . jsvaluetostringcopy gctxt rval) >>= wrapJSString+{-# INLINE valToStr #-} #endif  -- | Given a JavaScript value get its string value (as a Haskell 'Text').@@ -227,8 +253,9 @@ -- "" -- >>> testJSaddle $ show <$> valToText "1" -- "1"-valToText :: MakeValueRef val => val -> JSM Text+valToText :: ToJSVal value => value -> JSM Text valToText jsvar = valToStr jsvar >>= strToText+{-# INLINE valToText #-}  -- | Given a JavaScript value get a JSON string value. --   May throw JSException.@@ -251,17 +278,17 @@ -- "1" -- >>> testJSaddle $ obj >>= valToJSON 0 >>= strToText -- {}-valToJSON :: MakeValueRef val => Word -> val -> JSM JSStringRef-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)-valToJSON indent val = jsrefToJSON <$> makeValueRef val-foreign import javascript unsafe "$r = JSON.stringify($1);" jsrefToJSON :: JSRef a -> JSStringRef-#elif defined(USE_WEBKIT)-valToJSON indent val = do-    gctxt <- ask-    rval <- makeValueRef val-    rethrow $ liftIO . jsvaluecreatejsonstring gctxt rval (fromIntegral indent)+valToJSON :: ToJSVal value => Word -> value -> JSM JSString+#ifdef ghcjs_HOST_OS+valToJSON indent value = jsrefToJSON <$> toJSVal value+{-# INLINE valToJSON #-}+foreign import javascript unsafe "$r = JSON.stringify($1);" jsrefToJSON :: JSVal -> JSString #else-valToJSON = undefined+valToJSON indent value = do+    gctxt <- ask+    withToJSVal value $ \rval ->+        rethrow (liftIO . jsvaluecreatejsonstring gctxt rval (fromIntegral indent)) >>= wrapJSString+{-# INLINE valToJSON #-} #endif  -- | Given a JavaScript value get its object value.@@ -283,187 +310,320 @@ -- -- >>> testJSaddle $ valToObject "1" -- 1-valToObject :: MakeValueRef val => val -> JSM JSObjectRef-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-valToObject val = castRef <$> makeValueRef val+valToObject :: ToJSVal value => value -> JSM Object+valToObject value = Object <$>+#ifdef ghcjs_HOST_OS+    toJSVal value #else-valToObject val = do-    gctxt <- ask-    rval <- makeValueRef val-    rethrow $ liftIO . jsvaluetoobject gctxt rval+ do gctxt <- ask+    withToJSVal value $ \rval ->+        rethrow (liftIO . jsvaluetoobject gctxt rval) >>= makeNewJSVal #endif+{-# INLINE valToObject #-} --- | Convert to a JavaScript value (just an alias for 'makeValueRef')-val :: MakeValueRef value+instance MakeObject JSVal where+    makeObject = valToObject+    {-# INLINE makeObject #-}++-- | Convert to a JavaScript value (just an alias for 'toJSVal')+val :: ToJSVal value     => value          -- ^ value to convert to a JavaScript value-    -> JSM JSValueRef-val = makeValueRef+    -> JSM JSVal+val = toJSVal+{-# INLINE val #-} --- | If we already have a JSValueRef we are fine-instance MakeValueRef JSValueRef where-    makeValueRef = return+-- | If we already have a JSVal we are fine+instance ToJSVal JSVal where+    toJSVal = return+    {-# INLINE toJSVal #-} --- | A single JSValueRef can be used as the argument list-instance MakeArgRefs JSValueRef where-    makeArgRefs arg = return [arg]+-- | A single JSVal can be used as the argument list+instance MakeArgs JSVal where+    makeArgs arg = return [arg]+    {-# INLINE makeArgs #-} --- | JSValueRef can be made by evaluating a function in 'JSM' as long---   as it returns something we can make into a JSValueRef.-instance MakeValueRef v => MakeValueRef (JSM v) where-    makeValueRef v = v >>= makeValueRef+-- | JSVal can be made by evaluating a function in 'JSM' as long+--   as it returns something we can make into a JSVal.+instance ToJSVal v => ToJSVal (JSM v) where+    toJSVal v = v >>= toJSVal+    {-# INLINE toJSVal #-}  ----------- null --------------- -- | Make a @null@ JavaScript value-valMakeNull :: JSM JSValueRef-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)+valMakeNull :: JSM JSVal+#ifdef ghcjs_HOST_OS valMakeNull = return jsNull #else-valMakeNull = ask >>= (liftIO . jsvaluemakenull)+valMakeNull = ask >>= (liftIO . jsvaluemakenull) >>= makeNewJSVal #endif+{-# INLINE valMakeNull #-}  -- | Makes a @null@ JavaScript value-instance MakeValueRef JSNull where-    makeValueRef = const valMakeNull+instance ToJSVal JSNull where+    toJSVal = const valMakeNull+    {-# INLINE toJSVal #-}  -- | Makes an argument list with just a single @null@ JavaScript value-instance MakeArgRefs JSNull where-    makeArgRefs _ = valMakeNull >>= (\ref -> return [ref])+instance MakeArgs JSNull where+    makeArgs _ = valMakeNull >>= (\ref -> return [ref])+    {-# INLINE makeArgs #-} +-- | Makes a JSVal or @null@ JavaScript value+instance ToJSVal a => ToJSVal (Maybe a) where+    toJSVal Nothing = valMakeNull+    toJSVal (Just a) = toJSVal a+    {-# INLINE toJSVal #-}++-- | Test a JavaScript value to see if it is @null@+valIsNull :: ToJSVal value => value -> JSM Bool+#ifdef ghcjs_HOST_OS+valIsNull value = isNull <$> toJSVal value+#else+valIsNull value = do+    gctxt <- ask+    withToJSVal value $ \rval ->+        liftIO $ jsvalueisnull gctxt rval+#endif+{-# INLINE valIsNull #-}+ ----------- undefined --------------- -- | Make an @undefined@ JavaScript value-valMakeUndefined :: JSM JSValueRef-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)+valMakeUndefined :: JSM JSVal+#ifdef ghcjs_HOST_OS valMakeUndefined = return jsUndefined #else-valMakeUndefined = ask >>= (liftIO . jsvaluemakeundefined)+valMakeUndefined = ask >>= (liftIO . jsvaluemakeundefined) >>= makeNewJSVal #endif+{-# INLINE valMakeUndefined #-}  -- | Makes an @undefined@ JavaScript value-instance MakeValueRef JSUndefined where-    makeValueRef = const valMakeUndefined+instance ToJSVal JSUndefined where+    toJSVal = const valMakeUndefined+    {-# INLINE toJSVal #-}  --We can't allow this if JSUndefined is () as () is no args not "(null)". --Use [()] instead.---instance MakeArgRefs JSUndefined where---    makeArgRefs _ = valMakeUndefined >>= (\ref -> return [ref])+--instance MakeArgs JSUndefined where+--    makeArgs _ = valMakeUndefined >>= (\ref -> return [ref]) --- | This allows us to pass no arguments easily (altenative would be to use @[]::[JSValueRef]@).-instance MakeArgRefs () where-    makeArgRefs _ = return []+-- | This allows us to pass no arguments easily (altenative would be to use @[]::[JSVal]@).+instance MakeArgs () where+    makeArgs _ = return []+    {-# INLINE makeArgs #-} +-- | Test a JavaScript value to see if it is @undefined@+valIsUndefined :: ToJSVal value => value -> JSM Bool+#ifdef ghcjs_HOST_OS+valIsUndefined value = isUndefined <$> toJSVal value+#else+valIsUndefined value = do+    gctxt <- ask+    withToJSVal value $ \rval ->+        liftIO $ jsvalueisundefined gctxt rval+#endif+{-# INLINE valIsUndefined #-}++-- | Convert a JSVal to a Maybe JSVal (converting null and undefined to Nothing)+maybeNullOrUndefined :: ToJSVal value => value -> JSM (Maybe JSVal)+maybeNullOrUndefined value = do+    rval <- toJSVal value+    valIsNull rval >>= \case+        True -> return Nothing+        _    ->+            valIsUndefined rval >>= \case+                True -> return Nothing+                _    -> return (Just rval)+{-# INLINE maybeNullOrUndefined #-}++maybeNullOrUndefined' :: ToJSVal value => (JSVal -> JSM a) -> value -> JSM (Maybe a)+maybeNullOrUndefined' f value = do+    rval <- toJSVal value+    valIsNull rval >>= \case+        True -> return Nothing+        _    ->+            valIsUndefined rval >>= \case+                True -> return Nothing+                _    -> Just <$> f rval+{-# INLINE maybeNullOrUndefined' #-}+ ----------- booleans --------------- -- | Make a JavaScript boolean value-valMakeBool :: JSBool -> JSM JSValueRef-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-valMakeBool b = return . castRef $ toJSBool b+valMakeBool :: Bool -> JSM JSVal+#ifdef ghcjs_HOST_OS+valMakeBool b = return  $ toJSBool b #else valMakeBool b = do     gctxt <- ask-    liftIO $ jsvaluemakeboolean gctxt b+    liftIO (jsvaluemakeboolean gctxt b) >>= makeNewJSVal #endif+{-# INLINE valMakeBool #-}  -- | Make a JavaScript boolean value-instance MakeValueRef Bool where-    makeValueRef = valMakeBool+instance ToJSVal Bool where+    toJSVal = valMakeBool+    {-# INLINE toJSVal #-}  -- | Makes an argument list with just a single JavaScript boolean value-instance MakeArgRefs Bool where-    makeArgRefs b = valMakeBool b >>= (\ref -> return [ref])+instance MakeArgs Bool where+    makeArgs b = valMakeBool b >>= (\ref -> return [ref])+    {-# INLINE makeArgs #-}  ----------- numbers --------------- -- | Make a JavaScript number-valMakeNumber :: JSNumber -> JSM JSValueRef-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-valMakeNumber n = liftIO $ castRef <$> toJSRef n+valMakeNumber :: Double -> JSM JSVal+#ifdef ghcjs_HOST_OS+valMakeNumber n = liftIO $ GHCJS.toJSVal n #else valMakeNumber n = do     gctxt <- ask-    liftIO $ jsvaluemakenumber gctxt n+    liftIO (jsvaluemakenumber gctxt n) >>= makeNewJSVal #endif+{-# INLINE valMakeNumber #-}  -- | Makes a JavaScript number-instance MakeValueRef Double where-    makeValueRef = valMakeNumber+instance ToJSVal Double where+    toJSVal = valMakeNumber+    {-# INLINE toJSVal #-} +instance ToJSVal Float where+    toJSVal = valMakeNumber . realToFrac+    {-# INLINE toJSVal #-}++instance ToJSVal Word where+    toJSVal = valMakeNumber . fromIntegral+    {-# INLINE toJSVal #-}++instance ToJSVal Word32 where+    toJSVal = valMakeNumber . fromIntegral+    {-# INLINE toJSVal #-}++instance ToJSVal Word64 where+    toJSVal = valMakeNumber . fromIntegral+    {-# INLINE toJSVal #-}++instance ToJSVal Int where+    toJSVal = valMakeNumber . fromIntegral+    {-# INLINE toJSVal #-}++instance ToJSVal Int32 where+    toJSVal = valMakeNumber . fromIntegral+    {-# INLINE toJSVal #-}++instance ToJSVal Int64 where+    toJSVal = valMakeNumber . fromIntegral+    {-# INLINE toJSVal #-}+ -- | Makes an argument list with just a single JavaScript number-instance MakeArgRefs Double where-    makeArgRefs n = valMakeNumber n >>= (\ref -> return [ref])+instance MakeArgs Double where+    makeArgs n = valMakeNumber n >>= (\ref -> return [ref])+    {-# INLINE makeArgs #-} ------------ numbers ------------------ | Make a JavaScript string-valMakeString :: Text -> JSM JSValueRef-#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)-valMakeString = return . castRef . toJSString+-- | Make a JavaScript string from `Text`+valMakeText :: Text -> JSM JSVal+#ifdef ghcjs_HOST_OS+valMakeText = return . pToJSVal . textToJSString #else-valMakeString text = do+valMakeText text = do     gctxt <- ask-    liftIO $ jsvaluemakestring gctxt (textToStr text)+    withJSString (textToStr text) $ \s ->+        liftIO (jsvaluemakestring gctxt s) >>= makeNewJSVal #endif+{-# INLINE valMakeText #-} +-- | Make a JavaScript string from `JSString`+valMakeString :: JSString -> JSM JSVal+#ifdef ghcjs_HOST_OS+valMakeString = return . pToJSVal+#else+valMakeString str = do+    gctxt <- ask+    withJSString str $ \s ->+        liftIO (jsvaluemakestring gctxt s) >>= makeNewJSVal+#endif+{-# INLINE valMakeString #-}+ -- | Makes a JavaScript string-instance MakeValueRef Text where-    makeValueRef = valMakeString+instance ToJSVal Text where+    toJSVal = valMakeText+    {-# INLINE toJSVal #-}  -- | Makes an argument list with just a single JavaScript string-instance MakeArgRefs Text where-    makeArgRefs t = valMakeString t >>= (\ref -> return [ref])+instance MakeArgs Text where+    makeArgs t = valMakeText t >>= (\ref -> return [ref])+    {-# INLINE makeArgs #-}  -- | Makes a JavaScript string-instance MakeValueRef String where-    makeValueRef = valMakeString . T.pack+instance ToJSVal String where+    toJSVal = valMakeText . T.pack+    {-# INLINE toJSVal #-} +-- | Makes a JavaScript string+instance ToJSVal JSString where+    toJSVal = valMakeString+    {-# INLINE toJSVal #-}++-- | If we already have a JSString we are fine+instance ToJSString JSString where+    toJSString = id+    {-# INLINE toJSString #-}++instance ToJSString Text where+    toJSString = textToStr+    {-# INLINE toJSString #-}++instance ToJSString String where+    toJSString = textToStr . T.pack+    {-# INLINE toJSString #-}+ -- | Derefernce a value reference. ----- >>> testJSaddle $ show <$> deRefVal JSNull+-- >>> testJSaddle $ showJSValue <$> deRefVal JSNull -- ValNull--- >>> testJSaddle $ show <$> deRefVal ()+-- >>> testJSaddle $ showJSValue <$> deRefVal () -- ValUndefined--- >>> testJSaddle $ show <$> deRefVal True+-- >>> testJSaddle $ showJSValue <$> deRefVal True -- ValBool True--- >>> testJSaddle $ show <$> deRefVal False+-- >>> testJSaddle $ showJSValue <$> deRefVal False -- ValBool False--- >>> testJSaddle $ show <$> deRefVal (1.0 :: Double)+-- >>> testJSaddle $ showJSValue <$> deRefVal (1.0 :: Double) -- ValNumber 1.0--- >>> testJSaddle $ show <$> deRefVal (0.0 :: Double)+-- >>> testJSaddle $ showJSValue <$> deRefVal (0.0 :: Double) -- ValNumber 0.0--- >>> testJSaddle $ show <$> deRefVal ""+-- >>> testJSaddle $ showJSValue <$> deRefVal "" -- ValString ""--- >>> testJSaddle $ show <$> deRefVal "1"+-- >>> testJSaddle $ showJSValue <$> deRefVal "1" -- ValString "1"--- >>> testJSaddle $ show <$> valToObject True >>= deRefVal+-- >>> testJSaddle $ showJSValue <$> valToObject True >>= deRefVal -- ValObject 0x...-deRefVal :: MakeValueRef val => val -> JSM JSValue-#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)-deRefVal val = do-    gctxt <- ask-    valref <- makeValueRef val+deRefVal :: ToJSVal value => value -> JSM JSValue+#ifdef ghcjs_HOST_OS+deRefVal value = do+    valref <- toJSVal value     case (jsrefGetType valref :: Int) of         0 -> return ValUndefined         1 -> return ValNull         2 -> ValBool   <$> valToBool valref         3 -> ValNumber <$> valToNumber valref-        4 -> ValString <$> (valToStr valref >>= strToText)+        4 -> ValString <$> valToText valref         5 -> ValObject <$> valToObject valref foreign import javascript unsafe "$r = ($1 === undefined)?0:\                                        ($1===null)?1:\                                        (typeof $1===\"boolean\")?2:\                                        (typeof $1===\"number\")?3:\                                        (typeof $1===\"string\")?4:\-                                       (typeof $1===\"object\")?5:-1;" jsrefGetType :: JSValueRef -> Int-#elif defined(USE_WEBKIT)-deRefVal val = do-    gctxt <- ask-    valref <- makeValueRef val-    t <- liftIO $ jsvaluegettype gctxt valref-    case t of-        Kjstypenull      -> return ValNull-        Kjstypeundefined -> return ValUndefined-        Kjstypeboolean   -> ValBool   <$> valToBool valref-        Kjstypenumber    -> ValNumber <$> valToNumber valref-        Kjstypestring    -> ValString <$> (valToStr valref >>= strToText)-        Kjstypeobject    -> ValObject <$> valToObject valref+                                       (typeof $1===\"object\")?5:-1;" jsrefGetType :: JSVal -> Int #else-deRefVal = undefined+deRefVal value = do+    gctxt <- ask+    v <- toJSVal value+    withJSVal v $ \rval ->+        liftIO (jsvaluegettype gctxt rval) >>= \case+            Kjstypenull      -> return ValNull+            Kjstypeundefined -> return ValUndefined+            Kjstypeboolean   -> ValBool   <$> valToBool v+            Kjstypenumber    -> ValNumber <$> valToNumber v+            Kjstypestring    -> ValString <$> valToText v+            Kjstypeobject    -> ValObject <$> valToObject v #endif  -- | Make a JavaScript value out of a 'JSValue' ADT.@@ -478,24 +638,80 @@ -- "1" -- >>> testJSaddle $ valMakeRef (ValString $ pack "Hello") -- "Hello"-valMakeRef :: JSValue -> JSM JSValueRef-valMakeRef val =-    case val of-        ValNull      -> valMakeNull-        ValUndefined -> valMakeUndefined-        ValBool b    -> valMakeBool b-        ValNumber n  -> valMakeNumber n-        ValString s  -> valMakeString s-        ValObject o  -> return o+valMakeRef :: JSValue -> JSM JSVal+valMakeRef value =+    case value of+        ValNull              -> valMakeNull+        ValUndefined         -> valMakeUndefined+        ValBool b            -> valMakeBool b+        ValNumber n          -> valMakeNumber n+        ValString s          -> valMakeText s+        ValObject (Object o) -> return o  -- | Makes a JavaScript value from a 'JSValue' ADT.-instance MakeValueRef JSValue where-    makeValueRef = valMakeRef+instance ToJSVal JSValue where+    toJSVal = valMakeRef+    {-# INLINE toJSVal #-}  -- | Makes an argument list with just a single JavaScript value from a 'JSValue' ADT.-instance MakeArgRefs JSValue where-    makeArgRefs v = valMakeRef v >>= (\ref -> return [ref])+instance MakeArgs JSValue where+    makeArgs v = valMakeRef v >>= (\ref -> return [ref])+    {-# INLINE makeArgs #-} -instance MakeObjectRef JSNull where-    makeObjectRef = const valMakeNull+--instance MakeObjectRef JSNull where+--    makeObjectRef _ = Object <$> valMakeNull+--    {-# INLINE makeObjectRef #-}++#ifdef ghcjs_HOST_OS+foreign import javascript unsafe+  "$1===$2" jsvalueisstrictequal :: JSVal -> JSVal -> Bool+#endif++strictEqual :: (ToJSVal a, ToJSVal b) => a -> b -> JSM Bool+strictEqual a b = do+    aval <- toJSVal a+    bval <- toJSVal b+#ifdef ghcjs_HOST_OS+    return $ jsvalueisstrictequal aval bval+#else+    gctxt <- ask+    withJSVal aval $ \aref ->+        withJSVal bval $ \bref ->+            liftIO $ jsvalueisstrictequal gctxt aref bref+#endif++#ifdef ghcjs_HOST_OS+foreign import javascript unsafe "\+    try {\+        $r = $1 instanceof $2\+    }\+    catch(e) {\+        $3[0] = e;\+    }"+  js_isInstanceOf :: JSVal -> Object -> MutableJSArray -> Bool+#endif++instanceOf :: (ToJSVal value, MakeObject constructor) => value -> constructor -> JSM Bool+instanceOf value constructor = do+    v <- toJSVal value+    c <- makeObject constructor+#ifdef ghcjs_HOST_OS+    rethrow $ return . js_isInstanceOf v c+#else+    gctxt <- ask+    withJSVal v $ \rval ->+        withObject c $ \c' ->+            rethrow $ liftIO . jsvalueisinstanceofconstructor gctxt rval c'+#endif+++++++++++ 
+ tests/DocTest.hs view
@@ -0,0 +1,21 @@+module Main (+    main+) where++import Test.DocTest++main :: IO ()+main = doctest ["-isrc",+    "src/Language/Javascript/JSaddle/Arguments.hs",+    "src/Language/Javascript/JSaddle/Classes.hs",+    "src/Language/Javascript/JSaddle/Evaluate.hs",+    "src/Language/Javascript/JSaddle/Exception.hs",+    "src/Language/Javascript/JSaddle/Monad.hs",+    "src/Language/Javascript/JSaddle/Native.hs",+    "src/Language/Javascript/JSaddle/Object.hs",+    "src/Language/Javascript/JSaddle/Properties.hs",+    "src/Language/Javascript/JSaddle/String.hs",+    "src/Language/Javascript/JSaddle/Test.hs",+    "src/Language/Javascript/JSaddle/Types.hs",+    "src/Language/Javascript/JSaddle/Value.hs" ]+
− tests/TestJSaddle.hs
@@ -1,141 +0,0 @@-{-# LANGUAGE RecordWildCards #-}------------------------------------------------------------------------------------ Module      :  TestJSC--- Copyright   :  (c) Hamish Mackenzie--- License     :  MIT------ Maintainer  :  Hamish Mackenzie <Hamish.K.Mackenzie@googlemail.com>------ |-----------------------------------------------------------------------------------module Main (-    main-) where--import Prelude hiding((!!), catch)-import Graphics.UI.Gtk-       (Window, widgetDestroy, postGUIAsync, postGUISync, widgetShowAll,-        mainGUI, mainQuit, on, objectDestroy, containerAdd, scrolledWindowNew,-        windowSetPosition, windowSetDefaultSize, timeoutAddFull, windowNew,-        initGUI)-import Control.Concurrent-       (tryTakeMVar, forkIO, newMVar, putMVar, takeMVar, newEmptyMVar,-        yield)-import System.Glib.MainLoop (priorityLow)-import Graphics.UI.Gtk.General.Enums (WindowPosition(..))-import Graphics.UI.Gtk.WebKit.WebView-       (webViewGetMainFrame, webViewNew)-import System.IO.Unsafe (unsafePerformIO)-import Control.Monad.Trans.Reader (runReaderT)-import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase (JSContextRef)-import Graphics.UI.Gtk.WebKit.JavaScriptCore.WebFrame-       (webFrameGetGlobalContext)-import Language.Javascript.JSaddle-import Data.Text (Text)-import qualified Data.Text as T-import Control.Applicative-import Control.Monad.IO.Class (MonadIO(..))-import Control.Monad (forM, when)-import System.Log.Logger (debugM)-import Control.Lens.Getter ((^.))-import Data.Monoid ((<>))--data TestState = TestState { jsContext :: JSContextRef, window :: Window }--state = unsafePerformIO $ newMVar Nothing-done = unsafePerformIO $ newEmptyMVar---- >>> testJSaddle $ ((global ^. js "console" . js "log") # ["Hello"])-testJSaddle :: MakeValueRef val => JSM val -> IO ()-testJSaddle = testJSaddle' False---- >>> showJSaddle $ eval "document.body.innerHTML = 'Test'"-showJSaddle :: MakeValueRef val => JSM val -> IO ()-showJSaddle = testJSaddle' True--debugLog = debugM "jsaddle"--testJSaddle' :: MakeValueRef val => Bool -> JSM val -> IO ()-testJSaddle' showWindow f = do-    debugLog "taking done"-    tryTakeMVar done-    debugLog "taking state"-    mbState <- takeMVar state-    TestState {..} <- case mbState of-        Nothing -> do-            debugLog "newState"-            newState <- newEmptyMVar-            debugLog "fork"-            forkIO $ do-                debugLog "initGUI"-                initGUI-                debugLog "windowNew"-                window <- windowNew-                debugLog "timeoutAdd"-                timeoutAddFull (yield >> return True) priorityLow 10-                windowSetDefaultSize window 900 600-                windowSetPosition window WinPosCenter-                scrollWin <- scrolledWindowNew Nothing Nothing-                webView <- webViewNew-                window `containerAdd` scrollWin-                scrollWin `containerAdd` webView-                on window objectDestroy $ do-                    debugLog "onDestroy"-                    tryTakeMVar state-                    debugLog "put state"-                    putMVar state Nothing-                    debugLog "mainQuit"-                    mainQuit-                    debugLog "put done"-                    putMVar done ()-                    return True-                debugLog "get context"-                jsContext <- webViewGetMainFrame webView >>= webFrameGetGlobalContext-                debugLog "put initial state"-                putMVar newState TestState {..}-                debugLog "maybe show"-                when showWindow $ widgetShowAll window-                debugLog "mainGUI"-                mainGUI-                debugLog "mainGUI exited"-            takeMVar newState-        Just s@TestState {..} -> do-            debugLog "maybe show (2)"-            when showWindow . postGUISync $ widgetShowAll window-            return s-    x <- postGUISync $ runReaderT ((f >>= valToText >>= liftIO . putStrLn . T.unpack)-            `catch` \ (JSException e) -> valToText e >>= liftIO . putStrLn . T.unpack) jsContext-    debugLog "put state"-    putMVar state $ Just TestState {..}-    return x--main = do-    testJSaddle $ return ()-    Just TestState{..} <- takeMVar state-    postGUIAsync $ widgetDestroy window-    takeMVar done--listWindowProperties = testJSaddle $ T.pack . show <$> do-  window <- jsg "window"-  names <- propertyNames window-  forM names $ \name -> do-        v <- window ^. js name >>= valToText-        n <- strToText name-        return (n, v)-    `catch`-        \(JSException e) -> do-            n <- strToText name-            msg <- valToText e-            return (n, (T.pack $ " error ") <> msg)---------