-- | C code generator.  This module can convert a correct ImpCode
-- program to an equivalent C program.  This C program is expected to
-- be converted to WebAssembly, so we also produce the intended
-- JavaScript wrapper.
module Futhark.CodeGen.Backends.SequentialWASM
  ( compileProg,
    runServer,
    libraryExports,
    GC.CParts (..),
    GC.asLibrary,
    GC.asExecutable,
    GC.asServer,
  )
where

import Data.Maybe
import Data.Text qualified as T
import Futhark.CodeGen.Backends.GenericC qualified as GC
import Futhark.CodeGen.Backends.GenericWASM
import Futhark.CodeGen.Backends.SequentialC.Boilerplate
import Futhark.CodeGen.ImpCode.Sequential qualified as Imp
import Futhark.CodeGen.ImpGen.Sequential qualified as ImpGen
import Futhark.IR.SeqMem
import Futhark.MonadFreshNames

-- | Compile Futhark program to wasm program (some assembly
-- required).
--
-- The triple that is returned consists of
--
-- * Generated C code (to be passed to Emscripten).
--
-- * JavaScript wrapper code that presents a nicer interface to the
--   Emscripten-produced code (this should be put in a @.class.js@
--   file by itself).
--
-- * Options that should be passed to @emcc@.
compileProg :: MonadFreshNames m => T.Text -> Prog SeqMem -> m (ImpGen.Warnings, (GC.CParts, T.Text, [String]))
compileProg :: forall (m :: * -> *).
MonadFreshNames m =>
Text -> Prog SeqMem -> m (Warnings, (CParts, Text, [String]))
compileProg Text
version Prog SeqMem
prog = do
  (Warnings
ws, Program
prog') <- forall (m :: * -> *).
MonadFreshNames m =>
Prog SeqMem -> m (Warnings, Program)
ImpGen.compileProg Prog SeqMem
prog

  CParts
prog'' <-
    forall (m :: * -> *) op.
MonadFreshNames m =>
Text
-> Text
-> Operations op ()
-> CompilerM op () ()
-> Text
-> (Space, [Space])
-> [Option]
-> Definitions op
-> m CParts
GC.compileProg
      Text
"wasm"
      Text
version
      Operations Sequential ()
operations
      forall op s. CompilerM op s ()
generateBoilerplate
      Text
""
      (Space
DefaultSpace, [Space
DefaultSpace])
      []
      Program
prog'
  forall (f :: * -> *) a. Applicative f => a -> f a
pure (Warnings
ws, (CParts
prog'', [JSEntryPoint] -> Text
javascriptWrapper (Program -> [JSEntryPoint]
fRepMyRep Program
prog'), [JSEntryPoint] -> [String]
emccExportNames (Program -> [JSEntryPoint]
fRepMyRep Program
prog')))
  where
    operations :: GC.Operations Imp.Sequential ()
    operations :: Operations Sequential ()
operations =
      forall op s. Operations op s
GC.defaultOperations
        { opsCompiler :: OpCompiler Sequential ()
GC.opsCompiler = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        }

fRepMyRep :: Imp.Program -> [JSEntryPoint]
fRepMyRep :: Program -> [JSEntryPoint]
fRepMyRep Program
prog =
  let Imp.Functions [(Name, Function Sequential)]
fs = forall a. Definitions a -> Functions a
Imp.defFuns Program
prog
      function :: FunctionT a -> Maybe JSEntryPoint
function (Imp.Function Maybe EntryPoint
entry [Param]
_ [Param]
_ Code a
_) = do
        Imp.EntryPoint Name
n [(Uniqueness, ExternalValue)]
res [((Name, Uniqueness), ExternalValue)]
args <- Maybe EntryPoint
entry
        forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$
          JSEntryPoint
            { name :: String
name = Name -> String
nameToString Name
n,
              parameters :: [String]
parameters = forall a b. (a -> b) -> [a] -> [b]
map (ExternalValue -> String
extToString forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) [((Name, Uniqueness), ExternalValue)]
args,
              ret :: [String]
ret = forall a b. (a -> b) -> [a] -> [b]
map (ExternalValue -> String
extToString forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) [(Uniqueness, ExternalValue)]
res
            }
   in forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (forall {a}. FunctionT a -> Maybe JSEntryPoint
function forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) [(Name, Function Sequential)]
fs