Skip to content

Commit 19bc664

Browse files
committed
make *1 combinators return NonEmptyLists
1 parent 8105c9d commit 19bc664

File tree

2 files changed

+23
-17
lines changed

2 files changed

+23
-17
lines changed

src/Text/Parsing/StringParser/Combinators.purs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@ import Prelude
3232
import Control.Alt ((<|>))
3333
import Control.Lazy (fix)
3434
import Control.Monad.Rec.Class (Step(..), tailRecM)
35-
3635
import Data.Either (Either(..))
3736
import Data.Foldable (class Foldable, foldl)
38-
import Data.List (List(..), singleton, manyRec, reverse)
37+
import Data.List (List(..), manyRec)
38+
import Data.List.NonEmpty (NonEmptyList(..))
39+
import Data.List.NonEmpty as NEL
3940
import Data.Maybe (Maybe(..))
40-
41+
import Data.NonEmpty ((:|))
4142
import Text.Parsing.StringParser (Parser(..), fail)
4243

4344
-- | Read ahead without consuming input.
@@ -52,8 +53,8 @@ many :: forall a. Parser a -> Parser (List a)
5253
many = manyRec
5354

5455
-- | Match one or more times.
55-
many1 :: forall a. Parser a -> Parser (List a)
56-
many1 p = Cons <$> p <*> many p
56+
many1 :: forall a. Parser a -> Parser (NonEmptyList a)
57+
many1 p = cons' <$> p <*> many p
5758

5859
-- | Provide an error message in case of failure.
5960
withError :: forall a. Parser a -> String -> Parser a
@@ -90,18 +91,18 @@ sepBy1 p sep = do
9091

9192
-- | Parse zero or more separated values, optionally ending with a separator.
9293
sepEndBy :: forall a sep. Parser a -> Parser sep -> Parser (List a)
93-
sepEndBy p sep = sepEndBy1 p sep <|> pure Nil
94+
sepEndBy p sep = map NEL.toList (sepEndBy1 p sep) <|> pure Nil
9495

9596
-- | Parse one or more separated values, optionally ending with a separator.
96-
sepEndBy1 :: forall a sep. Parser a -> Parser sep -> Parser (List a)
97+
sepEndBy1 :: forall a sep. Parser a -> Parser sep -> Parser (NonEmptyList a)
9798
sepEndBy1 p sep = do
9899
a <- p
99100
(do _ <- sep
100101
as <- sepEndBy p sep
101-
pure (Cons a as)) <|> pure (singleton a)
102+
pure (cons' a as)) <|> pure (NEL.singleton a)
102103

103104
-- | Parse zero or more separated values, ending with a separator.
104-
endBy1 :: forall a sep. Parser a -> Parser sep -> Parser (List a)
105+
endBy1 :: forall a sep. Parser a -> Parser sep -> Parser (NonEmptyList a)
105106
endBy1 p sep = many1 $ p <* sep
106107

107108
-- | Parse one or more separated values, ending with a separator.
@@ -146,18 +147,21 @@ choice = foldl (<|>) (fail "Nothing to parse")
146147

147148
-- | Parse values until a terminator.
148149
manyTill :: forall a end. Parser a -> Parser end -> Parser (List a)
149-
manyTill p end = (end *> pure Nil) <|> many1Till p end
150+
manyTill p end = (end *> pure Nil) <|> map NEL.toList (many1Till p end)
150151

151152
-- | Parse values until the terminator matches, requiring at least one match.
152-
many1Till :: forall a end. Parser a -> Parser end -> Parser (List a)
153+
many1Till :: forall a end. Parser a -> Parser end -> Parser (NonEmptyList a)
153154
many1Till p end = do
154155
x <- p
155156
tailRecM inner (pure x)
156157
where
157158
ending acc = do
158159
_ <- end
159-
pure $ Done (reverse acc)
160+
pure $ Done (NEL.reverse acc)
160161
continue acc = do
161162
c <- p
162-
pure $ Loop (Cons c acc)
163+
pure $ Loop (NEL.cons c acc)
163164
inner acc = ending acc <|> continue acc
165+
166+
cons' :: forall a. a -> List a -> NonEmptyList a
167+
cons' h t = NonEmptyList (h :| t)

test/Main.purs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import Data.Either (isLeft, isRight, Either(..))
77
import Data.Foldable (fold)
88
import Data.List (List(Nil), (:))
99
import Data.List.Lazy (take, repeat)
10+
import Data.List.NonEmpty (NonEmptyList(..))
11+
import Data.NonEmpty ((:|))
1012
import Data.String (joinWith)
1113
import Data.String.CodeUnits (singleton)
1214
import Data.Unfoldable (replicate)
@@ -84,14 +86,14 @@ main = do
8486
assert' "opTest" $ expectResult "abc" opTest "a+b+c"
8587
assert' "exprTest" $ expectResult (-3) exprTest "1*2+3/4-5"
8688
assert' "tryTest "$ canParse tryTest "aacc"
87-
assert $ expectResult ('0':'1':'2':'3':'4':Nil) (many1 anyDigit) "01234/"
88-
assert $ expectResult ('5':'6':'7':'8':'9':Nil) (many1 anyDigit) "56789:"
89+
assert $ expectResult (NonEmptyList ('0' :| '1':'2':'3':'4':Nil)) (many1 anyDigit) "01234/"
90+
assert $ expectResult (NonEmptyList ('5' :| '6':'7':'8':'9':Nil)) (many1 anyDigit) "56789:"
8991
assert $ expectResult "aaaa" (regex "a+") "aaaab"
9092
assert $ expectResult ("a":"a":"a":Nil) (manyTill (string "a") (string "b")) "aaab"
9193
assert $ expectResult Nil (manyTill (string "a") (string "b")) "b"
92-
assert $ expectResult ("a":"a":"a":Nil) (many1Till (string "a") (string "b")) "aaab"
94+
assert $ expectResult (NonEmptyList ("a" :| "a":"a":Nil)) (many1Till (string "a") (string "b")) "aaab"
9395
assert $ parseFail (many1Till (string "a") (string "b")) "b"
9496
-- check against overflow
9597
assert $ canParse (many1Till (string "a") (string "and")) $ (fold <<< take 10000 $ repeat "a") <> "and"
9698
-- check correct order
97-
assert $ expectResult ('a':'b':'c':Nil) (many1Till anyChar (string "d")) "abcd"
99+
assert $ expectResult (NonEmptyList ('a' :| 'b':'c':Nil)) (many1Till anyChar (string "d")) "abcd"

0 commit comments

Comments
 (0)