1+ {-# LANGUAGE CPP #-}
12-- |
23-- Module : Streamly.Internal.Data.Parser.ParserK.Type
34-- Copyright : (c) 2020 Composewell Technologies
1819--
1920module Streamly.Internal.Data.ParserK.Type
2021 (
22+ -- * Setup
23+ -- | To execute the code examples provided in this module in ghci, please
24+ -- run the following commands first.
25+ --
26+ -- $setup
27+
28+ -- * Types
2129 Step (.. )
2230 , Input (.. )
2331 , ParseResult (.. )
2432 , ParserK (.. )
33+
34+ -- * Adapting from Parser
35+ , parserDone
2536 , parserK -- XXX move to StreamK module
2637 , toParser -- XXX unParserK, unK, unPK
38+
39+ -- * Basic Parsers
2740 , fromPure
2841 , fromEffect
2942 , die
3043
31- , parserDone
44+ -- * Expression Parsers
45+ , chainl
46+ , chainl1
47+ , chainr
48+ , chainr1
3249
3350 -- * Deprecated
3451 , adapt
@@ -52,6 +69,8 @@ import GHC.Types (SPEC(..))
5269import qualified Control.Monad.Fail as Fail
5370import qualified Streamly.Internal.Data.Parser.Type as ParserD
5471
72+ #include "DocTestDataParserK.hs"
73+
5574-------------------------------------------------------------------------------
5675-- Developer Notes
5776-------------------------------------------------------------------------------
@@ -534,3 +553,68 @@ toParser parser = ParserD.Parser step initial extract
534553 forall s. toParser (parserK s) = s #-}
535554{-# RULES "toParser/parserK fusion" [2]
536555 forall s. parserK (toParser s) = s #-}
556+
557+ -- | @chainl1 p op x@ parses /one/ or more occurrences of @p@, separated by
558+ -- @op@. Returns a value obtained by a /left/ associative application of all
559+ -- functions returned by @op@ to the values returned by @p@.
560+ --
561+ -- >>> num = Parser.decimal
562+ -- >>> plus = Parser.char '+' *> pure (+)
563+ -- >>> expr = ParserK.chainl1 (StreamK.parserK num) (StreamK.parserK plus)
564+ -- >>> StreamK.parse expr $ StreamK.fromStream $ Stream.fromList "1+2+3"
565+ -- Right 6
566+ --
567+ -- If you're building full expression parsers with operator precedence and
568+ -- associativity, consider using @makeExprParser@ from the @parser-combinators@
569+ -- package.
570+ --
571+ -- See also 'Streamly.Internal.Data.Parser.deintercalate'.
572+ --
573+ {-# INLINE chainl1 #-}
574+ chainl1 :: ParserK b IO a -> ParserK b IO (a -> a -> a ) -> ParserK b IO a
575+ chainl1 p op = p >>= go
576+
577+ where
578+
579+ go l = step l <|> pure l
580+
581+ step l = do
582+ f <- op
583+ r <- p
584+ go (f l r)
585+
586+ -- | @chainl p op x@ is like 'chainl1' but allows /zero/ or more occurrences of
587+ -- @p@, separated by @op@. If there are zero occurrences of @p@, the value @x@
588+ -- is returned.
589+ {-# INLINE chainl #-}
590+ chainl :: ParserK b IO a -> ParserK b IO (a -> a -> a ) -> a -> ParserK b IO a
591+ chainl p op x = chainl1 p op <|> pure x
592+
593+ -- | Like chainl1 but parses right associative application of the operator
594+ -- instead of left associative.
595+ --
596+ -- >>> num = Parser.decimal
597+ -- >>> pow = Parser.char '^' *> pure (^)
598+ -- >>> expr = ParserK.chainr1 (StreamK.parserK num) (StreamK.parserK pow)
599+ -- >>> StreamK.parse expr $ StreamK.fromStream $ Stream.fromList "2^3^2"
600+ -- Right 512
601+ --
602+ {-# INLINE chainr1 #-}
603+ chainr1 :: ParserK b IO a -> ParserK b IO (a -> a -> a ) -> ParserK b IO a
604+ chainr1 p op = p >>= go
605+
606+ where
607+
608+ go l = step l <|> pure l
609+
610+ step l = do
611+ f <- op
612+ r <- chainr1 p op
613+ return (f l r)
614+
615+ -- | @chainr p op x@ is like 'chainr1' but allows /zero/ or more occurrences of
616+ -- @p@, separated by @op@. If there are zero occurrences of @p@, the value @x@
617+ -- is returned.
618+ {-# INLINE chainr #-}
619+ chainr :: ParserK b IO a -> ParserK b IO (a -> a -> a ) -> a -> ParserK b IO a
620+ chainr p op x = chainr1 p op <|> pure x
0 commit comments