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 @@
#include "Python.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
#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
// and unicodeobject.c. We want to access it from str.cpp, though, so just use this little forwarding
// function.
......@@ -16,3 +22,83 @@
PyObject * _do_string_format(PyObject *self, PyObject *args, PyObject *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 {
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 {
va_list va;
PyObject* args;
......
......@@ -472,6 +472,8 @@ Box* bltinImport(Box* name, Box* globals, Box* locals, Box** args) {
Box* fromlist = args[0];
Box* level = args[1];
name = coerceUnicodeToStr(name);
if (name->cls != str_cls) {
raiseExcHelper(TypeError, "__import__() argument 1 must be string, not %s", getTypeName(name));
}
......@@ -673,6 +675,12 @@ Box* eval(Box* code) {
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;
BoxedModule* builtins_module;
......@@ -1146,6 +1154,8 @@ void setupBuiltins() {
builtins_module->giveAttr(
"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");
builtins_module->giveAttr("buffer", buffer_cls);
......
......@@ -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 {
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 {
......@@ -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 }),
ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
} catch (ExcInfo e) {
setCAPIException(e);
if (!e.matches(StopIteration))
setCAPIException(e);
return NULL;
}
}
......
......@@ -16,6 +16,7 @@
#include <sstream>
#include "capi/types.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/objmodel.h"
......@@ -277,6 +278,55 @@ Box* instanceDelitem(Box* _inst, Box* key) {
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() {
classobj_cls = BoxedHeapClass::create(type_cls, object_cls, &BoxedClassobj::gcHandler,
offsetof(BoxedClassobj, attrs), 0, sizeof(BoxedClassobj), false, "classobj");
......@@ -304,6 +354,8 @@ void setupClassobj() {
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("__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();
}
......
......@@ -174,6 +174,15 @@ Box* dictGetitem(BoxedDict* self, Box* k) {
auto it = self->d.find(k);
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);
}
......@@ -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
// runtimeICs.
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);
Box* b = static_cast<Box*>(mp);
......@@ -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 {
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 {
return getitem(dict, key);
} catch (ExcInfo e) {
......@@ -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 {
assert(op->cls == dict_cls);
assert(isSubclass(op->cls, dict_cls));
BoxedDict* self = static_cast<BoxedDict*>(op);
// 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) {
}
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)
self->d[p.first] = p.second;
return;
......
......@@ -15,6 +15,7 @@
#include <cstring>
#include "runtime/dict.h"
#include "runtime/objmodel.h"
namespace pyston {
......@@ -23,19 +24,19 @@ BoxedDictIterator::BoxedDictIterator(BoxedDict* d, IteratorType type)
}
Box* dictIterKeys(Box* s) {
assert(s->cls == dict_cls);
assert(isSubclass(s->cls, dict_cls));
BoxedDict* self = static_cast<BoxedDict*>(s);
return new BoxedDictIterator(self, BoxedDictIterator::KeyIterator);
}
Box* dictIterValues(Box* s) {
assert(s->cls == dict_cls);
assert(isSubclass(s->cls, dict_cls));
BoxedDict* self = static_cast<BoxedDict*>(s);
return new BoxedDictIterator(self, BoxedDictIterator::ValueIterator);
}
Box* dictIterItems(Box* s) {
assert(s->cls == dict_cls);
assert(isSubclass(s->cls, dict_cls));
BoxedDict* self = static_cast<BoxedDict*>(s);
return new BoxedDictIterator(self, BoxedDictIterator::ItemIterator);
}
......
......@@ -28,7 +28,7 @@ Box* listIterIter(Box* s) {
}
Box* listIter(Box* s) {
assert(s->cls == list_cls);
assert(isSubclass(s->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(s);
return new BoxedListIterator(self, 0);
}
......@@ -62,7 +62,7 @@ Box* listiterNext(Box* s) {
Box* listReversed(Box* s) {
assert(s->cls == list_cls);
assert(isSubclass(s->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(s);
return new (list_reverse_iterator_cls) BoxedListIterator(self, self->size - 1);
}
......@@ -132,7 +132,7 @@ void BoxedList::ensure(int space) {
extern "C" void listAppendInternal(Box* s, Box* v) {
// Lock must be held!
assert(s->cls == list_cls);
assert(isSubclass(s->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(s);
assert(self->size <= self->capacity);
......@@ -147,7 +147,7 @@ extern "C" void listAppendInternal(Box* s, Box* v) {
extern "C" void listAppendArrayInternal(Box* s, Box** v, int nelts) {
// Lock must be held!
assert(s->cls == list_cls);
assert(isSubclass(s->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(s);
assert(self->size <= self->capacity);
......@@ -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?
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);
LOCK_REGION(self->lock.asWrite());
......
......@@ -75,6 +75,12 @@ Box* seqiterNext(Box* s) {
RELEASE_ASSERT(s->cls == seqiter_cls || s->cls == seqreviter_cls, "");
BoxedSeqIter* self = static_cast<BoxedSeqIter*>(s);
if (!self->next) {
Box* hasnext = seqiterHasnext(s);
if (hasnext == False)
raiseExcHelper(StopIteration, "");
}
RELEASE_ASSERT(self->next, "");
Box* r = self->next;
self->next = NULL;
......
This diff is collapsed.
......@@ -364,6 +364,13 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
}
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);
}
......@@ -1913,9 +1920,9 @@ extern "C" bool isinstance(Box* obj, Box* cls, int64_t flags) {
}
if (!false_on_noncls) {
assert(cls->cls == type_cls);
assert(isSubclass(cls->cls, type_cls));
} else {
if (cls->cls != type_cls)
if (!isSubclass(cls->cls, type_cls))
return false;
}
......@@ -2410,6 +2417,7 @@ static CompiledFunction* pickVersion(CLFunction* f, int num_output_args, Box* oa
if (f->source == NULL) {
// 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("(First version: %p)\n", f->versions[0]->code);
abort();
}
......@@ -2825,7 +2833,7 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
else
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,
chosen_cf->spec->rtn_type->debugName().c_str(), r->cls->tp_name);
return r;
......@@ -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);
if (contained == NULL) {
Box* iter = callattrInternal0(rhs, &iter_str, CLASS_ONLY, NULL, ArgPassSpec(0));
if (iter)
ASSERT(isUserDefined(rhs->cls), "%s should probably have a __contains__", getTypeName(rhs));
RELEASE_ASSERT(iter == NULL, "need to try iterating");
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));
int result = _PySequence_IterSearch(rhs, lhs, PY_ITERSEARCH_CONTAINS);
if (result < 0)
throwCAPIException();
assert(result == 0 || result == 1);
return boxBool(result);
}
bool b = nonzero(contained);
......
......@@ -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
// unmodified if it wasn't a unicode object.
// This is intended for functions that deal with attribute or variable names, which we internally
......
......@@ -23,6 +23,7 @@
#include "Python.h"
#include "capi/types.h"
#include "core/common.h"
#include "core/types.h"
#include "core/util.h"
......@@ -33,6 +34,10 @@
#include "runtime/types.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 {
BoxedString::BoxedString(const char* s, size_t n) : s(s, n) {
......@@ -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) {
assert(self->cls == str_cls);
......@@ -1922,49 +1919,6 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) {
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) {
assert(self->cls == str_cls);
......@@ -2188,6 +2142,82 @@ extern "C" void PyString_ConcatAndDel(register PyObject** pv, register PyObject*
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 {
RELEASE_ASSERT(index == 0, "");
......@@ -2236,6 +2266,13 @@ void strDestructor(Box* b) {
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() {
str_cls->simple_destructor = strDestructor;
str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
......@@ -2289,16 +2326,12 @@ void setupStr() {
str_cls->giveAttr("endswith",
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("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("__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)));
// TODO not sure if this is right in all cases:
str_cls->giveAttr("__rmul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2)));
......@@ -2329,8 +2362,10 @@ void setupStr() {
str_cls->giveAttr(
"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);
addRTFunction(count, (void*)strCount2, BOXED_INT);
......
......@@ -511,10 +511,13 @@ static int call_gc_visit(PyObject* val, void* arg) {
static void proxy_to_tp_traverse(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
assert(b->cls->tp_traverse);
b->cls->tp_traverse(b, call_gc_visit, v);
}
static void proxy_to_tp_clear(Box* b) {
assert(b->cls->tp_clear);
b->cls->tp_clear(b);
}
......
......@@ -92,3 +92,7 @@ print l
print bytes
print bytes is str
print repr(b'1234')
print callable(1)
print callable(int)
print callable(lambda: 1)
......@@ -7,3 +7,8 @@ for i in xrange(30):
print o
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):
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:
except ZeroDivisionError:
pass
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):
__metaclass__ = M
print "Made C", type(C)
print isinstance(C, M)
print isinstance(C, type)
print isinstance(C, int)
def f(*args):
print "f()", args[:2]
......
......@@ -140,3 +140,10 @@ m = MappingTest()
m[1] = 2
del m[2]
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()
print " test ".rsplit(' ')
print " test ".rsplit(None)
print "1<>2<>3".rsplit('<>')
print "1<>2<>3".rsplit('<>', 1)
print "1<>2<>3".split('<>', 1)
print map(bool, ["hello", "", "world"])
......@@ -78,7 +80,8 @@ print "hello world".translate(translation_map, "llo")
print "hello world".translate(None, "llo")
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("hello")
......@@ -134,3 +137,5 @@ try:
except:
print "threw exception"
print repr("hello\tworld\t".expandtabs())
print repr("hello\tworld\t".expandtabs(12))
......@@ -79,3 +79,5 @@ def f(a):
f(a=1)
f(**{'a':2})
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