[pypy-svn] r68349 - in pypy/branch/improve-kwd-args/pypy: interpreter interpreter/test module/__builtin__ module/pypyjit objspace/flow

pedronis at codespeak.net pedronis at codespeak.net
Mon Oct 12 19:29:27 CEST 2009


Author: pedronis
Date: Mon Oct 12 19:29:24 2009
New Revision: 68349

Modified:
   pypy/branch/improve-kwd-args/pypy/interpreter/argument.py
   pypy/branch/improve-kwd-args/pypy/interpreter/pyframe.py
   pypy/branch/improve-kwd-args/pypy/interpreter/pyopcode.py
   pypy/branch/improve-kwd-args/pypy/interpreter/test/test_argument.py
   pypy/branch/improve-kwd-args/pypy/interpreter/test/test_function.py
   pypy/branch/improve-kwd-args/pypy/module/__builtin__/functional.py
   pypy/branch/improve-kwd-args/pypy/module/pypyjit/interp_jit.py
   pypy/branch/improve-kwd-args/pypy/objspace/flow/flowcontext.py
   pypy/branch/improve-kwd-args/pypy/objspace/flow/objspace.py
Log:
(pedronis, cfbolz): progress and regress all mixed up in a blob of confusion:
- make the argument parsing not rely on dicts, which is JIT-friendlier
- at the moment Arguments objects are not immutable any more, which is a bad
  idea


Modified: pypy/branch/improve-kwd-args/pypy/interpreter/argument.py
==============================================================================
--- pypy/branch/improve-kwd-args/pypy/interpreter/argument.py	(original)
+++ pypy/branch/improve-kwd-args/pypy/interpreter/argument.py	Mon Oct 12 19:29:24 2009
@@ -3,6 +3,7 @@
 """
 
 from pypy.interpreter.error import OperationError
+from pypy.rlib.debug import make_sure_not_resized
 
 class Arguments(object):
     """
@@ -13,16 +14,21 @@
 
     ###  Construction  ###
 
-    def __init__(self, space, args_w, kwds_w=None,
+    def __init__(self, space, args_w, keywords=None, keywords_w=None,
                  w_stararg=None, w_starstararg=None):
         self.space = space
         assert isinstance(args_w, list)
         self.arguments_w = args_w
-        from pypy.rlib.debug import make_sure_not_resized
+        self.keywords = keywords
+        self.keywords_w = keywords_w
+        if keywords is not None:
+            assert keywords_w is not None
+            assert len(keywords_w) == len(keywords)
+            make_sure_not_resized(self.keywords)
+            make_sure_not_resized(self.keywords_w)
+
         make_sure_not_resized(self.arguments_w)
-        self.kwds_w = kwds_w
-        self.w_stararg = w_stararg
-        self.w_starstararg = w_starstararg
+        self._combine_wrapped(w_stararg, w_starstararg)
 
     @staticmethod
     def factory(space, args_w, kwds_w=None,
@@ -31,65 +37,52 @@
                          w_stararg, w_starstararg)
 
     def num_args(self): # only used in module/__builtin__/interp_classobj.py
-        self._unpack()
         return len(self.arguments_w)
 
     def num_kwds(self): # only used in module/__builtin__/interp_classobj.py
-        self._unpack()
-        return len(self.kwds_w)
+        return len(self.keywords)
         
     def __repr__(self):
         """ NOT_RPYTHON """
-        if self.w_starstararg is not None:
-            return '%s(%s, %s, %s, %s)' % (self.__class__,
-                                           self.arguments_w,
-                                           self.kwds_w,
-                                           self.w_stararg,
-                                           self.w_starstararg)
-        if self.w_stararg is None:
-            if not self.kwds_w:
-                return '%s(%s)' % (self.__class__, self.arguments_w,)
-            else:
-                return '%s(%s, %s)' % (self.__class__, self.arguments_w,
-                                       self.kwds_w)
+        if not self.keywords:
+            return '%s(%s)' % (self.__class__, self.arguments_w,)
         else:
             return '%s(%s, %s, %s)' % (self.__class__, self.arguments_w,
-                                       self.kwds_w, self.w_stararg)
+                                       self.keywords, self.keywords_w)
 
 
     ###  Manipulation  ###
 
     def unpack(self): # used often
         "Return a ([w1,w2...], {'kw':w3...}) pair."
-        self._unpack()
-        return self.arguments_w, self.kwds_w
+        # XXX may want to change that later
+        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 prepend(self, w_firstarg): # used often
         "Return a new Arguments with a new argument inserted first."
         return self.factory(self.space, [w_firstarg] + self.arguments_w,
-                            self.kwds_w, self.w_stararg, self.w_starstararg)
+                            self.keywords, self.keywords_w)
             
-    def _unpack(self):
-        "unpack the *arg and **kwd into w_arguments and kwds_w"
-        # --- unpack the * argument now ---
-        if self.w_stararg is not None:
+    def _combine_wrapped(self, w_stararg, w_starstararg):
+        "unpack the *arg and **kwd into arguments_w and keywords_w"
+        # unpack the * arguments 
+        if w_stararg is not None:
             self.arguments_w = (self.arguments_w +
-                                self.space.unpackiterable(self.w_stararg))
-            self.w_stararg = None
-        # --- unpack the ** argument now ---
-        if self.kwds_w is None:
-            self.kwds_w = {}
-        if self.w_starstararg is not None:
+                                self.space.viewiterable(w_stararg))
+        # unpack the ** arguments
+        if 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("argument after ** must be "
                                                 "a dictionary"))
