array support

This commit is contained in:
David Halter
2012-04-15 00:05:34 +02:00
parent af1407dfc4
commit c03bc8c714
4 changed files with 125 additions and 48 deletions

View File

@@ -55,8 +55,9 @@ def memoize(default=None):
class Exec(object): class Exec(object):
def __init__(self, base): def __init__(self, base, params):
self.base = base self.base = base
self.params = params
def get_parent_until(self, *args): def get_parent_until(self, *args):
return self.base.get_parent_until(*args) return self.base.get_parent_until(*args)
@@ -95,6 +96,60 @@ class Instance(Exec):
(self.__class__.__name__, self.base) (self.__class__.__name__, self.base)
class Array(object):
"""
Used as a mirror to parsing.Array, if needed. It defines some getter
methods which are important in this module.
"""
def __init__(self, array):
self._array = array
def get_index_type(self, index):
#print self._array.values, index.values
values = self._array.values
#print 'ui', index.values, index.values[0][0].type
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.values[int(iv[0][0].name)]]
except:
pass
scope = self._array.parent_stmt.parent
return follow_call_list(scope, values)
def get_defined_names(self):
""" This method generates all ArrayElements for one parsing.Array. """
# array.type is a string with the type, e.g. 'list'
scope = get_scopes_for_name(builtin.Builtin.scope, self._array.type)[0]
names = scope.get_defined_names()
return [ArrayElement(n) for n in names]
def __repr__(self):
return "<%s of %s>" % (self.__class__.__name__, self._array)
class ArrayElement(object):
def __init__(self, name):
self.name = name
@property
def parent(self):
raise NotImplementedError("This shouldn't happen")
return
@property
def returns(self):
return self.name.parent.returns
@property
def names(self):
return self.name.names
def __repr__(self):
return "<%s of %s>" % (self.__class__.__name__, self.name)
class Execution(Exec): class Execution(Exec):
""" """
This class is used to evaluate functions and their returns. This class is used to evaluate functions and their returns.
@@ -110,7 +165,7 @@ class Execution(Exec):
stmts = [] stmts = []
if isinstance(scope, parsing.Class): if isinstance(scope, parsing.Class):
# there maybe executions of executions # there maybe executions of executions
stmts = [Instance(scope)] stmts = [Instance(scope, self.params)]
else: else:
if get_returns: if get_returns:
ret = scope.returns ret = scope.returns
@@ -139,11 +194,11 @@ def get_names_for_scope(scope):
while scope: while scope:
# class variables/functions are only availabe # 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:
compl += scope.get_set_vars() compl += scope.get_defined_names()
scope = scope.parent scope = scope.parent
# add builtins to the global scope # add builtins to the global scope
compl += builtin.Builtin.scope.get_set_vars() compl += builtin.Builtin.scope.get_defined_names()
#print 'gnfs', scope, compl #print 'gnfs', scope, compl
return compl return compl
@@ -184,10 +239,13 @@ def get_scopes_for_name(scope, name, search_global=False):
# result += filter_name(i) # result += filter_name(i)
#else: #else:
if [name] == list(scope.names): if [name] == list(scope.names):
if isinstance(scope, ArrayElement):
result.append(scope)
else:
par = scope.parent par = scope.parent
if isinstance(par, parsing.Flow): if isinstance(par, parsing.Flow):
# TODO get Flow data, which is defined by the loop (or # TODO get Flow data, which is defined by the loop
# with) # (or with)
pass pass
elif isinstance(par, parsing.Param): elif isinstance(par, parsing.Param):
if isinstance(par.parent.parent, parsing.Class) \ if isinstance(par.parent.parent, parsing.Class) \
@@ -204,7 +262,7 @@ def get_scopes_for_name(scope, name, search_global=False):
if search_global: if search_global:
names = get_names_for_scope(scope) names = get_names_for_scope(scope)
else: else:
names = scope.get_set_vars() names = scope.get_defined_names()
return remove_statements(filter_name(names)) return remove_statements(filter_name(names))
@@ -225,7 +283,8 @@ def strip_imports(scopes):
else: else:
result += new_scopes result += new_scopes
for n in new_scopes: for n in new_scopes:
result += strip_imports(i for i in n.get_imports() if i.star) result += strip_imports(i for i in n.get_imports()
if i.star)
else: else:
result.append(s) result.append(s)
return result return result
@@ -239,14 +298,19 @@ def follow_statement(stmt, scope=None):
""" """
if scope is None: if scope is None:
scope = stmt.get_parent_until(parsing.Function) scope = stmt.get_parent_until(parsing.Function)
call_list = stmt.get_assignment_calls()
debug.dbg('calls', call_list, call_list.values)
return follow_call_list(scope, call_list)
def follow_call_list(scope, call_list):
""" The call list has a special structure """
result = [] result = []
calls = stmt.get_assignment_calls() for calls in call_list:
debug.dbg('calls', calls, calls.values) for call in calls:
for tokens in calls: if not isinstance(call, str):
for tok in tokens:
if not isinstance(tok, str):
# the string tokens are just operations (+, -, etc.) # the string tokens are just operations (+, -, etc.)
result += follow_call(scope, tok) result += follow_call(scope, call)
return result return result
@@ -256,7 +320,7 @@ def follow_call(scope, call):
current = next(path) current = next(path)
if isinstance(current, parsing.Array): if isinstance(current, parsing.Array):
result = [current] result = [Array(current)]
else: else:
# TODO add better care for int/unicode, now str/float are just used # TODO add better care for int/unicode, now str/float are just used
# instead # instead
@@ -286,6 +350,9 @@ def follow_paths(path, results):
for i, r in enumerate(results): for i, r in enumerate(results):
results_new += follow_path(iter_paths[i], r) results_new += follow_path(iter_paths[i], r)
except StopIteration: except StopIteration:
#if isinstance(s, parsing.Array):
# completions += s.
#else:
return results return results
return results_new return results_new
@@ -303,11 +370,12 @@ def follow_path(path, input):
if isinstance(current, parsing.Array): if isinstance(current, parsing.Array):
# this must be an execution, either () or [] # this must be an execution, either () or []
if current.type == parsing.Array.LIST: if current.type == parsing.Array.LIST:
result = [] # TODO eval lists result = scope.get_index_type(current)
elif current.type not in [parsing.Array.DICT, parsing]: elif current.type not in [parsing.Array.DICT]:
# scope must be a class or func - make an instance or execution # scope must be a class or func - make an instance or execution
debug.dbg('befexec', scope) debug.dbg('befexec', scope)
result = strip_imports(Execution(scope).get_return_types()) exe = Execution(scope, current)
result = strip_imports(exe.get_return_types())
debug.dbg('exec', result) debug.dbg('exec', result)
#except AttributeError: #except AttributeError:
# debug.dbg('cannot execute:', scope) # debug.dbg('cannot execute:', scope)

