dynamic array additions are working with list.append

This commit is contained in:
David Halter
2012-08-09 14:21:51 +02:00
parent e4b911b943
commit c6f76a15ff
7 changed files with 129 additions and 5 deletions

View File

@@ -1,6 +1,8 @@
"""
For dynamic completion.
"""
import copy
import parsing
import evaluate
@@ -79,3 +81,65 @@ def search_params(param):
func.listeners.remove(listener)
return result
@evaluate.memoize_default([])
def check_array_additions(array, is_list=True):
"""
Checks if a `parsing.Array` has "add" statements:
>>> a = [""]
>>> a.append(1)
"""
def scan_array(arr, search_name):
""" Returns the function Calls that match func_name """
result = []
for sub in arr:
for s in sub:
if isinstance(s, parsing.Array):
result += scan_array(s, search_name)
elif isinstance(s, parsing.Call):
n = s.name
if isinstance(n, parsing.Name) and search_name in n.names:
result.append(s)
return result
def check_calls(calls, add_name):
result = []
for c in calls:
call_path = list(c.generate_call_path())
separate_index = call_path.index(add_name)
if not len(call_path) > separate_index + 1:
# this means that there is no execution -> [].append
continue
backtrack_path = iter(call_path[:separate_index])
position = c.parent_stmt.start_pos
scope = c.parent_stmt.parent
print 'd', call_path
e = evaluate.follow_call_path(backtrack_path, scope, position)
print 'e', e
if not array in e:
# the `append`, etc. belong to other arrays
continue
if add_name in ['append', 'add']:
result += evaluate.follow_call_list(call_path[separate_index + 1])
elif add_name in ['extend', 'update']:
result += evaluate.follow_call_list(call_path[separate_index + 1])
return result
stmt = array._array.parent_stmt
current_module = stmt.get_parent_until()
search_names = ['append', 'extend', 'insert'] if is_list else \
['add', 'update']
possible_stmts = []
result = []
for n in search_names:
try:
possible_stmts += current_module.used_names[n]
except KeyError:
continue
for stmt in possible_stmts:
result += check_calls(scan_array(stmt.get_assignment_calls(), n), n)
return result

View File

@@ -1171,9 +1171,14 @@ def follow_call_list(call_list):
def follow_call(call):
""" Follow a call is following a function, variable, string, etc. """
scope = call.parent_stmt.parent
path = call.generate_call_list()
path = call.generate_call_path()
position = call.parent_stmt.start_pos
return follow_call_path(path, scope, position)
def follow_call_path(path, scope, position):
""" Follows a path generated by `parsing.Call.generate_call_path()` """
current = next(path)
if isinstance(current, parsing.Array):
@@ -1239,7 +1244,9 @@ def follow_path(path, scope, position=None):
if isinstance(current, parsing.Array):
# This must be an execution, either () or [].
if current.type == parsing.Array.LIST:
result = scope.get_index_types(current)
result = list(scope.get_index_types(current))
if isinstance(scope, Array):
result += dynamic.check_array_additions(scope)
elif current.type not in [parsing.Array.DICT]:
# Scope must be a class or func - make an instance or execution.
debug.dbg('exe', scope)

View File

@@ -1,6 +1,7 @@
import re
import parsing
import dynamic # must be before evaluate, because it needs to be loaded first.
import evaluate
import modules
import debug

View File

@@ -137,6 +137,12 @@ class frozenset():
def copy(self):
return self
class tuple():
def index(self):
return 1
def count(self):
return 1
#--------------------------------------------------------
# basic types

View File

@@ -657,6 +657,7 @@ class Statement(Simple):
c_type = Call.NUMBER
if is_chain:
#print 'chain', self, tok, result
call = Call(tok, c_type, parent=result)
result = result.set_next_chain_call(call)
is_chain = False
@@ -807,17 +808,17 @@ class Call(object):
call.parent = self
return call
def generate_call_list(self):
def generate_call_path(self):
try:
for name_part in self.name.names:
yield name_part
except AttributeError:
yield self
if self.execution is not None:
for y in self.execution.generate_call_list():
for y in self.execution.generate_call_path():
yield y
if self.next is not None:
for y in self.next.generate_call_list():
for y in self.next.generate_call_path():
yield y
def __repr__(self):

View File

@@ -162,6 +162,13 @@ dic2 = {'asdf': 3, 'b': 'str'}
#? int()
dic2[index]
# -----------------
# chaining
# -----------------
#? int()
[tuple()].index()
# -----------------
# __getitem__
# -----------------

View File

@@ -74,8 +74,46 @@ class A():
def __init__(self, a):
#? int()
a
self.a = a
def test(self, a):
#? float()
a
def test2(self):
##? int()
self.a
A(3).test(2.0)
A(3).test2()
# -----------------
# list.append/insert
# -----------------
arr = []
for a in [1,2]:
arr.append(a);
arr.append # should not cause an exception
#? int()
arr[10]
arr = [tuple()]
for a in [1,2]:
arr.append(a);
#? int() tuple()
arr[10]
#? int()
arr[10].index()
arr = [""]
arr.insert(0, 1.0)
#? float() str()
arr[10]
# -----------------
# set.append
# -----------------