first succeeding precedence tests

This commit is contained in:
Dave Halter
2014-01-31 11:12:28 +01:00
parent 62a74a6d2f
commit cd1660dc53
4 changed files with 105 additions and 42 deletions

View File

@@ -82,6 +82,7 @@ from jedi.evaluate.cache import memoize_default
from jedi.evaluate import stdlib from jedi.evaluate import stdlib
from jedi.evaluate import finder from jedi.evaluate import finder
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.evaluate import precedence
class Evaluator(object): class Evaluator(object):
@@ -138,25 +139,11 @@ class Evaluator(object):
It is used to evaluate a two dimensional object, that has calls, arrays and It is used to evaluate a two dimensional object, that has calls, arrays and
operators in it. operators in it.
""" """
def evaluate_list_comprehension(lc, parent=None):
input = lc.input
nested_lc = lc.input.token_list[0]
if isinstance(nested_lc, pr.ListComprehension):
# is nested LC
input = nested_lc.stmt
module = input.get_parent_until()
# create a for loop, which does the same as list comprehensions
loop = pr.ForFlow(module, [input], lc.stmt.start_pos, lc.middle, True)
loop.parent = parent or lc.get_parent_until(pr.IsScope)
if isinstance(nested_lc, pr.ListComprehension):
loop = evaluate_list_comprehension(nested_lc, loop)
return loop
debug.dbg('eval_expression_list: %s', expression_list) debug.dbg('eval_expression_list: %s', expression_list)
result = [] result = []
calls_iterator = iter(expression_list) calls_iterator = iter(expression_list)
if len(expression_list) > 1:
print expression_list
for call in calls_iterator: for call in calls_iterator:
if pr.Array.is_type(call, pr.Array.NOARRAY): if pr.Array.is_type(call, pr.Array.NOARRAY):
r = list(itertools.chain.from_iterable(self.eval_statement(s) r = list(itertools.chain.from_iterable(self.eval_statement(s)
@@ -166,7 +153,7 @@ class Evaluator(object):
result += self.follow_path(call_path, r, call.parent, result += self.follow_path(call_path, r, call.parent,
position=call.start_pos) position=call.start_pos)
elif isinstance(call, pr.ListComprehension): elif isinstance(call, pr.ListComprehension):
loop = evaluate_list_comprehension(call) loop = _evaluate_list_comprehension(call)
# Caveat: parents are being changed, but this doesn't matter, # Caveat: parents are being changed, but this doesn't matter,
# because nothing else uses it. # because nothing else uses it.
call.stmt.parent = loop call.stmt.parent = loop
@@ -374,3 +361,20 @@ def filter_private_variable(scope, call_scope, var_name):
if s != scope.base.base: if s != scope.base.base:
return True return True
return False return False
def _evaluate_list_comprehension(lc, parent=None):
input = lc.input
nested_lc = lc.input.token_list[0]
if isinstance(nested_lc, pr.ListComprehension):
# is nested LC
input = nested_lc.stmt
module = input.get_parent_until()
# create a for loop, which does the same as list comprehensions
loop = pr.ForFlow(module, [input], lc.stmt.start_pos, lc.middle, True)
loop.parent = parent or lc.get_parent_until(pr.IsScope)
if isinstance(nested_lc, pr.ListComprehension):
loop = _evaluate_list_comprehension(nested_lc, loop)
return loop

View File

@@ -0,0 +1,71 @@
"""
Handles operator precedence.
"""
from jedi.parser import representation as pr
class PythonGrammar(object):
"""
Some kind of mirror of http://docs.python.org/3/reference/grammar.html.
"""
class AtStart(tuple):
pass
class MultiPart(str):
def __new__(cls, first, second):
self = str.__new__(cls, first)
self.second = second
factor = AtStart(('+', '-', '~'))
power = '**',
term = '*', '/', '%', '//'
arith_expr = '+', '-'
shift_expr = '<<', '>>'
and_expr = '&',
xor_expr = '^',
expr = '|',
comparison = ('<', '>', '==', '>=', '<=', '!=', 'in',
MultiPart('not', 'in'), 'is', MultiPart('is', 'not'))
not_test = AtStart(('not',))
and_test = 'and',
or_test = 'or',
#test = or_test ['if' or_test 'else' test] | lambdef
#sliceop = ':' [test]
#subscript = test | [test] ':' [test] [sliceop]
order = (factor, power, term, arith_expr, shift_expr, and_expr, xor_expr,
expr, comparison, not_test, and_test, or_test)
class Precedence(object):
def __init__(self, left, operator, right=None):
self.left = left
self.operator = operator
self.right = right
def create_precedence(expression_list, previous=None):
element = next(expression_list, None)
if element is None:
return previous
if isinstance(element, pr.Call):
element = str(element.name)
elif not isinstance(element, str):
if previous is None:
previous = element
return create_precedence(expression_list, previous=previous)
for term in PythonGrammar.order:
if element in term:
right = create_precedence(expression_list)
if right is None:
return previous
else:
return Precedence(previous, element, right)

View File

@@ -1,25 +0,0 @@
"""
Test Jedi's operation understanding. Jedi should understand simple additions,
multiplications, etc.
"""
x = [1, '', 'a', 1.0]
#? int() str() float()
x[12]
#? str()
x[1 + 1]
index = 0 + 1
#? str()
x[index]
def calculate(number):
return number + constant
constant = 1
#? float()
x[calculate(2)]

View File

@@ -0,0 +1,13 @@
from jedi.evaluate import precedence
def test_simple():
p = precedence.create_precedence(iter([1, '+', 2]))
assert p.left == 1
assert p.operator == '+'
assert p.right == 2
def test_invalid():
"""Should just return a simple operation"""
assert precedence.create_precedence(iter([1, '+'])) == 1