simple-parser 0.8.4 → 0.9
raw patch · 9 files changed
+100/−34 lines, 9 filesdep +exceptionsPVP ok
version bump matches the API change (PVP)
Dependencies added: exceptions
API changes (from Hackage documentation)
+ SimpleParser.Result: ParseErrorBundle :: NESeq (ParseError l s e) -> ParseErrorBundle l s e
+ SimpleParser.Result: [unParseErrorBundle] :: ParseErrorBundle l s e -> NESeq (ParseError l s e)
+ SimpleParser.Result: instance (Data.Typeable.Internal.Typeable l, Data.Typeable.Internal.Typeable s, Data.Typeable.Internal.Typeable (SimpleParser.Stream.Token s), Data.Typeable.Internal.Typeable (SimpleParser.Stream.Chunk s), Data.Typeable.Internal.Typeable e, GHC.Show.Show l, GHC.Show.Show s, GHC.Show.Show (SimpleParser.Stream.Token s), GHC.Show.Show (SimpleParser.Stream.Chunk s), GHC.Show.Show e) => GHC.Exception.Type.Exception (SimpleParser.Result.ParseError l s e)
+ SimpleParser.Result: instance (Data.Typeable.Internal.Typeable l, Data.Typeable.Internal.Typeable s, Data.Typeable.Internal.Typeable (SimpleParser.Stream.Token s), Data.Typeable.Internal.Typeable (SimpleParser.Stream.Chunk s), Data.Typeable.Internal.Typeable e, GHC.Show.Show l, GHC.Show.Show s, GHC.Show.Show (SimpleParser.Stream.Token s), GHC.Show.Show (SimpleParser.Stream.Chunk s), GHC.Show.Show e) => GHC.Exception.Type.Exception (SimpleParser.Result.ParseErrorBundle l s e)
+ SimpleParser.Result: instance (GHC.Classes.Eq l, GHC.Classes.Eq s, GHC.Classes.Eq (SimpleParser.Stream.Token s), GHC.Classes.Eq (SimpleParser.Stream.Chunk s), GHC.Classes.Eq e) => GHC.Classes.Eq (SimpleParser.Result.ParseErrorBundle l s e)
+ SimpleParser.Result: instance (GHC.Show.Show l, GHC.Show.Show s, GHC.Show.Show (SimpleParser.Stream.Token s), GHC.Show.Show (SimpleParser.Stream.Chunk s), GHC.Show.Show e) => GHC.Show.Show (SimpleParser.Result.ParseErrorBundle l s e)
+ SimpleParser.Result: listParseErrors :: ParseErrorBundle l s e -> [ParseError l s e]
+ SimpleParser.Result: newtype ParseErrorBundle l s e
+ SimpleParser.Throw: EmptyParseError :: EmptyParseError
+ SimpleParser.Throw: data EmptyParseError
+ SimpleParser.Throw: instance GHC.Classes.Eq SimpleParser.Throw.EmptyParseError
+ SimpleParser.Throw: instance GHC.Exception.Type.Exception SimpleParser.Throw.EmptyParseError
+ SimpleParser.Throw: instance GHC.Show.Show SimpleParser.Throw.EmptyParseError
+ SimpleParser.Throw: runParserEnd :: (Typeable l, Typeable s, Typeable e, Typeable (Token s), Typeable (Chunk s), Show l, Show s, Show e, Show (Token s), Show (Chunk s), Stream s, MonadThrow m) => Parser l s e a -> s -> m a
+ SimpleParser.Throw: runParserThrow :: (Typeable l, Typeable s, Typeable e, Typeable (Token s), Typeable (Chunk s), Show l, Show s, Show e, Show (Token s), Show (Chunk s), MonadThrow m) => Parser l s e a -> s -> m (ParseSuccess s a)
- SimpleParser.Result: ParseResultError :: !NESeq (ParseError l s e) -> ParseResult l s e a
+ SimpleParser.Result: ParseResultError :: !ParseErrorBundle l s e -> ParseResult l s e a
- SimpleParser.Result: matchSoleParseError :: NESeq (ParseError l s e) -> Maybe (ParseError l s e)
+ SimpleParser.Result: matchSoleParseError :: ParseErrorBundle l s e -> Maybe (ParseError l s e)
Files
- simple-parser.cabal +5/−2
- src/SimpleParser.hs +2/−0
- src/SimpleParser/Errata.hs +2/−2
- src/SimpleParser/Input.hs +3/−2
- src/SimpleParser/Interactive.hs +2/−2
- src/SimpleParser/Parser.hs +12/−12
- src/SimpleParser/Result.hs +35/−13
- src/SimpleParser/Throw.hs +38/−0
- test/Main.hs +1/−1
simple-parser.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 4bbc9417c33617079e899a0ae2e27cc738c1e6b0f4ed0ada613ea049b5d36317+-- hash: 31d2be3a928dd5d492fb80583be7ad1ca75b40f617f793ad6a069146084b3702 name: simple-parser-version: 0.8.4+version: 0.9 synopsis: Simple parser combinators description: Please see the README on GitHub at <https://github.com/ejconlon/simple-parser#readme> category: Parsing@@ -43,6 +43,7 @@ SimpleParser.Result SimpleParser.Stack SimpleParser.Stream+ SimpleParser.Throw other-modules: Paths_simple_parser hs-source-dirs:@@ -69,6 +70,7 @@ , bytestring ==0.10.* , containers ==0.6.* , errata ==0.3.*+ , exceptions ==0.10.* , mmorph ==1.1.* , mtl ==2.2.* , nonempty-containers ==0.3.*@@ -106,6 +108,7 @@ , bytestring ==0.10.* , containers ==0.6.* , errata ==0.3.*+ , exceptions ==0.10.* , mmorph ==1.1.* , mtl ==2.2.* , nonempty-containers ==0.3.*
src/SimpleParser.hs view
@@ -15,6 +15,7 @@ , module SimpleParser.Result , module SimpleParser.Stack , module SimpleParser.Stream+ , module SimpleParser.Throw ) where import SimpleParser.CharString@@ -28,3 +29,4 @@ import SimpleParser.Result import SimpleParser.Stack import SimpleParser.Stream+import SimpleParser.Throw
src/SimpleParser/Errata.hs view
@@ -12,7 +12,7 @@ import qualified Data.Text as T import Errata (Block, Style, blockMerged') import SimpleParser.Explain (ErrorExplanation (..), Explainable, ParseErrorExplanation (..), explainParseError)-import SimpleParser.Result (ParseError, ParseResult (..))+import SimpleParser.Result (ParseError, ParseErrorBundle (ParseErrorBundle), ParseResult (..)) import SimpleParser.Stream (Col (..), HasLinePos (..), Line (..), Pos, Span (..)) type LinePosExplainable l s e = (Explainable l s e, HasLinePos (Pos s))@@ -49,5 +49,5 @@ errataParseResult :: LinePosExplainable l s e => Style -> FilePath -> ParseResult l s e a -> [Block] errataParseResult style fp pr = case pr of- ParseResultError errs -> fmap (errataParseError style fp) (toList errs)+ ParseResultError (ParseErrorBundle errs) -> fmap (errataParseError style fp) (toList errs) ParseResultSuccess _ -> []
src/SimpleParser/Input.hs view
@@ -27,12 +27,13 @@ import Data.Maybe (isNothing) import SimpleParser.Chunked (Chunked (..)) import SimpleParser.Parser (ParserT (..), markWithOptStateParser, markWithStateParser)-import SimpleParser.Result (CompoundError (..), ParseError (..), ParseResult (..), RawError (..), StreamError (..))+import SimpleParser.Result (CompoundError (..), ParseError (..), ParseErrorBundle (..), ParseResult (..), RawError (..),+ StreamError (..)) import SimpleParser.Stack (emptyStack) import SimpleParser.Stream (Stream (..)) throwStreamError :: Monad m => RawError (Chunk s) (Token s) -> ParserT l s e m a-throwStreamError re = ParserT (\s -> pure (Just (ParseResultError (pure (ParseError emptyStack s (CompoundErrorStream (StreamError re)))))))+throwStreamError re = ParserT (\s -> pure (Just (ParseResultError (ParseErrorBundle (pure (ParseError emptyStack s (CompoundErrorStream (StreamError re)))))))) -- | Fetches the next token from the stream and runs the callback. withToken :: (Stream s, Monad m) => Maybe l -> (Maybe (Token s) -> ParserT l s e m a) -> ParserT l s e m a
src/SimpleParser/Interactive.hs view
@@ -16,7 +16,7 @@ import SimpleParser.Explain (Explainable, buildAllParseErrorExplanations, explainParseError) import SimpleParser.Input (matchEnd) import SimpleParser.Parser (Parser, runParser)-import SimpleParser.Result (ParseResult (..), ParseSuccess (..))+import SimpleParser.Result (ParseErrorBundle (..), ParseResult (..), ParseSuccess (..)) import SimpleParser.Stream (LinePosStream, newLinePosStream) import qualified Text.Builder as TB @@ -30,7 +30,7 @@ case runParser (parser <* matchEnd) (newLinePosStream (T.pack input)) of Nothing -> putStrLn "No result."- Just (ParseResultError es) ->+ Just (ParseResultError (ParseErrorBundle es)) -> case errStyle of ErrorStyleErrata -> let blocks = fmap (errataParseError fancyStyle "<interactive>") (toList es)
src/SimpleParser/Parser.hs view
@@ -46,8 +46,8 @@ import Data.Text (Text) import qualified Data.Text as T import SimpleParser.Chunked (Chunked (..))-import SimpleParser.Result (CompoundError (..), Mark (..), ParseError (..), ParseResult (..), ParseSuccess (..),- markParseError, parseErrorResume, unmarkParseError)+import SimpleParser.Result (CompoundError (..), Mark (..), ParseError (..), ParseErrorBundle (..), ParseResult (..),+ ParseSuccess (..), markParseError, parseErrorResume, unmarkParseError) import SimpleParser.Stack (emptyStack) -- | A 'ParserT' is a state/error/list transformer useful for parsing.@@ -100,15 +100,15 @@ Just res1 -> case res1 of ParseResultSuccess _ -> pure mres1- ParseResultError es1 -> runParserT two s >>= go2 (NESeq.toSeq es1)+ ParseResultError (ParseErrorBundle es1) -> runParserT two s >>= go2 (NESeq.toSeq es1) go2 es1 mres2 = case mres2 of- Nothing -> pure (fmap ParseResultError (NESeq.nonEmptySeq es1))+ Nothing -> pure (fmap (ParseResultError . ParseErrorBundle) (NESeq.nonEmptySeq es1)) Just res2 -> case res2 of ParseResultSuccess _ -> pure mres2- ParseResultError es2 -> pure (Just (ParseResultError (es1 ><| es2)))+ ParseResultError (ParseErrorBundle es2) -> pure (Just (ParseResultError (ParseErrorBundle (es1 ><| es2)))) -- | Yields the LONGEST string of 0 or more successes of the given parser. -- Failures will be silenced.@@ -166,7 +166,7 @@ ParseResultSuccess _ -> -- Nothing to catch, yield existing success pure mres- ParseResultError es ->+ ParseResultError (ParseErrorBundle es) -> -- Find first custom error to handle goSplit s0 Empty (NESeq.toSeq es) @@ -174,7 +174,7 @@ case seqPartition extractCustomError afterEs of Nothing -> -- No next custom error, finally yield all other errors- pure (maybe empty (pure . ParseResultError) (NESeq.nonEmptySeq (beforeEs <> afterEs)))+ pure (maybe empty (pure . ParseResultError . ParseErrorBundle) (NESeq.nonEmptySeq (beforeEs <> afterEs))) Just sep -> -- Found custom error - handle it goHandle s0 beforeEs sep@@ -195,13 +195,13 @@ Just res -> case res of ParseResultSuccess _ -> pure mres- ParseResultError es ->+ ParseResultError (ParseErrorBundle es) -> -- Add to list of errors and find next custom error goSplit s0 (beforeEs <> nextBeforeEs <> NESeq.toSeq es) afterEs -- | Throws a custom error throwParser :: Monad m => e -> ParserT l s e m a-throwParser e = ParserT (\s -> pure (Just (ParseResultError (pure (ParseError emptyStack s (CompoundErrorCustom e))))))+throwParser e = ParserT (\s -> pure (Just (ParseResultError (ParseErrorBundle (pure (ParseError emptyStack s (CompoundErrorCustom e))))))) -- | Catches a custom error catchParser :: Monad m => ParserT l s e m a -> (e -> ParserT l s e m a) -> ParserT l s e m a@@ -213,7 +213,7 @@ -- | A simple failing parser failParser :: Monad m => Text -> ParserT l s e m a-failParser msg = ParserT (\s -> pure (Just (ParseResultError (pure (ParseError emptyStack s (CompoundErrorFail msg))))))+failParser msg = ParserT (\s -> pure (Just (ParseResultError (ParseErrorBundle (pure (ParseError emptyStack s (CompoundErrorFail msg))))))) instance Monad m => MonadFail (ParserT l s e m) where fail = failParser . T.pack@@ -271,7 +271,7 @@ markParser ml parser = ParserT (\s -> fmap (fmap (go s)) (runParserT parser s)) where go s res = case res of- ParseResultError es -> ParseResultError (fmap (markParseError (Mark ml s)) es)+ ParseResultError (ParseErrorBundle es) -> ParseResultError (ParseErrorBundle (fmap (markParseError (Mark ml s)) es)) ParseResultSuccess _ -> res -- | Like 'markParser' but allows you to mutate state. See 'withToken' and 'withChunk'.@@ -288,7 +288,7 @@ unmarkParser parser = ParserT (fmap (fmap go) . runParserT parser) where go res = case res of- ParseResultError es -> ParseResultError (fmap unmarkParseError es)+ ParseResultError (ParseErrorBundle es) -> ParseResultError (ParseErrorBundle (fmap unmarkParseError es)) ParseResultSuccess _ -> res -- | If the first parser succeeds in the initial state, yield results from the second parser in the initial
src/SimpleParser/Result.hs view
@@ -13,15 +13,20 @@ , unmarkParseError , parseErrorEnclosingLabels , parseErrorNarrowestSpan+ , ParseErrorBundle (..)+ , listParseErrors+ , matchSoleParseError , ParseSuccess (..) , ParseResult (..)- , matchSoleParseError ) where +import Control.Exception (Exception)+import Data.Foldable (toList) import Data.Sequence (Seq (..)) import qualified Data.Sequence as Seq import Data.Sequence.NonEmpty (NESeq (..)) import Data.Text (Text)+import Data.Typeable (Typeable) import SimpleParser.Stack (Stack (..), bottomStack, bottomUpStack, emptyStack, pushStack, topStack) import SimpleParser.Stream (PosStream (..), Span (..), Stream (..)) @@ -74,6 +79,13 @@ , peError :: !(CompoundError s e) } +deriving instance (Eq l, Eq s, Eq (Token s), Eq (Chunk s), Eq e) => Eq (ParseError l s e)+deriving instance (Show l, Show s, Show (Token s), Show (Chunk s), Show e) => Show (ParseError l s e)++instance (+ Typeable l, Typeable s, Typeable (Token s), Typeable (Chunk s), Typeable e,+ Show l, Show s, Show (Token s), Show (Chunk s), Show e) => Exception (ParseError l s e)+ -- | Returns the resumption point of the 'ParseError'. -- If it has been marked, we use that, otherwise we assume it starts at the exact error point. parseErrorResume :: ParseError l s e -> s@@ -105,27 +117,37 @@ Empty -> Empty _ :<| s -> s >>= \(Mark ml _) -> maybe Seq.empty Seq.singleton ml -deriving instance (Eq l, Eq s, Eq (Token s), Eq (Chunk s), Eq e) => Eq (ParseError l s e)-deriving instance (Show l, Show s, Show (Token s), Show (Chunk s), Show e) => Show (ParseError l s e)- data ParseSuccess s a = ParseSuccess { psEndState :: !s , psValue :: !a } deriving (Eq, Show, Functor, Foldable, Traversable) -data ParseResult l s e a =- ParseResultError !(NESeq (ParseError l s e))- | ParseResultSuccess !(ParseSuccess s a)- deriving (Functor, Foldable, Traversable)+newtype ParseErrorBundle l s e = ParseErrorBundle { unParseErrorBundle :: NESeq (ParseError l s e) } -deriving instance (Eq l, Eq s, Eq (Token s), Eq (Chunk s), Eq e, Eq a) => Eq (ParseResult l s e a)-deriving instance (Show l, Show s, Show (Token s), Show (Chunk s), Show e, Show a) => Show (ParseResult l s e a)+deriving instance (Eq l, Eq s, Eq (Token s), Eq (Chunk s), Eq e) => Eq (ParseErrorBundle l s e)+deriving instance (Show l, Show s, Show (Token s), Show (Chunk s), Show e) => Show (ParseErrorBundle l s e) --- | If there is one parse error, return it, otherwise return nothing.+instance (+ Typeable l, Typeable s, Typeable (Token s), Typeable (Chunk s), Typeable e,+ Show l, Show s, Show (Token s), Show (Chunk s), Show e) => Exception (ParseErrorBundle l s e)++-- | Lists all errors in the bundle.+listParseErrors :: ParseErrorBundle l s e -> [ParseError l s e]+listParseErrors = toList . unParseErrorBundle++-- | If there is only one parse error in the bundle, return it, otherwise return nothing. -- Errors can accumulate if you use unrestricted branching (with 'orParser' or 'Alternative' '<|>') or manual 'Parser' constructor application. -- However, if you always branch with 'lookAheadMatch' then you will have singleton parse errors, and this will always return 'Just'.-matchSoleParseError :: NESeq (ParseError l s e) -> Maybe (ParseError l s e)-matchSoleParseError es =+matchSoleParseError :: ParseErrorBundle l s e -> Maybe (ParseError l s e)+matchSoleParseError (ParseErrorBundle es) = case es of e :<|| Empty -> Just e _ -> Nothing++data ParseResult l s e a =+ ParseResultError !(ParseErrorBundle l s e)+ | ParseResultSuccess !(ParseSuccess s a)+ deriving (Functor, Foldable, Traversable)++deriving instance (Eq l, Eq s, Eq (Token s), Eq (Chunk s), Eq e, Eq a) => Eq (ParseResult l s e a)+deriving instance (Show l, Show s, Show (Token s), Show (Chunk s), Show e, Show a) => Show (ParseResult l s e a)
+ src/SimpleParser/Throw.hs view
@@ -0,0 +1,38 @@+module SimpleParser.Throw+ ( EmptyParseError (..)+ , runParserThrow+ , runParserEnd+ ) where++import Control.Exception (Exception)+import Control.Monad.Catch (MonadThrow (throwM))+import Data.Typeable (Typeable)+import SimpleParser.Input (matchEnd)+import SimpleParser.Parser (Parser, runParser)+import SimpleParser.Result (ParseResult (..), ParseSuccess (..))+import SimpleParser.Stream (Chunk, Stream, Token)++data EmptyParseError = EmptyParseError+ deriving stock (Eq, Show)++instance Exception EmptyParseError++-- | Runs a parser and throws bundled errors / no parse result errors as exceptions.+runParserThrow :: (+ Typeable l, Typeable s, Typeable e, Typeable (Token s), Typeable (Chunk s),+ Show l, Show s, Show e, Show (Token s), Show (Chunk s),+ MonadThrow m) => Parser l s e a -> s -> m (ParseSuccess s a)+runParserThrow parser s =+ case runParser parser s of+ Nothing -> throwM EmptyParseError+ Just res ->+ case res of+ ParseResultError errs -> throwM errs+ ParseResultSuccess success -> pure success++-- | The easiest way to fully consume input and throw errors.+runParserEnd :: (+ Typeable l, Typeable s, Typeable e, Typeable (Token s), Typeable (Chunk s),+ Show l, Show s, Show e, Show (Token s), Show (Chunk s),+ Stream s, MonadThrow m) => Parser l s e a -> s -> m a+runParserEnd parser s = fmap psValue (runParserThrow (parser <* matchEnd) s)
test/Main.hs view
@@ -49,7 +49,7 @@ sucRes st = Just . ParseResultSuccess . ParseSuccess st errRes :: [TestParseError] -> Maybe (TestResult a)-errRes es = Just (ParseResultError (NESeq.unsafeFromSeq (Seq.fromList es)))+errRes es = Just (ParseResultError (ParseErrorBundle (NESeq.unsafeFromSeq (Seq.fromList es)))) custErr :: TestState -> Error -> TestParseError custErr endSt = ParseError emptyStack endSt . CompoundErrorCustom