-
-import Control.Monad.State
-import qualified Data.ByteString.Lazy.Char8 as B
-import Data.ByteString.Lazy.Char8 (ByteString)
-
--- |@Parser a@ is obviously a parser which parses and returns @a@.
-newtype Parser a = Parser {
- runParser :: State ParserState (ParserResult a)
- }
-
-type ParserState = (ByteString, IsEOFFatal)
-
-type IsEOFFatal = Bool
-
-data ParserResult a = Success !a
- | IllegalInput -- 受理出來ない入力があった
- | ReachedEOF -- 限界を越えて讀まうとした
- deriving (Eq, Show)
-
-
--- (>>=) :: Parser a -> (a -> Parser b) -> Parser b
-instance Monad Parser where
- p >>= f = Parser $! do saved@(_, isEOFFatal) <- get -- 失敗した時の爲に状態を保存
- result <- runParser p
- case result of
- Success a -> a `seq` runParser (f a)
- IllegalInput -> do put saved -- 状態を復歸
- return IllegalInput
- ReachedEOF -> do unless isEOFFatal
- $ put saved -- 状態を復歸
- return ReachedEOF
- return x = x `seq` Parser $! return $! Success x
- fail _ = Parser $! return $! IllegalInput
-
--- |@'parse' p bstr@ parses @bstr@ with @p@ and returns @(result,
--- remaining)@.
-parse :: Parser a -> ByteString -> (ParserResult a, ByteString)
-parse p input -- input は lazy である必要有り。
- = p `seq`
- let (result, (input', _)) = runState (runParser p) (input, True)
- in
- result `seq` (result, input') -- input' も lazy である必要有り。
-
--- |@'parseStr' p str@ packs @str@ and parses it.
-parseStr :: Parser a -> String -> (ParserResult a, ByteString)
-parseStr p input
- = p `seq` -- input は lazy である必要有り。
- parse p $! B.pack input
-
-
-anyChar :: Parser Char
-anyChar = Parser $!
- do (input, isEOFFatal) <- get
- if B.null input then
- return ReachedEOF
- else
- do let c = B.head input
- put (B.tail input, isEOFFatal)
- return (Success c)
-
-
-eof :: Parser ()
-eof = Parser $!
- do (input, _) <- get
- if B.null input then
- return $ Success ()
- else
- return IllegalInput
-
--- |@'allowEOF' p@ makes @p@ treat reaching EOF a normal failure.
-allowEOF :: Parser a -> Parser a
-allowEOF f = f `seq`
- Parser $! do (input, isEOFFatal) <- get
- put (input, False)
-
- result <- runParser f
-
- (input', _) <- get
- put (input', isEOFFatal)
-
- return result
-
-
-satisfy :: (Char -> Bool) -> Parser Char
-satisfy f = f `seq`
- do c <- anyChar
- unless (f c) (fail "")
- return c
-
-
-char :: Char -> Parser Char
-char c = c `seq` satisfy (== c)
-
-
-string :: String -> Parser String
-string str = str `seq`
- do mapM_ char str
- return str
-
-
-infixr 0 <|>
-
--- |This is the backtracking alternation. There is no non-backtracking
--- equivalent.
-(<|>) :: Parser a -> Parser a -> Parser a
-f <|> g
- = f `seq` g `seq`
- Parser $! do saved@(_, isEOFFatal) <- get -- 状態を保存
- result <- runParser f
- case result of
- Success a -> return $ Success a
- IllegalInput -> do put saved -- 状態を復歸
- runParser g
- ReachedEOF -> if isEOFFatal then
- return ReachedEOF
- else
- do put saved
- runParser g
-
-
-oneOf :: [Char] -> Parser Char
-oneOf = foldl (<|>) (fail "") . map char
-
-
-notFollowedBy :: Parser a -> Parser ()
-notFollowedBy p = p `seq`
- p >>= fail "" <|> return ()
-
-
-digit :: Parser Char
-digit = do c <- anyChar
- if c >= '0' && c <= '9' then
- return c
- else
- fail ""
-
-
-hexDigit :: Parser Char
-hexDigit = do c <- anyChar
- if (c >= '0' && c <= '9') ||
- (c >= 'a' && c <= 'f') ||
- (c >= 'A' && c <= 'F') then
- return c
- else
- fail ""
-
-
-many :: Parser a -> Parser [a]
-many p = p `seq`
- do x <- p
- xs <- many p
- return (x:xs)
- <|>
- return []
-
-
-many1 :: Parser a -> Parser [a]
-many1 p = p `seq`
- do ret <- many p
- case ret of
- [] -> fail ""
- xs -> return xs
-
-
-manyTill :: Parser a -> Parser end -> Parser [a]
-manyTill p end
- = p `seq` end `seq`
- many $! do x <- p
- end
- return x
-
-
-many1Till :: Parser a -> Parser end -> Parser [a]
-many1Till p end
- = p `seq` end `seq`
- many1 $! do x <- p
- end
- return x
-
-
-count :: Int -> Parser a -> Parser [a]
-count 0 _ = return []
-count n p = n `seq` p `seq`
- do x <- p
- xs <- count (n-1) p
- return (x:xs)
-
--- def may be a _|_
-option :: a -> Parser a -> Parser a
-option def p = p `seq`
- p <|> return def
-
-
-sepBy :: Parser a -> Parser sep -> Parser [a]
-sepBy p sep = p `seq` sep `seq`
- sepBy1 p sep <|> return []
-
-
-sepBy1 :: Parser a -> Parser sep -> Parser [a]
-sepBy1 p sep = p `seq` sep `seq`
- do x <- p
- xs <- many $! sep >> p
- return (x:xs)
-
-
-sp :: Parser Char
-sp = char ' '
-
-
-ht :: Parser Char
-ht = char '\t'
-
-
-crlf :: Parser String
-crlf = string "\x0d\x0a"