LaTeX reader: improved parsing of \def, \let.

We now correctly parse:

```
\def\bar{hello}
\let\fooi\bar
\def\fooii{\bar}
\fooi +\fooii

\def\bar{goodbye}
\fooi +\fooii
```
This commit is contained in:
John MacFarlane
2018-10-15 11:27:04 -07:00
parent 68ec838014
commit e6ee032a6d
2 changed files with 41 additions and 27 deletions
+18 -11
View File
@@ -1506,21 +1506,28 @@ macroDef =
letmacro :: PandocMonad m => LP m (Text, Macro)
letmacro = do
controlSeq "let"
Tok _ (CtrlSeq name) _ <- anyControlSeq
optional $ symbol '='
spaces
contents <- bracedOrToken
return (name, Macro ExpandWhenDefined [] Nothing contents)
(name, contents) <- withVerbatimMode $ do
Tok _ (CtrlSeq name) _ <- withVerbatimMode anyControlSeq
optional $ symbol '='
spaces
-- we first parse in verbatim mode, and then expand macros,
-- because we don't want \let\foo\bar to turn into
-- \let\foo hello if we have previously \def\bar{hello}
contents <- bracedOrToken
return (name, contents)
contents' <- fromMaybe contents <$> doMacros' 0 contents
return (name, Macro ExpandWhenDefined [] Nothing contents')
defmacro :: PandocMonad m => LP m (Text, Macro)
defmacro = try $ do
controlSeq "def"
Tok _ (CtrlSeq name) _ <- anyControlSeq
argspecs <- many (argspecArg <|> argspecPattern)
defmacro = try $
-- we use withVerbatimMode, because macros are to be expanded
-- at point of use, not point of definition
contents <- withVerbatimMode bracedOrToken
return (name, Macro ExpandWhenUsed argspecs Nothing contents)
withVerbatimMode $ do
controlSeq "def"
Tok _ (CtrlSeq name) _ <- anyControlSeq
argspecs <- many (argspecArg <|> argspecPattern)
contents <- bracedOrToken
return (name, Macro ExpandWhenUsed argspecs Nothing contents)
argspecArg :: PandocMonad m => LP m ArgSpec
argspecArg = do
+23 -16
View File
@@ -49,6 +49,7 @@ module Text.Pandoc.Readers.LaTeX.Parsing
, toksToString
, satisfyTok
, doMacros
, doMacros'
, setpos
, anyControlSeq
, anySymbol
@@ -451,22 +452,28 @@ doMacros' n inp = do
case M.lookup name macros of
Nothing -> return Nothing
Just (Macro expansionPoint argspecs optarg newtoks) -> do
setInput ts
args <- case optarg of
Nothing -> getargs M.empty argspecs
Just o -> do
x <- option o bracketedToks
getargs (M.singleton 1 x) argspecs
-- first boolean param is true if we're tokenizing
-- an argument (in which case we don't want to
-- expand #1 etc.)
ts' <- getInput
let result = foldr (addTok False args spos) ts' newtoks
case expansionPoint of
ExpandWhenUsed ->
doMacros' (n' + 1) result >>=
maybe (return (Just result)) (return . Just)
ExpandWhenDefined -> return $ Just result
let getargs' = do
args <- case optarg of
Nothing -> getargs M.empty argspecs
Just o -> do
x <- option o bracketedToks
getargs (M.singleton 1 x) argspecs
rest <- getInput
return (args, rest)
lstate <- getState
res <- lift $ runParserT getargs' lstate "args" ts
case res of
Left _ -> fail $ "Could not parse arguments for " ++
T.unpack name
Right (args, rest) -> do
-- first boolean param is true if we're tokenizing
-- an argument (in which case we don't want to
-- expand #1 etc.)
let result = foldr (addTok False args spos) rest newtoks
case expansionPoint of
ExpandWhenUsed ->
maybe (Just result) Just <$> doMacros' (n' + 1) result
ExpandWhenDefined -> return $ Just result
setpos :: SourcePos -> Tok -> Tok
setpos spos (Tok _ tt txt) = Tok spos tt txt