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'])