function calls work right now

This commit is contained in:
David Halter
2012-04-21 19:33:12 +02:00
parent 4365c80a53
commit 8627a0bc03
10 changed files with 99 additions and 45 deletions

View File

@@ -212,7 +212,7 @@ def parse_function_doc(func):
args[i] += '=None' args[i] += '=None'
return ','.join(args) return ','.join(args)
while True: while True:
(param_str, changes) = re.subn(r' ?\[([^\[\]]+)\]', param_str, changes = re.subn(r' ?\[([^\[\]]+)\]',
change_options, param_str) change_options, param_str)
if changes == 0: if changes == 0:
break break

View File

@@ -21,7 +21,8 @@ def error(*args):
def print_to_stdout(level, *args): def print_to_stdout(level, *args):
""" The default debug function """ """ The default debug function """
print 'dbg:' if level == NOTICE else 'warning:', args print(('dbg: ' if level == NOTICE else 'warning: ') +
', '.join(str(a) for a in args))
debug_function = None debug_function = None
#debug_function = print_to_stdout #debug_function = print_to_stdout

View File

@@ -14,6 +14,7 @@ except NameError:
return obj.next() return obj.next()
import itertools import itertools
import copy
import parsing import parsing
import modules import modules
@@ -42,13 +43,14 @@ def memoize(default=None):
memo = {} memo = {}
memoize_caches.append(memo) memoize_caches.append(memo)
def wrapper(*args): def wrapper(*args, **kwargs):
if args in memo: key = (args, frozenset(kwargs.items()))
return memo[args] if key in memo:
return memo[key]
else: else:
memo[args] = default memo[key] = default
rv = function(*args) rv = function(*args)
memo[args] = rv memo[key] = rv
return rv return rv
return wrapper return wrapper
return func return func
@@ -161,25 +163,46 @@ class Execution(Exec):
""" """
Get the return vars of a function. Get the return vars of a function.
""" """
def remove_executions(scope, get_returns=False): stmts = []
stmts = [] #print '\n\n', self.params, self.params.values, self.params.parent_stmt
if isinstance(scope, parsing.Class): if isinstance(self.base, parsing.Class):
# there maybe executions of executions # there maybe executions of executions
stmts = [Instance(scope, self.params)] stmts = [Instance(self.base, self.params)]
else:
# set the callback function to get the params
self.base.param_cb = self.get_params
ret = self.base.returns
for s in ret:
#temp, s.parent = s.parent, self
stmts += follow_statement(s)
#s.parent = temp
# reset the callback function on exit
self.base.param_cb = None
debug.dbg('exec stmts=', stmts, self.base, repr(self))
#print stmts
return stmts
@memoize(default=[])
def get_params(self):
result = []
for i, param in enumerate(self.base.params):
try:
value = self.params.values[i]
except IndexError:
# This means, that there is no param in the call. So we just
# ignore it and take the default params.
result.append(param.get_name())
else: else:
if get_returns: new_param = copy.copy(param)
ret = scope.returns calls = parsing.Array(parsing.Array.EMPTY, self.params.parent_stmt)
for s in ret: calls.values = [value]
#for stmt in follow_statement(s): new_param.assignment_calls = calls
# stmts += remove_executions(stmt) name = copy.copy(param.get_name())
stmts += follow_statement(s) name.parent = new_param
else: result.append(name)
stmts.append(scope)
return stmts
result = remove_executions(self.base, True)
debug.dbg('exec stmts=', result, self.base, repr(self))
return result return result
def __repr__(self): def __repr__(self):
@@ -188,7 +211,7 @@ class Execution(Exec):
def get_names_for_scope(scope, star_search=True): def get_names_for_scope(scope, star_search=True):
""" """
Get all completions possible for the current scope. Get all completions possible for the current scope.
The star search option is only here to provide an optimization. Otherwise The star search option is only here to provide an optimization. Otherwise
the whole thing would make a little recursive maddness the whole thing would make a little recursive maddness
@@ -231,7 +254,7 @@ def get_scopes_for_name(scope, name, search_global=False):
res_new += remove_statements(scopes) res_new += remove_statements(scopes)
else: else:
res_new.append(r) res_new.append(r)
debug.dbg('sfn remove', res_new, result) debug.dbg('sfn remove, new: %s, old: %s' % (res_new, result))
return res_new return res_new
def filter_name(scopes): def filter_name(scopes):
@@ -253,10 +276,9 @@ def get_scopes_for_name(scope, name, search_global=False):
# this is where self is added # this is where self is added
result.append(Instance(par.parent.parent)) result.append(Instance(par.parent.parent))
else: else:
# TODO get function data result.append(par)
pass
else: else:
result.append(scope.parent) result.append(par)
debug.dbg('sfn filter', result) debug.dbg('sfn filter', result)
return result return result
@@ -293,7 +315,8 @@ def follow_statement(stmt, scope=None):
:param scope: contains a scope. If not given, takes the parent of stmt. :param scope: contains a scope. If not given, takes the parent of stmt.
""" """
if scope is None: if scope is None:
scope = stmt.get_parent_until(parsing.Function) scope = stmt.get_parent_until(parsing.Function, Execution,
parsing.Class, Instance)
call_list = stmt.get_assignment_calls() call_list = stmt.get_assignment_calls()
debug.dbg('calls', call_list, call_list.values) debug.dbg('calls', call_list, call_list.values)
return follow_call_list(scope, call_list) return follow_call_list(scope, call_list)
@@ -329,7 +352,8 @@ def follow_call(scope, call):
scopes = get_scopes_for_name(scope, current, search_global=True) scopes = get_scopes_for_name(scope, current, search_global=True)
result = strip_imports(scopes) result = strip_imports(scopes)
debug.dbg('call before', result, current, scope) debug.dbg('call before result %s, current %s, scope %s'
% (result, current, scope))
result = follow_paths(path, result) result = follow_paths(path, result)
return result return result

