Use hslua v1.0.0

This commit is contained in:
Albert Krewinkel 2018-09-24 20:11:00 +02:00
parent 0272e63527
commit 56fe5b559e
No known key found for this signature in database
GPG key ID: 388DC0B21F631124
14 changed files with 260 additions and 312 deletions

View file

@ -372,8 +372,8 @@ library
blaze-html >= 0.9 && < 0.10,
blaze-markup >= 0.8 && < 0.9,
vector >= 0.10 && < 0.13,
hslua >= 0.9.5 && < 0.9.6,
hslua-module-text >= 0.1.2 && < 0.2,
hslua >= 1.0 && < 1.1,
hslua-module-text >= 0.2 && < 0.3,
binary >= 0.5 && < 0.10,
SHA >= 1.6 && < 1.7,
haddock-library >= 1.6 && < 1.7,
@ -615,7 +615,7 @@ test-suite test-pandoc
time >= 1.5 && < 1.10,
directory >= 1 && < 1.4,
filepath >= 1.1 && < 1.5,
hslua >= 0.9.5 && < 0.9.6,
hslua >= 1.0 && < 1.1,
process >= 1.2.3 && < 1.7,
temporary >= 1.1 && < 1.4,
Diff >= 0.2 && < 0.4,

View file

@ -1,4 +1,3 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 20172018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@ -16,6 +15,7 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{-# LANGUAGE NoImplicitPrelude #-}
{- |
Module : Text.Pandoc.Lua
Copyright : Copyright © 20172018 Albert Krewinkel
@ -34,12 +34,11 @@ module Text.Pandoc.Lua
import Prelude
import Control.Monad ((>=>))
import Foreign.Lua (Lua, LuaException (..))
import Foreign.Lua (Lua)
import Text.Pandoc.Class (PandocIO)
import Text.Pandoc.Definition (Pandoc)
import Text.Pandoc.Lua.Filter (LuaFilter, walkMWithLuaFilter)
import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath)
import Text.Pandoc.Lua.Util (popValue)
import Text.Pandoc.Lua.Init (LuaException (..), runPandocLua, registerScriptPath)
import Text.Pandoc.Options (ReaderOptions)
import qualified Foreign.Lua as Lua
@ -61,14 +60,14 @@ runLuaFilter' ropts filterPath format pd = do
top <- Lua.gettop
stat <- Lua.dofile filterPath
if stat /= Lua.OK
then Lua.throwTopMessageAsError
then Lua.throwTopMessage
else do
newtop <- Lua.gettop
-- Use the returned filters, or the implicitly defined global filter if
-- nothing was returned.
luaFilters <- if newtop - top >= 1
then Lua.peek Lua.stackTop
else Lua.getglobal "_G" *> fmap (:[]) popValue
else Lua.pushglobaltable *> fmap (:[]) Lua.popValue
runAll luaFilters pd
where
registerFormat = do

View file

@ -45,23 +45,22 @@ import Data.Data (Data, DataType, dataTypeConstrs, dataTypeName, dataTypeOf,
showConstr, toConstr, tyconUQname)
import Data.Foldable (foldrM)
import Data.Map (Map)
import Foreign.Lua (Lua, FromLuaStack, ToLuaStack)
import Foreign.Lua (Lua, Peekable, Pushable)
import Text.Pandoc.Definition
import Text.Pandoc.Lua.StackInstances ()
import Text.Pandoc.Lua.Util (typeCheck)
import Text.Pandoc.Walk (walkM, Walkable)
import qualified Data.Map.Strict as Map
import qualified Foreign.Lua as Lua
-- | Filter function stored at the given index in the registry
newtype LuaFilterFunction = LuaFilterFunction Int
-- | Filter function stored in the registry
newtype LuaFilterFunction = LuaFilterFunction Lua.Reference
-- | Collection of filter functions (at most one function per element
-- constructor)
newtype LuaFilter = LuaFilter (Map String LuaFilterFunction)
instance FromLuaStack LuaFilter where
instance Peekable LuaFilter where
peek idx = do
let constrs = metaFilterName
: pandocFilterNames
@ -87,10 +86,10 @@ registerFilterFunction = do
-- | Retrieve filter function from registry and push it to the top of the stack.
pushFilterFunction :: LuaFilterFunction -> Lua ()
pushFilterFunction (LuaFilterFunction fnRef) =
Lua.rawgeti Lua.registryindex fnRef
Lua.getref Lua.registryindex fnRef
elementOrList :: FromLuaStack a => a -> Lua [a]
elementOrList :: Peekable a => a -> Lua [a]
elementOrList x = do
let topOfStack = Lua.stackTop
elementUnchanged <- Lua.isnil topOfStack
@ -100,12 +99,10 @@ elementOrList x = do
mbres <- Lua.peekEither topOfStack
case mbres of
Right res -> [res] <$ Lua.pop 1
Left _ -> do
typeCheck Lua.stackTop Lua.TypeTable
Lua.toList topOfStack `finally` Lua.pop 1
Left _ -> Lua.peekList topOfStack `finally` Lua.pop 1
-- | Try running a filter for the given element
tryFilter :: (Data a, FromLuaStack a, ToLuaStack a)
tryFilter :: (Data a, Peekable a, Pushable a)
=> LuaFilter -> a -> Lua [a]
tryFilter (LuaFilter fnMap) x =
let filterFnName = showConstr (toConstr x)
@ -119,10 +116,10 @@ tryFilter (LuaFilter fnMap) x =
-- called with given element as argument and is expected to return an element.
-- Alternatively, the function can return nothing or nil, in which case the
-- element is left unchanged.
runFilterFunction :: ToLuaStack a => LuaFilterFunction -> a -> Lua ()
runFilterFunction :: Pushable a => LuaFilterFunction -> a -> Lua ()
runFilterFunction lf x = do
let errorPrefix = "Error while running filter function:\n"
(`Lua.modifyLuaError` (errorPrefix <>)) $ do
Lua.withExceptionMessage (errorPrefix <>) $ do
pushFilterFunction lf
Lua.push x
Lua.call 1 1
@ -178,7 +175,7 @@ metaFilterName = "Meta"
pandocFilterNames :: [String]
pandocFilterNames = ["Pandoc", "Doc"]
singleElement :: FromLuaStack a => a -> Lua a
singleElement :: Peekable a => a -> Lua a
singleElement x = do
elementUnchanged <- Lua.isnil (-1)
if elementUnchanged
@ -189,6 +186,6 @@ singleElement x = do
Right res -> res <$ Lua.pop 1
Left err -> do
Lua.pop 1
Lua.throwLuaError $
Lua.throwException $
"Error while trying to get a filter's return " ++
"value from lua stack.\n" ++ err

View file

@ -1,4 +1,3 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@ -16,6 +15,7 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{-# LANGUAGE NoImplicitPrelude #-}
{- |
Module : Text.Pandoc.Lua
Copyright : Copyright © 2017-2018 Albert Krewinkel
@ -40,7 +40,7 @@ import Control.Monad.Trans (MonadIO (..))
import Data.Data (Data, dataTypeConstrs, dataTypeOf, showConstr)
import Data.IORef (newIORef, readIORef)
import Data.Version (Version (versionBranch))
import Foreign.Lua (Lua, LuaException (..))
import Foreign.Lua (Lua)
import GHC.IO.Encoding (getForeignEncoding, setForeignEncoding, utf8)
import Paths_pandoc (version)
import Text.Pandoc.Class (PandocIO, getCommonState, getUserDataDir, getMediaBag,
@ -54,17 +54,22 @@ import qualified Foreign.Lua as Lua
import qualified Foreign.Lua.Module.Text as Lua
import qualified Text.Pandoc.Definition as Pandoc
-- | Lua error message
newtype LuaException = LuaException String deriving (Show)
-- | Run the lua interpreter, using pandoc's default way of environment
-- initialization.
runPandocLua :: Lua a -> PandocIO (Either LuaException a)
runPandocLua luaOp = do
luaPkgParams <- luaPackageParams
enc <- liftIO $ getForeignEncoding <* setForeignEncoding utf8
res <- liftIO $ Lua.runLuaEither (initLuaState luaPkgParams *> luaOp)
res <- liftIO $ Lua.runEither (initLuaState luaPkgParams *> luaOp)
liftIO $ setForeignEncoding enc
newMediaBag <- liftIO (readIORef (luaPkgMediaBag luaPkgParams))
setMediaBag newMediaBag
return res
return $ case res of
Left (Lua.Exception msg) -> Left (LuaException msg)
Right x -> Right x
-- | Generate parameters required to setup pandoc's lua environment.
luaPackageParams :: PandocIO LuaPackageParams

View file

@ -87,7 +87,7 @@ mediaDirectoryFn mbRef = do
zipWithM_ addEntry [1..] dirContents
return 1
where
addEntry :: Int -> (FilePath, MimeType, Int) -> Lua ()
addEntry :: Lua.Integer -> (FilePath, MimeType, Int) -> Lua ()
addEntry idx (fp, mimeType, contentLength) = do
Lua.newtable
Lua.push "path" *> Lua.push fp *> Lua.rawset (-3)

View file

@ -1,4 +1,3 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@ -17,6 +16,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-}
{- |
Module : Text.Pandoc.Lua.Module.Pandoc
Copyright : Copyright © 2017-2018 Albert Krewinkel
@ -36,13 +36,12 @@ import Control.Monad (when)
import Data.Default (Default (..))
import Data.Maybe (fromMaybe)
import Data.Text (pack)
import Foreign.Lua (ToLuaStack, FromLuaStack, Lua, NumResults, Optional, liftIO)
import Foreign.Lua (Lua, NumResults, Optional, Peekable, Pushable)
import System.Exit (ExitCode (..))
import Text.Pandoc.Class (runIO)
import Text.Pandoc.Definition (Block, Inline)
import Text.Pandoc.Lua.Filter (walkInlines, walkBlocks, LuaFilter)
import Text.Pandoc.Lua.StackInstances ()
import Text.Pandoc.Lua.Util (addFunction, loadScriptFromDataDir)
import Text.Pandoc.Walk (Walkable)
import Text.Pandoc.Options (ReaderOptions (readerExtensions))
import Text.Pandoc.Process (pipeProcess)
@ -57,14 +56,14 @@ import qualified Text.Pandoc.Lua.Util as LuaUtil
-- loaded.
pushModule :: Maybe FilePath -> Lua NumResults
pushModule datadir = do
loadScriptFromDataDir datadir "pandoc.lua"
addFunction "read" readDoc
addFunction "pipe" pipeFn
addFunction "walk_block" walkBlock
addFunction "walk_inline" walkInline
LuaUtil.loadScriptFromDataDir datadir "pandoc.lua"
LuaUtil.addFunction "read" readDoc
LuaUtil.addFunction "pipe" pipeFn
LuaUtil.addFunction "walk_block" walkBlock
LuaUtil.addFunction "walk_inline" walkInline
return 1
walkElement :: (ToLuaStack a, Walkable [Inline] a, Walkable [Block] a)
walkElement :: (Pushable a, Walkable [Inline] a, Walkable [Block] a)
=> a -> LuaFilter -> Lua a
walkElement x f = walkInlines f x >>= walkBlocks f
@ -82,7 +81,8 @@ readDoc content formatSpecOrNil = do
Right (reader, es) ->
case reader of
TextReader r -> do
res <- liftIO $ runIO $ r def{ readerExtensions = es } (pack content)
res <- Lua.liftIO . runIO $
r def{ readerExtensions = es } (pack content)
case res of
Right pd -> (1 :: NumResults) <$ Lua.push pd -- success, push Pandoc
Left s -> Lua.raiseError (show s) -- error while reading
@ -94,7 +94,7 @@ pipeFn :: String
-> BL.ByteString
-> Lua NumResults
pipeFn command args input = do
(ec, output) <- liftIO $ pipeProcess Nothing command args input
(ec, output) <- Lua.liftIO $ pipeProcess Nothing command args input
case ec of
ExitSuccess -> 1 <$ Lua.push output
ExitFailure n -> Lua.raiseError (PipeError command n output)
@ -105,14 +105,14 @@ data PipeError = PipeError
, pipeErrorOutput :: BL.ByteString
}
instance FromLuaStack PipeError where
instance Peekable PipeError where
peek idx =
PipeError
<$> (Lua.getfield idx "command" *> Lua.peek (-1) <* Lua.pop 1)
<*> (Lua.getfield idx "error_code" *> Lua.peek (-1) <* Lua.pop 1)
<*> (Lua.getfield idx "output" *> Lua.peek (-1) <* Lua.pop 1)
instance ToLuaStack PipeError where
instance Pushable PipeError where
push pipeErr = do
Lua.newtable
LuaUtil.addField "command" (pipeErrorCommand pipeErr)
@ -124,7 +124,7 @@ instance ToLuaStack PipeError where
pushPipeErrorMetaTable :: Lua ()
pushPipeErrorMetaTable = do
v <- Lua.newmetatable "pandoc pipe error"
when v $ addFunction "__tostring" pipeErrorMessage
when v $ LuaUtil.addFunction "__tostring" pipeErrorMessage
pipeErrorMessage :: PipeError -> Lua BL.ByteString
pipeErrorMessage (PipeError cmd errorCode output) = return $ mconcat

View file

@ -1,4 +1,3 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@ -16,6 +15,7 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{-# LANGUAGE NoImplicitPrelude #-}
{- |
Module : Text.Pandoc.Lua.Module.Utils
Copyright : Copyright © 2017-2018 Albert Krewinkel
@ -33,11 +33,11 @@ module Text.Pandoc.Lua.Module.Utils
import Prelude
import Control.Applicative ((<|>))
import Data.Default (def)
import Foreign.Lua (FromLuaStack, Lua, LuaInteger, NumResults)
import Foreign.Lua (Peekable, Lua, NumResults)
import Text.Pandoc.Class (runIO, setUserDataDir)
import Text.Pandoc.Definition (Pandoc, Meta, MetaValue, Block, Inline)
import Text.Pandoc.Lua.StackInstances ()
import Text.Pandoc.Lua.Util (addFunction, popValue)
import Text.Pandoc.Lua.Util (addFunction)
import qualified Data.Digest.Pure.SHA as SHA
import qualified Data.ByteString.Lazy as BSL
@ -89,7 +89,7 @@ runJSONFilter mbDatadir doc filterFile optArgs = do
Just x -> return x
Nothing -> do
Lua.getglobal "FORMAT"
(:[]) <$> popValue
(:[]) <$> Lua.popValue
filterRes <- Lua.liftIO . runIO $ do
setUserDataDir mbDatadir
JSONFilter.apply def args filterFile doc
@ -121,18 +121,18 @@ data AstElement
| MetaValueElement MetaValue
deriving (Show)
instance FromLuaStack AstElement where
instance Peekable AstElement where
peek idx = do
res <- Lua.tryLua $ (PandocElement <$> Lua.peek idx)
<|> (InlineElement <$> Lua.peek idx)
<|> (BlockElement <$> Lua.peek idx)
<|> (MetaElement <$> Lua.peek idx)
<|> (MetaValueElement <$> Lua.peek idx)
res <- Lua.try $ (PandocElement <$> Lua.peek idx)
<|> (InlineElement <$> Lua.peek idx)
<|> (BlockElement <$> Lua.peek idx)
<|> (MetaElement <$> Lua.peek idx)
<|> (MetaValueElement <$> Lua.peek idx)
case res of
Right x -> return x
Left _ -> Lua.throwLuaError
Left _ -> Lua.throwException
"Expected an AST element, but could not parse value as such."
-- | Convert a number < 4000 to uppercase roman numeral.
toRomanNumeral :: LuaInteger -> Lua String
toRomanNumeral :: Lua.Integer -> Lua String
toRomanNumeral = return . Shared.toRomanNumeral . fromIntegral

View file

@ -1,4 +1,3 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@ -16,8 +15,9 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
{- |
Module : Text.Pandoc.Lua.Packages
Copyright : Copyright © 2017-2018 Albert Krewinkel
@ -35,12 +35,11 @@ module Text.Pandoc.Lua.Packages
import Prelude
import Control.Monad (forM_)
import Data.ByteString.Char8 (unpack)
import Data.ByteString (ByteString)
import Data.IORef (IORef)
import Foreign.Lua (Lua, NumResults, liftIO)
import Text.Pandoc.Class (CommonState, readDataFile, runIO, setUserDataDir)
import Text.Pandoc.MediaBag (MediaBag)
import Text.Pandoc.Lua.Util (dostring')
import qualified Foreign.Lua as Lua
import Text.Pandoc.Lua.Module.Pandoc as Pandoc
@ -57,14 +56,10 @@ data LuaPackageParams = LuaPackageParams
-- | Insert pandoc's package loader as the first loader, making it the default.
installPandocPackageSearcher :: LuaPackageParams -> Lua ()
installPandocPackageSearcher luaPkgParams = do
luaVersion <- Lua.getglobal "_VERSION" *> Lua.peek (-1)
if luaVersion == "Lua 5.1"
then Lua.getglobal' "package.loaders"
else Lua.getglobal' "package.searchers"
Lua.getglobal' "package.searchers"
shiftArray
Lua.pushHaskellFunction (pandocPackageSearcher luaPkgParams)
Lua.wrapHaskellFunction
Lua.rawseti (-2) 1
Lua.rawseti (Lua.nthFromTop 2) 1
Lua.pop 1 -- remove 'package.searchers' from stack
where
shiftArray = forM_ [4, 3, 2, 1] $ \i -> do
@ -86,7 +81,6 @@ pandocPackageSearcher luaPkgParams pkgName =
where
pushWrappedHsFun f = do
Lua.pushHaskellFunction f
Lua.wrapHaskellFunction
return 1
searchPureLuaLoader = do
let filename = pkgName ++ ".lua"
@ -97,21 +91,19 @@ pandocPackageSearcher luaPkgParams pkgName =
Lua.push ("no file '" ++ filename ++ "' in pandoc's datadir")
return 1
loadStringAsPackage :: String -> String -> Lua NumResults
loadStringAsPackage :: String -> ByteString -> Lua NumResults
loadStringAsPackage pkgName script = do
status <- dostring' script
status <- Lua.dostring script
if status == Lua.OK
then return (1 :: NumResults)
else do
msg <- Lua.peek (-1) <* Lua.pop 1
Lua.push ("Error while loading ``" ++ pkgName ++ "`.\n" ++ msg)
Lua.lerror
return (2 :: NumResults)
msg <- Lua.popValue
Lua.raiseError ("Error while loading `" <> pkgName <> "`.\n" <> msg)
-- | Get the string representation of the pandoc module
dataDirScript :: Maybe FilePath -> FilePath -> IO (Maybe String)
-- | Get the ByteString representation of the pandoc module.
dataDirScript :: Maybe FilePath -> FilePath -> IO (Maybe ByteString)
dataDirScript datadir moduleFile = do
res <- runIO $ setUserDataDir datadir >> readDataFile moduleFile
return $ case res of
Left _ -> Nothing
Right s -> Just (unpack s)
Right s -> Just s

View file

@ -1,4 +1,3 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>
2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@ -19,6 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{- |
@ -37,67 +37,59 @@ module Text.Pandoc.Lua.StackInstances () where
import Prelude
import Control.Applicative ((<|>))
import Control.Monad (when)
import Control.Monad.Catch (finally)
import Data.Data (showConstr, toConstr)
import Data.Foldable (forM_)
import Foreign.Lua (FromLuaStack (peek), Lua, LuaInteger, LuaNumber, StackIndex,
ToLuaStack (push), Type (..), throwLuaError, tryLua)
import Foreign.Lua (Lua, Peekable, Pushable, StackIndex)
import Text.Pandoc.Definition
import Text.Pandoc.Extensions (Extensions)
import Text.Pandoc.Lua.Util (pushViaConstructor, typeCheck)
import Text.Pandoc.Lua.Util (defineHowTo, pushViaConstructor)
import Text.Pandoc.Options (ReaderOptions (..), TrackChanges)
import Text.Pandoc.Shared (Element (Blk, Sec), safeRead)
import Text.Pandoc.Shared (Element (Blk, Sec))
import qualified Foreign.Lua as Lua
import qualified Data.Set as Set
import qualified Foreign.Lua as Lua
import qualified Text.Pandoc.Lua.Util as LuaUtil
defineHowTo :: String -> Lua a -> Lua a
defineHowTo ctx op = op `Lua.modifyLuaError` (("Could not " ++ ctx ++ ": ") ++)
instance ToLuaStack Pandoc where
instance Pushable Pandoc where
push (Pandoc meta blocks) =
pushViaConstructor "Pandoc" blocks meta
instance FromLuaStack Pandoc where
instance Peekable Pandoc where
peek idx = defineHowTo "get Pandoc value" $ do
typeCheck idx Lua.TypeTable
blocks <- LuaUtil.rawField idx "blocks"
meta <- Lua.getfield idx "meta" *> (Lua.peek Lua.stackTop `finally` Lua.pop 1)
meta <- LuaUtil.rawField idx "meta"
return $ Pandoc meta blocks
instance ToLuaStack Meta where
instance Pushable Meta where
push (Meta mmap) =
pushViaConstructor "Meta" mmap
instance FromLuaStack Meta where
peek idx = defineHowTo "get Meta value" $ do
typeCheck idx Lua.TypeTable
Meta <$> peek idx
instance Peekable Meta where
peek idx = defineHowTo "get Meta value" $
Meta <$> Lua.peek idx
instance ToLuaStack MetaValue where
instance Pushable MetaValue where
push = pushMetaValue
instance FromLuaStack MetaValue where
instance Peekable MetaValue where
peek = peekMetaValue
instance ToLuaStack Block where
instance Pushable Block where
push = pushBlock
instance FromLuaStack Block where
instance Peekable Block where
peek = peekBlock
-- Inline
instance ToLuaStack Inline where
instance Pushable Inline where
push = pushInline
instance FromLuaStack Inline where
instance Peekable Inline where
peek = peekInline
-- Citation
instance ToLuaStack Citation where
instance Pushable Citation where
push (Citation cid prefix suffix mode noteNum hash) =
pushViaConstructor "Citation" cid mode prefix suffix noteNum hash
instance FromLuaStack Citation where
instance Peekable Citation where
peek idx = do
id' <- LuaUtil.rawField idx "id"
prefix <- LuaUtil.rawField idx "prefix"
@ -107,78 +99,63 @@ instance FromLuaStack Citation where
hash <- LuaUtil.rawField idx "hash"
return $ Citation id' prefix suffix mode num hash
instance ToLuaStack Alignment where
push = push . show
instance FromLuaStack Alignment where
peek idx = safeRead' =<< peek idx
instance Pushable Alignment where
push = Lua.push . show
instance Peekable Alignment where
peek = Lua.peekRead
instance ToLuaStack CitationMode where
push = push . show
instance FromLuaStack CitationMode where
peek idx = safeRead' =<< peek idx
instance Pushable CitationMode where
push = Lua.push . show
instance Peekable CitationMode where
peek = Lua.peekRead
instance ToLuaStack Format where
push (Format f) = push f
instance FromLuaStack Format where
peek idx = Format <$> peek idx
instance Pushable Format where
push (Format f) = Lua.push f
instance Peekable Format where
peek idx = Format <$> Lua.peek idx
instance ToLuaStack ListNumberDelim where
push = push . show
instance FromLuaStack ListNumberDelim where
peek idx = safeRead' =<< peek idx
instance Pushable ListNumberDelim where
push = Lua.push . show
instance Peekable ListNumberDelim where
peek = Lua.peekRead
instance ToLuaStack ListNumberStyle where
push = push . show
instance FromLuaStack ListNumberStyle where
peek idx = safeRead' =<< peek idx
instance Pushable ListNumberStyle where
push = Lua.push . show
instance Peekable ListNumberStyle where
peek = Lua.peekRead
instance ToLuaStack MathType where
push = push . show
instance FromLuaStack MathType where
peek idx = safeRead' =<< peek idx
instance Pushable MathType where
push = Lua.push . show
instance Peekable MathType where
peek = Lua.peekRead
instance ToLuaStack QuoteType where
push = push . show
instance FromLuaStack QuoteType where
peek idx = safeRead' =<< peek idx
instance ToLuaStack Double where
push = push . (realToFrac :: Double -> LuaNumber)
instance FromLuaStack Double where
peek = fmap (realToFrac :: LuaNumber -> Double) . peek
instance ToLuaStack Int where
push = push . (fromIntegral :: Int -> LuaInteger)
instance FromLuaStack Int where
peek = fmap (fromIntegral :: LuaInteger-> Int) . peek
safeRead' :: Read a => String -> Lua a
safeRead' s = case safeRead s of
Nothing -> throwLuaError ("Could not read: " ++ s)
Just x -> return x
instance Pushable QuoteType where
push = Lua.push . show
instance Peekable QuoteType where
peek = Lua.peekRead
-- | Push an meta value element to the top of the lua stack.
pushMetaValue :: MetaValue -> Lua ()
pushMetaValue = \case
MetaBlocks blcks -> pushViaConstructor "MetaBlocks" blcks
MetaBool bool -> push bool
MetaBool bool -> Lua.push bool
MetaInlines inlns -> pushViaConstructor "MetaInlines" inlns
MetaList metalist -> pushViaConstructor "MetaList" metalist
MetaMap metamap -> pushViaConstructor "MetaMap" metamap
MetaString str -> push str
MetaString str -> Lua.push str
-- | Interpret the value at the given stack index as meta value.
peekMetaValue :: StackIndex -> Lua MetaValue
peekMetaValue idx = defineHowTo "get MetaValue" $ do
-- Get the contents of an AST element.
let elementContent :: FromLuaStack a => Lua a
elementContent = peek idx
let elementContent :: Peekable a => Lua a
elementContent = Lua.peek idx
luatype <- Lua.ltype idx
case luatype of
TypeBoolean -> MetaBool <$> peek idx
TypeString -> MetaString <$> peek idx
TypeTable -> do
tag <- tryLua $ LuaUtil.getTag idx
Lua.TypeBoolean -> MetaBool <$> Lua.peek idx
Lua.TypeString -> MetaString <$> Lua.peek idx
Lua.TypeTable -> do
tag <- Lua.try $ LuaUtil.getTag idx
case tag of
Right "MetaBlocks" -> MetaBlocks <$> elementContent
Right "MetaBool" -> MetaBool <$> elementContent
@ -186,16 +163,16 @@ peekMetaValue idx = defineHowTo "get MetaValue" $ do
Right "MetaInlines" -> MetaInlines <$> elementContent
Right "MetaList" -> MetaList <$> elementContent
Right "MetaString" -> MetaString <$> elementContent
Right t -> throwLuaError ("Unknown meta tag: " ++ t)
Right t -> Lua.throwException ("Unknown meta tag: " <> t)
Left _ -> do
-- no meta value tag given, try to guess.
len <- Lua.rawlen idx
if len <= 0
then MetaMap <$> peek idx
else (MetaInlines <$> peek idx)
<|> (MetaBlocks <$> peek idx)
<|> (MetaList <$> peek idx)
_ -> throwLuaError "could not get meta value"
then MetaMap <$> Lua.peek idx
else (MetaInlines <$> Lua.peek idx)
<|> (MetaBlocks <$> Lua.peek idx)
<|> (MetaList <$> Lua.peek idx)
_ -> Lua.throwException "could not get meta value"
-- | Push an block element to the top of the lua stack.
pushBlock :: Block -> Lua ()
@ -219,7 +196,6 @@ pushBlock = \case
-- | Return the value at the given index as block if possible.
peekBlock :: StackIndex -> Lua Block
peekBlock idx = defineHowTo "get Block value" $ do
typeCheck idx Lua.TypeTable
tag <- LuaUtil.getTag idx
case tag of
"BlockQuote" -> BlockQuote <$> elementContent
@ -239,10 +215,10 @@ peekBlock idx = defineHowTo "get Block value" $ do
"Table" -> (\(capt, aligns, widths, headers, body) ->
Table capt aligns widths headers body)
<$> elementContent
_ -> throwLuaError ("Unknown block type: " ++ tag)
_ -> Lua.throwException ("Unknown block type: " <> tag)
where
-- Get the contents of an AST element.
elementContent :: FromLuaStack a => Lua a
elementContent :: Peekable a => Lua a
elementContent = LuaUtil.rawField idx "c"
-- | Push an inline element to the top of the lua stack.
@ -271,7 +247,6 @@ pushInline = \case
-- | Return the value at the given index as inline if possible.
peekInline :: StackIndex -> Lua Inline
peekInline idx = defineHowTo "get Inline value" $ do
typeCheck idx Lua.TypeTable
tag <- LuaUtil.getTag idx
case tag of
"Cite" -> uncurry Cite <$> elementContent
@ -295,10 +270,10 @@ peekInline idx = defineHowTo "get Inline value" $ do
"Strong" -> Strong <$> elementContent
"Subscript" -> Subscript <$> elementContent
"Superscript"-> Superscript <$> elementContent
_ -> throwLuaError ("Unknown inline type: " ++ tag)
_ -> Lua.throwException ("Unknown inline type: " <> tag)
where
-- Get the contents of an AST element.
elementContent :: FromLuaStack a => Lua a
elementContent :: Peekable a => Lua a
elementContent = LuaUtil.rawField idx "c"
withAttr :: (Attr -> a -> b) -> (LuaAttr, a) -> b
@ -307,18 +282,18 @@ withAttr f (attributes, x) = f (fromLuaAttr attributes) x
-- | Wrapper for Attr
newtype LuaAttr = LuaAttr { fromLuaAttr :: Attr }
instance ToLuaStack LuaAttr where
instance Pushable LuaAttr where
push (LuaAttr (id', classes, kv)) =
pushViaConstructor "Attr" id' classes kv
instance FromLuaStack LuaAttr where
peek idx = defineHowTo "get Attr value" (LuaAttr <$> peek idx)
instance Peekable LuaAttr where
peek idx = defineHowTo "get Attr value" (LuaAttr <$> Lua.peek idx)
--
-- Hierarchical elements
--
instance ToLuaStack Element where
push (Blk blk) = push blk
instance Pushable Element where
push (Blk blk) = Lua.push blk
push (Sec lvl num attr label contents) = do
Lua.newtable
LuaUtil.addField "level" lvl
@ -342,18 +317,13 @@ instance ToLuaStack Element where
--
-- Reader Options
--
instance ToLuaStack Extensions where
push exts = push (show exts)
instance Pushable Extensions where
push exts = Lua.push (show exts)
instance ToLuaStack TrackChanges where
push = push . showConstr . toConstr
instance Pushable TrackChanges where
push = Lua.push . showConstr . toConstr
instance ToLuaStack a => ToLuaStack (Set.Set a) where
push set = do
Lua.newtable
forM_ set (`LuaUtil.addValue` True)
instance ToLuaStack ReaderOptions where
instance Pushable ReaderOptions where
push ro = do
let ReaderOptions
(extensions :: Extensions)

View file

@ -1,4 +1,3 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-
Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>
2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@ -18,6 +17,8 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NoImplicitPrelude #-}
{- |
Module : Text.Pandoc.Lua.Util
Copyright : © 20122018 John MacFarlane,
@ -35,39 +36,35 @@ module Text.Pandoc.Lua.Util
, addField
, addFunction
, addValue
, typeCheck
, popValue
, PushViaCall
, pushViaCall
, pushViaConstructor
, loadScriptFromDataDir
, dostring'
, defineHowTo
, throwTopMessageAsError'
) where
import Prelude
import Control.Monad (when)
import Control.Monad.Catch (finally)
import Data.ByteString.Char8 (unpack)
import Foreign.Lua (FromLuaStack, Lua, NumArgs, StackIndex, Status,
ToLuaStack, ToHaskellFunction)
import Control.Monad (unless, when)
import Foreign.Lua ( Lua, NumArgs, Peekable, Pushable, StackIndex
, ToHaskellFunction )
import Text.Pandoc.Class (readDataFile, runIOorExplode, setUserDataDir)
import qualified Foreign.Lua as Lua
import qualified Text.Pandoc.UTF8 as UTF8
-- | Get value behind key from table at given index.
rawField :: FromLuaStack a => StackIndex -> String -> Lua a
rawField :: Peekable a => StackIndex -> String -> Lua a
rawField idx key = do
absidx <- Lua.absindex idx
Lua.push key
Lua.rawget absidx
popValue
Lua.popValue
-- | Add a value to the table at the top of the stack at a string-index.
addField :: ToLuaStack a => String -> a -> Lua ()
addField :: Pushable a => String -> a -> Lua ()
addField = addValue
-- | Add a key-value pair to the table at the top of the stack.
addValue :: (ToLuaStack a, ToLuaStack b) => a -> b -> Lua ()
addValue :: (Pushable a, Pushable b) => a -> b -> Lua ()
addValue key value = do
Lua.push key
Lua.push value
@ -78,26 +75,8 @@ addFunction :: ToHaskellFunction a => String -> a -> Lua ()
addFunction name fn = do
Lua.push name
Lua.pushHaskellFunction fn
Lua.wrapHaskellFunction
Lua.rawset (-3)
typeCheck :: StackIndex -> Lua.Type -> Lua ()
typeCheck idx expected = do
actual <- Lua.ltype idx
when (actual /= expected) $ do
expName <- Lua.typename expected
actName <- Lua.typename actual
Lua.throwLuaError $ "expected " ++ expName ++ " but got " ++ actName ++ "."
-- | Get, then pop the value at the top of the stack.
popValue :: FromLuaStack a => Lua a
popValue = do
resOrError <- Lua.peekEither (-1)
Lua.pop 1
case resOrError of
Left err -> Lua.throwLuaError err
Right x -> return x
-- | Helper class for pushing a single value to the stack via a lua function.
-- See @pushViaCall@.
class PushViaCall a where
@ -110,7 +89,7 @@ instance PushViaCall (Lua ()) where
pushArgs
Lua.call num 1
instance (ToLuaStack a, PushViaCall b) => PushViaCall (a -> b) where
instance (Pushable a, PushViaCall b) => PushViaCall (a -> b) where
pushViaCall' fn pushArgs num x =
pushViaCall' fn (pushArgs *> Lua.push x) (num + 1)
@ -127,26 +106,11 @@ pushViaConstructor pandocFn = pushViaCall ("pandoc." ++ pandocFn)
-- | Load a file from pandoc's data directory.
loadScriptFromDataDir :: Maybe FilePath -> FilePath -> Lua ()
loadScriptFromDataDir datadir scriptFile = do
script <- fmap unpack . Lua.liftIO . runIOorExplode $
script <- Lua.liftIO . runIOorExplode $
setUserDataDir datadir >> readDataFile scriptFile
status <- dostring' script
when (status /= Lua.OK) .
Lua.throwTopMessageAsError' $ \msg ->
"Couldn't load '" ++ scriptFile ++ "'.\n" ++ msg
-- | Load a string and immediately perform a full garbage collection. This is
-- important to keep the program from hanging: If the program containes a call
-- to @require@, then a new loader function is created which then becomes
-- garbage. If that function is collected at an inopportune time, i.e. when the
-- Lua API is called via a function that doesn't allow calling back into Haskell
-- (getraw, setraw, …), then the function's finalizer, and the full program,
-- will hang.
dostring' :: String -> Lua Status
dostring' script = do
loadRes <- Lua.loadstring script
if loadRes == Lua.OK
then Lua.pcall 0 1 Nothing <* Lua.gc Lua.GCCOLLECT 0
else return loadRes
status <- Lua.dostring script
when (status /= Lua.OK) $
throwTopMessageAsError' (("Couldn't load '" ++ scriptFile ++ "'.\n") ++)
-- | Get the tag of a value. This is an optimized and specialized version of
-- @Lua.getfield idx "tag"@. It only checks for the field on the table at index
@ -155,7 +119,21 @@ dostring' script = do
getTag :: StackIndex -> Lua String
getTag idx = do
-- push metatable or just the table
Lua.getmetatable idx >>= \hasMT -> when (not hasMT) (Lua.pushvalue idx)
Lua.getmetatable idx >>= \hasMT -> unless hasMT (Lua.pushvalue idx)
Lua.push "tag"
Lua.rawget (Lua.nthFromTop 2)
Lua.peek Lua.stackTop `finally` Lua.pop 2
Lua.tostring Lua.stackTop <* Lua.pop 2 >>= \case
Nothing -> Lua.throwException "untagged value"
Just x -> return (UTF8.toString x)
-- | Modify the message at the top of the stack before throwing it as an
-- Exception.
throwTopMessageAsError' :: (String -> String) -> Lua a
throwTopMessageAsError' modifier = do
msg <- Lua.tostring' Lua.stackTop
Lua.pop 2 -- remove error and error string pushed by tostring'
Lua.throwException (modifier (UTF8.toString msg))
defineHowTo :: String -> Lua a -> Lua a
defineHowTo ctx = Lua.withExceptionMessage (("Could not " <> ctx <> ": ") <>)

View file

@ -1,6 +1,6 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}
{- Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
@ -35,25 +35,26 @@ import Prelude
import Control.Arrow ((***))
import Control.Exception
import Control.Monad (when)
import Control.Monad.Trans (MonadIO (liftIO))
import Data.Char (toLower)
import Data.List (intersperse)
import qualified Data.Map as M
import Data.Text (Text, pack)
import Data.Typeable
import Foreign.Lua (Lua, ToLuaStack (..), callFunc)
import Foreign.Lua.Api
import Foreign.Lua (Lua, Pushable)
import Text.Pandoc.Class (PandocIO)
import Text.Pandoc.Definition
import Text.Pandoc.Error
import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath)
import Text.Pandoc.Lua.Init (LuaException (LuaException), runPandocLua,
registerScriptPath)
import Text.Pandoc.Lua.StackInstances ()
import Text.Pandoc.Lua.Util (addField, addValue, dostring')
import Text.Pandoc.Lua.Util (addField)
import Text.Pandoc.Options
import Text.Pandoc.Templates
import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.Writers.Shared
import qualified Foreign.Lua as Lua
attrToMap :: Attr -> M.Map String String
attrToMap (id',classes,keyvals) = M.fromList
$ ("id", id')
@ -62,26 +63,26 @@ attrToMap (id',classes,keyvals) = M.fromList
newtype Stringify a = Stringify a
instance ToLuaStack (Stringify Format) where
push (Stringify (Format f)) = push (map toLower f)
instance Pushable (Stringify Format) where
push (Stringify (Format f)) = Lua.push (map toLower f)
instance ToLuaStack (Stringify [Inline]) where
push (Stringify ils) = push =<< inlineListToCustom ils
instance Pushable (Stringify [Inline]) where
push (Stringify ils) = Lua.push =<< inlineListToCustom ils
instance ToLuaStack (Stringify [Block]) where
push (Stringify blks) = push =<< blockListToCustom blks
instance Pushable (Stringify [Block]) where
push (Stringify blks) = Lua.push =<< blockListToCustom blks
instance ToLuaStack (Stringify MetaValue) where
push (Stringify (MetaMap m)) = push (fmap Stringify m)
push (Stringify (MetaList xs)) = push (map Stringify xs)
push (Stringify (MetaBool x)) = push x
push (Stringify (MetaString s)) = push s
push (Stringify (MetaInlines ils)) = push (Stringify ils)
push (Stringify (MetaBlocks bs)) = push (Stringify bs)
instance Pushable (Stringify MetaValue) where
push (Stringify (MetaMap m)) = Lua.push (fmap Stringify m)
push (Stringify (MetaList xs)) = Lua.push (map Stringify xs)
push (Stringify (MetaBool x)) = Lua.push x
push (Stringify (MetaString s)) = Lua.push s
push (Stringify (MetaInlines ils)) = Lua.push (Stringify ils)
push (Stringify (MetaBlocks bs)) = Lua.push (Stringify bs)
instance ToLuaStack (Stringify Citation) where
instance Pushable (Stringify Citation) where
push (Stringify cit) = do
createtable 6 0
Lua.createtable 6 0
addField "citationId" $ citationId cit
addField "citationPrefix" . Stringify $ citationPrefix cit
addField "citationSuffix" . Stringify $ citationSuffix cit
@ -93,10 +94,12 @@ instance ToLuaStack (Stringify Citation) where
-- associated value.
newtype KeyValue a b = KeyValue (a, b)
instance (ToLuaStack a, ToLuaStack b) => ToLuaStack (KeyValue a b) where
instance (Pushable a, Pushable b) => Pushable (KeyValue a b) where
push (KeyValue (k, v)) = do
newtable
addValue k v
Lua.newtable
Lua.push k
Lua.push v
Lua.rawset (Lua.nthFromTop 3)
data PandocLuaException = PandocLuaException String
deriving (Show, Typeable)
@ -106,14 +109,13 @@ instance Exception PandocLuaException
-- | Convert Pandoc to custom markup.
writeCustom :: FilePath -> WriterOptions -> Pandoc -> PandocIO Text
writeCustom luaFile opts doc@(Pandoc meta _) = do
luaScript <- liftIO $ UTF8.readFile luaFile
res <- runPandocLua $ do
registerScriptPath luaFile
stat <- dostring' luaScript
stat <- Lua.dofile luaFile
-- check for error in lua script (later we'll change the return type
-- to handle this more gracefully):
when (stat /= OK) $
tostring (-1) >>= throw . PandocLuaException . UTF8.toString
when (stat /= Lua.OK) $
Lua.tostring' (-1) >>= throw . PandocLuaException . UTF8.toString
-- TODO - call hierarchicalize, so we have that info
rendered <- docToCustom opts doc
context <- metaToJSON opts
@ -122,7 +124,7 @@ writeCustom luaFile opts doc@(Pandoc meta _) = do
meta
return (rendered, context)
let (body, context) = case res of
Left e -> throw (PandocLuaException (show e))
Left (LuaException msg) -> throw (PandocLuaException msg)
Right x -> x
case writerTemplate opts of
Nothing -> return $ pack body
@ -134,7 +136,7 @@ writeCustom luaFile opts doc@(Pandoc meta _) = do
docToCustom :: WriterOptions -> Pandoc -> Lua String
docToCustom opts (Pandoc (Meta metamap) blocks) = do
body <- blockListToCustom blocks
callFunc "Doc" body (fmap Stringify metamap) (writerVariables opts)
Lua.callFunc "Doc" body (fmap Stringify metamap) (writerVariables opts)
-- | Convert Pandoc block element to Custom.
blockToCustom :: Block -- ^ Block element
@ -142,52 +144,55 @@ blockToCustom :: Block -- ^ Block element
blockToCustom Null = return ""
blockToCustom (Plain inlines) = callFunc "Plain" (Stringify inlines)
blockToCustom (Plain inlines) = Lua.callFunc "Plain" (Stringify inlines)
blockToCustom (Para [Image attr txt (src,tit)]) =
callFunc "CaptionedImage" src tit (Stringify txt) (attrToMap attr)
Lua.callFunc "CaptionedImage" src tit (Stringify txt) (attrToMap attr)
blockToCustom (Para inlines) = callFunc "Para" (Stringify inlines)
blockToCustom (Para inlines) = Lua.callFunc "Para" (Stringify inlines)
blockToCustom (LineBlock linesList) = callFunc "LineBlock" (map Stringify linesList)
blockToCustom (LineBlock linesList) =
Lua.callFunc "LineBlock" (map Stringify linesList)
blockToCustom (RawBlock format str) =
callFunc "RawBlock" (Stringify format) str
Lua.callFunc "RawBlock" (Stringify format) str
blockToCustom HorizontalRule = callFunc "HorizontalRule"
blockToCustom HorizontalRule = Lua.callFunc "HorizontalRule"
blockToCustom (Header level attr inlines) =
callFunc "Header" level (Stringify inlines) (attrToMap attr)
Lua.callFunc "Header" level (Stringify inlines) (attrToMap attr)
blockToCustom (CodeBlock attr str) =
callFunc "CodeBlock" str (attrToMap attr)
Lua.callFunc "CodeBlock" str (attrToMap attr)
blockToCustom (BlockQuote blocks) = callFunc "BlockQuote" (Stringify blocks)
blockToCustom (BlockQuote blocks) =
Lua.callFunc "BlockQuote" (Stringify blocks)
blockToCustom (Table capt aligns widths headers rows) =
let aligns' = map show aligns
capt' = Stringify capt
headers' = map Stringify headers
rows' = map (map Stringify) rows
in callFunc "Table" capt' aligns' widths headers' rows'
in Lua.callFunc "Table" capt' aligns' widths headers' rows'
blockToCustom (BulletList items) = callFunc "BulletList" (map Stringify items)
blockToCustom (BulletList items) =
Lua.callFunc "BulletList" (map Stringify items)
blockToCustom (OrderedList (num,sty,delim) items) =
callFunc "OrderedList" (map Stringify items) num (show sty) (show delim)
Lua.callFunc "OrderedList" (map Stringify items) num (show sty) (show delim)
blockToCustom (DefinitionList items) =
callFunc "DefinitionList"
(map (KeyValue . (Stringify *** map Stringify)) items)
Lua.callFunc "DefinitionList"
(map (KeyValue . (Stringify *** map Stringify)) items)
blockToCustom (Div attr items) =
callFunc "Div" (Stringify items) (attrToMap attr)
Lua.callFunc "Div" (Stringify items) (attrToMap attr)
-- | Convert list of Pandoc block elements to Custom.
blockListToCustom :: [Block] -- ^ List of block elements
-> Lua String
blockListToCustom xs = do
blocksep <- callFunc "Blocksep"
blocksep <- Lua.callFunc "Blocksep"
bs <- mapM blockToCustom xs
return $ mconcat $ intersperse blocksep bs
@ -200,51 +205,51 @@ inlineListToCustom lst = do
-- | Convert Pandoc inline element to Custom.
inlineToCustom :: Inline -> Lua String
inlineToCustom (Str str) = callFunc "Str" str
inlineToCustom (Str str) = Lua.callFunc "Str" str
inlineToCustom Space = callFunc "Space"
inlineToCustom Space = Lua.callFunc "Space"
inlineToCustom SoftBreak = callFunc "SoftBreak"
inlineToCustom SoftBreak = Lua.callFunc "SoftBreak"
inlineToCustom (Emph lst) = callFunc "Emph" (Stringify lst)
inlineToCustom (Emph lst) = Lua.callFunc "Emph" (Stringify lst)
inlineToCustom (Strong lst) = callFunc "Strong" (Stringify lst)
inlineToCustom (Strong lst) = Lua.callFunc "Strong" (Stringify lst)
inlineToCustom (Strikeout lst) = callFunc "Strikeout" (Stringify lst)
inlineToCustom (Strikeout lst) = Lua.callFunc "Strikeout" (Stringify lst)
inlineToCustom (Superscript lst) = callFunc "Superscript" (Stringify lst)
inlineToCustom (Superscript lst) = Lua.callFunc "Superscript" (Stringify lst)
inlineToCustom (Subscript lst) = callFunc "Subscript" (Stringify lst)
inlineToCustom (Subscript lst) = Lua.callFunc "Subscript" (Stringify lst)
inlineToCustom (SmallCaps lst) = callFunc "SmallCaps" (Stringify lst)
inlineToCustom (SmallCaps lst) = Lua.callFunc "SmallCaps" (Stringify lst)
inlineToCustom (Quoted SingleQuote lst) = callFunc "SingleQuoted" (Stringify lst)
inlineToCustom (Quoted SingleQuote lst) = Lua.callFunc "SingleQuoted" (Stringify lst)
inlineToCustom (Quoted DoubleQuote lst) = callFunc "DoubleQuoted" (Stringify lst)
inlineToCustom (Quoted DoubleQuote lst) = Lua.callFunc "DoubleQuoted" (Stringify lst)
inlineToCustom (Cite cs lst) = callFunc "Cite" (Stringify lst) (map Stringify cs)
inlineToCustom (Cite cs lst) = Lua.callFunc "Cite" (Stringify lst) (map Stringify cs)
inlineToCustom (Code attr str) =
callFunc "Code" str (attrToMap attr)
Lua.callFunc "Code" str (attrToMap attr)
inlineToCustom (Math DisplayMath str) =
callFunc "DisplayMath" str
Lua.callFunc "DisplayMath" str
inlineToCustom (Math InlineMath str) =
callFunc "InlineMath" str
Lua.callFunc "InlineMath" str
inlineToCustom (RawInline format str) =
callFunc "RawInline" (Stringify format) str
Lua.callFunc "RawInline" (Stringify format) str
inlineToCustom LineBreak = callFunc "LineBreak"
inlineToCustom LineBreak = Lua.callFunc "LineBreak"
inlineToCustom (Link attr txt (src,tit)) =
callFunc "Link" (Stringify txt) src tit (attrToMap attr)
Lua.callFunc "Link" (Stringify txt) src tit (attrToMap attr)
inlineToCustom (Image attr alt (src,tit)) =
callFunc "Image" (Stringify alt) src tit (attrToMap attr)
Lua.callFunc "Image" (Stringify alt) src tit (attrToMap attr)
inlineToCustom (Note contents) = callFunc "Note" (Stringify contents)
inlineToCustom (Note contents) = Lua.callFunc "Note" (Stringify contents)
inlineToCustom (Span attr items) =
callFunc "Span" (Stringify items) (attrToMap attr)
Lua.callFunc "Span" (Stringify items) (attrToMap attr)

View file

@ -12,8 +12,8 @@ packages:
- '.'
extra-deps:
- pandoc-citeproc-0.14.4
- hslua-0.9.5.1
- hslua-module-text-0.1.2.1
- hslua-1.0.0
- hslua-module-text-0.2.0
- ansi-terminal-0.8.0.2
- cmark-gfm-0.1.3
- QuickCheck-2.11.3

View file

@ -24,6 +24,8 @@ extra-deps:
- HsYAML-0.1.1.1
- texmath-0.11.1
- yaml-0.9.0
- hslua-1.0.0
- hslua-module-text-0.2.0
ghc-options:
"$locals": -fhide-source-paths -XNoImplicitPrelude
resolver: lts-12.6

View file

@ -164,11 +164,11 @@ tests = map (localOption (QuickCheckTests 20))
, testCase "informative error messages" . runPandocLua' $ do
Lua.pushboolean True
err <- Lua.peekEither Lua.stackTop :: Lua.Lua (Either String Pandoc)
case err of
err <- Lua.peekEither Lua.stackTop
case (err :: Either String Pandoc) of
Left msg -> do
let expectedMsg = "Could not get Pandoc value: "
++ "expected table but got boolean."
<> "table expected, got boolean"
Lua.liftIO $ assertEqual "unexpected error message" expectedMsg msg
Right _ -> error "Getting a Pandoc element from a bool should fail."
]
@ -182,10 +182,10 @@ assertFilterConversion msg filterPath docIn docExpected = do
Left exception -> assertFailure (show exception)
Right docRes -> assertEqual msg docExpected docRes
roundtripEqual :: (Eq a, Lua.FromLuaStack a, Lua.ToLuaStack a) => a -> IO Bool
roundtripEqual :: (Eq a, Lua.Peekable a, Lua.Pushable a) => a -> IO Bool
roundtripEqual x = (x ==) <$> roundtripped
where
roundtripped :: (Lua.FromLuaStack a, Lua.ToLuaStack a) => IO a
roundtripped :: (Lua.Peekable a, Lua.Pushable a) => IO a
roundtripped = runPandocLua' $ do
oldSize <- Lua.gettop
Lua.push x