View File

@@ -9,7 +9,7 @@ functions.modules.module_find_path.insert(0, '.')
f_name = 'parsetest.py' f_name = 'parsetest.py'
import os import os
path = os.getcwd() + '/' + f_name path = os.path.join(os.getcwd(), f_name)
f = open(path) f = open(path)
code = f.read() code = f.read()

View File

@@ -140,11 +140,11 @@ class c1():
c, 1, c3()) [0].pop() c, 1, c3()) [0].pop()
c = u"asdf".join([1,2]) c = u"asdf".join([1,2])
matrx_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
#import parsing as test #import parsing as test
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;
matrix_test. abc = [1,2+3]; abc[0].

View File

@@ -520,10 +520,13 @@ class Statement(Simple):
This is not done in the main parser, because it might be slow and This is not done in the main parser, because it might be slow and
most of the statements won't need this data anyway. This is something most of the statements won't need this data anyway. This is something
'like' a lazy execution. 'like' a lazy execution.
This is not really nice written, sorry for that. If you plan to replace
it and make it nicer, that would be cool :-)
""" """
if self.assignment_calls: if self.assignment_calls:
return self.assignment_calls return self.assignment_calls
result = Array(Array.EMPTY) result = Array(Array.EMPTY, self)
top = result top = result
level = 0 level = 0
is_chain = False is_chain = False
@@ -540,7 +543,7 @@ class Statement(Simple):
# TODO there may be multiple assignments: a = b = 1 # TODO there may be multiple assignments: a = b = 1
# initialize the first item # initialize the first item
result = Array(Array.EMPTY) result = Array(Array.EMPTY, self)
top = result top = result
continue continue
except TypeError: except TypeError:
@@ -560,7 +563,7 @@ class Statement(Simple):
c_type = Call.NUMBER c_type = Call.NUMBER
if is_chain: if is_chain:
call = Call(tok, c_type, result) call = Call(tok, c_type, self, result)
result = result.set_next_chain_call(call) result = result.set_next_chain_call(call)
is_chain = False is_chain = False
close_brackets = False close_brackets = False
@@ -568,17 +571,19 @@ class Statement(Simple):
if close_brackets: if close_brackets:
result = result.parent result = result.parent
close_brackets = False close_brackets = False
call = Call(tok, c_type, result) call = Call(tok, c_type, self, result)
result.add_to_current_field(call) result.add_to_current_field(call)
result = call result = call
elif tok in brackets.keys(): # brackets elif tok in brackets.keys(): # brackets
level += 1 level += 1
# TODO why is this not working, when the two statements ar not
# in the if/else clause (they are exactly the same!!!)
if is_call_or_close(): if is_call_or_close():
result = Array(brackets[tok], result) result = Array(brackets[tok], self, result)
result = result.parent.add_execution(result) result = result.parent.add_execution(result)
close_brackets = False close_brackets = False
else: else:
result = Array(brackets[tok], result) result = Array(brackets[tok], self, result)
result.parent.add_to_current_field(result) result.parent.add_to_current_field(result)
elif tok == ':': elif tok == ':':
if is_call_or_close(): if is_call_or_close():
@@ -586,7 +591,8 @@ class Statement(Simple):
close_brackets = False close_brackets = False
result.add_dictionary_key() result.add_dictionary_key()
elif tok == '.': elif tok == '.':
if close_brackets: if close_brackets and result.parent != top:
# only get out of the array, if it is a array execution
result = result.parent result = result.parent
close_brackets = False close_brackets = False
is_chain = True is_chain = True
@@ -645,7 +651,7 @@ class Call(object):
STRING = object() STRING = object()
""" The statement object of functions, to """ """ The statement object of functions, to """
def __init__(self, name, type, parent=None): def __init__(self, name, type, parent_stmt, parent=None):
self.name = name self.name = name
# parent is not the oposite of next. The parent of c: a = [b.c] would # parent is not the oposite of next. The parent of c: a = [b.c] would
# be an array. # be an array.
@@ -654,6 +660,7 @@ class Call(object):
self.next = None self.next = None
self.execution = None self.execution = None
self.parent_stmt = parent_stmt
def set_next_chain_call(self, call): def set_next_chain_call(self, call):
""" Adds another part of the statement""" """ Adds another part of the statement"""
@@ -705,14 +712,14 @@ class Array(Call):
below. below.
:type array_type: int :type array_type: int
""" """
EMPTY = object() EMPTY = None
TUPLE = object() TUPLE = 'tuple'
LIST = object() LIST = 'list'
DICT = object() DICT = 'dict'
SET = object() SET = 'set'
def __init__(self, arr_type, parent=None): def __init__(self, arr_type, parent_stmt, parent=None):
super(Array, self).__init__(None, arr_type, parent) super(Array, self).__init__(None, arr_type, parent_stmt, parent)
self.values = [] self.values = []
self.keys = [] self.keys = []
@@ -1024,6 +1031,8 @@ class PyFuzzyParser(object):
:type pre_used_token: set :type pre_used_token: set
:return: Statement + last parsed token. :return: Statement + last parsed token.
:rtype: (Statement, str) :rtype: (Statement, str)
TODO improve abort criterion of not closing parentheses
""" """
string = '' string = ''