module Data.Picoparsec.Monoid.Internal
(
Parser
, Result
, parse
, parseOnly
, module Data.Picoparsec.Combinator
, satisfy
, satisfyWith
, anyToken
, skip
, peekToken
, anyChar
, char
, satisfyChar
, peekChar
, peekChar'
, scan
, skipWhile
, string
, stringTransform
, take
, takeWhile
, takeWhile1
, takeWith
, takeTill
, scanChars
, skipCharsWhile
, takeCharsWhile
, takeCharsWhile1
, takeCharsTill
, takeTillChar
, takeTillChar1
, takeRest
, endOfLine
, ensureOne
) where
import Control.Applicative ((<|>), (<$>))
import Control.Monad (when)
import Data.Picoparsec.Combinator
import Data.Picoparsec.Internal.Types
import Data.Monoid (Monoid(..), (<>))
import Data.Monoid.Cancellative (LeftGCDMonoid(..))
import Data.Monoid.Null (MonoidNull(null))
import qualified Data.Monoid.Factorial as Factorial
import Data.Monoid.Factorial (FactorialMonoid)
import Data.Monoid.Textual (TextualMonoid)
import qualified Data.Monoid.Textual as Textual
import Prelude hiding (getChar, null, span, take, takeWhile)
import qualified Data.Picoparsec.Internal.Types as T
type Result = IResult
ensure' :: FactorialMonoid t => Int -> T.Input t -> T.Added t -> More -> T.Failure t r -> T.Success t t r
-> IResult t r
ensure' !n0 i0 a0 m0 kf0 ks0 =
T.runParser (demandInput >> go n0) i0 a0 m0 kf0 ks0
where
go !n = T.Parser $ \i a m kf ks ->
if Factorial.length (unI i) >= n
then ks i a m (unI i)
else T.runParser (demandInput >> go n) i a m kf ks
ensureOne :: FactorialMonoid t => Parser t t
ensureOne = T.Parser $ \i0 a0 m0 kf ks ->
if null (unI i0)
then ensure' 1 i0 a0 m0 kf ks
else ks i0 a0 m0 (unI i0)
prompt :: MonoidNull t => Input t -> Added t -> More
-> (Input t -> Added t -> More -> IResult t r)
-> (Input t -> Added t -> More -> IResult t r)
-> IResult t r
prompt i0 a0 _m0 kf ks = Partial $ \s ->
if null s
then kf i0 a0 Complete
else ks (i0 <> I s) (a0 <> A s) Incomplete
demandInput :: MonoidNull t => Parser t ()
demandInput = T.Parser $ \i0 a0 m0 kf ks ->
if m0 == Complete
then kf i0 a0 m0 ["demandInput"] "not enough input"
else let kf' i a m = kf i a m ["demandInput"] "not enough input"
ks' i a m = ks i a m ()
in prompt i0 a0 m0 kf' ks'
wantInput :: MonoidNull t => Parser t Bool
wantInput = T.Parser $ \i0 a0 m0 _kf ks ->
case () of
_ | not (null (unI i0)) -> ks i0 a0 m0 True
| m0 == Complete -> ks i0 a0 m0 False
| otherwise -> let kf' i a m = ks i a m False
ks' i a m = ks i a m True
in prompt i0 a0 m0 kf' ks'
wantMoreInput :: MonoidNull t => Parser t Bool
wantMoreInput = T.Parser $ \i0 a0 m0 _kf ks ->
if m0 == Complete
then ks i0 a0 m0 False
else let kf' i a m = ks i a m False
ks' i a m = ks i a m True
in prompt i0 a0 m0 kf' ks'
get :: Parser t t
get = T.Parser $ \i0 a0 m0 _kf ks -> ks i0 a0 m0 (unI i0)
put :: t -> Parser t ()
put s = T.Parser $ \_i0 a0 m0 _kf ks -> ks (I s) a0 m0 ()
satisfy :: FactorialMonoid t => (t -> Bool) -> Parser t t
satisfy p = do
s <- ensureOne
let Just (first, rest) = Factorial.splitPrimePrefix s
if p first then put rest >> return first else fail "satisfy"
satisfyChar :: TextualMonoid t => (Char -> Bool) -> Parser t Char
satisfyChar p = do
s <- ensureOne
case Textual.splitCharacterPrefix s
of Just (first, rest) | p first -> put rest >> return first
_ -> fail "satisfy"
skip :: FactorialMonoid t => (t -> Bool) -> Parser t ()
skip p = do
s <- ensureOne
let Just (first, rest) = Factorial.splitPrimePrefix s
if p first then put rest else fail "skip"
satisfyWith :: FactorialMonoid t => (t -> a) -> (a -> Bool) -> Parser t a
satisfyWith f p = do
s <- ensureOne
let Just (first, rest) = Factorial.splitPrimePrefix s
c = f $! first
if p c then put rest >> return c else fail "satisfyWith"
takeWith :: FactorialMonoid t => Int -> (t -> Bool) -> Parser t t
takeWith n0 p =
get >>= \i->
let !(h, t) = Factorial.splitAt n0 i
n1 = Factorial.length h
in if null t && n1 < n0
then put mempty
>> demandInput
>> takeWith' h n1 p
else if p h
then put t
>> return h
else fail "takeWith"
takeWith' :: FactorialMonoid t => t -> Int -> (t -> Bool) -> Parser t t
takeWith' h0 n0 p =
get >>= \i->
let !(h, t) = Factorial.splitAt n0 i
n1 = Factorial.length h
h1 = h0 <> h
in if null t && n1 < n0
then put mempty
>> demandInput
>> takeWith' h1 n1 p
else if p h1
then put t
>> return h1
else fail "takeWith"
take :: FactorialMonoid t => Int -> Parser t t
take n = takeWith n (const True)
string :: (LeftGCDMonoid t, MonoidNull t) => t -> Parser t t
string s =
get >>= \i->
let !(p, s', i') = stripCommonPrefix s i
in if null s'
then put i' >> return s
else if null i'
then put mempty
>> demandInput
>> string' p s'
else fail "string"
string' :: (LeftGCDMonoid t, MonoidNull t) => t -> t -> Parser t t
string' consumed rest =
get >>= \i->
let !(p, s', i') = stripCommonPrefix rest i
in if null s'
then put i' >> return (consumed <> rest)
else if null i'
then put mempty
>> demandInput
>> string' (consumed <> p) s'
else put (consumed <> i)
>> fail "string"
stringTransform :: (FactorialMonoid t, Eq t) => (t -> t) -> t
-> Parser t t
stringTransform f s = takeWith (Factorial.length s) ((==f s) . f)
skipWhile :: FactorialMonoid t => (t -> Bool) -> Parser t ()
skipWhile p = go
where
go = do
t <- Factorial.dropWhile p <$> get
put t
when (null t) $ do
input <- wantMoreInput
when input go
skipCharsWhile :: TextualMonoid t => (Char -> Bool) -> Parser t ()
skipCharsWhile p = go
where
go = do
t <- Textual.dropWhile_ False p <$> get
put t
when (null t) $ do
input <- wantMoreInput
when input go
takeTill :: FactorialMonoid t => (t -> Bool) -> Parser t t
takeTill p = takeWhile (not . p)
takeCharsTill :: TextualMonoid t => (Char -> Bool) -> Parser t t
takeCharsTill p = takeCharsWhile (not . p)
takeTillChar :: TextualMonoid t => (Char -> Bool) -> Parser t t
takeTillChar p = go id
where
go acc = do
(h,t) <- Textual.break_ False p <$> get
put t
if null t
then do
input <- wantInput
if input
then go (acc . mappend h)
else return (acc h)
else return (acc h)
takeTillChar1 :: TextualMonoid t => (Char -> Bool) -> Parser t t
takeTillChar1 p = do
(`when` demandInput) =<< null <$> get
(h,t) <- Textual.break_ False p <$> get
when (null h && maybe True p (Textual.characterPrefix t)) $ fail "takeTillChar1"
put t
if null t
then (h<>) <$> takeTillChar p
else return h
takeWhile :: FactorialMonoid t => (t -> Bool) -> Parser t t
takeWhile p = go id
where
go acc = do
(h,t) <- Factorial.span p <$> get
put t
if null t
then do
input <- wantMoreInput
if input
then go (acc . mappend h)
else return (acc h)
else return (acc h)
takeCharsWhile :: TextualMonoid t => (Char -> Bool) -> Parser t t
takeCharsWhile p = go id
where
go acc = do
(h,t) <- Textual.span_ False p <$> get
put t
if null t
then do
input <- wantMoreInput
if input
then go (acc . mappend h)
else return (acc h)
else return (acc h)
takeRest :: MonoidNull t => Parser t t
takeRest = go []
where
go acc = do
input <- wantInput
if input
then do
s <- get
put mempty
go (s:acc)
else return (mconcat $ reverse acc)
takeWhile1 :: FactorialMonoid t => (t -> Bool) -> Parser t t
takeWhile1 p = do
(`when` demandInput) =<< null <$> get
(h,t) <- Factorial.span p <$> get
when (null h) $ fail "takeWhile1"
put t
if null t
then (h<>) `fmap` takeWhile p
else return h
takeCharsWhile1 :: TextualMonoid t => (Char -> Bool) -> Parser t t
takeCharsWhile1 p = do
(`when` demandInput) =<< null <$> get
(h,t) <- Textual.span_ False p <$> get
when (null h) $ fail "takeCharsWhile1"
put t
if null t
then (h<>) `fmap` takeCharsWhile p
else return h
scan :: FactorialMonoid t => s -> (s -> t -> Maybe s) -> Parser t t
scan s0 f = go s0 id
where
go s acc = do
(h,t,s') <- Factorial.spanMaybe' s f <$> get
put t
if null t
then do
input <- wantMoreInput
if input
then go s' (acc . mappend h)
else return (acc h)
else return (acc h)
scanChars :: TextualMonoid t => s -> (s -> Char -> Maybe s) -> Parser t t
scanChars s0 fc = go s0 id
where
go s acc = do
(h,t,s') <- Textual.spanMaybe_' s fc <$> get
put t
if null t
then do
input <- wantMoreInput
if input
then go s' (acc . mappend h)
else return (acc h)
else return (acc h)
anyToken :: FactorialMonoid t => Parser t t
anyToken = satisfy $ const True
peekToken :: FactorialMonoid t => Parser t t
peekToken = T.Parser $ \i0 a0 m0 _kf ks ->
if null (unI i0)
then if m0 == Complete
then ks i0 a0 m0 mempty
else let k' i a m = ks i a m $! Factorial.primePrefix (unI i)
in prompt i0 a0 m0 k' k'
else ks i0 a0 m0 $! Factorial.primePrefix (unI i0)
anyChar :: TextualMonoid t => Parser t Char
anyChar = satisfyChar $ const True
char :: TextualMonoid t => Char -> Parser t Char
char c = satisfyChar (== c) <?> show c
peekChar :: TextualMonoid t => Parser t (Maybe Char)
peekChar = T.Parser $ \i0 a0 m0 _kf ks ->
if null (unI i0)
then if m0 == Complete
then ks i0 a0 m0 Nothing
else let k' i a m = ks i a m $! Textual.characterPrefix (unI i)
in prompt i0 a0 m0 k' k'
else ks i0 a0 m0 $! Textual.characterPrefix (unI i0)
peekChar' :: TextualMonoid t => Parser t Char
peekChar' = do
s <- ensureOne
case Textual.characterPrefix s
of Just c -> return c
_ -> fail "peekChar'"
endOfLine :: (Eq t, TextualMonoid t) => Parser t ()
endOfLine = (char '\n' >> return ()) <|> (string "\r\n" >> return ())
failK :: Failure t a
failK i0 _a0 _m0 stack msg = Fail (unI i0) stack msg
successK :: Success t a a
successK i0 _a0 _m0 a = Done (unI i0) a
parse :: Monoid t => Parser t a -> t -> IResult t a
parse m s = T.runParser m (I s) mempty Incomplete failK successK
parseOnly :: Monoid t => Parser t a -> t -> Either String a
parseOnly m s = case T.runParser m (I s) mempty Complete failK successK of
Fail _ _ err -> Left err
Done _ a -> Right a
_ -> error "parseOnly: impossible error!"