decorators to prevent recursion

This commit is contained in:
David Halter
2012-04-07 03:31:52 +02:00
parent 95835250d7
commit 1a7c09e002
2 changed files with 82 additions and 16 deletions

View File

@@ -12,6 +12,30 @@ import debug
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):
def __init__(self, base):
self.base = base
@@ -59,6 +83,7 @@ class Execution(Exec):
"""
cache = {}
@memoize(default=[])
def get_return_types(self):
"""
Get the return vars of a function.
@@ -79,20 +104,9 @@ class Execution(Exec):
stmts.append(scope)
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)
debug.dbg('exec stmts=', result, self.base, repr(self))
Execution.cache[self.base] = result
return result
def __repr__(self):
@@ -185,6 +199,7 @@ def strip_imports(scopes):
return result
@memoize(default=[])
def follow_statement(stmt, scope=None):
"""
:param stmt: contains a statement

View File

@@ -1,4 +1,3 @@
import re
import tokenize
import parsing
@@ -6,7 +5,7 @@ import evaluate
import modules
import debug
__all__ = ['complete', 'set_debug_function']
__all__ = ['complete', 'complete_test', 'set_debug_function']
class ParserError(LookupError):
@@ -117,10 +116,62 @@ def complete(source, row, column, file_callback=None):
:return: list of completion objects
:rtype: list
"""
row = 84
column = 17
f = FileWithCursor('__main__', source=source, row=row)
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
column = 200
f = FileWithCursor('__main__', source=source, row=row)