@@ -25,12 +25,13 @@ import Control.Monad.Reader (MonadReader, runReaderT, ask)
25
25
import Control.Monad.Trans.Reader (ReaderT )
26
26
import Control.Monad.IO.Class (MonadIO , liftIO )
27
27
import Control.Monad.IO.Unlift (MonadUnliftIO (.. ), UnliftIO (.. ), askUnliftIO )
28
- import Data.Aeson (Value (.. ), encode , toJSON )
28
+ import Data.Aeson (Key , Value (.. ), encode , toJSON )
29
29
import qualified Data.Aeson as Aeson
30
+ import qualified Data.Aeson.Key as Key
30
31
import Data.Scientific (fromFloatDigits , toRealFloat , toBoundedInteger , isInteger )
31
32
import Data.Text (Text )
32
33
import Data.Vector (fromList , imapM_ )
33
- import Data.HashMap.Strict (HashMap , empty , insert , toList )
34
+ import Data.Aeson.KeyMap (KeyMap , empty , insert , toList )
34
35
import Data.String.Conv (toS )
35
36
import Data.Time.Clock.POSIX (posixSecondsToUTCTime )
36
37
import Control.Concurrent (rtsSupportsBoundThreads , runInBoundThread )
@@ -50,8 +51,6 @@ foreign import ccall "JS_NewRuntime"
50
51
foreign import ccall " JS_FreeRuntime"
51
52
jsFreeRuntime :: Ptr JSRuntime -> IO ()
52
53
53
-
54
-
55
54
foreign import ccall " JS_NewContext"
56
55
jsNewContext :: Ptr JSRuntime -> IO (Ptr JSContext )
57
56
@@ -93,7 +92,7 @@ jsIsDate ctxPtr val = do
93
92
dateConstructor <- jsGetPropertyStr ctxPtr globalObject " Date"
94
93
liftIO $ do
95
94
jsFreeValue ctxPtr globalObject
96
- res <- with val $ \ valPtr -> with dateConstructor $ \ dateCPtr ->
95
+ res <- with val $ \ valPtr -> with dateConstructor $ \ dateCPtr ->
97
96
[C. block | int { return JS_IsInstanceOf($(JSContext *ctxPtr), *$(JSValueConst *valPtr), *$(JSValueConst *dateCPtr)); } |]
98
97
jsFreeValue ctxPtr dateConstructor
99
98
return $ res > 0
@@ -110,16 +109,16 @@ jsIsTryAll _ _ _ _ = throwM $ InternalError $ "jsIsTryAll_ unreachable case"
110
109
111
110
jsIs :: (MonadIO m , MonadThrow m ) => JSContextPtr -> JSValue -> m JSTypeEnum
112
111
jsIs ctx jsval = case fromCType $ tag jsval of
113
- Just JSTagObject ->
112
+ Just JSTagObject ->
114
113
jsIsTryAll jsval [jsIsArray ctx, jsIsDate ctx] [JSIsArray , JSIsDate ] (JSTypeFromTag JSTagObject )
115
- Just t | t == JSTagBigDecimal ||
114
+ Just t | t == JSTagBigDecimal ||
116
115
t == JSTagBigInt ||
117
116
t == JSTagBigFloat ||
118
- t == JSTagInt ||
117
+ t == JSTagInt ||
119
118
t == JSTagFloat64 -> return JSIsNumber
120
119
| otherwise -> return $ JSTypeFromTag t
121
120
Nothing -> throwM $ UnknownJSTag (tag jsval)
122
-
121
+
123
122
124
123
125
124
jsNullValue :: JSValue
@@ -149,7 +148,7 @@ checkIsException :: (MonadThrow m, MonadIO m) => Text -> JSContextPtr -> JSValue
149
148
checkIsException loc ctxPtr val =
150
149
case fromCType $ tag val of
151
150
Just JSTagException -> do
152
- err <- getErrorMessage ctxPtr
151
+ err <- getErrorMessage ctxPtr
153
152
liftIO $ jsFreeValue ctxPtr val
154
153
throwM $ JSException loc err
155
154
_ -> pure ()
@@ -159,25 +158,25 @@ checkIsException loc ctxPtr val =
159
158
jsonToJSValue :: (MonadThrow m , MonadIO m ) => JSContextPtr -> Value -> m JSValue
160
159
jsonToJSValue _ Null = pure jsNullValue
161
160
jsonToJSValue ctx (Bool b) = liftIO $ jsNewBool ctx b
162
- jsonToJSValue ctx (Number n) =
161
+ jsonToJSValue ctx (Number n) =
163
162
if not (isInteger n) then liftIO $ jsNewFloat64 ctx (toRealFloat n)
164
163
else case toBoundedInteger n of
165
164
Just i -> liftIO $ jsNewInt64 ctx i
166
165
Nothing -> throwM $ InternalError " Value does not fit in Int64"
167
166
jsonToJSValue ctx (String s) = liftIO $ jsNewString ctx $ toS s
168
167
jsonToJSValue ctxPtr (Array xs) = do
169
168
arrVal <- liftIO (C. withPtr_ $ \ arrValPtr -> [C. block | void { *$(JSValueConst *arrValPtr) = JS_NewArray($(JSContext *ctxPtr)); } |])
170
-
169
+
171
170
checkIsException " jsonToJSValue/Array/1" ctxPtr arrVal
172
171
173
- flip imapM_ xs $ \ index value -> do
172
+ flip imapM_ xs $ \ index value -> do
174
173
val <- jsonToJSValue ctxPtr value
175
174
checkIsException " jsonToJSValue/Array/2" ctxPtr val
176
175
177
176
let idx = fromIntegral index
178
- code <- liftIO (with arrVal $ \ arrValPtr -> with val $ \ valPtr ->
177
+ code <- liftIO (with arrVal $ \ arrValPtr -> with val $ \ valPtr ->
179
178
[C. block | int { return JS_DefinePropertyValueUint32(
180
- $(JSContext *ctxPtr),
179
+ $(JSContext *ctxPtr),
181
180
*$(JSValueConst *arrValPtr),
182
181
$(uint32_t idx),
183
182
*$(JSValueConst *valPtr),
@@ -192,25 +191,25 @@ jsonToJSValue ctxPtr (Array xs) = do
192
191
193
192
return arrVal
194
193
jsonToJSValue ctxPtr (Object o) = do
195
- objVal <- liftIO (C. withPtr_ $ \ objValPtr ->
194
+ objVal <- liftIO (C. withPtr_ $ \ objValPtr ->
196
195
[C. block | void { *$(JSValueConst *objValPtr) = JS_NewObject($(JSContext *ctxPtr)); } |])
197
196
198
197
checkIsException " jsonToJSValue/Object/1" ctxPtr objVal
199
-
198
+
200
199
forM_ (toList o) $ \ (key,value) -> do
201
200
val <- jsonToJSValue ctxPtr value
202
201
checkIsException " jsonToJSValue/Object/2" ctxPtr val
203
202
204
- code <- liftIO (with objVal $ \ objValPtr -> with val $ \ valPtr ->
205
- useAsCString (encodeUtf8 key) $ \ cstringPtr -> do
206
- [C. block | int {
203
+ code <- liftIO (with objVal $ \ objValPtr -> with val $ \ valPtr ->
204
+ useAsCString (encodeUtf8 $ Key. toText key) $ \ cstringPtr -> do
205
+ [C. block | int {
207
206
return JS_DefinePropertyValueStr(
208
- $(JSContext *ctxPtr),
207
+ $(JSContext *ctxPtr),
209
208
*$(JSValueConst *objValPtr),
210
209
$(const char *cstringPtr),
211
210
*$(JSValueConst *valPtr),
212
211
JS_PROP_C_W_E
213
- );
212
+ );
214
213
} |])
215
214
216
215
when (code < 0 ) $ do
@@ -262,7 +261,7 @@ jsToJSON ctx jsval = do
262
261
ty <- jsIs ctx jsval
263
262
case ty of
264
263
JSTypeFromTag JSTagException -> do
265
- err <- getErrorMessage ctx
264
+ err <- getErrorMessage ctx
266
265
liftIO $ jsFreeValue ctx jsval
267
266
throwM $ JSException " jsToJSON/JSTagException" err
268
267
JSTypeFromTag JSTagNull -> return Null
@@ -278,16 +277,16 @@ jsToJSON ctx jsval = do
278
277
return $ String $ toS s
279
278
JSIsArray -> do
280
279
len <- do
281
- lenVal <- jsGetPropertyStr ctx jsval " length"
280
+ lenVal <- jsGetPropertyStr ctx jsval " length"
282
281
len' <- jsToInt64 ctx lenVal
283
282
liftIO $ jsFreeValue ctx lenVal
284
283
return len'
285
284
vs <- jsArrayToJSON ctx jsval 0 (fromIntegral len)
286
285
return $ Array $ fromList vs
287
286
JSIsDate -> do
288
- getter <- jsGetPropertyStr ctx jsval " getTime"
287
+ getter <- jsGetPropertyStr ctx jsval " getTime"
289
288
290
- timestampRaw <- liftIO $ C. withPtr_ $ \ res -> with getter $ \ getterPtr -> with jsval $ \ jsvalPtr ->
289
+ timestampRaw <- liftIO $ C. withPtr_ $ \ res -> with getter $ \ getterPtr -> with jsval $ \ jsvalPtr ->
291
290
[C. block | void { *$(JSValue *res) = JS_Call($(JSContext *ctx), *$(JSValueConst *getterPtr), *$(JSValueConst *jsvalPtr), 0, NULL); } |]
292
291
293
292
timestamp <- jsToFloat64 ctx timestampRaw
@@ -297,17 +296,17 @@ jsToJSON ctx jsval = do
297
296
return $ toJSON $ posixSecondsToUTCTime $ realToFrac $ timestamp / 1000
298
297
JSTypeFromTag JSTagObject -> do
299
298
o <- jsObjectToJSON ctx jsval
300
- return $ Object o
299
+ return $ Object o
301
300
JSTypeFromTag f -> throwM $ UnsupportedTypeTag f
302
301
JSIsError -> throwM $ InternalError " JSIsError unreachable"
303
302
304
303
305
304
jsArrayToJSON :: (MonadCatch m , MonadIO m ) => JSContextPtr -> JSValue -> Int -> Int -> m [Value ]
306
- jsArrayToJSON ctxPtr jsval index len =
305
+ jsArrayToJSON ctxPtr jsval index len =
307
306
if index < len then do
308
307
v <- do
309
308
let idx = fromIntegral index
310
- val <- liftIO $ C. withPtr_ $ \ ptr -> with jsval $ \ jsvalPtr ->
309
+ val <- liftIO $ C. withPtr_ $ \ ptr -> with jsval $ \ jsvalPtr ->
311
310
[C. block | void { *$(JSValue *ptr) = JS_GetPropertyUint32($(JSContext *ctxPtr), *$(JSValueConst *jsvalPtr), $(uint32_t idx)); } |]
312
311
313
312
checkIsException " jsArrayToJSON" ctxPtr val
@@ -333,11 +332,11 @@ forLoop end f = go 0
333
332
334
333
335
334
336
- jsObjectToJSON :: (MonadCatch m , MonadIO m ) => JSContextPtr -> JSValue -> m (HashMap Text Value )
335
+ jsObjectToJSON :: (MonadCatch m , MonadIO m ) => JSContextPtr -> JSValue -> m (KeyMap Value )
337
336
jsObjectToJSON ctxPtr obj = do
338
337
let flags = unJSGPNMask $ jsGPNStringMask .|. jsGPNSymbolMask .|. jsGPNEnumOnly
339
338
properties <- liftIO $ malloc
340
- plen <- jsGetOwnPropertyNames ctxPtr obj properties flags
339
+ plen <- jsGetOwnPropertyNames ctxPtr obj properties flags
341
340
`catch` (\ (e:: SomeJSRuntimeException ) -> do
342
341
liftIO $ free properties
343
342
throwM e
@@ -352,8 +351,8 @@ jsObjectToJSON ctxPtr obj = do
352
351
cleanup properties plen
353
352
return res
354
353
where
355
- collectVals :: (MonadCatch m , MonadIO m ) => Ptr (Ptr JSPropertyEnum ) -> JSValueConstPtr -> Int -> Int -> m (HashMap Text Value )
356
- collectVals properties objPtr ! index end
354
+ collectVals :: (MonadCatch m , MonadIO m ) => Ptr (Ptr JSPropertyEnum ) -> JSValueConstPtr -> Int -> Int -> m (KeyMap Value )
355
+ collectVals properties objPtr ! index end
357
356
| index < end = do
358
357
let i = fromIntegral index
359
358
@@ -364,7 +363,7 @@ jsObjectToJSON ctxPtr obj = do
364
363
liftIO $ jsFreeValue ctxPtr key'
365
364
return res
366
365
367
- case key of
366
+ case key of
368
367
String k -> do
369
368
val <- do
370
369
val' <- liftIO $ C. withPtr_ $ \ ptr ->
@@ -375,7 +374,7 @@ jsObjectToJSON ctxPtr obj = do
375
374
return res
376
375
377
376
xs <- collectVals properties objPtr (index+ 1 ) end
378
- return $ insert k val xs
377
+ return $ insert ( Key. fromText k) val xs
379
378
x -> throwM $ InternalError $ " Could not get property name" <> toS (encode x)
380
379
381
380
| otherwise = return empty
@@ -410,26 +409,26 @@ jsGetPropertyStr ctxPtr val str = liftIO $
410
409
411
410
jsGetOwnPropertyNames :: (MonadThrow m , MonadIO m ) => JSContextPtr -> JSValue -> Ptr (Ptr JSPropertyEnum ) -> CInt -> m Int
412
411
jsGetOwnPropertyNames ctxPtr val properties flags = do
413
- (len,code) <- liftIO $ C. withPtr $ \ plen -> with val $ \ valPtr ->
412
+ (len,code) <- liftIO $ C. withPtr $ \ plen -> with val $ \ valPtr ->
414
413
[C. block | int { return JS_GetOwnPropertyNames($(JSContext *ctxPtr), $(JSPropertyEnum **properties), $(uint32_t *plen), *$(JSValueConst *valPtr), $(int flags)); } |]
415
414
if code == 0 then return (fromIntegral len)
416
415
else throwM $ InternalError " Could not get object properties"
417
416
418
417
419
418
jsCall :: JSContextPtr -> JSValue -> CInt -> (Ptr JSValue ) -> IO JSValue
420
- jsCall ctxt fun_obj argc argv = C. withPtr_ $ \ res -> with fun_obj $ \ funPtr ->
419
+ jsCall ctxt fun_obj argc argv = C. withPtr_ $ \ res -> with fun_obj $ \ funPtr ->
421
420
[C. block | void { *$(JSValue *res) = JS_Call($(JSContext *ctxt), *$(JSValueConst *funPtr), JS_NULL, $(int argc), $(JSValueConst *argv)); } |]
422
421
423
422
424
423
jsEval :: JSContextPtr -> CString -> CSize -> CString -> CInt -> IO JSValue
425
- jsEval ctxPtr input input_len filename eval_flags = C. withPtr_ $ \ ptr ->
424
+ jsEval ctxPtr input input_len filename eval_flags = C. withPtr_ $ \ ptr ->
426
425
[C. block | void { *$(JSValue *ptr) = JS_Eval($(JSContext *ctxPtr), $(const char *input), $(size_t input_len), $(const char *filename), $(int eval_flags)); } |]
427
426
428
427
429
428
evalRaw :: JSContextPtr -> JSEvalType -> ByteString -> IO JSValue
430
- evalRaw ctx eTyp code =
429
+ evalRaw ctx eTyp code =
431
430
useAsCString " script.js" $ \ cfilename ->
432
- useAsCStringLen code $ \ (ccode, ccode_len) ->
431
+ useAsCStringLen code $ \ (ccode, ccode_len) ->
433
432
jsEval ctx ccode (fromIntegral ccode_len) cfilename (toCType eTyp)
434
433
435
434
@@ -460,7 +459,7 @@ evalAs_ eTyp code = do
460
459
461
460
462
461
{-|
463
- More efficient than 'eval' if we don't care about the value of the expression,
462
+ More efficient than 'eval' if we don't care about the value of the expression,
464
463
e.g. if we are evaluating a function definition or performing other side-effects such as
465
464
printing to console/modifying state.
466
465
-}
@@ -511,7 +510,7 @@ callRaw ctxPtr funName args = do
511
510
ty <- jsIs ctxPtr fun
512
511
case ty of
513
512
JSTypeFromTag JSTagException -> do
514
- err <- getErrorMessage ctxPtr
513
+ err <- getErrorMessage ctxPtr
515
514
liftIO $ jsFreeValue ctxPtr fun
516
515
throwM $ JSException " callRaw" err
517
516
JSTypeFromTag JSTagUndefined -> throwM $ JSValueUndefined $ toS funName
@@ -573,7 +572,7 @@ quickjs f = do
573
572
_rt <- jsNewRuntime
574
573
_ctx <- jsNewContext _rt
575
574
576
- [C. block | void {
575
+ [C. block | void {
577
576
js_std_add_helpers($(JSContext *_ctx), -1, NULL);
578
577
} |]
579
578
return (_rt, _ctx)
@@ -595,15 +594,15 @@ This problem does not occur when running via Main.hs, if compiled as single thre
595
594
For more info see the paper [Extending the Haskell Foreign Function Interface with Concurrency](https://simonmar.github.io/bib/papers/conc-ffi.pdf)
596
595
-}
597
596
quickjsMultithreaded :: MonadUnliftIO m => ReaderT (Ptr JSContext ) m b -> m b
598
- quickjsMultithreaded f
597
+ quickjsMultithreaded f
599
598
| rtsSupportsBoundThreads = do
600
599
(u :: UnliftIO m ) <- askUnliftIO
601
-
600
+
602
601
liftIO $ runInBoundThread $ do
603
602
rt <- jsNewRuntime
604
603
ctx <- jsNewContext rt
605
604
606
- [C. block | void {
605
+ [C. block | void {
607
606
js_std_add_helpers($(JSContext *ctx), -1, NULL);
608
607
} |]
609
608
@@ -615,4 +614,3 @@ quickjsMultithreaded f
615
614
cleanup ctx rt = do
616
615
jsFreeContext ctx
617
616
jsFreeRuntime rt
618
-
0 commit comments