Skip to content

Commit e8d917b

Browse files
justinwoopaf31
authored andcommitted
fix overflow caused by manyTill implementation (#35)
1 parent fc4f2d8 commit e8d917b

File tree

2 files changed

+17
-3
lines changed

2 files changed

+17
-3
lines changed

src/Text/Parsing/StringParser/Combinators.purs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ import Prelude
3131

3232
import Control.Alt ((<|>))
3333
import Control.Lazy (fix)
34+
import Control.Monad.Rec.Class (Step(..), tailRecM)
3435

3536
import Data.Either (Either(..))
3637
import Data.Foldable (class Foldable, foldl)
37-
import Data.List (List(..), singleton, manyRec)
38+
import Data.List (List(..), singleton, manyRec, reverse)
3839
import Data.Maybe (Maybe(..))
3940

4041
import Text.Parsing.StringParser (Parser(..), fail)
@@ -151,5 +152,12 @@ manyTill p end = (end *> pure Nil) <|> many1Till p end
151152
many1Till :: forall a end. Parser a -> Parser end -> Parser (List a)
152153
many1Till p end = do
153154
x <- p
154-
xs <- manyTill p end
155-
pure (Cons x xs)
155+
tailRecM inner (pure x)
156+
where
157+
ending acc = do
158+
_ <- end
159+
pure $ Done (reverse acc)
160+
continue acc = do
161+
c <- p
162+
pure $ Loop (Cons c acc)
163+
inner acc = ending acc <|> continue acc

test/Main.purs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import Control.Monad.Eff (Eff)
77
import Control.Monad.Eff.Console (CONSOLE)
88

99
import Data.Either (isLeft, isRight, Either(..))
10+
import Data.Foldable (fold)
1011
import Data.List (List(Nil), (:))
12+
import Data.List.Lazy (take, repeat)
1113
import Data.String (joinWith, singleton)
1214
import Data.Unfoldable (replicate)
1315

@@ -90,3 +92,7 @@ main = do
9092
assert $ expectResult Nil (manyTill (string "a") (string "b")) "b"
9193
assert $ expectResult ("a":"a":"a":Nil) (many1Till (string "a") (string "b")) "aaab"
9294
assert $ parseFail (many1Till (string "a") (string "b")) "b"
95+
-- check against overflow
96+
assert $ canParse (many1Till (string "a") (string "and")) $ (fold <<< take 10000 $ repeat "a") <> "and"
97+
-- check correct order
98+
assert $ expectResult ('a':'b':'c':Nil) (many1Till anyChar (string "d")) "abcd"

0 commit comments

Comments
 (0)