Skip to content

Commit

Permalink
Better error messages in ChoiceDict.
Browse files Browse the repository at this point in the history
  • Loading branch information
eerimoq committed Jul 26, 2018
1 parent e403445 commit f60d0ca
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 15 deletions.
28 changes: 28 additions & 0 deletions tests/test_textparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,34 @@ def test_grammar_choice_dict_mismatch(self):

self.assertEqual(cm.exception.offset, 3)

def test_grammar_choice_dict_init(self):
datas = [
(
('WORD', 'WORD'),
"First token kind must be unique, but WORD isn't."
),
(
('WORD', Sequence('WORD')),
"First token kind must be unique, but WORD isn't."
),
(
(Sequence(Sequence('WORD')), ),
"First sequence member must be a string, not "
"<class 'textparser.Sequence'>."
),
(
(Choice('WORD'), ),
"Supported member types are Sequence and str, not "
"<class 'textparser.Choice'>."
)
]

for grammar, message in datas:
with self.assertRaises(textparser.Error) as cm:
ChoiceDict(*grammar)

self.assertEqual(str(cm.exception), message)

def test_grammar_delimited_list(self):
grammar = Grammar(DelimitedList('WORD'))

Expand Down
42 changes: 27 additions & 15 deletions textparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
__version__ = '0.11.0'


class _Tokens(object):
class Tokens(object):

def __init__(self, tokens):
if len(tokens) == 0 or tokens[-1].kind != '__EOF__':
Expand Down Expand Up @@ -167,6 +167,9 @@ def match(self, tokens):
class ChoiceDict(Pattern):
"""Matches any of given patterns.
The first token kind of all members must be unique, otherwise and
Error exception is raised.
"""

def __init__(self, *members):
Expand All @@ -175,21 +178,28 @@ def __init__(self, *members):

for member in members:
if isinstance(member, _String):
if member.kind in self._members_map:
raise Error
self._add_member(member.kind, member)
elif isinstance(member, Sequence):
first_member = member.members[0]

self._members_map[member.kind] = member
else:
if not isinstance(member, Sequence):
raise Error
if not isinstance(first_member, _String):
raise Error(
'First sequence member must be a string, not {}.'.format(
type(first_member)))

if not isinstance(member.members[0], _String):
raise Error
self._add_member(first_member.kind, member)
else:
raise Error(
'Supported member types are Sequence and str, not {}.'.format(
type(member)))

if member.members[0].kind in self._members_map:
raise Error
def _add_member(self, kind, member):
if kind in self._members_map:
raise Error(
"First token kind must be unique, but {} isn't.".format(
kind))

self._members_map[member.members[0].kind] = member
self._members_map[kind] = member

def match(self, tokens):
kind = tokens.peek().kind
Expand All @@ -201,7 +211,8 @@ def match(self, tokens):


class Repeated(Pattern):
"""Matches a pattern zero or more times.
"""Matches given pattern `element` at least `minimum_length` times and
returns the matches as a list.
"""

Expand Down Expand Up @@ -240,7 +251,8 @@ def match(self, tokens):


class RepeatedDict(Repeated):
"""Matches a pattern zero or more times.
"""Matches given pattern `element` at lead `minimum_length` times and
returns the matches as a dictionary.
"""

Expand Down Expand Up @@ -419,7 +431,7 @@ def __init__(self, grammar):
self._root = grammar

def parse(self, tokens):
tokens = _Tokens(tokens)
tokens = Tokens(tokens)
parsed = self._root.match(tokens)

if parsed is not None and tokens.peek().kind == '__EOF__':
Expand Down

0 comments on commit f60d0ca

Please sign in to comment.