mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-07 22:44:27 +08:00
first succeeding precedence tests
This commit is contained in:
@@ -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
|
||||||
|
|||||||
71
jedi/evaluate/precedence.py
Normal file
71
jedi/evaluate/precedence.py
Normal 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)
|
||||||
@@ -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)]
|
|
||||||
13
test/test_evaluate/test_precedence.py
Normal file
13
test/test_evaluate/test_precedence.py
Normal 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
|
||||||
Reference in New Issue
Block a user