mirror of
https://github.com/davidhalter/jedi.git
synced 2026-02-15 02:01:58 +08:00
reversed and for loops now produce strings in the correct order.
This commit is contained in:
@@ -147,12 +147,16 @@ class Evaluator(object):
|
|||||||
name = str(stmt.get_defined_names()[0])
|
name = str(stmt.get_defined_names()[0])
|
||||||
parent = self.wrap(stmt.get_parent_scope())
|
parent = self.wrap(stmt.get_parent_scope())
|
||||||
left = self.find_types(parent, name, stmt.start_pos, search_global=True)
|
left = self.find_types(parent, name, stmt.start_pos, search_global=True)
|
||||||
if isinstance(stmt.get_parent_until(tree.ForStmt), tree.ForStmt):
|
|
||||||
|
for_stmt = stmt.get_parent_until(tree.ForStmt)
|
||||||
|
if isinstance(for_stmt, tree.ForStmt):
|
||||||
# Iterate through result and add the values, that's possible
|
# Iterate through result and add the values, that's possible
|
||||||
# only in for loops without clutter, because they are
|
# only in for loops without clutter, because they are
|
||||||
# predictable.
|
# predictable.
|
||||||
for r in types:
|
for_iterable = self.eval_element(for_stmt.children[3])
|
||||||
left = precedence.calculate(self, left, operator, set([r]))
|
ordered = iterable.ordered_elements_of_iterable(self, for_iterable, types)
|
||||||
|
for index_types in ordered:
|
||||||
|
left = precedence.calculate(self, left, operator, index_types)
|
||||||
types = left
|
types = left
|
||||||
else:
|
else:
|
||||||
types = precedence.calculate(self, left, operator, types)
|
types = precedence.calculate(self, left, operator, types)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ from jedi.evaluate import compiled
|
|||||||
from jedi.evaluate import helpers
|
from jedi.evaluate import helpers
|
||||||
from jedi.evaluate.cache import CachedMetaClass, memoize_default
|
from jedi.evaluate.cache import CachedMetaClass, memoize_default
|
||||||
from jedi.evaluate import analysis
|
from jedi.evaluate import analysis
|
||||||
|
from jedi.evaluate.precedence import literals_to_types
|
||||||
|
|
||||||
|
|
||||||
class IterableWrapper(tree.Base):
|
class IterableWrapper(tree.Base):
|
||||||
@@ -390,6 +391,28 @@ class MergedArray(_FakeArray):
|
|||||||
return sum(len(a) for a in self._arrays)
|
return sum(len(a) for a in self._arrays)
|
||||||
|
|
||||||
|
|
||||||
|
def ordered_elements_of_iterable(evaluator, iterable_type, all_values):
|
||||||
|
"""
|
||||||
|
This function returns the ordered types of an iterable. If the input is not
|
||||||
|
an Array, we just return all types as the first and only item of the
|
||||||
|
output list.
|
||||||
|
"""
|
||||||
|
ordered = []
|
||||||
|
# Unpack the iterator values
|
||||||
|
for sequence in iterable_type:
|
||||||
|
if not isinstance(sequence, Array):
|
||||||
|
ordered = [literals_to_types(evaluator, all_values)]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# Try
|
||||||
|
for i, types in enumerate(sequence.per_index_values()):
|
||||||
|
try:
|
||||||
|
ordered[i] |= types
|
||||||
|
except IndexError:
|
||||||
|
ordered.append(set(types))
|
||||||
|
return ordered
|
||||||
|
|
||||||
|
|
||||||
def get_iterator_types(evaluator, element):
|
def get_iterator_types(evaluator, element):
|
||||||
"""Returns the types of any iterator (arrays, yields, __iter__, etc)."""
|
"""Returns the types of any iterator (arrays, yields, __iter__, etc)."""
|
||||||
iterators = []
|
iterators = []
|
||||||
|
|||||||
@@ -23,17 +23,19 @@ COMPARISON_OPERATORS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _literals_to_types(evaluator, result):
|
def literals_to_types(evaluator, result):
|
||||||
# Changes literals ('a', 1, 1.0, etc) to its type instances (str(),
|
# Changes literals ('a', 1, 1.0, etc) to its type instances (str(),
|
||||||
# int(), float(), etc).
|
# int(), float(), etc).
|
||||||
result = list(result)
|
new_result = set()
|
||||||
for i, r in enumerate(result):
|
for typ in result:
|
||||||
if is_literal(r):
|
if is_literal(typ):
|
||||||
# Literals are only valid as long as the operations are
|
# Literals are only valid as long as the operations are
|
||||||
# correct. Otherwise add a value-free instance.
|
# correct. Otherwise add a value-free instance.
|
||||||
cls = builtin.get_by_name(r.name.get_code())
|
cls = builtin.get_by_name(typ.name.get_code())
|
||||||
result[i] = list(evaluator.execute(cls))[0]
|
new_result.add(list(evaluator.execute(cls))[0])
|
||||||
return set(result)
|
else:
|
||||||
|
new_result.add(typ)
|
||||||
|
return new_result
|
||||||
|
|
||||||
|
|
||||||
def calculate_children(evaluator, children):
|
def calculate_children(evaluator, children):
|
||||||
@@ -69,13 +71,13 @@ def calculate(evaluator, left_result, operator, right_result):
|
|||||||
if not left_result or not right_result:
|
if not left_result or not right_result:
|
||||||
# illegal slices e.g. cause left/right_result to be None
|
# illegal slices e.g. cause left/right_result to be None
|
||||||
result = (left_result or set()) | (right_result or set())
|
result = (left_result or set()) | (right_result or set())
|
||||||
result = _literals_to_types(evaluator, result)
|
result = literals_to_types(evaluator, result)
|
||||||
else:
|
else:
|
||||||
# I don't think there's a reasonable chance that a string
|
# I don't think there's a reasonable chance that a string
|
||||||
# operation is still correct, once we pass something like six
|
# operation is still correct, once we pass something like six
|
||||||
# objects.
|
# objects.
|
||||||
if len(left_result) * len(right_result) > 6:
|
if len(left_result) * len(right_result) > 6:
|
||||||
result = _literals_to_types(evaluator, left_result | right_result)
|
result = literals_to_types(evaluator, left_result | right_result)
|
||||||
else:
|
else:
|
||||||
for left in left_result:
|
for left in left_result:
|
||||||
for right in right_result:
|
for right in right_result:
|
||||||
|
|||||||
@@ -155,9 +155,14 @@ def get_iterable_content(evaluator, arguments, argument_index):
|
|||||||
|
|
||||||
@argument_clinic('sequence, /', want_obj=True, want_arguments=True)
|
@argument_clinic('sequence, /', want_obj=True, want_arguments=True)
|
||||||
def builtins_reversed(evaluator, sequences, obj, arguments):
|
def builtins_reversed(evaluator, sequences, obj, arguments):
|
||||||
# Unpack the iterator values
|
# While we could do without this variable (just by using sequences), we
|
||||||
objects = get_iterable_content(evaluator, arguments, 0)
|
# want static analysis to work well. Therefore we need to generated the
|
||||||
rev = [iterable.AlreadyEvaluated([o]) for o in reversed(list(objects))]
|
# values again.
|
||||||
|
all_sequence_types = get_iterable_content(evaluator, arguments, 0)
|
||||||
|
|
||||||
|
ordered = iterable.ordered_elements_of_iterable(evaluator, sequences, all_sequence_types)
|
||||||
|
|
||||||
|
rev = [iterable.AlreadyEvaluated(o) for o in reversed(ordered)]
|
||||||
# Repack iterator values and then run it the normal way. This is
|
# Repack iterator values and then run it the normal way. This is
|
||||||
# necessary, because `reversed` is a function and autocompletion
|
# necessary, because `reversed` is a function and autocompletion
|
||||||
# would fail in certain cases like `reversed(x).__iter__` if we
|
# would fail in certain cases like `reversed(x).__iter__` if we
|
||||||
|
|||||||
Reference in New Issue
Block a user