hs-duktape-1.0.0: library/Scripting/Duktape/Raw.hs
{-# LANGUAGE OverloadedStrings, UnicodeSyntax, CPP #-}
{-# LANGUAGE ForeignFunctionInterface, CApiFFI, EmptyDataDecls #-}
module Scripting.Duktape.Raw where
import Foreign(peek, poke, malloc, free)
import Foreign.C.Types
import Foreign.C.String
import Foreign.Ptr
import Foreign.ForeignPtr hiding (newForeignPtr, addForeignPtrFinalizer)
import Foreign.Concurrent (newForeignPtr, addForeignPtrFinalizer)
import Control.Concurrent.MVar (withMVar, newMVar, MVar)
foreign import capi "duktape.h value DUK_TYPE_NONE" c_DUK_TYPE_NONE ∷ CInt
foreign import capi "duktape.h value DUK_TYPE_UNDEFINED" c_DUK_TYPE_UNDEFINED ∷ CInt
foreign import capi "duktape.h value DUK_TYPE_NULL" c_DUK_TYPE_NULL ∷ CInt
foreign import capi "duktape.h value DUK_TYPE_BOOLEAN" c_DUK_TYPE_BOOLEAN ∷ CInt
foreign import capi "duktape.h value DUK_TYPE_NUMBER" c_DUK_TYPE_NUMBER ∷ CInt
foreign import capi "duktape.h value DUK_TYPE_STRING" c_DUK_TYPE_STRING ∷ CInt
foreign import capi "duktape.h value DUK_TYPE_OBJECT" c_DUK_TYPE_OBJECT ∷ CInt
foreign import capi "duktape.h value DUK_TYPE_BUFFER" c_DUK_TYPE_BUFFER ∷ CInt
foreign import capi "duktape.h value DUK_TYPE_POINTER" c_DUK_TYPE_POINTER ∷ CInt
foreign import capi "duktape.h value DUK_TYPE_LIGHTFUNC" c_DUK_TYPE_LIGHTFUNC ∷ CInt
-- Duktape return vals
foreign import capi "duktape.h value DUK_RET_TYPE_ERROR" c_DUK_RET_TYPE_ERROR ∷ CInt
data DuktapeHeap
type DuktapeCtx = MVar (ForeignPtr DuktapeHeap)
type DukAllocFunction = Ptr () → CSize → IO (Ptr ())
type DukReallocFunction = Ptr () → Ptr () → CSize → IO (Ptr ())
type DukFreeFunction = Ptr () → Ptr () → IO ()
type DukFatalFunction = Ptr DuktapeHeap → CInt → CString → IO ()
type DukExecTimeoutCheckFunction = Ptr () → IO (CUInt)
type TimeoutCheck = IO Bool
type TimeoutCheckWrapped = FunPtr (IO Bool)
type CheckActionUData = Ptr TimeoutCheckWrapped
newtype InternalUData = InternalUData { getInternalUData ∷ Ptr () }
-- Static callback
foreign export ccall "hsduk_exec_timeout_check" execTimeoutCheck ∷ DukExecTimeoutCheckFunction
-- | Will always be invoked regularly by duktape runtime but returns false (do not timeout)
-- unless it receives a TimeoutCheck through udata
execTimeoutCheck ∷ DukExecTimeoutCheckFunction
execTimeoutCheck udata = if udata == nullPtr then return 0 else invoke
where
checkAction ∷ CheckActionUData
checkAction = castPtr udata
invoke = do
action ← peek checkAction
result ← unwrapTimeoutCheck action
return $ if result then 1 else 0
-- FunPtr wrappers / unwrappers
foreign import ccall safe "wrapper"
c_wrapper ∷ (Ptr DuktapeHeap → IO CInt) → IO (FunPtr (Ptr DuktapeHeap → IO CInt))
foreign import ccall "dynamic"
unwrapTimeoutCheck ∷ TimeoutCheckWrapped → IO Bool
foreign import ccall safe "wrapper"
wrapTimeoutCheck ∷ (IO Bool) → IO TimeoutCheckWrapped
-- Heap lifecycle
foreign import capi safe "duktape.h duk_create_heap"
c_duk_create_heap ∷ FunPtr DukAllocFunction → FunPtr DukReallocFunction → FunPtr DukFreeFunction → Ptr () → FunPtr DukFatalFunction → IO (Ptr DuktapeHeap)
foreign import capi safe "duktape.h duk_destroy_heap"
c_duk_destroy_heap ∷ Ptr DuktapeHeap → IO ()
-- Evaluation
foreign import capi safe "duktape.h duk_eval_raw"
c_duk_eval_raw ∷ Ptr DuktapeHeap → CString → CSize → CUInt → IO CInt
foreign import capi safe "duktape.h duk_peval_lstring"
c_duk_peval_lstring ∷ Ptr DuktapeHeap → CString → CSize → IO CInt
foreign import capi safe "duktape.h duk_pcall_prop"
c_duk_pcall_prop ∷ Ptr DuktapeHeap → CInt → CInt → IO CInt
-- Managing the stack
foreign import capi safe "duktape.h duk_pop"
c_duk_pop ∷ Ptr DuktapeHeap → IO ()
-- Properties
foreign import capi safe "duktape.h duk_put_prop_index"
c_duk_put_prop_index ∷ Ptr DuktapeHeap → CInt → CInt → IO CInt
foreign import capi safe "duktape.h duk_put_prop_string"
c_duk_put_prop_string ∷ Ptr DuktapeHeap → CInt → CString → IO CInt
-- Pushing to the stack
foreign import capi safe "duktape.h duk_push_string"
c_duk_push_string ∷ Ptr DuktapeHeap → CString → IO CString
foreign import capi safe "duktape.h duk_push_lstring"
c_duk_push_lstring ∷ Ptr DuktapeHeap → CString → CSize → IO CString
foreign import capi safe "duktape.h duk_push_number"
c_duk_push_number ∷ Ptr DuktapeHeap → CDouble → IO ()
foreign import capi safe "duktape.h duk_push_boolean"
c_duk_push_boolean ∷ Ptr DuktapeHeap → CInt → IO ()
foreign import capi safe "duktape.h duk_push_null"
c_duk_push_null ∷ Ptr DuktapeHeap → IO ()
foreign import capi safe "duktape.h duk_push_array"
c_duk_push_array ∷ Ptr DuktapeHeap → IO CInt
foreign import capi safe "duktape.h duk_push_object"
c_duk_push_object ∷ Ptr DuktapeHeap → IO CInt
foreign import capi safe "duktape.h duk_push_c_function"
c_duk_push_c_function ∷ Ptr DuktapeHeap → FunPtr (Ptr DuktapeHeap → IO CInt) → CInt → IO CInt
foreign import capi safe "duktape.h duk_push_global_object"
c_duk_push_global_object ∷ Ptr DuktapeHeap → IO ()
foreign import capi safe "duktape.h duk_get_global_string"
c_duk_get_global_string ∷ Ptr DuktapeHeap → CString → IO CInt
-- Fetching from the stack
foreign import capi safe "duktape.h duk_safe_to_lstring"
c_duk_safe_to_lstring ∷ Ptr DuktapeHeap → CInt → Ptr CSize → IO CString
foreign import capi safe "duktape.h duk_safe_to_string"
c_duk_safe_to_string ∷ Ptr DuktapeHeap → CInt → IO CString
foreign import capi safe "duktape.h duk_get_string"
c_duk_get_string ∷ Ptr DuktapeHeap → CInt → IO CString
foreign import capi safe "duktape.h duk_get_lstring"
c_duk_get_lstring ∷ Ptr DuktapeHeap → CInt → Ptr CSize → IO CString
foreign import capi safe "duktape.h duk_get_int"
c_duk_get_int ∷ Ptr DuktapeHeap → CInt → IO CInt
foreign import capi safe "duktape.h duk_get_uint"
c_duk_get_uint ∷ Ptr DuktapeHeap → CInt → IO CUInt
foreign import capi safe "duktape.h duk_get_number"
c_duk_get_number ∷ Ptr DuktapeHeap → CInt → IO CDouble
foreign import capi safe "duktape.h duk_get_boolean"
c_duk_get_boolean ∷ Ptr DuktapeHeap → CInt → IO CInt
foreign import capi safe "duktape.h duk_get_type"
c_duk_get_type ∷ Ptr DuktapeHeap → CInt → IO CInt
-- Encoding/decoding
foreign import capi safe "duktape.h duk_json_encode"
c_duk_json_encode ∷ Ptr DuktapeHeap → CInt → IO CString
foreign import capi safe "duktape.h duk_json_decode"
c_duk_json_decode ∷ Ptr DuktapeHeap → CInt → IO ()
-- Debugging
foreign import capi safe "duktape.h duk_push_context_dump"
c_duk_push_context_dump ∷ Ptr DuktapeHeap → IO ()
-------------------------------------------------------------------------------------------------------
nullUData ∷ InternalUData
nullUData = InternalUData nullPtr
createHeap ∷ FunPtr DukAllocFunction → FunPtr DukReallocFunction → FunPtr DukFreeFunction → InternalUData → FunPtr DukFatalFunction → IO (Maybe DuktapeCtx)
createHeap allocf reallocf freef udata fatalf = do
ptr ← c_duk_create_heap allocf reallocf freef (getInternalUData udata) fatalf
if ptr /= nullPtr
then newForeignPtr ptr (c_duk_destroy_heap ptr) >>= newMVar >>= return . Just
else return Nothing
createHeapF ∷ FunPtr DukFatalFunction → IO (Maybe DuktapeCtx)
createHeapF = createHeap nullFunPtr nullFunPtr nullFunPtr nullUData
-- | A TimeoutCheck is an IO action that returns True when the current script evaluation
-- should timeout (interpreter throws RangeError).
createGovernedHeap ∷ FunPtr DukAllocFunction → FunPtr DukReallocFunction → FunPtr DukFreeFunction → TimeoutCheck → FunPtr DukFatalFunction → IO (Maybe DuktapeCtx)
createGovernedHeap allocf reallocf freef timeoutCheck fatalf = do
(udata, release) ← wrapTimeoutCheckUData timeoutCheck
mctx ← createHeap allocf reallocf freef udata fatalf
case mctx of
Just ctx → withMVar ctx $ \fptr → do
addForeignPtrFinalizer fptr release
return mctx
Nothing → return Nothing
where
-- TimeoutCheck is wrapped to pass as void* udata in `createHeap` and will be provided (by duktape)
-- back to `execTimeoutCheck` when the interpreter invokes that callback.
wrapTimeoutCheckUData ∷ TimeoutCheck → IO (InternalUData, IO ())
wrapTimeoutCheckUData check = do
wrapped ← wrapTimeoutCheck check
ptr ← malloc
poke ptr wrapped
let finalizers = free ptr >> freeHaskellFunPtr wrapped
return (InternalUData $ castPtr ptr, finalizers)