Skip to content

Commit 0be7c39

Browse files
authored
Merge pull request #66 from natefaubion/fix-try
Add tryRethrow
2 parents 82f4d33 + 92c6b50 commit 0be7c39

File tree

5 files changed

+30
-9
lines changed

5 files changed

+30
-9
lines changed

Diff for: src/Text/Parsing/Parser.purs

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module Text.Parsing.Parser
2-
( ParseError
2+
( ParseError(..)
33
, parseErrorMessage
44
, parseErrorPosition
55
, ParseState(..)
@@ -10,7 +10,9 @@ module Text.Parsing.Parser
1010
, hoistParserT
1111
, mapParserT
1212
, consume
13+
, position
1314
, fail
15+
, failWithPosition
1416
) where
1517

1618
import Prelude
@@ -123,8 +125,14 @@ consume :: forall s m. Monad m => ParserT s m Unit
123125
consume = modify \(ParseState input position _) ->
124126
ParseState input position true
125127

128+
-- | Returns the current position in the stream.
129+
position :: forall s m. Monad m => ParserT s m Position
130+
position = gets \(ParseState _ pos _) -> pos
131+
126132
-- | Fail with a message.
127133
fail :: forall m s a. Monad m => String -> ParserT s m a
128-
fail message = do
129-
position <- gets \(ParseState _ pos _) -> pos
130-
throwError (ParseError message position)
134+
fail message = failWithPosition message =<< position
135+
136+
-- | Fail with a message and a position.
137+
failWithPosition :: forall m s a. Monad m => String -> Position -> ParserT s m a
138+
failWithPosition message position = throwError (ParseError message position)

Diff for: src/Text/Parsing/Parser/Combinators.purs

+9-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import Data.List (List(..), (:), many, some, singleton)
3030
import Data.Maybe (Maybe(..))
3131
import Data.Newtype (unwrap)
3232
import Data.Tuple (Tuple(..))
33-
import Text.Parsing.Parser (ParseState(..), ParserT(..), fail)
33+
import Text.Parsing.Parser (ParseState(..), ParserT(..), ParseError(..), fail)
3434

3535
-- | Provide an error message in the case of failure.
3636
withErrorMessage :: forall m s a. Monad m => ParserT s m a -> String -> ParserT s m a
@@ -74,6 +74,14 @@ try p = (ParserT <<< ExceptT <<< StateT) \(s@(ParseState _ _ consumed)) -> do
7474
Left _ -> pure (Tuple e (ParseState input position consumed))
7575
_ -> pure (Tuple e s')
7676

77+
-- | Like `try`, but will reannotate the error location to the `try` point.
78+
tryRethrow :: forall m s a. Monad m => ParserT s m a -> ParserT s m a
79+
tryRethrow p = (ParserT <<< ExceptT <<< StateT) \(s@(ParseState _ position consumed)) -> do
80+
Tuple e s'@(ParseState input' position' _) <- runStateT (runExceptT (unwrap p)) s
81+
case e of
82+
Left (ParseError err _) -> pure (Tuple (Left (ParseError err position)) (ParseState input' position' consumed))
83+
_ -> pure (Tuple e s')
84+
7785
-- | Parse a phrase, without modifying the consumed state or stream position.
7886
lookAhead :: forall s a m. Monad m => ParserT s m a -> ParserT s m a
7987
lookAhead p = (ParserT <<< ExceptT <<< StateT) \s -> do

Diff for: src/Text/Parsing/Parser/String.purs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Data.Maybe (Maybe(..))
1010
import Data.Newtype (wrap)
1111
import Data.String (Pattern, fromCharArray, length, singleton)
1212
import Text.Parsing.Parser (ParseState(..), ParserT, fail)
13-
import Text.Parsing.Parser.Combinators (try, (<?>))
13+
import Text.Parsing.Parser.Combinators (tryRethrow, (<?>))
1414
import Text.Parsing.Parser.Pos (updatePosString)
1515
import Prelude hiding (between)
1616

@@ -62,7 +62,7 @@ anyChar = do
6262

6363
-- | Match a character satisfying the specified predicate.
6464
satisfy :: forall s m. StringLike s => Monad m => (Char -> Boolean) -> ParserT s m Char
65-
satisfy f = try do
65+
satisfy f = tryRethrow do
6666
c <- anyChar
6767
if f c then pure c
6868
else fail $ "Character '" <> singleton c <> "' did not satisfy predicate"

Diff for: src/Text/Parsing/Parser/Token.purs

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import Data.String (toCharArray, null, toLower, fromCharArray, singleton, uncons
3939
import Data.Tuple (Tuple(..))
4040
import Math (pow)
4141
import Text.Parsing.Parser (ParseState(..), ParserT, fail)
42-
import Text.Parsing.Parser.Combinators (skipMany1, try, skipMany, notFollowedBy, option, choice, between, sepBy1, sepBy, (<?>), (<??>))
42+
import Text.Parsing.Parser.Combinators (skipMany1, try, tryRethrow, skipMany, notFollowedBy, option, choice, between, sepBy1, sepBy, (<?>), (<??>))
4343
import Text.Parsing.Parser.Pos (Position)
4444
import Text.Parsing.Parser.String (satisfy, oneOf, noneOf, string, char)
4545
import Prelude hiding (when,between)
@@ -57,7 +57,7 @@ token tokpos = do
5757

5858
-- | Create a parser which matches any token satisfying the predicate.
5959
when :: forall m a. Monad m => (a -> Position) -> (a -> Boolean) -> ParserT (List a) m a
60-
when tokpos f = try $ do
60+
when tokpos f = tryRethrow do
6161
a <- token tokpos
6262
guard $ f a
6363
pure a

Diff for: test/Main.purs

+5
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,11 @@ main = do
419419
"foo"
420420
(Position { column: 2, line: 1 })
421421

422+
parseErrorTestPosition
423+
(satisfy (_ == '?'))
424+
"foo"
425+
(Position { column: 1, line: 1 })
426+
422427
parseTest
423428
"foo"
424429
Nil

0 commit comments

Comments
 (0)