-            # don't change the original yet,
-            # in case something goes wrong               
-            d = self.kwds_w.copy()
+            keywords_w = [None] * space.int_w(space.len(w_starstararg))
+            keywords = [None] * space.int_w(space.len(w_starstararg))
+            i = 0
             for w_key in space.unpackiterable(w_starstararg):
                 try:
                     key = space.str_w(w_key)
@@ -98,14 +91,20 @@
                         raise
                     raise OperationError(space.w_TypeError,
                                          space.wrap("keywords must be strings"))
-                if key in d:
+                if self.keywords and key in self.keywords:
                     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
+                keywords[i] = key
+                keywords_w[i] = space.getitem(w_starstararg, w_key)
+                i += 1
+            if self.keywords is None:
+                self.keywords = keywords
+                self.keywords_w = keywords_w
+            else:
+                self.keywords += keywords
+                self.keywords_w += keywords_w
 
     def fixedunpack(self, argcount):
         # used by ./objspace/std/typeobject.py
@@ -113,16 +112,10 @@
         # ./annotation/description.py
         """The simplest argument parsing: get the 'argcount' arguments,
         or raise a real ValueError if the length is wrong."""
-        if bool(self.kwds_w) or (self.w_starstararg is not None and
-                                     self.space.is_true(self.w_starstararg)):
+        if self.keywords:
             raise ValueError, "no keyword arguments expected"
         if len(self.arguments_w) > argcount:
             raise ValueError, "too many arguments (%d expected)" % argcount
-        if self.w_stararg is not None:
-            self.arguments_w = (self.arguments_w +
-                                self.space.viewiterable(self.w_stararg,
-                                         argcount - len(self.arguments_w)))
-            self.w_stararg = None
         elif len(self.arguments_w) < argcount:
             raise ValueError, "not enough arguments (%d expected)" % argcount
         return self.arguments_w
@@ -135,15 +128,7 @@
         "Return the first argument for inspection."
         if self.arguments_w:
             return self.arguments_w[0]
-        if self.w_stararg is None:
-            return None
-        w_iter = self.space.iter(self.w_stararg)
-        try:
-            return self.space.next(w_iter)
-        except OperationError, e:
-            if not e.match(self.space, self.space.w_StopIteration):
-                raise
-            return None
+        return None
         
     ###  Parsing for function calls  ###
 
@@ -173,27 +158,15 @@
         else:
             upfront = 0
         
-        if self.w_stararg is not None:
-            # There is a case where we don't have to unpack() a w_stararg:
-            # if it matches exactly a *arg in the signature.
-            if (len(self.arguments_w) + upfront == co_argcount and
-                has_vararg and
-                self.space.is_w(self.space.type(self.w_stararg),
-                                self.space.w_tuple)):
-                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
+        assert args_w is not None, "tried to match arguments again"
         num_args = len(args_w)
 
-        kwds_w = self.kwds_w
+        keywords = self.keywords
+        keywords_w = self.keywords_w
         num_kwds = 0
-        if kwds_w is not None:
-            num_kwds = len(kwds_w)
+        if keywords is not None:
+            num_kwds = len(keywords)
 
         avail = num_args + upfront
 
@@ -208,29 +181,36 @@
                 scope_w[i + input_argcount] = args_w[i]
             input_argcount += take
 
-        # check that no keyword argument conflicts with these
-        # note that for this purpose we ignore the first blindargs,
-        # which were put into place by prepend().  This way, keywords do
-        # not conflict with the hidden extra argument bound by methods.
-        if kwds_w and input_argcount > blindargs:
-            for name in argnames[blindargs:input_argcount]:
-                if name in kwds_w:
-                    raise ArgErrMultipleValues(name)
-
-        remainingkwds_w = self.kwds_w
+        # the code assumes that keywords can potentially be large, but that
+        # argnames is typically not too large
+        num_remainingkwds = num_kwds
+        if keywords:
+            for i in range(num_kwds):
+                name = keywords[i]
+                try:
+                    j = argnames.index(name)
+                except ValueError:
+                    continue
+                if j < input_argcount:
+                    # check that no keyword argument conflicts with these note
+                    # that for this purpose we ignore the first blindargs,
+                    # which were put into place by prepend().  This way,
+                    # keywords do not conflict with the hidden extra argument
+                    # bound by methods.
+                    if blindargs <= j:
+                        raise ArgErrMultipleValues(name)
+                else:
+                    assert scope_w[j] is None
+                    scope_w[j] = keywords_w[i]
+                    keywords[i] = None # mark as used
+                    num_remainingkwds -= 1
         missing = 0
         if input_argcount < co_argcount:
-            if remainingkwds_w is None:
-                remainingkwds_w = {}
-            else:
-                remainingkwds_w = remainingkwds_w.copy()            
-            # not enough args, fill in kwargs or defaults if exists
             def_first = co_argcount - len(defaults_w)
             for i in range(input_argcount, co_argcount):
                 name = argnames[i]
-                if name in remainingkwds_w:
-                    scope_w[i] = remainingkwds_w[name]
-                    del remainingkwds_w[name]
+                if scope_w[i] is not None:
+                    pass
                 elif i >= def_first:
                     scope_w[i] = defaults_w[i-def_first]
                 else:
@@ -239,23 +219,19 @@
                     # keyword arguments, which will be checked for below.
                     missing += 1
 
-        
         # collect extra positional arguments into the *vararg
         if has_vararg:
