From 8ed240ec78643e0f3f19089f626ad6e7f2c19635 Mon Sep 17 00:00:00 2001 From: "HE, Tao" Date: Sun, 20 Jan 2019 13:39:05 +0800 Subject: [PATCH] Fix #28, avoid infinite loop when the parser can success with no text in nested `many`. Signed-off-by: HE, Tao --- src/parsec/__init__.py | 14 ++++++++++++++ tests/test_parsec.py | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/parsec/__init__.py b/src/parsec/__init__.py index de1cc44..0bf61a8 100644 --- a/src/parsec/__init__.py +++ b/src/parsec/__init__.py @@ -418,6 +418,20 @@ def times_parser(text, index): return res # failed, throw exception. if cnt >= maxt: # finish. break + # If we don't have any remaining text to start next loop, we need break. + # + # We cannot put the `index < len(text)` in where because some parser can + # success even when we have no any text. We also need to detect if the + # parser consume no text. + # + # See: #28 + if index >= len(text): + if cnt >= mint: + break # we already have decent result to return + else: + r = p(text, index) + if index != r.index: # report error when the parser cannot success with no text + return Value.failure(index, "already meets the end, no enough text") return values return times_parser diff --git a/tests/test_parsec.py b/tests/test_parsec.py index 965e702..5aad593 100644 --- a/tests/test_parsec.py +++ b/tests/test_parsec.py @@ -190,6 +190,16 @@ def test_many(self): self.assertEqual(parser.parse(''), []) self.assertEqual(parser.parse('1'), []) + # from #28 + def test_many_many(self): + parser = many(many(space())) + self.assertEqual(parser.parse(' '), [[' ', ' ', ' ', ' ']]) + + parser = times(spaces(), 4, 10) + self.assertEqual(parser.parse(''), [[], [], [], []]) + self.assertEqual(parser.parse(' '), [[' '], [], [], []]) + self.assertEqual(parser.parse(' '), [[' ', ' '], [], [], []]) + def test_many1(self): parser = many1(letter()) self.assertEqual(parser.parse('x'), ['x'])