diff options
Diffstat (limited to 'src/Text')
-rw-r--r-- | src/Text/Pandoc/Parsing.hs | 241 |
1 files changed, 118 insertions, 123 deletions
diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs index 74c029bfb..187343f9c 100644 --- a/src/Text/Pandoc/Parsing.hs +++ b/src/Text/Pandoc/Parsing.hs @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA {- | Module : Text.Pandoc.Parsing Copyright : Copyright (C) 2006-2010 John MacFarlane - License : GNU GPL, version 2 or above + License : GNU GPL, version 2 or above Maintainer : John MacFarlane <jgm@berkeley.edu> Stability : alpha @@ -27,9 +27,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA A utility library with parsers used in pandoc readers. -} -module Text.Pandoc.Parsing ( GeneralParser, - PandocParser, - (>>~), +module Text.Pandoc.Parsing ( (>>~), anyLine, many1Till, notFollowedBy', @@ -88,68 +86,64 @@ import Text.Pandoc.Shared import qualified Data.Map as M import Text.TeXMath.Macros (applyMacros, Macro, parseMacroDefinitions) -type GeneralParser st a = GenParser Char st a - -type PandocParser a = GeneralParser ParserState a - -- | Like >>, but returns the operation on the left. -- (Suggested by Tillmann Rendel on Haskell-cafe list.) (>>~) :: (Monad m) => m a -> m b -> m a a >>~ b = a >>= \x -> b >> return x -- | Parse any line of text -anyLine :: GeneralParser st String +anyLine :: GenParser Char st [Char] anyLine = manyTill anyChar newline -- | Like @manyTill@, but reads at least one item. -many1Till :: GeneralParser st a - -> GeneralParser st end - -> GeneralParser st [a] +many1Till :: GenParser tok st a + -> GenParser tok st end + -> GenParser tok st [a] many1Till p end = do first <- p rest <- manyTill p end return (first:rest) --- | A more general form of @notFollowedBy@. This one allows any +-- | A more general form of @notFollowedBy@. This one allows any -- type of parser to be specified, and succeeds only if that parser fails. -- It does not consume any input. -notFollowedBy' :: Show b => GeneralParser st b -> GeneralParser st () +notFollowedBy' :: Show b => GenParser a st b -> GenParser a st () notFollowedBy' p = try $ join $ do a <- try p return (unexpected (show a)) <|> return (return ()) -- (This version due to Andrew Pimlott on the Haskell mailing list.) --- | Parses one of a list of strings (tried in order). -oneOfStrings :: [String] -> GeneralParser st String +-- | Parses one of a list of strings (tried in order). +oneOfStrings :: [String] -> GenParser Char st String oneOfStrings listOfStrings = choice $ map (try . string) listOfStrings -- | Parses a space or tab. -spaceChar :: GeneralParser st Char +spaceChar :: CharParser st Char spaceChar = satisfy $ \c -> c == ' ' || c == '\t' -- | Skips zero or more spaces or tabs. -skipSpaces :: GeneralParser st () +skipSpaces :: GenParser Char st () skipSpaces = skipMany spaceChar -- | Skips zero or more spaces or tabs, then reads a newline. -blankline :: GeneralParser st Char +blankline :: GenParser Char st Char blankline = try $ skipSpaces >> newline -- | Parses one or more blank lines and returns a string of newlines. -blanklines :: GeneralParser st [Char] +blanklines :: GenParser Char st [Char] blanklines = many1 blankline -- | Parses material enclosed between start and end parsers. -enclosed :: GeneralParser st t -- ^ start parser - -> GeneralParser st end -- ^ end parser - -> GeneralParser st a -- ^ content parser (to be used repeatedly) - -> GeneralParser st [a] -enclosed start end parser = try $ +enclosed :: GenParser Char st t -- ^ start parser + -> GenParser Char st end -- ^ end parser + -> GenParser Char st a -- ^ content parser (to be used repeatedly) + -> GenParser Char st [a] +enclosed start end parser = try $ start >> notFollowedBy space >> many1Till parser end -- | Parse string, case insensitive. -stringAnyCase :: [Char] -> GeneralParser st String +stringAnyCase :: [Char] -> CharParser st String stringAnyCase [] = string "" stringAnyCase (x:xs) = do firstChar <- char (toUpper x) <|> char (toLower x) @@ -157,7 +151,7 @@ stringAnyCase (x:xs) = do return (firstChar:rest) -- | Parse contents of 'str' using 'parser' and return result. -parseFromString :: GeneralParser st a -> String -> GeneralParser st a +parseFromString :: GenParser tok st a -> [tok] -> GenParser tok st a parseFromString parser str = do oldPos <- getPosition oldInput <- getInput @@ -168,8 +162,8 @@ parseFromString parser str = do return result -- | Parse raw line block up to and including blank lines. -lineClump :: GeneralParser st String -lineClump = blanklines +lineClump :: GenParser Char st String +lineClump = blanklines <|> (many1 (notFollowedBy blankline >> anyLine) >>= return . unlines) -- | Parse a string of characters between an open character @@ -178,7 +172,7 @@ lineClump = blanklines -- @charsInBalanced '(' ')'@ will parse "(hello (there))" -- and return "hello (there)". Stop if a blank line is -- encountered. -charsInBalanced :: Char -> Char -> GeneralParser st String +charsInBalanced :: Char -> Char -> GenParser Char st String charsInBalanced open close = try $ do char open raw <- many $ (many1 (satisfy $ \c -> @@ -190,7 +184,7 @@ charsInBalanced open close = try $ do return $ concat raw -- | Like @charsInBalanced@, but allow blank lines in the content. -charsInBalanced' :: Char -> Char -> GeneralParser st String +charsInBalanced' :: Char -> Char -> GenParser Char st String charsInBalanced' open close = try $ do char open raw <- many $ (many1 (satisfy $ \c -> c /= open && c /= close)) @@ -209,13 +203,13 @@ uppercaseRomanDigits = map toUpper lowercaseRomanDigits -- | Parses a roman numeral (uppercase or lowercase), returns number. romanNumeral :: Bool -- ^ Uppercase if true - -> GeneralParser st Int + -> GenParser Char st Int romanNumeral upperCase = do - let romanDigits = if upperCase - then uppercaseRomanDigits + let romanDigits = if upperCase + then uppercaseRomanDigits else lowercaseRomanDigits lookAhead $ oneOf romanDigits - let [one, five, ten, fifty, hundred, fivehundred, thousand] = + let [one, five, ten, fifty, hundred, fivehundred, thousand] = map char romanDigits thousands <- many thousand >>= (return . (1000 *) . length) ninehundreds <- option 0 $ try $ hundred >> thousand >> return 900 @@ -239,14 +233,14 @@ romanNumeral upperCase = do -- Parsers for email addresses and URIs -emailChar :: GeneralParser st Char +emailChar :: GenParser Char st Char emailChar = alphaNum <|> satisfy (\c -> c == '-' || c == '+' || c == '_' || c == '.') -domainChar :: GeneralParser st Char +domainChar :: GenParser Char st Char domainChar = alphaNum <|> char '-' -domain :: GeneralParser st [Char] +domain :: GenParser Char st [Char] domain = do first <- many1 domainChar dom <- many1 $ try (char '.' >> many1 domainChar ) @@ -254,7 +248,7 @@ domain = do -- | Parses an email address; returns original and corresponding -- escaped mailto: URI. -emailAddress :: GeneralParser st (String, String) +emailAddress :: GenParser Char st (String, String) emailAddress = try $ do firstLetter <- alphaNum restAddr <- many emailChar @@ -265,7 +259,7 @@ emailAddress = try $ do return (full, escapeURI $ "mailto:" ++ full) -- | Parses a URI. Returns pair of original and URI-escaped version. -uri :: GeneralParser st (String, String) +uri :: GenParser Char st (String, String) uri = try $ do let protocols = [ "http:", "https:", "ftp:", "file:", "mailto:", "news:", "telnet:" ] @@ -299,8 +293,8 @@ uri = try $ do -- displacement (the difference between the source column at the end -- and the source column at the beginning). Vertical displacement -- (source row) is ignored. -withHorizDisplacement :: GeneralParser st a -- ^ Parser to apply - -> GeneralParser st (a, Int) -- ^ (result, displacement) +withHorizDisplacement :: GenParser Char st a -- ^ Parser to apply + -> GenParser Char st (a, Int) -- ^ (result, displacement) withHorizDisplacement parser = do pos1 <- getPosition result <- parser @@ -309,43 +303,43 @@ withHorizDisplacement parser = do -- | Parses a character and returns 'Null' (so that the parser can move on -- if it gets stuck). -nullBlock :: GeneralParser st Block +nullBlock :: GenParser Char st Block nullBlock = anyChar >> return Null -- | Fail if reader is in strict markdown syntax mode. -failIfStrict :: PandocParser () +failIfStrict :: GenParser a ParserState () failIfStrict = do state <- getState if stateStrict state then fail "strict mode" else return () -- | Fail unless we're in literate haskell mode. -failUnlessLHS :: PandocParser () +failUnlessLHS :: GenParser tok ParserState () failUnlessLHS = do state <- getState if stateLiterateHaskell state then return () else fail "Literate haskell feature" -- | Parses backslash, then applies character parser. -escaped :: GeneralParser st Char -- ^ Parser for character to escape - -> GeneralParser st Inline +escaped :: GenParser Char st Char -- ^ Parser for character to escape + -> GenParser Char st Inline escaped parser = try $ do char '\\' result <- parser return (Str [result]) -- | Parses an uppercase roman numeral and returns (UpperRoman, number). -upperRoman :: GeneralParser st (ListNumberStyle, Int) +upperRoman :: GenParser Char st (ListNumberStyle, Int) upperRoman = do num <- romanNumeral True return (UpperRoman, num) -- | Parses a lowercase roman numeral and returns (LowerRoman, number). -lowerRoman :: GeneralParser st (ListNumberStyle, Int) +lowerRoman :: GenParser Char st (ListNumberStyle, Int) lowerRoman = do num <- romanNumeral False return (LowerRoman, num) -- | Parses a decimal numeral and returns (Decimal, number). -decimal :: GeneralParser st (ListNumberStyle, Int) +decimal :: GenParser Char st (ListNumberStyle, Int) decimal = do num <- many1 digit return (Decimal, read num) @@ -354,7 +348,7 @@ decimal = do -- returns (DefaultStyle, [next example number]). The next -- example number is incremented in parser state, and the label -- (if present) is added to the label table. -exampleNum :: PandocParser (ListNumberStyle, Int) +exampleNum :: GenParser Char ParserState (ListNumberStyle, Int) exampleNum = do char '@' lab <- many (alphaNum <|> satisfy (\c -> c == '_' || c == '-')) @@ -368,38 +362,38 @@ exampleNum = do return (Example, num) -- | Parses a '#' returns (DefaultStyle, 1). -defaultNum :: GeneralParser st (ListNumberStyle, Int) +defaultNum :: GenParser Char st (ListNumberStyle, Int) defaultNum = do char '#' return (DefaultStyle, 1) -- | Parses a lowercase letter and returns (LowerAlpha, number). -lowerAlpha :: GeneralParser st (ListNumberStyle, Int) +lowerAlpha :: GenParser Char st (ListNumberStyle, Int) lowerAlpha = do ch <- oneOf ['a'..'z'] return (LowerAlpha, ord ch - ord 'a' + 1) -- | Parses an uppercase letter and returns (UpperAlpha, number). -upperAlpha :: GeneralParser st (ListNumberStyle, Int) +upperAlpha :: GenParser Char st (ListNumberStyle, Int) upperAlpha = do ch <- oneOf ['A'..'Z'] return (UpperAlpha, ord ch - ord 'A' + 1) -- | Parses a roman numeral i or I -romanOne :: GeneralParser st (ListNumberStyle, Int) +romanOne :: GenParser Char st (ListNumberStyle, Int) romanOne = (char 'i' >> return (LowerRoman, 1)) <|> (char 'I' >> return (UpperRoman, 1)) -- | Parses an ordered list marker and returns list attributes. -anyOrderedListMarker :: PandocParser ListAttributes -anyOrderedListMarker = choice $ +anyOrderedListMarker :: GenParser Char ParserState ListAttributes +anyOrderedListMarker = choice $ [delimParser numParser | delimParser <- [inPeriod, inOneParen, inTwoParens], numParser <- [decimal, exampleNum, defaultNum, romanOne, lowerAlpha, lowerRoman, upperAlpha, upperRoman]] -- | Parses a list number (num) followed by a period, returns list attributes. -inPeriod :: GeneralParser st (ListNumberStyle, Int) - -> GeneralParser st ListAttributes +inPeriod :: GenParser Char st (ListNumberStyle, Int) + -> GenParser Char st ListAttributes inPeriod num = try $ do (style, start) <- num char '.' @@ -407,18 +401,18 @@ inPeriod num = try $ do then DefaultDelim else Period return (start, style, delim) - + -- | Parses a list number (num) followed by a paren, returns list attributes. -inOneParen :: GeneralParser st (ListNumberStyle, Int) - -> GeneralParser st ListAttributes +inOneParen :: GenParser Char st (ListNumberStyle, Int) + -> GenParser Char st ListAttributes inOneParen num = try $ do (style, start) <- num char ')' return (start, style, OneParen) -- | Parses a list number (num) enclosed in parens, returns list attributes. -inTwoParens :: GeneralParser st (ListNumberStyle, Int) - -> GeneralParser st ListAttributes +inTwoParens :: GenParser Char st (ListNumberStyle, Int) + -> GenParser Char st ListAttributes inTwoParens num = try $ do char '(' (style, start) <- num @@ -427,9 +421,9 @@ inTwoParens num = try $ do -- | Parses an ordered list marker with a given style and delimiter, -- returns number. -orderedListMarker :: ListNumberStyle - -> ListNumberDelim - -> PandocParser Int +orderedListMarker :: ListNumberStyle + -> ListNumberDelim + -> GenParser Char ParserState Int orderedListMarker style delim = do let num = defaultNum <|> -- # can continue any kind of list case style of @@ -449,19 +443,19 @@ orderedListMarker style delim = do return start -- | Parses a character reference and returns a Str element. -charRef :: GeneralParser st Inline +charRef :: GenParser Char st Inline charRef = do c <- characterReference return $ Str [c] -- | Parse a table using 'headerParser', 'rowParser', -- 'lineParser', and 'footerParser'. -tableWith :: PandocParser ([[Block]], [Alignment], [Int]) - -> ([Int] -> PandocParser [[Block]]) - -> PandocParser sep - -> PandocParser end - -> PandocParser [Inline] - -> PandocParser Block +tableWith :: GenParser Char ParserState ([[Block]], [Alignment], [Int]) + -> ([Int] -> GenParser Char ParserState [[Block]]) + -> GenParser Char ParserState sep + -> GenParser Char ParserState end + -> GenParser Char ParserState [Inline] + -> GenParser Char ParserState Block tableWith headerParser rowParser lineParser footerParser captionParser = try $ do caption' <- option [] captionParser (heads, aligns, indices) <- headerParser @@ -479,8 +473,8 @@ tableWith headerParser rowParser lineParser footerParser captionParser = try $ d widthsFromIndices :: Int -- Number of columns on terminal -> [Int] -- Indices -> [Double] -- Fractional relative sizes of columns -widthsFromIndices _ [] = [] -widthsFromIndices numColumns' indices = +widthsFromIndices _ [] = [] +widthsFromIndices numColumns' indices = let numColumns = max numColumns' (if null indices then 0 else last indices) lengths' = zipWith (-) indices (0:indices) lengths = reverse $ @@ -504,10 +498,10 @@ widthsFromIndices numColumns' indices = -- (which may be grid), then the rows, -- which may be grid, separated by blank lines, and -- ending with a footer (dashed line followed by blank line). -gridTableWith :: PandocParser Block -- ^ Block parser - -> PandocParser [Inline] -- ^ Caption parser +gridTableWith :: GenParser Char ParserState Block -- ^ Block parser + -> GenParser Char ParserState [Inline] -- ^ Caption parser -> Bool -- ^ Headerless table - -> PandocParser Block + -> GenParser Char ParserState Block gridTableWith block tableCaption headless = tableWith (gridTableHeader headless block) (gridTableRow block) (gridTableSep '-') gridTableFooter tableCaption @@ -515,13 +509,13 @@ gridTableSplitLine :: [Int] -> String -> [String] gridTableSplitLine indices line = map removeFinalBar $ tail $ splitByIndices (init indices) $ removeTrailingSpace line -gridPart :: Char -> GeneralParser st (Int, Int) +gridPart :: Char -> GenParser Char st (Int, Int) gridPart ch = do dashes <- many1 (char ch) char '+' return (length dashes, length dashes + 1) -gridDashedLines :: Char -> GeneralParser st [(Int,Int)] +gridDashedLines :: Char -> GenParser Char st [(Int,Int)] gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) >>~ blankline removeFinalBar :: String -> String @@ -529,18 +523,18 @@ removeFinalBar = reverse . dropWhile (`elem` " \t") . dropWhile (=='|') . reverse -- | Separator between rows of grid table. -gridTableSep :: Char -> PandocParser Char +gridTableSep :: Char -> GenParser Char ParserState Char gridTableSep ch = try $ gridDashedLines ch >> return '\n' -- | Parse header for a grid table. gridTableHeader :: Bool -- ^ Headerless table - -> PandocParser Block - -> PandocParser ([[Block]], [Alignment], [Int]) + -> GenParser Char ParserState Block + -> GenParser Char ParserState ([[Block]], [Alignment], [Int]) gridTableHeader headless block = try $ do optional blanklines dashes <- gridDashedLines '-' rawContent <- if headless - then return $ repeat "" + then return $ repeat "" else many1 (notFollowedBy (gridTableSep '=') >> char '|' >> many1Till anyChar newline) @@ -559,16 +553,16 @@ gridTableHeader headless block = try $ do map removeLeadingTrailingSpace rawHeads return (heads, aligns, indices) -gridTableRawLine :: [Int] -> PandocParser [String] +gridTableRawLine :: [Int] -> GenParser Char ParserState [String] gridTableRawLine indices = do char '|' line <- many1Till anyChar newline return (gridTableSplitLine indices line) -- | Parse row of grid table. -gridTableRow :: PandocParser Block +gridTableRow :: GenParser Char ParserState Block -> [Int] - -> PandocParser [[Block]] + -> GenParser Char ParserState [[Block]] gridTableRow block indices = do colLines <- many1 (gridTableRawLine indices) let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $ @@ -587,23 +581,23 @@ compactifyCell :: [Block] -> [Block] compactifyCell bs = head $ compactify [bs] -- | Parse footer for a grid table. -gridTableFooter :: PandocParser [Char] +gridTableFooter :: GenParser Char ParserState [Char] gridTableFooter = blanklines --- -- | Parse a string with a given parser and state. -readWith :: PandocParser a -- ^ parser +readWith :: GenParser t ParserState a -- ^ parser -> ParserState -- ^ initial state - -> String -- ^ input + -> [t] -- ^ input -> a -readWith parser state input = +readWith parser state input = case runParser parser state "source" input of Left err -> error $ "\nError:\n" ++ show err Right result -> result -- | Parse a string with @parser@ (for testing). -testStringWith :: (Show a) => PandocParser a +testStringWith :: (Show a) => GenParser Char ParserState a -> String -> IO () testStringWith parser str = UTF8.putStrLn $ show $ @@ -629,7 +623,7 @@ data ParserState = ParserState stateHeaderTable :: [HeaderType], -- ^ Ordered list of header types used stateIndentedCodeClasses :: [String], -- ^ Classes to use for indented code blocks stateNextExample :: Int, -- ^ Number of next example - stateExamples :: M.Map String Int, -- ^ Map from example labels to numbers + stateExamples :: M.Map String Int, -- ^ Map from example labels to numbers stateHasChapters :: Bool, -- ^ True if \chapter encountered stateApplyMacros :: Bool, -- ^ Apply LaTeX macros? stateMacros :: [Macro] -- ^ List of macros defined so far @@ -637,7 +631,7 @@ data ParserState = ParserState deriving Show defaultParserState :: ParserState -defaultParserState = +defaultParserState = ParserState { stateParseRaw = False, stateParserContext = NullState, stateQuoteContext = NoQuote, @@ -661,12 +655,12 @@ defaultParserState = stateApplyMacros = True, stateMacros = []} -data HeaderType +data HeaderType = SingleHeader Char -- ^ Single line of characters underneath | DoubleHeader Char -- ^ Lines of characters above and below deriving (Eq, Show) -data ParserContext +data ParserContext = ListItemState -- ^ Used when running parser on list item contents | NullState -- ^ Default state deriving (Eq, Show) @@ -705,25 +699,25 @@ lookupKeySrc table key = case M.lookup key table of Just src -> Just src -- | Fail unless we're in "smart typography" mode. -failUnlessSmart :: PandocParser () +failUnlessSmart :: GenParser tok ParserState () failUnlessSmart = getState >>= guard . stateSmart -smartPunctuation :: PandocParser Inline - -> PandocParser Inline +smartPunctuation :: GenParser Char ParserState Inline + -> GenParser Char ParserState Inline smartPunctuation inlineParser = do failUnlessSmart choice [ quoted inlineParser, apostrophe, dash, ellipses ] -apostrophe :: PandocParser Inline +apostrophe :: GenParser Char ParserState Inline apostrophe = (char '\'' <|> char '\8217') >> return Apostrophe -quoted :: PandocParser Inline - -> PandocParser Inline +quoted :: GenParser Char ParserState Inline + -> GenParser Char ParserState Inline quoted inlineParser = doubleQuoted inlineParser <|> singleQuoted inlineParser withQuoteContext :: QuoteContext - -> (PandocParser Inline) - -> PandocParser Inline + -> (GenParser Char ParserState Inline) + -> GenParser Char ParserState Inline withQuoteContext context parser = do oldState <- getState let oldQuoteContext = stateQuoteContext oldState @@ -733,75 +727,75 @@ withQuoteContext context parser = do setState newState { stateQuoteContext = oldQuoteContext } return result -singleQuoted :: PandocParser Inline - -> PandocParser Inline +singleQuoted :: GenParser Char ParserState Inline + -> GenParser Char ParserState Inline singleQuoted inlineParser = try $ do singleQuoteStart withQuoteContext InSingleQuote $ many1Till inlineParser singleQuoteEnd >>= return . Quoted SingleQuote . normalizeSpaces -doubleQuoted :: PandocParser Inline - -> PandocParser Inline +doubleQuoted :: GenParser Char ParserState Inline + -> GenParser Char ParserState Inline doubleQuoted inlineParser = try $ do doubleQuoteStart withQuoteContext InDoubleQuote $ do contents <- manyTill inlineParser doubleQuoteEnd return . Quoted DoubleQuote . normalizeSpaces $ contents -failIfInQuoteContext :: QuoteContext -> PandocParser () +failIfInQuoteContext :: QuoteContext -> GenParser tok ParserState () failIfInQuoteContext context = do st <- getState if stateQuoteContext st == context then fail "already inside quotes" else return () -charOrRef :: [Char] -> GeneralParser st Char +charOrRef :: [Char] -> GenParser Char st Char charOrRef cs = oneOf cs <|> try (do c <- characterReference guard (c `elem` cs) return c) -singleQuoteStart :: PandocParser () -singleQuoteStart = do +singleQuoteStart :: GenParser Char ParserState () +singleQuoteStart = do failIfInQuoteContext InSingleQuote try $ do charOrRef "'\8216" notFollowedBy (oneOf ")!],.;:-? \t\n") notFollowedBy (try (oneOfStrings ["s","t","m","ve","ll","re"] >> - satisfy (not . isAlphaNum))) + satisfy (not . isAlphaNum))) -- possess/contraction return () -singleQuoteEnd :: GeneralParser st () +singleQuoteEnd :: GenParser Char st () singleQuoteEnd = try $ do charOrRef "'\8217" notFollowedBy alphaNum -doubleQuoteStart :: PandocParser () +doubleQuoteStart :: GenParser Char ParserState () doubleQuoteStart = do failIfInQuoteContext InDoubleQuote try $ do charOrRef "\"\8220" notFollowedBy (satisfy (\c -> c == ' ' || c == '\t' || c == '\n')) -doubleQuoteEnd :: GeneralParser st () +doubleQuoteEnd :: GenParser Char st () doubleQuoteEnd = do charOrRef "\"\8221" return () -ellipses :: GeneralParser st Inline +ellipses :: GenParser Char st Inline ellipses = do try (charOrRef "…") <|> try (string "..." >> return '…') return Ellipses -dash :: GeneralParser st Inline +dash :: GenParser Char st Inline dash = enDash <|> emDash -enDash :: GeneralParser st Inline +enDash :: GenParser Char st Inline enDash = do try (charOrRef "–") <|> try (char '-' >> lookAhead (satisfy isDigit) >> return '–') return EnDash -emDash :: GeneralParser st Inline +emDash :: GenParser Char st Inline emDash = do try (charOrRef "—") <|> (try $ string "--" >> optional (char '-') >> return '—') return EmDash @@ -811,7 +805,7 @@ emDash = do -- -- | Parse a \newcommand or \renewcommand macro definition. -macro :: PandocParser Block +macro :: GenParser Char ParserState Block macro = do getState >>= guard . stateApplyMacros inp <- getInput @@ -823,10 +817,11 @@ macro = do return Null -- | Apply current macros to string. -applyMacros' :: String -> PandocParser String +applyMacros' :: String -> GenParser Char ParserState String applyMacros' target = do apply <- liftM stateApplyMacros getState if apply then do macros <- liftM stateMacros getState return $ applyMacros macros target else return target + |