git.iko.soy/typeable/pandoc
on master help sign in
LaTeX reader: Support `\let`.
9e6b9cdJohn MacFarlane
src/Text/Pandoc/Readers/LaTeX.hs+28−13
@@ -65,7 +65,7 @@ import Text.Pandoc.Parsing hiding (many, optional, withRaw,
65 mathInline, mathDisplay,
65 mathInline, mathDisplay,
66 space, (<|>), spaces, blankline)
66 space, (<|>), spaces, blankline)
67import Text.Pandoc.Shared
67import Text.Pandoc.Shared
68−import Text.Pandoc.Readers.LaTeX.Types (Macro(..), Tok(..),
68+import Text.Pandoc.Readers.LaTeX.Types (Macro(..), ExpansionPoint(..), Tok(..),
69 TokType(..))
69 TokType(..))
70import Text.Pandoc.Walk
70import Text.Pandoc.Walk
71import Text.Pandoc.Error (PandocError(PandocParsecError, PandocMacroLoop))
71import Text.Pandoc.Error (PandocError(PandocParsecError, PandocMacroLoop))
@@ -375,7 +375,7 @@ doMacros n = do
375 macros <- sMacros <$> getState
375 macros <- sMacros <$> getState
376 case M.lookup name macros of
376 case M.lookup name macros of
377 Nothing -> return ()
377 Nothing -> return ()
378− Just (Macro numargs optarg newtoks) -> do
378+ Just (Macro expansionPoint numargs optarg newtoks) -> do
379 setInput ts
379 setInput ts
380 let getarg = spaces >> braced
380 let getarg = spaces >> braced
381 args <- case optarg of
381 args <- case optarg of
@@ -389,9 +389,12 @@ doMacros n = do
389 addTok t acc = setpos spos t : acc
389 addTok t acc = setpos spos t : acc
390 ts' <- getInput
390 ts' <- getInput
391 setInput $ foldr addTok ts' newtoks
391 setInput $ foldr addTok ts' newtoks
392+ case expansionPoint of
393+ ExpandWhenUsed ->
392− if n > 20 -- detect macro expansion loops
394+ if n > 20 -- detect macro expansion loops
393− then throwError $ PandocMacroLoop (T.unpack name)
395+ then throwError $ PandocMacroLoop (T.unpack name)
394− else doMacros (n + 1)
396+ else doMacros (n + 1)
397+ ExpandWhenDefined -> return ()
395
398
396setpos :: (Line, Column) -> Tok -> Tok
399setpos :: (Line, Column) -> Tok -> Tok
397setpos spos (Tok _ tt txt) = Tok spos tt txt
400setpos spos (Tok _ tt txt) = Tok spos tt txt
@@ -1375,7 +1378,8 @@ isBlockCommand s =
1375
1378
1376treatAsBlock :: Set.Set Text
1379treatAsBlock :: Set.Set Text
1377treatAsBlock = Set.fromList
1380treatAsBlock = Set.fromList
1381+ [ "let"
1378− [ "newcommand", "renewcommand"
1382+ , "newcommand", "renewcommand"
1379 , "newenvironment", "renewenvironment"
1383 , "newenvironment", "renewenvironment"
1380 , "providecommand", "provideenvironment"
1384 , "providecommand", "provideenvironment"
1381 -- newcommand, etc. should be parsed by macroDef, but we need this
1385 -- newcommand, etc. should be parsed by macroDef, but we need this
@@ -1517,7 +1521,7 @@ macroDef :: PandocMonad m => LP m Blocks
1517macroDef = do
1521macroDef = do
1518 mempty <$ ((commandDef <|> environmentDef) <* doMacros 0)
1522 mempty <$ ((commandDef <|> environmentDef) <* doMacros 0)
1519 where commandDef = do
1523 where commandDef = do
1520− (name, macro') <- newcommand
1524+ (name, macro') <- newcommand <|> letmacro
1521 guardDisabled Ext_latex_macros <|>
1525 guardDisabled Ext_latex_macros <|>
1522 updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
1526 updateState (\s -> s{ sMacros = M.insert name macro' (sMacros s) })
1523 environmentDef = do
1527 environmentDef = do
@@ -1532,6 +1536,15 @@ macroDef = do
1532 -- @\newcommand{\envname}[n-args][default]{begin}@
1536 -- @\newcommand{\envname}[n-args][default]{begin}@
1533 -- @\newcommand{\endenvname}@
1537 -- @\newcommand{\endenvname}@
1534
1538
1539+letmacro :: PandocMonad m => LP m (Text, Macro)
1540+letmacro = do
1541+ pos <- getPosition
1542+ controlSeq "let"
1543+ Tok _ (CtrlSeq name) _ <- anyControlSeq
1544+ optional $ symbol '='
1545+ contents <- braced <|> ((:[]) <$> anyControlSeq)
1546+ return (name, Macro ExpandWhenDefined 0 Nothing contents)
1547+
1535newcommand :: PandocMonad m => LP m (Text, Macro)
1548newcommand :: PandocMonad m => LP m (Text, Macro)
1536newcommand = do
1549newcommand = do
1537 pos <- getPosition
1550 pos <- getPosition
@@ -1546,13 +1559,15 @@ newcommand = do
1546 spaces
1559 spaces
1547 optarg <- option Nothing $ Just <$> try bracketedToks
1560 optarg <- option Nothing $ Just <$> try bracketedToks
1548 spaces
1561 spaces
1549− contents <- braced
1562+ contents <- withVerbatimMode braced
1563+ -- we use withVerbatimMode, because macros are to be expanded
1564+ -- at point of use, not point of definition
1550 when (mtype == "newcommand") $ do
1565 when (mtype == "newcommand") $ do
1551 macros <- sMacros <$> getState
1566 macros <- sMacros <$> getState
1552 case M.lookup name macros of
1567 case M.lookup name macros of
1553 Just _ -> report $ MacroAlreadyDefined (T.unpack txt) pos
1568 Just _ -> report $ MacroAlreadyDefined (T.unpack txt) pos
1554 Nothing -> return ()
1569 Nothing -> return ()
1555− return (name, Macro numargs optarg contents)
1570+ return (name, Macro ExpandWhenUsed numargs optarg contents)
1556
1571
1557newenvironment :: PandocMonad m => LP m (Text, Macro, Macro)
1572newenvironment :: PandocMonad m => LP m (Text, Macro, Macro)
1558newenvironment = do
1573newenvironment = do
@@ -1568,16 +1583,16 @@ newenvironment = do
1568 spaces
1583 spaces
1569 optarg <- option Nothing $ Just <$> try bracketedToks
1584 optarg <- option Nothing $ Just <$> try bracketedToks
1570 spaces
1585 spaces
1571− startcontents <- braced
1586+ startcontents <- withVerbatimMode braced
1572 spaces
1587 spaces
1573− endcontents <- braced
1588+ endcontents <- withVerbatimMode braced
1574 when (mtype == "newenvironment") $ do
1589 when (mtype == "newenvironment") $ do
1575 macros <- sMacros <$> getState
1590 macros <- sMacros <$> getState
1576 case M.lookup name macros of
1591 case M.lookup name macros of
1577 Just _ -> report $ MacroAlreadyDefined (T.unpack name) pos
1592 Just _ -> report $ MacroAlreadyDefined (T.unpack name) pos
1578 Nothing -> return ()
1593 Nothing -> return ()
1579− return (name, Macro numargs optarg startcontents,
1594+ return (name, Macro ExpandWhenUsed numargs optarg startcontents,
1580− Macro 0 Nothing endcontents)
1595+ Macro ExpandWhenUsed 0 Nothing endcontents)
1581
1596
1582bracketedToks :: PandocMonad m => LP m [Tok]
1597bracketedToks :: PandocMonad m => LP m [Tok]
1583bracketedToks = do
1598bracketedToks = do
src/Text/Pandoc/Readers/LaTeX/Types.hs+5−1
@@ -30,6 +30,7 @@ Types for LaTeX tokens and macros.
30module Text.Pandoc.Readers.LaTeX.Types ( Tok(..)
30module Text.Pandoc.Readers.LaTeX.Types ( Tok(..)
31 , TokType(..)
31 , TokType(..)
32 , Macro(..)
32 , Macro(..)
33+ , ExpansionPoint(..)
33 , Line
34 , Line
34 , Column )
35 , Column )
35where
36where
@@ -43,6 +44,9 @@ data TokType = CtrlSeq Text | Spaces | Newline | Symbol | Word | Comment |
43data Tok = Tok (Line, Column) TokType Text
44data Tok = Tok (Line, Column) TokType Text
44 deriving (Eq, Ord, Show)
45 deriving (Eq, Ord, Show)
45
46
47+data ExpansionPoint = ExpandWhenDefined | ExpandWhenUsed
48+ deriving (Eq, Ord, Show)
49+
46−data Macro = Macro Int (Maybe [Tok]) [Tok]
50+data Macro = Macro ExpansionPoint Int (Maybe [Tok]) [Tok]
47 deriving Show
51 deriving Show
48
52
test/command/macros.md+23
@@ -15,3 +15,26 @@ $\my+\my$
15\newcommand{\my}{\phi}
15\newcommand{\my}{\phi}
16$\my+\my$
16$\my+\my$
17```
17```
18+
19+`\let` macros should be expanded at point of
20+definition, while `\newcommand` macros should be
21+expanded at point of use:
22+
23+```
24+% pandoc -f latex -t latex
25+\let\a\b
26+\newcommand{\b}{\emph{ouk}}
27+\a
28+^D
29+\b
30+```
31+
32+```
33+% pandoc -f latex -t latex
34+\newcommand{\a}{\b}
35+\newcommand{\b}{\emph{ouk}}
36+\a
37+^D
38+\emph{ouk}
39+```
40+