Skip to content

Commit 81a29f8

Browse files
committed
Remove all *Rec combinators.
We don't need these anymore because the CPS ParserT is always stack-safe.
1 parent fa15274 commit 81a29f8

File tree

2 files changed

+8
-338
lines changed

2 files changed

+8
-338
lines changed

src/Parsing/Combinators.purs

Lines changed: 7 additions & 213 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
-- | ### Data.List
1515
-- | * [Data.List.many](https://pursuit.purescript.org/packages/purescript-lists/docs/Data.List#v:many)
1616
-- | * [Data.List.some](https://pursuit.purescript.org/packages/purescript-lists/docs/Data.List#v:some)
17-
-- | * [Data.List.someRec](https://pursuit.purescript.org/packages/purescript-lists/docs/Data.List#v:someRec)
18-
-- | * [Data.List.manyRec](https://pursuit.purescript.org/packages/purescript-lists/docs/Data.List#v:manyRec)
1917
-- |
2018
-- | ### Data.List.NonEmpty
2119
-- | * See the __many1__ combinator below.
@@ -40,6 +38,11 @@
4038
-- | return a parser `replicateA n p :: Parser s (Array a)` which will
4139
-- | repeat parser `p` exactly `n` times. `replicateA n p` will only succeed
4240
-- | if it can match parser `p` exactly `n` consecutive times.
41+
-- |
42+
-- | ## Stack-safety
43+
-- |
44+
-- | The `ParserT` monad is always stack-safe, so `MonadRec` combinators are
45+
-- | not necessary.
4346
module Parsing.Combinators
4447
( (<?>)
4548
, (<??>)
@@ -48,27 +51,16 @@ module Parsing.Combinators
4851
, between
4952
, chainl
5053
, chainl1
51-
, chainl1Rec
52-
, chainlRec
5354
, chainr
5455
, chainr1
55-
, chainr1Rec
56-
, chainrRec
5756
, choice
5857
, endBy
5958
, endBy1
60-
, endBy1Rec
61-
, endByRec
6259
, lookAhead
6360
, many1
64-
, many1Rec
6561
, many1Till
66-
, many1TillRec
67-
, many1TillRec_
6862
, many1Till_
6963
, manyTill
70-
, manyTillRec
71-
, manyTillRec_
7264
, manyTill_
7365
, module Control.Plus
7466
, module Data.Unfoldable
@@ -79,16 +71,10 @@ module Parsing.Combinators
7971
, optional
8072
, sepBy
8173
, sepBy1
82-
, sepBy1Rec
83-
, sepByRec
8474
, sepEndBy
8575
, sepEndBy1
86-
, sepEndBy1Rec
87-
, sepEndByRec
8876
, skipMany
8977
, skipMany1
90-
, skipMany1Rec
91-
, skipManyRec
9278
, try
9379
, tryRethrow
9480
, withErrorMessage
@@ -98,16 +84,14 @@ module Parsing.Combinators
9884
import Prelude
9985

10086
import Control.Lazy (defer)
101-
import Control.Monad.Rec.Class (Step(..), tailRecM)
10287
import Control.Plus (empty, (<|>), alt)
103-
import Data.Foldable (class Foldable, foldl, foldr)
88+
import Data.Foldable (class Foldable, foldr)
10489
import Data.Function.Uncurried (mkFn2, mkFn5, runFn2, runFn5)
105-
import Data.List (List(..), many, manyRec, reverse, (:))
90+
import Data.List (List(..), many, (:))
10691
import Data.List.NonEmpty (NonEmptyList, cons')
10792
import Data.List.NonEmpty as NEL
10893
import Data.Maybe (Maybe(..), fromMaybe)
10994
import Data.Tuple (Tuple(..))
110-
import Data.Tuple.Nested (type (/\), (/\))
11195
import Data.Unfoldable (replicateA)
11296
import Data.Unfoldable1 (replicate1A)
11397
import Parsing (ParseError(..), ParseState(..), ParserT(..), fail)
@@ -223,12 +207,6 @@ lookAhead (ParserT k1) = ParserT
223207
many1 :: forall m s a. ParserT s m a -> ParserT s m (NonEmptyList a)
224208
many1 p = NEL.cons' <$> p <*> many p
225209

226-
-- | Match one or more times.
227-
-- |
228-
-- | Stack-safe version of `many1` at the expense of a `MonadRec` constraint.
229-
many1Rec :: forall m s a. ParserT s m a -> ParserT s m (NonEmptyList a)
230-
many1Rec p = NEL.cons' <$> p <*> manyRec p
231-
232210
-- | Parse phrases delimited by a separator.
233211
-- |
234212
-- | For example:
@@ -239,38 +217,17 @@ many1Rec p = NEL.cons' <$> p <*> manyRec p
239217
sepBy :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
240218
sepBy p sep = map NEL.toList (sepBy1 p sep) <|> pure Nil
241219

242-
-- | Parse phrases delimited by a separator.
243-
-- |
244-
-- | Stack-safe version of `sepBy` at the expense of a `MonadRec` constraint.
245-
sepByRec :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
246-
sepByRec p sep = map NEL.toList (sepBy1Rec p sep) <|> pure Nil
247-
248220
-- | Parse phrases delimited by a separator, requiring at least one match.
249221
sepBy1 :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
250222
sepBy1 p sep = do
251223
a <- p
252224
as <- many $ sep *> p
253225
pure (NEL.cons' a as)
254226

255-
-- | Parse phrases delimited by a separator, requiring at least one match.
256-
-- |
257-
-- | Stack-safe version of `sepBy1` at the expense of a `MonadRec` constraint.
258-
sepBy1Rec :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
259-
sepBy1Rec p sep = do
260-
a <- p
261-
as <- manyRec $ sep *> p
262-
pure (NEL.cons' a as)
263-
264227
-- | Parse phrases delimited and optionally terminated by a separator.
265228
sepEndBy :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
266229
sepEndBy p sep = map NEL.toList (sepEndBy1 p sep) <|> pure Nil
267230

268-
-- | Parse phrases delimited and optionally terminated by a separator.
269-
-- |
270-
-- | Stack-safe version of `sepEndBy` at the expense of a `MonadRec` constraint.
271-
sepEndByRec :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
272-
sepEndByRec p sep = map NEL.toList (sepEndBy1Rec p sep) <|> pure Nil
273-
274231
-- | Parse phrases delimited and optionally terminated by a separator, requiring at least one match.
275232
sepEndBy1 :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
276233
sepEndBy1 p sep = do
@@ -281,45 +238,14 @@ sepEndBy1 p sep = do
281238
pure (NEL.cons' a as)
282239
) <|> pure (NEL.singleton a)
283240

284-
-- | Parse phrases delimited and optionally terminated by a separator, requiring at least one match.
285-
-- |
286-
-- | Stack-safe version of `sepEndBy1` at the expense of a `MonadRec` constraint.
287-
sepEndBy1Rec :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
288-
sepEndBy1Rec p sep = do
289-
a <- p
290-
(NEL.cons' a <$> tailRecM go Nil) <|> pure (NEL.singleton a)
291-
where
292-
go :: List a -> ParserT s m (Step (List a) (List a))
293-
go acc = nextOne <|> done
294-
where
295-
nextOne = do
296-
-- First make sure there's a separator.
297-
_ <- sep
298-
-- Then try the phrase and loop if it's there, or bail if it's not there.
299-
(p <#> \a -> Loop $ a : acc) <|> done
300-
301-
done = defer \_ -> pure $ Done $ reverse acc
302-
303241
-- | Parse phrases delimited and terminated by a separator, requiring at least one match.
304242
endBy1 :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
305243
endBy1 p sep = many1 $ p <* sep
306244

307-
-- | Parse phrases delimited and terminated by a separator, requiring at least one match.
308-
-- |
309-
-- | Stack-safe version of `endBy1` at the expense of a `MonadRec` constraint.
310-
endBy1Rec :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (NonEmptyList a)
311-
endBy1Rec p sep = many1Rec $ p <* sep
312-
313245
-- | Parse phrases delimited and terminated by a separator.
314246
endBy :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
315247
endBy p sep = many $ p <* sep
316248

317-
-- | Parse phrases delimited and terminated by a separator.
318-
-- |
319-
-- | Stack-safe version of `endBy` at the expense of a `MonadRec` constraint.
320-
endByRec :: forall m s a sep. ParserT s m a -> ParserT s m sep -> ParserT s m (List a)
321-
endByRec p sep = manyRec $ p <* sep
322-
323249
-- | Parse phrases delimited by a right-associative operator.
324250
-- |
325251
-- | For example:
@@ -330,12 +256,6 @@ endByRec p sep = manyRec $ p <* sep
330256
chainr :: forall m s a. ParserT s m a -> ParserT s m (a -> a -> a) -> a -> ParserT s m a
331257
chainr p f a = chainr1 p f <|> pure a
332258

333-
-- | Parse phrases delimited by a right-associative operator.
334-
-- |
335-
-- | Stack-safe version of `chainr` at the expense of a `MonadRec` constraint.
336-
chainrRec :: forall m s a. ParserT s m a -> ParserT s m (a -> a -> a) -> a -> ParserT s m a
337-
chainrRec p f a = chainr1Rec p f <|> pure a
338-
339259
-- | Parse phrases delimited by a left-associative operator.
340260
-- |
341261
-- | For example:
@@ -346,12 +266,6 @@ chainrRec p f a = chainr1Rec p f <|> pure a
346266
chainl :: forall m s a. ParserT s m a -> ParserT s m (a -> a -> a) -> a -> ParserT s m a
347267
chainl p f a = chainl1 p f <|> pure a
348268

349-
-- | Parse phrases delimited by a left-associative operator.
350-
-- |
351-
-- | Stack-safe version of `chainl` at the expense of a `MonadRec` constraint.
352-
chainlRec :: forall m s a. ParserT s m a -> ParserT s m (a -> a -> a) -> a -> ParserT s m a
353-
chainlRec p f a = chainl1Rec p f <|> pure a
354-
355269
-- | Parse phrases delimited by a left-associative operator, requiring at least one match.
356270
chainl1 :: forall m s a. ParserT s m a -> ParserT s m (a -> a -> a) -> ParserT s m a
357271
chainl1 p f = do
@@ -365,23 +279,6 @@ chainl1 p f = do
365279
chainl1' (f' a a')
366280
) <|> pure a
367281

368-
-- | Parse phrases delimited by a left-associative operator, requiring at least one match.
369-
-- |
370-
-- | Stack-safe version of `chainl1` at the expense of a `MonadRec` constraint.
371-
chainl1Rec :: forall m s a. ParserT s m a -> ParserT s m (a -> a -> a) -> ParserT s m a
372-
chainl1Rec p f = do
373-
a <- p
374-
tailRecM go a
375-
where
376-
go :: a -> ParserT s m (Step a a)
377-
go a =
378-
( do
379-
op <- f
380-
a' <- p
381-
pure $ Loop $ op a a'
382-
)
383-
<|> pure (Done a)
384-
385282
-- | Parse phrases delimited by a right-associative operator, requiring at least one match.
386283
chainr1 :: forall m s a. ParserT s m a -> ParserT s m (a -> a -> a) -> ParserT s m a
387284
chainr1 p f = do
@@ -395,51 +292,6 @@ chainr1 p f = do
395292
pure $ f' a a'
396293
) <|> pure a
397294

398-
-- | Parse phrases delimited by a right-associative operator, requiring at least one match.
399-
-- |
400-
-- | Stack-safe version of `chainr1` at the expense of a `MonadRec` constraint.
401-
chainr1Rec :: forall m s a. ParserT s m a -> ParserT s m (a -> a -> a) -> ParserT s m a
402-
chainr1Rec p f = do
403-
a <- p
404-
tailRecM go { last: a, init: Nil }
405-
where
406-
-- This looks scary at first glance, so I'm leaving a comment in a vain
407-
-- attempt to explain how it works.
408-
--
409-
-- The loop state is a record {init, last}, where `last` is the last (i.e.
410-
-- rightmost) `a` value that has been parsed so far, and `init` is a list of
411-
-- (value + operator) pairs that have been parsed before that.
412-
--
413-
-- The very first value is parsed at top level, and it becomes the initial
414-
-- value of `last`, while the initial value of `init` is just `Nil`,
415-
-- indicating that no pairs of (value + operator) have been parsed yet.
416-
--
417-
-- At every step, we parse an operator and a value, and then the newly parsed
418-
-- value becomes `last` (because, well, it's been parsed last), and the pair
419-
-- of (previous last + operator) is prepended to `init`.
420-
--
421-
-- After we can no longer parse a pair of (value + operation), we're done. At
422-
-- that point, we have a list of (value + operation) pairs in reverse order
423-
-- (since we prepend each pair as we go) and the very last value. All that's
424-
-- left is combine them all via `foldl`.
425-
go
426-
:: { init :: List (a /\ (a -> a -> a)), last :: a }
427-
-> ParserT s m
428-
( Step
429-
{ init :: List (a /\ (a -> a -> a)), last :: a }
430-
a
431-
)
432-
go { last, init } =
433-
( do
434-
op <- f
435-
a <- p
436-
pure $ Loop { last: a, init: (last /\ op) : init }
437-
)
438-
<|> pure (Done $ foldl apply last init)
439-
440-
apply :: a -> (a /\ (a -> a -> a)) -> a
441-
apply y (x /\ op) = x `op` y
442-
443295
-- | Parse one of a set of alternatives.
444296
choice :: forall f m s a. Foldable f => f (ParserT s m a) -> ParserT s m a
445297
choice = fromMaybe empty <<< foldr go Nothing
@@ -452,27 +304,13 @@ choice = fromMaybe empty <<< foldr go Nothing
452304
skipMany :: forall s a m. ParserT s m a -> ParserT s m Unit
453305
skipMany p = skipMany1 p <|> pure unit
454306

455-
-- | Skip many instances of a phrase.
456-
-- |
457-
-- | Stack-safe version of `skipMany` at the expense of a `MonadRec` constraint.
458-
skipManyRec :: forall s a m. ParserT s m a -> ParserT s m Unit
459-
skipManyRec p = skipMany1Rec p <|> pure unit
460-
461307
-- | Skip at least one instance of a phrase.
462308
skipMany1 :: forall s a m. ParserT s m a -> ParserT s m Unit
463309
skipMany1 p = do
464310
_ <- p
465311
_ <- skipMany p
466312
pure unit
467313

468-
-- | Skip at least one instance of a phrase.
469-
-- |
470-
-- | Stack-safe version of `skipMany1` at the expense of a `MonadRec` constraint.
471-
skipMany1Rec :: forall s a m. ParserT s m a -> ParserT s m Unit
472-
skipMany1Rec p = p *> tailRecM go unit
473-
where
474-
go _ = (p $> Loop unit) <|> pure (Done unit)
475-
476314
-- | Fail if the parser succeeds.
477315
-- |
478316
-- | Will never consume input.
@@ -488,30 +326,13 @@ manyTill p end = scan
488326
xs <- scan
489327
pure (x : xs)
490328

491-
-- | Parse many phrases until the terminator phrase matches.
492-
-- |
493-
-- | Stack-safe version of `manyTill` at the expense of a `MonadRec` constraint.
494-
manyTillRec :: forall s a m e. ParserT s m a -> ParserT s m e -> ParserT s m (List a)
495-
manyTillRec p end = tailRecM go Nil
496-
where
497-
go :: List a -> ParserT s m (Step (List a) (List a))
498-
go acc =
499-
(end <#> \_ -> Done $ reverse acc)
500-
<|> (p <#> \x -> Loop $ x : acc)
501-
502329
-- | Parse at least one phrase until the terminator phrase matches.
503330
many1Till :: forall s a m e. ParserT s m a -> ParserT s m e -> ParserT s m (NonEmptyList a)
504331
many1Till p end = do
505332
x <- p
506333
xs <- manyTill p end
507334
pure (NEL.cons' x xs)
508335

509-
-- | Parse at least one phrase until the terminator phrase matches.
510-
-- |
511-
-- | Stack-safe version of `many1Till` at the expense of a `MonadRec` constraint.
512-
many1TillRec :: forall s a m e. ParserT s m a -> ParserT s m e -> ParserT s m (NonEmptyList a)
513-
many1TillRec p end = NEL.cons' <$> p <*> manyTillRec p end
514-
515336
-- | Parse many phrases until the terminator phrase matches.
516337
-- | Returns the list of phrases and the terminator phrase.
517338
-- |
@@ -567,30 +388,3 @@ many1Till_ p end = do
567388
x <- p
568389
Tuple xs t <- manyTill_ p end
569390
pure $ Tuple (cons' x xs) t
570-
571-
-- | Parse many phrases until the terminator phrase matches.
572-
-- | Returns the list of phrases and the terminator phrase.
573-
-- |
574-
-- | Stack-safe version of `manyTill_` at the expense of a `MonadRec` constraint.
575-
manyTillRec_ :: forall s a m e. ParserT s m a -> ParserT s m e -> ParserT s m (Tuple (List a) e)
576-
manyTillRec_ p end = tailRecM go Nil
577-
where
578-
go :: List a -> ParserT s m (Step (List a) (Tuple (List a) e))
579-
go xs =
580-
do
581-
t <- end
582-
pure (Done (Tuple (reverse xs) t))
583-
<|>
584-
do
585-
x <- p
586-
pure (Loop (x : xs))
587-
588-
-- | Parse many phrases until the terminator phrase matches, requiring at least one match.
589-
-- | Returns the list of phrases and the terminator phrase.
590-
-- |
591-
-- | Stack-safe version of `many1Till_` at the expense of a `MonadRec` constraint.
592-
many1TillRec_ :: forall s a m e. ParserT s m a -> ParserT s m e -> ParserT s m (Tuple (NonEmptyList a) e)
593-
many1TillRec_ p end = do
594-
x <- p
595-
Tuple xs t <- manyTillRec_ p end
596-
pure $ Tuple (cons' x xs) t

0 commit comments

Comments
 (0)