packages feed

dovetail-0.1.0.0: src/Dovetail/FFI.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedStrings   #-}

module Dovetail.FFI 
  ( 
  -- * Foreign function interface
    FFI(..)
  , ForeignImport(..)
  , toEnv
  , toExterns
  ) where

import Data.Map qualified as Map  
import Dovetail.Types 
import Language.PureScript qualified as P
import Language.PureScript.Externs qualified as Externs
  
-- | Describes a module which is implemented in Haskell, and made available
-- to PureScript code using its foreign function interface. 
--
-- Right now, this consists only of foreign value declarations, even though
-- the FFI supports other forms of interop.
--
-- Values of this type can be constructed directly, but in many cases it is
-- simpler to use the "Dovetail.FFI.Builder" module
-- instead.
--
-- Values of this type can be consumed by the 'toExterns' and 'toEnv' functions,
-- and their results passed to the PureScript APIs or the low-level functions in
-- "Dovetail.Evaluate" and "Dovetail.Build", 
-- directly, but it is more likely that you will use values of this type with the 
-- higher-level 'Dovetail.ffi' function.
data FFI m = FFI
  { ffi_moduleName :: P.ModuleName
  -- ^ The module name for the module being implemented in Haskell.
  , ffi_values :: [ForeignImport m]
  -- ^ A list of values implemented in Haskell in this module.
  }
  
-- | A single value implemented in a foreign Haskell module.
data ForeignImport m = ForeignImport
  { fv_name :: P.Ident
  -- ^ The name of this value in PureScript code
  , fv_type :: P.SourceType
  -- ^ The PureScript type of this value
  , fv_value :: Value m
  -- ^ The value itself
  }

-- | Convert a foreign module into a PureScript externs file, for use during
-- separate compilation.
--
-- For advanced use cases, the result may be used with the functions in the 
-- "Dovetail.Build" module.
toExterns :: FFI m -> P.ExternsFile
toExterns (FFI mn vals) =
  Externs.ExternsFile   
    { Externs.efVersion      = "0.14.2"
    , Externs.efModuleName   = mn
    , Externs.efExports      = [P.ValueRef P.nullSourceSpan name | ForeignImport name _ _ <- vals]
    , Externs.efImports      = [ P.ExternsImport (P.ModuleName "Prim") P.Implicit (Just (P.ModuleName "Prim"))
                               , P.ExternsImport (P.ModuleName "Prim") P.Implicit Nothing
                               ]
    , Externs.efFixities     = []
    , Externs.efTypeFixities = []
    , Externs.efDeclarations = [Externs.EDValue name ty | ForeignImport name ty _ <- vals]
    , Externs.efSourceSpan   = P.nullSourceSpan
    } 

-- | Convert a foreign module into an evaluation environment.
--
-- For advanced use cases, the result may be used with the functions in the 
-- "Dovetail.Evaluate" module.
toEnv :: FFI m -> Env m
toEnv (FFI mn vals) = 
  Map.fromList [ (P.mkQualified name mn, val) | ForeignImport name _ val <- vals ]