git.iko.soy/typeable/pandoc
on master help sign in
Lua filters: improve error messages

Provide more context about the task which caused an error.

commit6528082401100cd8ef26c8dc3e953b960a997827 authorAlbert Krewinkel <albert@zeitkraut.de> dateFri 12 Jan 2018, 21:26 (9 years ago) parentf130109
5 files changed+45−15
pandoc.cabal+1 src/Text/Pandoc/Lua/Filter.hs+6−2 src/Text/Pandoc/Lua/StackInstances.hs+19−13 src/Text/Pandoc/Lua/Util.hs+9 test/Tests/Lua.hs+10
pandoc.cabal+1
@@ -347,6 +347,7 @@ library
347347 unordered-containers >= 0.2 && < 0.3,
348348 parsec >= 3.1 && < 3.2,
349349 mtl >= 2.2 && < 2.3,
350+ exceptions >= 0.8 && < 0.9,
350351 filepath >= 1.1 && < 1.5,
351352 process >= 1.2.3 && < 1.7,
352353 directory >= 1 && < 1.4,
src/Text/Pandoc/Lua/Filter.hs+6−2
@@ -11,6 +11,7 @@ module Text.Pandoc.Lua.Filter ( LuaFilterFunction
1111 , inlineElementNames
1212 ) where
1313import Control.Monad (mplus, unless, when, (>=>))
14+import Control.Monad.Catch (finally)
1415import Text.Pandoc.Definition
1516import Data.Foldable (foldrM)
1617import Data.Map (Map)
@@ -22,6 +23,7 @@ import Text.Pandoc.Walk (walkM, Walkable)
2223import Data.Data (Data, DataType, dataTypeConstrs, dataTypeName, dataTypeOf,
2324 showConstr, toConstr, tyconUQname)
2425import Text.Pandoc.Lua.StackInstances()
26+import Text.Pandoc.Lua.Util (typeCheck)
2527
2628type FunctionMap = Map String LuaFilterFunction
2729
@@ -65,7 +67,7 @@ registerFilterFunction idx = do
6567
6668elementOrList :: FromLuaStack a => a -> Lua [a]
6769elementOrList x = do
68− let topOfStack = Lua.StackIndex (-1)
70+ let topOfStack = Lua.stackTop
6971 elementUnchanged <- Lua.isnil topOfStack
7072 if elementUnchanged
7173 then [x] <$ Lua.pop 1
@@ -73,7 +75,9 @@ elementOrList x = do
7375 mbres <- Lua.peekEither topOfStack
7476 case mbres of
7577 Right res -> [res] <$ Lua.pop 1
76− Left _ -> Lua.toList topOfStack <* Lua.pop 1
78+ Left _ -> do
79+ typeCheck Lua.stackTop Lua.TypeTable
80+ Lua.toList topOfStack `finally` Lua.pop 1
7781
7882-- | Try running a filter for the given element
7983tryFilter :: (Data a, FromLuaStack a, ToLuaStack a)
src/Text/Pandoc/Lua/StackInstances.hs+19−13
@@ -35,13 +35,15 @@ module Text.Pandoc.Lua.StackInstances () where
3535
3636import Control.Applicative ((<|>))
3737import Control.Monad (when)
38+import Control.Monad.Catch (finally)
3839import Data.Data (showConstr, toConstr)
3940import Data.Foldable (forM_)
4041import Foreign.Lua (FromLuaStack (peek), Lua, LuaInteger, LuaNumber, StackIndex,
4142 ToLuaStack (push), Type (..), throwLuaError, tryLua)
4243import Text.Pandoc.Definition
4344import Text.Pandoc.Extensions (Extensions)
44−import Text.Pandoc.Lua.Util (adjustIndexBy, getTable, pushViaConstructor)
45+import Text.Pandoc.Lua.Util (adjustIndexBy, getTable, pushViaConstructor,
46+ typeCheck)
4547import Text.Pandoc.Options (ReaderOptions (..), TrackChanges)
4648import Text.Pandoc.Shared (Element (Blk, Sec), safeRead)
4749
@@ -49,21 +51,27 @@ import qualified Foreign.Lua as Lua
4951import qualified Data.Set as Set
5052import qualified Text.Pandoc.Lua.Util as LuaUtil
5153
54+defineHowTo :: String -> Lua a -> Lua a
55+defineHowTo ctx op = op `Lua.modifyLuaError` (("Could not " ++ ctx ++ ": ") ++)
56+
5257instance ToLuaStack Pandoc where
5358 push (Pandoc meta blocks) =
5459 pushViaConstructor "Pandoc" blocks meta
5560
5661instance FromLuaStack Pandoc where
57− peek idx = do
62+ peek idx = defineHowTo "get Pandoc value" $ do
63+ typeCheck idx Lua.TypeTable
5864 blocks <- getTable idx "blocks"
59− meta <- getTable idx "meta"
65+ meta <- Lua.getfield idx "meta" *> (Lua.peek Lua.stackTop `finally` Lua.pop 1)
6066 return $ Pandoc meta blocks
6167
6268instance ToLuaStack Meta where
6369 push (Meta mmap) =
6470 pushViaConstructor "Meta" mmap
6571instance FromLuaStack Meta where
66− peek idx = Meta <$> peek idx
72+ peek idx = defineHowTo "get Meta value" $ do
73+ typeCheck idx Lua.TypeTable
74+ Meta <$> peek idx
6775
6876instance ToLuaStack MetaValue where
6977 push = pushMetaValue
@@ -160,7 +168,7 @@ pushMetaValue = \case
160168
161169-- | Interpret the value at the given stack index as meta value.
162170peekMetaValue :: StackIndex -> Lua MetaValue
163−peekMetaValue idx = do
171+peekMetaValue idx = defineHowTo "get MetaValue" $ do
164172 -- Get the contents of an AST element.
165173 let elementContent :: FromLuaStack a => Lua a
166174 elementContent = peek idx
@@ -209,7 +217,8 @@ pushBlock = \case
209217
210218-- | Return the value at the given index as block if possible.
211219peekBlock :: StackIndex -> Lua Block
212−peekBlock idx = do
220+peekBlock idx = defineHowTo "get Block value" $ do
221+ typeCheck idx Lua.TypeTable
213222 tag <- getTag idx
214223 case tag of
215224 "BlockQuote" -> BlockQuote <$> elementContent
@@ -260,7 +269,8 @@ pushInline = \case
260269
261270-- | Return the value at the given index as inline if possible.
262271peekInline :: StackIndex -> Lua Inline
263−peekInline idx = do
272+peekInline idx = defineHowTo "get Inline value" $ do
273+ typeCheck idx Lua.TypeTable
264274 tag <- getTag idx
265275 case tag of
266276 "Cite" -> uncurry Cite <$> elementContent
@@ -296,11 +306,7 @@ getTag idx = do
296306 hasMT <- Lua.getmetatable idx
297307 push "tag"
298308 if hasMT then Lua.rawget (-2) else Lua.rawget (idx `adjustIndexBy` 1)
299− r <- tryLua (peek (-1))
300− Lua.settop top
301− case r of
302− Left (Lua.LuaException err) -> throwLuaError err
303− Right res -> return res
309+ peek Lua.stackTop `finally` Lua.settop top
304310
305311withAttr :: (Attr -> a -> b) -> (LuaAttr, a) -> b
306312withAttr f (attributes, x) = f (fromLuaAttr attributes) x
@@ -313,7 +319,7 @@ instance ToLuaStack LuaAttr where
313319 pushViaConstructor "Attr" id' classes kv
314320
315321instance FromLuaStack LuaAttr where
316− peek idx = LuaAttr <$> peek idx
322+ peek idx = defineHowTo "get Attr value" (LuaAttr <$> peek idx)
317323
318324--
319325-- Hierarchical elements
src/Text/Pandoc/Lua/Util.hs+9
@@ -36,6 +36,7 @@ module Text.Pandoc.Lua.Util
3636 , getRawInt
3737 , setRawInt
3838 , addRawInt
39+ , typeCheck
3940 , raiseError
4041 , popValue
4142 , PushViaCall
@@ -100,6 +101,14 @@ setRawInt idx key value = do
100101addRawInt :: ToLuaStack a => Int -> a -> Lua ()
101102addRawInt = setRawInt (-1)
102103
104+typeCheck :: StackIndex -> Lua.Type -> Lua ()
105+typeCheck idx expected = do
106+ actual <- Lua.ltype idx
107+ when (actual /= expected) $ do
108+ expName <- Lua.typename expected
109+ actName <- Lua.typename actual
110+ Lua.throwLuaError $ "expected " ++ expName ++ " but got " ++ actName ++ "."
111+
103112raiseError :: ToLuaStack a => a -> Lua NumResults
104113raiseError e = do
105114 Lua.push e
test/Tests/Lua.hs+10
@@ -123,6 +123,16 @@ tests = map (localOption (QuickCheckTests 20))
123123 Lua.getglobal "PANDOC_API_VERSION"
124124 Lua.liftIO . assertEqual "pandoc-types version is wrong" versionNums
125125 =<< Lua.peek Lua.stackTop
126+
127+ , testCase "informative error messages" . runPandocLua' $ do
128+ Lua.pushboolean True
129+ err <- Lua.peekEither Lua.stackTop :: Lua.Lua (Either String Pandoc)
130+ case err of
131+ Left msg -> do
132+ let expectedMsg = "Could not get Pandoc value: "
133+ ++ "expected table but got boolean."
134+ Lua.liftIO $ assertEqual "unexpected error message" expectedMsg msg
135+ Right _ -> error "Getting a Pandoc element from a bool should fail."
126136 ]
127137
128138assertFilterConversion :: String -> FilePath -> Pandoc -> Pandoc -> Assertion