Commit 62f6f344 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'django'

Bunch of small missing features, but with these and some small
workarounds inside django, we can run django-admin to the point
that it gives us the help message and then quits.
parents e3ae2963 33e44bea
...@@ -3,11 +3,17 @@ ...@@ -3,11 +3,17 @@
#include "Python.h" #include "Python.h"
#include "stringlib/stringdefs.h" #include "stringlib/stringdefs.h"
#include "stringlib/string_format.h" #include "stringlib/fastsearch.h"
#include "stringlib/count.h"
#include "stringlib/find.h"
#include "stringlib/split.h"
#define _Py_InsertThousandsGrouping _PyString_InsertThousandsGrouping #define _Py_InsertThousandsGrouping _PyString_InsertThousandsGrouping
#include "stringlib/localeutil.h" #include "stringlib/localeutil.h"
#include "stringlib/string_format.h"
// do_string_format needs to be declared as a static function, since it's used by both stringobject.c // do_string_format needs to be declared as a static function, since it's used by both stringobject.c
// and unicodeobject.c. We want to access it from str.cpp, though, so just use this little forwarding // and unicodeobject.c. We want to access it from str.cpp, though, so just use this little forwarding
// function. // function.
...@@ -16,3 +22,83 @@ ...@@ -16,3 +22,83 @@
PyObject * _do_string_format(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject * _do_string_format(PyObject *self, PyObject *args, PyObject *kwargs) {
return do_string_format(self, args, kwargs); return do_string_format(self, args, kwargs);
} }
PyObject* string_rsplit(PyStringObject* self, PyObject* args) {
Py_ssize_t len = PyString_GET_SIZE(self), n;
Py_ssize_t maxsplit = -1;
const char* s = PyString_AS_STRING(self), *sub;
PyObject* subobj = Py_None;
if (!PyArg_ParseTuple(args, "|On:rsplit", &subobj, &maxsplit))
return NULL;
if (maxsplit < 0)
maxsplit = PY_SSIZE_T_MAX;
if (subobj == Py_None)
return stringlib_rsplit_whitespace((PyObject*)self, s, len, maxsplit);
if (PyString_Check(subobj)) {
sub = PyString_AS_STRING(subobj);
n = PyString_GET_SIZE(subobj);
}
#ifdef Py_USING_UNICODE
else if (PyUnicode_Check(subobj))
return PyUnicode_RSplit((PyObject*)self, subobj, maxsplit);
#endif
else if (PyObject_AsCharBuffer(subobj, &sub, &n))
return NULL;
return stringlib_rsplit((PyObject*)self, s, len, sub, n, maxsplit);
}
Py_LOCAL_INLINE(Py_ssize_t)
string_find_internal(PyStringObject *self, PyObject *args, int dir)
{
PyObject *subobj;
const char *sub;
Py_ssize_t sub_len;
Py_ssize_t start=0, end=PY_SSIZE_T_MAX;
if (!stringlib_parse_args_finds("find/rfind/index/rindex",
args, &subobj, &start, &end))
return -2;
if (PyString_Check(subobj)) {
sub = PyString_AS_STRING(subobj);
sub_len = PyString_GET_SIZE(subobj);
}
#ifdef Py_USING_UNICODE
else if (PyUnicode_Check(subobj))
return PyUnicode_Find(
(PyObject *)self, subobj, start, end, dir);
#endif
else if (PyObject_AsCharBuffer(subobj, &sub, &sub_len))
/* XXX - the "expected a character buffer object" is pretty
confusing for a non-expert. remap to something else ? */
return -2;
if (dir > 0)
return stringlib_find_slice(
PyString_AS_STRING(self), PyString_GET_SIZE(self),
sub, sub_len, start, end);
else
return stringlib_rfind_slice(
PyString_AS_STRING(self), PyString_GET_SIZE(self),
sub, sub_len, start, end);
}
PyObject *
string_rfind(PyStringObject *self, PyObject *args)
{
Py_ssize_t result = string_find_internal(self, args, -1);
if (result == -2)
return NULL;
return PyInt_FromSsize_t(result);
}
PyObject *
string_find(PyStringObject *self, PyObject *args)
{
Py_ssize_t result = string_find_internal(self, args, +1);
if (result == -2)
return NULL;
return PyInt_FromSsize_t(result);
}
...@@ -932,6 +932,87 @@ extern "C" PyObject* PySequence_List(PyObject* v) noexcept { ...@@ -932,6 +932,87 @@ extern "C" PyObject* PySequence_List(PyObject* v) noexcept {
return result; return result;
} }
/* Iterate over seq. Result depends on the operation:
PY_ITERSEARCH_COUNT: -1 if error, else # of times obj appears in seq.
PY_ITERSEARCH_INDEX: 0-based index of first occurrence of obj in seq;
set ValueError and return -1 if none found; also return -1 on error.
Py_ITERSEARCH_CONTAINS: return 1 if obj in seq, else 0; -1 on error.
*/
extern "C" Py_ssize_t _PySequence_IterSearch(PyObject* seq, PyObject* obj, int operation) noexcept {
Py_ssize_t n;
int wrapped; /* for PY_ITERSEARCH_INDEX, true iff n wrapped around */
PyObject* it; /* iter(seq) */
if (seq == NULL || obj == NULL) {
null_error();
return -1;
}
it = PyObject_GetIter(seq);
if (it == NULL) {
type_error("argument of type '%.200s' is not iterable", seq);
return -1;
}
n = wrapped = 0;
for (;;) {
int cmp;
PyObject* item = PyIter_Next(it);
if (item == NULL) {
if (PyErr_Occurred())
goto Fail;
break;
}
cmp = PyObject_RichCompareBool(obj, item, Py_EQ);
Py_DECREF(item);
if (cmp < 0)
goto Fail;
if (cmp > 0) {
switch (operation) {
case PY_ITERSEARCH_COUNT:
if (n == PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError, "count exceeds C integer size");
goto Fail;
}
++n;
break;
case PY_ITERSEARCH_INDEX:
if (wrapped) {
PyErr_SetString(PyExc_OverflowError, "index exceeds C integer size");
goto Fail;
}
goto Done;
case PY_ITERSEARCH_CONTAINS:
n = 1;
goto Done;
default:
assert(!"unknown operation");
}
}
if (operation == PY_ITERSEARCH_INDEX) {
if (n == PY_SSIZE_T_MAX)
wrapped = 1;
++n;
}
}
if (operation != PY_ITERSEARCH_INDEX)
goto Done;
PyErr_SetString(PyExc_ValueError, "sequence.index(x): x not in sequence");
/* fall into failure code */
Fail:
n = -1;
/* fall through */
Done:
Py_DECREF(it);
return n;
}
extern "C" PyObject* PyObject_CallFunction(PyObject* callable, const char* format, ...) noexcept { extern "C" PyObject* PyObject_CallFunction(PyObject* callable, const char* format, ...) noexcept {
va_list va; va_list va;
PyObject* args; PyObject* args;
......
...@@ -472,6 +472,8 @@ Box* bltinImport(Box* name, Box* globals, Box* locals, Box** args) { ...@@ -472,6 +472,8 @@ Box* bltinImport(Box* name, Box* globals, Box* locals, Box** args) {
Box* fromlist = args[0]; Box* fromlist = args[0];
Box* level = args[1]; Box* level = args[1];
name = coerceUnicodeToStr(name);
if (name->cls != str_cls) { if (name->cls != str_cls) {
raiseExcHelper(TypeError, "__import__() argument 1 must be string, not %s", getTypeName(name)); raiseExcHelper(TypeError, "__import__() argument 1 must be string, not %s", getTypeName(name));
} }
...@@ -673,6 +675,12 @@ Box* eval(Box* code) { ...@@ -673,6 +675,12 @@ Box* eval(Box* code) {
return runEval(static_cast<BoxedString*>(code)->s.c_str(), locals, module); return runEval(static_cast<BoxedString*>(code)->s.c_str(), locals, module);
} }
static Box* callable(Box* obj) {
Box* r = PyBool_FromLong((long)PyCallable_Check(obj));
checkAndThrowCAPIException();
return r;
}
BoxedClass* notimplemented_cls; BoxedClass* notimplemented_cls;
BoxedModule* builtins_module; BoxedModule* builtins_module;
...@@ -1146,6 +1154,8 @@ void setupBuiltins() { ...@@ -1146,6 +1154,8 @@ void setupBuiltins() {
builtins_module->giveAttr( builtins_module->giveAttr(
"eval", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)eval, UNKNOWN, 1, 0, false, false), "eval")); "eval", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)eval, UNKNOWN, 1, 0, false, false), "eval"));
builtins_module->giveAttr("callable",
new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)callable, UNKNOWN, 1), "callable"));
BoxedClass* buffer_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "buffer"); BoxedClass* buffer_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "buffer");
builtins_module->giveAttr("buffer", buffer_cls); builtins_module->giveAttr("buffer", buffer_cls);
......
...@@ -280,7 +280,13 @@ extern "C" PyObject* PyObject_GetItem(PyObject* o, PyObject* key) noexcept { ...@@ -280,7 +280,13 @@ extern "C" PyObject* PyObject_GetItem(PyObject* o, PyObject* key) noexcept {
} }
extern "C" int PyObject_SetItem(PyObject* o, PyObject* key, PyObject* v) noexcept { extern "C" int PyObject_SetItem(PyObject* o, PyObject* key, PyObject* v) noexcept {
Py_FatalError("unimplemented"); try {
setitem(o, key, v);
return 0;
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
}
} }
extern "C" int PyObject_DelItem(PyObject* o, PyObject* key) noexcept { extern "C" int PyObject_DelItem(PyObject* o, PyObject* key) noexcept {
...@@ -490,7 +496,8 @@ extern "C" PyObject* PyIter_Next(PyObject* iter) noexcept { ...@@ -490,7 +496,8 @@ extern "C" PyObject* PyIter_Next(PyObject* iter) noexcept {
return callattr(iter, &next_str, CallattrFlags({.cls_only = true, .null_on_nonexistent = false }), return callattr(iter, &next_str, CallattrFlags({.cls_only = true, .null_on_nonexistent = false }),
ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
} catch (ExcInfo e) { } catch (ExcInfo e) {
setCAPIException(e); if (!e.matches(StopIteration))
setCAPIException(e);
return NULL; return NULL;
} }
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <sstream> #include <sstream>
#include "capi/types.h"
#include "core/types.h" #include "core/types.h"
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
...@@ -277,6 +278,55 @@ Box* instanceDelitem(Box* _inst, Box* key) { ...@@ -277,6 +278,55 @@ Box* instanceDelitem(Box* _inst, Box* key) {
return runtimeCall(delitem_func, ArgPassSpec(1), key, NULL, NULL, NULL, NULL); return runtimeCall(delitem_func, ArgPassSpec(1), key, NULL, NULL, NULL, NULL);
} }
Box* instanceContains(Box* _inst, Box* key) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
Box* contains_func = _instanceGetattribute(inst, boxStrConstant("__contains__"), false);
if (!contains_func) {
int result = _PySequence_IterSearch(inst, key, PY_ITERSEARCH_CONTAINS);
if (result < 0)
throwCAPIException();
assert(result == 0 || result == 1);
return boxBool(result);
}
Box* r = runtimeCall(contains_func, ArgPassSpec(1), key, NULL, NULL, NULL, NULL);
return boxBool(nonzero(r));
}
static Box* instanceHash(BoxedInstance* inst) {
assert(inst->cls == instance_cls);
PyObject* func;
PyObject* res;
func = _instanceGetattribute(inst, boxStrConstant("__hash__"), false);
if (func == NULL) {
/* If there is no __eq__ and no __cmp__ method, we hash on the
address. If an __eq__ or __cmp__ method exists, there must
be a __hash__. */
func = _instanceGetattribute(inst, boxStrConstant("__eq__"), false);
if (func == NULL) {
func = _instanceGetattribute(inst, boxStrConstant("__cmp__"), false);
if (func == NULL) {
return boxInt(_Py_HashPointer(inst));
}
}
raiseExcHelper(TypeError, "unhashable instance");
}
res = runtimeCall(func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
if (PyInt_Check(res) || PyLong_Check(res)) {
static std::string hash_str("__hash__");
return callattr(res, &hash_str, CallattrFlags({.cls_only = true, .null_on_nonexistent = false }),
ArgPassSpec(0), nullptr, nullptr, nullptr, nullptr, nullptr);
} else {
raiseExcHelper(TypeError, "__hash__() should return an int");
}
}
void setupClassobj() { void setupClassobj() {
classobj_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedClassobj::gcHandler, classobj_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedClassobj::gcHandler,
offsetof(BoxedClassobj, attrs), 0, sizeof(BoxedClassobj), false, "classobj"); offsetof(BoxedClassobj, attrs), 0, sizeof(BoxedClassobj), false, "classobj");
...@@ -304,6 +354,8 @@ void setupClassobj() { ...@@ -304,6 +354,8 @@ void setupClassobj() {
instance_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)instanceGetitem, UNKNOWN, 2))); instance_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)instanceGetitem, UNKNOWN, 2)));
instance_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)instanceSetitem, UNKNOWN, 3))); instance_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)instanceSetitem, UNKNOWN, 3)));
instance_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)instanceDelitem, UNKNOWN, 2))); instance_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)instanceDelitem, UNKNOWN, 2)));
instance_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)instanceContains, UNKNOWN, 2)));
instance_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)instanceHash, UNKNOWN, 1)));
instance_cls->freeze(); instance_cls->freeze();
} }
......
...@@ -174,6 +174,15 @@ Box* dictGetitem(BoxedDict* self, Box* k) { ...@@ -174,6 +174,15 @@ Box* dictGetitem(BoxedDict* self, Box* k) {
auto it = self->d.find(k); auto it = self->d.find(k);
if (it == self->d.end()) { if (it == self->d.end()) {
// Try calling __missing__ if this is a subclass
if (self->cls != dict_cls) {
static const std::string missing("__missing__");
Box* r = callattr(self, &missing, CallattrFlags({.cls_only = true, .null_on_nonexistent = true }),
ArgPassSpec(1), k, NULL, NULL, NULL, NULL);
if (r)
return r;
}
raiseExcHelper(KeyError, k); raiseExcHelper(KeyError, k);
} }
...@@ -191,7 +200,7 @@ extern "C" PyObject* PyDict_New() noexcept { ...@@ -191,7 +200,7 @@ extern "C" PyObject* PyDict_New() noexcept {
// The performance should hopefully be comparable to the CPython fast case, since we can use // The performance should hopefully be comparable to the CPython fast case, since we can use
// runtimeICs. // runtimeICs.
extern "C" int PyDict_SetItem(PyObject* mp, PyObject* _key, PyObject* _item) noexcept { extern "C" int PyDict_SetItem(PyObject* mp, PyObject* _key, PyObject* _item) noexcept {
ASSERT(mp->cls == dict_cls || mp->cls == attrwrapper_cls, "%s", getTypeName(mp)); ASSERT(isSubclass(mp->cls, dict_cls) || mp->cls == attrwrapper_cls, "%s", getTypeName(mp));
assert(mp); assert(mp);
Box* b = static_cast<Box*>(mp); Box* b = static_cast<Box*>(mp);
...@@ -219,7 +228,7 @@ extern "C" int PyDict_SetItemString(PyObject* mp, const char* key, PyObject* ite ...@@ -219,7 +228,7 @@ extern "C" int PyDict_SetItemString(PyObject* mp, const char* key, PyObject* ite
} }
extern "C" PyObject* PyDict_GetItem(PyObject* dict, PyObject* key) noexcept { extern "C" PyObject* PyDict_GetItem(PyObject* dict, PyObject* key) noexcept {
ASSERT(dict->cls == dict_cls || dict->cls == attrwrapper_cls, "%s", getTypeName(dict)); ASSERT(isSubclass(dict->cls, dict_cls) || dict->cls == attrwrapper_cls, "%s", getTypeName(dict));
try { try {
return getitem(dict, key); return getitem(dict, key);
} catch (ExcInfo e) { } catch (ExcInfo e) {
...@@ -230,7 +239,7 @@ extern "C" PyObject* PyDict_GetItem(PyObject* dict, PyObject* key) noexcept { ...@@ -230,7 +239,7 @@ extern "C" PyObject* PyDict_GetItem(PyObject* dict, PyObject* key) noexcept {
} }
extern "C" int PyDict_Next(PyObject* op, Py_ssize_t* ppos, PyObject** pkey, PyObject** pvalue) noexcept { extern "C" int PyDict_Next(PyObject* op, Py_ssize_t* ppos, PyObject** pkey, PyObject** pvalue) noexcept {
assert(op->cls == dict_cls); assert(isSubclass(op->cls, dict_cls));
BoxedDict* self = static_cast<BoxedDict*>(op); BoxedDict* self = static_cast<BoxedDict*>(op);
// Callers of PyDict_New() provide a pointer to some storage for this function to use, in // Callers of PyDict_New() provide a pointer to some storage for this function to use, in
...@@ -430,7 +439,7 @@ extern "C" Box* dictNew(Box* _cls, BoxedTuple* args, BoxedDict* kwargs) { ...@@ -430,7 +439,7 @@ extern "C" Box* dictNew(Box* _cls, BoxedTuple* args, BoxedDict* kwargs) {
} }
void dictMerge(BoxedDict* self, Box* other) { void dictMerge(BoxedDict* self, Box* other) {
if (other->cls == dict_cls) { if (isSubclass(other->cls, dict_cls)) {
for (const auto& p : static_cast<BoxedDict*>(other)->d) for (const auto& p : static_cast<BoxedDict*>(other)->d)
self->d[p.first] = p.second; self->d[p.first] = p.second;
return; return;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <cstring> #include <cstring>
#include "runtime/dict.h" #include "runtime/dict.h"
#include "runtime/objmodel.h"
namespace pyston { namespace pyston {
...@@ -23,19 +24,19 @@ BoxedDictIterator::BoxedDictIterator(BoxedDict* d, IteratorType type) ...@@ -23,19 +24,19 @@ BoxedDictIterator::BoxedDictIterator(BoxedDict* d, IteratorType type)
} }
Box* dictIterKeys(Box* s) { Box* dictIterKeys(Box* s) {
assert(s->cls == dict_cls); assert(isSubclass(s->cls, dict_cls));
BoxedDict* self = static_cast<BoxedDict*>(s); BoxedDict* self = static_cast<BoxedDict*>(s);
return new BoxedDictIterator(self, BoxedDictIterator::KeyIterator); return new BoxedDictIterator(self, BoxedDictIterator::KeyIterator);
} }
Box* dictIterValues(Box* s) { Box* dictIterValues(Box* s) {
assert(s->cls == dict_cls); assert(isSubclass(s->cls, dict_cls));
BoxedDict* self = static_cast<BoxedDict*>(s); BoxedDict* self = static_cast<BoxedDict*>(s);
return new BoxedDictIterator(self, BoxedDictIterator::ValueIterator); return new BoxedDictIterator(self, BoxedDictIterator::ValueIterator);
} }
Box* dictIterItems(Box* s) { Box* dictIterItems(Box* s) {
assert(s->cls == dict_cls); assert(isSubclass(s->cls, dict_cls));
BoxedDict* self = static_cast<BoxedDict*>(s); BoxedDict* self = static_cast<BoxedDict*>(s);
return new BoxedDictIterator(self, BoxedDictIterator::ItemIterator); return new BoxedDictIterator(self, BoxedDictIterator::ItemIterator);
} }
......
...@@ -28,7 +28,7 @@ Box* listIterIter(Box* s) { ...@@ -28,7 +28,7 @@ Box* listIterIter(Box* s) {
} }
Box* listIter(Box* s) { Box* listIter(Box* s) {
assert(s->cls == list_cls); assert(isSubclass(s->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(s); BoxedList* self = static_cast<BoxedList*>(s);
return new BoxedListIterator(self, 0); return new BoxedListIterator(self, 0);
} }
...@@ -62,7 +62,7 @@ Box* listiterNext(Box* s) { ...@@ -62,7 +62,7 @@ Box* listiterNext(Box* s) {
Box* listReversed(Box* s) { Box* listReversed(Box* s) {
assert(s->cls == list_cls); assert(isSubclass(s->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(s); BoxedList* self = static_cast<BoxedList*>(s);
return new (list_reverse_iterator_cls) BoxedListIterator(self, self->size - 1); return new (list_reverse_iterator_cls) BoxedListIterator(self, self->size - 1);
} }
...@@ -132,7 +132,7 @@ void BoxedList::ensure(int space) { ...@@ -132,7 +132,7 @@ void BoxedList::ensure(int space) {
extern "C" void listAppendInternal(Box* s, Box* v) { extern "C" void listAppendInternal(Box* s, Box* v) {
// Lock must be held! // Lock must be held!
assert(s->cls == list_cls); assert(isSubclass(s->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(s); BoxedList* self = static_cast<BoxedList*>(s);
assert(self->size <= self->capacity); assert(self->size <= self->capacity);
...@@ -147,7 +147,7 @@ extern "C" void listAppendInternal(Box* s, Box* v) { ...@@ -147,7 +147,7 @@ extern "C" void listAppendInternal(Box* s, Box* v) {
extern "C" void listAppendArrayInternal(Box* s, Box** v, int nelts) { extern "C" void listAppendArrayInternal(Box* s, Box** v, int nelts) {
// Lock must be held! // Lock must be held!
assert(s->cls == list_cls); assert(isSubclass(s->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(s); BoxedList* self = static_cast<BoxedList*>(s);
assert(self->size <= self->capacity); assert(self->size <= self->capacity);
...@@ -161,7 +161,7 @@ extern "C" void listAppendArrayInternal(Box* s, Box** v, int nelts) { ...@@ -161,7 +161,7 @@ extern "C" void listAppendArrayInternal(Box* s, Box** v, int nelts) {
// TODO the inliner doesn't want to inline these; is there any point to having them in the inline section? // TODO the inliner doesn't want to inline these; is there any point to having them in the inline section?
extern "C" Box* listAppend(Box* s, Box* v) { extern "C" Box* listAppend(Box* s, Box* v) {
assert(s->cls == list_cls); assert(isSubclass(s->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(s); BoxedList* self = static_cast<BoxedList*>(s);
LOCK_REGION(self->lock.asWrite()); LOCK_REGION(self->lock.asWrite());
......
...@@ -75,6 +75,12 @@ Box* seqiterNext(Box* s) { ...@@ -75,6 +75,12 @@ Box* seqiterNext(Box* s) {
RELEASE_ASSERT(s->cls == seqiter_cls || s->cls == seqreviter_cls, ""); RELEASE_ASSERT(s->cls == seqiter_cls || s->cls == seqreviter_cls, "");
BoxedSeqIter* self = static_cast<BoxedSeqIter*>(s); BoxedSeqIter* self = static_cast<BoxedSeqIter*>(s);
if (!self->next) {
Box* hasnext = seqiterHasnext(s);
if (hasnext == False)
raiseExcHelper(StopIteration, "");
}
RELEASE_ASSERT(self->next, ""); RELEASE_ASSERT(self->next, "");
Box* r = self->next; Box* r = self->next;
self->next = NULL; self->next = NULL;
......
This diff is collapsed.
...@@ -364,6 +364,13 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset ...@@ -364,6 +364,13 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
} }
void BoxedClass::finishInitialization() { void BoxedClass::finishInitialization() {
assert(!tp_traverse);
assert(!tp_clear);
if (tp_base) {
tp_traverse = tp_base->tp_traverse;
tp_clear = tp_base->tp_clear;
}
commonClassSetup(this); commonClassSetup(this);
} }
...@@ -1913,9 +1920,9 @@ extern "C" bool isinstance(Box* obj, Box* cls, int64_t flags) { ...@@ -1913,9 +1920,9 @@ extern "C" bool isinstance(Box* obj, Box* cls, int64_t flags) {
} }
if (!false_on_noncls) { if (!false_on_noncls) {
assert(cls->cls == type_cls); assert(isSubclass(cls->cls, type_cls));
} else { } else {
if (cls->cls != type_cls) if (!isSubclass(cls->cls, type_cls))
return false; return false;
} }
...@@ -2410,6 +2417,7 @@ static CompiledFunction* pickVersion(CLFunction* f, int num_output_args, Box* oa ...@@ -2410,6 +2417,7 @@ static CompiledFunction* pickVersion(CLFunction* f, int num_output_args, Box* oa
if (f->source == NULL) { if (f->source == NULL) {
// TODO I don't think this should be happening any more? // TODO I don't think this should be happening any more?
printf("Error: couldn't find suitable function version and no source to recompile!\n"); printf("Error: couldn't find suitable function version and no source to recompile!\n");
printf("(First version: %p)\n", f->versions[0]->code);
abort(); abort();
} }
...@@ -2825,7 +2833,7 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg ...@@ -2825,7 +2833,7 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
else else
r = chosen_cf->call(oarg1, oarg2, oarg3, oargs); r = chosen_cf->call(oarg1, oarg2, oarg3, oargs);
ASSERT(chosen_cf->spec->rtn_type->isFitBy(r->cls), "%s (%p) %s %s", ASSERT(chosen_cf->spec->rtn_type->isFitBy(r->cls), "%s (%p) was supposed to return %s, but gave a %s",
g.func_addr_registry.getFuncNameAtAddress(chosen_cf->code, true, NULL).c_str(), chosen_cf->code, g.func_addr_registry.getFuncNameAtAddress(chosen_cf->code, true, NULL).c_str(), chosen_cf->code,
chosen_cf->spec->rtn_type->debugName().c_str(), r->cls->tp_name); chosen_cf->spec->rtn_type->debugName().c_str(), r->cls->tp_name);
return r; return r;
...@@ -3206,17 +3214,11 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -3206,17 +3214,11 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
Box* contained = callattrInternal1(rhs, &contains_str, CLASS_ONLY, NULL, ArgPassSpec(1), lhs); Box* contained = callattrInternal1(rhs, &contains_str, CLASS_ONLY, NULL, ArgPassSpec(1), lhs);
if (contained == NULL) { if (contained == NULL) {
Box* iter = callattrInternal0(rhs, &iter_str, CLASS_ONLY, NULL, ArgPassSpec(0)); int result = _PySequence_IterSearch(rhs, lhs, PY_ITERSEARCH_CONTAINS);
if (iter) if (result < 0)
ASSERT(isUserDefined(rhs->cls), "%s should probably have a __contains__", getTypeName(rhs)); throwCAPIException();
RELEASE_ASSERT(iter == NULL, "need to try iterating"); assert(result == 0 || result == 1);
return boxBool(result);
Box* getitem = typeLookup(rhs->cls, getitem_str, NULL);
if (getitem)
ASSERT(isUserDefined(rhs->cls), "%s should probably have a __contains__", getTypeName(rhs));
RELEASE_ASSERT(getitem == NULL, "need to try old iteration protocol");
raiseExcHelper(TypeError, "argument of type '%s' is not iterable", getTypeName(rhs));
} }
bool b = nonzero(contained); bool b = nonzero(contained);
......
...@@ -147,8 +147,6 @@ static const char* objectNewParameterTypeErrorMsg() { ...@@ -147,8 +147,6 @@ static const char* objectNewParameterTypeErrorMsg() {
} }
} }
bool exceptionMatches(const ExcInfo& e, BoxedClass* cls);
// This function will ascii-encode any unicode objects it gets passed, or return the argument // This function will ascii-encode any unicode objects it gets passed, or return the argument
// unmodified if it wasn't a unicode object. // unmodified if it wasn't a unicode object.
// This is intended for functions that deal with attribute or variable names, which we internally // This is intended for functions that deal with attribute or variable names, which we internally
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "Python.h" #include "Python.h"
#include "capi/types.h"
#include "core/common.h" #include "core/common.h"
#include "core/types.h" #include "core/types.h"
#include "core/util.h" #include "core/util.h"
...@@ -33,6 +34,10 @@ ...@@ -33,6 +34,10 @@
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
extern "C" PyObject* string_rsplit(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_find(PyStringObject* self, PyObject* args) noexcept;
extern "C" PyObject* string_rfind(PyStringObject* self, PyObject* args) noexcept;
namespace pyston { namespace pyston {
BoxedString::BoxedString(const char* s, size_t n) : s(s, n) { BoxedString::BoxedString(const char* s, size_t n) : s(s, n) {
...@@ -1636,14 +1641,6 @@ Box* strSplit(BoxedString* self, BoxedString* sep, BoxedInt* _max_split) { ...@@ -1636,14 +1641,6 @@ Box* strSplit(BoxedString* self, BoxedString* sep, BoxedInt* _max_split) {
} }
} }
Box* strRsplit(BoxedString* self, BoxedString* sep, BoxedInt* _max_split) {
// TODO: implement this for real
// for now, just forward rsplit() to split() in the cases they have to return the same value
assert(isSubclass(_max_split->cls, int_cls));
RELEASE_ASSERT(_max_split->n <= 0, "");
return strSplit(self, sep, _max_split);
}
Box* strStrip(BoxedString* self, Box* chars) { Box* strStrip(BoxedString* self, Box* chars) {
assert(self->cls == str_cls); assert(self->cls == str_cls);
...@@ -1922,49 +1919,6 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) { ...@@ -1922,49 +1919,6 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) {
return result; return result;
} }
Box* strFind(BoxedString* self, Box* elt, Box* _start) {
if (self->cls != str_cls)
raiseExcHelper(TypeError, "descriptor 'find' requires a 'str' object but received a '%s'", getTypeName(self));
if (elt->cls != str_cls)
raiseExcHelper(TypeError, "expected a character buffer object");
if (_start->cls != int_cls) {
raiseExcHelper(TypeError, "'start' must be an int for now");
// Real error message:
// raiseExcHelper(TypeError, "slice indices must be integers or None or have an __index__ method");
}
int64_t start = static_cast<BoxedInt*>(_start)->n;
if (start < 0) {
start += self->s.size();
start = std::max(0L, start);
}
BoxedString* sub = static_cast<BoxedString*>(elt);
size_t r = self->s.find(sub->s, start);
if (r == std::string::npos)
return boxInt(-1);
return boxInt(r);
}
Box* strRfind(BoxedString* self, Box* elt) {
if (self->cls != str_cls)
raiseExcHelper(TypeError, "descriptor 'rfind' requires a 'str' object but received a '%s'", getTypeName(self));
if (elt->cls != str_cls)
raiseExcHelper(TypeError, "expected a character buffer object");
BoxedString* sub = static_cast<BoxedString*>(elt);
size_t r = self->s.rfind(sub->s);
if (r == std::string::npos)
return boxInt(-1);
return boxInt(r);
}
extern "C" Box* strGetitem(BoxedString* self, Box* slice) { extern "C" Box* strGetitem(BoxedString* self, Box* slice) {
assert(self->cls == str_cls); assert(self->cls == str_cls);
...@@ -2188,6 +2142,82 @@ extern "C" void PyString_ConcatAndDel(register PyObject** pv, register PyObject* ...@@ -2188,6 +2142,82 @@ extern "C" void PyString_ConcatAndDel(register PyObject** pv, register PyObject*
PyString_Concat(pv, w); PyString_Concat(pv, w);
} }
static PyObject* string_expandtabs(PyStringObject* self, PyObject* args) noexcept {
const char* e, *p, *qe;
char* q;
Py_ssize_t i, j, incr;
PyObject* u;
int tabsize = 8;
if (!PyArg_ParseTuple(args, "|i:expandtabs", &tabsize))
return NULL;
/* First pass: determine size of output string */
i = 0; /* chars up to and including most recent \n or \r */
j = 0; /* chars since most recent \n or \r (use in tab calculations) */
e = PyString_AS_STRING(self) + PyString_GET_SIZE(self); /* end of input */
for (p = PyString_AS_STRING(self); p < e; p++) {
if (*p == '\t') {
if (tabsize > 0) {
incr = tabsize - (j % tabsize);
if (j > PY_SSIZE_T_MAX - incr)
goto overflow1;
j += incr;
}
} else {
if (j > PY_SSIZE_T_MAX - 1)
goto overflow1;
j++;
if (*p == '\n' || *p == '\r') {
if (i > PY_SSIZE_T_MAX - j)
goto overflow1;
i += j;
j = 0;
}
}
}
if (i > PY_SSIZE_T_MAX - j)
goto overflow1;
/* Second pass: create output string and fill it */
u = PyString_FromStringAndSize(NULL, i + j);
if (!u)
return NULL;
j = 0; /* same as in first pass */
q = PyString_AS_STRING(u); /* next output char */
qe = PyString_AS_STRING(u) + PyString_GET_SIZE(u); /* end of output */
for (p = PyString_AS_STRING(self); p < e; p++) {
if (*p == '\t') {
if (tabsize > 0) {
i = tabsize - (j % tabsize);
j += i;
while (i--) {
if (q >= qe)
goto overflow2;
*q++ = ' ';
}
}
} else {
if (q >= qe)
goto overflow2;
*q++ = *p;
j++;
if (*p == '\n' || *p == '\r')
j = 0;
}
}
return u;
overflow2:
Py_DECREF(u);
overflow1:
PyErr_SetString(PyExc_OverflowError, "new string is too long");
return NULL;
}
static Py_ssize_t string_buffer_getreadbuf(PyObject* self, Py_ssize_t index, const void** ptr) noexcept { static Py_ssize_t string_buffer_getreadbuf(PyObject* self, Py_ssize_t index, const void** ptr) noexcept {
RELEASE_ASSERT(index == 0, ""); RELEASE_ASSERT(index == 0, "");
...@@ -2236,6 +2266,13 @@ void strDestructor(Box* b) { ...@@ -2236,6 +2266,13 @@ void strDestructor(Box* b) {
self->s.~basic_string(); self->s.~basic_string();
} }
static PyMethodDef string_methods[] = {
{ "rsplit", (PyCFunction)string_rsplit, METH_VARARGS, NULL },
{ "find", (PyCFunction)string_find, METH_VARARGS, NULL },
{ "rfind", (PyCFunction)string_rfind, METH_VARARGS, NULL },
{ "expandtabs", (PyCFunction)string_expandtabs, METH_VARARGS, NULL },
};
void setupStr() { void setupStr() {
str_cls->simple_destructor = strDestructor; str_cls->simple_destructor = strDestructor;
str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
...@@ -2289,16 +2326,12 @@ void setupStr() { ...@@ -2289,16 +2326,12 @@ void setupStr() {
str_cls->giveAttr("endswith", str_cls->giveAttr("endswith",
new BoxedFunction(boxRTFunction((void*)strEndswith, BOXED_BOOL, 4, 2, 0, 0), { NULL, NULL })); new BoxedFunction(boxRTFunction((void*)strEndswith, BOXED_BOOL, 4, 2, 0, 0), { NULL, NULL }));
str_cls->giveAttr("find",
new BoxedFunction(boxRTFunction((void*)strFind, BOXED_INT, 3, 1, false, false), { boxInt(0) }));
str_cls->giveAttr("rfind", new BoxedFunction(boxRTFunction((void*)strRfind, BOXED_INT, 2)));
str_cls->giveAttr("partition", new BoxedFunction(boxRTFunction((void*)strPartition, UNKNOWN, 2))); str_cls->giveAttr("partition", new BoxedFunction(boxRTFunction((void*)strPartition, UNKNOWN, 2)));
str_cls->giveAttr("format", new BoxedFunction(boxRTFunction((void*)strFormat, UNKNOWN, 1, 0, true, true))); str_cls->giveAttr("format", new BoxedFunction(boxRTFunction((void*)strFormat, UNKNOWN, 1, 0, true, true)));
str_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)strAdd, UNKNOWN, 2))); str_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)strAdd, UNKNOWN, 2)));
str_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)strMod, STR, 2))); str_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)strMod, UNKNOWN, 2)));
str_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2))); str_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2)));
// TODO not sure if this is right in all cases: // TODO not sure if this is right in all cases:
str_cls->giveAttr("__rmul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2))); str_cls->giveAttr("__rmul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2)));
...@@ -2329,8 +2362,10 @@ void setupStr() { ...@@ -2329,8 +2362,10 @@ void setupStr() {
str_cls->giveAttr( str_cls->giveAttr(
"split", new BoxedFunction(boxRTFunction((void*)strSplit, LIST, 3, 2, false, false), { None, boxInt(-1) })); "split", new BoxedFunction(boxRTFunction((void*)strSplit, LIST, 3, 2, false, false), { None, boxInt(-1) }));
str_cls->giveAttr(
"rsplit", new BoxedFunction(boxRTFunction((void*)strRsplit, LIST, 3, 2, false, false), { None, boxInt(-1) })); for (auto& md : string_methods) {
str_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, str_cls));
}
CLFunction* count = boxRTFunction((void*)strCount2Unboxed, INT, 2); CLFunction* count = boxRTFunction((void*)strCount2Unboxed, INT, 2);
addRTFunction(count, (void*)strCount2, BOXED_INT); addRTFunction(count, (void*)strCount2, BOXED_INT);
......
...@@ -511,10 +511,13 @@ static int call_gc_visit(PyObject* val, void* arg) { ...@@ -511,10 +511,13 @@ static int call_gc_visit(PyObject* val, void* arg) {
static void proxy_to_tp_traverse(GCVisitor* v, Box* b) { static void proxy_to_tp_traverse(GCVisitor* v, Box* b) {
boxGCHandler(v, b); boxGCHandler(v, b);
assert(b->cls->tp_traverse);
b->cls->tp_traverse(b, call_gc_visit, v); b->cls->tp_traverse(b, call_gc_visit, v);
} }
static void proxy_to_tp_clear(Box* b) { static void proxy_to_tp_clear(Box* b) {
assert(b->cls->tp_clear);
b->cls->tp_clear(b); b->cls->tp_clear(b);
} }
......
...@@ -92,3 +92,7 @@ print l ...@@ -92,3 +92,7 @@ print l
print bytes print bytes
print bytes is str print bytes is str
print repr(b'1234') print repr(b'1234')
print callable(1)
print callable(int)
print callable(lambda: 1)
...@@ -7,3 +7,8 @@ for i in xrange(30): ...@@ -7,3 +7,8 @@ for i in xrange(30):
print o print o
print collections.deque().maxlen print collections.deque().maxlen
d = collections.defaultdict(lambda: [])
print d[1]
d[2].append(3)
print sorted(d.items())
...@@ -21,3 +21,42 @@ for i in xrange(1, 4): ...@@ -21,3 +21,42 @@ for i in xrange(1, 4):
print i in (1, 2, 5) print i in (1, 2, 5)
class D(object):
def __getitem__(self, i):
print i
if i < 10:
return i ** 2
raise IndexError()
d = D()
print 5 in d
print 15 in d
print 25 in d
class D():
def __getitem__(self, i):
print i
if i < 10:
return i ** 2
raise IndexError()
d = D()
print 5 in d
print 15 in d
print 25 in d
class F():
def __init__(self):
self.n = 0
def __iter__(self):
return self
def next(self):
if self.n >= 10:
raise StopIteration()
self.n += 1
return self.n ** 2
f = F()
print 5 in f
print 15 in f
print 25 in f
# expected: fail
# - exceptions
class D(object):
def __getitem__(self, idx):
print "getitem", idx
if idx >= 20:
raise IndexError()
return idx
print 10 in D()
print 1000 in D()
class MyDict(dict):
pass
d = MyDict()
d[1] = 2
print d.keys()
print d.values()
print d.items()
print list(d.iterkeys())
print list(d.itervalues())
print list(d.iteritems())
class DictWithMissing(dict):
def __missing__(self, key):
print key
return key
d = DictWithMissing()
print d[5]
...@@ -129,3 +129,18 @@ try: ...@@ -129,3 +129,18 @@ try:
except ZeroDivisionError: except ZeroDivisionError:
pass pass
print l print l
idxs = [-100, -50, -5, -1, 0, 1, 5, 50, 100]
for i1 in idxs:
for i2 in idxs:
l = range(10)
del l[i1:i2]
print i1, i2, l
l = []
del l[:]
print l
l = range(5)
l[2:4] = tuple(range(2))
print l
class MyList(list):
pass
l = MyList(range(5))
print type(l)
l.foo = 1
print l.foo
print l
print len(MyList.__new__(MyList))
l[:] = l[:]
print l
...@@ -26,6 +26,9 @@ class C(object): ...@@ -26,6 +26,9 @@ class C(object):
__metaclass__ = M __metaclass__ = M
print "Made C", type(C) print "Made C", type(C)
print isinstance(C, M)
print isinstance(C, type)
print isinstance(C, int)
def f(*args): def f(*args):
print "f()", args[:2] print "f()", args[:2]
......
...@@ -140,3 +140,10 @@ m = MappingTest() ...@@ -140,3 +140,10 @@ m = MappingTest()
m[1] = 2 m[1] = 2
del m[2] del m[2]
print m[3] print m[3]
class Hashable:
def __hash__(self):
return 5
print hash(Hashable())
del Hashable.__hash__
print type(hash(Hashable()))
...@@ -15,6 +15,8 @@ print " test ".rsplit() ...@@ -15,6 +15,8 @@ print " test ".rsplit()
print " test ".rsplit(' ') print " test ".rsplit(' ')
print " test ".rsplit(None) print " test ".rsplit(None)
print "1<>2<>3".rsplit('<>') print "1<>2<>3".rsplit('<>')
print "1<>2<>3".rsplit('<>', 1)
print "1<>2<>3".split('<>', 1)
print map(bool, ["hello", "", "world"]) print map(bool, ["hello", "", "world"])
...@@ -78,7 +80,8 @@ print "hello world".translate(translation_map, "llo") ...@@ -78,7 +80,8 @@ print "hello world".translate(translation_map, "llo")
print "hello world".translate(None, "llo") print "hello world".translate(None, "llo")
for i in xrange(-10, 10): for i in xrange(-10, 10):
print i, "aaaaa".find("a", i) print i, "aaaaa".find("a", i), "aaaa".find("a", 2, i)
print i, "aaaaa".rfind("a", i), "aaaa".rfind("a", 2, i)
print "hello world".partition("hi") print "hello world".partition("hi")
print "hello world".partition("hello") print "hello world".partition("hello")
...@@ -134,3 +137,5 @@ try: ...@@ -134,3 +137,5 @@ try:
except: except:
print "threw exception" print "threw exception"
print repr("hello\tworld\t".expandtabs())
print repr("hello\tworld\t".expandtabs(12))
...@@ -79,3 +79,5 @@ def f(a): ...@@ -79,3 +79,5 @@ def f(a):
f(a=1) f(a=1)
f(**{'a':2}) f(**{'a':2})
f(**{u'a':3}) f(**{u'a':3})
print repr('%s' % u'') # this gives a unicode object!
# Make sure we can subclass from weakref.ref, since the weakref module itself does this
from weakref import ref
class MyRef(ref):
pass
for i in xrange(100):
m = MyRef(MyRef)
import gc
gc.collect()
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