Commit c2877853 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Support receiving **kw for builtin functions

Need to special-case some places in the keyword handling
since they previously assumed that they would first have
to check if the keyword name matched a positional argument,
before putting into the output **kw.
parent 83685055
......@@ -150,7 +150,7 @@ Box* dictContains(BoxedDict* self, Box* k) {
return boxBool(self->d.count(k) != 0);
}
extern "C" Box* dictNew(Box* _cls) {
extern "C" Box* dictNew(Box* _cls, BoxedDict* kwargs) {
if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "dict.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str());
......@@ -160,7 +160,13 @@ extern "C" Box* dictNew(Box* _cls) {
getNameOfClass(cls)->c_str());
RELEASE_ASSERT(cls == dict_cls, "");
return new BoxedDict();
BoxedDict* r = new BoxedDict();
assert(kwargs->cls == dict_cls);
// Copy any kwargs:
r->d = kwargs->d;
return r;
}
BoxedClass* dict_iterator_cls = NULL;
......@@ -177,7 +183,7 @@ void setupDict() {
dict_cls->giveAttr("__name__", boxStrConstant("dict"));
// dict_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)dictLen, NULL, 1)));
// dict_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)dictGetitem, NULL, 2)));
dict_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)dictNew, UNKNOWN, 1)));
dict_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)dictNew, UNKNOWN, 1, 0, false, true)));
// dict_cls->giveAttr("__init__", new BoxedFunction(boxRTFunction((void*)dictInit, NULL, 1)));
dict_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)dictRepr, STR, 1)));
dict_cls->giveAttr("__str__", dict_cls->getattr("__repr__"));
......
......@@ -1746,7 +1746,12 @@ static void placeKeyword(const std::vector<AST_expr*>& arg_names, std::vector<bo
if (!found) {
if (okwargs) {
okwargs->d[boxString(kw_name)] = kw_val;
Box*& v = okwargs->d[boxString(kw_name)];
if (v) {
raiseExcHelper(TypeError, "<function>() got multiple values for keyword argument '%s'",
kw_name.c_str());
}
v = kw_val;
} else {
raiseExcHelper(TypeError, "<function>() got an unexpected keyword argument '%s'", kw_name.c_str());
}
......@@ -1919,7 +1924,7 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
}
const std::vector<AST_expr*>* arg_names = f->source ? f->source->arg_names.args : NULL;
if (arg_names == nullptr && argspec.num_keywords) {
if (arg_names == nullptr && argspec.num_keywords && !f->takes_kwargs) {
raiseExcHelper(TypeError, "<function @%p>() doesn't take keyword arguments", f->versions[0]->code);
}
......@@ -1928,29 +1933,47 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
for (int i = 0; i < argspec.num_keywords; i++) {
assert(!rewrite_args && "would need to be handled here");
assert(arg_names);
int arg_idx = i + argspec.num_args;
Box* kw_val = getArg(arg_idx, arg1, arg2, arg3, args);
if (!arg_names) {
assert(okwargs);
okwargs->d[boxStringPtr((*keyword_names)[i])] = kw_val;
continue;
}
assert(arg_names);
placeKeyword(*arg_names, params_filled, *(*keyword_names)[i], kw_val, oarg1, oarg2, oarg3, oargs, okwargs);
}
if (argspec.has_kwargs) {
assert(!rewrite_args && "would need to be handled here");
assert(arg_names);
Box* kwargs
= getArg(argspec.num_args + argspec.num_keywords + (argspec.has_starargs ? 1 : 0), arg1, arg2, arg3, args);
RELEASE_ASSERT(kwargs->cls == dict_cls, "haven't implemented this for non-dicts");
BoxedDict* d_kwargs = static_cast<BoxedDict*>(kwargs);
for (auto& p : d_kwargs->d) {
if (p.first->cls != str_cls)
raiseExcHelper(TypeError, "<function>() keywords must be strings");
BoxedString* s = static_cast<BoxedString*>(p.first);
placeKeyword(*arg_names, params_filled, s->s, p.second, oarg1, oarg2, oarg3, oargs, okwargs);
if (arg_names) {
placeKeyword(*arg_names, params_filled, s->s, p.second, oarg1, oarg2, oarg3, oargs, okwargs);
} else {
assert(okwargs);
Box*& v = okwargs->d[p.first];
if (v) {
raiseExcHelper(TypeError, "<function>() got multiple values for keyword argument '%s'",
s->s.c_str());
}
v = p.second;
}
}
}
......
......@@ -53,13 +53,7 @@ print 'a' in {}
print 'a' in {'a': 1}
print 'a' in dict()
try:
# attempting to print the following result causes the test
# to fail (bad output), but runtime is ok. otherwise it
# throws a TypeError exception.
# print 'a' in dict(a=1)
'a' in dict(a=1)
except TypeError, e:
# throws <function ...> doesn't take keyword arguments
pass
print 'a' in dict(a=1)
print d
print dict(**dict(a=1, b=2))
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