[pypy-commit] pypy default: merge heads
arigo
noreply at buildbot.pypy.org
Wed Feb 27 19:54:51 CET 2013
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r61864:6a7a87dc6323
Date: 2013-02-27 19:55 +0100
http://bitbucket.org/pypy/pypy/changeset/6a7a87dc6323/
Log: merge heads
diff too long, truncating to 2000 out of 2365 lines
diff --git a/rpython/flowspace/argument.py b/rpython/annotator/argument.py
copy from rpython/flowspace/argument.py
copy to rpython/annotator/argument.py
--- a/rpython/flowspace/argument.py
+++ b/rpython/annotator/argument.py
@@ -1,84 +1,45 @@
"""
Arguments objects.
"""
+from rpython.annotator.model import SomeTuple, SomeObject
+# for parsing call arguments
+class RPythonCallsSpace(object):
+ """Pseudo Object Space providing almost no real operation.
+ For the Arguments class: if it really needs other operations, it means
+ that the call pattern is too complex for R-Python.
+ """
+ def newtuple(self, items_s):
+ if len(items_s) == 1 and items_s[0] is Ellipsis:
+ res = SomeObject() # hack to get a SomeObject as the *arg
+ res.from_ellipsis = True
+ return res
+ else:
+ return SomeTuple(items_s)
-class Signature(object):
- _immutable_ = True
- _immutable_fields_ = ["argnames[*]"]
- __slots__ = ("argnames", "varargname", "kwargname")
+ def unpackiterable(self, s_obj, expected_length=None):
+ if isinstance(s_obj, SomeTuple):
+ return list(s_obj.items)
+ if (s_obj.__class__ is SomeObject and
+ getattr(s_obj, 'from_ellipsis', False)): # see newtuple()
+ return [Ellipsis]
+ raise CallPatternTooComplex("'*' argument must be SomeTuple")
- def __init__(self, argnames, varargname=None, kwargname=None):
- self.argnames = argnames
- self.varargname = varargname
- self.kwargname = kwargname
+ def is_true(self, s_tup):
+ assert isinstance(s_tup, SomeTuple)
+ return bool(s_tup.items)
- def find_argname(self, name):
- try:
- return self.argnames.index(name)
- except ValueError:
- return -1
- def num_argnames(self):
- return len(self.argnames)
-
- def has_vararg(self):
- return self.varargname is not None
-
- def has_kwarg(self):
- return self.kwargname is not None
-
- def scope_length(self):
- scopelen = len(self.argnames)
- scopelen += self.has_vararg()
- scopelen += self.has_kwarg()
- return scopelen
-
- def getallvarnames(self):
- argnames = self.argnames
- if self.varargname is not None:
- argnames = argnames + [self.varargname]
- if self.kwargname is not None:
- argnames = argnames + [self.kwargname]
- return argnames
-
- def __repr__(self):
- return "Signature(%r, %r, %r)" % (
- self.argnames, self.varargname, self.kwargname)
-
- def __eq__(self, other):
- if not isinstance(other, Signature):
- return NotImplemented
- return (self.argnames == other.argnames and
- self.varargname == other.varargname and
- self.kwargname == other.kwargname)
-
- def __ne__(self, other):
- if not isinstance(other, Signature):
- return NotImplemented
- return not self == other
-
- # make it look tuply for its use in the annotator
-
- def __len__(self):
- return 3
-
- def __getitem__(self, i):
- if i == 0:
- return self.argnames
- if i == 1:
- return self.varargname
- if i == 2:
- return self.kwargname
- raise IndexError
+class CallPatternTooComplex(Exception):
+ pass
class ArgumentsForTranslation(object):
+ w_starstararg = None
def __init__(self, space, args_w, keywords=None, keywords_w=None,
w_stararg=None, w_starstararg=None):
self.w_stararg = w_stararg
- self.w_starstararg = w_starstararg
- self.combine_has_happened = False
+ assert w_starstararg is None
self.space = space
assert isinstance(args_w, list)
self.arguments_w = args_w
@@ -95,53 +56,13 @@
return '%s(%s, %s, %s)' % (name, self.arguments_w,
self.keywords, self.keywords_w)
- def _combine_wrapped(self, w_stararg, w_starstararg):
- "unpack the *arg and **kwd into arguments_w and keywords_w"
- if w_stararg is not None:
- self._combine_starargs_wrapped(w_stararg)
- if w_starstararg is not None:
- self._combine_starstarargs_wrapped(w_starstararg)
-
- def _combine_starargs_wrapped(self, w_stararg):
- # unpack the * arguments
- space = self.space
- args_w = space.unpackiterable(w_stararg)
- self.arguments_w = self.arguments_w + args_w
-
- def _combine_starstarargs_wrapped(self, w_starstararg):
- # unpack the ** arguments
- space = self.space
- keywords, values_w = space.view_as_kwargs(w_starstararg)
- if keywords is not None: # this path also taken for empty dicts
- if self.keywords is None:
- self.keywords = keywords
- self.keywords_w = values_w
- else:
- if set(keywords) & set(self.keywords):
- raise TypeError("got multiple values for keyword arguments '%s'", set(keywords) & set(self.keywords))
- self.keywords = self.keywords + keywords
- self.keywords_w = self.keywords_w + values_w
- return
- if space.isinstance_w(w_starstararg, space.w_dict):
- keys_w = space.unpackiterable(w_starstararg)
+ @property
+ def positional_args(self):
+ if self.w_stararg is not None:
+ args_w = self.space.unpackiterable(self.w_stararg)
+ return self.arguments_w + args_w
else:
- w_keys = space.call_method(w_starstararg, "keys")
- keys_w = space.unpackiterable(w_keys)
- keywords_w = [None] * len(keys_w)
- keywords = [None] * len(keys_w)
- for i, w_key in enumerate(keys_w):
- key = space.str_w(w_key)
- if key in self.keywords:
- raise TypeError("got multiple values for keyword argument '%s'" % key)
- keywords[i] = key
- keywords_w[i] = space.getitem(w_starstararg, w_key)
- self.keyword_names_w = keys_w
- if self.keywords is None:
- self.keywords = keywords
- self.keywords_w = keywords_w
- else:
- self.keywords = self.keywords + keywords
- self.keywords_w = self.keywords_w + keywords_w
+ return self.arguments_w
def fixedunpack(self, argcount):
"""The simplest argument parsing: get the 'argcount' arguments,
@@ -154,12 +75,6 @@
raise ValueError("not enough arguments (%d expected)" % argcount)
return self.arguments_w
- def combine_if_necessary(self):
- if self.combine_has_happened:
- return
- self._combine_wrapped(self.w_stararg, self.w_starstararg)
- self.combine_has_happened = True
-
def prepend(self, w_firstarg): # used often
"Return a new Arguments with a new argument inserted first."
return ArgumentsForTranslation(self.space, [w_firstarg] + self.arguments_w,
@@ -178,10 +93,9 @@
# args_w = list of the normal actual parameters, wrapped
# scope_w = resulting list of wrapped values
#
- self.combine_if_necessary()
co_argcount = signature.num_argnames() # expected formal arguments, without */**
- args_w = self.arguments_w
+ args_w = self.positional_args
num_args = len(args_w)
keywords = self.keywords or []
num_kwds = len(keywords)
@@ -263,12 +177,8 @@
def unpack(self):
"Return a ([w1,w2...], {'kw':w3...}) pair."
- self.combine_if_necessary()
- kwds_w = {}
- if self.keywords:
- for i in range(len(self.keywords)):
- kwds_w[self.keywords[i]] = self.keywords_w[i]
- return self.arguments_w, kwds_w
+ kwds_w = dict(zip(self.keywords, self.keywords_w)) if self.keywords else {}
+ return self.positional_args, kwds_w
def match_signature(self, signature, defaults_w):
"""Parse args and kwargs according to the signature of a code object,
@@ -281,11 +191,11 @@
def unmatch_signature(self, signature, data_w):
"""kind of inverse of match_signature"""
- args_w, kwds_w = self.unpack()
- need_cnt = len(args_w)
- need_kwds = kwds_w.keys()
+ need_cnt = len(self.positional_args)
+ need_kwds = self.keywords or []
space = self.space
argnames, varargname, kwargname = signature
+ assert kwargname is None
cnt = len(argnames)
data_args_w = data_w[:cnt]
if varargname:
@@ -293,31 +203,17 @@
cnt += 1
else:
data_w_stararg = space.newtuple([])
+ assert len(data_w) == cnt
unfiltered_kwds_w = {}
- if kwargname:
- data_w_starargarg = data_w[cnt]
- for w_key in space.unpackiterable(data_w_starargarg):
- key = space.str_w(w_key)
- w_value = space.getitem(data_w_starargarg, w_key)
- unfiltered_kwds_w[key] = w_value
- cnt += 1
- assert len(data_w) == cnt
-
- ndata_args_w = len(data_args_w)
- if ndata_args_w >= need_cnt:
+ if len(data_args_w) >= need_cnt:
args_w = data_args_w[:need_cnt]
for argname, w_arg in zip(argnames[need_cnt:], data_args_w[need_cnt:]):
unfiltered_kwds_w[argname] = w_arg
assert not space.is_true(data_w_stararg)
else:
stararg_w = space.unpackiterable(data_w_stararg)
- datalen = len(data_args_w)
- args_w = [None] * (datalen + len(stararg_w))
- for i in range(0, datalen):
- args_w[i] = data_args_w[i]
- for i in range(0, len(stararg_w)):
- args_w[i + datalen] = stararg_w[i]
+ args_w = data_args_w + stararg_w
assert len(args_w) == need_cnt
keywords = []
@@ -358,8 +254,7 @@
return (shape_cnt, shape_keys, shape_star, shape_stst), data_w
def _rawshape(self, nextra=0):
- assert not self.combine_has_happened
- shape_cnt = len(self.arguments_w) + nextra # Number of positional args
+ shape_cnt = len(self.arguments_w) + nextra # Number of positional args
if self.keywords:
shape_keys = self.keywords[:] # List of keywords (strings)
shape_keys.sort()
diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -19,7 +19,7 @@
from rpython.annotator.dictdef import DictDef
from rpython.annotator import description
from rpython.annotator.signature import annotationoftype
-from rpython.flowspace.argument import ArgumentsForTranslation
+from rpython.annotator.argument import ArgumentsForTranslation, RPythonCallsSpace
from rpython.rlib.objectmodel import r_dict, Symbolic
from rpython.tool.algo.unionfind import UnionFind
from rpython.rtyper.lltypesystem import lltype, llmemory
@@ -734,51 +734,6 @@
return False
else:
return True
-
-# for parsing call arguments
-class RPythonCallsSpace(object):
- """Pseudo Object Space providing almost no real operation.
- For the Arguments class: if it really needs other operations, it means
- that the call pattern is too complex for R-Python.
- """
- w_tuple = SomeTuple
- def newtuple(self, items_s):
- if len(items_s) == 1 and items_s[0] is Ellipsis:
- res = SomeObject() # hack to get a SomeObject as the *arg
- res.from_ellipsis = True
- return res
- else:
- return SomeTuple(items_s)
-
- def newdict(self):
- raise CallPatternTooComplex, "'**' argument"
-
- def unpackiterable(self, s_obj, expected_length=None):
- if isinstance(s_obj, SomeTuple):
- if (expected_length is not None and
- expected_length != len(s_obj.items)):
- raise ValueError
- return list(s_obj.items)
- if (s_obj.__class__ is SomeObject and
- getattr(s_obj, 'from_ellipsis', False)): # see newtuple()
- return [Ellipsis]
- raise CallPatternTooComplex, "'*' argument must be SomeTuple"
- fixedview = unpackiterable
- listview = unpackiterable
-
- def is_w(self, one, other):
- return one is other
-
- def type(self, item):
- return type(item)
-
- def is_true(self, s_tup):
- assert isinstance(s_tup, SomeTuple)
- return bool(s_tup.items)
-
-class CallPatternTooComplex(Exception):
- pass
-
# get current bookkeeper
def getbookkeeper():
diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py
--- a/rpython/annotator/description.py
+++ b/rpython/annotator/description.py
@@ -3,7 +3,7 @@
from rpython.annotator.signature import enforce_signature_args, enforce_signature_return
from rpython.flowspace.model import Constant, FunctionGraph
from rpython.flowspace.bytecode import cpython_code_signature
-from rpython.flowspace.argument import rawshape, ArgErr
+from rpython.annotator.argument import rawshape, ArgErr
from rpython.tool.sourcetools import valid_identifier, func_with_new_name
from rpython.tool.pairtype import extendabletype
diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -13,7 +13,7 @@
from rpython.rlib.rarithmetic import r_uint, base_int, r_longlong, r_ulonglong
from rpython.rlib.rarithmetic import r_singlefloat
from rpython.rlib import objectmodel
-from rpython.flowspace.objspace import FlowObjSpace, FlowingError
+from rpython.flowspace.objspace import build_flow, FlowingError
from rpython.translator.test import snippet
@@ -40,9 +40,6 @@
class TestAnnotateTestCase:
- def setup_class(cls):
- cls.space = FlowObjSpace()
-
def teardown_method(self, meth):
assert annmodel.s_Bool == annmodel.SomeBool()
@@ -60,7 +57,7 @@
except AttributeError:
pass
name = func.func_name
- funcgraph = self.space.build_flow(func)
+ funcgraph = build_flow(func)
funcgraph.source = inspect.getsource(func)
return funcgraph
@@ -775,7 +772,7 @@
assert isinstance(s, annmodel.SomePBC)
assert s.const == myobj
- def test_cleanup_protocol(self):
+ def test_cleanup_protocol(self):
class Stuff:
def __init__(self):
self.called = False
@@ -3754,7 +3751,7 @@
def test_join_none_and_nonnull(self):
from rpython.rlib.rstring import assert_str0
-
+
def f(i):
a = str(i)
a = assert_str0(a)
@@ -3798,7 +3795,7 @@
class A(object):
def __iter__(self):
return self
-
+
def fn():
return iter(A())
@@ -3857,7 +3854,7 @@
return True
x = X()
-
+
def f(i):
if i:
x1 = x
diff --git a/rpython/annotator/test/test_argument.py b/rpython/annotator/test/test_argument.py
new file mode 100644
--- /dev/null
+++ b/rpython/annotator/test/test_argument.py
@@ -0,0 +1,171 @@
+# -*- coding: utf-8 -*-
+import py
+from rpython.annotator.argument import ArgumentsForTranslation, rawshape
+from rpython.flowspace.argument import Signature
+
+class DummySpace(object):
+ def newtuple(self, items):
+ return tuple(items)
+
+ def is_true(self, obj):
+ return bool(obj)
+
+ def unpackiterable(self, it):
+ return list(it)
+
+
+def make_arguments_for_translation(space, args_w, keywords_w={},
+ w_stararg=None, w_starstararg=None):
+ return ArgumentsForTranslation(space, args_w, keywords_w.keys(),
+ keywords_w.values(), w_stararg,
+ w_starstararg)
+
+class TestArgumentsForTranslation(object):
+
+ def test_prepend(self):
+ space = DummySpace()
+ args = ArgumentsForTranslation(space, ["0"])
+ args1 = args.prepend("thingy")
+ assert args1 is not args
+ assert args1.arguments_w == ["thingy", "0"]
+ assert args1.keywords is args.keywords
+ assert args1.keywords_w is args.keywords_w
+
+ def test_fixedunpacked(self):
+ space = DummySpace()
+
+ args = ArgumentsForTranslation(space, [], ["k"], [1])
+ py.test.raises(ValueError, args.fixedunpack, 1)
+
+ args = ArgumentsForTranslation(space, ["a", "b"])
+ py.test.raises(ValueError, args.fixedunpack, 0)
+ py.test.raises(ValueError, args.fixedunpack, 1)
+ py.test.raises(ValueError, args.fixedunpack, 3)
+ py.test.raises(ValueError, args.fixedunpack, 4)
+
+ assert args.fixedunpack(2) == ['a', 'b']
+
+ def test_unmatch_signature(self):
+ space = DummySpace()
+ args = make_arguments_for_translation(space, [1,2,3])
+ sig = Signature(['a', 'b', 'c'], None, None)
+ data = args.match_signature(sig, [])
+ new_args = args.unmatch_signature(sig, data)
+ assert args.unpack() == new_args.unpack()
+
+ args = make_arguments_for_translation(space, [1])
+ sig = Signature(['a', 'b', 'c'], None, None)
+ data = args.match_signature(sig, [2, 3])
+ new_args = args.unmatch_signature(sig, data)
+ assert args.unpack() == new_args.unpack()
+
+ args = make_arguments_for_translation(space, [1,2,3,4,5])
+ sig = Signature(['a', 'b', 'c'], 'r', None)
+ data = args.match_signature(sig, [])
+ new_args = args.unmatch_signature(sig, data)
+ assert args.unpack() == new_args.unpack()
+
+ args = make_arguments_for_translation(space, [1], {'c': 3, 'b': 2})
+ sig = Signature(['a', 'b', 'c'], None, None)
+ data = args.match_signature(sig, [])
+ new_args = args.unmatch_signature(sig, data)
+ assert args.unpack() == new_args.unpack()
+
+ args = make_arguments_for_translation(space, [1], {'c': 5})
+ sig = Signature(['a', 'b', 'c'], None, None)
+ data = args.match_signature(sig, [2, 3])
+ new_args = args.unmatch_signature(sig, data)
+ assert args.unpack() == new_args.unpack()
+
+ args = make_arguments_for_translation(space, [1], {'c': 5, 'd': 7})
+ sig = Signature(['a', 'b', 'c'], None, 'kw')
+ py.test.raises(TypeError, args.match_signature, sig, [2, 3])
+
+ def test_rawshape(self):
+ space = DummySpace()
+ args = make_arguments_for_translation(space, [1,2,3])
+ assert rawshape(args) == (3, (), False, False)
+
+ args = make_arguments_for_translation(space, [1])
+ assert rawshape(args, 2) == (3, (), False, False)
+
+ args = make_arguments_for_translation(space, [1,2,3,4,5])
+ assert rawshape(args) == (5, (), False, False)
+
+ args = make_arguments_for_translation(space, [1], {'c': 3, 'b': 2})
+ assert rawshape(args) == (1, ('b', 'c'), False, False)
+
+ args = make_arguments_for_translation(space, [1], {'c': 5})
+ assert rawshape(args) == (1, ('c', ), False, False)
+
+ args = make_arguments_for_translation(space, [1], {'c': 5, 'd': 7})
+ assert rawshape(args) == (1, ('c', 'd'), False, False)
+
+ args = make_arguments_for_translation(space, [1,2,3,4,5], {'e': 5, 'd': 7})
+ assert rawshape(args) == (5, ('d', 'e'), False, False)
+
+
+ def test_flatten(self):
+ space = DummySpace()
+ args = make_arguments_for_translation(space, [1,2,3])
+ assert args.flatten() == ((3, (), False, False), [1, 2, 3])
+
+ args = make_arguments_for_translation(space, [1])
+ assert args.flatten() == ((1, (), False, False), [1])
+
+ args = make_arguments_for_translation(space, [1,2,3,4,5])
+ assert args.flatten() == ((5, (), False, False), [1,2,3,4,5])
+
+ args = make_arguments_for_translation(space, [1], {'c': 3, 'b': 2})
+ assert args.flatten() == ((1, ('b', 'c'), False, False), [1, 2, 3])
+
+ args = make_arguments_for_translation(space, [1], {'c': 5})
+ assert args.flatten() == ((1, ('c', ), False, False), [1, 5])
+
+ args = make_arguments_for_translation(space, [1], {'c': 5, 'd': 7})
+ assert args.flatten() == ((1, ('c', 'd'), False, False), [1, 5, 7])
+
+ args = make_arguments_for_translation(space, [1,2,3,4,5], {'e': 5, 'd': 7})
+ assert args.flatten() == ((5, ('d', 'e'), False, False), [1, 2, 3, 4, 5, 7, 5])
+
+ def test_stararg_flowspace_variable(self):
+ space = DummySpace()
+ var = object()
+ shape = ((2, ('g', ), True, False), [1, 2, 9, var])
+ args = make_arguments_for_translation(space, [1,2], {'g': 9},
+ w_stararg=var)
+ assert args.flatten() == shape
+
+ args = ArgumentsForTranslation.fromshape(space, *shape)
+ assert args.flatten() == shape
+
+
+ def test_fromshape(self):
+ space = DummySpace()
+ shape = ((3, (), False, False), [1, 2, 3])
+ args = ArgumentsForTranslation.fromshape(space, *shape)
+ assert args.flatten() == shape
+
+ shape = ((1, (), False, False), [1])
+ args = ArgumentsForTranslation.fromshape(space, *shape)
+ assert args.flatten() == shape
+
+ shape = ((5, (), False, False), [1,2,3,4,5])
+ args = ArgumentsForTranslation.fromshape(space, *shape)
+ assert args.flatten() == shape
+
+ shape = ((1, ('b', 'c'), False, False), [1, 2, 3])
+ args = ArgumentsForTranslation.fromshape(space, *shape)
+ assert args.flatten() == shape
+
+ shape = ((1, ('c', ), False, False), [1, 5])
+ args = ArgumentsForTranslation.fromshape(space, *shape)
+ assert args.flatten() == shape
+
+ shape = ((1, ('c', 'd'), False, False), [1, 5, 7])
+ args = ArgumentsForTranslation.fromshape(space, *shape)
+ assert args.flatten() == shape
+
+ shape = ((5, ('d', 'e'), False, False), [1, 2, 3, 4, 5, 7, 5])
+ args = ArgumentsForTranslation.fromshape(space, *shape)
+ assert args.flatten() == shape
diff --git a/rpython/flowspace/argument.py b/rpython/flowspace/argument.py
--- a/rpython/flowspace/argument.py
+++ b/rpython/flowspace/argument.py
@@ -73,409 +73,25 @@
raise IndexError
-class ArgumentsForTranslation(object):
- def __init__(self, space, args_w, keywords=None, keywords_w=None,
- w_stararg=None, w_starstararg=None):
+class CallSpec(object):
+ """Represents the arguments passed into a function call, i.e. the
+ `a, b, *c, **d` part in `return func(a, b, *c, **d)`.
+ """
+ def __init__(self, args_w, keywords=None, w_stararg=None,
+ w_starstararg=None):
self.w_stararg = w_stararg
- self.w_starstararg = w_starstararg
- self.combine_has_happened = False
- self.space = space
+ assert w_starstararg is None, "No **-unpacking in RPython"
assert isinstance(args_w, list)
self.arguments_w = args_w
- self.keywords = keywords
- self.keywords_w = keywords_w
- self.keyword_names_w = None
-
- def __repr__(self):
- """ NOT_RPYTHON """
- name = self.__class__.__name__
- if not self.keywords:
- return '%s(%s)' % (name, self.arguments_w,)
- else:
- return '%s(%s, %s, %s)' % (name, self.arguments_w,
- self.keywords, self.keywords_w)
-
- def _combine_wrapped(self, w_stararg, w_starstararg):
- "unpack the *arg and **kwd into arguments_w and keywords_w"
- if w_stararg is not None:
- self._combine_starargs_wrapped(w_stararg)
- if w_starstararg is not None:
- self._combine_starstarargs_wrapped(w_starstararg)
-
- def _combine_starargs_wrapped(self, w_stararg):
- # unpack the * arguments
- space = self.space
- args_w = space.unpackiterable(w_stararg)
- self.arguments_w = self.arguments_w + args_w
-
- def _combine_starstarargs_wrapped(self, w_starstararg):
- # unpack the ** arguments
- space = self.space
- keywords, values_w = space.view_as_kwargs(w_starstararg)
- if keywords is not None: # this path also taken for empty dicts
- if self.keywords is None:
- self.keywords = keywords
- self.keywords_w = values_w
- else:
- if set(keywords) & set(self.keywords):
- raise TypeError("got multiple values for keyword arguments '%s'", set(keywords) & set(self.keywords))
- self.keywords = self.keywords + keywords
- self.keywords_w = self.keywords_w + values_w
- return
- if space.isinstance_w(w_starstararg, space.w_dict):
- keys_w = space.unpackiterable(w_starstararg)
- else:
- w_keys = space.call_method(w_starstararg, "keys")
- keys_w = space.unpackiterable(w_keys)
- keywords_w = [None] * len(keys_w)
- keywords = [None] * len(keys_w)
- for i, w_key in enumerate(keys_w):
- key = space.str_w(w_key)
- if key in self.keywords:
- raise TypeError("got multiple values for keyword argument '%s'" % key)
- keywords[i] = key
- keywords_w[i] = space.getitem(w_starstararg, w_key)
- self.keyword_names_w = keys_w
- if self.keywords is None:
- self.keywords = keywords
- self.keywords_w = keywords_w
- else:
- self.keywords = self.keywords + keywords
- self.keywords_w = self.keywords_w + keywords_w
-
- def fixedunpack(self, argcount):
- """The simplest argument parsing: get the 'argcount' arguments,
- or raise a real ValueError if the length is wrong."""
- if self.keywords:
- raise ValueError("no keyword arguments expected")
- if len(self.arguments_w) > argcount:
- raise ValueError("too many arguments (%d expected)" % argcount)
- elif len(self.arguments_w) < argcount:
- raise ValueError("not enough arguments (%d expected)" % argcount)
- return self.arguments_w
-
- def combine_if_necessary(self):
- if self.combine_has_happened:
- return
- self._combine_wrapped(self.w_stararg, self.w_starstararg)
- self.combine_has_happened = True
-
- def prepend(self, w_firstarg): # used often
- "Return a new Arguments with a new argument inserted first."
- return ArgumentsForTranslation(self.space, [w_firstarg] + self.arguments_w,
- self.keywords, self.keywords_w, self.w_stararg,
- self.w_starstararg)
-
- def copy(self):
- return ArgumentsForTranslation(self.space, self.arguments_w,
- self.keywords, self.keywords_w, self.w_stararg,
- self.w_starstararg)
-
- def _match_signature(self, scope_w, signature, defaults_w=None):
- """Parse args and kwargs according to the signature of a code object,
- or raise an ArgErr in case of failure.
- """
- # args_w = list of the normal actual parameters, wrapped
- # scope_w = resulting list of wrapped values
- #
- self.combine_if_necessary()
- co_argcount = signature.num_argnames() # expected formal arguments, without */**
-
- args_w = self.arguments_w
- num_args = len(args_w)
- keywords = self.keywords or []
- num_kwds = len(keywords)
-
- # put as many positional input arguments into place as available
- take = min(num_args, co_argcount)
- scope_w[:take] = args_w[:take]
- input_argcount = take
-
- # collect extra positional arguments into the *vararg
- if signature.has_vararg():
- if num_args > co_argcount:
- starargs_w = args_w[co_argcount:]
- else:
- starargs_w = []
- scope_w[co_argcount] = self.space.newtuple(starargs_w)
- elif num_args > co_argcount:
- raise ArgErrCount(num_args, num_kwds, signature, defaults_w, 0)
-
- # if a **kwargs argument is needed, explode
- if signature.has_kwarg():
- raise TypeError("Keyword arguments as **kwargs is not supported by RPython")
-
- # handle keyword arguments
- num_remainingkwds = 0
- keywords_w = self.keywords_w
- kwds_mapping = None
- if num_kwds:
- # kwds_mapping maps target indexes in the scope (minus input_argcount)
- # to positions in the keywords_w list
- kwds_mapping = [-1] * (co_argcount - input_argcount)
- # match the keywords given at the call site to the argument names
- # the called function takes
- # this function must not take a scope_w, to make the scope not
- # escape
- num_remainingkwds = len(keywords)
- for i, name in enumerate(keywords):
- # If name was not encoded as a string, it could be None. In that
- # case, it's definitely not going to be in the signature.
- if name is None:
- continue
- j = signature.find_argname(name)
- # if j == -1 nothing happens
- if j < input_argcount:
- # check that no keyword argument conflicts with these.
- if j >= 0:
- raise ArgErrMultipleValues(name)
- else:
- kwds_mapping[j - input_argcount] = i # map to the right index
- num_remainingkwds -= 1
-
- if num_remainingkwds:
- if co_argcount == 0:
- raise ArgErrCount(num_args, num_kwds, signature, defaults_w, 0)
- raise ArgErrUnknownKwds(self.space, num_remainingkwds, keywords,
- kwds_mapping, self.keyword_names_w)
-
- # check for missing arguments and fill them from the kwds,
- # or with defaults, if available
- missing = 0
- if input_argcount < co_argcount:
- def_first = co_argcount - (0 if defaults_w is None else len(defaults_w))
- j = 0
- kwds_index = -1
- for i in range(input_argcount, co_argcount):
- if kwds_mapping is not None:
- kwds_index = kwds_mapping[j]
- j += 1
- if kwds_index >= 0:
- scope_w[i] = keywords_w[kwds_index]
- continue
- defnum = i - def_first
- if defnum >= 0:
- scope_w[i] = defaults_w[defnum]
- else:
- missing += 1
- if missing:
- raise ArgErrCount(num_args, num_kwds, signature, defaults_w, missing)
-
- def unpack(self):
- "Return a ([w1,w2...], {'kw':w3...}) pair."
- self.combine_if_necessary()
- kwds_w = {}
- if self.keywords:
- for i in range(len(self.keywords)):
- kwds_w[self.keywords[i]] = self.keywords_w[i]
- return self.arguments_w, kwds_w
-
- def match_signature(self, signature, defaults_w):
- """Parse args and kwargs according to the signature of a code object,
- or raise an ArgErr in case of failure.
- """
- scopelen = signature.scope_length()
- scope_w = [None] * scopelen
- self._match_signature(scope_w, signature, defaults_w)
- return scope_w
-
- def unmatch_signature(self, signature, data_w):
- """kind of inverse of match_signature"""
- args_w, kwds_w = self.unpack()
- need_cnt = len(args_w)
- need_kwds = kwds_w.keys()
- space = self.space
- argnames, varargname, kwargname = signature
- cnt = len(argnames)
- data_args_w = data_w[:cnt]
- if varargname:
- data_w_stararg = data_w[cnt]
- cnt += 1
- else:
- data_w_stararg = space.newtuple([])
-
- unfiltered_kwds_w = {}
- if kwargname:
- data_w_starargarg = data_w[cnt]
- for w_key in space.unpackiterable(data_w_starargarg):
- key = space.str_w(w_key)
- w_value = space.getitem(data_w_starargarg, w_key)
- unfiltered_kwds_w[key] = w_value
- cnt += 1
- assert len(data_w) == cnt
-
- ndata_args_w = len(data_args_w)
- if ndata_args_w >= need_cnt:
- args_w = data_args_w[:need_cnt]
- for argname, w_arg in zip(argnames[need_cnt:], data_args_w[need_cnt:]):
- unfiltered_kwds_w[argname] = w_arg
- assert not space.is_true(data_w_stararg)
- else:
- stararg_w = space.unpackiterable(data_w_stararg)
- datalen = len(data_args_w)
- args_w = [None] * (datalen + len(stararg_w))
- for i in range(0, datalen):
- args_w[i] = data_args_w[i]
- for i in range(0, len(stararg_w)):
- args_w[i + datalen] = stararg_w[i]
- assert len(args_w) == need_cnt
-
- keywords = []
- keywords_w = []
- for key in need_kwds:
- keywords.append(key)
- keywords_w.append(unfiltered_kwds_w[key])
-
- return ArgumentsForTranslation(self.space, args_w, keywords, keywords_w)
-
- @staticmethod
- def fromshape(space, (shape_cnt, shape_keys, shape_star, shape_stst), data_w):
- args_w = data_w[:shape_cnt]
- p = end_keys = shape_cnt + len(shape_keys)
- if shape_star:
- w_star = data_w[p]
- p += 1
- else:
- w_star = None
- if shape_stst:
- w_starstar = data_w[p]
- p += 1
- else:
- w_starstar = None
- return ArgumentsForTranslation(space, args_w, list(shape_keys),
- data_w[shape_cnt:end_keys], w_star,
- w_starstar)
+ self.keywords = keywords or {}
def flatten(self):
""" Argument <-> list of w_objects together with "shape" information """
- shape_cnt, shape_keys, shape_star, shape_stst = self._rawshape()
- data_w = self.arguments_w + [self.keywords_w[self.keywords.index(key)]
- for key in shape_keys]
+ shape_cnt = len(self.arguments_w) # Number of positional args
+ shape_keys = tuple(sorted(self.keywords))
+ shape_star = self.w_stararg is not None # Flag: presence of *arg
+ shape_stst = False # Flag: presence of **kwds
+ data_w = self.arguments_w + [self.keywords[key] for key in shape_keys]
if shape_star:
data_w.append(self.w_stararg)
- if shape_stst:
- data_w.append(self.w_starstararg)
return (shape_cnt, shape_keys, shape_star, shape_stst), data_w
-
- def _rawshape(self, nextra=0):
- assert not self.combine_has_happened
- shape_cnt = len(self.arguments_w) + nextra # Number of positional args
- if self.keywords:
- shape_keys = self.keywords[:] # List of keywords (strings)
- shape_keys.sort()
- else:
- shape_keys = []
- shape_star = self.w_stararg is not None # Flag: presence of *arg
- shape_stst = self.w_starstararg is not None # Flag: presence of **kwds
- return shape_cnt, tuple(shape_keys), shape_star, shape_stst # shape_keys are sorted
-
-
-def rawshape(args, nextra=0):
- return args._rawshape(nextra)
-
-
-#
-# ArgErr family of exceptions raised in case of argument mismatch.
-# We try to give error messages following CPython's, which are very informative.
-#
-
-class ArgErr(Exception):
- def getmsg(self):
- raise NotImplementedError
-
-
-class ArgErrCount(ArgErr):
- def __init__(self, got_nargs, nkwds, signature,
- defaults_w, missing_args):
- self.signature = signature
-
- self.num_defaults = 0 if defaults_w is None else len(defaults_w)
- self.missing_args = missing_args
- self.num_args = got_nargs
- self.num_kwds = nkwds
-
- def getmsg(self):
- n = self.signature.num_argnames()
- if n == 0:
- msg = "takes no arguments (%d given)" % (
- self.num_args + self.num_kwds)
- else:
- defcount = self.num_defaults
- has_kwarg = self.signature.has_kwarg()
- num_args = self.num_args
- num_kwds = self.num_kwds
- if defcount == 0 and not self.signature.has_vararg():
- msg1 = "exactly"
- if not has_kwarg:
- num_args += num_kwds
- num_kwds = 0
- elif not self.missing_args:
- msg1 = "at most"
- else:
- msg1 = "at least"
- has_kwarg = False
- n -= defcount
- if n == 1:
- plural = ""
- else:
- plural = "s"
- if has_kwarg or num_kwds > 0:
- msg2 = " non-keyword"
- else:
- msg2 = ""
- msg = "takes %s %d%s argument%s (%d given)" % (
- msg1,
- n,
- msg2,
- plural,
- num_args)
- return msg
-
-
-class ArgErrMultipleValues(ArgErr):
- def __init__(self, argname):
- self.argname = argname
-
- def getmsg(self):
- msg = "got multiple values for keyword argument '%s'" % (
- self.argname)
- return msg
-
-
-class ArgErrUnknownKwds(ArgErr):
- def __init__(self, space, num_remainingkwds, keywords, kwds_mapping,
- keyword_names_w):
- name = ''
- self.num_kwds = num_remainingkwds
- if num_remainingkwds == 1:
- for i in range(len(keywords)):
- if i not in kwds_mapping:
- name = keywords[i]
- if name is None:
- # We'll assume it's unicode. Encode it.
- # Careful, I *think* it should not be possible to
- # get an IndexError here but you never know.
- try:
- if keyword_names_w is None:
- raise IndexError
- # note: negative-based indexing from the end
- w_name = keyword_names_w[i - len(keywords)]
- except IndexError:
- name = '?'
- else:
- w_enc = space.wrap(space.sys.defaultencoding)
- w_err = space.wrap("replace")
- w_name = space.call_method(w_name, "encode", w_enc,
- w_err)
- name = space.str_w(w_name)
- break
- self.kwd_name = name
-
- def getmsg(self):
- if self.num_kwds == 1:
- msg = "got an unexpected keyword argument '%s'" % (
- self.kwd_name)
- else:
- msg = "got %d unexpected keyword arguments" % (
- self.num_kwds)
- return msg
diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py
--- a/rpython/flowspace/bytecode.py
+++ b/rpython/flowspace/bytecode.py
@@ -36,7 +36,6 @@
code, consts, names, varnames, filename,
name, firstlineno, lnotab, freevars):
"""Initialize a new code object"""
- self.co_name = name
assert nlocals >= 0
self.co_argcount = argcount
self.co_nlocals = nlocals
diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py
--- a/rpython/flowspace/flowcontext.py
+++ b/rpython/flowspace/flowcontext.py
@@ -7,13 +7,14 @@
from rpython.tool.error import source_lines
from rpython.tool.stdlib_opcode import host_bytecode_spec
-from rpython.flowspace.argument import ArgumentsForTranslation
+from rpython.flowspace.argument import CallSpec
from rpython.flowspace.model import (Constant, Variable, Block, Link,
- c_last_exception)
+ c_last_exception, SpaceOperation)
from rpython.flowspace.framestate import (FrameState, recursively_unflatten,
recursively_flatten)
from rpython.flowspace.specialcase import (rpython_print_item,
rpython_print_newline)
+from rpython.flowspace.operation import implicit_exceptions
class FlowingError(Exception):
@@ -361,11 +362,6 @@
"peek past the bottom of the stack")
return self.locals_stack_w[index]
- def pushrevvalues(self, n, values_w): # n should be len(values_w)
- assert len(values_w) == n
- for i in range(n - 1, -1, -1):
- self.pushvalue(values_w[i])
-
def settopvalue(self, w_object, index_from_top=0):
index = self.valuestackdepth + ~index_from_top
assert index >= self.pycode.co_nlocals, (
@@ -377,16 +373,6 @@
values_w.reverse()
return values_w
- def peekvalues(self, n):
- values_w = [None] * n
- base = self.valuestackdepth - n
- while True:
- n -= 1
- if n < 0:
- break
- values_w[n] = self.locals_stack_w[base + n]
- return values_w
-
def dropvalues(self, n):
finaldepth = self.valuestackdepth - n
for n in range(finaldepth, self.valuestackdepth):
@@ -473,6 +459,17 @@
def guessbool(self, w_condition, **kwds):
return self.recorder.guessbool(self, w_condition, **kwds)
+ def do_operation(self, name, *args_w):
+ spaceop = SpaceOperation(name, args_w, Variable())
+ spaceop.offset = self.last_instr
+ self.record(spaceop)
+ return spaceop.result
+
+ def do_operation_with_implicit_exceptions(self, name, *args_w):
+ w_result = self.do_operation(name, *args_w)
+ self.handle_implicit_exceptions(implicit_exceptions.get(name))
+ return w_result
+
def handle_implicit_exceptions(self, exceptions):
"""
Catch possible exceptions implicitly.
@@ -742,7 +739,7 @@
def YIELD_VALUE(self, _, next_instr):
assert self.pycode.is_generator
w_result = self.popvalue()
- self.space.do_operation('yield', w_result)
+ self.do_operation('yield', w_result)
# XXX yield expressions not supported. This will blow up if the value
# isn't popped straightaway.
self.pushvalue(None)
@@ -753,7 +750,7 @@
def PRINT_ITEM(self, oparg, next_instr):
w_item = self.popvalue()
- w_s = self.space.do_operation('str', w_item)
+ w_s = self.do_operation('str', w_item)
self.space.appcall(rpython_print_item, w_s)
def PRINT_NEWLINE(self, oparg, next_instr):
@@ -961,26 +958,18 @@
self.pushvalue(last_val)
def call_function(self, oparg, w_star=None, w_starstar=None):
+ if w_starstar is not None:
+ raise FlowingError(self, "Dict-unpacking is not RPython")
n_arguments = oparg & 0xff
n_keywords = (oparg >> 8) & 0xff
- if n_keywords:
- keywords = [None] * n_keywords
- keywords_w = [None] * n_keywords
- while True:
- n_keywords -= 1
- if n_keywords < 0:
- break
- w_value = self.popvalue()
- w_key = self.popvalue()
- key = self.space.str_w(w_key)
- keywords[n_keywords] = key
- keywords_w[n_keywords] = w_value
- else:
- keywords = None
- keywords_w = None
+ keywords = {}
+ for _ in range(n_keywords):
+ w_value = self.popvalue()
+ w_key = self.popvalue()
+ key = self.space.str_w(w_key)
+ keywords[key] = w_value
arguments = self.popvalues(n_arguments)
- args = ArgumentsForTranslation(self.space, arguments, keywords,
- keywords_w, w_star, w_starstar)
+ args = CallSpec(arguments, keywords, w_star, w_starstar)
w_function = self.popvalue()
w_result = self.space.call_args(w_function, args)
self.pushvalue(w_result)
@@ -1017,8 +1006,9 @@
def UNPACK_SEQUENCE(self, itemcount, next_instr):
w_iterable = self.popvalue()
- items = self.space.unpackiterable(w_iterable, itemcount)
- self.pushrevvalues(itemcount, items)
+ items = self.space.unpack_sequence(w_iterable, itemcount)
+ for w_item in reversed(items):
+ self.pushvalue(w_item)
def slice(self, w_start, w_end):
w_obj = self.popvalue()
diff --git a/rpython/flowspace/objspace.py b/rpython/flowspace/objspace.py
--- a/rpython/flowspace/objspace.py
+++ b/rpython/flowspace/objspace.py
@@ -7,9 +7,9 @@
import types
from inspect import CO_NEWLOCALS
-from rpython.flowspace.argument import ArgumentsForTranslation
+from rpython.flowspace.argument import CallSpec
from rpython.flowspace.model import (Constant, Variable, WrapException,
- UnwrapException, checkgraph, SpaceOperation)
+ UnwrapException, checkgraph)
from rpython.flowspace.bytecode import HostCode
from rpython.flowspace import operation
from rpython.flowspace.flowcontext import (FlowSpaceFrame, fixeggblocks,
@@ -84,6 +84,9 @@
# objects which should keep their SomeObjectness
not_really_const = NOT_REALLY_CONST
+ def build_flow(self, func):
+ return build_flow(func, self)
+
def is_w(self, w_one, w_two):
return self.is_true(self.is_(w_one, w_two))
@@ -91,21 +94,20 @@
id = None # real version added by add_operations()
def newdict(self, module="ignored"):
- return self.do_operation('newdict')
+ return self.frame.do_operation('newdict')
def newtuple(self, args_w):
- try:
- content = [self.unwrap(w_arg) for w_arg in args_w]
- except UnwrapException:
- return self.do_operation('newtuple', *args_w)
+ if all(isinstance(w_arg, Constant) for w_arg in args_w):
+ content = [w_arg.value for w_arg in args_w]
+ return Constant(tuple(content))
else:
- return Constant(tuple(content))
+ return self.frame.do_operation('newtuple', *args_w)
def newlist(self, args_w, sizehint=None):
- return self.do_operation('newlist', *args_w)
+ return self.frame.do_operation('newlist', *args_w)
def newslice(self, w_start, w_stop, w_step):
- return self.do_operation('newslice', w_start, w_stop, w_step)
+ return self.frame.do_operation('newslice', w_start, w_stop, w_step)
def newbool(self, b):
if b:
@@ -262,59 +264,29 @@
w_type = w_instclass
return FSException(w_type, w_value)
- def build_flow(self, func):
- """
- """
- _assert_rpythonic(func)
- code = HostCode._from_code(func.func_code)
- if (code.is_generator and
- not hasattr(func, '_generator_next_method_of_')):
- graph = PyGraph(func, code)
- block = graph.startblock
- for name, w_value in zip(code.co_varnames, block.framestate.mergeable):
- if isinstance(w_value, Variable):
- w_value.rename(name)
- return bootstrap_generator(graph)
- graph = PyGraph(func, code)
- frame = self.frame = FlowSpaceFrame(self, graph, code)
- frame.build_flow()
- fixeggblocks(graph)
- checkgraph(graph)
- if code.is_generator:
- tweak_generator_graph(graph)
- return graph
+ def unpackiterable(self, w_iterable):
+ if isinstance(w_iterable, Constant):
+ l = w_iterable.value
+ return [self.wrap(x) for x in l]
+ else:
+ raise UnwrapException("cannot unpack a Variable iterable ")
- def unpackiterable(self, w_iterable, expected_length=None):
- if not isinstance(w_iterable, Variable):
+ def unpack_sequence(self, w_iterable, expected_length):
+ if isinstance(w_iterable, Constant):
l = list(self.unwrap(w_iterable))
- if expected_length is not None and len(l) != expected_length:
+ if len(l) != expected_length:
raise ValueError
return [self.wrap(x) for x in l]
- elif expected_length is None:
- raise UnwrapException("cannot unpack a Variable iterable "
- "without knowing its length")
else:
w_len = self.len(w_iterable)
w_correct = self.eq(w_len, self.wrap(expected_length))
if not self.is_true(w_correct):
e = self.exc_from_raise(self.w_ValueError, self.w_None)
raise e
- return [self.do_operation('getitem', w_iterable, self.wrap(i))
+ return [self.frame.do_operation('getitem', w_iterable, self.wrap(i))
for i in range(expected_length)]
# ____________________________________________________________
- def do_operation(self, name, *args_w):
- spaceop = SpaceOperation(name, args_w, Variable())
- spaceop.offset = self.frame.last_instr
- self.frame.record(spaceop)
- return spaceop.result
-
- def do_operation_with_implicit_exceptions(self, name, *args_w):
- w_result = self.do_operation(name, *args_w)
- self.frame.handle_implicit_exceptions(
- operation.implicit_exceptions.get(name))
- return w_result
-
def not_(self, w_obj):
return self.wrap(not self.is_true(w_obj))
@@ -325,27 +297,21 @@
pass
else:
return bool(obj)
- w_truthvalue = self.do_operation('is_true', w_obj)
+ w_truthvalue = self.frame.do_operation('is_true', w_obj)
return self.frame.guessbool(w_truthvalue)
def iter(self, w_iterable):
- try:
- iterable = self.unwrap(w_iterable)
- except UnwrapException:
- pass
- else:
+ if isinstance(w_iterable, Constant):
+ iterable = w_iterable.value
if isinstance(iterable, unrolling_iterable):
return self.wrap(iterable.get_unroller())
- w_iter = self.do_operation("iter", w_iterable)
+ w_iter = self.frame.do_operation("iter", w_iterable)
return w_iter
def next(self, w_iter):
frame = self.frame
- try:
- it = self.unwrap(w_iter)
- except UnwrapException:
- pass
- else:
+ if isinstance(w_iter, Constant):
+ it = w_iter.value
if isinstance(it, _unroller):
try:
v, next_unroller = it.step()
@@ -354,7 +320,7 @@
else:
frame.replace_in_stack(it, next_unroller)
return self.wrap(v)
- w_item = self.do_operation("next", w_iter)
+ w_item = frame.do_operation("next", w_iter)
frame.handle_implicit_exceptions([StopIteration, RuntimeError])
return w_item
@@ -363,8 +329,8 @@
if w_obj is self.frame.w_globals:
raise FlowingError(self.frame,
"Attempting to modify global variable %r." % (w_key))
- return self.do_operation_with_implicit_exceptions('setitem', w_obj,
- w_key, w_val)
+ return self.frame.do_operation_with_implicit_exceptions('setitem',
+ w_obj, w_key, w_val)
def setitem_str(self, w_obj, key, w_value):
return self.setitem(w_obj, self.wrap(key), w_value)
@@ -375,7 +341,7 @@
if w_obj in self.not_really_const:
const_w = self.not_really_const[w_obj]
if w_name not in const_w:
- return self.do_operation_with_implicit_exceptions('getattr',
+ return self.frame.do_operation_with_implicit_exceptions('getattr',
w_obj, w_name)
try:
obj = self.unwrap_for_computation(w_obj)
@@ -394,7 +360,7 @@
return self.wrap(result)
except WrapException:
pass
- return self.do_operation_with_implicit_exceptions('getattr',
+ return self.frame.do_operation_with_implicit_exceptions('getattr',
w_obj, w_name)
def isinstance_w(self, w_obj, w_type):
@@ -414,7 +380,7 @@
if w_module in self.not_really_const:
const_w = self.not_really_const[w_obj]
if w_name not in const_w:
- return self.do_operation_with_implicit_exceptions('getattr',
+ return self.frame.do_operation_with_implicit_exceptions('getattr',
w_obj, w_name)
try:
return self.wrap(getattr(w_module.value, w_name.value))
@@ -427,39 +393,42 @@
return self.call_function(w_meth, *arg_w)
def call_function(self, w_func, *args_w):
- args = ArgumentsForTranslation(self, list(args_w))
+ args = CallSpec(list(args_w))
return self.call_args(w_func, args)
def appcall(self, func, *args_w):
"""Call an app-level RPython function directly"""
w_func = self.wrap(func)
- return self.do_operation('simple_call', w_func, *args_w)
+ return self.frame.do_operation('simple_call', w_func, *args_w)
def call_args(self, w_callable, args):
- try:
- fn = self.unwrap(w_callable)
+ if isinstance(w_callable, Constant):
+ fn = w_callable.value
if hasattr(fn, "_flowspace_rewrite_directly_as_"):
fn = fn._flowspace_rewrite_directly_as_
w_callable = self.wrap(fn)
- sc = self.specialcases[fn] # TypeError if 'fn' not hashable
- except (UnwrapException, KeyError, TypeError):
- pass
+ try:
+ sc = self.specialcases[fn] # TypeError if 'fn' not hashable
+ except (KeyError, TypeError):
+ pass
+ else:
+ assert args.keywords == {}, "should not call %r with keyword arguments" % (fn,)
+ if args.w_stararg is not None:
+ args_w = args.arguments_w + self.unpackiterable(args.w_stararg)
+ else:
+ args_w = args.arguments_w
+ return sc(self, fn, args_w)
+
+ if args.keywords or isinstance(args.w_stararg, Variable):
+ shape, args_w = args.flatten()
+ w_res = self.frame.do_operation('call_args', w_callable,
+ Constant(shape), *args_w)
else:
- return sc(self, fn, args)
-
- try:
- args_w, kwds_w = args.copy().unpack()
- except UnwrapException:
- args_w, kwds_w = '?', '?'
- # NOTE: annrpython needs to know about the following two operations!
- if not kwds_w:
- # simple case
- w_res = self.do_operation('simple_call', w_callable, *args_w)
- else:
- # general case
- shape, args_w = args.flatten()
- w_res = self.do_operation('call_args', w_callable, Constant(shape),
- *args_w)
+ if args.w_stararg is not None:
+ args_w = args.arguments_w + self.unpackiterable(args.w_stararg)
+ else:
+ args_w = args.arguments_w
+ w_res = self.frame.do_operation('simple_call', w_callable, *args_w)
# maybe the call has generated an exception (any one)
# but, let's say, not if we are calling a built-in class or function
@@ -562,11 +531,34 @@
# type cannot sanely appear in flow graph,
# store operation with variable result instead
pass
- w_result = self.do_operation_with_implicit_exceptions(name, *args_w)
+ w_result = self.frame.do_operation_with_implicit_exceptions(name, *args_w)
return w_result
setattr(FlowObjSpace, name, generic_operator)
-
for (name, symbol, arity, specialnames) in operation.MethodTable:
make_op(name, arity)
+
+
+def build_flow(func, space=FlowObjSpace()):
+ """
+ Create the flow graph for the function.
+ """
+ _assert_rpythonic(func)
+ code = HostCode._from_code(func.func_code)
+ if (code.is_generator and
+ not hasattr(func, '_generator_next_method_of_')):
+ graph = PyGraph(func, code)
+ block = graph.startblock
+ for name, w_value in zip(code.co_varnames, block.framestate.mergeable):
+ if isinstance(w_value, Variable):
+ w_value.rename(name)
+ return bootstrap_generator(graph)
+ graph = PyGraph(func, code)
+ frame = space.frame = FlowSpaceFrame(space, graph, code)
+ frame.build_flow()
+ fixeggblocks(graph)
+ checkgraph(graph)
+ if code.is_generator:
+ tweak_generator_graph(graph)
+ return graph
diff --git a/rpython/flowspace/specialcase.py b/rpython/flowspace/specialcase.py
--- a/rpython/flowspace/specialcase.py
+++ b/rpython/flowspace/specialcase.py
@@ -3,22 +3,18 @@
from rpython.rlib.rarithmetic import r_uint
from rpython.rlib.objectmodel import we_are_translated
-def sc_import(space, fn, args):
- args_w, kwds_w = args.unpack()
- assert kwds_w == {}, "should not call %r with keyword arguments" % (fn,)
+def sc_import(space, fn, args_w):
assert len(args_w) > 0 and len(args_w) <= 5, 'import needs 1 to 5 arguments'
args = [space.unwrap(arg) for arg in args_w]
return space.import_name(*args)
-def sc_operator(space, fn, args):
- args_w, kwds_w = args.unpack()
- assert kwds_w == {}, "should not call %r with keyword arguments" % (fn,)
+def sc_operator(space, fn, args_w):
opname = OperationName[fn]
if len(args_w) != Arity[opname]:
if opname == 'pow' and len(args_w) == 2:
args_w = args_w + [Constant(None)]
elif opname == 'getattr' and len(args_w) == 3:
- return space.do_operation('simple_call', Constant(getattr), *args_w)
+ return space.frame.do_operation('simple_call', Constant(getattr), *args_w)
else:
raise Exception("should call %r with exactly %d arguments" % (
fn, Arity[opname]))
@@ -51,18 +47,16 @@
# _________________________________________________________________________
-def sc_r_uint(space, r_uint, args):
+def sc_r_uint(space, r_uint, args_w):
# special case to constant-fold r_uint(32-bit-constant)
# (normally, the 32-bit constant is a long, and is not allowed to
# show up in the flow graphs at all)
- args_w, kwds_w = args.unpack()
- assert not kwds_w
[w_value] = args_w
if isinstance(w_value, Constant):
return Constant(r_uint(w_value.value))
- return space.do_operation('simple_call', space.wrap(r_uint), w_value)
+ return space.frame.do_operation('simple_call', space.wrap(r_uint), w_value)
-def sc_we_are_translated(space, we_are_translated, args):
+def sc_we_are_translated(space, we_are_translated, args_w):
return Constant(True)
def sc_locals(space, locals, args):
diff --git a/rpython/flowspace/test/test_argument.py b/rpython/flowspace/test/test_argument.py
--- a/rpython/flowspace/test/test_argument.py
+++ b/rpython/flowspace/test/test_argument.py
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
import py
-from rpython.flowspace.argument import (ArgumentsForTranslation, rawshape,
- Signature)
+from rpython.flowspace.argument import Signature
class TestSignature(object):
@@ -50,277 +49,3 @@
assert x == ["a", "b", "c"]
assert y == "d"
assert z == "e"
-
-class dummy_wrapped_dict(dict):
- def __nonzero__(self):
- raise NotImplementedError
-
-class kwargsdict(dict):
- pass
-
-class DummySpace(object):
- def newtuple(self, items):
- return tuple(items)
-
- def is_true(self, obj):
- if isinstance(obj, dummy_wrapped_dict):
- return bool(dict(obj))
- return bool(obj)
-
- def fixedview(self, it):
- return list(it)
-
- def listview(self, it):
- return list(it)
-
- def unpackiterable(self, it):
- return list(it)
-
- def view_as_kwargs(self, x):
- if len(x) == 0:
- return [], []
- return None, None
-
- def newdict(self):
- return {}
-
- def newlist(self, l=[]):
- return l
-
- def setitem(self, obj, key, value):
- obj[key] = value
-
- def getitem(self, obj, key):
- return obj[key]
-
- def wrap(self, obj):
- return obj
-
- def str_w(self, s):
- return str(s)
-
- def len(self, x):
- return len(x)
-
- def int_w(self, x):
- return x
-
- def eq_w(self, x, y):
- return x == y
-
- def isinstance(self, obj, cls):
- return isinstance(obj, cls)
- isinstance_w = isinstance
-
- def exception_match(self, w_type1, w_type2):
- return issubclass(w_type1, w_type2)
-
- def call_method(self, obj, name, *args):
- method = getattr(obj, name)
- return method(*args)
-
- def type(self, obj):
- class Type:
- def getname(self, space, default='?'):
- return type(obj).__name__
- return Type()
-
-
- w_TypeError = TypeError
- w_AttributeError = AttributeError
- w_UnicodeEncodeError = UnicodeEncodeError
- w_dict = dict
- w_str = str
-
-def make_arguments_for_translation(space, args_w, keywords_w={},
- w_stararg=None, w_starstararg=None):
- return ArgumentsForTranslation(space, args_w, keywords_w.keys(),
- keywords_w.values(), w_stararg,
- w_starstararg)
-
-class TestArgumentsForTranslation(object):
-
- def test_prepend(self):
- space = DummySpace()
- args = ArgumentsForTranslation(space, ["0"])
- args1 = args.prepend("thingy")
- assert args1 is not args
- assert args1.arguments_w == ["thingy", "0"]
- assert args1.keywords is args.keywords
- assert args1.keywords_w is args.keywords_w
-
- def test_fixedunpacked(self):
- space = DummySpace()
-
- args = ArgumentsForTranslation(space, [], ["k"], [1])
- py.test.raises(ValueError, args.fixedunpack, 1)
-
- args = ArgumentsForTranslation(space, ["a", "b"])
- py.test.raises(ValueError, args.fixedunpack, 0)
- py.test.raises(ValueError, args.fixedunpack, 1)
- py.test.raises(ValueError, args.fixedunpack, 3)
- py.test.raises(ValueError, args.fixedunpack, 4)
-
- assert args.fixedunpack(2) == ['a', 'b']
-
- def test_unmatch_signature(self):
- space = DummySpace()
- args = make_arguments_for_translation(space, [1,2,3])
- sig = Signature(['a', 'b', 'c'], None, None)
- data = args.match_signature(sig, [])
- new_args = args.unmatch_signature(sig, data)
- assert args.unpack() == new_args.unpack()
-
- args = make_arguments_for_translation(space, [1])
- sig = Signature(['a', 'b', 'c'], None, None)
- data = args.match_signature(sig, [2, 3])
- new_args = args.unmatch_signature(sig, data)
- assert args.unpack() == new_args.unpack()
-
- args = make_arguments_for_translation(space, [1,2,3,4,5])
- sig = Signature(['a', 'b', 'c'], 'r', None)
- data = args.match_signature(sig, [])
- new_args = args.unmatch_signature(sig, data)
- assert args.unpack() == new_args.unpack()
-
- args = make_arguments_for_translation(space, [1], {'c': 3, 'b': 2})
- sig = Signature(['a', 'b', 'c'], None, None)
- data = args.match_signature(sig, [])
- new_args = args.unmatch_signature(sig, data)
- assert args.unpack() == new_args.unpack()
-
- args = make_arguments_for_translation(space, [1], {'c': 5})
- sig = Signature(['a', 'b', 'c'], None, None)
- data = args.match_signature(sig, [2, 3])
- new_args = args.unmatch_signature(sig, data)
- assert args.unpack() == new_args.unpack()
-
- args = make_arguments_for_translation(space, [1], {'c': 5, 'd': 7})
- sig = Signature(['a', 'b', 'c'], None, 'kw')
- py.test.raises(TypeError, args.match_signature, sig, [2, 3])
-
- def test_rawshape(self):
- space = DummySpace()
- args = make_arguments_for_translation(space, [1,2,3])
- assert rawshape(args) == (3, (), False, False)
-
- args = make_arguments_for_translation(space, [1])
- assert rawshape(args, 2) == (3, (), False, False)
-
- args = make_arguments_for_translation(space, [1,2,3,4,5])
- assert rawshape(args) == (5, (), False, False)
-
- args = make_arguments_for_translation(space, [1], {'c': 3, 'b': 2})
- assert rawshape(args) == (1, ('b', 'c'), False, False)
-
- args = make_arguments_for_translation(space, [1], {'c': 5})
- assert rawshape(args) == (1, ('c', ), False, False)
-
- args = make_arguments_for_translation(space, [1], {'c': 5, 'd': 7})
- assert rawshape(args) == (1, ('c', 'd'), False, False)
-
- args = make_arguments_for_translation(space, [1,2,3,4,5], {'e': 5, 'd': 7})
- assert rawshape(args) == (5, ('d', 'e'), False, False)
-
- args = make_arguments_for_translation(space, [], {},
- w_stararg=[1],
- w_starstararg={'c': 5, 'd': 7})
- assert rawshape(args) == (0, (), True, True)
-
- args = make_arguments_for_translation(space, [1,2], {'g': 9},
- w_stararg=[3,4,5],
- w_starstararg={'e': 5, 'd': 7})
- assert rawshape(args) == (2, ('g', ), True, True)
-
- def test_copy_and_shape(self):
- space = DummySpace()
- args = ArgumentsForTranslation(space, ['a'], ['x'], [1],
- ['w1'], {'y': 'w2'})
- args1 = args.copy()
- args.combine_if_necessary()
- assert rawshape(args1) == (1, ('x',), True, True)
-
-
- def test_flatten(self):
- space = DummySpace()
- args = make_arguments_for_translation(space, [1,2,3])
- assert args.flatten() == ((3, (), False, False), [1, 2, 3])
-
- args = make_arguments_for_translation(space, [1])
- assert args.flatten() == ((1, (), False, False), [1])
-
- args = make_arguments_for_translation(space, [1,2,3,4,5])
- assert args.flatten() == ((5, (), False, False), [1,2,3,4,5])
-
- args = make_arguments_for_translation(space, [1], {'c': 3, 'b': 2})
- assert args.flatten() == ((1, ('b', 'c'), False, False), [1, 2, 3])
-
- args = make_arguments_for_translation(space, [1], {'c': 5})
- assert args.flatten() == ((1, ('c', ), False, False), [1, 5])
-
- args = make_arguments_for_translation(space, [1], {'c': 5, 'd': 7})
- assert args.flatten() == ((1, ('c', 'd'), False, False), [1, 5, 7])
-
- args = make_arguments_for_translation(space, [1,2,3,4,5], {'e': 5, 'd': 7})
- assert args.flatten() == ((5, ('d', 'e'), False, False), [1, 2, 3, 4, 5, 7, 5])
-
- args = make_arguments_for_translation(space, [], {},
- w_stararg=[1],
- w_starstararg={'c': 5, 'd': 7})
- assert args.flatten() == ((0, (), True, True), [[1], {'c': 5, 'd': 7}])
-
- args = make_arguments_for_translation(space, [1,2], {'g': 9},
- w_stararg=[3,4,5],
- w_starstararg={'e': 5, 'd': 7})
- assert args.flatten() == ((2, ('g', ), True, True), [1, 2, 9, [3, 4, 5], {'e': 5, 'd': 7}])
-
- def test_stararg_flowspace_variable(self):
- space = DummySpace()
- var = object()
- shape = ((2, ('g', ), True, False), [1, 2, 9, var])
- args = make_arguments_for_translation(space, [1,2], {'g': 9},
- w_stararg=var)
- assert args.flatten() == shape
-
- args = ArgumentsForTranslation.fromshape(space, *shape)
- assert args.flatten() == shape
-
-
- def test_fromshape(self):
- space = DummySpace()
- shape = ((3, (), False, False), [1, 2, 3])
- args = ArgumentsForTranslation.fromshape(space, *shape)
- assert args.flatten() == shape
-
- shape = ((1, (), False, False), [1])
- args = ArgumentsForTranslation.fromshape(space, *shape)
- assert args.flatten() == shape
-
- shape = ((5, (), False, False), [1,2,3,4,5])
- args = ArgumentsForTranslation.fromshape(space, *shape)
- assert args.flatten() == shape
-
- shape = ((1, ('b', 'c'), False, False), [1, 2, 3])
- args = ArgumentsForTranslation.fromshape(space, *shape)
- assert args.flatten() == shape
-
- shape = ((1, ('c', ), False, False), [1, 5])
- args = ArgumentsForTranslation.fromshape(space, *shape)
- assert args.flatten() == shape
-
- shape = ((1, ('c', 'd'), False, False), [1, 5, 7])
- args = ArgumentsForTranslation.fromshape(space, *shape)
- assert args.flatten() == shape
-
- shape = ((5, ('d', 'e'), False, False), [1, 2, 3, 4, 5, 7, 5])
- args = ArgumentsForTranslation.fromshape(space, *shape)
- assert args.flatten() == shape
-
- shape = ((0, (), True, True), [[1], {'c': 5, 'd': 7}])
- args = ArgumentsForTranslation.fromshape(space, *shape)
- assert args.flatten() == shape
-
- shape = ((2, ('g', ), True, True), [1, 2, 9, [3, 4, 5], {'e': 5, 'd': 7}])
- args = ArgumentsForTranslation.fromshape(space, *shape)
- assert args.flatten() == shape
-
diff --git a/rpython/flowspace/test/test_framestate.py b/rpython/flowspace/test/test_framestate.py
--- a/rpython/flowspace/test/test_framestate.py
+++ b/rpython/flowspace/test/test_framestate.py
@@ -6,9 +6,6 @@
from rpython.flowspace.pygraph import PyGraph
class TestFrameState:
- def setup_class(cls):
- cls.space = FlowObjSpace()
-
def getframe(self, func):
try:
func = func.im_func
@@ -16,7 +13,7 @@
pass
code = HostCode._from_code(func.func_code)
graph = PyGraph(func, code)
- frame = FlowSpaceFrame(self.space, graph, code)
+ frame = FlowSpaceFrame(FlowObjSpace(), graph, code)
# hack the frame
frame.setstate(graph.startblock.framestate)
frame.locals_stack_w[frame.pycode.co_nlocals-1] = Constant(None)
diff --git a/rpython/flowspace/test/test_generator.py b/rpython/flowspace/test/test_generator.py
--- a/rpython/flowspace/test/test_generator.py
+++ b/rpython/flowspace/test/test_generator.py
@@ -1,5 +1,5 @@
from rpython.conftest import option
-from rpython.flowspace.objspace import FlowObjSpace
+from rpython.flowspace.objspace import build_flow
from rpython.flowspace.model import Variable
from rpython.flowspace.generator import (make_generatoriterator_class,
replace_graph_with_bootstrap, get_variable_names, attach_next_method)
@@ -67,7 +67,7 @@
yield n
yield n
#
- graph = FlowObjSpace().build_flow(func)
+ graph = build_flow(func)
if option.view:
graph.show()
block = graph.startblock
@@ -93,8 +93,7 @@
yield n + 1
z -= 10
#
- space = FlowObjSpace()
- graph = space.build_flow(f)
+ graph = build_flow(f)
GeneratorIterator = make_generatoriterator_class(graph)
replace_graph_with_bootstrap(GeneratorIterator, graph)
func1 = attach_next_method(GeneratorIterator, graph)
@@ -104,12 +103,12 @@
assert func1._generator_next_method_of_ is GeneratorIterator
assert hasattr(GeneratorIterator, 'next')
#
- graph_next = space.build_flow(GeneratorIterator.next.im_func)
+ graph_next = build_flow(GeneratorIterator.next.im_func)
join_blocks(graph_next)
if option.view:
graph_next.show()
#
- graph1 = space.build_flow(func1)
+ graph1 = build_flow(func1)
if option.view:
graph1.show()
@@ -119,7 +118,7 @@
yield n + 1
z -= 10
#
- graph = FlowObjSpace().build_flow(f)
+ graph = build_flow(f)
if option.view:
graph.show()
block = graph.startblock
diff --git a/rpython/flowspace/test/test_objspace.py b/rpython/flowspace/test/test_objspace.py
--- a/rpython/flowspace/test/test_objspace.py
+++ b/rpython/flowspace/test/test_objspace.py
@@ -5,7 +5,7 @@
from rpython.flowspace.model import Constant, mkentrymap, c_last_exception
from rpython.translator.simplify import simplify_graph
-from rpython.flowspace.objspace import FlowObjSpace
+from rpython.flowspace.objspace import build_flow
from rpython.flowspace.flowcontext import FlowingError, FlowSpaceFrame
from rpython.conftest import option
from rpython.tool.stdlib_opcode import host_bytecode_spec
@@ -34,7 +34,7 @@
except AttributeError:
pass
#name = func.func_name
- graph = self.space.build_flow(func, **kwds)
+ graph = build_flow(func, **kwds)
graph.source = inspect.getsource(func)
self.show(graph)
return graph
@@ -43,9 +43,6 @@
if option.view:
graph.show()
- def setup_class(cls):
- cls.space = FlowObjSpace()
-
def all_operations(self, graph):
result = {}
for node in graph.iterblocks():
@@ -702,6 +699,35 @@
for op in block.operations:
assert not op.opname == "call_args"
+ def test_starstar_call(self):
+ """Check that CALL_FUNCTION_KW and CALL_FUNCTION_VAR_KW raise a
+ useful error.
+ """
+ def g(a, b, c):
+ return a*b*c
+ def f1():
+ return g(**{'a':0})
+ with py.test.raises(FlowingError) as excinfo:
+ graph = self.codetest(f1)
+ assert 'Dict-unpacking' in str(excinfo.value)
+ def f2():
+ return g(*(0,), **{'c':3})
+ with py.test.raises(FlowingError) as excinfo:
+ graph = self.codetest(f2)
+ assert 'Dict-unpacking' in str(excinfo.value)
+
+ def test_kwarg_call(self):
+ def g(x):
+ return x
+ def f():
+ return g(x=2)
+ graph = self.codetest(f)
+ for block in graph.iterblocks():
+ for op in block.operations:
+ assert op.opname == "call_args"
+ assert op.args == map(Constant,
+ [g, (0, ('x',), False, False), 2])
+
def test_catch_importerror_1(self):
def f():
try:
@@ -740,7 +766,7 @@
def test_relative_import(self):
def f():
- from ..test.test_objspace import FlowObjSpace
+ from ..objspace import build_flow
# Check that the function works in Python
assert f() is None
self.codetest(f)
diff --git a/rpython/rlib/test/test_nonconst.py b/rpython/rlib/test/test_nonconst.py
--- a/rpython/rlib/test/test_nonconst.py
+++ b/rpython/rlib/test/test_nonconst.py
@@ -4,7 +4,6 @@
from rpython.rlib.nonconst import NonConstant
-from rpython.flowspace.objspace import FlowObjSpace
from rpython.annotator.annrpython import RPythonAnnotator
from rpython.conftest import option
from rpython.annotator.model import SomeInstance
@@ -13,20 +12,20 @@
def nonconst_f():
a = NonConstant(3)
return a
-
+
a = RPythonAnnotator()
s = a.build_types(nonconst_f, [])
assert s.knowntype is int
assert not hasattr(s, 'const')
#rtyper = a.translator.buildrtyper(type_system="ootype")
#rtyper.specialize()
-
+
def test_nonconst_list():
def nonconst_l():
a = NonConstant([1, 2, 3])
return a[0]
-
+
a = RPythonAnnotator()
s = a.build_types(nonconst_l, [])
More information about the pypy-commit
mailing list