-            if self.w_stararg is None:   # common case
-                args_left = co_argcount - upfront
-                if args_left < 0:  # check required by rpython
-                    assert extravarargs is not None
-                    starargs_w = extravarargs
-                    if num_args:
-                        starargs_w = starargs_w + args_w
-                elif num_args > args_left:
-                    starargs_w = args_w[args_left:]
-                else:
-                    starargs_w = []
-                scope_w[co_argcount] = self.space.newtuple(starargs_w)
-            else:      # shortcut for the non-unpack() case above
-                scope_w[co_argcount] = self.w_stararg
+            args_left = co_argcount - upfront
+            if args_left < 0:  # check required by rpython
+                assert extravarargs is not None
+                starargs_w = extravarargs
+                if num_args:
+                    starargs_w = starargs_w + args_w
+            elif num_args > args_left:
+                starargs_w = args_w[args_left:]
+            else:
+                starargs_w = []
+            scope_w[co_argcount] = self.space.newtuple(starargs_w)
         elif avail > co_argcount:
             raise ArgErrCount(avail, num_kwds,
                               (co_argcount, has_vararg, has_kwarg),
@@ -264,18 +240,23 @@
         # collect extra keyword arguments into the **kwarg
         if has_kwarg:
             w_kwds = self.space.newdict()
-            if remainingkwds_w:
-                for key, w_value in remainingkwds_w.items():
-                    self.space.setitem(w_kwds, self.space.wrap(key), w_value)
+            if num_remainingkwds:
+                for i in range(len(keywords)):
+                    key = keywords[i]
+                    if key is not None:
+                        self.space.setitem(w_kwds, self.space.wrap(key), keywords_w[i])
             scope_w[co_argcount + has_vararg] = w_kwds
-        elif remainingkwds_w:
-            raise ArgErrUnknownKwds(remainingkwds_w)
+        elif num_remainingkwds:
+            raise ArgErrUnknownKwds(num_remainingkwds, keywords)
 
         if missing:
             raise ArgErrCount(avail, num_kwds,
                               (co_argcount, has_vararg, has_kwarg),
                               defaults_w, missing)
 
+        self.arguments_w = None
+        self.keywords = None
+        self.keywords_w = None
         return co_argcount + has_vararg + has_kwarg
     
 
@@ -358,14 +339,11 @@
             space.setitem(w_kwds, space.wrap(key), w_value)
         return w_args, w_kwds
 
+    @staticmethod
     def fromshape(space, (shape_cnt,shape_keys,shape_star,shape_stst), data_w):
         # used by geninterped code
         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[p]
-            p += 1
+        p = end_keys = shape_cnt + len(shape_keys)
         if shape_star:
             w_star = data_w[p]
             p += 1
@@ -376,27 +354,64 @@
             p += 1
         else:
             w_starstar = None
-        return Arguments(space, args_w, kwds_w, w_star, w_starstar)
-    fromshape = staticmethod(fromshape)
+        return Arguments(space, args_w, list(shape_keys),
+                         data_w[shape_cnt:end_keys], w_star,
+                          w_starstar)
+
+    def copy(self):
+        if self.keywords is None:
+            keywords = None
+            keywords_w = None
+        else:
+            keywords = self.keywords[:]
+            keywords_w = self.keywords_w[:]
+        return Arguments(self.space, self.arguments_w[:], keywords,
+                         keywords_w)
 
 
-    def normalize(self):
-        """Return an instance of the Arguments class.  (Instances of other
-        classes may not be suitable for long-term storage or multiple
-        usage.)  Also force the type and validity of the * and ** arguments
-        to be checked now.
-        """
-        args_w, kwds_w = self.unpack()
-        return Arguments(self.space, args_w, kwds_w)
+class ArgumentsForTranslation(Arguments):
+    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
+        Arguments.__init__(self, space, args_w, keywords, keywords_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
 
-class ArgumentsForTranslation(Arguments):
     @staticmethod
     def factory(space, args_w, kwds_w=None,
                 w_stararg=None, w_starstararg=None):
         return ArgumentsForTranslation(space, args_w, kwds_w,
                                        w_stararg, w_starstararg)
 
+    def copy(self):
+        if self.keywords is None:
+            keywords = None
+            keywords_w = None
+        else:
+            keywords = self.keywords[:]
+            keywords_w = self.keywords_w[:]
+        return ArgumentsForTranslation(self.space, self.arguments_w[:], keywords,
+                                       keywords_w, self.w_stararg,
+                                       self.w_starstararg)
+
+    def _match_signature(self, w_firstarg, scope_w, argnames, has_vararg=False,
+                         has_kwarg=False, defaults_w=[], blindargs=0):
+        self.combine_if_necessary()
+        # _match_signature is destructive
+        return Arguments._match_signature(
+               self, w_firstarg, scope_w, argnames, has_vararg, has_kwarg,
+               defaults_w, blindargs)
+
+    def unpack(self):
+        self.combine_if_necessary()
+        return Arguments.unpack(self)
+
     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.
@@ -444,27 +459,26 @@
                 args_w[i + datalen] = stararg_w[i]
             assert len(args_w) == need_cnt
             
-        kwds_w = {}
+        keywords = []
+        keywords_w = []
         for key in need_kwds:
-            kwds_w[key] = unfiltered_kwds_w[key]
+            keywords.append(key)
+            keywords_w.append(unfiltered_kwds_w[key])
                     
-        return ArgumentsForTranslation(self.space, args_w, kwds_w)
+        return ArgumentsForTranslation(self.space, args_w, keywords, keywords_w)
 
     @staticmethod
     def frompacked(space, w_args=None, w_kwds=None):
         raise NotImplementedError("go away")
     
+    @staticmethod
     def fromshape(space, (shape_cnt,shape_keys,shape_star,shape_stst), data_w):
         # used by
         # ./rpython/callparse.py
         # ./rpython/rbuiltin.py
         # ./annotation/bookkeeper.py
         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[p]
-            p += 1
+        p = end_keys = shape_cnt + len(shape_keys)
         if shape_star:
             w_star = data_w[p]
             p += 1
@@ -475,14 +489,16 @@
             p += 1
         else:
             w_starstar = None
-        return ArgumentsForTranslation(space, args_w, kwds_w, w_star, w_starstar)
-    fromshape = staticmethod(fromshape)
+        return ArgumentsForTranslation(space, args_w, list(shape_keys),
+                                       data_w[shape_cnt:end_keys], w_star,
+                                       w_starstar)
 
     def flatten(self):
         # used by ./objspace/flow/objspace.py
         """ 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.kwds_w[key] for key in shape_keys]
+        data_w = self.arguments_w + [self.keywords_w[self.keywords.index(key)]
+                                         for key in shape_keys]
         if shape_star:
             data_w.append(self.w_stararg)
         if shape_stst:
@@ -490,9 +506,10 @@
         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.kwds_w:
-            shape_keys = self.kwds_w.keys()           # List of keywords (strings)
+        if self.keywords:
+            shape_keys = self.keywords[:]                # List of keywords (strings)
             shape_keys.sort()
         else:
             shape_keys = []
@@ -581,11 +598,14 @@
 
 class ArgErrUnknownKwds(ArgErr):
 
-    def __init__(self, kwds_w):
+    def __init__(self, num_remainingkwds, keywords):
         self.kwd_name = ''
-        self.num_kwds = len(kwds_w)
-        if self.num_kwds == 1:
-            self.kwd_name = kwds_w.keys()[0]
+        self.num_kwds = num_remainingkwds
+        if num_remainingkwds == 1:
+            for kwd_name in keywords:
+                if kwd_name is not None:
+                    self.kwd_name = kwd_name
+                    break
 
     def getmsg(self, fnname):
         if self.num_kwds == 1:

Modified: pypy/branch/improve-kwd-args/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/branch/improve-kwd-args/pypy/interpreter/pyframe.py	(original)
+++ pypy/branch/improve-kwd-args/pypy/interpreter/pyframe.py	Mon Oct 12 19:29:24 2009
@@ -184,17 +184,6 @@
         self.valuestackdepth = hint(depth, promote=True)
         return w_object
 
-    def popstrdictvalues(self, n):
-        dic_w = {}
-        while True:
-            n -= 1
-            if n < 0:
-                break
-            w_value = self.popvalue()
-            w_key   = self.popvalue()
-            key = self.space.str_w(w_key)
-            dic_w[key] = w_value
-        return dic_w
 
     # we need two popvalues that return different data types:
     # one in case we want list another in case of tuple
@@ -282,8 +271,8 @@
     def make_arguments(self, nargs):
         return Arguments(self.space, self.peekvalues(nargs))
 
-    def argument_factory(self, arguments, keywords, w_star, w_starstar):
-        return Arguments(self.space, arguments, keywords, w_star, w_starstar)
+    def argument_factory(self, arguments, keywords, keywords_w, w_star, w_starstar):
+        return Arguments(self.space, arguments, keywords, keywords_w, w_star, w_starstar)
 
     @jit.dont_look_inside
     def descr__reduce__(self, space):

Modified: pypy/branch/improve-kwd-args/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/branch/improve-kwd-args/pypy/interpreter/pyopcode.py	(original)
+++ pypy/branch/improve-kwd-args/pypy/interpreter/pyopcode.py	Mon Oct 12 19:29:24 2009
@@ -9,7 +9,6 @@
 from pypy.interpreter.baseobjspace import UnpackValueError, Wrappable
 from pypy.interpreter import gateway, function, eval
 from pypy.interpreter import pyframe, pytraceback
-from pypy.interpreter.argument import Arguments
 from pypy.interpreter.pycode import PyCode
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.rlib.objectmodel import we_are_translated
@@ -896,11 +895,24 @@
     
         n_arguments = oparg & 0xff
         n_keywords = (oparg>>8) & 0xff
-        keywords = None
         if n_keywords:
-            keywords = f.popstrdictvalues(n_keywords)
+            keywords = [None] * n_keywords
+            keywords_w = [None] * n_keywords
+            dic_w = {}
+            while True:
+                n_keywords -= 1
+                if n_keywords < 0:
+                    break
+                w_value = f.popvalue()
+                w_key   = f.popvalue()
+                key = f.space.str_w(w_key)
+                keywords[n_keywords] = key
+                keywords_w[n_keywords] = w_value
+        else:
+            keywords = None
+            keywords_w = None
         arguments = f.popvalues(n_arguments)
-        args = f.argument_factory(arguments, keywords, w_star, w_starstar)
+        args = f.argument_factory(arguments, keywords, keywords_w, w_star, w_starstar)
         w_function  = f.popvalue()
         if we_are_jitted():
             w_result = f.space.call_args(w_function, args)

Modified: pypy/branch/improve-kwd-args/pypy/interpreter/test/test_argument.py
==============================================================================
--- pypy/branch/improve-kwd-args/pypy/interpreter/test/test_argument.py	(original)
+++ pypy/branch/improve-kwd-args/pypy/interpreter/test/test_argument.py	Mon Oct 12 19:29:24 2009
@@ -11,6 +11,9 @@
     def is_true(self, obj):
         return bool(obj)
 
+    def viewiterable(self, it):
+        return list(it)
+
     def unpackiterable(self, it):
         return list(it)
 
@@ -29,6 +32,12 @@
     def str_w(self, s):
         return str(s)
 
+    def len(self, x):
+        return len(x)
+
+    def int_w(self, x):
+        return x
+
     def isinstance(self, obj, cls):
         return isinstance(obj, cls)
 
@@ -47,23 +56,31 @@
         args._match_signature(None, l, [])
         assert len(l) == 0
         l = [None, None]
+        args = Arguments(space, [])
         py.test.raises(ArgErr, args._match_signature, None, l, ["a"])
+        args = Arguments(space, [])
         py.test.raises(ArgErr, args._match_signature, None, l, ["a"],
                        has_vararg=True)
+        args = Arguments(space, [])
         l = [None]
         args._match_signature(None, l, ["a"], defaults_w=[1])
         assert l == [1]
+        args = Arguments(space, [])
         l = [None]
         args._match_signature(None, l, [], has_vararg=True)
         assert l == [()]
+        args = Arguments(space, [])
         l = [None]
         args._match_signature(None, l, [], has_kwarg=True)
         assert l == [{}]
+        args = Arguments(space, [])
         l = [None, None]
         py.test.raises(ArgErr, args._match_signature, 41, l, [])
+        args = Arguments(space, [])
         l = [None]
         args._match_signature(1, l, ["a"])
         assert l == [1]
+        args = Arguments(space, [])
         l = [None]
         args._match_signature(1, l, [], has_vararg=True)
         assert l == [(1,)]
@@ -73,29 +90,37 @@
         values = [4, 5, 6, 7]
         for havefirstarg in [0, 1]:
             for i in range(len(values)-havefirstarg):
-                args = values[havefirstarg:i+havefirstarg]
+                arglist = values[havefirstarg:i+havefirstarg]
                 starargs = tuple(values[i+havefirstarg:])
                 if havefirstarg:
                     firstarg = values[0]
                 else:
                     firstarg = None
-                args = Arguments(space, args, w_stararg=starargs)
+                args = Arguments(space, arglist, w_stararg=starargs)
                 l = [None, None, None, None]
                 args._match_signature(firstarg, l, ["a", "b", "c", "d"])
                 assert l == [4, 5, 6, 7]
+                args = Arguments(space, arglist, w_stararg=starargs)
                 l = [None, None, None, None, None, None]
                 py.test.raises(ArgErr, args._match_signature, firstarg, l, ["a"])
+                args = Arguments(space, arglist, w_stararg=starargs)
+                l = [None, None, None, None, None, None]
                 py.test.raises(ArgErr, args._match_signature, firstarg, l, ["a", "b", "c", "d", "e"])
+                args = Arguments(space, arglist, w_stararg=starargs)
+                l = [None, None, None, None, None, None]
                 py.test.raises(ArgErr, args._match_signature, firstarg, l, ["a", "b", "c", "d", "e"],
                                has_vararg=True)
                 l = [None, None, None, None, None]
+                args = Arguments(space, arglist, w_stararg=starargs)
                 args._match_signature(firstarg, l, ["a", "b", "c", "d", "e"], defaults_w=[1])
                 assert l == [4, 5, 6, 7, 1]
                 for j in range(len(values)):
                     l = [None] * (j + 1)
+                    args = Arguments(space, arglist, w_stararg=starargs)
                     args._match_signature(firstarg, l, ["a", "b", "c", "d", "e"][:j], has_vararg=True)
                     assert l == values[:j] + [tuple(values[j:])]
                 l = [None, None, None, None, None]
+                args = Arguments(space, arglist, w_stararg=starargs)
                 args._match_signature(firstarg, l, ["a", "b", "c", "d"], has_kwarg=True)
                 assert l == [4, 5, 6, 7, {}]
 
@@ -104,24 +129,33 @@
         for i in range(3):
             kwds = [("c", 3)]
             kwds_w = dict(kwds[:i])
+            keywords = kwds_w.keys()
+            keywords_w = kwds_w.values()
             w_kwds = dict(kwds[i:])
             if i == 2:
                 w_kwds = None
-            args = Arguments(space, [1, 2], kwds_w, w_starstararg=w_kwds)
+            assert len(keywords) == len(keywords_w)
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
             l = [None, None, None]
             args._match_signature(None, l, ["a", "b", "c"], defaults_w=[4])
             assert l == [1, 2, 3]
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
             l = [None, None, None, None]
             args._match_signature(None, l, ["a", "b", "b1", "c"], defaults_w=[4, 5])
             assert l == [1, 2, 4, 3]
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
             l = [None, None, None, None]
             args._match_signature(None, l, ["a", "b", "c", "d"], defaults_w=[4, 5])
             assert l == [1, 2, 3, 5]
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
             l = [None, None, None, None]
             py.test.raises(ArgErr, args._match_signature, None, l,
                            ["c", "b", "a", "d"], defaults_w=[4, 5])
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+            l = [None, None, None, None]
             py.test.raises(ArgErr, args._match_signature, None, l,
                            ["a", "b", "c1", "d"], defaults_w=[4, 5])
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
             l = [None, None, None]
             args._match_signature(None, l, ["a", "b"], has_kwarg=True)
             assert l == [1, 2, {'c': 3}]
@@ -131,26 +165,26 @@
         kwds = [("c", 3), ('d', 4)]
         for i in range(4):
             kwds_w = dict(kwds[:i])
+            keywords = kwds_w.keys()
+            keywords_w = kwds_w.values()
             w_kwds = dict(kwds[i:])
             if i == 3:
                 w_kwds = None
-            args = Arguments(space, [1, 2], kwds_w, w_starstararg=w_kwds)
+            args = Arguments(space, [1, 2], keywords, keywords_w, w_starstararg=w_kwds)
             l = [None, None, None, None]
             args._match_signature(None, l, ["a", "b", "c"], has_kwarg=True)
             assert l == [1, 2, 3, {'d': 4}]
 
     def test_duplicate_kwds(self):
         space = DummySpace()
-        args = Arguments(space, [], {"a": 1}, w_starstararg={"a": 2})
-        excinfo = py.test.raises(OperationError, args._match_signature, None,
-                                 [None], [], has_kwarg=True)
+        excinfo = py.test.raises(OperationError, Arguments, space, [], ["a"],
+                                 [1], w_starstararg={"a": 2})
         assert excinfo.value.w_type is TypeError
 
     def test_starstararg_wrong_type(self):
         space = DummySpace()
-        args = Arguments(space, [], {"a": 1}, w_starstararg="hello")
-        excinfo = py.test.raises(OperationError, args._match_signature, None,
-                                 [None], [], has_kwarg=True)
+        excinfo = py.test.raises(OperationError, Arguments, space, [], ["a"],
+                                 [1], w_starstararg="hello")
         assert excinfo.value.w_type is TypeError
 
     def test_unwrap_error(self):
@@ -163,14 +197,12 @@
                 raise OperationError(ValueError, None)
             return str(w)
         space.str_w = str_w
-        args = Arguments(space, [], {"a": 1}, w_starstararg={None: 1})
-        excinfo = py.test.raises(OperationError, args._match_signature, None,
-                                 [None], [], has_kwarg=True)
+        excinfo = py.test.raises(OperationError, Arguments, space, [],
+                                 ["a"], [1], w_starstararg={None: 1})
         assert excinfo.value.w_type is TypeError
         assert excinfo.value.w_value is not None
-        args = Arguments(space, [], {"a": 1}, w_starstararg={valuedummy: 1})
-        excinfo = py.test.raises(OperationError, args._match_signature, None,
-                                 [None], [], has_kwarg=True)
+        excinfo = py.test.raises(OperationError, Arguments, space, [],
+                                 ["a"], [1], w_starstararg={valuedummy: 1})
         assert excinfo.value.w_type is ValueError
         assert excinfo.value.w_value is None
 
@@ -180,142 +212,153 @@
         kwds = [("a", 3), ('b', 4)]
         for i in range(4):
             kwds_w = dict(kwds[:i])
+            keywords = kwds_w.keys()
+            keywords_w = kwds_w.values()
             w_kwds = dict(kwds[i:])
             if i == 3:
                 w_kwds = None
-            args = Arguments(space, [1, 2], kwds_w, w_starstararg=w_kwds)
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:],
+                             w_starstararg=w_kwds)
             l = [None, None, None]
             args._match_signature(None, l, ["a", "b"], has_kwarg=True, blindargs=2)
             assert l == [1, 2, {'a':3, 'b': 4}]
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:],
+                             w_starstararg=w_kwds)
+            l = [None, None, None]
             py.test.raises(ArgErrUnknownKwds, args._match_signature, None, l,
                            ["a", "b"], blindargs=2)
 
 
+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_unmatch_signature(self):
         space = DummySpace()
-        args = ArgumentsForTranslation(space, [1,2,3])
+        args = make_arguments_for_translation(space, [1,2,3])
         sig = (['a', 'b', 'c'], None, None)
-        data = args.match_signature(sig, [])
+        data = args.copy().match_signature(sig, [])
         new_args = args.unmatch_signature(sig, data)
         assert args.unpack() == new_args.unpack()
 
-        args = ArgumentsForTranslation(space, [1])
+        args = make_arguments_for_translation(space, [1])
         sig = (['a', 'b', 'c'], None, None)
-        data = args.match_signature(sig, [2, 3])
+        data = args.copy().match_signature(sig, [2, 3])
         new_args = args.unmatch_signature(sig, data)
         assert args.unpack() == new_args.unpack()
 
-        args = ArgumentsForTranslation(space, [1,2,3,4,5])
+        args = make_arguments_for_translation(space, [1,2,3,4,5])
         sig = (['a', 'b', 'c'], 'r', None)
-        data = args.match_signature(sig, [])
+        data = args.copy().match_signature(sig, [])
         new_args = args.unmatch_signature(sig, data)
         assert args.unpack() == new_args.unpack()
 
-        args = ArgumentsForTranslation(space, [1], {'c': 3, 'b': 2})
+        args = make_arguments_for_translation(space, [1], {'c': 3, 'b': 2})
         sig = (['a', 'b', 'c'], None, None)
-        data = args.match_signature(sig, [])
+        data = args.copy().match_signature(sig, [])
         new_args = args.unmatch_signature(sig, data)
         assert args.unpack() == new_args.unpack()
 
-        args = ArgumentsForTranslation(space, [1], {'c': 5})
+        args = make_arguments_for_translation(space, [1], {'c': 5})
         sig = (['a', 'b', 'c'], None, None)
-        data = args.match_signature(sig, [2, 3])
+        data = args.copy().match_signature(sig, [2, 3])
         new_args = args.unmatch_signature(sig, data)
         assert args.unpack() == new_args.unpack()
 
-        args = ArgumentsForTranslation(space, [1], {'c': 5, 'd': 7})
+        args = make_arguments_for_translation(space, [1], {'c': 5, 'd': 7})
         sig = (['a', 'b', 'c'], None, 'kw')
-        data = args.match_signature(sig, [2, 3])
+        data = args.copy().match_signature(sig, [2, 3])
         new_args = args.unmatch_signature(sig, data)
         assert args.unpack() == new_args.unpack()
 
-        args = ArgumentsForTranslation(space, [1,2,3,4,5], {'e': 5, 'd': 7})
+        args = make_arguments_for_translation(space, [1,2,3,4,5], {'e': 5, 'd': 7})
         sig = (['a', 'b', 'c'], 'r', 'kw')
-        data = args.match_signature(sig, [2, 3])
+        data = args.copy().match_signature(sig, [2, 3])
         new_args = args.unmatch_signature(sig, data)
         assert args.unpack() == new_args.unpack()
 
-        args = ArgumentsForTranslation(space, [], {},
+        args = make_arguments_for_translation(space, [], {},
                                        w_stararg=[1],
                                        w_starstararg={'c': 5, 'd': 7})
         sig = (['a', 'b', 'c'], None, 'kw')
-        data = args.match_signature(sig, [2, 3])
+        data = args.copy().match_signature(sig, [2, 3])
         new_args = args.unmatch_signature(sig, data)
         assert args.unpack() == new_args.unpack()
 
-        args = ArgumentsForTranslation(space, [1,2], {'g': 9},
+        args = make_arguments_for_translation(space, [1,2], {'g': 9},
                                        w_stararg=[3,4,5],
                                        w_starstararg={'e': 5, 'd': 7})
         sig = (['a', 'b', 'c'], 'r', 'kw')
-        data = args.match_signature(sig, [2, 3])
+        data = args.copy().match_signature(sig, [2, 3])
         new_args = args.unmatch_signature(sig, data)
         assert args.unpack() == new_args.unpack()
 
     def test_rawshape(self):
         space = DummySpace()
-        args = ArgumentsForTranslation(space, [1,2,3])
+        args = make_arguments_for_translation(space, [1,2,3])
         assert rawshape(args) == (3, (), False, False)
 
-        args = ArgumentsForTranslation(space, [1])
+        args = make_arguments_for_translation(space, [1])
         assert rawshape(args, 2) == (3, (), False, False)
 
-        args = ArgumentsForTranslation(space, [1,2,3,4,5])
+        args = make_arguments_for_translation(space, [1,2,3,4,5])
         assert rawshape(args) == (5, (), False, False)
 
-        args = ArgumentsForTranslation(space, [1], {'c': 3, 'b': 2})
+        args = make_arguments_for_translation(space, [1], {'c': 3, 'b': 2})
         assert rawshape(args) == (1, ('b', 'c'), False, False)
 
-        args = ArgumentsForTranslation(space, [1], {'c': 5})
+        args = make_arguments_for_translation(space, [1], {'c': 5})
         assert rawshape(args) == (1, ('c', ), False, False)
 
-        args = ArgumentsForTranslation(space, [1], {'c': 5, 'd': 7})
+        args = make_arguments_for_translation(space, [1], {'c': 5, 'd': 7})
         assert rawshape(args) == (1, ('c', 'd'), False, False)
 
-        args = ArgumentsForTranslation(space, [1,2,3,4,5], {'e': 5, 'd': 7})
+        args = make_arguments_for_translation(space, [1,2,3,4,5], {'e': 5, 'd': 7})
         assert rawshape(args) == (5, ('d', 'e'), False, False)
 
-        args = ArgumentsForTranslation(space, [], {},
+        args = make_arguments_for_translation(space, [], {},
                                        w_stararg=[1],
                                        w_starstararg={'c': 5, 'd': 7})
         assert rawshape(args) == (0, (), True, True)
 
-        args = ArgumentsForTranslation(space, [1,2], {'g': 9},
+        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_flatten(self):
         space = DummySpace()
-        args = ArgumentsForTranslation(space, [1,2,3])
+        args = make_arguments_for_translation(space, [1,2,3])
         assert args.flatten() == ((3, (), False, False), [1, 2, 3])
 
-        args = ArgumentsForTranslation(space, [1])
+        args = make_arguments_for_translation(space, [1])
         assert args.flatten() == ((1, (), False, False), [1])
 
-        args = ArgumentsForTranslation(space, [1,2,3,4,5])
+        args = make_arguments_for_translation(space, [1,2,3,4,5])
         assert args.flatten() == ((5, (), False, False), [1,2,3,4,5])
 
-        args = ArgumentsForTranslation(space, [1], {'c': 3, 'b': 2})
+        args = make_arguments_for_translation(space, [1], {'c': 3, 'b': 2})
         assert args.flatten() == ((1, ('b', 'c'), False, False), [1, 2, 3])
 
-        args = ArgumentsForTranslation(space, [1], {'c': 5})
+        args = make_arguments_for_translation(space, [1], {'c': 5})
         assert args.flatten() == ((1, ('c', ), False, False), [1, 5])
 
-        args = ArgumentsForTranslation(space, [1], {'c': 5, 'd': 7})
+        args = make_arguments_for_translation(space, [1], {'c': 5, 'd': 7})
         assert args.flatten() == ((1, ('c', 'd'), False, False), [1, 5, 7])
 
-        args = ArgumentsForTranslation(space, [1,2,3,4,5], {'e': 5, 'd': 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 = ArgumentsForTranslation(space, [], {},
+        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 = ArgumentsForTranslation(space, [1,2], {'g': 9},
+        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}])
@@ -324,7 +367,7 @@
         space = DummySpace()
         var = object()
         shape = ((2, ('g', ), True, False), [1, 2, 9, var])
-        args = ArgumentsForTranslation(space, [1,2], {'g': 9},
+        args = make_arguments_for_translation(space, [1,2], {'g': 9},
                                        w_stararg=var)
         assert args.flatten() == shape
 

Modified: pypy/branch/improve-kwd-args/pypy/interpreter/test/test_function.py
==============================================================================
--- pypy/branch/improve-kwd-args/pypy/interpreter/test/test_function.py	(original)
+++ pypy/branch/improve-kwd-args/pypy/interpreter/test/test_function.py	Mon Oct 12 19:29:24 2009
@@ -480,20 +480,20 @@
         w_meth1 = descr_function_get(space, func, obj1, space.type(obj1))
         meth1 = space.unwrap(w_meth1)
         assert isinstance(meth1, Method)
-        assert meth1.call_args(args) == obj1
+        assert meth1.call_args(args.copy()) == obj1
         # Check method returned from method.__get__()
         # --- meth1 is already bound so meth1.__get__(*) is meth1.
         w_meth2 = meth1.descr_method_get(obj2, space.type(obj2))
         meth2 = space.unwrap(w_meth2)
         assert isinstance(meth2, Method)
-        assert meth2.call_args(args) == obj1
+        assert meth2.call_args(args.copy()) == obj1
         # Check method returned from unbound_method.__get__()
         w_meth3 = descr_function_get(space, func, None, space.type(obj2))
         meth3 = space.unwrap(w_meth3)
         w_meth4 = meth3.descr_method_get(obj2, space.w_None)
         meth4 = space.unwrap(w_meth4)
         assert isinstance(meth4, Method)
-        assert meth4.call_args(args) == obj2
+        assert meth4.call_args(args.copy()) == obj2
         # Check method returned from unbound_method.__get__()
         # --- with an incompatible class
         w_meth5 = meth3.descr_method_get(space.wrap('hello'), space.w_str)

Modified: pypy/branch/improve-kwd-args/pypy/module/__builtin__/functional.py
==============================================================================
--- pypy/branch/improve-kwd-args/pypy/module/__builtin__/functional.py	(original)
+++ pypy/branch/improve-kwd-args/pypy/module/__builtin__/functional.py	Mon Oct 12 19:29:24 2009
@@ -108,6 +108,7 @@
         compare = space.gt
     else:
         compare = space.lt
+    # XXXXXXXXX
     args, kwargs = arguments.unpack()
     if len(args) > 1:
         w_sequence = space.newtuple(args)
@@ -120,9 +121,7 @@
         w_key = kwargs["key"]
     except KeyError:
         w_key = None
-    else:
-        del kwargs["key"]
-    if kwargs:
+    if len(kwargs) != 1:
         msg = "%s() got unexpected keyword argument" % (implementation_of,)
         raise OperationError(space.w_TypeError, space.wrap(msg))
     w_iter = space.iter(w_sequence)

Modified: pypy/branch/improve-kwd-args/pypy/module/pypyjit/interp_jit.py
==============================================================================
--- pypy/branch/improve-kwd-args/pypy/module/pypyjit/interp_jit.py	(original)
+++ pypy/branch/improve-kwd-args/pypy/module/pypyjit/interp_jit.py	Mon Oct 12 19:29:24 2009
@@ -103,6 +103,7 @@
         * set_param(name=value, ...)            # as keyword arguments
         * set_param("name=value,name=value")    # as a user-supplied string
     '''
+    # XXXXXXXXX
     args_w, kwds_w = args.unpack()
     if len(args_w) > 1:
         msg = ("set_param() takes at most 1 non-keyword argument, %d given"

Modified: pypy/branch/improve-kwd-args/pypy/objspace/flow/flowcontext.py
==============================================================================
--- pypy/branch/improve-kwd-args/pypy/objspace/flow/flowcontext.py	(original)
+++ pypy/branch/improve-kwd-args/pypy/objspace/flow/flowcontext.py	Mon Oct 12 19:29:24 2009
@@ -397,5 +397,5 @@
 class FlowSpaceFrame(pyframe.PyFrame):
     def make_arguments(self, nargs):
         return ArgumentsForTranslation(self.space, self.peekvalues(nargs))
-    def argument_factory(self, arguments, keywords, w_star, w_starstar):
-        return ArgumentsForTranslation(self.space, arguments, keywords, w_star, w_starstar)
+    def argument_factory(self, *args):
+        return ArgumentsForTranslation(self.space, *args)

Modified: pypy/branch/improve-kwd-args/pypy/objspace/flow/objspace.py
==============================================================================
--- pypy/branch/improve-kwd-args/pypy/objspace/flow/objspace.py	(original)
+++ pypy/branch/improve-kwd-args/pypy/objspace/flow/objspace.py	Mon Oct 12 19:29:24 2009
@@ -370,7 +370,7 @@
             return sc(self, fn, args)
 
         try:
-            args_w, kwds_w = args.unpack()
+            args_w, kwds_w = args.copy().unpack()
         except UnwrapException:
             args_w, kwds_w = '?', '?'
         # NOTE: annrpython needs to know about the following two operations!



More information about the Pypy-commit mailing list