Skip to content

Commit de0cf6b

Browse files
committed
Implement 'try'
1 parent ba4ed77 commit de0cf6b

File tree

3 files changed

+24
-11
lines changed

3 files changed

+24
-11
lines changed

src/Text/Parsing/StringParser.purs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ module Text.Parsing.StringParser where
22

33
import Data.Either (Either(..))
44

5+
type Pos = Number
6+
57
--
68
-- Strings are represented as a string with an index from the
79
-- start of the string.
@@ -12,7 +14,7 @@ import Data.Either (Either(..))
1214
-- This allows us to avoid repeatedly finding substrings
1315
-- every time we match a character.
1416
--
15-
type PosString = { str :: String, pos :: Number }
17+
type PosString = { str :: String, pos :: Pos }
1618

1719
--
1820
-- The type of parsing errors
@@ -26,13 +28,13 @@ instance showParseError :: Show ParseError where
2628
-- A parser is represented as a function which takes a pair of
2729
-- continuations for failure and success.
2830
--
29-
data Parser a = Parser (forall r. PosString -> (ParseError -> r) -> (a -> PosString -> r) -> r)
31+
data Parser a = Parser (forall r. PosString -> (Pos -> ParseError -> r) -> (a -> PosString -> r) -> r)
3032

31-
unParser :: forall a r. Parser a -> PosString -> (ParseError -> r) -> (a -> PosString -> r) -> r
33+
unParser :: forall a r. Parser a -> PosString -> (Pos -> ParseError -> r) -> (a -> PosString -> r) -> r
3234
unParser (Parser p) = p
3335

3436
runParser :: forall a. Parser a -> String -> Either ParseError a
35-
runParser p s = unParser p { str: s, pos: 0 } Left (\a _ -> Right a)
37+
runParser p s = unParser p { str: s, pos: 0 } (\_ err -> Left err) (\a _ -> Right a)
3638

3739
--
3840
-- Parser type class instances
@@ -58,10 +60,16 @@ instance bindParser :: Bind Parser where
5860
instance monadParser :: Monad Parser
5961

6062
instance alternativeParser :: Alternative Parser where
61-
empty = Parser (\_ fc _ -> fc (ParseError "No alternative"))
63+
empty = fail "No alternative"
6264
(<|>) p1 p2 = Parser (\s fc sc ->
63-
unParser p1 s (\_ ->
64-
unParser p2 s fc sc) sc)
65+
unParser p1 s (\pos msg ->
66+
if s.pos == pos
67+
then unParser p2 s fc sc
68+
else fc pos msg)
69+
sc)
6570

6671
fail :: forall a. String -> Parser a
67-
fail msg = Parser (\_ fc _ -> fc (ParseError msg))
72+
fail msg = Parser (\{ pos = pos } fc _ -> fc pos (ParseError msg))
73+
74+
try :: forall a. Parser a -> Parser a
75+
try p = Parser (\(s@{ pos = pos }) fc sc -> unParser p s (\_ -> fc pos) sc)

src/Text/Parsing/StringParser/String.purs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import Text.Parsing.StringParser
55

66
eof :: Parser {}
77
eof = Parser (\s fc sc -> case s of
8-
{ str = str, pos = i } | i < length str -> fc (ParseError "Expected EOF")
8+
{ str = str, pos = i } | i < length str -> fc i (ParseError "Expected EOF")
99
_ -> sc {} s)
1010

1111
anyChar :: Parser String
1212
anyChar = Parser (\s fc sc -> case s of
1313
{ str = str, pos = i } | i < length str -> sc (charAt i str) { str: str, pos: i + 1 }
14-
_ -> fc (ParseError "Unexpected EOF"))
14+
{ pos = i } -> fc i (ParseError "Unexpected EOF"))
1515

1616
string :: String -> Parser String
1717
string nt = Parser (\s fc sc -> case s of
1818
{ str = str, pos = i } | indexOf' nt i str == i -> sc nt { str: str, pos: i + length nt }
19-
{ pos = i } -> fc (ParseError $ "Expected '" ++ nt ++ "' at position " ++ show i ++ "."))
19+
{ pos = i } -> fc i (ParseError $ "Expected '" ++ nt ++ "'."))

tests/Tests.purs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ exprTest = buildExprParser [[Infix (string "/" >>= \_ -> return (/)) AssocRight]
5050
,[Infix (string "*" >>= \_ -> return (*)) AssocRight]
5151
,[Infix (string "-" >>= \_ -> return (-)) AssocRight]
5252
,[Infix (string "+" >>= \_ -> return (+)) AssocRight]] digit
53+
54+
tryTest :: Parser String
55+
tryTest = try ((++) <$> string "aa" <*> string "bb") <|>
56+
(++) <$> string "aa" <*> string "cc"
5357

5458
main = do
5559
parseTest nested "(((a)))"
@@ -64,3 +68,4 @@ main = do
6468
return as) "a,a,a,"
6569
parseTest opTest "a+b+c"
6670
parseTest exprTest "1*2+3/4-5"
71+
parseTest tryTest "aacc"

0 commit comments

Comments
 (0)