packages feed

simple-parser 0.2.1 → 0.2.2

raw patch · 6 files changed

+104/−14 lines, 6 filesdep +mmorphPVP ok

version bump matches the API change (PVP)

Dependencies added: mmorph

API changes (from Hackage documentation)

+ SimpleParser.Parser: instance Control.Monad.Morph.MFunctor (SimpleParser.Parser.ParserT e s)
+ SimpleParser.Parser: isolateParser :: Monad m => ParserT e s m a -> ParserT e s m a
+ SimpleParser.Parser: lookAheadParser :: Monad m => ParserT e s m a -> ParserT e s m a

Files

simple-parser.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: cae86899037beab7723314f49d8129dda7254a4261348de1d4b2e5ed8ebde7bf+-- hash: 05dbeeb0f7613ae6d38c54b0654472b0b1d48dc401b57a41cae0dc16554fb065  name:           simple-parser-version:        0.2.1+version:        0.2.2 synopsis:       Simple parser combinators description:    Please see the README on GitHub at <https://github.com/ejconlon/simple-parser#readme> category:       Parsing@@ -44,6 +44,7 @@       base >=4.12 && <5     , containers >=0.6 && <0.7     , list-t >=1.0 && <1.1+    , mmorph >=1.1 && <1.2     , mtl >=2.2 && <2.3     , text >=1.2 && <1.3   default-language: Haskell2010@@ -61,6 +62,7 @@       base >=4.12 && <5     , containers >=0.6 && <0.7     , list-t >=1.0 && <1.1+    , mmorph >=1.1 && <1.2     , mtl >=2.2 && <2.3     , simple-parser     , tasty
src/SimpleParser.hs view
@@ -1,6 +1,8 @@--- | Re-exports for all modules. See 'SimpleParser.Examples.Json' or the test suit for examples,--- 'SimpleParser.Parser' for the core transformer, 'SimpleParser.Stream' for the source abstraction,--- or 'SimpleParser.Input' for useful combinators.+-- | This is basically a simpler and slower (Mega)Parsec that is fully backtracking by default.+--+-- The root module re-exports all modules. See "SimpleParser.Examples.Json" or the test suit for examples,+-- "SimpleParser.Parser" for the core transformer, "SimpleParser.Stream" for the source abstraction,+-- or "SimpleParser.Input" for useful combinators. module SimpleParser   ( module SimpleParser.Input   , module SimpleParser.Parser
src/SimpleParser/Examples/Json.hs view
@@ -9,7 +9,6 @@ import Control.Applicative (empty) import Control.Monad (void) import Data.Char (isSpace)-import Data.Foldable (asum) import Data.Text (Text) import Data.Void (Void) import SimpleParser@@ -104,7 +103,7 @@ nullParser = JsonNull <$ nullTok  boolParser :: JsonParser (JsonF a)-boolParser = branchParser [JsonBool True <$ trueTok, JsonBool False <$ falseTok]+boolParser = isolateParser (branchParser [JsonBool True <$ trueTok, JsonBool False <$ falseTok])  objectPairParser :: JsonParser a -> JsonParser (String, a) objectPairParser root = do@@ -120,7 +119,7 @@ arrayParser root = jsonBetween openBracket closeBracket (fmap JsonArray (jsonSepBy root comma))  rootParser :: JsonParser a -> JsonParser (JsonF a)-rootParser root = asum opts where+rootParser root = isolateParser (branchParser opts) where   pairParser = objectPairParser root   opts =     [ objectParser pairParser
src/SimpleParser/Parser.hs view
@@ -7,6 +7,7 @@   , reflectParser   , branchParser   , suppressParser+  , isolateParser   , defaultParser   , optionalParser   , silenceParser@@ -14,12 +15,14 @@   , greedyStarParser_   , greedyPlusParser   , greedyPlusParser_+  , lookAheadParser   ) where  import Control.Applicative (Alternative (..), liftA2) import Control.Monad (MonadPlus (..), ap, (>=>)) import Control.Monad.Except (MonadError (..)) import Control.Monad.Identity (Identity (..))+import Control.Monad.Morph (MFunctor (..)) import Control.Monad.State (MonadState (..)) import Control.Monad.Trans (MonadTrans (..)) import Data.Foldable (toList)@@ -73,6 +76,9 @@ instance MonadTrans (ParserT e s) where   lift ma = ParserT (\s -> lift (fmap (\a -> ParseResult (ParseSuccess a) s) ma)) +instance MFunctor (ParserT e s) where+  hoist trans (ParserT f) = ParserT (hoist trans . f)+ -- | Runs a non-effectful parser from an inital state and collects all results. runParser :: Parser e s a -> s -> [ParseResult e s a] runParser m s = runIdentity (ListT.toList (runParserT m s))@@ -100,6 +106,7 @@         pure (Just (ParseResult (ParseSuccess v) t, ListT (go rest)))  -- | Combines the results of many parsers.+-- Equvalent to 'asum'. branchParser :: (Foldable f, Monad m) => f (ParserT e s m a) -> ParserT e s m a branchParser = start . toList where   start ps =@@ -115,10 +122,8 @@           r:rs -> run s r rs       Just (a, rest) -> pure (Just (a, rest)) --- | If the parse results in ANY successes, keep only those. Otherwise return all failures.--- This may block indefinitely as it awaits either the end of the parser or its first success.-suppressParser :: Monad m => ParserT e s m a -> ParserT e s m a-suppressParser parser = ParserT (ListT . go [] . runParserT parser) where+gatherParser :: Monad m => Bool -> ParserT e s m a -> ParserT e s m a+gatherParser single parser = ParserT (ListT . go [] . runParserT parser) where   go !acc listt = do     m <- ListT.uncons listt     case m of@@ -126,7 +131,9 @@       Just (r@(ParseResult v _), rest) ->         case v of           ParseError _ -> go (r:acc) rest-          ParseSuccess _ -> pure (Just (r, ListT (filterOk rest)))+          ParseSuccess _ ->+            let t = if single then empty else ListT (filterOk rest)+            in pure (Just (r, t))    returnErr racc =     case racc of@@ -143,6 +150,18 @@           ParseError _ -> nextListt           ParseSuccess _ -> pure (Just (r, ListT nextListt)) +-- | If the parse results in ANY successes, keep only those. Otherwise return all failures.+-- This may block indefinitely as it awaits either the end of the parser or its first success.+-- See 'isolateParser' if you want only one success.+suppressParser :: Monad m => ParserT e s m a -> ParserT e s m a+suppressParser = gatherParser False++-- | If the parse results in ANY successes, keep only THE FIRST. Otherwise return all failures.+-- This may block indefinitely as it awaits either the end of the parser or its first success.+-- See 'suppressParser' if you want all successes.+isolateParser :: Monad m => ParserT e s m a -> ParserT e s m a+isolateParser = gatherParser True+ -- | If the parser yields no results (success or failure), yield a given value. defaultParser :: Monad m => a -> ParserT e s m a -> ParserT e s m a defaultParser def parser = ParserT (\s -> ListT (go s (runParserT parser s))) where@@ -158,6 +177,7 @@ optionalParser parser = defaultParser Nothing (fmap Just parser)  -- | Removes all failures from the parse results.+-- Equivalent to 'catchError (const empty)'. silenceParser :: Monad m => ParserT e s m a -> ParserT e s m a silenceParser parser = ParserT (ListT . go . runParserT parser) where   go listt = do@@ -197,3 +217,13 @@ -- | Same as 'greedyPlusParser' but discards the result. greedyPlusParser_ :: Monad m => ParserT e s m a -> ParserT e s m () greedyPlusParser_ parser = parser *> greedyStarParser_ parser++-- | Yield the results of the given parser, but rewind back to the starting state.+-- Note that these results may contain errors, so you may want to stifle them with 'silenceParser', for example.+lookAheadParser :: Monad m => ParserT e s m a -> ParserT e s m a+lookAheadParser parser = do+  s <- get+  flip catchError (\e -> put s *> throwError e) $ do+    v <- parser+    put s+    pure v
src/SimpleParser/Stream.hs view
@@ -1,5 +1,5 @@ -- | This reworks 'Text.Megaparsec.Stream' to split interfaces.--- See https://hackage.haskell.org/package/megaparsec-9.0.1/docs/Text-Megaparsec-Stream.html+-- See <https://hackage.haskell.org/package/megaparsec-9.0.1/docs/Text-Megaparsec-Stream.html Text.Megaparsec.Stream>. module SimpleParser.Stream   ( Chunked (..)   , Stream (..)
test/Main.hs view
@@ -425,6 +425,44 @@         ]   in testParserTrees parser cases +test_isolate_success :: [TestTree]+test_isolate_success =+  let state = OffsetStream 0 "hi"+      parser = isolateParser (asum [pure 1, pure 2]) :: TestParser Int+      cases =+        [ ("non-empty", InputOutput "hi" [parseSuccessResult 1 state])+        ]+  in testParserTrees parser cases++test_isolate_fail_first :: [TestTree]+test_isolate_fail_first =+  let err = Error "boo"+      parser = isolateParser (asum [throwError err, pure 2]) :: TestParser Int+      cases =+        [ ("non-empty", InputOutput "hi" [parseSuccessResult 2 (OffsetStream 0 "hi")])+        ]+  in testParserTrees parser cases++test_isolate_fail_second :: [TestTree]+test_isolate_fail_second =+  let err = Error "boo"+      parser = isolateParser (asum [pure 1, throwError err]) :: TestParser Int+      cases =+        [ ("non-empty", InputOutput "hi" [parseSuccessResult 1 (OffsetStream 0 "hi")])+        ]+  in testParserTrees parser cases++test_isolate_fail_both :: [TestTree]+test_isolate_fail_both =+  let state = OffsetStream 0 "hi"+      err1 = Error "boo1"+      err2 = Error "boo2"+      parser = isolateParser (asum [throwError err1, throwError err2]) :: TestParser Int+      cases =+        [ ("non-empty", InputOutput "hi" [parseErrorResult err1 state, parseErrorResult err2 state])+        ]+  in testParserTrees parser cases+ test_silence_success :: [TestTree] test_silence_success =   let state = OffsetStream 0 "hi"@@ -459,6 +497,25 @@       parser = silenceParser (asum [throwError err1, throwError err2]) :: TestParser Int       cases =         [ ("non-empty", InputOutput "hi" [])+        ]+  in testParserTrees parser cases++test_look_ahead_success :: [TestTree]+test_look_ahead_success =+  let parser = lookAheadParser anyToken+      cases =+        [ ("empty", InputOutput "" [])+        , ("non-empty", InputOutput "hi" [parseSuccessResult 'h' (OffsetStream 0 "hi")])+        ]+  in testParserTrees parser cases++test_look_ahead_failure :: [TestTree]+test_look_ahead_failure =+  let err = Error "boo"+      parser = lookAheadParser (anyToken *> throwError err) :: TestParser Char+      cases =+        [ ("empty", InputOutput "" [])+        , ("non-empty", InputOutput "hi" [parseErrorResult err (OffsetStream 0 "hi")])         ]   in testParserTrees parser cases