Commit 93a9f529 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'master' into refcounting

parents d849bb93 c9268664
...@@ -38,6 +38,7 @@ addons: ...@@ -38,6 +38,7 @@ addons:
- g++-4.8 - g++-4.8
- gdb - gdb
- libbz2-dev - libbz2-dev
- libgeoip-dev
- libgmp3-dev - libgmp3-dev
- libmpfr-dev - libmpfr-dev
- liblzma-dev - liblzma-dev
......
...@@ -28,6 +28,12 @@ sudo apt-get install -yq automake git cmake ninja-build ccache libncurses5-dev l ...@@ -28,6 +28,12 @@ sudo apt-get install -yq automake git cmake ninja-build ccache libncurses5-dev l
sudo yum install git make cmake clang gcc gcc-c++ ccache ninja-build xz-devel automake libtool gmp-devel mpfr-devel readline-devel openssl-devel sqlite-devel python-devel zlib-devel bzip2-devel ncurses-devel texlive-latex2man libffi-devel sudo yum install git make cmake clang gcc gcc-c++ ccache ninja-build xz-devel automake libtool gmp-devel mpfr-devel readline-devel openssl-devel sqlite-devel python-devel zlib-devel bzip2-devel ncurses-devel texlive-latex2man libffi-devel
``` ```
### Additional prerequisites for running the integration tests
**Ubuntu**
```
sudo apt-get install libgeoip-dev
```
### Building and testing ### Building and testing
``` ```
git clone https://github.com/dropbox/pyston.git ~/pyston git clone https://github.com/dropbox/pyston.git ~/pyston
......
...@@ -1947,15 +1947,15 @@ extern "C" PyObject* PyNumber_Positive(PyObject* o) noexcept { ...@@ -1947,15 +1947,15 @@ extern "C" PyObject* PyNumber_Positive(PyObject* o) noexcept {
} }
extern "C" PyObject* PyNumber_Absolute(PyObject* o) noexcept { extern "C" PyObject* PyNumber_Absolute(PyObject* o) noexcept {
if (o == Py_None) PyNumberMethods* m;
return type_error("bad operand type for abs(): '%.200s'", o);
try { if (o == NULL)
return abs_(o); return null_error();
} catch (ExcInfo e) { m = o->cls->tp_as_number;
fatalOrError(PyExc_NotImplementedError, "unimplemented"); if (m && m->nb_absolute)
return nullptr; return m->nb_absolute(o);
}
return type_error("bad operand type for abs(): '%.200s'", o);
} }
extern "C" PyObject* PyNumber_Invert(PyObject* o) noexcept { extern "C" PyObject* PyNumber_Invert(PyObject* o) noexcept {
......
...@@ -86,6 +86,7 @@ static PyObject* do_mklist(const char**, va_list*, int, int, int) noexcept; ...@@ -86,6 +86,7 @@ static PyObject* do_mklist(const char**, va_list*, int, int, int) noexcept;
static PyObject* do_mkdict(const char**, va_list*, int, int, int) noexcept; static PyObject* do_mkdict(const char**, va_list*, int, int, int) noexcept;
static PyObject* do_mkvalue(const char**, va_list*, int) noexcept; static PyObject* do_mkvalue(const char**, va_list*, int) noexcept;
typedef double va_double;
static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noexcept { static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noexcept {
for (;;) { for (;;) {
switch (*(*p_format)++) { switch (*(*p_format)++) {
...@@ -124,8 +125,54 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe ...@@ -124,8 +125,54 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe
case 'l': case 'l':
return PyInt_FromLong(va_arg(*p_va, long)); return PyInt_FromLong(va_arg(*p_va, long));
case 'k': {
unsigned long n;
n = va_arg(*p_va, unsigned long);
if (n > (unsigned long)PyInt_GetMax())
return PyLong_FromUnsignedLong(n);
else
return PyInt_FromLong(n);
}
#ifdef HAVE_LONG_LONG
case 'L':
return PyLong_FromLongLong((PY_LONG_LONG)va_arg(*p_va, PY_LONG_LONG));
case 'K':
return PyLong_FromUnsignedLongLong((PY_LONG_LONG)va_arg(*p_va, unsigned PY_LONG_LONG));
#endif
#ifdef Py_USING_UNICODE
case 'u': {
PyObject* v;
Py_UNICODE* u = va_arg(*p_va, Py_UNICODE*);
Py_ssize_t n;
if (**p_format == '#') {
++*p_format;
if (flags & FLAG_SIZE_T)
n = va_arg(*p_va, Py_ssize_t);
else
n = va_arg(*p_va, int);
} else
n = -1;
if (u == NULL) {
v = Py_None;
Py_INCREF(v);
} else {
if (n < 0)
n = _ustrlen(u);
v = PyUnicode_FromUnicode(u, n);
}
return v;
}
#endif
case 'f':
case 'd': case 'd':
return PyFloat_FromDouble(va_arg(*p_va, double)); return PyFloat_FromDouble((double)va_arg(*p_va, va_double));
#ifndef WITHOUT_COMPLEX
case 'D':
return PyComplex_FromCComplex(*((Py_complex*)va_arg(*p_va, Py_complex*)));
#endif /* WITHOUT_COMPLEX */
case 'c': { case 'c': {
char p[1]; char p[1];
...@@ -133,34 +180,6 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe ...@@ -133,34 +180,6 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe
return PyString_FromStringAndSize(p, 1); return PyString_FromStringAndSize(p, 1);
} }
case 'N':
case 'S':
case 'O':
if (**p_format == '&') {
typedef PyObject* (*converter)(void*);
converter func = va_arg(*p_va, converter);
void* arg = va_arg(*p_va, void*);
++*p_format;
return (*func)(arg);
} else {
PyObject* v;
v = va_arg(*p_va, PyObject*);
if (v != NULL) {
if (*(*p_format - 1) != 'N')
Py_INCREF(v);
} else if (!PyErr_Occurred())
/* If a NULL was passed
* because a call that should
* have constructed a value
* failed, that's OK, and we
* pass the error on; but if
* no error occurred it's not
* clear that the caller knew
* what she was doing. */
PyErr_SetString(PyExc_SystemError, "NULL object passed to Py_BuildValue");
return v;
}
case 's': case 's':
case 'z': { case 'z': {
PyObject* v; PyObject* v;
...@@ -190,37 +209,34 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe ...@@ -190,37 +209,34 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe
} }
return v; return v;
} }
#ifdef HAVE_LONG_LONG
case 'L':
return PyLong_FromLongLong((PY_LONG_LONG)va_arg(*p_va, PY_LONG_LONG));
case 'K': case 'N':
return PyLong_FromUnsignedLongLong((PY_LONG_LONG)va_arg(*p_va, unsigned PY_LONG_LONG)); case 'S':
#endif case 'O':
#ifdef Py_USING_UNICODE if (**p_format == '&') {
case 'u': { typedef PyObject* (*converter)(void*);
PyObject* v; converter func = va_arg(*p_va, converter);
Py_UNICODE* u = va_arg(*p_va, Py_UNICODE*); void* arg = va_arg(*p_va, void*);
Py_ssize_t n;
if (**p_format == '#') {
++*p_format; ++*p_format;
if (flags & FLAG_SIZE_T) return (*func)(arg);
n = va_arg(*p_va, Py_ssize_t);
else
n = va_arg(*p_va, int);
} else
n = -1;
if (u == NULL) {
v = Py_None;
Py_INCREF(v);
} else { } else {
if (n < 0) PyObject* v;
n = _ustrlen(u); v = va_arg(*p_va, PyObject*);
v = PyUnicode_FromUnicode(u, n); if (v != NULL) {
} if (*(*p_format - 1) != 'N')
Py_INCREF(v);
} else if (!PyErr_Occurred())
/* If a NULL was passed
* because a call that should
* have constructed a value
* failed, that's OK, and we
* pass the error on; but if
* no error occurred it's not
* clear that the caller knew
* what she was doing. */
PyErr_SetString(PyExc_SystemError, "NULL object passed to Py_BuildValue");
return v; return v;
} }
#endif
case ':': case ':':
case ',': case ',':
...@@ -229,7 +245,8 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe ...@@ -229,7 +245,8 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe
break; break;
default: default:
RELEASE_ASSERT(0, "%c", *((*p_format) - 1)); PyErr_SetString(PyExc_SystemError, "bad format char passed to Py_BuildValue");
return NULL;
} }
} }
abort(); abort();
......
...@@ -90,19 +90,10 @@ extern "C" Box* vars(Box* obj) { ...@@ -90,19 +90,10 @@ extern "C" Box* vars(Box* obj) {
} }
extern "C" Box* abs_(Box* x) { extern "C" Box* abs_(Box* x) {
if (PyInt_Check(x)) { Box* rtn = PyNumber_Absolute(x);
i64 n = static_cast<BoxedInt*>(x)->n; if (!rtn)
return boxInt(n >= 0 ? n : -n); throwCAPIException();
} else if (x->cls == float_cls) { return rtn;
double d = static_cast<BoxedFloat*>(x)->d;
return boxFloat(std::abs(d));
} else if (x->cls == long_cls) {
return longAbs(static_cast<BoxedLong*>(x));
} else {
static BoxedString* abs_str = getStaticString("__abs__");
CallattrFlags callattr_flags{.cls_only = true, .null_on_nonexistent = false, .argspec = ArgPassSpec(0) };
return callattr(x, abs_str, callattr_flags, NULL, NULL, NULL, NULL, NULL);
}
} }
extern "C" Box* binFunc(Box* x) { extern "C" Box* binFunc(Box* x) {
...@@ -326,11 +317,12 @@ extern "C" Box* chr(Box* arg) { ...@@ -326,11 +317,12 @@ extern "C" Box* chr(Box* arg) {
} }
extern "C" Box* unichr(Box* arg) { extern "C" Box* unichr(Box* arg) {
if (arg->cls != int_cls) int n = -1;
raiseExcHelper(TypeError, "an integer is required"); if (!PyArg_ParseSingle(arg, 0, "unichr", "i", &n))
throwCAPIException();
i64 n = static_cast<BoxedInt*>(arg)->n;
Box* rtn = PyUnicode_FromOrdinal(n); Box* rtn = PyUnicode_FromOrdinal(n);
if (!rtn)
checkAndThrowCAPIException(); checkAndThrowCAPIException();
return rtn; return rtn;
} }
...@@ -937,6 +929,111 @@ Fail_1: ...@@ -937,6 +929,111 @@ Fail_1:
return NULL; return NULL;
} }
static PyObject* filterunicode(PyObject* func, PyObject* strobj) {
PyObject* result;
Py_ssize_t i, j;
Py_ssize_t len = PyUnicode_GetSize(strobj);
Py_ssize_t outlen = len;
if (func == Py_None) {
/* If it's a real string we can return the original,
* as no character is ever false and __getitem__
* does return this character. If it's a subclass
* we must go through the __getitem__ loop */
if (PyUnicode_CheckExact(strobj)) {
Py_INCREF(strobj);
return strobj;
}
}
if ((result = PyUnicode_FromUnicode(NULL, len)) == NULL)
return NULL;
for (i = j = 0; i < len; ++i) {
PyObject* item, *arg, *good;
int ok;
item = (*strobj->cls->tp_as_sequence->sq_item)(strobj, i);
if (item == NULL)
goto Fail_1;
if (func == Py_None) {
ok = 1;
} else {
arg = PyTuple_Pack(1, item);
if (arg == NULL) {
Py_DECREF(item);
goto Fail_1;
}
good = PyEval_CallObject(func, arg);
Py_DECREF(arg);
if (good == NULL) {
Py_DECREF(item);
goto Fail_1;
}
ok = PyObject_IsTrue(good);
Py_DECREF(good);
}
if (ok > 0) {
Py_ssize_t reslen;
if (!PyUnicode_Check(item)) {
PyErr_SetString(PyExc_TypeError, "can't filter unicode to unicode:"
" __getitem__ returned different type");
Py_DECREF(item);
goto Fail_1;
}
reslen = PyUnicode_GET_SIZE(item);
if (reslen == 1)
PyUnicode_AS_UNICODE(result)[j++] = PyUnicode_AS_UNICODE(item)[0];
else {
/* do we need more space? */
Py_ssize_t need = j + reslen + len - i - 1;
/* check that didnt overflow */
if ((j > PY_SSIZE_T_MAX - reslen) || ((j + reslen) > PY_SSIZE_T_MAX - len) || ((j + reslen + len) < i)
|| ((j + reslen + len - i) <= 0)) {
Py_DECREF(item);
return NULL;
}
assert(need >= 0);
assert(outlen >= 0);
if (need > outlen) {
/* overallocate,
to avoid reallocations */
if (need < 2 * outlen) {
if (outlen > PY_SSIZE_T_MAX / 2) {
Py_DECREF(item);
return NULL;
} else {
need = 2 * outlen;
}
}
if (PyUnicode_Resize(&result, need) < 0) {
Py_DECREF(item);
goto Fail_1;
}
outlen = need;
}
memcpy(PyUnicode_AS_UNICODE(result) + j, PyUnicode_AS_UNICODE(item), reslen * sizeof(Py_UNICODE));
j += reslen;
}
}
Py_DECREF(item);
if (ok < 0)
goto Fail_1;
}
if (j < outlen)
PyUnicode_Resize(&result, j);
return result;
Fail_1:
Py_DECREF(result);
return NULL;
}
static PyObject* filtertuple(PyObject* func, PyObject* tuple) { static PyObject* filtertuple(PyObject* func, PyObject* tuple) {
PyObject* result; PyObject* result;
Py_ssize_t i, j; Py_ssize_t i, j;
...@@ -1013,7 +1110,6 @@ Box* filter2(Box* f, Box* container) { ...@@ -1013,7 +1110,6 @@ Box* filter2(Box* f, Box* container) {
f = bool_cls; f = bool_cls;
// Special cases depending on the type of container influences the return type // Special cases depending on the type of container influences the return type
// TODO There are other special cases like this
if (PyTuple_Check(container)) { if (PyTuple_Check(container)) {
Box* rtn = filtertuple(f, static_cast<BoxedTuple*>(container)); Box* rtn = filtertuple(f, static_cast<BoxedTuple*>(container));
if (!rtn) { if (!rtn) {
...@@ -1030,6 +1126,14 @@ Box* filter2(Box* f, Box* container) { ...@@ -1030,6 +1126,14 @@ Box* filter2(Box* f, Box* container) {
return rtn; return rtn;
} }
if (PyUnicode_Check(container)) {
Box* rtn = filterunicode(f, container);
if (!rtn) {
throwCAPIException();
}
return rtn;
}
Box* rtn = new BoxedList(); Box* rtn = new BoxedList();
for (Box* e : container->pyElements()) { for (Box* e : container->pyElements()) {
Box* r = runtimeCall(f, ArgPassSpec(1), e, NULL, NULL, NULL, NULL); Box* r = runtimeCall(f, ArgPassSpec(1), e, NULL, NULL, NULL, NULL);
...@@ -1157,20 +1261,26 @@ class BoxedEnumerate : public Box { ...@@ -1157,20 +1261,26 @@ class BoxedEnumerate : public Box {
private: private:
BoxIterator iterator, iterator_end; BoxIterator iterator, iterator_end;
int64_t idx; int64_t idx;
BoxedLong* idx_long;
public: public:
BoxedEnumerate(BoxIterator iterator_begin, BoxIterator iterator_end, int64_t idx) BoxedEnumerate(BoxIterator iterator_begin, BoxIterator iterator_end, int64_t idx, BoxedLong* idx_long)
: iterator(iterator_begin), iterator_end(iterator_end), idx(idx) {} : iterator(iterator_begin), iterator_end(iterator_end), idx(idx), idx_long(idx_long) {}
DEFAULT_CLASS(enumerate_cls); DEFAULT_CLASS(enumerate_cls);
static Box* new_(Box* cls, Box* obj, Box* start) { static Box* new_(Box* cls, Box* obj, Box* start) {
RELEASE_ASSERT(cls == enumerate_cls, ""); RELEASE_ASSERT(cls == enumerate_cls, "");
RELEASE_ASSERT(PyInt_Check(start), ""); RELEASE_ASSERT(PyInt_Check(start) || PyLong_Check(start), "");
int64_t idx = static_cast<BoxedInt*>(start)->n; int64_t idx = PyInt_AsSsize_t(start);
BoxedLong* idx_long = NULL;
if (idx == -1 && PyErr_Occurred()) {
PyErr_Clear();
assert(PyLong_Check(start));
idx_long = (BoxedLong*)start;
}
llvm::iterator_range<BoxIterator> range = obj->pyElements(); llvm::iterator_range<BoxIterator> range = obj->pyElements();
return new BoxedEnumerate(range.begin(), range.end(), idx); return new BoxedEnumerate(range.begin(), range.end(), idx, idx_long);
} }
static Box* iter(Box* _self) noexcept { static Box* iter(Box* _self) noexcept {
...@@ -1184,7 +1294,19 @@ public: ...@@ -1184,7 +1294,19 @@ public:
BoxedEnumerate* self = static_cast<BoxedEnumerate*>(_self); BoxedEnumerate* self = static_cast<BoxedEnumerate*>(_self);
Box* val = *self->iterator; Box* val = *self->iterator;
++self->iterator; ++self->iterator;
return BoxedTuple::create({ boxInt(self->idx++), val }); Box* rtn = BoxedTuple::create({ self->idx_long ? self->idx_long : boxInt(self->idx), val });
// check if incrementing the counter would overflow it, if so switch to long counter
if (self->idx == PY_SSIZE_T_MAX) {
assert(!self->idx_long);
self->idx_long = boxLong(self->idx);
self->idx = -1;
}
if (self->idx_long)
self->idx_long = (BoxedLong*)longAdd(self->idx_long, boxInt(1));
else
++self->idx;
return rtn;
} }
static Box* hasnext(Box* _self) { static Box* hasnext(Box* _self) {
...@@ -1512,7 +1634,7 @@ Box* input(Box* prompt) { ...@@ -1512,7 +1634,7 @@ Box* input(Box* prompt) {
Box* builtinRound(Box* _number, Box* _ndigits) { Box* builtinRound(Box* _number, Box* _ndigits) {
double x = PyFloat_AsDouble(_number); double x = PyFloat_AsDouble(_number);
if (PyErr_Occurred()) if (PyErr_Occurred())
raiseExcHelper(TypeError, "a float is required"); throwCAPIException();
/* interpret 2nd argument as a Py_ssize_t; clip on overflow */ /* interpret 2nd argument as a Py_ssize_t; clip on overflow */
Py_ssize_t ndigits = PyNumber_AsSsize_t(_ndigits, NULL); Py_ssize_t ndigits = PyNumber_AsSsize_t(_ndigits, NULL);
...@@ -2052,8 +2174,8 @@ void setupBuiltins() { ...@@ -2052,8 +2174,8 @@ void setupBuiltins() {
{ NULL, NULL }, NULL, range_doc); { NULL, NULL }, NULL, range_doc);
builtins_module->giveAttr("range", range_obj); builtins_module->giveAttr("range", range_obj);
auto* round_obj auto* round_obj = new BoxedBuiltinFunctionOrMethod(
= new BoxedBuiltinFunctionOrMethod(FunctionMetadata::create((void*)builtinRound, BOXED_FLOAT, 2, false, false), FunctionMetadata::create((void*)builtinRound, BOXED_FLOAT, 2, ParamNames({ "number", "ndigits" }, "", "")),
"round", { autoDecref(boxInt(0)) }, NULL, round_doc); "round", { autoDecref(boxInt(0)) }, NULL, round_doc);
builtins_module->giveAttr("round", round_obj); builtins_module->giveAttr("round", round_obj);
...@@ -2164,7 +2286,7 @@ void setupBuiltins() { ...@@ -2164,7 +2286,7 @@ void setupBuiltins() {
FunctionMetadata::create((void*)builtinCmp, UNKNOWN, 2), "cmp", cmp_doc)); FunctionMetadata::create((void*)builtinCmp, UNKNOWN, 2), "cmp", cmp_doc));
builtins_module->giveAttr( builtins_module->giveAttr(
"format", new BoxedBuiltinFunctionOrMethod(FunctionMetadata::create((void*)builtinFormat, UNKNOWN, 2), "format", "format", new BoxedBuiltinFunctionOrMethod(FunctionMetadata::create((void*)builtinFormat, UNKNOWN, 2), "format",
format_doc)); { NULL }, NULL, format_doc));
static PyMethodDef builtin_methods[] = { static PyMethodDef builtin_methods[] = {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "runtime/dict.h" #include "runtime/dict.h"
#include "capi/typeobject.h"
#include "capi/types.h" #include "capi/types.h"
#include "core/ast.h" #include "core/ast.h"
#include "core/common.h" #include "core/common.h"
...@@ -923,6 +924,8 @@ void setupDict() { ...@@ -923,6 +924,8 @@ void setupDict() {
dictiterkey_cls->instances_are_nonzero = dictitervalue_cls->instances_are_nonzero dictiterkey_cls->instances_are_nonzero = dictitervalue_cls->instances_are_nonzero
= dictiteritem_cls->instances_are_nonzero = true; = dictiteritem_cls->instances_are_nonzero = true;
dict_cls->tp_hash = PyObject_HashNotImplemented;
dict_cls->giveAttr("__len__", new BoxedFunction(FunctionMetadata::create((void*)dictLen, BOXED_INT, 1))); dict_cls->giveAttr("__len__", new BoxedFunction(FunctionMetadata::create((void*)dictLen, BOXED_INT, 1)));
dict_cls->giveAttr("__new__", new BoxedFunction(FunctionMetadata::create((void*)dictNew, UNKNOWN, 1, true, true))); dict_cls->giveAttr("__new__", new BoxedFunction(FunctionMetadata::create((void*)dictNew, UNKNOWN, 1, true, true)));
dict_cls->giveAttr("__init__", new BoxedFunction(FunctionMetadata::create((void*)dictInit, NONE, 1, true, true))); dict_cls->giveAttr("__init__", new BoxedFunction(FunctionMetadata::create((void*)dictInit, NONE, 1, true, true)));
...@@ -980,6 +983,7 @@ void setupDict() { ...@@ -980,6 +983,7 @@ void setupDict() {
dict_cls->giveAttr("__nonzero__", new BoxedFunction(FunctionMetadata::create((void*)dictNonzero, BOXED_BOOL, 1))); dict_cls->giveAttr("__nonzero__", new BoxedFunction(FunctionMetadata::create((void*)dictNonzero, BOXED_BOOL, 1)));
add_operators(dict_cls);
dict_cls->freeze(); dict_cls->freeze();
// create the dictonary iterator types // create the dictonary iterator types
......
...@@ -433,16 +433,20 @@ extern "C" Box* div_i64_i64(i64 lhs, i64 rhs) { ...@@ -433,16 +433,20 @@ extern "C" Box* div_i64_i64(i64 lhs, i64 rhs) {
return boxInt(div_result); return boxInt(div_result);
} }
extern "C" i64 mod_i64_i64(i64 lhs, i64 rhs) { extern "C" Box* mod_i64_i64(i64 lhs, i64 rhs) {
if (rhs == 0) { if (rhs == 0) {
raiseExcHelper(ZeroDivisionError, "integer division or modulo by zero"); raiseExcHelper(ZeroDivisionError, "integer division or modulo by zero");
} }
// I don't think this can overflow:
// this would overflow:
if (lhs == PYSTON_INT_MIN && rhs == -1)
return boxLong(0); // long because pypy and cpython both return a long
if (lhs < 0 && rhs > 0) if (lhs < 0 && rhs > 0)
return ((lhs + 1) % rhs) + (rhs - 1); return boxInt(((lhs + 1) % rhs) + (rhs - 1));
if (lhs > 0 && rhs < 0) if (lhs > 0 && rhs < 0)
return ((lhs - 1) % rhs) + (rhs + 1); return boxInt(((lhs - 1) % rhs) + (rhs + 1));
return lhs % rhs; return boxInt(lhs % rhs);
} }
extern "C" Box* pow_i64_i64(i64 lhs, i64 rhs, Box* mod) { extern "C" Box* pow_i64_i64(i64 lhs, i64 rhs, Box* mod) {
...@@ -777,7 +781,7 @@ Box* intRLShift(BoxedInt* lhs, Box* rhs) { ...@@ -777,7 +781,7 @@ Box* intRLShift(BoxedInt* lhs, Box* rhs) {
extern "C" Box* intModInt(BoxedInt* lhs, BoxedInt* rhs) { extern "C" Box* intModInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(PyInt_Check(lhs)); assert(PyInt_Check(lhs));
assert(PyInt_Check(rhs)); assert(PyInt_Check(rhs));
return boxInt(mod_i64_i64(lhs->n, rhs->n)); return mod_i64_i64(lhs->n, rhs->n);
} }
extern "C" Box* intMod(BoxedInt* lhs, Box* rhs) { extern "C" Box* intMod(BoxedInt* lhs, Box* rhs) {
...@@ -788,7 +792,7 @@ extern "C" Box* intMod(BoxedInt* lhs, Box* rhs) { ...@@ -788,7 +792,7 @@ extern "C" Box* intMod(BoxedInt* lhs, Box* rhs) {
return incref(NotImplemented); return incref(NotImplemented);
} }
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs); BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxInt(mod_i64_i64(lhs->n, rhs_int->n)); return mod_i64_i64(lhs->n, rhs_int->n);
} }
Box* intRMod(BoxedInt* lhs, Box* rhs) { Box* intRMod(BoxedInt* lhs, Box* rhs) {
...@@ -800,7 +804,7 @@ Box* intRMod(BoxedInt* lhs, Box* rhs) { ...@@ -800,7 +804,7 @@ Box* intRMod(BoxedInt* lhs, Box* rhs) {
return NotImplemented; return NotImplemented;
} }
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs); BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxInt(mod_i64_i64(rhs_int->n, lhs->n)); return mod_i64_i64(rhs_int->n, lhs->n);
} }
extern "C" Box* intDivmod(BoxedInt* lhs, Box* rhs) { extern "C" Box* intDivmod(BoxedInt* lhs, Box* rhs) {
...@@ -1082,6 +1086,9 @@ extern "C" Box* intHash(BoxedInt* self) { ...@@ -1082,6 +1086,9 @@ extern "C" Box* intHash(BoxedInt* self) {
raiseExcHelper(TypeError, "descriptor '__hash__' requires a 'int' object but received a '%s'", raiseExcHelper(TypeError, "descriptor '__hash__' requires a 'int' object but received a '%s'",
getTypeName(self)); getTypeName(self));
if (self->n == -1)
return boxInt(-2);
if (self->cls == int_cls) if (self->cls == int_cls)
return self; return self;
return boxInt(self->n); return boxInt(self->n);
...@@ -1473,6 +1480,30 @@ extern "C" int PyInt_ClearFreeList() noexcept { ...@@ -1473,6 +1480,30 @@ extern "C" int PyInt_ClearFreeList() noexcept {
return freelist_size; return freelist_size;
} }
static Box* intFormat(PyObject* self, Box* format_spec) {
if (PyBytes_Check(format_spec)) {
Box* rtn = _PyInt_FormatAdvanced(self, PyBytes_AS_STRING(format_spec), PyBytes_GET_SIZE(format_spec));
if (!rtn)
throwCAPIException();
return rtn;
}
if (PyUnicode_Check(format_spec)) {
/* Convert format_spec to a str */
PyObject* result;
PyObject* str_spec = PyObject_Str(format_spec);
if (str_spec == NULL)
throwCAPIException();
result = _PyInt_FormatAdvanced(self, PyBytes_AS_STRING(str_spec), PyBytes_GET_SIZE(str_spec));
Py_DECREF(str_spec);
if (!result)
throwCAPIException();
return result;
}
raiseExcHelper(TypeError, "__format__ requires str or unicode");
}
void setupInt() { void setupInt() {
static PyNumberMethods int_as_number; static PyNumberMethods int_as_number;
int_cls->tp_as_number = &int_as_number; int_cls->tp_as_number = &int_as_number;
...@@ -1492,7 +1523,7 @@ void setupInt() { ...@@ -1492,7 +1523,7 @@ void setupInt() {
_addFuncIntFloatUnknown("__floordiv__", (void*)intFloordivInt, (void*)intFloordivFloat, (void*)intFloordiv); _addFuncIntFloatUnknown("__floordiv__", (void*)intFloordivInt, (void*)intFloordivFloat, (void*)intFloordiv);
_addFuncIntFloatUnknown("__truediv__", (void*)intTruedivInt, (void*)intTruedivFloat, (void*)intTruediv); _addFuncIntFloatUnknown("__truediv__", (void*)intTruedivInt, (void*)intTruedivFloat, (void*)intTruediv);
_addFuncIntFloatUnknown("__mul__", (void*)intMulInt, (void*)intMulFloat, (void*)intMul); _addFuncIntFloatUnknown("__mul__", (void*)intMulInt, (void*)intMulFloat, (void*)intMul);
_addFuncIntUnknown("__mod__", BOXED_INT, (void*)intModInt, (void*)intMod); _addFuncIntUnknown("__mod__", UNKNOWN, (void*)intModInt, (void*)intMod);
_addFuncPow("__pow__", BOXED_INT, (void*)intPowFloat, (void*)intPow); _addFuncPow("__pow__", BOXED_INT, (void*)intPowFloat, (void*)intPow);
int_cls->giveAttr("__radd__", new BoxedFunction(FunctionMetadata::create((void*)intRAdd, UNKNOWN, 2))); int_cls->giveAttr("__radd__", new BoxedFunction(FunctionMetadata::create((void*)intRAdd, UNKNOWN, 2)));
...@@ -1538,6 +1569,8 @@ void setupInt() { ...@@ -1538,6 +1569,8 @@ void setupInt() {
int_cls->giveAttr("__float__", new BoxedFunction(FunctionMetadata::create((void*)intFloat, BOXED_FLOAT, 1))); int_cls->giveAttr("__float__", new BoxedFunction(FunctionMetadata::create((void*)intFloat, BOXED_FLOAT, 1)));
int_cls->giveAttr("__long__", new BoxedFunction(FunctionMetadata::create((void*)intLong, LONG, 1))); int_cls->giveAttr("__long__", new BoxedFunction(FunctionMetadata::create((void*)intLong, LONG, 1)));
int_cls->giveAttr("__format__", new BoxedFunction(FunctionMetadata::create((void*)intFormat, STR, 2)));
int_cls->giveAttr("__doc__", int_cls->giveAttr("__doc__",
boxString("int(x=0) -> int or long\n" boxString("int(x=0) -> int or long\n"
"int(x, base=10) -> int or long\n" "int(x, base=10) -> int or long\n"
......
...@@ -28,7 +28,7 @@ static_assert(sizeof(int64_t) == sizeof(long), ""); ...@@ -28,7 +28,7 @@ static_assert(sizeof(int64_t) == sizeof(long), "");
#define PYSTON_INT_MAX LONG_MAX #define PYSTON_INT_MAX LONG_MAX
extern "C" Box* div_i64_i64(i64 lhs, i64 rhs); extern "C" Box* div_i64_i64(i64 lhs, i64 rhs);
extern "C" i64 mod_i64_i64(i64 lhs, i64 rhs); extern "C" Box* mod_i64_i64(i64 lhs, i64 rhs);
extern "C" Box* add_i64_i64(i64 lhs, i64 rhs); extern "C" Box* add_i64_i64(i64 lhs, i64 rhs);
extern "C" Box* sub_i64_i64(i64 lhs, i64 rhs); extern "C" Box* sub_i64_i64(i64 lhs, i64 rhs);
......
...@@ -1540,8 +1540,12 @@ Box* longHash(BoxedLong* self) { ...@@ -1540,8 +1540,12 @@ Box* longHash(BoxedLong* self) {
getTypeName(self)); getTypeName(self));
// If the long fits into an int we have to return the same hash in order that we can find the value in a dict. // If the long fits into an int we have to return the same hash in order that we can find the value in a dict.
if (mpz_fits_slong_p(self->n)) if (mpz_fits_slong_p(self->n)) {
return boxInt(mpz_get_si(self->n)); auto v = mpz_get_si(self->n);
if (v == -1)
v = -2;
return boxInt(v);
}
// CPython use the absolute value of self mod ULONG_MAX. // CPython use the absolute value of self mod ULONG_MAX.
unsigned long remainder = mpz_tdiv_ui(self->n, ULONG_MAX); unsigned long remainder = mpz_tdiv_ui(self->n, ULONG_MAX);
...@@ -1556,6 +1560,14 @@ Box* longHash(BoxedLong* self) { ...@@ -1556,6 +1560,14 @@ Box* longHash(BoxedLong* self) {
return boxInt(remainder); return boxInt(remainder);
} }
long long_hash(PyObject* self) noexcept {
try {
return unboxInt(longHash((BoxedLong*)self));
} catch (ExcInfo e) {
RELEASE_ASSERT(0, "");
}
}
extern "C" Box* longTrunc(BoxedLong* self) { extern "C" Box* longTrunc(BoxedLong* self) {
if (!PyLong_Check(self)) if (!PyLong_Check(self))
raiseExcHelper(TypeError, "descriptor '__trunc__' requires a 'long' object but received a '%s'", raiseExcHelper(TypeError, "descriptor '__trunc__' requires a 'long' object but received a '%s'",
...@@ -1729,5 +1741,6 @@ void setupLong() { ...@@ -1729,5 +1741,6 @@ void setupLong() {
long_cls->freeze(); long_cls->freeze();
long_cls->tp_as_number->nb_power = long_pow; long_cls->tp_as_number->nb_power = long_pow;
long_cls->tp_hash = long_hash;
} }
} }
import os, sys, subprocess, shutil
sys.path.append(os.path.dirname(__file__) + "/../lib")
from test_helper import create_virtenv, run_test
ENV_NAME = "geoip_test_env_" + os.path.basename(sys.executable)
SRC_DIR = os.path.abspath(os.path.join(ENV_NAME, "src"))
PYTHON_EXE = os.path.abspath(os.path.join(ENV_NAME, "bin", "python"))
pkg = ["-e", "git+https://github.com/maxmind/geoip-api-python.git@v1.3.2#egg=GeoIP"]
create_virtenv(ENV_NAME, pkg, force_create = True)
GEOIP_DIR = os.path.abspath(os.path.join(SRC_DIR, "geoip"))
expected = [{'ran': 10}]
run_test([PYTHON_EXE, "setup.py", "test"], cwd=GEOIP_DIR, expected=expected)
import sys
__builtins__.aoeu = 1 __builtins__.aoeu = 1
print aoeu print aoeu
...@@ -37,10 +39,14 @@ print filter(lambda x: x % 2, xrange(20)) ...@@ -37,10 +39,14 @@ print filter(lambda x: x % 2, xrange(20))
print type(enumerate([])) print type(enumerate([]))
print list(enumerate(xrange(5, 10))) print list(enumerate(xrange(5, 10)))
print list(enumerate(start=-42, sequence=xrange(5, 10))) print list(enumerate(start=-42, sequence=xrange(5, 10)))
print list(enumerate(range(3), 2**128)) # tests long
print list(enumerate(range(3), 2**63-1)) # tests start with int and than switch to long
# If the first argument is None, filter calls checks for truthiness (ie is equivalent to passing 'bool') # If the first argument is None, filter calls checks for truthiness (ie is equivalent to passing 'bool')
print filter(None, xrange(-5, 5)) print filter(None, xrange(-5, 5))
print filter(None, unicode("12"))
print isinstance(1, int) print isinstance(1, int)
print isinstance(1, (float, int)) print isinstance(1, (float, int))
print isinstance(1, (float, (), (int, 3), 4)) print isinstance(1, (float, (), (int, 3), 4))
...@@ -79,6 +85,7 @@ print hex(12345) ...@@ -79,6 +85,7 @@ print hex(12345)
print oct(234) print oct(234)
print hex(0) print hex(0)
print oct(0) # This should not add an additional leading 0, ie should return "0" not "00" print oct(0) # This should not add an additional leading 0, ie should return "0" not "00"
print abs((-sys.maxint)-1)
try: try:
print hex([]) print hex([])
...@@ -129,9 +136,24 @@ print apply(sorted, [l], { "reverse" : True }) ...@@ -129,9 +136,24 @@ print apply(sorted, [l], { "reverse" : True })
print format(5.0, '+') print format(5.0, '+')
print format(5.011111111111, '+.6') print format(5.011111111111, '+.6')
print format("abc", '') print format("abc", '')
print format(0, str(10))
print '{n}'.format(n=None) print '{n}'.format(n=None)
print hash(1L)
def C(long):
def __hash__(self):
return self
print hash(2L)
try:
print hash({})
except TypeError as e:
print e
try:
print hash(set())
except TypeError as e:
print e
# Thankfully, setting __builtins__ has no effect: # Thankfully, setting __builtins__ has no effect:
__builtins__ = {'zzz': 2} __builtins__ = {'zzz': 2}
try: try:
......
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