diff options
author | Albert Krewinkel <albert@zeitkraut.de> | 2018-09-19 21:05:36 +0200 |
---|---|---|
committer | Albert Krewinkel <albert@zeitkraut.de> | 2018-09-19 21:36:13 +0200 |
commit | 4264a1b1437f4b5885cf907aede821c8d611dff9 (patch) | |
tree | 42ac7dc4f7d7b485e72683d7b28d4a0bb09041bc /src/Text/Pandoc/Lua | |
parent | 8f841297df2aa4dcb1789843e562d4404baf1bf0 (diff) | |
download | pandoc-4264a1b1437f4b5885cf907aede821c8d611dff9.tar.gz |
Lua filter: cleanup filter execution code
Diffstat (limited to 'src/Text/Pandoc/Lua')
-rw-r--r-- | src/Text/Pandoc/Lua/Filter.hs | 124 |
1 files changed, 73 insertions, 51 deletions
diff --git a/src/Text/Pandoc/Lua/Filter.hs b/src/Text/Pandoc/Lua/Filter.hs index 264066305..6cbb10c6b 100644 --- a/src/Text/Pandoc/Lua/Filter.hs +++ b/src/Text/Pandoc/Lua/Filter.hs @@ -1,6 +1,33 @@ -{-# LANGUAGE NoImplicitPrelude #-} +{- +Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu> + 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +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 FlexibleContexts #-} - +{-# LANGUAGE NoImplicitPrelude #-} +{- | +Module : Text.Pandoc.Lua.Filter +Copyright : © 2012–2018 John MacFarlane, + © 2017-2018 Albert Krewinkel +License : GNU GPL, version 2 or above +Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de> +Stability : alpha + +Types and functions for running Lua filters. +-} module Text.Pandoc.Lua.Filter ( LuaFilterFunction , LuaFilter , tryFilter @@ -12,60 +39,56 @@ module Text.Pandoc.Lua.Filter ( LuaFilterFunction , inlineElementNames ) where import Prelude -import Control.Monad (mplus, unless, when, (>=>)) +import Control.Monad (mplus, (>=>)) import Control.Monad.Catch (finally) -import Text.Pandoc.Definition -import Data.Foldable (foldrM) -import Data.Map (Map) -import qualified Data.Map as Map -import qualified Foreign.Lua as Lua -import Foreign.Lua (FromLuaStack (peek), Lua, StackIndex, - Status (OK), ToLuaStack (push)) -import Text.Pandoc.Walk (walkM, Walkable) import Data.Data (Data, DataType, dataTypeConstrs, dataTypeName, dataTypeOf, showConstr, toConstr, tyconUQname) -import Text.Pandoc.Lua.StackInstances() +import Data.Foldable (foldrM) +import Data.Map (Map) +import Foreign.Lua (Lua, FromLuaStack, ToLuaStack) +import Text.Pandoc.Definition +import Text.Pandoc.Lua.StackInstances () import Text.Pandoc.Lua.Util (typeCheck) +import Text.Pandoc.Walk (walkM, Walkable) -type FunctionMap = Map String LuaFilterFunction - -newtype LuaFilterFunction = LuaFilterFunction { functionIndex :: Int } - -instance ToLuaStack LuaFilterFunction where - push = pushFilterFunction +import qualified Data.Map.Strict as Map +import qualified Foreign.Lua as Lua -instance FromLuaStack LuaFilterFunction where - peek = registerFilterFunction +-- | Filter function stored at the given index in the registry +newtype LuaFilterFunction = LuaFilterFunction Int -newtype LuaFilter = LuaFilter FunctionMap +-- | Collection of filter functions (at most one function per element +-- constructor) +newtype LuaFilter = LuaFilter (Map String LuaFilterFunction) instance FromLuaStack LuaFilter where - peek idx = - let constrs = metaFilterName : pandocFilterNames - ++ blockElementNames - ++ inlineElementNames - fn c acc = do - Lua.getfield idx c - filterFn <- Lua.tryLua (peek (-1)) - Lua.pop 1 + peek idx = do + let constrs = metaFilterName + : pandocFilterNames + ++ blockElementNames + ++ inlineElementNames + let go constr acc = do + Lua.getfield idx constr + filterFn <- registerFilterFunction return $ case filterFn of - Left _ -> acc - Right f -> (c, f) : acc - in LuaFilter . Map.fromList <$> foldrM fn [] constrs - --- | Push the filter function to the top of the stack. + Nothing -> acc + Just fn -> Map.insert constr fn acc + LuaFilter <$> foldrM go Map.empty constrs + +-- | Register the function at the top of the stack as a filter function in the +-- registry. +registerFilterFunction :: Lua (Maybe LuaFilterFunction) +registerFilterFunction = do + isFn <- Lua.isfunction Lua.stackTop + if isFn + then Just . LuaFilterFunction <$> Lua.ref Lua.registryindex + else Nothing <$ Lua.pop 1 + +-- | Retrieve filter function from registry and push it to the top of the stack. pushFilterFunction :: LuaFilterFunction -> Lua () -pushFilterFunction lf = - -- The function is stored in a lua registry table, retrieve it from there. - Lua.rawgeti Lua.registryindex (functionIndex lf) - -registerFilterFunction :: StackIndex -> Lua LuaFilterFunction -registerFilterFunction idx = do - isFn <- Lua.isfunction idx - unless isFn . Lua.throwLuaError $ "Not a function at index " ++ show idx - Lua.pushvalue idx - refIdx <- Lua.ref Lua.registryindex - return $ LuaFilterFunction refIdx +pushFilterFunction (LuaFilterFunction fnRef) = + Lua.rawgeti Lua.registryindex fnRef + elementOrList :: FromLuaStack a => a -> Lua [a] elementOrList x = do @@ -98,12 +121,11 @@ tryFilter (LuaFilter fnMap) x = -- element is left unchanged. runFilterFunction :: ToLuaStack a => LuaFilterFunction -> a -> Lua () runFilterFunction lf x = do - pushFilterFunction lf - push x - z <- Lua.pcall 1 1 Nothing - when (z /= OK) $ do - let addPrefix = ("Error while running filter function: " ++) - Lua.throwTopMessageAsError' addPrefix + let errorPrefix = "Error while running filter function:\n" + (`Lua.modifyLuaError` (errorPrefix <>)) $ do + pushFilterFunction lf + Lua.push x + Lua.call 1 1 walkMWithLuaFilter :: LuaFilter -> Pandoc -> Lua Pandoc walkMWithLuaFilter f = |