@@ -45,6 +45,7 @@ module Language.Javascript.JSaddle.Value (
45 , showJSValue
45 , showJSValue
47 -- * Converting JavaScript values
47 -- * Converting JavaScript values
48 , valToBool
49 , valToBool
49 , valToNumber
50 , valToNumber
50 , valToStr
51 , valToStr
@@ -54,15 +55,24 @@ module Language.Javascript.JSaddle.Value (
55 -- * Make JavaScript values from Haskell ones
56 -- * Make JavaScript values from Haskell ones
58 , valIsNull
61 , valIsNull
59 , valUndefined
63 , valUndefined
60 , valIsUndefined
65 , valIsUndefined
61 , maybeNullOrUndefined
66 , maybeNullOrUndefined
62 , maybeNullOrUndefined'
67 , maybeNullOrUndefined'
64 , valMakeNumber
72 , valMakeNumber
65 , valMakeString
73 , valMakeString
67 -- * Convert to and from JSValue
77 -- * Convert to and from JSValue
68 , deRefVal
78 , deRefVal
@@ -71,33 +81,35 @@ module Language.Javascript.JSaddle.Value (
71 , instanceOf
81 , instanceOf
84+import Data.Text (Text)
85+import qualified Data.Text as T (pack, unpack)
86+import Data.Aeson (Value)
74import Language.Javascript.JSaddle.Types
89import Language.Javascript.JSaddle.Types
75 (Object(..), JSString(..), JSVal(..))
90 (Object(..), JSString(..), JSVal(..))
76−#ifdef ghcjs_HOST_OS
91+import GHCJS.Marshal (ToJSVal(..))
77−import Control.Monad.IO.Class (MonadIO(..))
78−import GHCJS.Types (isNull, isUndefined)
79−import GHCJS.Foreign (toJSBool, isTruthy, jsNull, jsUndefined)
80−import qualified GHCJS.Marshal as GHCJS (toJSVal)
81import GHCJS.Marshal.Pure (pToJSVal)
92import GHCJS.Marshal.Pure (pToJSVal)
82import Data.JSString.Text (textToJSString)
93import Data.JSString.Text (textToJSString)
83−import qualified Data.Text as T (pack)
85−import qualified Data.Text as T (pack, unpack)
95+import Data.Char (chr, ord)
96+import Data.Word (Word, Word8, Word16, Word32)
97+import Data.Int (Int8, Int16, Int32)
98+import GHCJS.Marshal.Internal (ToJSVal(..), FromJSVal(..))
99+import Language.Javascript.JSaddle.Types
100+ (Object(..), JSString(..), JSVal(..), JSValueForSend(..))
86import Language.Javascript.JSaddle.Native
101import Language.Javascript.JSaddle.Native
87− (wrapJSString, withJSVal, withObject, withJSString,
102+ (wrapJSString, withJSVal, withObject, withJSString, withToJSVal)
89import Language.Javascript.JSaddle.Run
103import Language.Javascript.JSaddle.Run
90 (Command(..), AsyncCommand(..), Result(..), sendCommand,
104 (Command(..), AsyncCommand(..), Result(..), sendCommand,
91 sendLazyCommand)
105 sendLazyCommand)
93import Language.Javascript.JSaddle.Monad (JSM)
107import Language.Javascript.JSaddle.Monad (JSM)
94−import Data.Text (Text)
95import Language.Javascript.JSaddle.Classes
108import Language.Javascript.JSaddle.Classes
96− (MakeObject(..), ToJSString(..), ToJSVal(..))
109+ (MakeObject(..), MakeArgs(..))
110+import Language.Javascript.JSaddle.Marshal.String (ToJSString(..), FromJSString(..))
97import Language.Javascript.JSaddle.String (strToText, textToStr)
111import Language.Javascript.JSaddle.String (strToText, textToStr)
98−import Language.Javascript.JSaddle.Arguments (MakeArgs(..))
112+import Language.Javascript.JSaddle.Foreign (jsTrue, jsFalse, jsNull, toJSBool, jsUndefined, isTruthyIO, isNullIO, isUndefinedIO)
99−import Data.Word (Word32, Word, Word64)
100−import Data.Int (Int32, Int64)
103-- >>> import Language.Javascript.JSaddle.Test (testJSaddle)
115-- >>> import Language.Javascript.JSaddle.Test (testJSaddle)
@@ -154,20 +166,7 @@ showJSValue (ValObject _) = "object"
154-- >>> testJSaddle $ valToBool "1"
166-- >>> testJSaddle $ valToBool "1"
156valToBool :: ToJSVal value => value -> JSM Bool
168valToBool :: ToJSVal value => value -> JSM Bool
158−valToBool value = isTruthy <$> toJSVal value
161− toJSVal value >>= \case
169+valToBool value = toJSVal value >>= isTruthyIO
162− (JSVal 0) -> return False -- null
163− (JSVal 1) -> return False -- undefined
164− (JSVal 2) -> return False -- false
165− (JSVal 3) -> return True -- true
167− withJSVal v $ \rval -> do
168− ValueToBoolResult result <- sendCommand (ValueToBool rval)
172-- | Given a JavaScript value get its numeric value.
171-- | Given a JavaScript value get its numeric value.
173-- May throw JSException.
172-- May throw JSException.
@@ -308,15 +307,21 @@ valToObject value = Object <$> toJSVal value
308instance MakeObject JSVal where
307instance MakeObject JSVal where
309 makeObject = valToObject
308 makeObject = valToObject
310+instance ToJSVal Object where
311+ toJSVal (Object r) = return r
311-- | Convert to a JavaScript value (just an alias for 'toJSVal')
313-- | Convert to a JavaScript value (just an alias for 'toJSVal')
312val :: ToJSVal value
314val :: ToJSVal value
313 => value -- ^ value to convert to a JavaScript value
315 => value -- ^ value to convert to a JavaScript value
314 -> JSM JSVal
316 -> JSM JSVal
315val = toJSVal
317val = toJSVal
319+#ifndef ghcjs_HOST_OS
317-- | If we already have a JSVal we are fine
320-- | If we already have a JSVal we are fine
318instance ToJSVal JSVal where
321instance ToJSVal JSVal where
319 toJSVal = return
322 toJSVal = return
323+ {-# INLINE toJSVal #-}
321-- | A single JSVal can be used as the argument list
326-- | A single JSVal can be used as the argument list
322instance MakeArgs JSVal where
327instance MakeArgs JSVal where
@@ -326,55 +331,68 @@ instance MakeArgs JSVal where
326-- as it returns something we can make into a JSVal.
331-- as it returns something we can make into a JSVal.
327instance ToJSVal v => ToJSVal (JSM v) where
332instance ToJSVal v => ToJSVal (JSM v) where
328 toJSVal v = v >>= toJSVal
333 toJSVal v = v >>= toJSVal
334+ {-# INLINE toJSVal #-}
330----------- null ---------------
336----------- null ---------------
331-- | A @null@ JavaScript value
337-- | A @null@ JavaScript value
332valNull :: JSVal
338valNull :: JSVal
334valNull = jsNull
339valNull = jsNull
336−valNull = JSVal 0
340+{-# INLINE valNull #-}
339-- | Makes a @null@ JavaScript value
342-- | Makes a @null@ JavaScript value
340instance ToJSVal JSNull where
343instance ToJSVal JSNull where
341− toJSVal = const (return valNull)
344+ toJSVal = const (return jsNull)
345+ {-# INLINE toJSVal #-}
343-- | Makes an argument list with just a single @null@ JavaScript value
347-- | Makes an argument list with just a single @null@ JavaScript value
344instance MakeArgs JSNull where
348instance MakeArgs JSNull where
345− makeArgs _ = return [valNull]
349+ makeArgs _ = return [jsNull]
351+#ifndef ghcjs_HOST_OS
347-- | Makes a JSVal or @null@ JavaScript value
352-- | Makes a JSVal or @null@ JavaScript value
348instance ToJSVal a => ToJSVal (Maybe a) where
353instance ToJSVal a => ToJSVal (Maybe a) where
349− toJSVal Nothing = return valNull
354+ toJSVal Nothing = return jsNull
350 toJSVal (Just a) = toJSVal a
355 toJSVal (Just a) = toJSVal a
356+ {-# INLINE toJSVal #-}
357+instance FromJSVal a => FromJSVal (Maybe a) where
358+ fromJSValUnchecked x =
359+ isUndefinedIO x >>= \case
360+ True -> return Nothing
361+ False -> isNullIO x >>= \case
362+ True -> return Nothing
363+ False -> fromJSVal x
364+ {-# INLINE fromJSValUnchecked #-}
366+ isUndefinedIO x >>= \case
367+ True -> return (Just Nothing)
368+ False -> isNullIO x >>= \case
369+ True -> return (Just Nothing)
370+ False -> fmap (fmap Just) fromJSVal x
371+ {-# INLINE fromJSVal #-}
373+-- Make an array out of various lists
374+instance ToJSVal a => ToJSVal [a] where
375+ toJSVal = toJSValListOf
376+ {-# INLINE toJSVal #-}
378+instance FromJSVal a => FromJSVal [a] where
379+ fromJSVal = fromJSValListOf
380+ {-# INLINE fromJSVal #-}
352-- | Test a JavaScript value to see if it is @null@
383-- | Test a JavaScript value to see if it is @null@
353valIsNull :: ToJSVal value => value -> JSM Bool
384valIsNull :: ToJSVal value => value -> JSM Bool
355−valIsNull value = isNull <$> toJSVal value
358− toJSVal value >>= \case
385+valIsNull value = toJSVal value >>= isNullIO
359− JSVal 0 -> return True
361− withJSVal v $ \rval -> do
362− IsNullResult result <- sendCommand $ IsNull rval
366----------- undefined ---------------
387----------- undefined ---------------
367-- | An @undefined@ JavaScript value
388-- | An @undefined@ JavaScript value
368valUndefined :: JSVal
389valUndefined :: JSVal
370valUndefined = jsUndefined
390valUndefined = jsUndefined
372−valUndefined = JSVal 1
391+{-# INLINE valUndefined #-}
375-- | Makes an @undefined@ JavaScript value
393-- | Makes an @undefined@ JavaScript value
376instance ToJSVal JSUndefined where
394instance ToJSVal JSUndefined where
377− toJSVal = const (return valUndefined)
395+ toJSVal = const (return jsUndefined)
379--We can't allow this if JSUndefined is () as () is no args not "(null)".
397--We can't allow this if JSUndefined is () as () is no args not "(null)".
380--Use [()] instead.
398--Use [()] instead.
@@ -387,16 +405,7 @@ instance MakeArgs () where
388-- | Test a JavaScript value to see if it is @undefined@
406-- | Test a JavaScript value to see if it is @undefined@
389valIsUndefined :: ToJSVal value => value -> JSM Bool
407valIsUndefined :: ToJSVal value => value -> JSM Bool
391−valIsUndefined value = isUndefined <$> toJSVal value
393−valIsUndefined value = toJSVal value >>= \case
408+valIsUndefined value = toJSVal value >>= isUndefinedIO
394− JSVal 1 -> return True
396− withJSVal v $ \rval -> do
397− IsUndefinedResult result <- sendCommand $ IsUndefined rval
401-- | Convert a JSVal to a Maybe JSVal (converting null and undefined to Nothing)
410-- | Convert a JSVal to a Maybe JSVal (converting null and undefined to Nothing)
402maybeNullOrUndefined :: ToJSVal value => value -> JSM (Maybe JSVal)
411maybeNullOrUndefined :: ToJSVal value => value -> JSM (Maybe JSVal)
@@ -422,15 +431,15 @@ maybeNullOrUndefined' f value = do
422----------- booleans ---------------
431----------- booleans ---------------
423-- | A JavaScript boolean value
432-- | A JavaScript boolean value
424valBool :: Bool -> JSVal
433valBool :: Bool -> JSVal
426−valBool b = toJSBool b
434+valBool = toJSBool
427−#else
435+{-# INLINE valBool #-}
428−valBool b = JSVal $ if b then 3 else 2
437+#ifndef ghcjs_HOST_OS
431-- | Make a JavaScript boolean value
438-- | Make a JavaScript boolean value
432instance ToJSVal Bool where
439instance ToJSVal Bool where
433 toJSVal = return . valBool
440 toJSVal = return . valBool
441+ {-# INLINE toJSVal #-}
435-- | Makes an argument list with just a single JavaScript boolean value
444-- | Makes an argument list with just a single JavaScript boolean value
436instance MakeArgs Bool where
445instance MakeArgs Bool where
@@ -440,35 +449,53 @@ instance MakeArgs Bool where
440-- | Make a JavaScript number
449-- | Make a JavaScript number
441valMakeNumber :: Double -> JSM JSVal
450valMakeNumber :: Double -> JSM JSVal
442#ifdef ghcjs_HOST_OS
451#ifdef ghcjs_HOST_OS
443−valMakeNumber n = liftIO $ GHCJS.toJSVal n
452+valMakeNumber n = toJSVal n
445valMakeNumber = sendLazyCommand . NumberToValue
454valMakeNumber = sendLazyCommand . NumberToValue
457+#ifndef ghcjs_HOST_OS
448-- | Makes a JavaScript number
458-- | Makes a JavaScript number
449instance ToJSVal Double where
459instance ToJSVal Double where
450 toJSVal = valMakeNumber
460 toJSVal = valMakeNumber
461+ {-# INLINE toJSVal #-}
452instance ToJSVal Float where
463instance ToJSVal Float where
453 toJSVal = valMakeNumber . realToFrac
464 toJSVal = valMakeNumber . realToFrac
465+ {-# INLINE toJSVal #-}
455instance ToJSVal Word where
467instance ToJSVal Word where
456 toJSVal = valMakeNumber . fromIntegral
468 toJSVal = valMakeNumber . fromIntegral
469+ {-# INLINE toJSVal #-}
458−instance ToJSVal Word32 where
471+instance ToJSVal Word8 where
472+ toJSVal = valMakeNumber . fromIntegral
473+ {-# INLINE toJSVal #-}
475+instance ToJSVal Word16 where
459 toJSVal = valMakeNumber . fromIntegral
476 toJSVal = valMakeNumber . fromIntegral
477+ {-# INLINE toJSVal #-}
461−instance ToJSVal Word64 where
479+instance ToJSVal Word32 where
462 toJSVal = valMakeNumber . fromIntegral
480 toJSVal = valMakeNumber . fromIntegral
481+ {-# INLINE toJSVal #-}
464instance ToJSVal Int where
483instance ToJSVal Int where
465 toJSVal = valMakeNumber . fromIntegral
484 toJSVal = valMakeNumber . fromIntegral
485+ {-# INLINE toJSVal #-}
467−instance ToJSVal Int32 where
487+instance ToJSVal Int8 where
468 toJSVal = valMakeNumber . fromIntegral
488 toJSVal = valMakeNumber . fromIntegral
489+ {-# INLINE toJSVal #-}
470−instance ToJSVal Int64 where
491+instance ToJSVal Int16 where
471 toJSVal = valMakeNumber . fromIntegral
492 toJSVal = valMakeNumber . fromIntegral
493+ {-# INLINE toJSVal #-}
495+instance ToJSVal Int32 where
496+ toJSVal = valMakeNumber . fromIntegral
497+ {-# INLINE toJSVal #-}
473-- | Makes an argument list with just a single JavaScript number
500-- | Makes an argument list with just a single JavaScript number
474instance MakeArgs Double where
501instance MakeArgs Double where
@@ -491,21 +518,33 @@ valMakeString s =
491 withJSString s $ sendLazyCommand . StringToValue
518 withJSString s $ sendLazyCommand . StringToValue
521+#ifndef ghcjs_HOST_OS
494-- | Makes a JavaScript string
522-- | Makes a JavaScript string
495instance ToJSVal Text where
523instance ToJSVal Text where
496 toJSVal = valMakeText
524 toJSVal = valMakeText
525+ {-# INLINE toJSVal #-}
526+instance FromJSVal Text where
527+ fromJSValUnchecked = valToText
528+ {-# INLINE fromJSValUnchecked #-}
529+ fromJSVal = fmap Just . valToText
530+ {-# INLINE fromJSVal #-}
498-- | Makes an argument list with just a single JavaScript string
533-- | Makes an argument list with just a single JavaScript string
499instance MakeArgs Text where
534instance MakeArgs Text where
500 makeArgs t = valMakeText t >>= (\ref -> return [ref])
535 makeArgs t = valMakeText t >>= (\ref -> return [ref])
502−-- | Makes a JavaScript string
537+#ifndef ghcjs_HOST_OS
503−instance ToJSVal String where
504− toJSVal = valMakeText . T.pack
506-- | Makes a JavaScript string
538-- | Makes a JavaScript string
507instance ToJSVal JSString where
539instance ToJSVal JSString where
508 toJSVal = valMakeString
540 toJSVal = valMakeString
541+ {-# INLINE toJSVal #-}
542+instance FromJSVal JSString where
543+ fromJSValUnchecked = valToStr
544+ {-# INLINE fromJSValUnchecked #-}
545+ fromJSVal = fmap Just . valToStr
546+ {-# INLINE fromJSVal #-}
510-- | If we already have a JSString we are fine
549-- | If we already have a JSString we are fine
511instance ToJSString JSString where
550instance ToJSString JSString where
@@ -517,6 +556,51 @@ instance ToJSString Text where
517instance ToJSString String where
556instance ToJSString String where
518 toJSString = textToStr . T.pack
557 toJSString = textToStr . T.pack
559+instance FromJSString Text where
560+ fromJSString = strToText
562+instance FromJSString String where
563+ fromJSString v = T.unpack $ strToText v
565+instance FromJSString JSString where
568+#ifndef ghcjs_HOST_OS
569+instance ToJSVal Char where
570+ toJSVal = valMakeNumber . fromIntegral . ord
571+ {-# INLINE toJSVal #-}
572+ toJSValListOf = valMakeText . T.pack
573+ {-# INLINE toJSValListOf #-}
574+instance FromJSVal Char where
575+ fromJSValUnchecked = fmap (chr . round) . valToNumber
576+ {-# INLINE fromJSValUnchecked #-}
577+ fromJSVal = fmap (Just . chr . round) . valToNumber
578+ {-# INLINE fromJSVal #-}
579+ fromJSValUncheckedListOf = fmap (T.unpack . strToText) . valToStr
580+ {-# INLINE fromJSValListOf #-}
581+ fromJSValListOf = fmap (Just . T.unpack . strToText) . valToStr
582+ {-# INLINE fromJSValUncheckedListOf #-}
585+-- | Make a JavaScript string from AESON `Value`
586+valMakeJSON :: Value -> JSM JSVal
588+valMakeJSON = toJSVal
590+valMakeJSON = sendLazyCommand . JSONValueToValue
593+#ifndef ghcjs_HOST_OS
594+-- | Makes a JSON value
595+instance ToJSVal Value where
596+ toJSVal = valMakeJSON
597+ {-# INLINE toJSVal #-}
600+-- | Makes an argument list with just a single JSON value
601+instance MakeArgs Value where
602+ makeArgs t = valMakeJSON t >>= (\ref -> return [ref])
520-- | Derefernce a value reference.
604-- | Derefernce a value reference.
522-- >>> testJSaddle $ showJSValue <$> deRefVal JSNull
606-- >>> testJSaddle $ showJSValue <$> deRefVal JSNull
@@ -597,6 +681,7 @@ valMakeRef value =
597-- | Makes a JavaScript value from a 'JSValue' ADT.
681-- | Makes a JavaScript value from a 'JSValue' ADT.
598instance ToJSVal JSValue where
682instance ToJSVal JSValue where
599 toJSVal = valMakeRef
683 toJSVal = valMakeRef
684+ {-# INLINE toJSVal #-}
601-- | Makes an argument list with just a single JavaScript value from a 'JSValue' ADT.
686-- | Makes an argument list with just a single JavaScript value from a 'JSValue' ADT.
602instance MakeArgs JSValue where
687instance MakeArgs JSValue where
@@ -664,4 +749,3 @@ instanceOf value constructor = do