1
0
forked from VimPlug/jedi

follow algorithm started

This commit is contained in:
David Halter
2012-03-20 18:46:33 +01:00
parent 6b8551c917
commit 4bd8d475c2
4 changed files with 200 additions and 60 deletions

View File

@@ -1,4 +1,34 @@
import parsing import parsing
import __builtin__
import itertools
class Arr(object):
"""
- caching one function
- iterating over arrays objects
- test
"""
cache = []
def __init__(self, scope, ):
self.counter = 0
self.types = [] # each an array, like: [[list], [A,B]]
def __iter__(self):
return self
def next(self):
if self.counter < len(Arr.cache):
return Arr.cache[self.counter]
else:
if blub:
Arr.cache.append(1)
self.counter += 1
return Arr.cache[self.counter]
else:
raise StopIteration
def get_names_for_scope(scope): def get_names_for_scope(scope):
""" Get all completions possible for the current scope. """ """ Get all completions possible for the current scope. """
@@ -16,15 +46,69 @@ def get_names_for_scope(scope):
# point: chaining # point: chaining
# execution: -> eval returns default & ? # execution: -> eval returns default & ?
def follow_statement(scope, stmt): def follow_statement(scope, stmt):
arr = stmt.get_assignment_calls() arr = stmt.get_assignment_calls().values[0][0]
return call print arr
path = arr.generate_call_list()
path, path_print = itertools.tee(path)
print '\n\ncalls:'
for c in path_print:
print c
print '\n\nfollow'
current = next(path)
result = []
if isinstance(current, parsing.Array):
if current.arr_type == parsing.Array.EMPTY:
# the normal case - no array type
print 'length', len(current)
elif current.arr_type == parsing.Array.LIST:
result.append(__builtin__.list())
elif current.arr_type == parsing.Array.SET:
result.append(__builtin__.set())
elif current.arr_type == parsing.Array.TUPLE:
result.append(__builtin__.tuple())
elif current.arr_type == parsing.Array.DICT:
result.append(__builtin__.dict())
else:
print current
pass
print result
result = follow_paths(path, result)
print result
exit()
return result
def follow_paths(path, results):
results_new = []
try:
if len(results) > 1:
iter_paths = itertools.tee(path, len(results))
else:
iter_paths = [path]
for i, r in enumerate(results):
results_new += follow_path(iter_paths[i], r)
except StopIteration:
return results
return results_new
def follow_path(path, result):
current = next(path)
#result = []
result = follow_paths(path, result)
return result
def follow_array(scope, array): def follow_array(scope, array):
return yield 1
def follow_path(scope, path): def follow_path_old(scope, path):
""" """
Follow a path of python names. Follow a path of python names.
recursive! recursive!

View File

@@ -178,7 +178,7 @@ def complete(source, row, column, file_callback=None):
column = 17 column = 17
row = 140 row = 140
column = 2 column = 200
f = File(source=source, row=row) f = File(source=source, row=row)
scope = f.parser.user_scope scope = f.parser.user_scope
@@ -197,15 +197,15 @@ def complete(source, row, column, file_callback=None):
dbg(e) dbg(e)
result = [] result = []
if path:
name = path.pop()
if path: if path:
# just parse one statement # just parse one statement
r = parsing.PyFuzzyParser(".".join(path)) r = parsing.PyFuzzyParser(".".join(path))
print 'p', r.top.get_code(), r.top.statements[0] print 'p', r.top.get_code().replace('\n', r'\n'), r.top.statements[0]
evaluate.follow_statement(scope, r.top.statements[0]) evaluate.follow_statement(scope, r.top.statements[0])
exit() exit()
name = path.pop()
if path:
scopes = evaluate.follow_path(scope, tuple(path)) scopes = evaluate.follow_path(scope, tuple(path))
dbg('possible scopes', scopes) dbg('possible scopes', scopes)

View File

