[pypy-svn] r68436 - pypy/trunk/pypy/interpreter
cfbolz at codespeak.net
cfbolz at codespeak.net
Wed Oct 14 14:55:34 CEST 2009
Author: cfbolz
Date: Wed Oct 14 14:55:33 2009
New Revision: 68436
Added:
pypy/trunk/pypy/interpreter/argument.py.merge.tmp
- copied, changed from r68434, pypy/trunk/pypy/interpreter/argument.py
Log:
merging of svn+ssh://codespeak.net/svn/pypy/branch/improve-kwd-args/pypy/interpreter/argument.py
revisions 68277 to 68434:
------------------------------------------------------------------------
r68403 | cfbolz | 2009-10-13 23:22:02 +0200 (Tue, 13 Oct 2009) | 2 lines
fix annotation
------------------------------------------------------------------------
r68401 | cfbolz | 2009-10-13 22:46:56 +0200 (Tue, 13 Oct 2009) | 3 lines
(cfbolz, pedronis around): invent a beautiful Signature object instead of a
measly tuple.
------------------------------------------------------------------------
r68378 | pedronis | 2009-10-13 15:25:09 +0200 (Tue, 13 Oct 2009) | 2 lines
(cfbolz, pedronis): write unit tests for the error productions. aren't we nice.
------------------------------------------------------------------------
r68377 | pedronis | 2009-10-13 14:39:06 +0200 (Tue, 13 Oct 2009) | 2 lines
(cfbolz, pedronis): improve the silly guy
------------------------------------------------------------------------
r68376 | pedronis | 2009-10-13 14:36:52 +0200 (Tue, 13 Oct 2009) | 3 lines
(cfbolz, pedronis) improve test coverage, kill some rarely used methods
------------------------------------------------------------------------
r68366 | cfbolz | 2009-10-13 12:19:10 +0200 (Tue, 13 Oct 2009) | 2 lines
fix translation
------------------------------------------------------------------------
r68365 | pedronis | 2009-10-13 12:06:57 +0200 (Tue, 13 Oct 2009) | 3 lines
(cfbolz, pedronis) fixes and cleanups
------------------------------------------------------------------------
r68364 | cfbolz | 2009-10-13 12:01:43 +0200 (Tue, 13 Oct 2009) | 2 lines
fix repr
------------------------------------------------------------------------
r68354 | cfbolz | 2009-10-12 22:49:53 +0200 (Mon, 12 Oct 2009) | 2 lines
fix geninterp to no longer use fromshape
------------------------------------------------------------------------
r68353 | cfbolz | 2009-10-12 22:23:56 +0200 (Mon, 12 Oct 2009) | 2 lines
make Arguments immutable again and fix variaous breakages
------------------------------------------------------------------------
r68349 | pedronis | 2009-10-12 19:29:24 +0200 (Mon, 12 Oct 2009) | 5 lines
(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
------------------------------------------------------------------------
r68332 | pedronis | 2009-10-12 14:57:53 +0200 (Mon, 12 Oct 2009) | 2 lines
(pedronis, cfbolz): more tests, this time for the interfaces that the translation toolchain uses
------------------------------------------------------------------------
r68330 | pedronis | 2009-10-12 10:54:14 +0200 (Mon, 12 Oct 2009) | 3 lines
(cfbolz, pedronis) fix failures
------------------------------------------------------------------------
r68288 | pedronis | 2009-10-09 18:34:40 +0200 (Fri, 09 Oct 2009) | 3 lines
(cfbolz, pedronis) fix some breakage, time to go home
------------------------------------------------------------------------
r68284 | pedronis | 2009-10-09 17:52:29 +0200 (Fri, 09 Oct 2009) | 4 lines
(pedronis, cfbolz): make a subclass of Arguments, ArgumentsForTranslation,
which is used only in the translation toolchain (flow space, annotator, rtyper
to be precise).
------------------------------------------------------------------------
r68283 | pedronis | 2009-10-09 17:13:59 +0200 (Fri, 09 Oct 2009) | 4 lines
(pedronis, cfbolz): reorder methods a bit to group those used only by the
translation toolchain. annotate with use places a bit all methods. kill
has_keywords.
------------------------------------------------------------------------
r68280 | pedronis | 2009-10-09 16:50:58 +0200 (Fri, 09 Oct 2009) | 2 lines
(pedronis, cfbolz): kill the now useless abstract base class
------------------------------------------------------------------------
r68278 | pedronis | 2009-10-09 16:43:11 +0200 (Fri, 09 Oct 2009) | 2 lines
(cfbolz, pedronis): a branch where we want to refactor the Arguments class for fun and profit.
------------------------------------------------------------------------
Copied: pypy/trunk/pypy/interpreter/argument.py.merge.tmp (from r68434, pypy/trunk/pypy/interpreter/argument.py)
==============================================================================
--- pypy/trunk/pypy/interpreter/argument.py (original)
+++ pypy/trunk/pypy/interpreter/argument.py.merge.tmp Wed Oct 14 14:55:33 2009
@@ -3,190 +3,80 @@
"""
from pypy.interpreter.error import OperationError
+from pypy.rlib.debug import make_sure_not_resized
+from pypy.rlib.jit import purefunction
-class AbstractArguments:
- def parse_into_scope(self, w_firstarg,
- scope_w, fnname, signature, defaults_w=[]):
- """Parse args and kwargs to initialize a frame
- according to the signature of code object.
- Store the argumentvalues into scope_w.
- scope_w must be big enough for signature.
- """
- argnames, varargname, kwargname = signature
- has_vararg = varargname is not None
- has_kwarg = kwargname is not None
- try:
- return self._match_signature(w_firstarg,
- scope_w, argnames, has_vararg,
- has_kwarg, defaults_w, 0)
- except ArgErr, e:
- raise OperationError(self.space.w_TypeError,
- self.space.wrap(e.getmsg(fnname)))
+class Signature(object):
+ _immutable_ = True
+ _immutable_fields_ = ["argnames[*]"]
+ __slots__ = ("argnames", "varargname", "kwargname")
+
+ def __init__(self, argnames, varargname=None, kwargname=None):
+ self.argnames = argnames
+ self.varargname = varargname
+ self.kwargname = kwargname
- def _parse(self, w_firstarg, signature, defaults_w, blindargs=0):
- """Parse args and kwargs according to the signature of a code object,
- or raise an ArgErr in case of failure.
- """
- argnames, varargname, kwargname = signature
- scopelen = len(argnames)
- has_vararg = varargname is not None
- has_kwarg = kwargname is not None
- if has_vararg:
- scopelen += 1
- if has_kwarg:
- scopelen += 1
- scope_w = [None] * scopelen
- self._match_signature(w_firstarg, scope_w, argnames, has_vararg, has_kwarg, defaults_w, blindargs)
- return scope_w
-
- def parse(self, fnname, signature, defaults_w=[], blindargs=0):
- """Parse args and kwargs to initialize a frame
- according to the signature of code object.
- """
- try:
- return self._parse(None, signature, defaults_w, blindargs)
- except ArgErr, e:
- raise OperationError(self.space.w_TypeError,
- self.space.wrap(e.getmsg(fnname)))
-
- # xxx have only this one
- def parse_obj(self, w_firstarg,
- fnname, signature, defaults_w=[], blindargs=0):
- """Parse args and kwargs to initialize a frame
- according to the signature of code object.
- """
+ @purefunction
+ def find_argname(self, name):
try:
- return self._parse(w_firstarg, signature, defaults_w, blindargs)
- except ArgErr, e:
- raise OperationError(self.space.w_TypeError,
- self.space.wrap(e.getmsg(fnname)))
-
- def frompacked(space, w_args=None, w_kwds=None):
- """Convenience static method to build an Arguments
- from a wrapped sequence and a wrapped dictionary."""
- return Arguments(space, [], w_stararg=w_args, w_starstararg=w_kwds)
- frompacked = staticmethod(frompacked)
-
- def topacked(self):
- """Express the Argument object as a pair of wrapped w_args, w_kwds."""
- space = self.space
- args_w, kwds_w = self.unpack()
- w_args = space.newtuple(args_w)
- w_kwds = space.newdict()
- for key, w_value in kwds_w.items():
- space.setitem(w_kwds, space.wrap(key), w_value)
- return w_args, w_kwds
-
- 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[p]
- p += 1
- 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 Arguments(space, args_w, kwds_w, w_star, w_starstar)
- fromshape = staticmethod(fromshape)
-
- 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.
- """
- return self._parse(None, signature, defaults_w)
+ 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 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([])
+ def __repr__(self):
+ return "Signature(%r, %r, %r)" % (
+ self.argnames, self.varargname, self.kwargname)
- 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
+ def __eq__(self, other):
+ return (self.argnames == other.argnames and
+ self.varargname == other.varargname and
+ self.kwargname == other.kwargname)
+
+ def __ne__(self, other):
+ return not self == other
+
+
+ # make it look tuply for 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
- 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
-
- kwds_w = {}
- for key in need_kwds:
- kwds_w[key] = unfiltered_kwds_w[key]
-
- return Arguments(self.space, args_w, kwds_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)
-
- def unpack(self):
- """ Purely abstract
- """
- raise NotImplementedError()
-
- def firstarg(self):
- """ Purely abstract
- """
- raise NotImplementedError()
-
- def prepend(self, w_firstarg):
- """ Purely abstract
- """
- raise NotImplementedError()
- def _match_signature(self, w_firstarg, scope_w, argnames, has_vararg=False, has_kwarg=False, defaults_w=[], blindargs=0):
- """ Purely abstract
- """
- raise NotImplementedError()
-
- def fixedunpack(self, argcount):
- """ Purely abstract
- """
- raise NotImplementedError()
-
-class Arguments(AbstractArguments):
+class Arguments(object):
"""
Collects the arguments of a function call.
@@ -195,74 +85,66 @@
### 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
- make_sure_not_resized(self.arguments_w)
- self.kwds_w = kwds_w
- self.w_stararg = w_stararg
- self.w_starstararg = w_starstararg
+ 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)
- def num_args(self):
- self._unpack()
- return len(self.arguments_w)
-
- def num_kwds(self):
- self._unpack()
- return len(self.kwds_w)
+ make_sure_not_resized(self.arguments_w)
+ self._combine_wrapped(w_stararg, w_starstararg)
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,)
- else:
- return 'Arguments(%s, %s)' % (self.arguments_w, self.kwds_w)
+ """ NOT_RPYTHON """
+ name = self.__class__.__name__
+ if not self.keywords:
+ return '%s(%s)' % (name, self.arguments_w,)
else:
- return 'Arguments(%s, %s, %s)' % (self.arguments_w,
- self.kwds_w,
- self.w_stararg)
+ return '%s(%s, %s, %s)' % (name, self.arguments_w,
+ self.keywords, self.keywords_w)
+
### Manipulation ###
- def unpack(self):
+ def unpack(self): # slowish
"Return a ([w1,w2...], {'kw':w3...}) pair."
- self._unpack()
- return self.arguments_w, self.kwds_w
+ 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 replace_arguments(self, args_w):
+ "Return a new Arguments with a args_w as positional arguments."
+ return Arguments(self.space, args_w, self.keywords, self.keywords_w)
def prepend(self, w_firstarg):
"Return a new Arguments with a new argument inserted first."
- return Arguments(self.space, [w_firstarg] + self.arguments_w,
- self.kwds_w, self.w_stararg, self.w_starstararg)
-
- 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:
+ return self.replace_arguments([w_firstarg] + self.arguments_w)
+
+ 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)
@@ -271,31 +153,28 @@
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
-
- def has_keywords(self):
- return bool(self.kwds_w) or (self.w_starstararg is not None and
- self.space.is_true(self.w_starstararg))
+ 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 = 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.has_keywords():
+ 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
@@ -304,20 +183,12 @@
"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 ###
- def _match_signature(self, w_firstarg, scope_w, argnames, has_vararg=False,
- has_kwarg=False, defaults_w=[], blindargs=0):
+ def _match_signature(self, w_firstarg, scope_w, signature, defaults_w=[],
+ blindargs=0):
"""Parse args and kwargs according to the signature of a code object,
or raise an ArgErr in case of failure.
Return the number of arguments filled in.
@@ -328,7 +199,9 @@
# argnames = list of formal parameter names
# scope_w = resulting list of wrapped values
#
- co_argcount = len(argnames) # expected formal arguments, without */**
+ co_argcount = signature.num_argnames() # expected formal arguments, without */**
+ has_vararg = signature.has_vararg()
+ has_kwarg = signature.has_kwarg()
extravarargs = None
input_argcount = 0
@@ -342,27 +215,14 @@
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
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
@@ -377,29 +237,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]: # XXX
- 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
+ used_keywords = None
+ if keywords:
+ used_keywords = [False] * num_kwds
+ for i in range(num_kwds):
+ name = keywords[i]
+ j = signature.find_argname(name)
+ if j < 0:
+ continue
+ elif 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]
+ used_keywords[i] = True # 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:
@@ -408,67 +275,236 @@
# 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),
+ co_argcount, has_vararg, has_kwarg,
defaults_w, 0)
# 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)):
+ if not used_keywords[i]:
+ key = keywords[i]
+ 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, used_keywords)
if missing:
raise ArgErrCount(avail, num_kwds,
- (co_argcount, has_vararg, has_kwarg),
+ co_argcount, has_vararg, has_kwarg,
defaults_w, missing)
return co_argcount + has_vararg + has_kwarg
- ### Argument <-> list of w_objects together with "shape" information
- def _rawshape(self, nextra=0):
- 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)
+
+ def parse_into_scope(self, w_firstarg,
+ scope_w, fnname, signature, defaults_w=[]):
+ """Parse args and kwargs to initialize a frame
+ according to the signature of code object.
+ Store the argumentvalues into scope_w.
+ scope_w must be big enough for signature.
+ """
+ try:
+ return self._match_signature(w_firstarg,
+ scope_w, signature, defaults_w, 0)
+ except ArgErr, e:
+ raise OperationError(self.space.w_TypeError,
+ self.space.wrap(e.getmsg(fnname)))
+
+ def _parse(self, w_firstarg, signature, defaults_w, blindargs=0):
+ """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(w_firstarg, scope_w, signature, defaults_w,
+ blindargs)
+ return scope_w
+
+
+ def parse_obj(self, w_firstarg,
+ fnname, signature, defaults_w=[], blindargs=0):
+ """Parse args and kwargs to initialize a frame
+ according to the signature of code object.
+ """
+ try:
+ return self._parse(w_firstarg, signature, defaults_w, blindargs)
+ except ArgErr, e:
+ raise OperationError(self.space.w_TypeError,
+ self.space.wrap(e.getmsg(fnname)))
+
+ @staticmethod
+ def frompacked(space, w_args=None, w_kwds=None):
+ """Convenience static method to build an Arguments
+ from a wrapped sequence and a wrapped dictionary."""
+ return Arguments(space, [], w_stararg=w_args, w_starstararg=w_kwds)
+
+ def topacked(self):
+ """Express the Argument object as a pair of wrapped w_args, w_kwds."""
+ space = self.space
+ w_args = space.newtuple(self.arguments_w)
+ w_kwds = space.newdict()
+ for i in range(len(self.keywords)):
+ space.setitem(w_kwds, space.wrap(self.keywords[i]),
+ self.keywords_w[i])
+ return w_args, w_kwds
+
+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
+
+ 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, w_firstarg, scope_w, signature, defaults_w=[],
+ blindargs=0):
+ self.combine_if_necessary()
+ # _match_signature is destructive
+ return Arguments._match_signature(
+ self, w_firstarg, scope_w, signature,
+ 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.
+ """
+ return self._parse(None, signature, defaults_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:
- 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
- shape_keys.sort()
- return shape_cnt, tuple(shape_keys), shape_star, shape_stst # shape_keys are sorted
+ 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 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):
+ 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)
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.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:
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)
@@ -485,28 +521,31 @@
class ArgErrCount(ArgErr):
- def __init__(self, nargs, nkwds, signature, defaults_w, missing_args):
- self.signature = signature
+ def __init__(self, got_nargs, nkwds, expected_nargs, has_vararg, has_kwarg,
+ defaults_w, missing_args):
+ self.expected_nargs = expected_nargs
+ self.has_vararg = has_vararg
+ self.has_kwarg = has_kwarg
+
self.num_defaults = len(defaults_w)
self.missing_args = missing_args
- self.num_args = nargs
+ self.num_args = got_nargs
self.num_kwds = nkwds
def getmsg(self, fnname):
args = None
- num_args, has_vararg, has_kwarg = self.signature
#args_w, kwds_w = args.unpack()
- if has_kwarg or (self.num_kwds and self.num_defaults):
+ if self.has_kwarg or (self.num_kwds and self.num_defaults):
msg2 = "non-keyword "
if self.missing_args:
- required_args = num_args - self.num_defaults
+ required_args = self.expected_nargs - self.num_defaults
nargs = required_args - self.missing_args
else:
nargs = self.num_args
else:
msg2 = ""
nargs = self.num_args + self.num_kwds
- n = num_args
+ n = self.expected_nargs
if n == 0:
msg = "%s() takes no %sargument (%d given)" % (
fnname,
@@ -514,7 +553,7 @@
nargs)
else:
defcount = self.num_defaults
- if defcount == 0 and not has_vararg:
+ if defcount == 0 and not self.has_vararg:
msg1 = "exactly"
elif not self.missing_args:
msg1 = "at most"
@@ -549,11 +588,14 @@
class ArgErrUnknownKwds(ArgErr):
- def __init__(self, kwds_w):
+ def __init__(self, num_remainingkwds, keywords, used_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 i in range(len(keywords)):
+ if not used_keywords[i]:
+ self.kwd_name = keywords[i]
+ break
def getmsg(self, fnname):
if self.num_kwds == 1:
More information about the Pypy-commit
mailing list