@@ -40,12 +40,14 @@ module Text.Pandoc.Lua.Util
4040 , loadScriptFromDataDir
4141 , defineHowTo
4242 , throwTopMessageAsError'
43+ , callWithTraceback
44+ , dofileWithTraceback
4345 ) where
4446
4547import Prelude
4648import Control.Monad (unless, when)
47−import Foreign.Lua ( Lua, NumArgs, Peekable, Pushable, StackIndex
48− , ToHaskellFunction )
49+import Foreign.Lua ( Lua, NumArgs, NumResults, Peekable, Pushable, StackIndex
50+ , Status, ToHaskellFunction )
4951import Text.Pandoc.Class (readDataFile, runIOorExplode, setUserDataDir)
5052
5153import qualified Foreign.Lua as Lua
@@ -137,3 +139,35 @@ throwTopMessageAsError' modifier = do
137139-- | Mark the context of a Lua computation for better error reporting.
138140defineHowTo :: String -> Lua a -> Lua a
139141defineHowTo ctx = Lua.withExceptionMessage (("Could not " <> ctx <> ": ") <>)
142+
143+-- | Like @'Lua.pcall'@, but uses a predefined error handler which adds a
144+-- traceback on error.
145+pcallWithTraceback :: NumArgs -> NumResults -> Lua Status
146+pcallWithTraceback nargs nresults = do
147+ let traceback' :: Lua NumResults
148+ traceback' = do
149+ l <- Lua.state
150+ msg <- Lua.tostring' (Lua.nthFromBottom 1)
151+ Lua.traceback l (Just (UTF8.toString msg)) 2
152+ return 1
153+ tracebackIdx <- Lua.absindex (Lua.nthFromTop (Lua.fromNumArgs nargs + 1))
154+ Lua.pushHaskellFunction traceback'
155+ Lua.insert tracebackIdx
156+ result <- Lua.pcall nargs nresults (Just tracebackIdx)
157+ Lua.remove tracebackIdx
158+ return result
159+
160+-- | Like @'Lua.call'@, but adds a traceback to the error message (if any).
161+callWithTraceback :: NumArgs -> NumResults -> Lua ()
162+callWithTraceback nargs nresults = do
163+ result <- pcallWithTraceback nargs nresults
164+ when (result /= Lua.OK) Lua.throwTopMessage
165+
166+-- | Run the given string as a Lua program, while also adding a traceback to the
167+-- error message if an error occurs.
168+dofileWithTraceback :: FilePath -> Lua Status
169+dofileWithTraceback fp = do
170+ loadRes <- Lua.loadfile fp
171+ case loadRes of
172+ Lua.OK -> pcallWithTraceback 0 Lua.multret
173+ _ -> return loadRes