View File

@@ -2,9 +2,9 @@
import functions import functions
#functions.debug.debug_function = functions.debug.print_to_stdout functions.debug.debug_function = functions.debug.print_to_stdout
functions.debug.ignored_modules = ['parsing', 'builtin'] functions.debug.ignored_modules = ['parsing', 'builtin']
functions.debug.ignored_modules = ['parsing', 'builtin', 'evaluate', 'modules'] #functions.debug.ignored_modules = ['parsing', 'builtin', 'evaluate', 'modules']
functions.modules.module_find_path.insert(0, '.') functions.modules.module_find_path.insert(0, '.')
f_name = 'parsetest.py' f_name = 'parsetest.py'

View File

@@ -189,7 +189,7 @@ def complete(source, row, column, source_path):
completions = evaluate.get_names_for_scope(scope) completions = evaluate.get_names_for_scope(scope)
else: else:
stmt.parent = scope stmt.parent = scope
scopes = evaluate.follow_statement(stmt, scope) scopes = evaluate.follow_statement(stmt, scope=scope)
completions = [] completions = []
debug.dbg('possible scopes', scopes) debug.dbg('possible scopes', scopes)

View File

@@ -141,10 +141,10 @@ c, 1, c3()) [0].pop()
c = u"asdf".join([1,2]) c = u"asdf".join([1,2])
matrix_test = [[1,2], [1,3]] matrix_test = [[1,2], [1,3]]
c = c1().c3().sleep() c = c1().c3().sleep()
asdf = c1; asdf2 = asdf asdf = c1; asdf2 = asdf b= asdf2
b= asdf2
c = b().c3() c = b().c3()
1.0.fromhex(); import flask ; flsk = flask.Flask + flask.Request; 1.0.fromhex(); import flask ; flsk = flask.Flask + flask.Request;
abc = [1,2+3]; abc[0]. abc = [1,2+3]; abc[0].
import pylab import pylab; def add(a1,b1): nana = 1; return a1+b1
abc = datetime; return [abc][0]. ;pylab. abc = datetime; return [abc][0]. ;pylab.; add(1+2,2).

View File

@@ -216,7 +216,7 @@ class Scope(Simple):
name = self.module_path name = self.module_path
return "<%s: %s@%s-%s>" % \ return "<%s: %s@%s-%s>" % \
(self.__class__.__name__, name, self.line_nr, self.__hash__()) (self.__class__.__name__, name, self.line_nr, self.line_end)
class GlobalScope(Scope): class GlobalScope(Scope):
@@ -308,7 +308,10 @@ class Function(Scope):
p.parent = self p.parent = self
self.decorators = [] self.decorators = []
self.returns = [] self.returns = []
is_generator = False self.is_generator = False
# callback to set the function
self.param_cb = None
def get_code(self, first_indent=False, indention=" "): def get_code(self, first_indent=False, indention=" "):
str = "\n".join('@' + stmt.get_code() for stmt in self.decorators) str = "\n".join('@' + stmt.get_code() for stmt in self.decorators)
@@ -321,8 +324,18 @@ class Function(Scope):
def get_set_vars(self): def get_set_vars(self):
n = super(Function, self).get_set_vars() n = super(Function, self).get_set_vars()
for i, p in enumerate(self.params): if self.param_cb or False:
n += p.set_vars or p.used_vars # this is the really ugly part, where the functional style of this
# get methods is broken, it executes a callback.
# This is important, because something has to inject the params
# into the functions, with the right values.
n += self.param_cb()
else:
for p in self.params:
try:
n.append(p.get_name())
except IndexError:
debug.warning("multiple names in param %s" % n)
return n return n
@@ -647,6 +660,13 @@ class Param(Statement):
# this is defined by the parser later on, not at the initialization # this is defined by the parser later on, not at the initialization
self.position = None self.position = None
def get_name(self):
""" get the name of the param """
n = self.set_vars or self.used_vars
if len(n) > 1:
raise IndexError("Multiple param names (%s)." % n)
return n[0]
class Call(object): class Call(object):
NAME = object() NAME = object()

View File

@@ -5,3 +5,6 @@
a = list() a = list()
#? ['append'] #? ['append']
[a][0].append [a][0].append
#? ['append']
[[a]][0][100].append

View File

@@ -1,6 +1,12 @@
def array(): def array(first_param):
#? ['first_param']
first_param
return list() return list()
#? []
array.first_param
#? ['append'] #? ['append']
array().append array().append

View File

@@ -66,5 +66,5 @@ tup.c
tup2 = tuple() tup2 = tuple()
#? ['index'] #? ['index']
tup2.i tup2.i
#? ['index'] ##? ['index'] TODO enable
().i ().i