ParseLib2.hs revision f89a3a8a5f8f4c39570125a7c5e5da9a1c700d1c
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci{- ---------------------------------------------------------------------------
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci A LIBRARY OF MONADIC PARSER COMBINATORS
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci 29th July 1996
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci Revised, October 1996
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci Graham Hutton Erik Meijer
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci University of Nottingham University of Utrecht
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciThis Haskell 1.4 script defines a library of parser combinators, and is taken
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccifrom sections 1-6 of our article "Monadic Parser Combinators". Some changes
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccito the library have been made in the move from Gofer to Haskell:
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci * Do notation is used in place of monad comprehension notation;
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci * The parser datatype is defined using "newtype", to avoid the overhead
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci of tagging and untagging parsers with the P constructor.
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-----------------------------------------------------------------------------
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciAdded to April 1997, for offside rule, block comments, annotations,
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciextra characters in identifiers .. -
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciextra combinator parsers for skipping over input -}
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccimodule ParseLib2
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci (Parser, item, papply, (+++), sat, many, many1, sepby, sepby1, chainl,
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci chainl1, chainr, chainr1, ops, bracket, char, digit, lower, upper,
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci letter, alphanum, string, ident, nat, int, spaces, comment, junk,
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci parse, token, natural, integer, symbol, identifier,
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci many1_offside, many_offside, off,
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci opt, skipUntil, skipUntilOff, skipUntilParse, skipNest) where
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciimport Data.Char
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciimport Control.Monad
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciinfixr 5 +++
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-- * The parser monad ---------------------------------------------------------
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccinewtype Parser a = P (Pos -> Pstring -> [(a, Pstring)])
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccitype Pstring = (Pos, String)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccitype Pos = (Int, Int)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciinstance Functor Parser where
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci -- fmap :: (a -> b) -> (Parser a -> Parser b)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci fmap f (P p) = P (\ pos inp -> [(f v, out) | (v, out) <- p pos inp])
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciinstance Monad Parser where
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci -- return :: a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return v = P (\ _ inp -> [(v, inp)])
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci -- >>= :: Parser a -> (a -> Parser b) -> Parser b
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci (P p) >>= f = P (\ pos inp -> concat [papply (f v) pos out
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci | (v, out) <- p pos inp])
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci fail _ = P (\ _ _ -> [])
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciinstance MonadPlus Parser where
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci -- mzero :: Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci mzero = P (\ _ _ -> [])
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci -- mplus :: Parser a -> Parser a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci (P p) `mplus` (P q) = P (\ pos inp -> (p pos inp ++ q pos inp))
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-- bits which donn't fit into Haskell's type classes just yet :-(
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccienv :: Parser Pos
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccienv = P (\ pos inp -> [(pos, inp)])
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccisetenv :: Pos -> Parser a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccisetenv s (P m) = P $ \ _ -> m s
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciupdate :: (Pstring -> Pstring) -> Parser Pstring
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciupdate f = P ( \ _ s -> [(s, f s)])
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccifetch :: Parser Pstring
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccifetch = update id
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-- * Other primitive parser combinators ---------------------------------------
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciitem :: Parser Char
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciitem = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci (pos, x : _) <- update newstate
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci defpos <- env
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci if onside pos defpos then return x else mzero
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccifirst :: Parser a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccifirst (P p) = P (\ pos inp -> case p pos inp of
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci [] -> []
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci x : _ -> [x])
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccipapply :: Parser a -> Pos -> Pstring -> [(a, Pstring)]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccipapply (P p) = p
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-- layout handling functions
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccionside :: Pos -> Pos -> Bool
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccionside (l, c) (dl, dc) = (c > dc) || (l == dl)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccinewstate :: Pstring -> Pstring
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccinewstate i@((l, c), xxs) = case xxs of
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci [] -> i
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci x : xs -> ((l', c'), xs)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci where
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci (l', c') = case x of
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci '\n' -> (l + 1, 0)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci '\t' -> (l, ((c `div` 8) + 1) * 8)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci _ -> (l, c + 1)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-- * Derived combinators ------------------------------------------------------
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci(+++) :: Parser a -> Parser a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccip +++ q = first (p `mplus` q)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccisat :: (Char -> Bool) -> Parser Char
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccisat p = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci x <- item
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci if p x then return x else mzero
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccimany :: Parser a -> Parser [a]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccimany p = many1 p +++ return []
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccimany1 :: Parser a -> Parser [a]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccimany1 p = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci x <- p
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci xs <- many p
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return (x : xs)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccisepby :: Parser a -> Parser b -> Parser [a]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccisepby p sep = sepby1 p sep +++ return []
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccisepby1 :: Parser a -> Parser b -> Parser [a]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccisepby1 p sep = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci x <- p
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci xs <- many (sep >> p)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return (x : xs)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccichainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccichainl p op v = chainl1 p op +++ return v
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccichainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccichainl1 p op = p >>= rest
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci where
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci rest x = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci f <- op
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci y <- p
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci rest (f x y)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci +++ return x
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccichainr :: Parser a -> Parser (a -> a -> a) -> a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccichainr p op v = chainr1 p op +++ return v
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccichainr1 :: Parser a -> Parser (a -> a -> a) -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccichainr1 p op = p >>= rest
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci where
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci rest x = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci f <- op
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci y <- p `chainr1` op
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return (f x y)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci +++ return x
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciops :: [(Parser a, b)] -> Parser b
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciops xs = foldr1 (+++) [p >> return op | (p, op) <- xs]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccibracket :: Parser a -> Parser b -> Parser c -> Parser b
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccibracket open p close = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci open
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci x <- p
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci close
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return x
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-- * Useful parsers -----------------------------------------------------------
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccichar :: Char -> Parser Char
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccichar x = sat (x ==)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccidigit :: Parser Char
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccidigit = sat isDigit
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccilower :: Parser Char
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccilower = sat isLower
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciupper :: Parser Char
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciupper = sat isUpper
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciletter :: Parser Char
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciletter = sat isAlpha
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccialphanum :: Parser Char
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccialphanum = sat (\ x -> isAlphaNum x || x `elem` "'_.#")
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccistring :: String -> Parser String
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccistring "" = return ""
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccistring (x : xs) = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci char x
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci string xs
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return (x : xs)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciident :: Parser String
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciident = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci x <- lower
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci xs <- many alphanum
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return (x : xs)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccinat :: Parser Int
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccinat = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci x <- digit
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return (digitToInt x)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci `chainl1` return op
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci where
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci m `op` n = 10 * m + n
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciint :: Parser Int
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciint = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci char '-'
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci n <- nat
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return (-n)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci +++ nat
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-- * Lexical combinators ------------------------------------------------------
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccispaces :: Parser ()
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccispaces = many1 (sat isJunk) >> return ()
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciisJunk :: Char -> Bool
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciisJunk x = isSpace x || (not . isPrint) x || isControl x
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccicomment :: Parser ()
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccicomment = onelinecomment `mplus` bracecomment
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccionelinecomment :: Parser ()
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccionelinecomment = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci string "--"
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci many (sat (/= '\n'))
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return ()
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccibracecomment :: Parser ()
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccibracecomment = skipNest
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci (string "{-" >> sat (`notElem` "!@*"))
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci (sat (`notElem` "!@*") >> string "-}")
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccijunk :: Parser ()
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccijunk = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci _ <- setenv (0, -1) (many (spaces +++ comment))
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return ()
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciparse :: Parser a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciparse = (junk >>)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccitoken :: Parser a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccitoken p = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci v <- p
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci junk
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return v
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-- * Token parsers ------------------------------------------------------------
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccinatural :: Parser Int
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccinatural = token nat
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciinteger :: Parser Int
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciinteger = token int
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccisymbol :: String -> Parser String
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccisymbol xs = token (string xs)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciidentifier :: [String] -> Parser String
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciidentifier ks = token $ do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci x <- ident
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci if notElem x ks then return x else mzero
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-- * Offside Parsers ---------------------------------------------------------
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccimany1_offside :: Parser a -> Parser [a]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccimany1_offside p = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci (pos, _) <- fetch
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci setenv pos (many1 (off p))
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccimany_offside :: Parser a -> Parser [a]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccimany_offside p = many1_offside p +++ mzero
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccioff :: Parser a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccioff p = do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci (_, dc) <- env
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci ((l, c), _) <- fetch
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci if c == dc then setenv (l, dc) p else mzero
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci-- Noel's own favourite parsers
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciskipUntil :: Parser a -> Parser a
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciskipUntil p = p +++ do
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci token (many1 (sat (not . isSpace)))
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci skipUntil p
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciskipNest :: Parser a -> Parser b -> Parser ()
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciskipNest start finish = let
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci x = (finish >> return ())
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci +++ (skipNest start finish >> x) +++ (item >> x)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci in start >> x
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci{- this are messy, but make writing incomplete parsers a whole lot
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccieasier. -}
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciskipUntilOff :: Parser a -> Parser [a]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciskipUntilOff p = fmap (concatMap justs) . many_offside $
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci fmap Just p +++ fmap (const Nothing) (many1 (token (many1 item)))
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciskipUntilParse :: Char -> Parser a -> Parser [a]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciskipUntilParse u p = fmap (concatMap justs) . many $
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci do r <- p
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci token (char u)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return (Just r)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci +++
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci do many . token . many1 . sat $ (/= u)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci token (char u)
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci return Nothing
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccijusts :: Maybe t -> [t]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccijusts (Just a) = [a]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgolluccijusts Nothing = []
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciopt :: Parser [a] -> Parser [a]
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucciopt p = p +++ return []
1e5905d1f04191cad9dae6117e1508c7f7d5587apgollucci