Skip to content

Commit 3464a4b

Browse files
committed
#47 Ensure ParseError is returned for parse TypeError
* also expose ParseError and PARSE_ERRORS in the API
1 parent 477f629 commit 3464a4b

File tree

3 files changed

+48
-24
lines changed

3 files changed

+48
-24
lines changed

boolean/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
from boolean.boolean import Expression
1818
from boolean.boolean import Symbol
19+
from boolean.boolean import ParseError
20+
from boolean.boolean import PARSE_ERRORS
1921

2022
from boolean.boolean import AND
2123
from boolean.boolean import NOT

boolean/boolean.py

+23-24
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@
6060

6161
PARSE_ERRORS = {
6262
PARSE_UNKNOWN_TOKEN: 'Unknown token',
63-
PARSE_UNBALANCED_CLOSING_PARENS: 'Bad closing parenthesis',
63+
PARSE_UNBALANCED_CLOSING_PARENS: 'Unbalanced parenthesis',
6464
PARSE_INVALID_EXPRESSION: 'Invalid expression',
6565
}
6666

6767

6868
class ParseError(Exception):
6969
"""
70-
Raised when the parser or tokemizer encounters a syntax error. Instances of
70+
Raised when the parser or tokenizer encounters a syntax error. Instances of
7171
this class have attributes token_type, token_string, position, error_code to
7272
access the details of the error. str() of the exception instance returns a
7373
formatted message.
@@ -80,21 +80,16 @@ def __init__(self, token_type=None, token_string='', position=-1, error_code=0):
8080
self.error_code = error_code
8181

8282
def __str__(self, *args, **kwargs):
83-
ttype = ''
84-
if self.token_type:
85-
ttype = TOKEN_TYPES.get(self.token_type) or repr(self.token_type)
86-
ttype = ' for token type: %r' % (ttype)
87-
8883
tstr = ''
8984
if self.token_string:
90-
tstr = ' with value: %r' % (self.token_string)
85+
tstr = ' for token: %r' % (self.token_string)
9186

9287
pos = ''
9388
if self.position > 0:
9489
pos = ' at position: %d' % (self.position)
9590
emsg = PARSE_ERRORS.get(self.error_code, 'Unknown parsing error')
9691

97-
return '{emsg){ttype}{tstr}(pos}.'.format(ttype=ttype, tstr=tstr, pos=pos, emsg=emsg)
92+
return '{emsg}{tstr}{pos}.'.format(tstr=tstr, pos=pos, emsg=emsg)
9893

9994

10095
class BooleanAlgebra(object):
@@ -225,32 +220,36 @@ def parse(self, expr, simplify=False):
225220
elif token == TOKEN_RPAR:
226221
while True:
227222
if ast[0] is None:
228-
raise ParseError(token, tokstr, position,
229-
PARSE_UNBALANCED_CLOSING_PARENS)
223+
raise ParseError(token, tokstr, position, PARSE_UNBALANCED_CLOSING_PARENS)
230224
if ast[1] is TOKEN_LPAR:
231225
ast[0].append(ast[2])
232226
ast = ast[0]
233227
break
228+
if isinstance(ast[1], int):
229+
raise ParseError(token, tokstr, position, PARSE_UNBALANCED_CLOSING_PARENS)
234230
subex = ast[1](*ast[2:])
235231
ast[0].append(subex)
236232
ast = ast[0]
237233
else:
238234
raise ParseError(token, tokstr, position, PARSE_UNKNOWN_TOKEN)
239235

240-
while True:
241-
if ast[0] is None:
242-
if ast[1] is None:
243-
244-
if len(ast) != 3:
245-
raise ParseError(error_code=PARSE_INVALID_EXPRESSION)
246-
parsed = ast[2]
236+
try:
237+
while True:
238+
if ast[0] is None:
239+
if ast[1] is None:
240+
241+
if len(ast) != 3:
242+
raise ParseError(error_code=PARSE_INVALID_EXPRESSION)
243+
parsed = ast[2]
244+
else:
245+
parsed = ast[1](*ast[2:])
246+
break
247247
else:
248-
parsed = ast[1](*ast[2:])
249-
break
250-
else:
251-
subex = ast[1](*ast[2:])
252-
ast[0].append(subex)
253-
ast = ast[0]
248+
subex = ast[1](*ast[2:])
249+
ast[0].append(subex)
250+
ast = ast[0]
251+
except TypeError:
252+
raise ParseError(error_code=PARSE_INVALID_EXPRESSION)
254253

255254
if simplify:
256255
return parsed.simplify()

boolean/test_boolean.py

+23
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020

2121
from boolean import BooleanAlgebra
22+
from boolean import ParseError
2223
from boolean import Symbol
2324
from boolean import TOKEN_NOT
2425
from boolean import TOKEN_AND
@@ -265,6 +266,28 @@ def build_symbol(current_dotted):
265266
)
266267
self.assertEqual(expected, expr)
267268

269+
def test_parse_raise_ParseError(self):
270+
algebra = BooleanAlgebra()
271+
invalid_expressions = [
272+
'l-a AND none',
273+
'(l-a + AND l-b',
274+
'(l-a + AND l-b)',
275+
'(l-a AND l-b',
276+
'(l-a + AND l-b))',
277+
'(l-a AND l-b))',
278+
'l-a AND',
279+
'OR l-a',
280+
'+ l-a',
281+
]
282+
283+
for expr in invalid_expressions:
284+
print(expr)
285+
try:
286+
algebra.parse(expr)
287+
self.fail("Exception should be raised when parsing '%s'" % expr)
288+
except ParseError:
289+
pass
290+
268291

269292
class BaseElementTestCase(unittest.TestCase):
270293

0 commit comments

Comments
 (0)