Skip to content

Commit

Permalink
Fix #28, avoid infinite loop when the parser can success with no text…
Browse files Browse the repository at this point in the history
… in nested `many`.

Signed-off-by: HE, Tao <sighingnow@gmail.com>
  • Loading branch information
sighingnow committed Jan 20, 2019
1 parent b1872d2 commit 8ed240e
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/parsec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 10 additions & 0 deletions tests/test_parsec.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'])
Expand Down

0 comments on commit 8ed240e

Please sign in to comment.