diff --git a/jedi/evaluate/precedence.py b/jedi/evaluate/precedence.py index 88783d3a..aa67a2d2 100644 --- a/jedi/evaluate/precedence.py +++ b/jedi/evaluate/precedence.py @@ -40,14 +40,14 @@ class PythonGrammar(object): #TEST = or_test ['if' or_test 'else' test] | lambdef - #SLICEOP = ':' [test] - #SUBSCRIPT = test | [test] ':' [test] [sliceop] + SLICE = ':', ORDER = (POWER, TERM, ARITH_EXPR, SHIFT_EXPR, AND_EXPR, XOR_EXPR, - EXPR, COMPARISON, AND_TEST, OR_TEST) + EXPR, COMPARISON, AND_TEST, OR_TEST, SLICE) FACTOR_PRIORITY = 0 # highest priority LOWEST_PRIORITY = len(ORDER) - NOT_TEST_PRIORITY = LOWEST_PRIORITY - 2 # priority only lower for `and`/`or` + NOT_TEST_PRIORITY = LOWEST_PRIORITY - 3 # priority only lower for `and`/`or` + SLICE_PRIORITY = LOWEST_PRIORITY - 1 # priority only lower for `and`/`or` class Precedence(object): @@ -89,6 +89,10 @@ def _get_number(iterator, priority=PythonGrammar.LOWEST_PRIORITY): elif el in PythonGrammar.NOT_TEST \ and priority >= PythonGrammar.NOT_TEST_PRIORITY: right = _get_number(iterator, PythonGrammar.NOT_TEST_PRIORITY) + elif el in PythonGrammar.SLICE \ + and priority >= PythonGrammar.SLICE_PRIORITY: + iterator.push_back(el) + return None else: _syntax_error(el) return _get_number(iterator, priority) @@ -98,12 +102,9 @@ def _get_number(iterator, priority=PythonGrammar.LOWEST_PRIORITY): def _check_operator(iterator, priority=PythonGrammar.LOWEST_PRIORITY): - """ - """ try: left = _get_number(iterator, priority) except StopIteration: - _syntax_error(iterator.current, 'SyntaxError operand missing') return None for el in iterator: @@ -143,6 +144,8 @@ def _check_operator(iterator, priority=PythonGrammar.LOWEST_PRIORITY): if operator == '**': check_prio += 1 # to the power of is right-associative right = _check_operator(iterator, check_prio) - if right is not None: + if right is None and not operator in PythonGrammar.SLICE: + _syntax_error(iterator.current, 'SyntaxError operand missing') + else: left = Precedence(left, str(operator), right) return left diff --git a/test/test_evaluate/test_precedence.py b/test/test_evaluate/test_precedence.py index 3fc3ea62..5faaad5c 100644 --- a/test/test_evaluate/test_precedence.py +++ b/test/test_evaluate/test_precedence.py @@ -2,9 +2,12 @@ from jedi.parser import Parser from jedi.evaluate import precedence -def parse_tree(statement_string): +def parse_tree(statement_string, is_slice=False): p = Parser(statement_string, no_docstr=True) stmt = p.module.statements[0] + if is_slice: + # get the part of the execution that is the slice + stmt = stmt.expression_list()[0].execution[0] iterable = iter(stmt.expression_list()) pr = precedence.create_precedence(iterable) if isinstance(pr, precedence.Precedence): @@ -51,3 +54,14 @@ def test_multi_part(): def test_power(): assert parse_tree('2 ** 3 ** 4') == (2, '**', (3, '**', 4)) + + +def test_slice(): + """ + Should be parsed as normal operators. This is not proper Python syntax, + but the warning shouldn't be given in the precedence generation. + """ + assert parse_tree('[0][2+1:3]', is_slice=True) == ((2, '+', 1), ':', 3) + assert parse_tree('[0][:]', is_slice=True) == (None, ':', None) + assert parse_tree('[0][1:]', is_slice=True) == (1, ':', None) + assert parse_tree('[0][:2]', is_slice=True) == (None, ':', 2)