mirror of
https://github.com/jgm/pandoc.git
synced 2026-09-24 16:35:42 +00:00
Generalised all functions in Parsing.hs
Before it wasn't possible to use these general combinators with the ParsecT transformer but with the more general types this is now possible.
This commit is contained in:
+168
-128
@@ -1,5 +1,8 @@
|
|||||||
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeSynonymInstances,
|
{-# LANGUAGE
|
||||||
FlexibleInstances#-}
|
FlexibleContexts
|
||||||
|
, GeneralizedNewtypeDeriving
|
||||||
|
, TypeSynonymInstances
|
||||||
|
, FlexibleInstances #-}
|
||||||
{-
|
{-
|
||||||
Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
|
Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
|
||||||
|
|
||||||
@@ -177,12 +180,15 @@ import Text.Pandoc.Asciify (toAsciiChar)
|
|||||||
import Data.Default
|
import Data.Default
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Control.Applicative ((*>), (<*), (<$), liftA2, Applicative)
|
import Control.Monad.Identity
|
||||||
|
import Control.Applicative ((<$>), (<*>), (*>), (<*), (<$), Applicative)
|
||||||
import Data.Monoid
|
import Data.Monoid
|
||||||
import Data.Maybe (catMaybes)
|
import Data.Maybe (catMaybes)
|
||||||
|
|
||||||
type Parser t s = Parsec t s
|
type Parser t s = Parsec t s
|
||||||
|
|
||||||
|
type ParserT = ParsecT
|
||||||
|
|
||||||
newtype F a = F { unF :: Reader ParserState a } deriving (Monad, Applicative, Functor)
|
newtype F a = F { unF :: Reader ParserState a } deriving (Monad, Applicative, Functor)
|
||||||
|
|
||||||
runF :: F a -> ParserState -> a
|
runF :: F a -> ParserState -> a
|
||||||
@@ -201,11 +207,11 @@ instance Monoid a => Monoid (F a) where
|
|||||||
|
|
||||||
-- | Like >>, but returns the operation on the left.
|
-- | Like >>, but returns the operation on the left.
|
||||||
-- (Suggested by Tillmann Rendel on Haskell-cafe list.)
|
-- (Suggested by Tillmann Rendel on Haskell-cafe list.)
|
||||||
(>>~) :: (Monad m) => m a -> m b -> m a
|
(>>~) :: (Applicative m) => m a -> m b -> m a
|
||||||
a >>~ b = a >>= \x -> b >> return x
|
a >>~ b = a <* b
|
||||||
|
|
||||||
-- | Parse any line of text
|
-- | Parse any line of text
|
||||||
anyLine :: Parser [Char] st [Char]
|
anyLine :: Stream [Char] m Char => ParserT [Char] st m [Char]
|
||||||
anyLine = do
|
anyLine = do
|
||||||
-- This is much faster than:
|
-- This is much faster than:
|
||||||
-- manyTill anyChar newline
|
-- manyTill anyChar newline
|
||||||
@@ -221,9 +227,10 @@ anyLine = do
|
|||||||
_ -> mzero
|
_ -> mzero
|
||||||
|
|
||||||
-- | Like @manyTill@, but reads at least one item.
|
-- | Like @manyTill@, but reads at least one item.
|
||||||
many1Till :: Parser [tok] st a
|
many1Till :: Stream s m t
|
||||||
-> Parser [tok] st end
|
=> ParserT s st m a
|
||||||
-> Parser [tok] st [a]
|
-> ParserT s st m end
|
||||||
|
-> ParserT s st m [a]
|
||||||
many1Till p end = do
|
many1Till p end = do
|
||||||
first <- p
|
first <- p
|
||||||
rest <- manyTill p end
|
rest <- manyTill p end
|
||||||
@@ -232,14 +239,14 @@ many1Till p end = do
|
|||||||
-- | 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.
|
-- type of parser to be specified, and succeeds only if that parser fails.
|
||||||
-- It does not consume any input.
|
-- It does not consume any input.
|
||||||
notFollowedBy' :: Show b => Parser [a] st b -> Parser [a] st ()
|
notFollowedBy' :: (Show b, Stream s m a) => ParserT s st m b -> ParserT s st m ()
|
||||||
notFollowedBy' p = try $ join $ do a <- try p
|
notFollowedBy' p = try $ join $ do a <- try p
|
||||||
return (unexpected (show a))
|
return (unexpected (show a))
|
||||||
<|>
|
<|>
|
||||||
return (return ())
|
return (return ())
|
||||||
-- (This version due to Andrew Pimlott on the Haskell mailing list.)
|
-- (This version due to Andrew Pimlott on the Haskell mailing list.)
|
||||||
|
|
||||||
oneOfStrings' :: (Char -> Char -> Bool) -> [String] -> Parser [Char] st String
|
oneOfStrings' :: Stream s m Char => (Char -> Char -> Bool) -> [String] -> ParserT s st m String
|
||||||
oneOfStrings' _ [] = fail "no strings"
|
oneOfStrings' _ [] = fail "no strings"
|
||||||
oneOfStrings' matches strs = try $ do
|
oneOfStrings' matches strs = try $ do
|
||||||
c <- anyChar
|
c <- anyChar
|
||||||
@@ -254,11 +261,11 @@ oneOfStrings' matches strs = try $ do
|
|||||||
-- | Parses one of a list of strings. If the list contains
|
-- | Parses one of a list of strings. If the list contains
|
||||||
-- two strings one of which is a prefix of the other, the longer
|
-- two strings one of which is a prefix of the other, the longer
|
||||||
-- string will be matched if possible.
|
-- string will be matched if possible.
|
||||||
oneOfStrings :: [String] -> Parser [Char] st String
|
oneOfStrings :: Stream s m Char => [String] -> ParserT s st m String
|
||||||
oneOfStrings = oneOfStrings' (==)
|
oneOfStrings = oneOfStrings' (==)
|
||||||
|
|
||||||
-- | Parses one of a list of strings (tried in order), case insensitive.
|
-- | Parses one of a list of strings (tried in order), case insensitive.
|
||||||
oneOfStringsCI :: [String] -> Parser [Char] st String
|
oneOfStringsCI :: Stream s m Char => [String] -> ParserT s st m String
|
||||||
oneOfStringsCI = oneOfStrings' ciMatch
|
oneOfStringsCI = oneOfStrings' ciMatch
|
||||||
where ciMatch x y = toLower' x == toLower' y
|
where ciMatch x y = toLower' x == toLower' y
|
||||||
-- this optimizes toLower by checking common ASCII case
|
-- this optimizes toLower by checking common ASCII case
|
||||||
@@ -269,35 +276,35 @@ oneOfStringsCI = oneOfStrings' ciMatch
|
|||||||
| otherwise = toLower c
|
| otherwise = toLower c
|
||||||
|
|
||||||
-- | Parses a space or tab.
|
-- | Parses a space or tab.
|
||||||
spaceChar :: Parser [Char] st Char
|
spaceChar :: Stream s m Char => ParserT s st m Char
|
||||||
spaceChar = satisfy $ \c -> c == ' ' || c == '\t'
|
spaceChar = satisfy $ \c -> c == ' ' || c == '\t'
|
||||||
|
|
||||||
-- | Parses a nonspace, nonnewline character.
|
-- | Parses a nonspace, nonnewline character.
|
||||||
nonspaceChar :: Parser [Char] st Char
|
nonspaceChar :: Stream s m Char => ParserT s st m Char
|
||||||
nonspaceChar = satisfy $ flip notElem ['\t', '\n', ' ', '\r']
|
nonspaceChar = satisfy $ flip notElem ['\t', '\n', ' ', '\r']
|
||||||
|
|
||||||
-- | Skips zero or more spaces or tabs.
|
-- | Skips zero or more spaces or tabs.
|
||||||
skipSpaces :: Parser [Char] st ()
|
skipSpaces :: Stream s m Char => ParserT s st m ()
|
||||||
skipSpaces = skipMany spaceChar
|
skipSpaces = skipMany spaceChar
|
||||||
|
|
||||||
-- | Skips zero or more spaces or tabs, then reads a newline.
|
-- | Skips zero or more spaces or tabs, then reads a newline.
|
||||||
blankline :: Parser [Char] st Char
|
blankline :: Stream s m Char => ParserT s st m Char
|
||||||
blankline = try $ skipSpaces >> newline
|
blankline = try $ skipSpaces >> newline
|
||||||
|
|
||||||
-- | Parses one or more blank lines and returns a string of newlines.
|
-- | Parses one or more blank lines and returns a string of newlines.
|
||||||
blanklines :: Parser [Char] st [Char]
|
blanklines :: Stream s m Char => ParserT s st m [Char]
|
||||||
blanklines = many1 blankline
|
blanklines = many1 blankline
|
||||||
|
|
||||||
-- | Parses material enclosed between start and end parsers.
|
-- | Parses material enclosed between start and end parsers.
|
||||||
enclosed :: Parser [Char] st t -- ^ start parser
|
enclosed :: Stream s m Char => ParserT s st m t -- ^ start parser
|
||||||
-> Parser [Char] st end -- ^ end parser
|
-> ParserT s st m end -- ^ end parser
|
||||||
-> Parser [Char] st a -- ^ content parser (to be used repeatedly)
|
-> ParserT s st m a -- ^ content parser (to be used repeatedly)
|
||||||
-> Parser [Char] st [a]
|
-> ParserT s st m [a]
|
||||||
enclosed start end parser = try $
|
enclosed start end parser = try $
|
||||||
start >> notFollowedBy space >> many1Till parser end
|
start >> notFollowedBy space >> many1Till parser end
|
||||||
|
|
||||||
-- | Parse string, case insensitive.
|
-- | Parse string, case insensitive.
|
||||||
stringAnyCase :: [Char] -> Parser [Char] st String
|
stringAnyCase :: Stream s m Char => [Char] -> ParserT s st m String
|
||||||
stringAnyCase [] = string ""
|
stringAnyCase [] = string ""
|
||||||
stringAnyCase (x:xs) = do
|
stringAnyCase (x:xs) = do
|
||||||
firstChar <- char (toUpper x) <|> char (toLower x)
|
firstChar <- char (toUpper x) <|> char (toLower x)
|
||||||
@@ -305,7 +312,7 @@ stringAnyCase (x:xs) = do
|
|||||||
return (firstChar:rest)
|
return (firstChar:rest)
|
||||||
|
|
||||||
-- | Parse contents of 'str' using 'parser' and return result.
|
-- | Parse contents of 'str' using 'parser' and return result.
|
||||||
parseFromString :: Parser [tok] st a -> [tok] -> Parser [tok] st a
|
parseFromString :: Stream s m t => ParserT s st m a -> s -> ParserT s st m a
|
||||||
parseFromString parser str = do
|
parseFromString parser str = do
|
||||||
oldPos <- getPosition
|
oldPos <- getPosition
|
||||||
oldInput <- getInput
|
oldInput <- getInput
|
||||||
@@ -316,7 +323,7 @@ parseFromString parser str = do
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
-- | Parse raw line block up to and including blank lines.
|
-- | Parse raw line block up to and including blank lines.
|
||||||
lineClump :: Parser [Char] st String
|
lineClump :: Stream [Char] m Char => ParserT [Char] st m String
|
||||||
lineClump = blanklines
|
lineClump = blanklines
|
||||||
<|> (many1 (notFollowedBy blankline >> anyLine) >>= return . unlines)
|
<|> (many1 (notFollowedBy blankline >> anyLine) >>= return . unlines)
|
||||||
|
|
||||||
@@ -325,8 +332,8 @@ lineClump = blanklines
|
|||||||
-- pairs of open and close, which must be different. For example,
|
-- pairs of open and close, which must be different. For example,
|
||||||
-- @charsInBalanced '(' ')' anyChar@ will parse "(hello (there))"
|
-- @charsInBalanced '(' ')' anyChar@ will parse "(hello (there))"
|
||||||
-- and return "hello (there)".
|
-- and return "hello (there)".
|
||||||
charsInBalanced :: Char -> Char -> Parser [Char] st Char
|
charsInBalanced :: Stream s m Char => Char -> Char -> ParserT s st m Char
|
||||||
-> Parser [Char] st String
|
-> ParserT s st m String
|
||||||
charsInBalanced open close parser = try $ do
|
charsInBalanced open close parser = try $ do
|
||||||
char open
|
char open
|
||||||
let isDelim c = c == open || c == close
|
let isDelim c = c == open || c == close
|
||||||
@@ -350,8 +357,8 @@ uppercaseRomanDigits :: [Char]
|
|||||||
uppercaseRomanDigits = map toUpper lowercaseRomanDigits
|
uppercaseRomanDigits = map toUpper lowercaseRomanDigits
|
||||||
|
|
||||||
-- | Parses a roman numeral (uppercase or lowercase), returns number.
|
-- | Parses a roman numeral (uppercase or lowercase), returns number.
|
||||||
romanNumeral :: Bool -- ^ Uppercase if true
|
romanNumeral :: Stream s m Char => Bool -- ^ Uppercase if true
|
||||||
-> Parser [Char] st Int
|
-> ParserT s st m Int
|
||||||
romanNumeral upperCase = do
|
romanNumeral upperCase = do
|
||||||
let romanDigits = if upperCase
|
let romanDigits = if upperCase
|
||||||
then uppercaseRomanDigits
|
then uppercaseRomanDigits
|
||||||
@@ -383,8 +390,8 @@ romanNumeral upperCase = do
|
|||||||
|
|
||||||
-- | Parses an email address; returns original and corresponding
|
-- | Parses an email address; returns original and corresponding
|
||||||
-- escaped mailto: URI.
|
-- escaped mailto: URI.
|
||||||
emailAddress :: Parser [Char] st (String, String)
|
emailAddress :: Stream s m Char => ParserT s st m (String, String)
|
||||||
emailAddress = try $ liftA2 toResult mailbox (char '@' *> domain)
|
emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
|
||||||
where toResult mbox dom = let full = fromEntities $ mbox ++ '@':dom
|
where toResult mbox dom = let full = fromEntities $ mbox ++ '@':dom
|
||||||
in (full, escapeURI $ "mailto:" ++ full)
|
in (full, escapeURI $ "mailto:" ++ full)
|
||||||
mailbox = intercalate "." `fmap` (emailWord `sepby1` dot)
|
mailbox = intercalate "." `fmap` (emailWord `sepby1` dot)
|
||||||
@@ -398,7 +405,7 @@ emailAddress = try $ liftA2 toResult mailbox (char '@' *> domain)
|
|||||||
isEmailPunct c = c `elem` "!\"#$%&'*+-/=?^_{|}~;"
|
isEmailPunct c = c `elem` "!\"#$%&'*+-/=?^_{|}~;"
|
||||||
-- note: sepBy1 from parsec consumes input when sep
|
-- note: sepBy1 from parsec consumes input when sep
|
||||||
-- succeeds and p fails, so we use this variant here.
|
-- succeeds and p fails, so we use this variant here.
|
||||||
sepby1 p sep = liftA2 (:) p (many (try $ sep >> p))
|
sepby1 p sep = (:) <$> p <*> (many (try $ sep >> p))
|
||||||
|
|
||||||
|
|
||||||
-- Schemes from http://www.iana.org/assignments/uri-schemes.html plus
|
-- Schemes from http://www.iana.org/assignments/uri-schemes.html plus
|
||||||
@@ -426,11 +433,11 @@ schemes = ["coap","doi","javascript","aaa","aaas","about","acap","cap","cid",
|
|||||||
"ventrilo","view-source","webcal","wtai","wyciwyg","xfire","xri",
|
"ventrilo","view-source","webcal","wtai","wyciwyg","xfire","xri",
|
||||||
"ymsgr"]
|
"ymsgr"]
|
||||||
|
|
||||||
uriScheme :: Parser [Char] st String
|
uriScheme :: Stream s m Char => ParserT s st m String
|
||||||
uriScheme = oneOfStringsCI schemes
|
uriScheme = oneOfStringsCI schemes
|
||||||
|
|
||||||
-- | Parses a URI. Returns pair of original and URI-escaped version.
|
-- | Parses a URI. Returns pair of original and URI-escaped version.
|
||||||
uri :: Parser [Char] st (String, String)
|
uri :: Stream [Char] m Char => ParserT [Char] st m (String, String)
|
||||||
uri = try $ do
|
uri = try $ do
|
||||||
scheme <- uriScheme
|
scheme <- uriScheme
|
||||||
char ':'
|
char ':'
|
||||||
@@ -460,7 +467,7 @@ uri = try $ do
|
|||||||
let uri' = scheme ++ ":" ++ fromEntities str'
|
let uri' = scheme ++ ":" ++ fromEntities str'
|
||||||
return (uri', escapeURI uri')
|
return (uri', escapeURI uri')
|
||||||
|
|
||||||
mathInlineWith :: String -> String -> Parser [Char] st String
|
mathInlineWith :: Stream s m Char => String -> String -> ParserT s st m String
|
||||||
mathInlineWith op cl = try $ do
|
mathInlineWith op cl = try $ do
|
||||||
string op
|
string op
|
||||||
notFollowedBy space
|
notFollowedBy space
|
||||||
@@ -474,12 +481,12 @@ mathInlineWith op cl = try $ do
|
|||||||
notFollowedBy digit -- to prevent capture of $5
|
notFollowedBy digit -- to prevent capture of $5
|
||||||
return $ concat words'
|
return $ concat words'
|
||||||
|
|
||||||
mathDisplayWith :: String -> String -> Parser [Char] st String
|
mathDisplayWith :: Stream s m Char => String -> String -> ParserT s st m String
|
||||||
mathDisplayWith op cl = try $ do
|
mathDisplayWith op cl = try $ do
|
||||||
string op
|
string op
|
||||||
many1Till (noneOf "\n" <|> (newline >>~ notFollowedBy' blankline)) (try $ string cl)
|
many1Till (noneOf "\n" <|> (newline >>~ notFollowedBy' blankline)) (try $ string cl)
|
||||||
|
|
||||||
mathDisplay :: Parser [Char] ParserState String
|
mathDisplay :: Stream s m Char => ParserT s ParserState m String
|
||||||
mathDisplay =
|
mathDisplay =
|
||||||
(guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
|
(guardEnabled Ext_tex_math_dollars >> mathDisplayWith "$$" "$$")
|
||||||
<|> (guardEnabled Ext_tex_math_single_backslash >>
|
<|> (guardEnabled Ext_tex_math_single_backslash >>
|
||||||
@@ -487,7 +494,7 @@ mathDisplay =
|
|||||||
<|> (guardEnabled Ext_tex_math_double_backslash >>
|
<|> (guardEnabled Ext_tex_math_double_backslash >>
|
||||||
mathDisplayWith "\\\\[" "\\\\]")
|
mathDisplayWith "\\\\[" "\\\\]")
|
||||||
|
|
||||||
mathInline :: Parser [Char] ParserState String
|
mathInline :: Stream s m Char => ParserT s ParserState m String
|
||||||
mathInline =
|
mathInline =
|
||||||
(guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
|
(guardEnabled Ext_tex_math_dollars >> mathInlineWith "$" "$")
|
||||||
<|> (guardEnabled Ext_tex_math_single_backslash >>
|
<|> (guardEnabled Ext_tex_math_single_backslash >>
|
||||||
@@ -499,8 +506,9 @@ mathInline =
|
|||||||
-- displacement (the difference between the source column at the end
|
-- displacement (the difference between the source column at the end
|
||||||
-- and the source column at the beginning). Vertical displacement
|
-- and the source column at the beginning). Vertical displacement
|
||||||
-- (source row) is ignored.
|
-- (source row) is ignored.
|
||||||
withHorizDisplacement :: Parser [Char] st a -- ^ Parser to apply
|
withHorizDisplacement :: Stream s m Char
|
||||||
-> Parser [Char] st (a, Int) -- ^ (result, displacement)
|
=> ParserT s st m a -- ^ Parser to apply
|
||||||
|
-> ParserT s st m (a, Int) -- ^ (result, displacement)
|
||||||
withHorizDisplacement parser = do
|
withHorizDisplacement parser = do
|
||||||
pos1 <- getPosition
|
pos1 <- getPosition
|
||||||
result <- parser
|
result <- parser
|
||||||
@@ -509,7 +517,7 @@ withHorizDisplacement parser = do
|
|||||||
|
|
||||||
-- | Applies a parser and returns the raw string that was parsed,
|
-- | Applies a parser and returns the raw string that was parsed,
|
||||||
-- along with the value produced by the parser.
|
-- along with the value produced by the parser.
|
||||||
withRaw :: Monad m => ParsecT [Char] st m a -> ParsecT [Char] st m (a, [Char])
|
withRaw :: Stream [Char] m Char => ParsecT [Char] st m a -> ParsecT [Char] st m (a, [Char])
|
||||||
withRaw parser = do
|
withRaw parser = do
|
||||||
pos1 <- getPosition
|
pos1 <- getPosition
|
||||||
inp <- getInput
|
inp <- getInput
|
||||||
@@ -525,12 +533,13 @@ withRaw parser = do
|
|||||||
return (result, raw)
|
return (result, raw)
|
||||||
|
|
||||||
-- | Parses backslash, then applies character parser.
|
-- | Parses backslash, then applies character parser.
|
||||||
escaped :: Parser [Char] st Char -- ^ Parser for character to escape
|
escaped :: Stream s m Char
|
||||||
-> Parser [Char] st Char
|
=> ParserT s st m Char -- ^ Parser for character to escape
|
||||||
|
-> ParserT s st m Char
|
||||||
escaped parser = try $ char '\\' >> parser
|
escaped parser = try $ char '\\' >> parser
|
||||||
|
|
||||||
-- | Parse character entity.
|
-- | Parse character entity.
|
||||||
characterReference :: Parser [Char] st Char
|
characterReference :: Stream s m Char => ParserT s st m Char
|
||||||
characterReference = try $ do
|
characterReference = try $ do
|
||||||
char '&'
|
char '&'
|
||||||
ent <- many1Till nonspaceChar (char ';')
|
ent <- many1Till nonspaceChar (char ';')
|
||||||
@@ -539,19 +548,19 @@ characterReference = try $ do
|
|||||||
Nothing -> fail "entity not found"
|
Nothing -> fail "entity not found"
|
||||||
|
|
||||||
-- | Parses an uppercase roman numeral and returns (UpperRoman, number).
|
-- | Parses an uppercase roman numeral and returns (UpperRoman, number).
|
||||||
upperRoman :: Parser [Char] st (ListNumberStyle, Int)
|
upperRoman :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
|
||||||
upperRoman = do
|
upperRoman = do
|
||||||
num <- romanNumeral True
|
num <- romanNumeral True
|
||||||
return (UpperRoman, num)
|
return (UpperRoman, num)
|
||||||
|
|
||||||
-- | Parses a lowercase roman numeral and returns (LowerRoman, number).
|
-- | Parses a lowercase roman numeral and returns (LowerRoman, number).
|
||||||
lowerRoman :: Parser [Char] st (ListNumberStyle, Int)
|
lowerRoman :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
|
||||||
lowerRoman = do
|
lowerRoman = do
|
||||||
num <- romanNumeral False
|
num <- romanNumeral False
|
||||||
return (LowerRoman, num)
|
return (LowerRoman, num)
|
||||||
|
|
||||||
-- | Parses a decimal numeral and returns (Decimal, number).
|
-- | Parses a decimal numeral and returns (Decimal, number).
|
||||||
decimal :: Parser [Char] st (ListNumberStyle, Int)
|
decimal :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
|
||||||
decimal = do
|
decimal = do
|
||||||
num <- many1 digit
|
num <- many1 digit
|
||||||
return (Decimal, read num)
|
return (Decimal, read num)
|
||||||
@@ -560,7 +569,8 @@ decimal = do
|
|||||||
-- returns (DefaultStyle, [next example number]). The next
|
-- returns (DefaultStyle, [next example number]). The next
|
||||||
-- example number is incremented in parser state, and the label
|
-- example number is incremented in parser state, and the label
|
||||||
-- (if present) is added to the label table.
|
-- (if present) is added to the label table.
|
||||||
exampleNum :: Parser [Char] ParserState (ListNumberStyle, Int)
|
exampleNum :: Stream s m Char
|
||||||
|
=> ParserT s ParserState m (ListNumberStyle, Int)
|
||||||
exampleNum = do
|
exampleNum = do
|
||||||
char '@'
|
char '@'
|
||||||
lab <- many (alphaNum <|> satisfy (\c -> c == '_' || c == '-'))
|
lab <- many (alphaNum <|> satisfy (\c -> c == '_' || c == '-'))
|
||||||
@@ -574,38 +584,39 @@ exampleNum = do
|
|||||||
return (Example, num)
|
return (Example, num)
|
||||||
|
|
||||||
-- | Parses a '#' returns (DefaultStyle, 1).
|
-- | Parses a '#' returns (DefaultStyle, 1).
|
||||||
defaultNum :: Parser [Char] st (ListNumberStyle, Int)
|
defaultNum :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
|
||||||
defaultNum = do
|
defaultNum = do
|
||||||
char '#'
|
char '#'
|
||||||
return (DefaultStyle, 1)
|
return (DefaultStyle, 1)
|
||||||
|
|
||||||
-- | Parses a lowercase letter and returns (LowerAlpha, number).
|
-- | Parses a lowercase letter and returns (LowerAlpha, number).
|
||||||
lowerAlpha :: Parser [Char] st (ListNumberStyle, Int)
|
lowerAlpha :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
|
||||||
lowerAlpha = do
|
lowerAlpha = do
|
||||||
ch <- oneOf ['a'..'z']
|
ch <- oneOf ['a'..'z']
|
||||||
return (LowerAlpha, ord ch - ord 'a' + 1)
|
return (LowerAlpha, ord ch - ord 'a' + 1)
|
||||||
|
|
||||||
-- | Parses an uppercase letter and returns (UpperAlpha, number).
|
-- | Parses an uppercase letter and returns (UpperAlpha, number).
|
||||||
upperAlpha :: Parser [Char] st (ListNumberStyle, Int)
|
upperAlpha :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
|
||||||
upperAlpha = do
|
upperAlpha = do
|
||||||
ch <- oneOf ['A'..'Z']
|
ch <- oneOf ['A'..'Z']
|
||||||
return (UpperAlpha, ord ch - ord 'A' + 1)
|
return (UpperAlpha, ord ch - ord 'A' + 1)
|
||||||
|
|
||||||
-- | Parses a roman numeral i or I
|
-- | Parses a roman numeral i or I
|
||||||
romanOne :: Parser [Char] st (ListNumberStyle, Int)
|
romanOne :: Stream s m Char => ParserT s st m (ListNumberStyle, Int)
|
||||||
romanOne = (char 'i' >> return (LowerRoman, 1)) <|>
|
romanOne = (char 'i' >> return (LowerRoman, 1)) <|>
|
||||||
(char 'I' >> return (UpperRoman, 1))
|
(char 'I' >> return (UpperRoman, 1))
|
||||||
|
|
||||||
-- | Parses an ordered list marker and returns list attributes.
|
-- | Parses an ordered list marker and returns list attributes.
|
||||||
anyOrderedListMarker :: Parser [Char] ParserState ListAttributes
|
anyOrderedListMarker :: Stream s m Char => ParserT s ParserState m ListAttributes
|
||||||
anyOrderedListMarker = choice $
|
anyOrderedListMarker = choice $
|
||||||
[delimParser numParser | delimParser <- [inPeriod, inOneParen, inTwoParens],
|
[delimParser numParser | delimParser <- [inPeriod, inOneParen, inTwoParens],
|
||||||
numParser <- [decimal, exampleNum, defaultNum, romanOne,
|
numParser <- [decimal, exampleNum, defaultNum, romanOne,
|
||||||
lowerAlpha, lowerRoman, upperAlpha, upperRoman]]
|
lowerAlpha, lowerRoman, upperAlpha, upperRoman]]
|
||||||
|
|
||||||
-- | Parses a list number (num) followed by a period, returns list attributes.
|
-- | Parses a list number (num) followed by a period, returns list attributes.
|
||||||
inPeriod :: Parser [Char] st (ListNumberStyle, Int)
|
inPeriod :: Stream s m Char
|
||||||
-> Parser [Char] st ListAttributes
|
=> ParserT s st m (ListNumberStyle, Int)
|
||||||
|
-> ParserT s st m ListAttributes
|
||||||
inPeriod num = try $ do
|
inPeriod num = try $ do
|
||||||
(style, start) <- num
|
(style, start) <- num
|
||||||
char '.'
|
char '.'
|
||||||
@@ -615,16 +626,18 @@ inPeriod num = try $ do
|
|||||||
return (start, style, delim)
|
return (start, style, delim)
|
||||||
|
|
||||||
-- | Parses a list number (num) followed by a paren, returns list attributes.
|
-- | Parses a list number (num) followed by a paren, returns list attributes.
|
||||||
inOneParen :: Parser [Char] st (ListNumberStyle, Int)
|
inOneParen :: Stream s m Char
|
||||||
-> Parser [Char] st ListAttributes
|
=> ParserT s st m (ListNumberStyle, Int)
|
||||||
|
-> ParserT s st m ListAttributes
|
||||||
inOneParen num = try $ do
|
inOneParen num = try $ do
|
||||||
(style, start) <- num
|
(style, start) <- num
|
||||||
char ')'
|
char ')'
|
||||||
return (start, style, OneParen)
|
return (start, style, OneParen)
|
||||||
|
|
||||||
-- | Parses a list number (num) enclosed in parens, returns list attributes.
|
-- | Parses a list number (num) enclosed in parens, returns list attributes.
|
||||||
inTwoParens :: Parser [Char] st (ListNumberStyle, Int)
|
inTwoParens :: Stream s m Char
|
||||||
-> Parser [Char] st ListAttributes
|
=> ParserT s st m (ListNumberStyle, Int)
|
||||||
|
-> ParserT s st m ListAttributes
|
||||||
inTwoParens num = try $ do
|
inTwoParens num = try $ do
|
||||||
char '('
|
char '('
|
||||||
(style, start) <- num
|
(style, start) <- num
|
||||||
@@ -633,9 +646,10 @@ inTwoParens num = try $ do
|
|||||||
|
|
||||||
-- | Parses an ordered list marker with a given style and delimiter,
|
-- | Parses an ordered list marker with a given style and delimiter,
|
||||||
-- returns number.
|
-- returns number.
|
||||||
orderedListMarker :: ListNumberStyle
|
orderedListMarker :: Stream s m Char
|
||||||
|
=> ListNumberStyle
|
||||||
-> ListNumberDelim
|
-> ListNumberDelim
|
||||||
-> Parser [Char] ParserState Int
|
-> ParserT s ParserState m Int
|
||||||
orderedListMarker style delim = do
|
orderedListMarker style delim = do
|
||||||
let num = defaultNum <|> -- # can continue any kind of list
|
let num = defaultNum <|> -- # can continue any kind of list
|
||||||
case style of
|
case style of
|
||||||
@@ -655,12 +669,12 @@ orderedListMarker style delim = do
|
|||||||
return start
|
return start
|
||||||
|
|
||||||
-- | Parses a character reference and returns a Str element.
|
-- | Parses a character reference and returns a Str element.
|
||||||
charRef :: Parser [Char] st Inline
|
charRef :: Stream s m Char => ParserT s st m Inline
|
||||||
charRef = do
|
charRef = do
|
||||||
c <- characterReference
|
c <- characterReference
|
||||||
return $ Str [c]
|
return $ Str [c]
|
||||||
|
|
||||||
lineBlockLine :: Parser [Char] st String
|
lineBlockLine :: Stream [Char] m Char => ParserT [Char] st m String
|
||||||
lineBlockLine = try $ do
|
lineBlockLine = try $ do
|
||||||
char '|'
|
char '|'
|
||||||
char ' '
|
char ' '
|
||||||
@@ -671,7 +685,7 @@ lineBlockLine = try $ do
|
|||||||
return $ white ++ unwords (line : continuations)
|
return $ white ++ unwords (line : continuations)
|
||||||
|
|
||||||
-- | Parses an RST-style line block and returns a list of strings.
|
-- | Parses an RST-style line block and returns a list of strings.
|
||||||
lineBlockLines :: Parser [Char] st [String]
|
lineBlockLines :: Stream [Char] m Char => ParserT [Char] st m [String]
|
||||||
lineBlockLines = try $ do
|
lineBlockLines = try $ do
|
||||||
lines' <- many1 lineBlockLine
|
lines' <- many1 lineBlockLine
|
||||||
skipMany1 $ blankline <|> try (char '|' >> blankline)
|
skipMany1 $ blankline <|> try (char '|' >> blankline)
|
||||||
@@ -679,11 +693,12 @@ lineBlockLines = try $ do
|
|||||||
|
|
||||||
-- | Parse a table using 'headerParser', 'rowParser',
|
-- | Parse a table using 'headerParser', 'rowParser',
|
||||||
-- 'lineParser', and 'footerParser'.
|
-- 'lineParser', and 'footerParser'.
|
||||||
tableWith :: Parser [Char] ParserState ([[Block]], [Alignment], [Int])
|
tableWith :: Stream s m Char
|
||||||
-> ([Int] -> Parser [Char] ParserState [[Block]])
|
=> ParserT s ParserState m ([[Block]], [Alignment], [Int])
|
||||||
-> Parser [Char] ParserState sep
|
-> ([Int] -> ParserT s ParserState m [[Block]])
|
||||||
-> Parser [Char] ParserState end
|
-> ParserT s ParserState m sep
|
||||||
-> Parser [Char] ParserState Block
|
-> ParserT s ParserState m end
|
||||||
|
-> ParserT s ParserState m Block
|
||||||
tableWith headerParser rowParser lineParser footerParser = try $ do
|
tableWith headerParser rowParser lineParser footerParser = try $ do
|
||||||
(heads, aligns, indices) <- headerParser
|
(heads, aligns, indices) <- headerParser
|
||||||
lines' <- rowParser indices `sepEndBy1` lineParser
|
lines' <- rowParser indices `sepEndBy1` lineParser
|
||||||
@@ -725,9 +740,10 @@ widthsFromIndices numColumns' indices =
|
|||||||
-- (which may be grid), then the rows,
|
-- (which may be grid), then the rows,
|
||||||
-- which may be grid, separated by blank lines, and
|
-- which may be grid, separated by blank lines, and
|
||||||
-- ending with a footer (dashed line followed by blank line).
|
-- ending with a footer (dashed line followed by blank line).
|
||||||
gridTableWith :: Parser [Char] ParserState [Block] -- ^ Block list parser
|
gridTableWith :: Stream [Char] m Char
|
||||||
|
=> ParserT [Char] ParserState m [Block] -- ^ Block list parser
|
||||||
-> Bool -- ^ Headerless table
|
-> Bool -- ^ Headerless table
|
||||||
-> Parser [Char] ParserState Block
|
-> ParserT [Char] ParserState m Block
|
||||||
gridTableWith blocks headless =
|
gridTableWith blocks headless =
|
||||||
tableWith (gridTableHeader headless blocks) (gridTableRow blocks)
|
tableWith (gridTableHeader headless blocks) (gridTableRow blocks)
|
||||||
(gridTableSep '-') gridTableFooter
|
(gridTableSep '-') gridTableFooter
|
||||||
@@ -736,13 +752,13 @@ gridTableSplitLine :: [Int] -> String -> [String]
|
|||||||
gridTableSplitLine indices line = map removeFinalBar $ tail $
|
gridTableSplitLine indices line = map removeFinalBar $ tail $
|
||||||
splitStringByIndices (init indices) $ trimr line
|
splitStringByIndices (init indices) $ trimr line
|
||||||
|
|
||||||
gridPart :: Char -> Parser [Char] st (Int, Int)
|
gridPart :: Stream s m Char => Char -> ParserT s st m (Int, Int)
|
||||||
gridPart ch = do
|
gridPart ch = do
|
||||||
dashes <- many1 (char ch)
|
dashes <- many1 (char ch)
|
||||||
char '+'
|
char '+'
|
||||||
return (length dashes, length dashes + 1)
|
return (length dashes, length dashes + 1)
|
||||||
|
|
||||||
gridDashedLines :: Char -> Parser [Char] st [(Int,Int)]
|
gridDashedLines :: Stream s m Char => Char -> ParserT s st m [(Int,Int)]
|
||||||
gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) >>~ blankline
|
gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) >>~ blankline
|
||||||
|
|
||||||
removeFinalBar :: String -> String
|
removeFinalBar :: String -> String
|
||||||
@@ -750,13 +766,14 @@ removeFinalBar =
|
|||||||
reverse . dropWhile (`elem` " \t") . dropWhile (=='|') . reverse
|
reverse . dropWhile (`elem` " \t") . dropWhile (=='|') . reverse
|
||||||
|
|
||||||
-- | Separator between rows of grid table.
|
-- | Separator between rows of grid table.
|
||||||
gridTableSep :: Char -> Parser [Char] ParserState Char
|
gridTableSep :: Stream s m Char => Char -> ParserT s ParserState m Char
|
||||||
gridTableSep ch = try $ gridDashedLines ch >> return '\n'
|
gridTableSep ch = try $ gridDashedLines ch >> return '\n'
|
||||||
|
|
||||||
-- | Parse header for a grid table.
|
-- | Parse header for a grid table.
|
||||||
gridTableHeader :: Bool -- ^ Headerless table
|
gridTableHeader :: Stream [Char] m Char
|
||||||
-> Parser [Char] ParserState [Block]
|
=> Bool -- ^ Headerless table
|
||||||
-> Parser [Char] ParserState ([[Block]], [Alignment], [Int])
|
-> ParserT [Char] ParserState m [Block]
|
||||||
|
-> ParserT [Char] ParserState m ([[Block]], [Alignment], [Int])
|
||||||
gridTableHeader headless blocks = try $ do
|
gridTableHeader headless blocks = try $ do
|
||||||
optional blanklines
|
optional blanklines
|
||||||
dashes <- gridDashedLines '-'
|
dashes <- gridDashedLines '-'
|
||||||
@@ -779,16 +796,17 @@ gridTableHeader headless blocks = try $ do
|
|||||||
heads <- mapM (parseFromString blocks) $ map trim rawHeads
|
heads <- mapM (parseFromString blocks) $ map trim rawHeads
|
||||||
return (heads, aligns, indices)
|
return (heads, aligns, indices)
|
||||||
|
|
||||||
gridTableRawLine :: [Int] -> Parser [Char] ParserState [String]
|
gridTableRawLine :: Stream s m Char => [Int] -> ParserT s ParserState m [String]
|
||||||
gridTableRawLine indices = do
|
gridTableRawLine indices = do
|
||||||
char '|'
|
char '|'
|
||||||
line <- many1Till anyChar newline
|
line <- many1Till anyChar newline
|
||||||
return (gridTableSplitLine indices line)
|
return (gridTableSplitLine indices line)
|
||||||
|
|
||||||
-- | Parse row of grid table.
|
-- | Parse row of grid table.
|
||||||
gridTableRow :: Parser [Char] ParserState [Block]
|
gridTableRow :: Stream [Char] m Char
|
||||||
|
=> ParserT [Char] ParserState m [Block]
|
||||||
-> [Int]
|
-> [Int]
|
||||||
-> Parser [Char] ParserState [[Block]]
|
-> ParserT [Char] ParserState m [[Block]]
|
||||||
gridTableRow blocks indices = do
|
gridTableRow blocks indices = do
|
||||||
colLines <- many1 (gridTableRawLine indices)
|
colLines <- many1 (gridTableRawLine indices)
|
||||||
let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $
|
let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $
|
||||||
@@ -807,15 +825,16 @@ compactifyCell :: [Block] -> [Block]
|
|||||||
compactifyCell bs = head $ compactify [bs]
|
compactifyCell bs = head $ compactify [bs]
|
||||||
|
|
||||||
-- | Parse footer for a grid table.
|
-- | Parse footer for a grid table.
|
||||||
gridTableFooter :: Parser [Char] ParserState [Char]
|
gridTableFooter :: Stream s m Char => ParserT s ParserState m [Char]
|
||||||
gridTableFooter = blanklines
|
gridTableFooter = blanklines
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
-- | Parse a string with a given parser and state.
|
-- | Parse a string with a given parser and state.
|
||||||
readWith :: Parser [Char] st a -- ^ parser
|
readWith :: (Show s, Stream s Identity Char)
|
||||||
|
=> ParserT s st Identity a -- ^ parser
|
||||||
-> st -- ^ initial state
|
-> st -- ^ initial state
|
||||||
-> [Char] -- ^ input
|
-> s -- ^ input
|
||||||
-> a
|
-> a
|
||||||
readWith parser state input =
|
readWith parser state input =
|
||||||
case runParser parser state "source" input of
|
case runParser parser state "source" input of
|
||||||
@@ -823,15 +842,16 @@ readWith parser state input =
|
|||||||
let errPos = errorPos err'
|
let errPos = errorPos err'
|
||||||
errLine = sourceLine errPos
|
errLine = sourceLine errPos
|
||||||
errColumn = sourceColumn errPos
|
errColumn = sourceColumn errPos
|
||||||
theline = (lines input ++ [""]) !! (errLine - 1)
|
theline = (lines (show input) ++ [""]) !! (errLine - 1)
|
||||||
in error $ "\nError at " ++ show err' ++ "\n" ++
|
in error $ "\nError at " ++ show err' ++ "\n" ++
|
||||||
theline ++ "\n" ++ replicate (errColumn - 1) ' ' ++
|
theline ++ "\n" ++ replicate (errColumn - 1) ' ' ++
|
||||||
"^"
|
"^"
|
||||||
Right result -> result
|
Right result -> result
|
||||||
|
|
||||||
-- | Parse a string with @parser@ (for testing).
|
-- | Parse a string with @parser@ (for testing).
|
||||||
testStringWith :: (Show a) => Parser [Char] ParserState a
|
testStringWith :: (Show s, Show a, Stream s Identity Char)
|
||||||
-> String
|
=> ParserT s ParserState Identity a
|
||||||
|
-> s
|
||||||
-> IO ()
|
-> IO ()
|
||||||
testStringWith parser str = UTF8.putStrLn $ show $
|
testStringWith parser str = UTF8.putStrLn $ show $
|
||||||
readWith parser defaultParserState str
|
readWith parser defaultParserState str
|
||||||
@@ -878,7 +898,7 @@ instance HasMeta ParserState where
|
|||||||
|
|
||||||
class HasReaderOptions st where
|
class HasReaderOptions st where
|
||||||
extractReaderOptions :: st -> ReaderOptions
|
extractReaderOptions :: st -> ReaderOptions
|
||||||
getOption :: (ReaderOptions -> b) -> Parser s st b
|
getOption :: (Stream s m t) => (ReaderOptions -> b) -> ParserT s st m b
|
||||||
-- default
|
-- default
|
||||||
getOption f = (f . extractReaderOptions) `fmap` getState
|
getOption f = (f . extractReaderOptions) `fmap` getState
|
||||||
|
|
||||||
@@ -946,19 +966,19 @@ defaultParserState =
|
|||||||
stateWarnings = []}
|
stateWarnings = []}
|
||||||
|
|
||||||
-- | Succeed only if the extension is enabled.
|
-- | Succeed only if the extension is enabled.
|
||||||
guardEnabled :: HasReaderOptions st => Extension -> Parser s st ()
|
guardEnabled :: (Stream s m a, HasReaderOptions st) => Extension -> ParserT s st m ()
|
||||||
guardEnabled ext = getOption readerExtensions >>= guard . Set.member ext
|
guardEnabled ext = getOption readerExtensions >>= guard . Set.member ext
|
||||||
|
|
||||||
-- | Succeed only if the extension is disabled.
|
-- | Succeed only if the extension is disabled.
|
||||||
guardDisabled :: HasReaderOptions st => Extension -> Parser s st ()
|
guardDisabled :: (Stream s m a, HasReaderOptions st) => Extension -> ParserT s st m ()
|
||||||
guardDisabled ext = getOption readerExtensions >>= guard . not . Set.member ext
|
guardDisabled ext = getOption readerExtensions >>= guard . not . Set.member ext
|
||||||
|
|
||||||
-- | Update the position on which the last string ended.
|
-- | Update the position on which the last string ended.
|
||||||
updateLastStrPos :: HasLastStrPosition st => Parser s st ()
|
updateLastStrPos :: (Stream s m a, HasLastStrPosition st) => ParserT s st m ()
|
||||||
updateLastStrPos = getPosition >>= updateState . setLastStrPos
|
updateLastStrPos = getPosition >>= updateState . setLastStrPos
|
||||||
|
|
||||||
-- | Whether we are right after the end of a string.
|
-- | Whether we are right after the end of a string.
|
||||||
notAfterString :: HasLastStrPosition st => Parser s st Bool
|
notAfterString :: (Stream s m a, HasLastStrPosition st) => ParserT s st m Bool
|
||||||
notAfterString = do
|
notAfterString = do
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
st <- getState
|
st <- getState
|
||||||
@@ -998,8 +1018,8 @@ type SubstTable = M.Map Key Inlines
|
|||||||
-- and the auto_identifers extension is set, generate a new
|
-- and the auto_identifers extension is set, generate a new
|
||||||
-- unique identifier, and update the list of identifiers
|
-- unique identifier, and update the list of identifiers
|
||||||
-- in state.
|
-- in state.
|
||||||
registerHeader :: (HasReaderOptions st, HasHeaderMap st, HasIdentifierList st)
|
registerHeader :: (Stream s m a, HasReaderOptions st, HasHeaderMap st, HasIdentifierList st)
|
||||||
=> Attr -> Inlines -> Parser s st Attr
|
=> Attr -> Inlines -> ParserT s st m Attr
|
||||||
registerHeader (ident,classes,kvs) header' = do
|
registerHeader (ident,classes,kvs) header' = do
|
||||||
ids <- extractIdentifierList `fmap` getState
|
ids <- extractIdentifierList `fmap` getState
|
||||||
exts <- getOption readerExtensions
|
exts <- getOption readerExtensions
|
||||||
@@ -1020,25 +1040,28 @@ registerHeader (ident,classes,kvs) header' = do
|
|||||||
return (ident,classes,kvs)
|
return (ident,classes,kvs)
|
||||||
|
|
||||||
-- | Fail unless we're in "smart typography" mode.
|
-- | Fail unless we're in "smart typography" mode.
|
||||||
failUnlessSmart :: HasReaderOptions st => Parser s st ()
|
failUnlessSmart :: (Stream s m a, HasReaderOptions st) => ParserT s st m ()
|
||||||
failUnlessSmart = getOption readerSmart >>= guard
|
failUnlessSmart = getOption readerSmart >>= guard
|
||||||
|
|
||||||
smartPunctuation :: Parser [Char] ParserState Inlines
|
smartPunctuation :: Stream s m Char
|
||||||
-> Parser [Char] ParserState Inlines
|
=> ParserT s ParserState m Inlines
|
||||||
|
-> ParserT s ParserState m Inlines
|
||||||
smartPunctuation inlineParser = do
|
smartPunctuation inlineParser = do
|
||||||
failUnlessSmart
|
failUnlessSmart
|
||||||
choice [ quoted inlineParser, apostrophe, dash, ellipses ]
|
choice [ quoted inlineParser, apostrophe, dash, ellipses ]
|
||||||
|
|
||||||
apostrophe :: Parser [Char] ParserState Inlines
|
apostrophe :: Stream s m Char => ParserT s st m Inlines
|
||||||
apostrophe = (char '\'' <|> char '\8217') >> return (B.str "\x2019")
|
apostrophe = (char '\'' <|> char '\8217') >> return (B.str "\x2019")
|
||||||
|
|
||||||
quoted :: Parser [Char] ParserState Inlines
|
quoted :: Stream s m Char
|
||||||
-> Parser [Char] ParserState Inlines
|
=> ParserT s ParserState m Inlines
|
||||||
|
-> ParserT s ParserState m Inlines
|
||||||
quoted inlineParser = doubleQuoted inlineParser <|> singleQuoted inlineParser
|
quoted inlineParser = doubleQuoted inlineParser <|> singleQuoted inlineParser
|
||||||
|
|
||||||
withQuoteContext :: QuoteContext
|
withQuoteContext :: Stream s m t
|
||||||
-> Parser [tok] ParserState a
|
=> QuoteContext
|
||||||
-> Parser [tok] ParserState a
|
-> ParserT s ParserState m a
|
||||||
|
-> ParserT s ParserState m a
|
||||||
withQuoteContext context parser = do
|
withQuoteContext context parser = do
|
||||||
oldState <- getState
|
oldState <- getState
|
||||||
let oldQuoteContext = stateQuoteContext oldState
|
let oldQuoteContext = stateQuoteContext oldState
|
||||||
@@ -1048,99 +1071,112 @@ withQuoteContext context parser = do
|
|||||||
setState newState { stateQuoteContext = oldQuoteContext }
|
setState newState { stateQuoteContext = oldQuoteContext }
|
||||||
return result
|
return result
|
||||||
|
|
||||||
singleQuoted :: Parser [Char] ParserState Inlines
|
singleQuoted :: Stream s m Char
|
||||||
-> Parser [Char] ParserState Inlines
|
=> ParserT s ParserState m Inlines
|
||||||
|
-> ParserT s ParserState m Inlines
|
||||||
singleQuoted inlineParser = try $ do
|
singleQuoted inlineParser = try $ do
|
||||||
singleQuoteStart
|
singleQuoteStart
|
||||||
withQuoteContext InSingleQuote $ many1Till inlineParser singleQuoteEnd >>=
|
withQuoteContext InSingleQuote $ many1Till inlineParser singleQuoteEnd >>=
|
||||||
return . B.singleQuoted . mconcat
|
return . B.singleQuoted . mconcat
|
||||||
|
|
||||||
doubleQuoted :: Parser [Char] ParserState Inlines
|
doubleQuoted :: Stream s m Char
|
||||||
-> Parser [Char] ParserState Inlines
|
=> ParserT s ParserState m Inlines
|
||||||
|
-> ParserT s ParserState m Inlines
|
||||||
doubleQuoted inlineParser = try $ do
|
doubleQuoted inlineParser = try $ do
|
||||||
doubleQuoteStart
|
doubleQuoteStart
|
||||||
withQuoteContext InDoubleQuote $ manyTill inlineParser doubleQuoteEnd >>=
|
withQuoteContext InDoubleQuote $ manyTill inlineParser doubleQuoteEnd >>=
|
||||||
return . B.doubleQuoted . mconcat
|
return . B.doubleQuoted . mconcat
|
||||||
|
|
||||||
failIfInQuoteContext :: QuoteContext -> Parser [tok] ParserState ()
|
failIfInQuoteContext :: Stream s m t
|
||||||
|
=> QuoteContext
|
||||||
|
-> ParserT s ParserState m ()
|
||||||
failIfInQuoteContext context = do
|
failIfInQuoteContext context = do
|
||||||
st <- getState
|
st <- getState
|
||||||
if stateQuoteContext st == context
|
if stateQuoteContext st == context
|
||||||
then fail "already inside quotes"
|
then fail "already inside quotes"
|
||||||
else return ()
|
else return ()
|
||||||
|
|
||||||
charOrRef :: [Char] -> Parser [Char] st Char
|
charOrRef :: Stream s m Char => String -> ParserT s st m Char
|
||||||
charOrRef cs =
|
charOrRef cs =
|
||||||
oneOf cs <|> try (do c <- characterReference
|
oneOf cs <|> try (do c <- characterReference
|
||||||
guard (c `elem` cs)
|
guard (c `elem` cs)
|
||||||
return c)
|
return c)
|
||||||
|
|
||||||
singleQuoteStart :: Parser [Char] ParserState ()
|
singleQuoteStart :: Stream s m Char
|
||||||
|
=> ParserT s ParserState m ()
|
||||||
singleQuoteStart = do
|
singleQuoteStart = do
|
||||||
failIfInQuoteContext InSingleQuote
|
failIfInQuoteContext InSingleQuote
|
||||||
-- single quote start can't be right after str
|
-- single quote start can't be right after str
|
||||||
guard =<< notAfterString
|
guard =<< notAfterString
|
||||||
() <$ charOrRef "'\8216\145"
|
() <$ charOrRef "'\8216\145"
|
||||||
|
|
||||||
singleQuoteEnd :: Parser [Char] st ()
|
singleQuoteEnd :: Stream s m Char
|
||||||
|
=> ParserT s st m ()
|
||||||
singleQuoteEnd = try $ do
|
singleQuoteEnd = try $ do
|
||||||
charOrRef "'\8217\146"
|
charOrRef "'\8217\146"
|
||||||
notFollowedBy alphaNum
|
notFollowedBy alphaNum
|
||||||
|
|
||||||
doubleQuoteStart :: Parser [Char] ParserState ()
|
doubleQuoteStart :: Stream s m Char
|
||||||
|
=> ParserT s ParserState m ()
|
||||||
doubleQuoteStart = do
|
doubleQuoteStart = do
|
||||||
failIfInQuoteContext InDoubleQuote
|
failIfInQuoteContext InDoubleQuote
|
||||||
try $ do charOrRef "\"\8220\147"
|
try $ do charOrRef "\"\8220\147"
|
||||||
notFollowedBy . satisfy $ flip elem [' ', '\t', '\n']
|
notFollowedBy . satisfy $ flip elem [' ', '\t', '\n']
|
||||||
|
|
||||||
doubleQuoteEnd :: Parser [Char] st ()
|
doubleQuoteEnd :: Stream s m Char
|
||||||
doubleQuoteEnd = do
|
=> ParserT s st m ()
|
||||||
charOrRef "\"\8221\148"
|
doubleQuoteEnd = void (charOrRef "\"\8221\148")
|
||||||
return ()
|
|
||||||
|
|
||||||
ellipses :: Parser [Char] st Inlines
|
ellipses :: Stream s m Char
|
||||||
|
=> ParserT s st m Inlines
|
||||||
ellipses = do
|
ellipses = do
|
||||||
try (charOrRef "\8230\133") <|> try (string "..." >> return '…')
|
try (charOrRef "\8230\133") <|> try (string "..." >> return '…')
|
||||||
return (B.str "\8230")
|
return (B.str "\8230")
|
||||||
|
|
||||||
dash :: Parser [Char] ParserState Inlines
|
dash :: Stream s m Char => ParserT s ParserState m Inlines
|
||||||
dash = do
|
dash = do
|
||||||
oldDashes <- getOption readerOldDashes
|
oldDashes <- getOption readerOldDashes
|
||||||
if oldDashes
|
if oldDashes
|
||||||
then emDashOld <|> enDashOld
|
then emDashOld <|> enDashOld
|
||||||
else B.str `fmap` (hyphenDash <|> emDash <|> enDash)
|
else B.str <$> (hyphenDash <|> emDash <|> enDash)
|
||||||
|
|
||||||
-- Two hyphens = en-dash, three = em-dash
|
-- Two hyphens = en-dash, three = em-dash
|
||||||
hyphenDash :: Parser [Char] st String
|
hyphenDash :: Stream s m Char
|
||||||
|
=> ParserT s st m String
|
||||||
hyphenDash = do
|
hyphenDash = do
|
||||||
try $ string "--"
|
try $ string "--"
|
||||||
option "\8211" (char '-' >> return "\8212")
|
option "\8211" (char '-' >> return "\8212")
|
||||||
|
|
||||||
emDash :: Parser [Char] st String
|
emDash :: Stream s m Char
|
||||||
|
=> ParserT s st m String
|
||||||
emDash = do
|
emDash = do
|
||||||
try (charOrRef "\8212\151")
|
try (charOrRef "\8212\151")
|
||||||
return "\8212"
|
return "\8212"
|
||||||
|
|
||||||
enDash :: Parser [Char] st String
|
enDash :: Stream s m Char
|
||||||
|
=> ParserT s st m String
|
||||||
enDash = do
|
enDash = do
|
||||||
try (charOrRef "\8212\151")
|
try (charOrRef "\8212\151")
|
||||||
return "\8211"
|
return "\8211"
|
||||||
|
|
||||||
enDashOld :: Parser [Char] st Inlines
|
enDashOld :: Stream s m Char
|
||||||
|
=> ParserT s st m Inlines
|
||||||
enDashOld = do
|
enDashOld = do
|
||||||
try (charOrRef "\8211\150") <|>
|
try (charOrRef "\8211\150") <|>
|
||||||
try (char '-' >> lookAhead (satisfy isDigit) >> return '–')
|
try (char '-' >> lookAhead (satisfy isDigit) >> return '–')
|
||||||
return (B.str "\8211")
|
return (B.str "\8211")
|
||||||
|
|
||||||
emDashOld :: Parser [Char] st Inlines
|
emDashOld :: Stream s m Char
|
||||||
|
=> ParserT s st m Inlines
|
||||||
emDashOld = do
|
emDashOld = do
|
||||||
try (charOrRef "\8212\151") <|> (try $ string "--" >> optional (char '-') >> return '-')
|
try (charOrRef "\8212\151") <|> (try $ string "--" >> optional (char '-') >> return '-')
|
||||||
return (B.str "\8212")
|
return (B.str "\8212")
|
||||||
|
|
||||||
-- This is used to prevent exponential blowups for things like:
|
-- This is used to prevent exponential blowups for things like:
|
||||||
-- a**a*a**a*a**a*a**a*a**a*a**a*a**
|
-- a**a*a**a*a**a*a**a*a**a*a**a*a**
|
||||||
nested :: Parser s ParserState a
|
nested :: Stream s m a
|
||||||
-> Parser s ParserState a
|
=> ParserT s ParserState m a
|
||||||
|
-> ParserT s ParserState m a
|
||||||
nested p = do
|
nested p = do
|
||||||
nestlevel <- stateMaxNestingLevel `fmap` getState
|
nestlevel <- stateMaxNestingLevel `fmap` getState
|
||||||
guard $ nestlevel > 0
|
guard $ nestlevel > 0
|
||||||
@@ -1149,7 +1185,8 @@ nested p = do
|
|||||||
updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
|
updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
|
||||||
return res
|
return res
|
||||||
|
|
||||||
citeKey :: HasLastStrPosition st => Parser [Char] st (Bool, String)
|
citeKey :: (Stream s m Char, HasLastStrPosition st)
|
||||||
|
=> ParserT s st m (Bool, String)
|
||||||
citeKey = try $ do
|
citeKey = try $ do
|
||||||
guard =<< notAfterString
|
guard =<< notAfterString
|
||||||
suppress_author <- option False (char '-' *> return True)
|
suppress_author <- option False (char '-' *> return True)
|
||||||
@@ -1166,7 +1203,8 @@ citeKey = try $ do
|
|||||||
--
|
--
|
||||||
|
|
||||||
-- | Parse a \newcommand or \renewcommand macro definition.
|
-- | Parse a \newcommand or \renewcommand macro definition.
|
||||||
macro :: (HasMacros st, HasReaderOptions st) => Parser [Char] st Blocks
|
macro :: (Stream [Char] m Char, HasMacros st, HasReaderOptions st)
|
||||||
|
=> ParserT [Char] st m Blocks
|
||||||
macro = do
|
macro = do
|
||||||
apply <- getOption readerApplyMacros
|
apply <- getOption readerApplyMacros
|
||||||
inp <- getInput
|
inp <- getInput
|
||||||
@@ -1181,7 +1219,9 @@ macro = do
|
|||||||
else return $ rawBlock "latex" def'
|
else return $ rawBlock "latex" def'
|
||||||
|
|
||||||
-- | Apply current macros to string.
|
-- | Apply current macros to string.
|
||||||
applyMacros' :: String -> Parser [Char] ParserState String
|
applyMacros' :: Stream [Char] m Char
|
||||||
|
=> String
|
||||||
|
-> ParserT [Char] ParserState m String
|
||||||
applyMacros' target = do
|
applyMacros' target = do
|
||||||
apply <- getOption readerApplyMacros
|
apply <- getOption readerApplyMacros
|
||||||
if apply
|
if apply
|
||||||
|
|||||||
Reference in New Issue
Block a user