{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Text.Pandoc.Lua.ErrorConversion
  ( errorConversion
  ) where
import Foreign.Lua (Lua (..), NumResults)
import Text.Pandoc.Error (PandocError (PandocLuaError))
import Text.Pandoc.Lua.Marshaling.PandocError (pushPandocError, peekPandocError)
import qualified Control.Monad.Catch as Catch
import qualified Data.Text as T
import qualified Foreign.Lua as Lua
errorConversion :: Lua.ErrorConversion
errorConversion = Lua.ErrorConversion
  { Lua.addContextToException = addContextToException
  , Lua.alternative           = alternative
  , Lua.errorToException      = errorToException
  , Lua.exceptionToError      = exceptionToError
  }
errorToException :: forall a . Lua.State -> IO a
errorToException l = Lua.unsafeRunWith l $ do
  err <- peekPandocError Lua.stackTop
  Lua.pop 1
  Catch.throwM err
alternative :: forall a . Lua a -> Lua a -> Lua a
alternative x y = Catch.try x >>= \case
  Left (_ :: PandocError) -> y
  Right x' -> return x'
addContextToException :: forall a . String -> Lua a -> Lua a
addContextToException ctx op = op `Catch.catch` \case
  PandocLuaError msg -> Catch.throwM $ PandocLuaError (T.pack ctx <> msg)
  e -> Catch.throwM e
exceptionToError :: Lua NumResults -> Lua NumResults
exceptionToError op = op `Catch.catch` \e -> do
  pushPandocError e
  Lua.error