@@ -110,6 +110,8 @@ import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..),
110import Text.Pandoc.Shared
110import Text.Pandoc.Shared
111import Text.Parsec.Pos
111import Text.Parsec.Pos
113+-- import Debug.Trace (traceShowId)
113newtype DottedNum = DottedNum [Int]
115newtype DottedNum = DottedNum [Int]
114 deriving (Show)
116 deriving (Show)
@@ -231,7 +233,7 @@ rawLaTeXParser retokenize parser valParser = do
231 Right toks' -> do
233 Right toks' -> do
232 res <- lift $ runParserT (do when retokenize $ do
234 res <- lift $ runParserT (do when retokenize $ do
233 -- retokenize, applying macros
235 -- retokenize, applying macros
234− doMacros 0
236+ doMacros
235 ts <- many (satisfyTok (const True))
237 ts <- many (satisfyTok (const True))
236 setInput ts
238 setInput ts
237 rawparser)
239 rawparser)
@@ -246,7 +248,7 @@ rawLaTeXParser retokenize parser valParser = do
246applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s)
248applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s)
247 => String -> ParserT String s m String
249 => String -> ParserT String s m String
248applyMacros s = (guardDisabled Ext_latex_macros >> return s) <|>
250applyMacros s = (guardDisabled Ext_latex_macros >> return s) <|>
249− do let retokenize = doMacros 0 *>
251+ do let retokenize = doMacros *>
250 (toksToString <$> many (satisfyTok (const True)))
252 (toksToString <$> many (satisfyTok (const True)))
251 pstate <- getState
253 pstate <- getState
252 let lstate = def{ sOptions = extractReaderOptions pstate
254 let lstate = def{ sOptions = extractReaderOptions pstate
@@ -371,7 +373,7 @@ satisfyTok :: PandocMonad m => (Tok -> Bool) -> LP m Tok
371satisfyTok f =
373satisfyTok f =
373 res <- tokenPrim (T.unpack . untoken) updatePos matcher
375 res <- tokenPrim (T.unpack . untoken) updatePos matcher
374− doMacros 0 -- apply macros on remaining input stream
376+ doMacros -- apply macros on remaining input stream
375 return res
377 return res
376 where matcher t | f t = Just t
378 where matcher t | f t = Just t
377 | otherwise = Nothing
379 | otherwise = Nothing
@@ -379,25 +381,29 @@ satisfyTok f =
379 updatePos _spos _ (Tok pos _ _ : _) = pos
381 updatePos _spos _ (Tok pos _ _ : _) = pos
380 updatePos spos _ [] = incSourceColumn spos 1
382 updatePos spos _ [] = incSourceColumn spos 1
382−doMacros :: PandocMonad m => Int -> LP m ()
384+doMacros :: PandocMonad m => LP m ()
383−doMacros n = do
385+doMacros = do
384 verbatimMode <- sVerbatimMode <$> getState
386 verbatimMode <- sVerbatimMode <$> getState
385 unless verbatimMode $ do
387 unless verbatimMode $ do
386− inp <- getInput
388+ mbNewInp <- getInput >>= doMacros' 1
390+ Nothing -> return ()
391+ Just inp -> setInput inp
393+doMacros' :: PandocMonad m => Int -> [Tok] -> LP m (Maybe [Tok])
387− case inp of
395+ case inp of
388− Tok spos (CtrlSeq "begin") _ : Tok _ Symbol "{" :
396+ Tok spos (CtrlSeq "begin") _ : Tok _ Symbol "{" :
389− Tok _ Word name : Tok _ Symbol "}" : ts
397+ Tok _ Word name : Tok _ Symbol "}" : ts
390− -> handleMacros spos name ts
398+ -> handleMacros n spos name ts
391− Tok spos (CtrlSeq "end") _ : Tok _ Symbol "{" :
399+ Tok spos (CtrlSeq "end") _ : Tok _ Symbol "{" :
392− Tok _ Word name : Tok _ Symbol "}" : ts
400+ Tok _ Word name : Tok _ Symbol "}" : ts
393− -> handleMacros spos ("end" <> name) ts
401+ -> handleMacros n spos ("end" <> name) ts
394− Tok _ (CtrlSeq "expandafter") _ : t : ts
402+ Tok _ (CtrlSeq "expandafter") _ : t : ts
397− getInput >>= setInput . combineTok t
403+ -> (fmap (combineTok t)) <$> doMacros' n ts
398− Tok spos (CtrlSeq name) _ : ts
404+ Tok spos (CtrlSeq name) _ : ts
399− -> handleMacros spos name ts
405+ -> handleMacros n spos name ts
400− _ -> return ()
406+ _ -> return Nothing
403 combineTok (Tok spos (CtrlSeq name) x) (Tok _ Word w : ts)
409 combineTok (Tok spos (CtrlSeq name) x) (Tok _ Word w : ts)
@@ -419,9 +425,7 @@ doMacros n = do
419 getargs argmap rest
425 getargs argmap rest
420 getargs argmap (ArgNum i : Pattern toks : rest) =
426 getargs argmap (ArgNum i : Pattern toks : rest) =
422− x <- mconcat <$> manyTill
428+ x <- mconcat <$> manyTill bracedOrToken (matchPattern toks)
423− (braced <|> ((:[]) <$> anyTok))
425 getargs (M.insert i x argmap) rest
429 getargs (M.insert i x argmap) rest
426 getargs argmap (ArgNum i : rest) = do
430 getargs argmap (ArgNum i : rest) = do
427 x <- try $ spaces >> bracedOrToken
431 x <- try $ spaces >> bracedOrToken
@@ -439,10 +443,12 @@ doMacros n = do
439 Tok spos (CtrlSeq x) (txt <> " ") : acc
443 Tok spos (CtrlSeq x) (txt <> " ") : acc
440 addTok _ _ spos t acc = setpos spos t : acc
444 addTok _ _ spos t acc = setpos spos t : acc
442− handleMacros spos name ts = do
446+ handleMacros n' spos name ts = do
447+ when (n' > 20) -- detect macro expansion loops
448+ $ throwError $ PandocMacroLoop (T.unpack name)
443 macros <- sMacros <$> getState
449 macros <- sMacros <$> getState
444 case M.lookup name macros of
450 case M.lookup name macros of
445− Nothing -> return ()
451+ Nothing -> return Nothing
446 Just (Macro expansionPoint argspecs optarg newtoks) -> do
452 Just (Macro expansionPoint argspecs optarg newtoks) -> do
447 setInput ts
453 setInput ts
448 args <- case optarg of
454 args <- case optarg of
@@ -454,15 +460,12 @@ doMacros n = do
454 -- an argument (in which case we don't want to
460 -- an argument (in which case we don't want to
455 -- expand #1 etc.)
461 -- expand #1 etc.)
456 ts' <- getInput
462 ts' <- getInput
457− setInput $ foldr (addTok False args spos) ts' newtoks
463+ let result = foldr (addTok False args spos) ts' newtoks
459 case expansionPoint of
464 case expansionPoint of
460− ExpandWhenUsed ->
465+ ExpandWhenUsed ->
461− if n > 20 -- detect macro expansion loops
462− then throwError $ PandocMacroLoop (T.unpack name)
463− else doMacros (n + 1)
466+ doMacros' (n' + 1) result >>=
467+ maybe (return (Just result)) (return . Just)
464− ExpandWhenDefined -> return ()
468+ ExpandWhenDefined -> return $ Just result
467setpos :: SourcePos -> Tok -> Tok
470setpos :: SourcePos -> Tok -> Tok
468setpos spos (Tok _ tt txt) = Tok spos tt txt
471setpos spos (Tok _ tt txt) = Tok spos tt txt