@@ -1,4 +1,6 @@
11{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE MultiParamTypeClasses #-}
24{-# LANGUAGE ScopedTypeVariables #-}
35{-
46Copyright (C) 2006-2017 John MacFarlane <jgm@berkeley.edu>
@@ -39,10 +41,12 @@ import Control.Applicative (many, optional, (<|>))
3941import Control.Monad
4042import Control.Monad.Except (throwError)
4143import Data.Char (chr, isAlphaNum, isLetter, ord, isDigit)
44+import Data.Default
4245import Data.Text (Text, unpack)
4346import qualified Data.Text as T
4447import Data.List (intercalate, isPrefixOf)
4548import qualified Data.Map as M
49+import qualified Data.Set as Set
4650import Data.Maybe (fromMaybe, maybeToList)
4751import Safe (minimumDef)
4852import System.FilePath (addExtension, replaceExtension, takeExtension)
@@ -70,7 +74,7 @@ readLaTeX :: PandocMonad m
7074 -> Text -- ^ String to parse (assumes @'\n'@ line endings)
7175 -> m Pandoc
7276readLaTeX opts ltx = do
73− parsed <- runParserT parseLaTeX def{ stateOptions = opts } "source"
77+ parsed <- runParserT parseLaTeX def{ sOptions = opts } "source"
7478 (tokenize (crFilter ltx))
7579 case parsed of
7680 Right result -> return result
@@ -81,7 +85,7 @@ parseLaTeX = do
8185 bs <- blocks
8286 eof
8387 st <- getState
84− let meta = stateMeta st
88+ let meta = sMeta st
8589 let doc' = doc bs
8690 let headerLevel (Header n _ _) = [n]
8791 headerLevel _ = []
@@ -97,22 +101,85 @@ parseLaTeX = do
97101
98102testParser :: LP PandocIO a -> Text -> IO a
99103testParser p t = do
100− res <- runIOorExplode (runParserT p defaultParserState{
101− stateOptions = def{ readerExtensions =
104+ res <- runIOorExplode (runParserT p defaultLaTeXState{
105+ sOptions = def{ readerExtensions =
102106 getDefaultExtensions "latex" }} "name" (tokenize t))
103107 case res of
104108 Left e -> error (show e)
105109 Right r -> return r
106110
107−type LP m = ParserT [Tok] ParserState m
108−
109−rawLaTeXBlock :: PandocMonad m => ParserT String ParserState m String
111+data Macro = Macro -- TODO
112+ deriving Show
113+
114+data LaTeXState = LaTeXState{ sOptions :: ReaderOptions
115+ , sMeta :: Meta
116+ , sQuoteContext :: QuoteContext
117+ , sMacros :: [Macro]
118+ , sContainers :: [String]
119+ , sHeaders :: M.Map Inlines String
120+ , sLogMessages :: [LogMessage]
121+ , sIdentifiers :: Set.Set String }
122+ deriving Show
123+
124+defaultLaTeXState :: LaTeXState
125+defaultLaTeXState = LaTeXState{ sOptions = def
126+ , sMeta = nullMeta
127+ , sQuoteContext = NoQuote
128+ , sMacros = []
129+ , sContainers = []
130+ , sHeaders = M.empty
131+ , sLogMessages = []
132+ , sIdentifiers = Set.empty }
133+
134+instance PandocMonad m => HasQuoteContext LaTeXState m where
135+ getQuoteContext = sQuoteContext <$> getState
136+ withQuoteContext context parser = do
137+ oldState <- getState
138+ let oldQuoteContext = sQuoteContext oldState
139+ setState oldState { sQuoteContext = context }
140+ result <- parser
141+ newState <- getState
142+ setState newState { sQuoteContext = oldQuoteContext }
143+ return result
144+
145+instance HasLogMessages LaTeXState where
146+ addLogMessage msg st = st{ sLogMessages = msg : sLogMessages st }
147+ getLogMessages st = reverse $ sLogMessages st
148+
149+instance HasIdentifierList LaTeXState where
150+ extractIdentifierList = sIdentifiers
151+ updateIdentifierList f st = st{ sIdentifiers = f $ sIdentifiers st }
152+
153+instance HasIncludeFiles LaTeXState where
154+ getIncludeFiles = sContainers
155+ addIncludeFile f s = s{ sContainers = f : sContainers s }
156+ dropLatestIncludeFile s = s { sContainers = drop 1 $ sContainers s }
157+
158+instance HasHeaderMap LaTeXState where
159+ extractHeaderMap = sHeaders
160+ updateHeaderMap f st = st{ sHeaders = f $ sHeaders st }
161+
162+instance HasReaderOptions LaTeXState where
163+ extractReaderOptions = sOptions
164+
165+instance HasMeta LaTeXState where
166+ setMeta field val st =
167+ st{ sMeta = setMeta field val $ sMeta st }
168+ deleteMeta field st =
169+ st{ sMeta = deleteMeta field $ sMeta st }
170+
171+instance Default LaTeXState where
172+ def = defaultLaTeXState
173+
174+type LP m = ParserT [Tok] LaTeXState m
175+
176+rawLaTeXBlock :: PandocMonad m => ParserT String LaTeXState m String
110177rawLaTeXBlock = mzero
111178
112−rawLaTeXInline :: PandocMonad m => ParserT String ParserState m Inline
179+rawLaTeXInline :: PandocMonad m => ParserT String LaTeXState m Inline
113180rawLaTeXInline = mzero
114181
115−inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines
182+inlineCommand :: PandocMonad m => ParserT String LaTeXState m Inlines
116183inlineCommand = mzero
117184
118185data TokType = CtrlSeq | Spaces | Newline | Symbol | Word | Comment |
@@ -206,11 +273,11 @@ satisfyTok f =
206273 setSourceColumn (setSourceLine spos lin) col
207274 updatePos spos _ [] = spos
208275
209−-- TODO use something other than ParserState
276+-- TODO use something other than LaTeXState
210277doMacros :: PandocMonad m => LP m ()
211278doMacros = do
212279 inp <- getInput
213− macros <- stateMacros <$> getState
280+ macros <- sMacros <$> getState
214281 case inp of
215282 t@(Tok spos CtrlSeq txt) : ts
216283 | txt == "\\macro" -> do -- TODO actually check macros
@@ -419,8 +486,8 @@ quoted' f starter ender = do
419486enquote :: PandocMonad m => LP m Inlines
420487enquote = do
421488 skipopts
422− context <- stateQuoteContext <$> getState
423− if context == InDoubleQuote
489+ quoteContext <- sQuoteContext <$> getState
490+ if quoteContext == InDoubleQuote
424491 then singleQuoted <$> withQuoteContext InSingleQuote tok
425492 else doubleQuoted <$> withQuoteContext InDoubleQuote tok
426493
@@ -1119,7 +1186,7 @@ ignoreBlocks name = (name, p)
11191186
11201187addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
11211188addMeta field val = updateState $ \st ->
1122− st{ stateMeta = addMetaField field val $ stateMeta st }
1189+ st{ sMeta = addMetaField field val $ sMeta st }
11231190
11241191authors :: PandocMonad m => LP m ()
11251192authors = try $ do
@@ -1165,7 +1232,7 @@ closing = do
11651232 let extractInlines (MetaBlocks [Plain ys]) = ys
11661233 extractInlines (MetaBlocks [Para ys ]) = ys
11671234 extractInlines _ = []
1168− let sigs = case lookupMeta "author" (stateMeta st) of
1235+ let sigs = case lookupMeta "author" (sMeta st) of
11691236 Just (MetaList xs) ->
11701237 para $ trimInlines $ fromList $
11711238 intercalate [LineBreak] $ map extractInlines xs
@@ -1371,7 +1438,7 @@ blocks = mconcat <$> many block
13711438--
13721439-- addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
13731440-- addMeta field val = updateState $ \st ->
1374−-- st{ stateMeta = addMetaField field val $ stateMeta st }
1441+-- st{ sMeta = addMetaField field val $ sMeta st }
13751442--
13761443-- splitBibs :: String -> [Inlines]
13771444-- splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
@@ -1464,10 +1531,10 @@ blocks = mconcat <$> many block
14641531-- where strToCode (Str s) = Code nullAttr s
14651532-- strToCode x = x
14661533--
1467−-- rawLaTeXBlock :: PandocMonad m => ParserT String ParserState String
1534+-- rawLaTeXBlock :: PandocMonad m => ParserT String LaTeXState String
14681535-- rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
14691536--
1470−-- rawLaTeXInline :: PandocMonad m => ParserT String ParserState Inline
1537+-- rawLaTeXInline :: PandocMonad m => ParserT String LaTeXState Inline
14711538-- rawLaTeXInline = do
14721539-- raw <- (snd <$> withRaw inlineCommand)
14731540-- <|> (snd <$> withRaw inlineEnvironment)
@@ -1504,7 +1571,7 @@ blocks = mconcat <$> many block
15041571-- bs <- blocks
15051572-- st <- getState
15061573-- -- add signature (author) and address (title)
1507−-- let addr = case lookupMeta "address" (stateMeta st) of
1574+-- let addr = case lookupMeta "address" (sMeta st) of
15081575-- Just (MetaBlocks [Plain xs]) ->
15091576-- para $ trimInlines $ fromList xs
15101577-- _ -> mempty