@@ -499,11 +499,14 @@ class Statement(Simple):
'like' a lazy execution. 'like' a lazy execution.
""" """
result = Array(Array.EMPTY) result = Array(Array.EMPTY)
top = result
level = 0 level = 0
is_chain = False is_chain = False
close_brackets = False
for tok_temp in self.token_list: print 'tok_list', self.token_list
#print 'tok', tok_temp for i, tok_temp in enumerate(self.token_list):
#print 'tok', tok_temp, result
try: try:
token_type, tok, indent = tok_temp token_type, tok, indent = tok_temp
if level == 0 and \ if level == 0 and \
@@ -519,56 +522,126 @@ class Statement(Simple):
tok = tok_temp tok = tok_temp
brackets = {'(': Array.EMPTY, '[': Array.LIST, '{': Array.SET} brackets = {'(': Array.EMPTY, '[': Array.LIST, '{': Array.SET}
is_call = isinstance(result, Call) is_call = lambda: result.__class__ == Call
is_call_or_close = lambda: is_call() or close_brackets
if isinstance(tok, Name): if isinstance(tok, Name):
call = Call(tok, result)
if is_chain: if is_chain:
call = Call(tok, result)
result = result.set_next_chain_call(call) result = result.set_next_chain_call(call)
is_chain = False is_chain = False
close_brackets = False
else: else:
if close_brackets:
result = result.parent
close_brackets = False
call = Call(tok, result)
result.add_to_current_field(call) result.add_to_current_field(call)
result = call result = call
elif tok in brackets.keys(): elif tok in brackets.keys():
level += 1 level += 1
if is_call_or_close():
result = Array(brackets[tok], result) result = Array(brackets[tok], result)
if is_call:
result = result.parent.add_execution(result) result = result.parent.add_execution(result)
close_brackets = False
else: else:
result = Array(brackets[tok], result)
result.parent.add_to_current_field(result) result.parent.add_to_current_field(result)
elif tok == ':': elif tok == ':':
if is_call: if is_call_or_close():
result = result.parent result = result.parent
close_brackets = False
result.add_dictionary_key() result.add_dictionary_key()
elif tok == '.': elif tok == '.':
if close_brackets:
result = result.parent
close_brackets = False
is_chain = True is_chain = True
elif tok == ',': elif tok == ',':
if is_call: if is_call_or_close():
result = result.parent result = result.parent
close_brackets = False
result.add_field() result.add_field()
# important - it cannot be empty anymore # important - it cannot be empty anymore
if result.arr_type == Array.EMPTY: if result.arr_type == Array.EMPTY:
result.arr_type = Array.TUPLE result.arr_type = Array.TUPLE
elif tok in [')', '}', ']']: elif tok in [')', '}', ']']:
level -= 1 while is_call_or_close():
result = result.parent result = result.parent
close_brackets = False
if tok == '}' and not len(result):
# this is a really special case - empty brackets {} are
# always dictionaries and not sets.
result.arr_type = Array.DICT
level -= 1
#result = result.parent
close_brackets = True
else: else:
# TODO catch numbers and strings -> token_type and make # TODO catch numbers and strings -> token_type and make
# calls out of them # calls out of them
if is_call: if is_call_or_close():
result = result.parent result = result.parent
close_brackets = False
result.add_to_current_field(tok) result.add_to_current_field(tok)
if isinstance(result, Call): print 'tok_end', tok_temp, result, close_brackets
# if the last added object was a name, the result will not be the
# top tree.
result = result.parent
if level != 0: if level != 0:
raise ParserError("Brackets don't match: %s. This is not normal " raise ParserError("Brackets don't match: %s. This is not normal "
"behaviour. Please submit a bug" % level) "behaviour. Please submit a bug" % level)
return result return top
class Array(object): class Call(object):
""" The statement object of functions, to """
def __init__(self, name, parent=None):
self.name = name
# parent is not the oposite of next. The parent of c: a = [b.c] would
# be an array.
self.parent = parent
self.next = None
self.execution = None
def set_next_chain_call(self, call):
""" Adds another part of the statement"""
self.next = call
#print '\n\npar', call.parent, self.parent, type(call), type(self)
call.parent = self.parent
return call
def add_execution(self, call):
"""
An execution is nothing else than brackets, with params in them, which
shows access on the internals of this name.
"""
self.execution = call
# there might be multiple executions, like a()[0], in that case, they
# have the same parent. Otherwise it's not possible to parse proper.
if self.parent.execution == self:
call.parent = self.parent
else:
call.parent = self
return call
def generate_call_list(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():
yield y
if self.next is not None:
for y in self.next.generate_call_list():
yield y
def __repr__(self):
return "<%s: %s of %s>" % \
(self.__class__.__name__, self.name, self.parent)
class Array(Call):
""" """
Describes the different python types for an array, but also empty Describes the different python types for an array, but also empty
statements. In the Python syntax definitions this type is named 'atom'. statements. In the Python syntax definitions this type is named 'atom'.
@@ -586,14 +659,18 @@ class Array(object):
SET = object() SET = object()
def __init__(self, arr_type, parent=None): def __init__(self, arr_type, parent=None):
super(Array, self).__init__(None, parent)
self.arr_type = arr_type self.arr_type = arr_type
self.values = [] self.values = []
self.keys = [] self.keys = []
self.parent = parent
def add_field(self): def add_field(self):
""" """
Just add a new field to the values. Just add a new field to the values.
Each value has a sub-array, because there may be different tokens in
one array.
""" """
self.values.append([]) self.values.append([])
self.keys.append(None) self.keys.append(None)
@@ -624,15 +701,17 @@ class Array(object):
def __iter__(self): def __iter__(self):
if self.arr_type == self.DICT: if self.arr_type == self.DICT:
return self.values.items() return self.values.items().__iter__()
else: else:
return self.values return self.values.__iter__()
def __repr__(self): def __repr__(self):
if self.arr_type == self.EMPTY: if self.arr_type == self.EMPTY:
temp = 'empty' temp = 'empty'
elif self.arr_type == self.TUPLE: elif self.arr_type == self.TUPLE:
temp = 'tuple' temp = 'tuple'
elif self.arr_type == self.LIST:
temp = 'list'
elif self.arr_type == self.DICT: elif self.arr_type == self.DICT:
temp = 'dict' temp = 'dict'
elif self.arr_type == self.SET: elif self.arr_type == self.SET:
@@ -641,33 +720,8 @@ class Array(object):
(self.__class__.__name__, temp, self.parent) (self.__class__.__name__, temp, self.parent)
class Call(object): class NamePart(str):
""" The statement object of functions, to """ pass
def __init__(self, name, parent):
self.name = name
self.parent = parent
self.next = None
self.param_array = None
self.executions = []
def set_next_chain_call(self, call):
""" Adds another part of the statement"""
self.next = call
call.parent = self.parent
return call
def add_execution(self, call):
"""
An execution is nothing else than brackets, with params in them, which
shows access on the internals of this name.
"""
self.executions.append(call)
return call
def __repr__(self):
return "<%s: %s of %s>" % \
(self.__class__.__name__, self.name, self.parent)
class Name(Simple): class Name(Simple):
@@ -679,7 +733,7 @@ class Name(Simple):
""" """
def __init__(self, names, indent, line_nr, line_end): def __init__(self, names, indent, line_nr, line_end):
super(Name, self).__init__(indent, line_nr, line_end) super(Name, self).__init__(indent, line_nr, line_end)
self.names = tuple(names) self.names = tuple(NamePart(n) for n in names)
def get_code(self): def get_code(self):
""" Returns the names in a full string format """ """ Returns the names in a full string format """

View File

@@ -136,5 +136,7 @@ class c1():
c1().c2.\ (c1().c2.\
c c, 1, c3()) [0].pop()
c = "a".join([1,2])