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) { ...@@ -150,7 +150,7 @@ Box* dictContains(BoxedDict* self, Box* k) {
return boxBool(self->d.count(k) != 0); 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)) if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "dict.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str()); 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) { ...@@ -160,7 +160,13 @@ extern "C" Box* dictNew(Box* _cls) {
getNameOfClass(cls)->c_str()); getNameOfClass(cls)->c_str());
RELEASE_ASSERT(cls == dict_cls, ""); 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; BoxedClass* dict_iterator_cls = NULL;
...@@ -177,7 +183,7 @@ void setupDict() { ...@@ -177,7 +183,7 @@ void setupDict() {
dict_cls->giveAttr("__name__", boxStrConstant("dict")); dict_cls->giveAttr("__name__", boxStrConstant("dict"));
// dict_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)dictLen, NULL, 1))); // 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("__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("__init__", new BoxedFunction(boxRTFunction((void*)dictInit, NULL, 1)));
dict_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)dictRepr, STR, 1))); dict_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)dictRepr, STR, 1)));
dict_cls->giveAttr("__str__", dict_cls->getattr("__repr__")); 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 ...@@ -1746,7 +1746,12 @@ static void placeKeyword(const std::vector<AST_expr*>& arg_names, std::vector<bo
if (!found) { if (!found) {
if (okwargs) { 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 { } else {
raiseExcHelper(TypeError, "<function>() got an unexpected keyword argument '%s'", kw_name.c_str()); 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 ...@@ -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; 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); 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 ...@@ -1928,29 +1933,47 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
for (int i = 0; i < argspec.num_keywords; i++) { for (int i = 0; i < argspec.num_keywords; i++) {
assert(!rewrite_args && "would need to be handled here"); assert(!rewrite_args && "would need to be handled here");
assert(arg_names);
int arg_idx = i + argspec.num_args; int arg_idx = i + argspec.num_args;
Box* kw_val = getArg(arg_idx, arg1, arg2, arg3, 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); placeKeyword(*arg_names, params_filled, *(*keyword_names)[i], kw_val, oarg1, oarg2, oarg3, oargs, okwargs);
} }
if (argspec.has_kwargs) { if (argspec.has_kwargs) {
assert(!rewrite_args && "would need to be handled here"); assert(!rewrite_args && "would need to be handled here");
assert(arg_names);
Box* kwargs Box* kwargs
= getArg(argspec.num_args + argspec.num_keywords + (argspec.has_starargs ? 1 : 0), arg1, arg2, arg3, args); = 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"); RELEASE_ASSERT(kwargs->cls == dict_cls, "haven't implemented this for non-dicts");
BoxedDict* d_kwargs = static_cast<BoxedDict*>(kwargs); BoxedDict* d_kwargs = static_cast<BoxedDict*>(kwargs);
for (auto& p : d_kwargs->d) { for (auto& p : d_kwargs->d) {
if (p.first->cls != str_cls) if (p.first->cls != str_cls)
raiseExcHelper(TypeError, "<function>() keywords must be strings"); raiseExcHelper(TypeError, "<function>() keywords must be strings");
BoxedString* s = static_cast<BoxedString*>(p.first); 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 {} ...@@ -53,13 +53,7 @@ print 'a' in {}
print 'a' in {'a': 1} print 'a' in {'a': 1}
print 'a' in dict() print 'a' in dict()
try: print 'a' in dict(a=1)
# 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 d 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