@@ -3,7 +3,7 @@
3{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE TypeSynonymInstances #-}
4{-# LANGUAGE TypeSynonymInstances #-}
5{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE LambdaCase #-}
6−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
6+#ifdef ghcjs_HOST_OS
7{-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI #-}
7{-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI #-}
9{-# OPTIONS_GHC -fno-warn-orphans #-}
9{-# OPTIONS_GHC -fno-warn-orphans #-}
@@ -41,6 +41,7 @@ module Language.Javascript.JSaddle.Value (
41 , JSUndefined
41 , JSUndefined
42 , JSString
42 , JSString
43 , JSValue(..)
43 , JSValue(..)
45 -- * Converting JavaScript values
46 -- * Converting JavaScript values
46 , valToBool
47 , valToBool
@@ -69,10 +70,11 @@ module Language.Javascript.JSaddle.Value (
69 , instanceOf
70 , instanceOf
73+import Control.Applicative ((<$>))
72import Prelude hiding (catch)
74import Prelude hiding (catch)
73import Language.Javascript.JSaddle.Types
75import Language.Javascript.JSaddle.Types
74 (Object(..), JSString, JSVal)
76 (Object(..), JSString, JSVal)
75−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
77+#ifdef ghcjs_HOST_OS
76import Language.Javascript.JSaddle.Types
78import Language.Javascript.JSaddle.Types
77 (MutableJSArray)
79 (MutableJSArray)
78import GHCJS.Types (JSVal(..), isNull, isUndefined)
80import GHCJS.Types (JSVal(..), isNull, isUndefined)
@@ -102,9 +104,14 @@ import Language.Javascript.JSaddle.Classes
102 (MakeObject(..), ToJSString(..), ToJSVal(..))
104 (MakeObject(..), ToJSString(..), ToJSVal(..))
103import Language.Javascript.JSaddle.String (strToText, textToStr)
105import Language.Javascript.JSaddle.String (strToText, textToStr)
104import Language.Javascript.JSaddle.Arguments (MakeArgs(..))
106import Language.Javascript.JSaddle.Arguments (MakeArgs(..))
105−import Data.Word (Word32, Word64)
107+import Data.Word (Word32, Word, Word64)
106import Data.Int (Int32, Int64)
108import Data.Int (Int32, Int64)
111+-- >>> import Language.Javascript.JSaddle.Test (testJSaddle)
112+-- >>> import Language.Javascript.JSaddle.Monad (catch)
113+-- >>> import Language.Javascript.JSaddle.Exception (JSException(..))
108data JSNull = JSNull -- ^ Type that represents a value that can only be null.
115data JSNull = JSNull -- ^ Type that represents a value that can only be null.
109 -- Haskell of course has no null so we are adding this type.
116 -- Haskell of course has no null so we are adding this type.
110type JSUndefined = () -- ^ A type that can only be undefined in JavaScript. Using ()
117type JSUndefined = () -- ^ A type that can only be undefined in JavaScript. Using ()
@@ -122,7 +129,16 @@ data JSValue = ValNull -- ^ null
122 | ValNumber Double -- ^ a number
129 | ValNumber Double -- ^ a number
123 | ValString Text -- ^ a string
130 | ValString Text -- ^ a string
124 | ValObject Object -- ^ an object
131 | ValObject Object -- ^ an object
125−-- deriving(Show, Eq)
132+
133+-- | Show a JSValue but just say "object" if the value is a JavaScript object.
134+showJSValue :: JSValue -> String
135+showJSValue ValNull = "null"
136+showJSValue ValUndefined = "undefined"
137+showJSValue (ValBool True) = "true"
138+showJSValue (ValBool False) = "false"
139+showJSValue (ValNumber x) = show x
140+showJSValue (ValString s) = show s
141+showJSValue (ValObject _) = "object"
127-- | Given a JavaScript value get its boolean value.
143-- | Given a JavaScript value get its boolean value.
128-- All values in JavaScript convert to bool.
144-- All values in JavaScript convert to bool.
@@ -144,7 +160,7 @@ data JSValue = ValNull -- ^ null
144-- >>> testJSaddle $ valToBool "1"
160-- >>> testJSaddle $ valToBool "1"
146valToBool :: ToJSVal value => value -> JSM Bool
162valToBool :: ToJSVal value => value -> JSM Bool
147−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
163+#ifdef ghcjs_HOST_OS
148valToBool value = isTruthy <$> toJSVal value
164valToBool value = isTruthy <$> toJSVal value
150valToBool value = do
166valToBool value = do
@@ -174,18 +190,16 @@ valToBool value = do
174-- >>> testJSaddle $ show <$> valToNumber "1"
190-- >>> testJSaddle $ show <$> valToNumber "1"
176valToNumber :: ToJSVal value => value -> JSM Double
192valToNumber :: ToJSVal value => value -> JSM Double
177−#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)
193+#ifdef ghcjs_HOST_OS
178valToNumber value = jsrefToNumber <$> toJSVal value
194valToNumber value = jsrefToNumber <$> toJSVal value
179{-# INLINE valToNumber #-}
195{-# INLINE valToNumber #-}
180foreign import javascript unsafe "$r = Number($1);" jsrefToNumber :: JSVal -> Double
196foreign import javascript unsafe "$r = Number($1);" jsrefToNumber :: JSVal -> Double
181−#elif defined(USE_WEBKIT)
197+#else
182valToNumber value = do
198valToNumber value = do
183 gctxt <- ask
199 gctxt <- ask
184 withToJSVal value $ \rval ->
200 withToJSVal value $ \rval ->
185 rethrow $ liftIO . jsvaluetonumber gctxt rval
201 rethrow $ liftIO . jsvaluetonumber gctxt rval
186{-# INLINE valToNumber #-}
202{-# INLINE valToNumber #-}
188−valToNumber = undefined
191-- | Given a JavaScript value get its string value (as a JavaScript string).
205-- | Given a JavaScript value get its string value (as a JavaScript string).
@@ -208,18 +222,16 @@ valToNumber = undefined
208-- >>> testJSaddle $ valToStr "1" >>= strToText
222-- >>> testJSaddle $ valToStr "1" >>= strToText
210valToStr :: ToJSVal value => value -> JSM JSString
224valToStr :: ToJSVal value => value -> JSM JSString
211−#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)
225+#ifdef ghcjs_HOST_OS
212valToStr value = jsrefToString <$> toJSVal value
226valToStr value = jsrefToString <$> toJSVal value
213{-# INLINE valToStr #-}
227{-# INLINE valToStr #-}
214foreign import javascript unsafe "$r = $1.toString();" jsrefToString :: JSVal -> JSString
228foreign import javascript unsafe "$r = $1.toString();" jsrefToString :: JSVal -> JSString
215−#elif defined(USE_WEBKIT)
229+#else
216valToStr value = do
230valToStr value = do
217 gctxt <- ask
231 gctxt <- ask
218 withToJSVal value $ \rval ->
232 withToJSVal value $ \rval ->
219− (rethrow $ liftIO . jsvaluetostringcopy gctxt rval) >>= wrapJSString
233+ rethrow (liftIO . jsvaluetostringcopy gctxt rval) >>= wrapJSString
220{-# INLINE valToStr #-}
234{-# INLINE valToStr #-}
225-- | Given a JavaScript value get its string value (as a Haskell 'Text').
237-- | Given a JavaScript value get its string value (as a Haskell 'Text').
@@ -267,18 +279,16 @@ valToText jsvar = valToStr jsvar >>= strToText
267-- >>> testJSaddle $ obj >>= valToJSON 0 >>= strToText
279-- >>> testJSaddle $ obj >>= valToJSON 0 >>= strToText
269valToJSON :: ToJSVal value => Word -> value -> JSM JSString
281valToJSON :: ToJSVal value => Word -> value -> JSM JSString
270−#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)
282+#ifdef ghcjs_HOST_OS
271valToJSON indent value = jsrefToJSON <$> toJSVal value
283valToJSON indent value = jsrefToJSON <$> toJSVal value
272{-# INLINE valToJSON #-}
284{-# INLINE valToJSON #-}
273foreign import javascript unsafe "$r = JSON.stringify($1);" jsrefToJSON :: JSVal -> JSString
285foreign import javascript unsafe "$r = JSON.stringify($1);" jsrefToJSON :: JSVal -> JSString
274−#elif defined(USE_WEBKIT)
286+#else
275valToJSON indent value = do
287valToJSON indent value = do
276 gctxt <- ask
288 gctxt <- ask
277 withToJSVal value $ \rval ->
289 withToJSVal value $ \rval ->
278− (rethrow $ liftIO . jsvaluecreatejsonstring gctxt rval (fromIntegral indent)) >>= wrapJSString
290+ rethrow (liftIO . jsvaluecreatejsonstring gctxt rval (fromIntegral indent)) >>= wrapJSString
279{-# INLINE valToJSON #-}
291{-# INLINE valToJSON #-}
281−valToJSON = undefined
284-- | Given a JavaScript value get its object value.
294-- | Given a JavaScript value get its object value.
@@ -302,12 +312,12 @@ valToJSON = undefined
303valToObject :: ToJSVal value => value -> JSM Object
313valToObject :: ToJSVal value => value -> JSM Object
304valToObject value = Object <$>
314valToObject value = Object <$>
305−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
315+#ifdef ghcjs_HOST_OS
306 toJSVal value
316 toJSVal value
308 do gctxt <- ask
318 do gctxt <- ask
309 withToJSVal value $ \rval ->
319 withToJSVal value $ \rval ->
310− (rethrow $ liftIO . jsvaluetoobject gctxt rval) >>= makeNewJSVal
320+ rethrow (liftIO . jsvaluetoobject gctxt rval) >>= makeNewJSVal
312{-# INLINE valToObject #-}
322{-# INLINE valToObject #-}
@@ -341,7 +351,7 @@ instance ToJSVal v => ToJSVal (JSM v) where
341----------- null ---------------
351----------- null ---------------
342-- | Make a @null@ JavaScript value
352-- | Make a @null@ JavaScript value
343valMakeNull :: JSM JSVal
353valMakeNull :: JSM JSVal
344−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
354+#ifdef ghcjs_HOST_OS
345valMakeNull = return jsNull
355valMakeNull = return jsNull
347valMakeNull = ask >>= (liftIO . jsvaluemakenull) >>= makeNewJSVal
357valMakeNull = ask >>= (liftIO . jsvaluemakenull) >>= makeNewJSVal
@@ -366,7 +376,7 @@ instance ToJSVal a => ToJSVal (Maybe a) where
367-- | Test a JavaScript value to see if it is @null@
377-- | Test a JavaScript value to see if it is @null@
368valIsNull :: ToJSVal value => value -> JSM Bool
378valIsNull :: ToJSVal value => value -> JSM Bool
369−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
379+#ifdef ghcjs_HOST_OS
370valIsNull value = isNull <$> toJSVal value
380valIsNull value = isNull <$> toJSVal value
372valIsNull value = do
382valIsNull value = do
@@ -379,7 +389,7 @@ valIsNull value = do
379----------- undefined ---------------
389----------- undefined ---------------
380-- | Make an @undefined@ JavaScript value
390-- | Make an @undefined@ JavaScript value
381valMakeUndefined :: JSM JSVal
391valMakeUndefined :: JSM JSVal
382−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
392+#ifdef ghcjs_HOST_OS
383valMakeUndefined = return jsUndefined
393valMakeUndefined = return jsUndefined
385valMakeUndefined = ask >>= (liftIO . jsvaluemakeundefined) >>= makeNewJSVal
395valMakeUndefined = ask >>= (liftIO . jsvaluemakeundefined) >>= makeNewJSVal
@@ -403,7 +413,7 @@ instance MakeArgs () where
404-- | Test a JavaScript value to see if it is @undefined@
414-- | Test a JavaScript value to see if it is @undefined@
405valIsUndefined :: ToJSVal value => value -> JSM Bool
415valIsUndefined :: ToJSVal value => value -> JSM Bool
406−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
416+#ifdef ghcjs_HOST_OS
407valIsUndefined value = isUndefined <$> toJSVal value
417valIsUndefined value = isUndefined <$> toJSVal value
409valIsUndefined value = do
419valIsUndefined value = do
@@ -439,12 +449,12 @@ maybeNullOrUndefined' f value = do
439----------- booleans ---------------
449----------- booleans ---------------
440-- | Make a JavaScript boolean value
450-- | Make a JavaScript boolean value
441valMakeBool :: Bool -> JSM JSVal
451valMakeBool :: Bool -> JSM JSVal
442−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
452+#ifdef ghcjs_HOST_OS
443valMakeBool b = return $ toJSBool b
453valMakeBool b = return $ toJSBool b
445valMakeBool b = do
455valMakeBool b = do
446 gctxt <- ask
456 gctxt <- ask
447− (liftIO $ jsvaluemakeboolean gctxt b) >>= makeNewJSVal
457+ liftIO (jsvaluemakeboolean gctxt b) >>= makeNewJSVal
449{-# INLINE valMakeBool #-}
459{-# INLINE valMakeBool #-}
@@ -461,12 +471,12 @@ instance MakeArgs Bool where
461----------- numbers ---------------
471----------- numbers ---------------
462-- | Make a JavaScript number
472-- | Make a JavaScript number
463valMakeNumber :: Double -> JSM JSVal
473valMakeNumber :: Double -> JSM JSVal
464−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
474+#ifdef ghcjs_HOST_OS
465valMakeNumber n = liftIO $ GHCJS.toJSVal n
475valMakeNumber n = liftIO $ GHCJS.toJSVal n
467valMakeNumber n = do
477valMakeNumber n = do
468 gctxt <- ask
478 gctxt <- ask
469− (liftIO $ jsvaluemakenumber gctxt n) >>= makeNewJSVal
479+ liftIO (jsvaluemakenumber gctxt n) >>= makeNewJSVal
471{-# INLINE valMakeNumber #-}
481{-# INLINE valMakeNumber #-}
@@ -510,25 +520,25 @@ instance MakeArgs Double where
511-- | Make a JavaScript string from `Text`
521-- | Make a JavaScript string from `Text`
512valMakeText :: Text -> JSM JSVal
522valMakeText :: Text -> JSM JSVal
513−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
523+#ifdef ghcjs_HOST_OS
514valMakeText = return . pToJSVal . textToJSString
524valMakeText = return . pToJSVal . textToJSString
516valMakeText text = do
526valMakeText text = do
517 gctxt <- ask
527 gctxt <- ask
518 withJSString (textToStr text) $ \s ->
528 withJSString (textToStr text) $ \s ->
519− (liftIO $ jsvaluemakestring gctxt s) >>= makeNewJSVal
529+ liftIO (jsvaluemakestring gctxt s) >>= makeNewJSVal
521{-# INLINE valMakeText #-}
531{-# INLINE valMakeText #-}
523-- | Make a JavaScript string from `JSString`
533-- | Make a JavaScript string from `JSString`
524valMakeString :: JSString -> JSM JSVal
534valMakeString :: JSString -> JSM JSVal
525−#if (defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)) || !defined(USE_WEBKIT)
535+#ifdef ghcjs_HOST_OS
526valMakeString = return . pToJSVal
536valMakeString = return . pToJSVal
528valMakeString str = do
538valMakeString str = do
529 gctxt <- ask
539 gctxt <- ask
530 withJSString str $ \s ->
540 withJSString str $ \s ->
531− (liftIO $ jsvaluemakestring gctxt s) >>= makeNewJSVal
541+ liftIO (jsvaluemakestring gctxt s) >>= makeNewJSVal
533{-# INLINE valMakeString #-}
543{-# INLINE valMakeString #-}
@@ -567,26 +577,26 @@ instance ToJSString String where
568-- | Derefernce a value reference.
578-- | Derefernce a value reference.
570−-- >>> testJSaddle $ show <$> deRefVal JSNull
580+-- >>> testJSaddle $ showJSValue <$> deRefVal JSNull
571-- ValNull
581-- ValNull
572−-- >>> testJSaddle $ show <$> deRefVal ()
582+-- >>> testJSaddle $ showJSValue <$> deRefVal ()
573-- ValUndefined
583-- ValUndefined
574−-- >>> testJSaddle $ show <$> deRefVal True
584+-- >>> testJSaddle $ showJSValue <$> deRefVal True
575-- ValBool True
585-- ValBool True
576−-- >>> testJSaddle $ show <$> deRefVal False
586+-- >>> testJSaddle $ showJSValue <$> deRefVal False
577-- ValBool False
587-- ValBool False
578−-- >>> testJSaddle $ show <$> deRefVal (1.0 :: Double)
588+-- >>> testJSaddle $ showJSValue <$> deRefVal (1.0 :: Double)
579-- ValNumber 1.0
589-- ValNumber 1.0
580−-- >>> testJSaddle $ show <$> deRefVal (0.0 :: Double)
590+-- >>> testJSaddle $ showJSValue <$> deRefVal (0.0 :: Double)
581-- ValNumber 0.0
591-- ValNumber 0.0
582−-- >>> testJSaddle $ show <$> deRefVal ""
592+-- >>> testJSaddle $ showJSValue <$> deRefVal ""
583-- ValString ""
593-- ValString ""
584−-- >>> testJSaddle $ show <$> deRefVal "1"
594+-- >>> testJSaddle $ showJSValue <$> deRefVal "1"
585-- ValString "1"
595-- ValString "1"
586−-- >>> testJSaddle $ show <$> valToObject True >>= deRefVal
596+-- >>> testJSaddle $ showJSValue <$> valToObject True >>= deRefVal
587-- ValObject 0x...
597-- ValObject 0x...
588deRefVal :: ToJSVal value => value -> JSM JSValue
598deRefVal :: ToJSVal value => value -> JSM JSValue
589−#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)
599+#ifdef ghcjs_HOST_OS
590deRefVal value = do
600deRefVal value = do
591 valref <- toJSVal value
601 valref <- toJSVal value
592 case (jsrefGetType valref :: Int) of
602 case (jsrefGetType valref :: Int) of
@@ -602,20 +612,18 @@ foreign import javascript unsafe "$r = ($1 === undefined)?0:\
602 (typeof $1===\"number\")?3:\
612 (typeof $1===\"number\")?3:\
603 (typeof $1===\"string\")?4:\
613 (typeof $1===\"string\")?4:\
604 (typeof $1===\"object\")?5:-1;" jsrefGetType :: JSVal -> Int
614 (typeof $1===\"object\")?5:-1;" jsrefGetType :: JSVal -> Int
605−#elif defined(USE_WEBKIT)
615+#else
606deRefVal value = do
616deRefVal value = do
607 gctxt <- ask
617 gctxt <- ask
608 v <- toJSVal value
618 v <- toJSVal value
609 withJSVal v $ \rval ->
619 withJSVal v $ \rval ->
610− (liftIO $ jsvaluegettype gctxt rval) >>= \case
620+ liftIO (jsvaluegettype gctxt rval) >>= \case
611 Kjstypenull -> return ValNull
621 Kjstypenull -> return ValNull
612 Kjstypeundefined -> return ValUndefined
622 Kjstypeundefined -> return ValUndefined
613 Kjstypeboolean -> ValBool <$> valToBool v
623 Kjstypeboolean -> ValBool <$> valToBool v
614 Kjstypenumber -> ValNumber <$> valToNumber v
624 Kjstypenumber -> ValNumber <$> valToNumber v
615 Kjstypestring -> ValString <$> valToText v
625 Kjstypestring -> ValString <$> valToText v
616 Kjstypeobject -> ValObject <$> valToObject v
626 Kjstypeobject -> ValObject <$> valToObject v
621-- | Make a JavaScript value out of a 'JSValue' ADT.
629-- | Make a JavaScript value out of a 'JSValue' ADT.
@@ -654,7 +662,7 @@ instance MakeArgs JSValue where
654-- makeObjectRef _ = Object <$> valMakeNull
662-- makeObjectRef _ = Object <$> valMakeNull
655-- {-# INLINE makeObjectRef #-}
663-- {-# INLINE makeObjectRef #-}
657−#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)
665+#ifdef ghcjs_HOST_OS
658foreign import javascript unsafe
666foreign import javascript unsafe
659 "$1===$2" jsvalueisstrictequal :: JSVal -> JSVal -> Bool
667 "$1===$2" jsvalueisstrictequal :: JSVal -> JSVal -> Bool
@@ -663,7 +671,7 @@ strictEqual :: (ToJSVal a, ToJSVal b) => a -> b -> JSM Bool
663strictEqual a b = do
671strictEqual a b = do
664 aval <- toJSVal a
672 aval <- toJSVal a
665 bval <- toJSVal b
673 bval <- toJSVal b
666−#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)
674+#ifdef ghcjs_HOST_OS
667 return $ jsvalueisstrictequal aval bval
675 return $ jsvalueisstrictequal aval bval
669 gctxt <- ask
677 gctxt <- ask
@@ -672,7 +680,7 @@ strictEqual a b = do
672 liftIO $ jsvalueisstrictequal gctxt aref bref
680 liftIO $ jsvalueisstrictequal gctxt aref bref
675−#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)
683+#ifdef ghcjs_HOST_OS
676foreign import javascript unsafe "\
684foreign import javascript unsafe "\
678 $r = $1 instanceof $2\
686 $r = $1 instanceof $2\
@@ -687,7 +695,7 @@ instanceOf :: (ToJSVal value, MakeObject constructor) => value -> constructor ->
687instanceOf value constructor = do
695instanceOf value constructor = do
688 v <- toJSVal value
696 v <- toJSVal value
689 c <- makeObject constructor
697 c <- makeObject constructor
690−#if defined(ghcjs_HOST_OS) && defined(USE_JAVASCRIPTFFI)
698+#ifdef ghcjs_HOST_OS
691 rethrow $ return . js_isInstanceOf v c
699 rethrow $ return . js_isInstanceOf v c
693 gctxt <- ask
701 gctxt <- ask