From 8412e63213a0e071ade79b74b007d9f0e544513c Mon Sep 17 00:00:00 2001 From: James Brock Date: Wed, 7 Oct 2020 02:00:01 +0900 Subject: [PATCH 1/2] Parsing failure context region (#97) --- src/Text/Parsing/Parser.purs | 13 +++++++------ test/Main.purs | 9 +++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Text/Parsing/Parser.purs b/src/Text/Parsing/Parser.purs index 013df83..32be296 100644 --- a/src/Text/Parsing/Parser.purs +++ b/src/Text/Parsing/Parser.purs @@ -13,7 +13,7 @@ module Text.Parsing.Parser , position , fail , failWithPosition - , label + , region ) where import Prelude @@ -138,8 +138,9 @@ fail message = failWithPosition message =<< position failWithPosition :: forall m s a. Monad m => String -> Position -> ParserT s m a failWithPosition message pos = throwError (ParseError message pos) --- | If parsing fails inside this labelled context, then prepend the `String` --- | to the error `String` in the `ParseError`. -label :: forall m s a. Monad m => String -> ParserT s m a -> ParserT s m a -label messagePrefix p = catchError p $ \ (ParseError message pos) -> - throwError $ ParseError (messagePrefix <> message) pos +-- | Contextualize parsing failures inside a region. If a parsing failure +-- | occurs, then the `ParseError` will be transformed by each containing +-- | `region` as the parser backs out the call stack. +region :: forall m s a. Monad m => (ParseError -> ParseError) -> ParserT s m a -> ParserT s m a +region context p = catchError p $ \err -> throwError $ context err + diff --git a/test/Main.purs b/test/Main.purs index 21c0dd5..b2466a0 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -13,7 +13,7 @@ import Data.Tuple (Tuple(..)) import Effect (Effect) import Effect.Console (logShow) import Test.Assert (assert') -import Text.Parsing.Parser (Parser, ParserT, ParseError(..), runParser, parseErrorPosition, label) +import Text.Parsing.Parser (Parser, ParserT, ParseError(..), runParser, parseErrorPosition, region) import Text.Parsing.Parser.Combinators (endBy1, sepBy1, optionMaybe, try, chainl, between) import Text.Parsing.Parser.Expr (Assoc(..), Operator(..), buildExprParser) import Text.Parsing.Parser.Language (javaStyle, haskellStyle, haskellDef) @@ -500,11 +500,12 @@ main = do case runParser "aa" p of Right _ -> assert' "error: ParseError expected!" false Left (ParseError message pos) -> do - let messageExpected = "context1context2Expected \"b\"" + let messageExpected = "context1 context2 Expected \"b\"" assert' ("expected message: " <> messageExpected <> ", message: " <> message) (message == messageExpected) logShow messageExpected where - p = label "context1" $ do + prependContext m' (ParseError m pos) = ParseError (m' <> m) pos + p = region (prependContext "context1 ") $ do _ <- string "a" - label "context2" $ do + region (prependContext "context2 ") $ do string "b" From 96ab4779abb6bdd35f9e6104a3b24504a08e2df4 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 31 Jan 2020 17:44:44 +0100 Subject: [PATCH 2/2] derive generic instance of Position --- bower.json | 3 ++- spago.dhall | 1 + src/Text/Parsing/Parser.purs | 13 ++++++------- src/Text/Parsing/Parser/Pos.purs | 3 +++ test/Main.purs | 9 ++++----- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/bower.json b/bower.json index 3e0f3bb..f89a733 100644 --- a/bower.json +++ b/bower.json @@ -29,7 +29,8 @@ "purescript-maybe": "^4.0.0", "purescript-strings": "^4.0.0", "purescript-transformers": "^4.1.0", - "purescript-unicode": "^4.0.0" + "purescript-unicode": "^4.0.0", + "purescript-generics-rep": "^6.1.1" }, "devDependencies": { "purescript-assert": "^4.0.0", diff --git a/spago.dhall b/spago.dhall index b40582a..fabd3c7 100644 --- a/spago.dhall +++ b/spago.dhall @@ -3,6 +3,7 @@ [ "arrays" , "assert" , "console" + , "generics-rep" , "effect" , "either" , "foldable-traversable" diff --git a/src/Text/Parsing/Parser.purs b/src/Text/Parsing/Parser.purs index 32be296..013df83 100644 --- a/src/Text/Parsing/Parser.purs +++ b/src/Text/Parsing/Parser.purs @@ -13,7 +13,7 @@ module Text.Parsing.Parser , position , fail , failWithPosition - , region + , label ) where import Prelude @@ -138,9 +138,8 @@ fail message = failWithPosition message =<< position failWithPosition :: forall m s a. Monad m => String -> Position -> ParserT s m a failWithPosition message pos = throwError (ParseError message pos) --- | Contextualize parsing failures inside a region. If a parsing failure --- | occurs, then the `ParseError` will be transformed by each containing --- | `region` as the parser backs out the call stack. -region :: forall m s a. Monad m => (ParseError -> ParseError) -> ParserT s m a -> ParserT s m a -region context p = catchError p $ \err -> throwError $ context err - +-- | If parsing fails inside this labelled context, then prepend the `String` +-- | to the error `String` in the `ParseError`. +label :: forall m s a. Monad m => String -> ParserT s m a -> ParserT s m a +label messagePrefix p = catchError p $ \ (ParseError message pos) -> + throwError $ ParseError (messagePrefix <> message) pos diff --git a/src/Text/Parsing/Parser/Pos.purs b/src/Text/Parsing/Parser/Pos.purs index e65c6f2..6a20dff 100644 --- a/src/Text/Parsing/Parser/Pos.purs +++ b/src/Text/Parsing/Parser/Pos.purs @@ -1,6 +1,7 @@ module Text.Parsing.Parser.Pos where import Prelude +import Data.Generic.Rep (class Generic) import Data.Foldable (foldl) import Data.Newtype (wrap) import Data.String (split) @@ -14,6 +15,8 @@ newtype Position = Position , column :: Int } +derive instance genericPosition :: Generic Position _ + instance showPosition :: Show Position where show (Position { line: line, column: column }) = "(Position { line: " <> show line <> ", column: " <> show column <> " })" diff --git a/test/Main.purs b/test/Main.purs index b2466a0..21c0dd5 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -13,7 +13,7 @@ import Data.Tuple (Tuple(..)) import Effect (Effect) import Effect.Console (logShow) import Test.Assert (assert') -import Text.Parsing.Parser (Parser, ParserT, ParseError(..), runParser, parseErrorPosition, region) +import Text.Parsing.Parser (Parser, ParserT, ParseError(..), runParser, parseErrorPosition, label) import Text.Parsing.Parser.Combinators (endBy1, sepBy1, optionMaybe, try, chainl, between) import Text.Parsing.Parser.Expr (Assoc(..), Operator(..), buildExprParser) import Text.Parsing.Parser.Language (javaStyle, haskellStyle, haskellDef) @@ -500,12 +500,11 @@ main = do case runParser "aa" p of Right _ -> assert' "error: ParseError expected!" false Left (ParseError message pos) -> do - let messageExpected = "context1 context2 Expected \"b\"" + let messageExpected = "context1context2Expected \"b\"" assert' ("expected message: " <> messageExpected <> ", message: " <> message) (message == messageExpected) logShow messageExpected where - prependContext m' (ParseError m pos) = ParseError (m' <> m) pos - p = region (prependContext "context1 ") $ do + p = label "context1" $ do _ <- string "a" - region (prependContext "context2 ") $ do + label "context2" $ do string "b"