mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-09 15:24:46 +08:00
decorators to prevent recursion
This commit is contained in:
37
evaluate.py
37
evaluate.py
@@ -12,6 +12,30 @@ import debug
|
|||||||
import builtin
|
import builtin
|
||||||
|
|
||||||
|
|
||||||
|
def memoize(default=None):
|
||||||
|
"""
|
||||||
|
This is a typical memoization decorator, BUT there is one difference:
|
||||||
|
To prevent recursion it sets defaults.
|
||||||
|
|
||||||
|
Preventing recursion is in this case the much bigger use than speed. I
|
||||||
|
don't think, that there is a big speed difference, but there are many cases
|
||||||
|
where recursion could happen (think about a = b; b = a).
|
||||||
|
"""
|
||||||
|
memo = {}
|
||||||
|
def func(function):
|
||||||
|
def wrapper(*args):
|
||||||
|
print function, args
|
||||||
|
if args in memo:
|
||||||
|
return memo[args]
|
||||||
|
else:
|
||||||
|
memo[args] = default
|
||||||
|
rv = function(*args)
|
||||||
|
memo[args] = rv
|
||||||
|
return rv
|
||||||
|
return wrapper
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
class Exec(object):
|
class Exec(object):
|
||||||
def __init__(self, base):
|
def __init__(self, base):
|
||||||
self.base = base
|
self.base = base
|
||||||
@@ -59,6 +83,7 @@ class Execution(Exec):
|
|||||||
"""
|
"""
|
||||||
cache = {}
|
cache = {}
|
||||||
|
|
||||||
|
@memoize(default=[])
|
||||||
def get_return_types(self):
|
def get_return_types(self):
|
||||||
"""
|
"""
|
||||||
Get the return vars of a function.
|
Get the return vars of a function.
|
||||||
@@ -79,20 +104,9 @@ class Execution(Exec):
|
|||||||
stmts.append(scope)
|
stmts.append(scope)
|
||||||
return stmts
|
return stmts
|
||||||
|
|
||||||
# check cache
|
|
||||||
try:
|
|
||||||
ex = Execution.cache[self.base]
|
|
||||||
debug.dbg('hit function cache', self.base, ex)
|
|
||||||
return ex
|
|
||||||
except KeyError:
|
|
||||||
# cache is not only here as a cache, but also to prevent an
|
|
||||||
# endless recursion.
|
|
||||||
Execution.cache[self.base] = []
|
|
||||||
|
|
||||||
result = remove_executions(self.base, True)
|
result = remove_executions(self.base, True)
|
||||||
debug.dbg('exec stmts=', result, self.base, repr(self))
|
debug.dbg('exec stmts=', result, self.base, repr(self))
|
||||||
|
|
||||||
Execution.cache[self.base] = result
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@@ -185,6 +199,7 @@ def strip_imports(scopes):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@memoize(default=[])
|
||||||
def follow_statement(stmt, scope=None):
|
def follow_statement(stmt, scope=None):
|
||||||
"""
|
"""
|
||||||
:param stmt: contains a statement
|
:param stmt: contains a statement
|
||||||
|
|||||||
61
functions.py
61
functions.py
@@ -1,4 +1,3 @@
|
|||||||
import re
|
|
||||||
import tokenize
|
import tokenize
|
||||||
|
|
||||||
import parsing
|
import parsing
|
||||||
@@ -6,7 +5,7 @@ import evaluate
|
|||||||
import modules
|
import modules
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
__all__ = ['complete', 'set_debug_function']
|
__all__ = ['complete', 'complete_test', 'set_debug_function']
|
||||||
|
|
||||||
|
|
||||||
class ParserError(LookupError):
|
class ParserError(LookupError):
|
||||||
@@ -117,10 +116,62 @@ def complete(source, row, column, file_callback=None):
|
|||||||
:return: list of completion objects
|
:return: list of completion objects
|
||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
row = 84
|
f = FileWithCursor('__main__', source=source, row=row)
|
||||||
column = 17
|
scope = f.parser.user_scope
|
||||||
|
|
||||||
row = 140
|
# print a debug.dbg title
|
||||||
|
debug.dbg('complete_scope', scope)
|
||||||
|
|
||||||
|
try:
|
||||||
|
path = f.get_row_path(column)
|
||||||
|
print path
|
||||||
|
debug.dbg('completion_path', path)
|
||||||
|
except ParserError as e:
|
||||||
|
path = []
|
||||||
|
debug.dbg(e)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
if path and path[0]:
|
||||||
|
# just parse one statement
|
||||||
|
#debug.ignored_modules = ['builtin']
|
||||||
|
r = parsing.PyFuzzyParser(path)
|
||||||
|
#debug.ignored_modules = ['parsing', 'builtin']
|
||||||
|
#print 'p', r.top.get_code().replace('\n', r'\n'), r.top.statements[0]
|
||||||
|
scopes = evaluate.follow_statement(r.top.statements[0], scope)
|
||||||
|
|
||||||
|
#name = path.pop() # use this later
|
||||||
|
compl = []
|
||||||
|
debug.dbg('possible scopes')
|
||||||
|
for s in scopes:
|
||||||
|
compl += s.get_defined_names()
|
||||||
|
|
||||||
|
#else:
|
||||||
|
# compl = evaluate.get_names_for_scope(scope)
|
||||||
|
|
||||||
|
debug.dbg('possible-compl', compl)
|
||||||
|
|
||||||
|
# make a partial comparison, because the other options have to
|
||||||
|
# be returned as well.
|
||||||
|
result = compl
|
||||||
|
#result = [c for c in compl if name in c.names[-1]]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def complete_test(source, row, column, file_callback=None):
|
||||||
|
"""
|
||||||
|
An auto completer for python files.
|
||||||
|
|
||||||
|
:param source: The source code of the current file
|
||||||
|
:type source: string
|
||||||
|
:param row: The row to complete in.
|
||||||
|
:type row: int
|
||||||
|
:param col: The column to complete in.
|
||||||
|
:type col: int
|
||||||
|
:return: list of completion objects
|
||||||
|
:rtype: list
|
||||||
|
"""
|
||||||
|
# !!!!!!! this is the old version and will be deleted soon !!!!!!!
|
||||||
row = 150
|
row = 150
|
||||||
column = 200
|
column = 200
|
||||||
f = FileWithCursor('__main__', source=source, row=row)
|
f = FileWithCursor('__main__', source=source, row=row)
|
||||||
|
|||||||
Reference in New Issue
Block a user