[pypy-svn] r8836 - in pypy/dist/pypy: annotation interpreter translator translator/test
arigo at codespeak.net
arigo at codespeak.net
Fri Feb 4 13:41:54 CET 2005
Author: arigo
Date: Thu Feb 3 18:13:45 2005
New Revision: 8836
Modified:
pypy/dist/pypy/annotation/bookkeeper.py
pypy/dist/pypy/interpreter/argument.py
pypy/dist/pypy/translator/genc.h
pypy/dist/pypy/translator/genpyrex.py
pypy/dist/pypy/translator/test/snippet.py
pypy/dist/pypy/translator/test/test_ctrans.py
pypy/dist/pypy/translator/test/test_pyrextrans.py
Log:
- modified the Argument class to unpack ** arguments lazily too, just like *
arguments. This allows the flow object space to handle ** arguments in
calls.
- updated genc.h accordingly to accept and decode ** arguments between the C
functions.
- removed the skip_on_error() in test_ctrans -- these ones mask real errors,
and skipping should be restricted on "no C compiler found" kind of errors.
- genpyrex.py probably works, but writing a test for that is slightly messy.
Still, a proto-test found a previous bug in genpyrex.py.
Modified: pypy/dist/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/dist/pypy/annotation/bookkeeper.py (original)
+++ pypy/dist/pypy/annotation/bookkeeper.py Thu Feb 3 18:13:45 2005
@@ -226,7 +226,7 @@
elif func.func_code.co_flags & CO_VARARGS:
# calls to *arg functions: create one version per number of args
- assert not args.kwds_w, (
+ assert not args.has_keywords(), (
"keyword forbidden in calls to *arg functions")
nbargs = len(args.arguments_w)
if args.w_stararg is not None:
Modified: pypy/dist/pypy/interpreter/argument.py
==============================================================================
--- pypy/dist/pypy/interpreter/argument.py (original)
+++ pypy/dist/pypy/interpreter/argument.py Thu Feb 3 18:13:45 2005
@@ -22,25 +22,7 @@
self.arguments_w = list(args_w)
self.kwds_w = kwds_w.copy()
self.w_stararg = w_stararg
- if w_starstararg is not None:
- # unlike the * argument we unpack the ** argument immediately.
- # maybe we could allow general mappings?
- if not space.is_true(space.isinstance(w_starstararg, space.w_dict)):
- raise OperationError(space.w_TypeError,
- space.wrap("the keywords must be "
- "a dictionary"))
- for w_key in space.unpackiterable(w_starstararg):
- try:
- key = space.str_w(w_key)
- except OperationError:
- raise OperationError(space.w_TypeError,
- space.wrap("keywords must be strings"))
- if key in self.kwds_w:
- raise OperationError(self.space.w_TypeError,
- self.space.wrap("got multiple values "
- "for keyword argument "
- "'%s'" % key))
- self.kwds_w[key] = space.getitem(w_starstararg, w_key)
+ self.w_starstararg = w_starstararg
def frompacked(space, w_args=None, w_kwds=None):
"""Convenience static method to build an Arguments
@@ -49,6 +31,11 @@
frompacked = staticmethod(frompacked)
def __repr__(self):
+ if self.w_starstararg is not None:
+ return 'Arguments(%s, %s, %s, %s)' % (self.arguments_w,
+ self.kwds_w,
+ self.w_stararg,
+ self.w_starstararg)
if self.w_stararg is None:
if not self.kwds_w:
return 'Arguments(%s)' % (self.arguments_w,)
@@ -63,22 +50,52 @@
def unpack(self):
"Return a ([w1,w2...], {'kw':w3...}) pair."
+ # --- unpack the * argument now ---
if self.w_stararg is not None:
self.arguments_w += self.space.unpackiterable(self.w_stararg)
self.w_stararg = None
+ # --- unpack the ** argument now ---
+ if self.w_starstararg is not None:
+ space = self.space
+ w_starstararg = self.w_starstararg
+ # maybe we could allow general mappings?
+ if not space.is_true(space.isinstance(w_starstararg, space.w_dict)):
+ raise OperationError(space.w_TypeError,
+ space.wrap("the keywords must be "
+ "a dictionary"))
+ d = self.kwds_w.copy() # don't change the original yet,
+ # in case something goes wrong
+ for w_key in space.unpackiterable(w_starstararg):
+ try:
+ key = space.str_w(w_key)
+ except OperationError:
+ raise OperationError(space.w_TypeError,
+ space.wrap("keywords must be strings"))
+ if key in d:
+ raise OperationError(self.space.w_TypeError,
+ self.space.wrap("got multiple values "
+ "for keyword argument "
+ "'%s'" % key))
+ d[key] = space.getitem(w_starstararg, w_key)
+ self.kwds_w = d
+ self.w_starstararg = None
return self.arguments_w, self.kwds_w
def prepend(self, w_firstarg):
"Return a new Arguments with a new argument inserted first."
args = Arguments(self.space, [w_firstarg] + self.arguments_w,
- self.kwds_w, self.w_stararg)
+ self.kwds_w, self.w_stararg, self.w_starstararg)
args.blind_arguments = self.blind_arguments + 1
return args
+ def has_keywords(self):
+ return self.kwds_w or (self.w_starstararg is not None and
+ self.space.is_true(self.w_starstararg))
+
def fixedunpack(self, argcount):
"""The simplest argument parsing: get the 'argcount' arguments,
or raise a real ValueError if the length is wrong."""
- if self.kwds_w:
+ if self.has_keywords():
raise ValueError, "no keyword arguments expected"
if len(self.arguments_w) > argcount:
raise ValueError, "too many arguments (%d expected)" % argcount
@@ -143,6 +160,10 @@
pass
else:
self.unpack() # sets self.w_stararg to None
+ # always unpack the ** arguments
+ if self.w_starstararg is not None:
+ self.unpack()
+
args_w = self.arguments_w
kwds_w = self.kwds_w
@@ -198,21 +219,32 @@
shape_cnt = len(self.arguments_w) # Number of positional args
shape_keys = self.kwds_w.keys() # List of keywords (strings)
shape_star = self.w_stararg is not None # Flag: presence of *arg
+ shape_stst = self.w_starstararg is not None # Flag: presence of **kwds
data_w = self.arguments_w + [self.kwds_w[key] for key in shape_keys]
if shape_star:
data_w.append(self.w_stararg)
- return (shape_cnt, tuple(shape_keys), shape_star), data_w
+ if shape_stst:
+ data_w.append(self.w_starstararg)
+ return (shape_cnt, tuple(shape_keys), shape_star, shape_stst), data_w
- def fromshape(space, (shape_cnt, shape_keys, shape_star), data_w):
+ def fromshape(space, (shape_cnt,shape_keys,shape_star,shape_stst), data_w):
args_w = data_w[:shape_cnt]
+ p = shape_cnt
kwds_w = {}
for i in range(len(shape_keys)):
- kwds_w[shape_keys[i]] = data_w[shape_cnt+i]
+ kwds_w[shape_keys[i]] = data_w[p]
+ p += 1
if shape_star:
- w_star = data_w[-1]
+ w_star = data_w[p]
+ p += 1
else:
w_star = None
- return Arguments(space, args_w, kwds_w, w_star)
+ if shape_stst:
+ w_starstar = data_w[p]
+ p += 1
+ else:
+ w_starstar = None
+ return Arguments(space, args_w, kwds_w, w_star, w_starstar)
fromshape = staticmethod(fromshape)
# XXX the "shape" tuple should be considered as a black box from
# other code, but translator/genc.h examines it.
Modified: pypy/dist/pypy/translator/genc.h
==============================================================================
--- pypy/dist/pypy/translator/genc.h (original)
+++ pypy/dist/pypy/translator/genc.h Thu Feb 3 18:13:45 2005
@@ -470,19 +470,21 @@
PyObject* o;
PyObject* key;
PyObject* t2;
- int i, nargs, nkwds, nvarargs, starflag;
+ int i, nargs, nkwds, nvarargs, starflag, starstarflag;
va_list vargs;
if (!PyTuple_Check(shape) ||
- PyTuple_GET_SIZE(shape) != 3 ||
+ PyTuple_GET_SIZE(shape) != 4 ||
!PyInt_Check(PyTuple_GET_ITEM(shape, 0)) ||
!PyTuple_Check(PyTuple_GET_ITEM(shape, 1)) ||
- !PyInt_Check(PyTuple_GET_ITEM(shape, 2))) {
+ !PyInt_Check(PyTuple_GET_ITEM(shape, 2)) ||
+ !PyInt_Check(PyTuple_GET_ITEM(shape, 3))) {
Py_FatalError("in genc.h: invalid 'shape' argument");
}
nargs = PyInt_AS_LONG(PyTuple_GET_ITEM(shape, 0));
nkwds = PyTuple_GET_SIZE(PyTuple_GET_ITEM(shape, 1));
starflag = PyInt_AS_LONG(PyTuple_GET_ITEM(shape, 2));
+ starstarflag = PyInt_AS_LONG(PyTuple_GET_ITEM(shape, 3));
va_start(vargs, shape);
t = PyTuple_New(nargs);
@@ -516,6 +518,22 @@
if (t == NULL)
goto finally;
}
+ if (starstarflag) {
+ int len1, len2, len3;
+ o = va_arg(vargs, PyObject *);
+ len1 = PyDict_Size(d);
+ len2 = PyDict_Size(o);
+ if (len1 < 0 || len2 < 0)
+ goto finally;
+ if (PyDict_Update(d, o) < 0)
+ goto finally;
+ len3 = PyDict_Size(d);
+ if (len1 + len2 != len3) {
+ PyErr_SetString(PyExc_TypeError,
+ "genc.h: duplicate keyword arguments");
+ goto finally;
+ }
+ }
va_end(vargs);
result = PyObject_Call(callable, t, d);
Modified: pypy/dist/pypy/translator/genpyrex.py
==============================================================================
--- pypy/dist/pypy/translator/genpyrex.py (original)
+++ pypy/dist/pypy/translator/genpyrex.py Thu Feb 3 18:13:45 2005
@@ -114,10 +114,12 @@
shape = self.op.args[1].value
args = Arguments.fromshape(None, shape, a[2:])
lst = args.arguments_w[:]
- for key, value in args.kwds_w:
+ for key, value in args.kwds_w.items():
lst.append("%s=%s" % (key, value))
if args.w_stararg is not None:
lst.append("*%s" % args.w_stararg)
+ if args.w_starstararg is not None:
+ lst.append("**%s" % args.w_starstararg)
return "%s = %s(%s)" % (self.resultname, a[0], ", ".join(lst))
def op_simple_call(self):
Modified: pypy/dist/pypy/translator/test/snippet.py
==============================================================================
--- pypy/dist/pypy/translator/test/snippet.py (original)
+++ pypy/dist/pypy/translator/test/snippet.py Thu Feb 3 18:13:45 2005
@@ -540,6 +540,9 @@
def call_with_keyword(z):
return default_args(-20, z=z)
+def call_very_complex(z, args, kwds):
+ return default_args(-20, z=z, *args, **kwds)
+
def powerset(setsize=int):
"""Powerset
Modified: pypy/dist/pypy/translator/test/test_ctrans.py
==============================================================================
--- pypy/dist/pypy/translator/test/test_ctrans.py (original)
+++ pypy/dist/pypy/translator/test/test_ctrans.py Thu Feb 3 18:13:45 2005
@@ -15,12 +15,14 @@
class TestNoTypeCGenTestCase:
objspacename = 'flow'
- def build_cfunc(self, func):
+ def build_cfunc(self, func, *morefuncs):
try: func = func.im_func
except AttributeError: pass
t = Translator(func)
+ for fn in morefuncs:
+ t.getflowgraph(fn)
t.simplify()
- return py.test.skip_on_error(t.ccompile)
+ return t.ccompile()
def test_simple_func(self):
cfunc = self.build_cfunc(snippet.simple_func)
@@ -153,6 +155,13 @@
call_with_keyword = self.build_cfunc(snippet.call_with_keyword)
assert call_with_keyword(100) == 82
+ def test_call_very_complex(self):
+ call_very_complex = self.build_cfunc(snippet.call_very_complex,
+ snippet.default_args)
+ assert call_very_complex(5, (3,), {}) == -12
+ assert call_very_complex(5, (), {'y': 3}) == -12
+ raises(TypeError, call_very_complex, 5, (3,), {'y': 4})
+
def test_finallys(self):
finallys = self.build_cfunc(snippet.finallys)
assert finallys(['hello']) == 8
@@ -196,7 +205,7 @@
argstypelist.append(spec)
a = t.annotate(argstypelist)
a.simplify()
- return py.test.skip_on_error(t.ccompile)
+ return t.ccompile()
def test_set_attr(self):
set_attr = self.getcompiled(snippet.set_attr)
Modified: pypy/dist/pypy/translator/test/test_pyrextrans.py
==============================================================================
--- pypy/dist/pypy/translator/test/test_pyrextrans.py (original)
+++ pypy/dist/pypy/translator/test/test_pyrextrans.py Thu Feb 3 18:13:45 2005
@@ -91,6 +91,15 @@
assert sand(0, 6) == "no"
assert sand(0, 0) == "no"
+# -- the following test doesn't really work right now --
+## def test_call_very_complex(self):
+## call_very_complex = self.build_cfunc(snippet.call_very_complex,
+## snippet.default_args)
+## assert call_very_complex(5, (3,), {}) == -12
+## assert call_very_complex(5, (), {'y': 3}) == -12
+## py.test.raises("call_very_complex(5, (3,), {'y': 4})")
+
+
class TestTypedTestCase:
def getcompiled(self, func):
More information about the Pypy-commit
mailing list