module Text.ParserCombinators.Poly.Base
(
Commitment(..)
, PolyParse
, apply
, discard
, failBad
, adjustErrBad
, indent
, oneOf
, exactly
, upto
, many1
, sepBy
, sepBy1
, bracketSep
, bracket
, manyFinally
, manyFinally'
) where
import Control.Applicative
#ifdef __NHC__
default (Integer,Double,[])
instance Commitment []
instance PolyParse []
#endif
class Commitment p where
commit :: p a -> p a
adjustErr :: p a -> (String -> String) -> p a
oneOf' :: [(String, p a)] -> p a
class (Functor p, Monad p, Applicative p, Alternative p, Commitment p) =>
PolyParse p
infixl 3 `apply`
infixl 3 `discard`
apply :: PolyParse p => p (a->b) -> p a -> p b
apply = (<*>)
discard :: PolyParse p => p a -> p b -> p a
px `discard` py = do { x <- px; y <- py; y `seq` return x; }
failBad :: PolyParse p => String -> p a
failBad e = commit (fail e)
adjustErrBad :: PolyParse p => p a -> (String->String) -> p a
p `adjustErrBad` f = commit (p `adjustErr` f)
oneOf :: PolyParse p => [p a] -> p a
oneOf [] = fail ("failed to parse any of the possible choices")
oneOf (p:ps) = p <|> oneOf ps
indent :: Int -> String -> String
indent n = unlines . map (replicate n ' ' ++) . lines
exactly :: PolyParse p => Int -> p a -> p [a]
exactly 0 p = return []
exactly n p = return (:) `apply` (p `adjustErr` (("When expecting exactly "
++show n++" more items")++))
`apply` exactly (n-1) p
upto :: PolyParse p => Int -> p a -> p [a]
upto 0 p = return []
upto n p = do x <- p; return (x:) `apply` upto (n-1) p
<|> return []
many1 :: PolyParse p => p a -> p [a]
many1 p = do { x <- p `adjustErr` (("In a sequence:\n"++). indent 2)
; return (x:) `apply` many p
}
sepBy :: PolyParse p => p a -> p sep -> p [a]
sepBy p sep = do sepBy1 p sep <|> return []
sepBy1 :: PolyParse p => p a -> p sep -> p [a]
sepBy1 p sep = do { x <- p
; return (x:) `apply` many (do {sep; p})
}
`adjustErr` ("When looking for a non-empty sequence with separators:\n\t"++)
bracketSep :: PolyParse p => p bra -> p sep -> p ket -> p a -> p [a]
bracketSep open sep close p =
do { open; close; return [] }
<|>
do { open `adjustErr` ("Missing opening bracket:\n\t"++)
; x <- p `adjustErr` ("After first bracket in a group:\n\t"++)
; return (x:)
`apply` manyFinally (do {sep; p})
(close `adjustErrBad` ("When looking for closing bracket:\n\t"++))
}
bracket :: PolyParse p => p bra -> p ket -> p a -> p a
bracket open close p = do
do { open `adjustErr` ("Missing opening bracket:\n\t"++)
; p `discard` (close `adjustErr` ("Missing closing bracket:\n\t"++))
}
manyFinally :: PolyParse p => p a -> p z -> p [a]
manyFinally p t =
(many p `discard` t)
<|>
oneOf' [ ("sequence terminator", do { t; return [] } )
, ("item in a sequence", do { p; return [] } )
]
manyFinally' :: PolyParse p => p a -> p z -> p [a]
manyFinally' p t =
(do t; return [])
<|>
(do x <- p; return (x:) `apply` manyFinally' p t)
<|>
oneOf' [ ("sequence terminator", do { t; return [] } )
, ("item in a sequence", do { p; return [] } )
]