{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Language.JavaScript.Inline.Core.Export where

import qualified Data.ByteString.Lazy as LBS
import Data.Proxy
import Language.JavaScript.Inline.Core.Class
import Language.JavaScript.Inline.Core.Dict
import Language.JavaScript.Inline.Core.Message
import Language.JavaScript.Inline.Core.Session

-- | The class of Haskell functions which can be exported as JavaScript
-- functions. The Haskell function type should be @a -> b -> .. -> IO r@, where
-- the arguments @a@, @b@, etc are 'FromJS' instances, and the result @r@ is
-- 'ToJS' instance.
class Export f where
  exportArgsFromJS :: Proxy f -> [Dict FromJS]
  exportMonomorphize :: Session -> f -> [LBS.ByteString] -> IO JSExpr

instance ToJS r => Export (IO r) where
  exportArgsFromJS :: Proxy (IO r) -> [Dict FromJS]
exportArgsFromJS Proxy (IO r)
_ = []
  exportMonomorphize :: Session -> IO r -> [ByteString] -> IO JSExpr
exportMonomorphize Session
_ IO r
m [] = r -> JSExpr
forall a. ToJS a => a -> JSExpr
toJS (r -> JSExpr) -> IO r -> IO JSExpr
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO r
m
  exportMonomorphize Session
_ IO r
_ [ByteString]
_ = String -> IO JSExpr
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Language.JavaScript.Inline.Core.Export: impossible"

instance (FromJS a, Export b) => Export (a -> b) where
  exportArgsFromJS :: Proxy (a -> b) -> [Dict FromJS]
exportArgsFromJS Proxy (a -> b)
_ =
    Proxy a -> Dict FromJS
forall (c :: * -> Constraint) a. c a => Proxy a -> Dict c
Dict (Proxy a
forall k (t :: k). Proxy t
Proxy @a) Dict FromJS -> [Dict FromJS] -> [Dict FromJS]
forall a. a -> [a] -> [a]
: Proxy b -> [Dict FromJS]
forall f. Export f => Proxy f -> [Dict FromJS]
exportArgsFromJS (Proxy b
forall k (t :: k). Proxy t
Proxy @b)
  exportMonomorphize :: Session -> (a -> b) -> [ByteString] -> IO JSExpr
exportMonomorphize Session
s a -> b
f (ByteString
x : [ByteString]
xs) = do
    a
a <- Session -> ByteString -> IO a
forall a. FromJS a => Session -> ByteString -> IO a
fromJS Session
s ByteString
x
    Session -> b -> [ByteString] -> IO JSExpr
forall f. Export f => Session -> f -> [ByteString] -> IO JSExpr
exportMonomorphize Session
s (a -> b
f a
a) [ByteString]
xs
  exportMonomorphize Session
_ a -> b
_ [ByteString]
_ = String -> IO JSExpr
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Language.JavaScript.Inline.Core.Export: impossible"