diff --git a/evaluate.py b/evaluate.py index df0ff623..9f264b83 100644 --- a/evaluate.py +++ b/evaluate.py @@ -161,19 +161,15 @@ class Array(object): self._array = array def get_index_types(self, index=None): - #print self._array.values, index.values values = self._array.values - #print 'ui', index.values, index.values[0][0].type if index is not None: - # This is indexing only one element, with a fixed index number - iv = index.values - if len(iv) == 1 and len(iv[0]) == 1 \ - and iv[0][0].type == parsing.Call.NUMBER \ - and self._array.type != parsing.Array.DICT: - try: - values = [self._array[int(iv[0][0].name)]] - except: - pass + # This is indexing only one element, with a fixed index number, + # otherwise it just ignores the index (e.g. [1+1]) + try: + index_nr = int(index.get_only_subelement().name) + values = [self._array[index_nr]] + except: + pass scope = self._array.parent_stmt.parent return follow_call_list(scope, values) @@ -317,7 +313,7 @@ def strip_imports(scopes): result.append(s) return result -def assign_tuples(scope, tuples, results, seek_name): +def assign_tuples(tup, results, seek_name): """ This is a normal assignment checker. In python functions and other things can return tuples: @@ -326,6 +322,8 @@ def assign_tuples(scope, tuples, results, seek_name): Here, if seek_name is "a", the number type will be returned. The first part (before `=`) is the param tuples, the second one result. + + :type tup: parsing.Array """ def eval_results(index): types = [] @@ -334,23 +332,31 @@ def assign_tuples(scope, tuples, results, seek_name): return types result = [] - for i, t in enumerate(tuples): - # used in an assignment, there is just one call and no other things, - # therefor we can just assume, that the first part is important. - t = t[0] - # check the left part, if it's still tuples in it or a Call - if isinstance(t, parsing.Array): - # these are "sub" tuples - print 'arr', t - result += assign_tuples(scope, t, eval_results(i), seek_name) - else: - if t.name.names[-1] == seek_name: - result += eval_results(i) - print 't', t, result + if tup.type == parsing.Array.NOARRAY: + # here we have unnessecary braces, which we just remove + arr = tup.get_only_subelement() + result = assign_tuples(arr, results, seek_name) + else: + for i, t in enumerate(tup): + # used in assignments. there is just one call and no other things, + # therefor we can just assume, that the first part is important. + if len(t) != 1: + raise AttributeError('Array length should be 1') + t = t[0] + + # check the left part, if it's still tuples in it or a Call + if isinstance(t, parsing.Array): + # these are "sub" tuples + print 'arr', t + result += assign_tuples(t, eval_results(i), seek_name) + print 'arr2', result else: - print 'name not found' - #print follow_call_list(scope, result[i]) - print seek_name, tuples, results + if t.name.names[-1] == seek_name: + result += eval_results(i) + print 't', t, result + else: + print 'name not found', t.name + print seek_name, tup, results return result @memoize(default=[]) @@ -373,7 +379,7 @@ def follow_statement(stmt, scope=None, seek_name=None): new_result = [] for op, set_vars in stmt.assignment_details: print '\ntup' - new_result += assign_tuples(scope, set_vars, result, seek_name) + new_result += assign_tuples(set_vars, result, seek_name) print new_result print '\n\nlala', op, set_vars.values, call_list.values print stmt, scope @@ -382,13 +388,22 @@ def follow_statement(stmt, scope=None, seek_name=None): def follow_call_list(scope, call_list): - """ The call list has a special structure """ - result = [] - for calls in call_list: - for call in calls: - if not isinstance(call, str): - # the string tokens are just operations (+, -, etc.) - result += follow_call(scope, call) + """ + The call list has a special structure. + This can be either `parsing.Array` or `list`. + """ + if isinstance(call_list, parsing.Array) \ + and call_list.type != parsing.Array.NOARRAY: + # Especially 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: + result = [] + for calls in call_list: + for call in calls: + if not isinstance(call, str): + # The string tokens are just operations (+, -, etc.) + result += follow_call(scope, call) return result diff --git a/ftest.py b/ftest.py index 9d16d836..5eaaad7b 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 8bb1ec2b..c2dc5878 100644 --- a/parsetest.py +++ b/parsetest.py @@ -147,4 +147,4 @@ c = b().c3(); abc = datetime; return [abc][0]. ;pylab.; add(1+2,2).; for fi in [ 1.0.fromhex(); import flask ; flsk = flask.Flask + flask.Request; abc = [1,2+3]; abc[0]. import pylab; def add(a1,b1): nana = 1; return a1+b1 -flow_test.; a12, (b12, c12) = (1,("", "")); a12. +flow_test.; a12, (b12, c12) = (1,(list, "")); b12. diff --git a/parsing.py b/parsing.py index a567c8d1..2a60aba6 100644 --- a/parsing.py +++ b/parsing.py @@ -799,6 +799,16 @@ class Array(Call): self.keys[c] = self.values[c] self.values[c] = [] + def get_only_subelement(self): + """ + Returns the only element that an array contains. If it contains + more than one element, raise an exception. + """ + if len(self.values) != 1 or len(self.values[0]) != 1: + raise AttributeError("More than one value found") + return self.values[0][0] + + def __len__(self): return len(self.values) @@ -814,14 +824,8 @@ class Array(Call): def __repr__(self): if self.type == self.NOARRAY: temp = 'noarray' - elif self.type == self.TUPLE: - temp = 'tuple' - elif self.type == self.LIST: - temp = 'list' - elif self.type == self.DICT: - temp = 'dict' - elif self.type == self.SET: - temp = 'set' + else: + temp = self.type parent_str = " of %s" % self.parent if self.parent else "" return "<%s: %s%s>" % (self.__class__.__name__, temp, parent_str) diff --git a/test/completion/arrays.py b/test/completion/arrays.py index 5e2e2ee1..5f888d25 100644 --- a/test/completion/arrays.py +++ b/test/completion/arrays.py @@ -1,6 +1,11 @@ +# ----------------- +# basic array lookups +# ----------------- #? ['imag'] -[1,2][0].imag +[1,""][0].imag +#? [] +[1,""][1].imag a = list() #? ['append'] @@ -10,14 +15,52 @@ a = list() [[a]][0][100].append +# ----------------- +# tuple assignments +# ----------------- a1, b1 = (1, "") #? ['real'] a1.real #? ['lower'] b1.lower +#? [] +b1.real (a2, b2) = (1, "") #? ['imag'] a2.imag #? ['upper'] b2.upper + +# ----------------- +# subtuple assignment +# ----------------- +(a3, (b3, c3)) = (1, ("", list)) +##? ['append'] +c3.append +#? [] +c3.upper +#? [] +c3.real + +a4, (b4, c4) = (1, ("", list)) +#? ['append'] +c4.append +#? [] +c4.upper +#? [] +c4.real +#? ['real'] +a4.real +#? ['upper'] +b4.upper + + +# ----------------- +# unnessecary braces +# ----------------- +u, v = 1, "" +#? ['real'] +u.real +#? [] +u.upper diff --git a/test/completion/basic.py b/test/completion/basic.py index 13da2275..a5532b4e 100644 --- a/test/completion/basic.py +++ b/test/completion/basic.py @@ -14,7 +14,7 @@ with open('') as f1, open('') as f2: def global_define(): - #global glob + global glob glob = 3 #? ['real'] diff --git a/test/completion/types.py b/test/completion/types.py index fa887f68..ffb8222d 100644 --- a/test/completion/types.py +++ b/test/completion/types.py @@ -68,3 +68,11 @@ tup2 = tuple() tup2.i ##? ['index'] TODO enable ().i + +tup3 = 1,"" +#? ['index'] +tup3.index + +tup4 = 1,"" +#? ['index'] +tup4.index diff --git a/test/run.py b/test/run.py index 4d6b3aae..8ebb1648 100755 --- a/test/run.py +++ b/test/run.py @@ -43,8 +43,8 @@ def completion_test(source): # TODO remove set! duplicates should not be normal comp_str = str(sorted(set([str(c) for c in completions]))) if comp_str != correct: - print 'Solution not correct, received %s, wanted %s' % \ - (comp_str, correct) + print 'Solution on %s not correct, received %s, wanted %s'\ + % (line_nr, comp_str, correct) #print [(c.name, c.name.parent) for c in completions] fails += 1 correct = None