diff --git a/evaluate.py b/evaluate.py index b371adb8..bf3261a5 100644 --- a/evaluate.py +++ b/evaluate.py @@ -219,7 +219,8 @@ def get_names_for_scope(scope, star_search=True): start_scope = scope while scope: # class variables/functions are only availabe - if not isinstance(scope, parsing.Class) or scope == start_scope: + if (not isinstance(scope, parsing.Class) or scope == start_scope) \ + and not isinstance(scope, parsing.Flow): compl += scope.get_defined_names() scope = scope.parent @@ -249,8 +250,8 @@ def get_scopes_for_name(scope, name, search_global=False): res_new = [] for r in result: if isinstance(r, parsing.Statement): + # global variables handling if r.is_global(): - res_new += [] for token_name in r.token_list[1:]: if isinstance(token_name, parsing.Name): res_new += get_scopes_for_name(r.parent, @@ -265,32 +266,42 @@ def get_scopes_for_name(scope, name, search_global=False): def filter_name(scopes): # the name is already given in the parent function + + def handle_non_arrays(): + result = [] + par = scope.parent + if isinstance(par, parsing.Flow): + if par.command == 'for': + # take the first statement (for has always only + # one, remember `in`). And follow it. After that, + # get the types which are in the array + arrays = follow_statement(par.inits[0]) + for array in arrays: + for_vars = array.get_index_types() + if len(par.set_vars) > 1: + var_arr = par.set_stmt.get_assignment_calls() + result += assign_tuples(var_arr, for_vars, name) + else: + result += for_vars + else: + debug.warning('Why are you here? %s' % par.command) + elif isinstance(par, parsing.Param) \ + and isinstance(par.parent.parent, parsing.Class) \ + and par.position == 0: + # this is where self gets added + result.append(Instance(par.parent.parent)) + result.append(par) + else: + result.append(par) + return result + result = [] for scope in scopes: if [name] == list(scope.names): if isinstance(scope, ArrayElement): result.append(scope) else: - par = scope.parent - if isinstance(par, parsing.Flow): - if par.command == 'for': - # take the first statement (for has always only - # one, remember `in`). And follow it. After that, - # get the types which are in the array - arrays = follow_statement(par.inits[0]) - # TODO for loops can have tuples as set_vars - for array in arrays: - result += array.get_index_types() - else: - debug.warning('Why are you here? %s' % par.command) - elif isinstance(par, parsing.Param) \ - and isinstance(par.parent.parent, parsing.Class) \ - and par.position == 0: - # this is where self gets added - result.append(Instance(par.parent.parent)) - result.append(par) - else: - result.append(par) + result += handle_non_arrays() debug.dbg('sfn filter', result) return result @@ -319,6 +330,7 @@ def strip_imports(scopes): result.append(s) return result + def assign_tuples(tup, results, seek_name): """ This is a normal assignment checker. In python functions and other things @@ -359,6 +371,7 @@ def assign_tuples(tup, results, seek_name): result += eval_results(i) return result + @memoize(default=[]) def follow_statement(stmt, scope=None, seek_name=None): """ @@ -388,7 +401,7 @@ def follow_call_list(scope, call_list): This can be either `parsing.Array` or `list`. """ if parsing.Array.is_type(call_list, parsing.Array.TUPLE): - # Tuples can stand just alone without any braces. These would be + # Tuples can stand just alone without any braces. These would be # recognized as separate calls, but actually are a tuple. result = follow_call(scope, call_list) else: diff --git a/ftest.py b/ftest.py index 10fef9d8..3c59ec23 100755 --- a/ftest.py +++ b/ftest.py @@ -2,7 +2,7 @@ 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', 'evaluate', 'modules'] functions.modules.module_find_path.insert(0, '.') diff --git a/parsetest.py b/parsetest.py index b2bafe58..6c03d7ec 100644 --- a/parsetest.py +++ b/parsetest.py @@ -154,7 +154,7 @@ def globalfunc(): global globalvar, globalvar2 globalvar = 3 +for abcde, efgh in [(1,"")]: + abcde.real - - -globalvar. +abcde. diff --git a/parsing.py b/parsing.py index a98fbcbf..c33d9893 100644 --- a/parsing.py +++ b/parsing.py @@ -431,6 +431,14 @@ class Flow(Scope): next.parent = self.parent return next +class ForFlow(Flow): + """ + Used for the for loop, because there are two statement parts. + """ + def __init__(self, command, inits, indent, line_nr, set_stmt): + super(ForFlow, self).__init__(command, inits, indent, line_nr, + set_stmt.used_vars) + self.set_stmt = set_stmt class Import(Simple): """ @@ -942,35 +950,6 @@ class PyFuzzyParser(object): names.append(tok) return (names, token_type, tok, start_indent, start_line) - def _parse_value_list(self, pre_used_token=None): - """ - A value list is a comma separated list. This is used for: - >>> for a,b,self.c in enumerate(test) - - TODO there may be multiple "sub" value lists e.g. (a,(b,c)). - """ - value_list = [] - if pre_used_token: - token_type, tok, indent = pre_used_token - n, token_type, tok, start_indent, start_line = \ - self._parsedotname(tok) - if n: - temp = Name(n, start_indent, start_line, self.line_nr) - value_list.append() - - token_type, tok, indent = self.next() - while tok != 'in' and token_type != tokenize.NEWLINE: - n, token_type, tok, start_indent, start_line = \ - self._parsedotname(self.current) - if n: - temp = Name(n, start_indent, start_line, self.line_nr) - value_list.append(temp) - if tok == 'in': - break - - token_type, tok, indent = self.next() - return (value_list, tok) - def _parseimportlist(self): """ The parser for the imports. Unlike the class and function parse @@ -1329,12 +1308,12 @@ class PyFuzzyParser(object): self.freshscope = False #loops elif tok == 'for': - value_list, tok = self._parse_value_list() + set_stmt, tok = self._parse_statement(added_breaks=['in']) if tok == 'in': statement, tok = self._parse_statement() if tok == ':': - f = Flow('for', [statement], indent, - self.line_nr, value_list) + f = ForFlow('for', [statement], indent, + self.line_nr, set_stmt) debug.dbg("new scope: flow for@%s" % (f.line_nr)) self.scope = self.scope.add_statement(f) @@ -1352,7 +1331,7 @@ class PyFuzzyParser(object): if command == 'except' and tok in added_breaks: # the except statement defines a var # this is only true for python 2 - path, token_type, tok, start_indent, start_line2 = \ + path, token_type, tok, start_indent, start_line2 =\ self._parsedotname() n = Name(path, start_indent, start_line2, self.line_nr) diff --git a/test/completion/basic.py b/test/completion/basic.py index 02926ebe..08f6b2ce 100644 --- a/test/completion/basic.py +++ b/test/completion/basic.py @@ -12,7 +12,7 @@ for a1 in 1,"": #? ['upper'] a1.upper -for a3, b3 in (1,""), (1,""): +for a3, b3 in (1,""), (1,""), (1,""): #? ['real'] a3.real #? []