aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlbert Krewinkel <albert@zeitkraut.de>2018-10-13 14:57:20 +0200
committerAlbert Krewinkel <albert@zeitkraut.de>2018-10-13 14:57:20 +0200
commitd126c26dd5f9eaed17462a3f1836b0edaf79e11c (patch)
tree33a738c27479c43a575ef1d466d24f7f9ebd913c /src
parent3db9e15689766b7f416e0410252297dff11bd770 (diff)
downloadpandoc-d126c26dd5f9eaed17462a3f1836b0edaf79e11c.tar.gz
Lua filter internals: push Shared.Element as userdata
Hierarchical Elements were pushed to Lua as plain tables. This is simple, but has the disadvantage that marshaling is eager: all child elements will be marshaled as part of the object. Using a Lua userdata object instead allows lazy access to fields, causing content marshaling just (but also each time) when a field is accessed. Filters which do not traverse the full element contents tree become faster as a result.
Diffstat (limited to 'src')
-rw-r--r--src/Text/Pandoc/Lua/StackInstances.hs43
1 files changed, 24 insertions, 19 deletions
diff --git a/src/Text/Pandoc/Lua/StackInstances.hs b/src/Text/Pandoc/Lua/StackInstances.hs
index 8538a14ee..25e81bb64 100644
--- a/src/Text/Pandoc/Lua/StackInstances.hs
+++ b/src/Text/Pandoc/Lua/StackInstances.hs
@@ -36,9 +36,10 @@ module Text.Pandoc.Lua.StackInstances () where
import Prelude
import Control.Applicative ((<|>))
-import Control.Monad (when)
import Data.Data (showConstr, toConstr)
import Foreign.Lua (Lua, Peekable, Pushable, StackIndex)
+import Foreign.Lua.Userdata ( ensureUserdataMetatable, pushAnyWithMetatable
+ , metatableName)
import Text.Pandoc.Definition
import Text.Pandoc.Extensions (Extensions)
import Text.Pandoc.Lua.Util (defineHowTo, pushViaConstructor)
@@ -308,24 +309,28 @@ instance Peekable LuaListAttributes where
--
instance Pushable Element where
push (Blk blk) = Lua.push blk
- push (Sec lvl num attr label contents) = do
- Lua.newtable
- LuaUtil.addField "level" lvl
- LuaUtil.addField "numbering" num
- LuaUtil.addField "attr" (LuaAttr attr)
- LuaUtil.addField "label" label
- LuaUtil.addField "contents" contents
- pushSecMetaTable
- Lua.setmetatable (-2)
- where
- pushSecMetaTable :: Lua ()
- pushSecMetaTable = do
- inexistant <- Lua.newmetatable "PandocElementSec"
- when inexistant $ do
- LuaUtil.addField "t" "Sec"
- Lua.push "__index"
- Lua.pushvalue (-2)
- Lua.rawset (-3)
+ push sec = pushAnyWithMetatable pushElementMetatable sec
+ where
+ pushElementMetatable = ensureUserdataMetatable (metatableName sec) $
+ LuaUtil.addFunction "__index" indexElement
+
+instance Peekable Element where
+ peek idx = Lua.ltype idx >>= \case
+ Lua.TypeUserdata -> Lua.peekAny idx
+ _ -> Blk <$> Lua.peek idx
+
+indexElement :: Element -> String -> Lua Lua.NumResults
+indexElement = \case
+ (Blk _) -> const (1 <$ Lua.pushnil) -- this shouldn't happen
+ (Sec lvl num attr label contents) -> fmap (return 1) . \case
+ "level" -> Lua.push lvl
+ "numbering" -> Lua.push num
+ "attr" -> Lua.push (LuaAttr attr)
+ "label" -> Lua.push label
+ "contents" -> Lua.push contents
+ "tag" -> Lua.push "Sec"
+ "t" -> Lua.push "Sec"
+ _ -> Lua.pushnil
--