Skip to content

Commit 60b0eb9

Browse files
committed
WIP takeMany
1 parent e5cdcd3 commit 60b0eb9

File tree

2 files changed

+61
-1
lines changed

2 files changed

+61
-1
lines changed

src/Parsing/Combinators.purs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ module Parsing.Combinators
5555
, manyTill_
5656
, many1Till
5757
, many1Till_
58+
, manyFromTo
5859
, skipMany
5960
, skipMany1
6061
, sepBy
@@ -440,3 +441,43 @@ manyTill_ p end = tailRecM go Nil
440441
do
441442
x <- p
442443
pure (Loop (x : xs))
444+
445+
446+
-- | Repeat the phase like *many* at least *N* times, but no more than *M*
447+
-- | times.
448+
-- |
449+
-- | Returns the list of results and the length of the list.
450+
-- |
451+
-- | `manyFromTo n n` is equivalent to `replicateA n`.
452+
manyFromTo :: forall s m a. Int -> Int -> ParserT s m a -> ParserT s m (Tuple Int (List a))
453+
manyFromTo from to p =
454+
if from > to then
455+
pure (Tuple 0 Nil)
456+
else
457+
tailRecM go (Tuple 0 Nil)
458+
where
459+
go (Tuple i xs) =
460+
if i >= to then
461+
pure (Done (Tuple i (reverse xs)))
462+
else
463+
( do
464+
x <- p
465+
pure (Loop (Tuple (i+1) (x : xs)))
466+
)
467+
<|>
468+
( if i >= from
469+
then
470+
pure (Done (Tuple i (reverse xs)))
471+
else
472+
fail "manyFromTo expected more"
473+
)
474+
475+
-- | Repeat the parse phrases and collect them in a list until the supplied
476+
-- | predicate returns false.
477+
-- |
478+
-- | The predicate takes the number of phrases already parsed, and the
479+
-- | result of the most recent parse.
480+
-- |
481+
-- | Returns the list of results and the length of the list.
482+
-- while :: forall s m a. (Int -> a -> m Boolean) -> ParserT s m a -> ParserT s m (Tuple Int (List a))
483+
-- while predicate p =

test/Main.purs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import Effect.Console (log, logShow)
3434
import Effect.Unsafe (unsafePerformEffect)
3535
import Node.Process (lookupEnv)
3636
import Parsing (ParseError(..), Parser, ParserT, Position(..), consume, fail, initialPos, parseErrorMessage, parseErrorPosition, position, region, runParser)
37-
import Parsing.Combinators (between, chainl, chainl1, chainr, chainr1, choice, endBy, endBy1, lookAhead, many, many1, many1Till, many1Till_, manyTill, manyTill_, notFollowedBy, optionMaybe, sepBy, sepBy1, sepEndBy, sepEndBy1, skipMany, skipMany1, try, (<?>), (<??>), (<~?>))
37+
import Parsing.Combinators (between, chainl, chainl1, chainr, chainr1, choice, endBy, endBy1, lookAhead, many, many1, many1Till, many1Till_, manyFromTo, manyTill, manyTill_, notFollowedBy, optionMaybe, sepBy, sepBy1, sepEndBy, sepEndBy1, skipMany, skipMany1, try, (<?>), (<??>), (<~?>))
3838
import Parsing.Expr (Assoc(..), Operator(..), buildExprParser)
3939
import Parsing.Language (haskellDef, haskellStyle, javaStyle)
4040
import Parsing.String (anyChar, anyCodePoint, anyTill, char, eof, match, regex, rest, satisfy, string, takeN)
@@ -1006,3 +1006,22 @@ main = do
10061006
rmap fst <$> splitCap "((🌼)) (()())" (match balancedParens)
10071007
, expected: NonEmptyList $ Right "((🌼))" :| Left " " : Right "(()())" : Nil
10081008
}
1009+
1010+
log "\nTESTS manyFromTo\n"
1011+
1012+
assertEqual' "manyFromTo 1"
1013+
{ actual: runParser "aaab" $ manyFromTo 0 3 (char 'a')
1014+
, expected: Right (Tuple 3 ('a':'a':'a':Nil))
1015+
}
1016+
assertEqual' "manyFromTo 2"
1017+
{ actual: runParser "aaaa" $ manyFromTo 0 3 (char 'a')
1018+
, expected: Right (Tuple 3 ('a':'a':'a':Nil))
1019+
}
1020+
assertEqual' "manyFromTo 3"
1021+
{ actual: runParser "b" $ manyFromTo 0 3 (char 'a')
1022+
, expected: Right (Tuple 0 (Nil))
1023+
}
1024+
assertEqual' "manyFromTo 4"
1025+
{ actual: lmap parseErrorPosition $ runParser "ab" $ manyFromTo 3 3 (char 'a')
1026+
, expected: Left (Position {index:1,line:1,column:2})
1027+
}

0 commit comments

Comments
 (0)