content: {-# LANGUAGE LambdaCase        #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE RankNTypes        #-}
  {- |
     Module      : Text.Pandoc.Lua.Run
     Copyright   : Copyright © 2017-2024 Albert Krewinkel
     License     : GPL-2.0-or-later
     Maintainer  : Albert Krewinkel <albert+pandoc@tarleb.com>
  
  Run code in the Lua interpreter.
  -}
  module Text.Pandoc.Lua.Run
    ( runLua
    , runLuaNoEnv
    , runLuaWith
    ) where
  
  import Control.Monad.Catch (try)
  import Control.Monad.Trans (MonadIO (..))
  import HsLua as Lua hiding (try)
  import Text.Pandoc.Class (PandocMonad (..))
  import Text.Pandoc.Error (PandocError)
  import Text.Pandoc.Lua.Global (Global (..), setGlobals)
  import Text.Pandoc.Lua.Init (initLua)
  import Text.Pandoc.Lua.PandocLua (PandocLua (..), liftPandocLua)
  
  -- | Run the Lua interpreter, using pandoc's default way of environment
  -- initialization.
  runLua :: (PandocMonad m, MonadIO m)
         => LuaE PandocError a -> m (Either PandocError a)
  runLua action = do
    runPandocLuaWith Lua.run . try $ do
      initLua
      liftPandocLua action
  
  runLuaWith :: (PandocMonad m, MonadIO m)
             => GCManagedState -> LuaE PandocError a -> m (Either PandocError a)
  runLuaWith luaState action = do
    runPandocLuaWith (withGCManagedState luaState) . try $ do
      initLua
      liftPandocLua action
  
  -- | Like 'runLua', but ignores all environment variables like @LUA_PATH@.
  runLuaNoEnv :: (PandocMonad m, MonadIO m)
              => LuaE PandocError a -> m (Either PandocError a)
  runLuaNoEnv action = do
    runPandocLuaWith Lua.run . try $ do
      liftPandocLua $ do
        -- This is undocumented, but works -- the code is adapted from the
        -- `lua.c` sources for the default interpreter.
        Lua.pushboolean True
        Lua.setfield Lua.registryindex "LUA_NOENV"
      initLua
      liftPandocLua action
  
  -- | Evaluate a @'PandocLua'@ computation, running all contained Lua
  -- operations.
  runPandocLuaWith :: (PandocMonad m, MonadIO m)
                   => (forall b. LuaE PandocError b -> IO b)
                   -> PandocLua a
                   -> m a
  runPandocLuaWith runner pLua = do
    origState <- getCommonState
    let globals = defaultGlobals
    (result, newState) <- liftIO . runner . unPandocLua $ do
      putCommonState origState
      liftPandocLua $ setGlobals globals
      r <- pLua
      c <- getCommonState
      return (r, c)
    putCommonState newState
    return result
  
  -- | Global variables which should always be set.
  defaultGlobals :: [Global]
  defaultGlobals =
    [ PANDOC_API_VERSION
    , PANDOC_STATE
    , PANDOC_VERSION
    ]
  