diff --git a/CHANGELOG.md b/CHANGELOG.md index ccc150d..ae8d746 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ New features: Bugfixes: - fix spago package sets' upstream url +- make `sepEndBy` stack safe Other improvements: diff --git a/src/StringParser/Combinators.purs b/src/StringParser/Combinators.purs index 04b7682..8688fcb 100644 --- a/src/StringParser/Combinators.purs +++ b/src/StringParser/Combinators.purs @@ -142,11 +142,9 @@ sepEndBy p sep = (sepEndBy1 p sep <#> NEL.toList) <|> (sep $> Nil) <|> pure Nil sepEndBy1 :: forall a sep. Parser a -> Parser sep -> Parser (NonEmptyList a) sepEndBy1 p sep = do a <- p - ( do - _ <- sep - as <- sepEndBy p sep - pure (cons' a as) - ) <|> pure (NEL.singleton a) + as <- many $ try (sep *> p) + _ <- optional sep + pure (cons' a as) -- | Parse zero or more separated values, ending with a separator. endBy :: forall a sep. Parser a -> Parser sep -> Parser (List a) diff --git a/test/Main.purs b/test/Main.purs index 0dc6130..9bfdd9f 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -7,6 +7,7 @@ import Effect.Console (log) import Test.CodePoints (testCodePoints) import Test.CodeUnits (testCodeUnits) import Test.BasicSpecs (runTestCases) +import Test.StackSafeCombinators (testStackSafeCombinators) main :: Effect Unit main = do @@ -18,3 +19,6 @@ main = do log "\n\nTesting CodePoint parsing\n" testCodePoints + + log "\n\nTesting stack safety of combinators\n" + testStackSafeCombinators diff --git a/test/StackSafeCombinators.purs b/test/StackSafeCombinators.purs new file mode 100644 index 0000000..8ce5cf1 --- /dev/null +++ b/test/StackSafeCombinators.purs @@ -0,0 +1,19 @@ +module Test.StackSafeCombinators where + +import Prelude + +import Data.Array (replicate) +import Data.Either (isRight) +import Data.String.Common as SC +import Effect (Effect) +import Effect.Class.Console (log) +import StringParser (Parser, char, runParser, sepEndBy) +import Test.Assert (assert) + +canParse :: forall a. Parser a -> String -> Boolean +canParse p input = isRight $ runParser p input + +testStackSafeCombinators :: Effect Unit +testStackSafeCombinators = do + log "Running overflow tests" + assert $ canParse (sepEndBy (char 'a') (char ';')) (SC.joinWith ";" $ replicate 100000 "a")