Commit 56e8878a authored by Robert Bradshaw's avatar Robert Bradshaw

merge

parents dfbb24da 4dbdde33
...@@ -2062,12 +2062,12 @@ class SequenceNode(ExprNode): ...@@ -2062,12 +2062,12 @@ class SequenceNode(ExprNode):
rhs.py_result(), rhs.py_result(),
rhs.py_result(), rhs.py_result(),
len(self.args))) len(self.args)))
code.putln("PyObject* tuple = %s;" % rhs.py_result())
for i in range(len(self.args)): for i in range(len(self.args)):
item = self.unpacked_items[i] item = self.unpacked_items[i]
code.putln( code.putln(
"%s = PyTuple_GET_ITEM(%s, %s);" % ( "%s = PyTuple_GET_ITEM(tuple, %s);" % (
item.result_code, item.result_code,
rhs.py_result(),
i)) i))
code.put_incref(item.result_code, item.ctype()) code.put_incref(item.result_code, item.ctype())
value_node = self.coerced_unpacked_items[i] value_node = self.coerced_unpacked_items[i]
......
...@@ -797,7 +797,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -797,7 +797,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("}") code.putln("}")
for entry in py_attrs: for entry in py_attrs:
name = "p->%s" % entry.cname name = "p->%s" % entry.cname
code.putln("tmp = %s;" % code.as_pyobject(name, entry.type)) code.putln("tmp = ((PyObject*)%s);" % name)
code.put_init_to_py_none(name, entry.type) code.put_init_to_py_none(name, entry.type)
code.putln("Py_XDECREF(tmp);") code.putln("Py_XDECREF(tmp);")
code.putln( code.putln(
......
...@@ -928,15 +928,19 @@ class DefNode(FuncDefNode): ...@@ -928,15 +928,19 @@ class DefNode(FuncDefNode):
assmt = None assmt = None
num_kwonly_args = 0 num_kwonly_args = 0
num_required_kw_args = 0
reqd_kw_flags_cname = "0" reqd_kw_flags_cname = "0"
def __init__(self, pos, **kwds): def __init__(self, pos, **kwds):
FuncDefNode.__init__(self, pos, **kwds) FuncDefNode.__init__(self, pos, **kwds)
n = 0 n = r = 0
for arg in self.args: for arg in self.args:
if arg.kw_only: if arg.kw_only:
n += 1 n += 1
if not arg.default:
r += 1
self.num_kwonly_args = n self.num_kwonly_args = n
self.num_required_kw_args = r
def analyse_declarations(self, env): def analyse_declarations(self, env):
for arg in self.args: for arg in self.args:
...@@ -958,9 +962,13 @@ class DefNode(FuncDefNode): ...@@ -958,9 +962,13 @@ class DefNode(FuncDefNode):
self.declare_pyfunction(env) self.declare_pyfunction(env)
self.analyse_signature(env) self.analyse_signature(env)
self.return_type = self.entry.signature.return_type() self.return_type = self.entry.signature.return_type()
if self.star_arg or self.starstar_arg or self.num_kwonly_args > 0: if self.star_arg:
env.use_utility_code(get_starargs_utility_code) env.use_utility_code(get_stararg_utility_code)
if self.starstar_arg:
env.use_utility_code(get_splitkeywords_utility_code)
if self.num_required_kw_args:
env.use_utility_code(get_checkkeywords_utility_code)
def analyse_signature(self, env): def analyse_signature(self, env):
any_type_tests_needed = 0 any_type_tests_needed = 0
# Use the simpler calling signature for zero- and one-argument functions. # Use the simpler calling signature for zero- and one-argument functions.
...@@ -1215,6 +1223,10 @@ class DefNode(FuncDefNode): ...@@ -1215,6 +1223,10 @@ class DefNode(FuncDefNode):
if not default_seen: if not default_seen:
arg_formats.append("|") arg_formats.append("|")
default_seen = 1 default_seen = 1
elif arg.kw_only:
if not default_seen:
arg_formats.append("|")
default_seen = 1
elif default_seen and not arg.kw_only: elif default_seen and not arg.kw_only:
error(arg.pos, "Non-default argument following default argument") error(arg.pos, "Non-default argument following default argument")
if arg.needs_conversion: if arg.needs_conversion:
...@@ -1241,9 +1253,8 @@ class DefNode(FuncDefNode): ...@@ -1241,9 +1253,8 @@ class DefNode(FuncDefNode):
pt_argstring) pt_argstring)
if has_star_or_kw_args: if has_star_or_kw_args:
code.putln("{") code.putln("{")
code.put_xdecref(Naming.args_cname, py_object_type) self.put_stararg_decrefs(code)
code.put_xdecref(Naming.kwds_cname, py_object_type) self.generate_arg_decref(self.star_arg, code)
self.generate_arg_xdecref(self.star_arg, code)
self.generate_arg_xdecref(self.starstar_arg, code) self.generate_arg_xdecref(self.starstar_arg, code)
code.putln(error_return_code) code.putln(error_return_code)
code.putln("}") code.putln("}")
...@@ -1251,14 +1262,19 @@ class DefNode(FuncDefNode): ...@@ -1251,14 +1262,19 @@ class DefNode(FuncDefNode):
code.putln(error_return_code) code.putln(error_return_code)
def put_stararg_decrefs(self, code): def put_stararg_decrefs(self, code):
if self.star_arg or self.starstar_arg or self.num_kwonly_args > 0: if self.star_arg:
code.put_xdecref(Naming.args_cname, py_object_type) code.put_decref(Naming.args_cname, py_object_type)
if self.starstar_arg:
code.put_xdecref(Naming.kwds_cname, py_object_type) code.put_xdecref(Naming.kwds_cname, py_object_type)
def generate_arg_xdecref(self, arg, code): def generate_arg_xdecref(self, arg, code):
if arg: if arg:
code.put_var_xdecref(arg.entry) code.put_var_xdecref(arg.entry)
def generate_arg_decref(self, arg, code):
if arg:
code.put_var_decref(arg.entry)
def arg_address(self, arg): def arg_address(self, arg):
if arg: if arg:
return "&%s" % arg.entry.cname return "&%s" % arg.entry.cname
...@@ -1267,19 +1283,55 @@ class DefNode(FuncDefNode): ...@@ -1267,19 +1283,55 @@ class DefNode(FuncDefNode):
def generate_stararg_getting_code(self, code): def generate_stararg_getting_code(self, code):
num_kwonly = self.num_kwonly_args num_kwonly = self.num_kwonly_args
nargs = len(self.args) - num_kwonly - self.entry.signature.num_fixed_args() fixed_args = self.entry.signature.num_fixed_args()
star_arg_addr = self.arg_address(self.star_arg) nargs = len(self.args) - num_kwonly - fixed_args
starstar_arg_addr = self.arg_address(self.starstar_arg) error_return = "return %s;" % self.error_value()
code.putln(
"if (__Pyx_GetStarArgs(&%s, &%s, %s, %s, %s, %s, %s) < 0) return %s;" % ( if self.star_arg:
Naming.args_cname, star_arg_addr = self.arg_address(self.star_arg)
Naming.kwds_cname, code.putln(
Naming.kwdlist_cname, "if (unlikely(__Pyx_GetStarArg(&%s, %s, %s) < 0)) return %s;" % (
nargs, Naming.args_cname,
star_arg_addr, nargs,
starstar_arg_addr, star_arg_addr,
self.reqd_kw_flags_cname, self.error_value()))
self.error_value())) elif self.entry.signature.has_generic_args:
# make sure supernumerous positional arguments do not run
# into keyword-only arguments and provide a more helpful
# message than PyArg_ParseTupelAndKeywords()
code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > %d)) {" % (
Naming.args_cname, nargs))
error_message = "function takes at most %d positional arguments (%d given)"
code.putln("PyErr_Format(PyExc_TypeError, \"%s\", %d, PyTuple_GET_SIZE(%s));" % (
error_message, nargs, Naming.args_cname))
code.putln(error_return)
code.putln("}")
handle_error = 0
if self.starstar_arg:
handle_error = 1
code.put(
"if (unlikely(__Pyx_SplitKeywords(&%s, %s, %s, %s) < 0)) " % (
Naming.kwds_cname,
Naming.kwdlist_cname,
self.arg_address(self.starstar_arg),
self.reqd_kw_flags_cname))
elif self.num_required_kw_args:
handle_error = 1
code.put("if (unlikely(__Pyx_CheckRequiredKeywords(%s, %s, %s) < 0)) " % (
Naming.kwds_cname,
Naming.kwdlist_cname,
self.reqd_kw_flags_cname))
if handle_error:
if self.star_arg:
code.putln("{")
code.put_decref(Naming.args_cname, py_object_type)
code.put_decref(self.star_arg.entry.cname, py_object_type)
code.putln(error_return)
code.putln("}")
else:
code.putln(error_return)
def generate_argument_conversion_code(self, code): def generate_argument_conversion_code(self, code):
# Generate code to convert arguments from # Generate code to convert arguments from
...@@ -3318,98 +3370,92 @@ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed ...@@ -3318,98 +3370,92 @@ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# #
# __Pyx_GetStarArgs splits the args tuple and kwds dict into two parts # __Pyx_GetStarArg splits the args tuple into two parts, one part
# each, one part suitable for passing to PyArg_ParseTupleAndKeywords, # suitable for passing to PyArg_ParseTupleAndKeywords, and the other
# and the other containing any extra arguments. On success, replaces # containing any extra arguments. On success, replaces the borrowed
# the borrowed references *args and *kwds with references to a new # reference *args with references to a new tuple, and passes back a
# tuple and dict, and passes back new references in *args2 and *kwds2. # new reference in *args2. Does not touch any of its arguments on
# Does not touch any of its arguments on failure. # failure.
get_stararg_utility_code = [
"""
static INLINE int __Pyx_GetStarArg(PyObject **args, Py_ssize_t nargs, PyObject **args2); /*proto*/
""","""
static INLINE int __Pyx_GetStarArg(
PyObject **args,
Py_ssize_t nargs,
PyObject **args2)
{
PyObject *args1 = 0;
*args2 = 0;
args1 = PyTuple_GetSlice(*args, 0, nargs);
if (!args1)
return -1;
*args2 = PyTuple_GetSlice(*args, nargs, PyTuple_GET_SIZE(*args));
if (!*args2) {
Py_DECREF(args1);
return -1;
}
*args = args1;
return 0;
}
"""]
#------------------------------------------------------------------------------------
#
# __Pyx_SplitKeywords splits the kwds dict into two parts one part
# suitable for passing to PyArg_ParseTupleAndKeywords, and the other
# containing any extra arguments. On success, replaces the borrowed
# reference *kwds with references to a new dict, and passes back a
# new reference in *kwds2. Does not touch any of its arguments on
# failure.
# #
# Any of *kwds, args2 and kwds2 may be 0 (but not args or kwds). If # Any of *kwds and kwds2 may be 0 (but not kwds). If *kwds == 0, it
# *kwds == 0, it is not changed. If kwds2 == 0 and *kwds != 0, a new # is not changed. If kwds2 == 0 and *kwds != 0, a new reference to
# reference to the same dictionary is passed back in *kwds. # the same dictionary is passed back in *kwds.
# #
# If rqd_kwds is not 0, it is an array of booleans corresponding to the # If rqd_kwds is not 0, it is an array of booleans corresponding to
# names in kwd_list, indicating required keyword arguments. If any of # the names in kwd_list, indicating required keyword arguments. If
# these are not present in kwds, an exception is raised. # any of these are not present in kwds, an exception is raised.
# #
get_starargs_utility_code = [ get_splitkeywords_utility_code = [
""" """
static int __Pyx_GetStarArgs(PyObject **args, PyObject **kwds, char *kwd_list[], \ static int __Pyx_SplitKeywords(PyObject **kwds, char *kwd_list[], \
Py_ssize_t nargs, PyObject **args2, PyObject **kwds2, char rqd_kwds[]); /*proto*/ PyObject **kwds2, char rqd_kwds[]); /*proto*/
""",""" ""","""
static int __Pyx_GetStarArgs( static int __Pyx_SplitKeywords(
PyObject **args,
PyObject **kwds, PyObject **kwds,
char *kwd_list[], char *kwd_list[],
Py_ssize_t nargs,
PyObject **args2,
PyObject **kwds2, PyObject **kwds2,
char rqd_kwds[]) char rqd_kwds[])
{ {
PyObject *s = 0, *x = 0, *args1 = 0, *kwds1 = 0; PyObject *s = 0, *x = 0, *kwds1 = 0;
int i; int i;
char **p; char **p;
if (args2) if (*kwds) {
*args2 = 0; kwds1 = PyDict_New();
if (kwds2) if (!kwds1)
*kwds2 = 0;
if (args2) {
args1 = PyTuple_GetSlice(*args, 0, nargs);
if (!args1)
goto bad; goto bad;
*args2 = PyTuple_GetSlice(*args, nargs, PyTuple_GET_SIZE(*args)); *kwds2 = PyDict_Copy(*kwds);
if (!*args2) if (!*kwds2)
goto bad; goto bad;
} for (i = 0, p = kwd_list; *p; i++, p++) {
else if (PyTuple_GET_SIZE(*args) > nargs) { s = PyString_FromString(*p);
int m = nargs; x = PyDict_GetItem(*kwds, s);
int n = PyTuple_GET_SIZE(*args); if (x) {
PyErr_Format(PyExc_TypeError, if (PyDict_SetItem(kwds1, s, x) < 0)
"function takes at most %d positional arguments (%d given)", goto bad;
m, n); if (PyDict_DelItem(*kwds2, s) < 0)
goto bad; goto bad;
}
else {
args1 = *args;
Py_INCREF(args1);
}
if (*kwds) {
if (kwds2) {
kwds1 = PyDict_New();
if (!kwds1)
goto bad;
*kwds2 = PyDict_Copy(*kwds);
if (!*kwds2)
goto bad;
for (i = 0, p = kwd_list; *p; i++, p++) {
s = PyString_FromString(*p);
x = PyDict_GetItem(*kwds, s);
if (x) {
if (PyDict_SetItem(kwds1, s, x) < 0)
goto bad;
if (PyDict_DelItem(*kwds2, s) < 0)
goto bad;
}
else if (rqd_kwds && rqd_kwds[i])
goto missing_kwarg;
Py_DECREF(s);
}
s = 0;
}
else {
kwds1 = *kwds;
Py_INCREF(kwds1);
if (rqd_kwds) {
for (i = 0, p = kwd_list; *p; i++, p++)
if (rqd_kwds[i] && !PyDict_GetItemString(kwds1, *p))
goto missing_kwarg;
} }
else if (rqd_kwds && rqd_kwds[i])
goto missing_kwarg;
Py_DECREF(s);
} }
s = 0;
} }
else { else {
if (rqd_kwds) { if (rqd_kwds) {
...@@ -3417,14 +3463,11 @@ static int __Pyx_GetStarArgs( ...@@ -3417,14 +3463,11 @@ static int __Pyx_GetStarArgs(
if (rqd_kwds[i]) if (rqd_kwds[i])
goto missing_kwarg; goto missing_kwarg;
} }
if (kwds2) { *kwds2 = PyDict_New();
*kwds2 = PyDict_New(); if (!*kwds2)
if (!*kwds2) goto bad;
goto bad;
}
} }
*args = args1;
*kwds = kwds1; *kwds = kwds1;
return 0; return 0;
missing_kwarg: missing_kwarg:
...@@ -3432,14 +3475,40 @@ missing_kwarg: ...@@ -3432,14 +3475,40 @@ missing_kwarg:
"required keyword argument '%s' is missing", *p); "required keyword argument '%s' is missing", *p);
bad: bad:
Py_XDECREF(s); Py_XDECREF(s);
Py_XDECREF(args1);
Py_XDECREF(kwds1); Py_XDECREF(kwds1);
if (args2) { Py_XDECREF(*kwds2);
Py_XDECREF(*args2); return -1;
}
"""]
get_checkkeywords_utility_code = [
"""
static INLINE int __Pyx_CheckRequiredKeywords(PyObject *kwds, char *kwd_list[],
char rqd_kwds[]); /*proto*/
""","""
static INLINE int __Pyx_CheckRequiredKeywords(
PyObject *kwds,
char *kwd_list[],
char rqd_kwds[])
{
int i;
char **p;
if (kwds) {
for (i = 0, p = kwd_list; *p; i++, p++)
if (rqd_kwds[i] && !PyDict_GetItemString(kwds, *p))
goto missing_kwarg;
} }
if (kwds2) { else {
Py_XDECREF(*kwds2); for (i = 0, p = kwd_list; *p; i++, p++)
if (rqd_kwds[i])
goto missing_kwarg;
} }
return 0;
missing_kwarg:
PyErr_Format(PyExc_TypeError,
"required keyword argument '%s' is missing", *p);
return -1; return -1;
} }
"""] """]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment