Commit f95bd65f authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #467 from undingen/pycrypto

Misc stuff for pycrypto
parents a53ab1a8 1dc72576
...@@ -93,7 +93,7 @@ endif() ...@@ -93,7 +93,7 @@ endif()
add_subdirectory(${DEPS_DIR}/llvm-trunk ${CMAKE_BINARY_DIR}/llvm EXCLUDE_FROM_ALL) add_subdirectory(${DEPS_DIR}/llvm-trunk ${CMAKE_BINARY_DIR}/llvm EXCLUDE_FROM_ALL)
set(CMAKE_MODULE_PATH "${CMAKE_BINARY_DIR}/llvm/share/llvm/cmake/") set(CMAKE_MODULE_PATH "${CMAKE_BINARY_DIR}/llvm/share/llvm/cmake/")
include(LLVMConfig) include(LLVMConfig)
llvm_map_components_to_libnames(LLVM_LIBS core mcjit native bitreader ipo irreader debuginfodwarf instrumentation ${INTEL_JIT_EVENTS_LIB}) llvm_map_components_to_libnames(LLVM_LIBS core mcjit native bitreader bitwriter ipo irreader debuginfodwarf instrumentation ${INTEL_JIT_EVENTS_LIB})
# libunwind # libunwind
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
......
...@@ -97,7 +97,7 @@ else ...@@ -97,7 +97,7 @@ else
LLVM_BIN := $(LLVM_BUILD)/Release/bin LLVM_BIN := $(LLVM_BUILD)/Release/bin
endif endif
LLVM_LINK_LIBS := core mcjit native bitreader ipo irreader debuginfodwarf instrumentation LLVM_LINK_LIBS := core mcjit native bitreader bitwriter ipo irreader debuginfodwarf instrumentation
ifneq ($(ENABLE_INTEL_JIT_EVENTS),0) ifneq ($(ENABLE_INTEL_JIT_EVENTS),0)
LLVM_LINK_LIBS += inteljitevents LLVM_LINK_LIBS += inteljitevents
endif endif
......
...@@ -155,6 +155,10 @@ def libc_ver(executable=sys.executable,lib='',version='', ...@@ -155,6 +155,10 @@ def libc_ver(executable=sys.executable,lib='',version='',
The file is read and scanned in chunks of chunksize bytes. The file is read and scanned in chunks of chunksize bytes.
""" """
# Pyston change: hard code pyston executable libc version
if executable == sys.executable:
return ("glibc", "2.6")
if hasattr(os.path, 'realpath'): if hasattr(os.path, 'realpath'):
# Python 2.2 introduced os.path.realpath(); it is used # Python 2.2 introduced os.path.realpath(); it is used
# here to work around problems with Cygwin not being # here to work around problems with Cygwin not being
......
Subproject commit 8f62d5d7440cff89f98ed5a2e7756321811a0f2d Subproject commit 51f55dd4068f116ca287369cedddce624de73da6
...@@ -1038,6 +1038,149 @@ static PyObject* binary_op(PyObject* v, PyObject* w, const int op_slot, const ch ...@@ -1038,6 +1038,149 @@ static PyObject* binary_op(PyObject* v, PyObject* w, const int op_slot, const ch
return result; return result;
} }
/*
Calling scheme used for ternary operations:
*** In some cases, w.op is called before v.op; see binary_op1. ***
v w z Action
-------------------------------------------------------------------
new new new v.op(v,w,z), w.op(v,w,z), z.op(v,w,z)
new old new v.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
old new new w.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
old old new z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
new new old v.op(v,w,z), w.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
new old old v.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
old new old w.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
old old old coerce(v,w,z), v.op(v,w,z)
Legend:
-------
* new == new style number
* old == old style number
* Action indicates the order in which operations are tried until either
a valid result is produced or an error occurs.
* coerce(v,w,z) actually does: coerce(v,w), coerce(v,z), coerce(w,z) and
only if z != Py_None; if z == Py_None, then it is treated as absent
variable and only coerce(v,w) is tried.
*/
static PyObject* ternary_op(PyObject* v, PyObject* w, PyObject* z, const int op_slot, const char* op_name) noexcept {
PyNumberMethods* mv, *mw, *mz;
PyObject* x = NULL;
ternaryfunc slotv = NULL;
ternaryfunc slotw = NULL;
ternaryfunc slotz = NULL;
mv = v->cls->tp_as_number;
mw = w->cls->tp_as_number;
if (mv != NULL && NEW_STYLE_NUMBER(v))
slotv = NB_TERNOP(mv, op_slot);
if (w->cls != v->cls && mw != NULL && NEW_STYLE_NUMBER(w)) {
slotw = NB_TERNOP(mw, op_slot);
if (slotw == slotv)
slotw = NULL;
}
if (slotv) {
if (slotw && PyType_IsSubtype(w->cls, v->cls)) {
x = slotw(v, w, z);
if (x != Py_NotImplemented)
return x;
Py_DECREF(x); /* can't do it */
slotw = NULL;
}
x = slotv(v, w, z);
if (x != Py_NotImplemented)
return x;
Py_DECREF(x); /* can't do it */
}
if (slotw) {
x = slotw(v, w, z);
if (x != Py_NotImplemented)
return x;
Py_DECREF(x); /* can't do it */
}
mz = z->cls->tp_as_number;
if (mz != NULL && NEW_STYLE_NUMBER(z)) {
slotz = NB_TERNOP(mz, op_slot);
if (slotz == slotv || slotz == slotw)
slotz = NULL;
if (slotz) {
x = slotz(v, w, z);
if (x != Py_NotImplemented)
return x;
Py_DECREF(x); /* can't do it */
}
}
if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w) || (z != Py_None && !NEW_STYLE_NUMBER(z))) {
/* we have an old style operand, coerce */
PyObject* v1, *z1, *w2, *z2;
int c;
c = PyNumber_Coerce(&v, &w);
if (c != 0)
goto error3;
/* Special case: if the third argument is None, it is
treated as absent argument and not coerced. */
if (z == Py_None) {
if (v->cls->tp_as_number) {
slotz = NB_TERNOP(v->cls->tp_as_number, op_slot);
if (slotz)
x = slotz(v, w, z);
else
c = -1;
} else
c = -1;
goto error2;
}
v1 = v;
z1 = z;
c = PyNumber_Coerce(&v1, &z1);
if (c != 0)
goto error2;
w2 = w;
z2 = z1;
c = PyNumber_Coerce(&w2, &z2);
if (c != 0)
goto error1;
if (v1->cls->tp_as_number != NULL) {
slotv = NB_TERNOP(v1->cls->tp_as_number, op_slot);
if (slotv)
x = slotv(v1, w2, z2);
else
c = -1;
} else
c = -1;
Py_DECREF(w2);
Py_DECREF(z2);
error1:
Py_DECREF(v1);
Py_DECREF(z1);
error2:
Py_DECREF(v);
Py_DECREF(w);
error3:
if (c >= 0)
return x;
}
if (z == Py_None)
PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for ** or pow(): "
"'%.100s' and '%.100s'",
v->cls->tp_name, w->cls->tp_name);
else
PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for pow(): "
"'%.100s', '%.100s', '%.100s'",
v->cls->tp_name, w->cls->tp_name, z->cls->tp_name);
return NULL;
}
extern "C" PyObject* PySequence_Concat(PyObject* s, PyObject* o) noexcept { extern "C" PyObject* PySequence_Concat(PyObject* s, PyObject* o) noexcept {
PySequenceMethods* m; PySequenceMethods* m;
...@@ -1392,9 +1535,8 @@ extern "C" PyObject* PyNumber_Divmod(PyObject* lhs, PyObject* rhs) noexcept { ...@@ -1392,9 +1535,8 @@ extern "C" PyObject* PyNumber_Divmod(PyObject* lhs, PyObject* rhs) noexcept {
} }
} }
extern "C" PyObject* PyNumber_Power(PyObject*, PyObject*, PyObject* o3) noexcept { extern "C" PyObject* PyNumber_Power(PyObject* v, PyObject* w, PyObject* z) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented"); return ternary_op(v, w, z, NB_SLOT(nb_power), "** or pow()");
return nullptr;
} }
extern "C" PyObject* PyNumber_Negative(PyObject* o) noexcept { extern "C" PyObject* PyNumber_Negative(PyObject* o) noexcept {
...@@ -1421,9 +1563,13 @@ extern "C" PyObject* PyNumber_Invert(PyObject* o) noexcept { ...@@ -1421,9 +1563,13 @@ extern "C" PyObject* PyNumber_Invert(PyObject* o) noexcept {
return nullptr; return nullptr;
} }
extern "C" PyObject* PyNumber_Lshift(PyObject*, PyObject*) noexcept { extern "C" PyObject* PyNumber_Lshift(PyObject* lhs, PyObject* rhs) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented"); try {
return nullptr; return binop(lhs, rhs, AST_TYPE::LShift);
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
}
} }
extern "C" PyObject* PyNumber_Rshift(PyObject* lhs, PyObject* rhs) noexcept { extern "C" PyObject* PyNumber_Rshift(PyObject* lhs, PyObject* rhs) noexcept {
...@@ -1684,8 +1830,21 @@ extern "C" PyObject* PyNumber_Index(PyObject* o) noexcept { ...@@ -1684,8 +1830,21 @@ extern "C" PyObject* PyNumber_Index(PyObject* o) noexcept {
return o; return o;
} }
fatalOrError(PyExc_NotImplementedError, "unimplemented"); if (PyIndex_Check(o)) {
return nullptr; result = o->cls->tp_as_number->nb_index(o);
if (result && !PyInt_Check(result) && !PyLong_Check(result)) {
PyErr_Format(PyExc_TypeError, "__index__ returned non-(int,long) "
"(type %.200s)",
result->cls->tp_name);
Py_DECREF(result);
return NULL;
}
} else {
PyErr_Format(PyExc_TypeError, "'%.200s' object cannot be interpreted "
"as an index",
o->cls->tp_name);
}
return result;
} }
extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) noexcept { extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) noexcept {
...@@ -1693,18 +1852,42 @@ extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) noexcept { ...@@ -1693,18 +1852,42 @@ extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) noexcept {
return nullptr; return nullptr;
} }
extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* o, PyObject* exc) noexcept { extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* item, PyObject* err) noexcept {
if (isSubclass(o->cls, int_cls)) { Py_ssize_t result;
int64_t n = static_cast<BoxedInt*>(o)->n; PyObject* runerr;
static_assert(sizeof(n) == sizeof(Py_ssize_t), ""); PyObject* value = PyNumber_Index(item);
return n; if (value == NULL)
} else if (isSubclass(o->cls, long_cls)) { return -1;
return PyLong_AsSsize_t(o);
/* We're done if PyInt_AsSsize_t() returns without error. */
result = PyInt_AsSsize_t(value);
if (result != -1 || !(runerr = PyErr_Occurred()))
goto finish;
/* Error handling code -- only manage OverflowError differently */
if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError))
goto finish;
PyErr_Clear();
/* If no error-handling desired then the default clipping
is sufficient.
*/
if (!err) {
assert(PyLong_Check(value));
/* Whether or not it is less than or equal to
zero is determined by the sign of ob_size
*/
if (_PyLong_Sign(value) < 0)
result = PY_SSIZE_T_MIN;
else
result = PY_SSIZE_T_MAX;
} else {
/* Otherwise replace the error with caller's error object. */
PyErr_Format(err, "cannot fit '%.200s' into an index-sized integer", item->cls->tp_name);
} }
PyErr_Format(PyExc_TypeError, "'%.200s' object cannot be interpreted " finish:
"as an index", Py_DECREF(value);
o->cls->tp_name); return result;
return -1;
} }
} }
...@@ -281,7 +281,7 @@ public: ...@@ -281,7 +281,7 @@ public:
// Generate a hash for the module // Generate a hash for the module
HashOStream hash_stream; HashOStream hash_stream;
M->print(hash_stream, 0); llvm::WriteBitcodeToFile(M, hash_stream);
hash_before_codegen = hash_stream.getHash(); hash_before_codegen = hash_stream.getHash();
llvm::SmallString<128> cache_file = cache_dir; llvm::SmallString<128> cache_file = cache_dir;
......
...@@ -750,6 +750,12 @@ Box* divmod(Box* lhs, Box* rhs) { ...@@ -750,6 +750,12 @@ Box* divmod(Box* lhs, Box* rhs) {
return binopInternal(lhs, rhs, AST_TYPE::DivMod, false, NULL); return binopInternal(lhs, rhs, AST_TYPE::DivMod, false, NULL);
} }
Box* powFunc(Box* x, Box* y, Box* z) {
Box* rtn = PyNumber_Power(x, y, z);
checkAndThrowCAPIException();
return rtn;
}
Box* execfile(Box* _fn) { Box* execfile(Box* _fn) {
// The "globals" and "locals" arguments aren't implemented for now // The "globals" and "locals" arguments aren't implemented for now
if (!isSubclass(_fn->cls, str_cls)) { if (!isSubclass(_fn->cls, str_cls)) {
...@@ -1082,6 +1088,8 @@ void setupBuiltins() { ...@@ -1082,6 +1088,8 @@ void setupBuiltins() {
Box* hasattr_obj = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)hasattr, BOXED_BOOL, 2), "hasattr"); Box* hasattr_obj = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)hasattr, BOXED_BOOL, 2), "hasattr");
builtins_module->giveAttr("hasattr", hasattr_obj); builtins_module->giveAttr("hasattr", hasattr_obj);
builtins_module->giveAttr("pow", new BoxedBuiltinFunctionOrMethod(
boxRTFunction((void*)powFunc, UNKNOWN, 3, 1, false, false), "pow", { None }));
Box* isinstance_obj Box* isinstance_obj
= new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)isinstance_func, BOXED_BOOL, 2), "isinstance"); = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)isinstance_func, BOXED_BOOL, 2), "isinstance");
......
...@@ -38,9 +38,9 @@ namespace pyston { ...@@ -38,9 +38,9 @@ namespace pyston {
BoxedClass* method_cls; BoxedClass* method_cls;
extern "C" bool _PyIndex_Check(PyObject* op) noexcept { extern "C" bool _PyIndex_Check(PyObject* obj) noexcept {
// TODO this is wrong (the CPython version checks for things that can be coerced to a number): return (Py_TYPE(obj)->tp_as_number != NULL && PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_HAVE_INDEX)
return PyInt_Check(op); && Py_TYPE(obj)->tp_as_number->nb_index != NULL);
} }
extern "C" bool _PyObject_CheckBuffer(PyObject* obj) noexcept { extern "C" bool _PyObject_CheckBuffer(PyObject* obj) noexcept {
......
...@@ -488,6 +488,29 @@ static Box* instanceHash(BoxedInstance* inst) { ...@@ -488,6 +488,29 @@ static Box* instanceHash(BoxedInstance* inst) {
} }
} }
static PyObject* instance_index(PyObject* self) noexcept {
PyObject* func, *res;
/*
static PyObject* indexstr = NULL;
if (indexstr == NULL) {
indexstr = PyString_InternFromString("__index__");
if (indexstr == NULL)
return NULL;
}
*/
if ((func = instance_getattro(self, boxString("__index__"))) == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear();
PyErr_SetString(PyExc_TypeError, "object cannot be interpreted as an index");
return NULL;
}
res = PyEval_CallObject(func, (PyObject*)NULL);
Py_DECREF(func);
return res;
}
Box* instanceCall(Box* _inst, Box* _args, Box* _kwargs) { Box* instanceCall(Box* _inst, Box* _args, Box* _kwargs) {
assert(_inst->cls == instance_cls); assert(_inst->cls == instance_cls);
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst); BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
...@@ -541,5 +564,6 @@ void setupClassobj() { ...@@ -541,5 +564,6 @@ void setupClassobj() {
instance_cls->freeze(); instance_cls->freeze();
instance_cls->tp_getattro = instance_getattro; instance_cls->tp_getattro = instance_getattro;
instance_cls->tp_setattro = instance_setattro; instance_cls->tp_setattro = instance_setattro;
instance_cls->tp_as_number->nb_index = instance_index;
} }
} }
...@@ -390,20 +390,27 @@ extern "C" Box* floatRMod(BoxedFloat* lhs, Box* rhs) { ...@@ -390,20 +390,27 @@ extern "C" Box* floatRMod(BoxedFloat* lhs, Box* rhs) {
} }
} }
extern "C" Box* floatPowFloat(BoxedFloat* lhs, BoxedFloat* rhs) { extern "C" Box* floatPowFloat(BoxedFloat* lhs, BoxedFloat* rhs, Box* mod = None) {
assert(lhs->cls == float_cls); assert(lhs->cls == float_cls);
assert(rhs->cls == float_cls); assert(rhs->cls == float_cls);
if (mod != None)
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
return boxFloat(pow(lhs->d, rhs->d)); return boxFloat(pow(lhs->d, rhs->d));
} }
extern "C" Box* floatPowInt(BoxedFloat* lhs, BoxedInt* rhs) { extern "C" Box* floatPowInt(BoxedFloat* lhs, BoxedInt* rhs, Box* mod = None) {
assert(lhs->cls == float_cls); assert(lhs->cls == float_cls);
assert(isSubclass(rhs->cls, int_cls)); assert(isSubclass(rhs->cls, int_cls));
if (mod != None)
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
return boxFloat(pow(lhs->d, rhs->n)); return boxFloat(pow(lhs->d, rhs->n));
} }
extern "C" Box* floatPow(BoxedFloat* lhs, Box* rhs) { extern "C" Box* floatPow(BoxedFloat* lhs, Box* rhs, Box* mod) {
assert(lhs->cls == float_cls); assert(lhs->cls == float_cls);
if (mod != None)
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
if (isSubclass(rhs->cls, int_cls)) { if (isSubclass(rhs->cls, int_cls)) {
return floatPowInt(lhs, static_cast<BoxedInt*>(rhs)); return floatPowInt(lhs, static_cast<BoxedInt*>(rhs));
} else if (rhs->cls == float_cls) { } else if (rhs->cls == float_cls) {
...@@ -708,6 +715,19 @@ static void _addFunc(const char* name, ConcreteCompilerType* rtn_type, void* flo ...@@ -708,6 +715,19 @@ static void _addFunc(const char* name, ConcreteCompilerType* rtn_type, void* flo
float_cls->giveAttr(name, new BoxedFunction(cl)); float_cls->giveAttr(name, new BoxedFunction(cl));
} }
static void _addFuncPow(const char* name, ConcreteCompilerType* rtn_type, void* float_func, void* int_func,
void* boxed_func) {
std::vector<ConcreteCompilerType*> v_ffu{ BOXED_FLOAT, BOXED_FLOAT, UNKNOWN };
std::vector<ConcreteCompilerType*> v_fiu{ BOXED_FLOAT, BOXED_INT, UNKNOWN };
std::vector<ConcreteCompilerType*> v_fuu{ BOXED_FLOAT, UNKNOWN, UNKNOWN };
CLFunction* cl = createRTFunction(3, 1, false, false);
addRTFunction(cl, float_func, rtn_type, v_ffu);
addRTFunction(cl, int_func, rtn_type, v_fiu);
addRTFunction(cl, boxed_func, UNKNOWN, v_fuu);
float_cls->giveAttr(name, new BoxedFunction(cl, { None }));
}
void setupFloat() { void setupFloat() {
_addFunc("__add__", BOXED_FLOAT, (void*)floatAddFloat, (void*)floatAddInt, (void*)floatAdd); _addFunc("__add__", BOXED_FLOAT, (void*)floatAddFloat, (void*)floatAddInt, (void*)floatAdd);
float_cls->giveAttr("__radd__", float_cls->getattr("__add__")); float_cls->giveAttr("__radd__", float_cls->getattr("__add__"));
...@@ -729,7 +749,7 @@ void setupFloat() { ...@@ -729,7 +749,7 @@ void setupFloat() {
_addFunc("__mul__", BOXED_FLOAT, (void*)floatMulFloat, (void*)floatMulInt, (void*)floatMul); _addFunc("__mul__", BOXED_FLOAT, (void*)floatMulFloat, (void*)floatMulInt, (void*)floatMul);
float_cls->giveAttr("__rmul__", float_cls->getattr("__mul__")); float_cls->giveAttr("__rmul__", float_cls->getattr("__mul__"));
_addFunc("__pow__", BOXED_FLOAT, (void*)floatPowFloat, (void*)floatPowInt, (void*)floatPow); _addFuncPow("__pow__", BOXED_FLOAT, (void*)floatPowFloat, (void*)floatPowInt, (void*)floatPow);
_addFunc("__sub__", BOXED_FLOAT, (void*)floatSubFloat, (void*)floatSubInt, (void*)floatSub); _addFunc("__sub__", BOXED_FLOAT, (void*)floatSubFloat, (void*)floatSubInt, (void*)floatSub);
_addFunc("__rsub__", BOXED_FLOAT, (void*)floatRSubFloat, (void*)floatRSubInt, (void*)floatRSub); _addFunc("__rsub__", BOXED_FLOAT, (void*)floatRSubFloat, (void*)floatRSubInt, (void*)floatRSub);
......
...@@ -589,7 +589,9 @@ extern "C" PyObject* PyImport_ImportModule(const char* name) noexcept { ...@@ -589,7 +589,9 @@ extern "C" PyObject* PyImport_ImportModule(const char* name) noexcept {
try { try {
// TODO: check if this has the same behaviour as the cpython implementation // TODO: check if this has the same behaviour as the cpython implementation
std::string str = name; std::string str = name;
return import(0, None, &str); BoxedList* silly_list = new BoxedList();
listAppendInternal(silly_list, boxString("__doc__"));
return import(0, silly_list, &str);
} catch (ExcInfo e) { } catch (ExcInfo e) {
setCAPIException(e); setCAPIException(e);
return NULL; return NULL;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#include "core/types.h" #include "core/types.h"
#include "runtime/capi.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
...@@ -134,25 +135,22 @@ Box* xrange(Box* cls, Box* start, Box* stop, Box** args) { ...@@ -134,25 +135,22 @@ Box* xrange(Box* cls, Box* start, Box* stop, Box** args) {
Box* step = args[0]; Box* step = args[0];
if (stop == NULL) { if (stop == NULL) {
RELEASE_ASSERT(isSubclass(start->cls, int_cls), "%s", getTypeName(start)); i64 istop = PyLong_AsLong(start);
checkAndThrowCAPIException();
i64 istop = static_cast<BoxedInt*>(start)->n;
return new BoxedXrange(0, istop, 1); return new BoxedXrange(0, istop, 1);
} else if (step == NULL) { } else if (step == NULL) {
RELEASE_ASSERT(isSubclass(start->cls, int_cls), "%s", getTypeName(start)); i64 istart = PyLong_AsLong(start);
RELEASE_ASSERT(isSubclass(stop->cls, int_cls), "%s", getTypeName(stop)); checkAndThrowCAPIException();
i64 istop = PyLong_AsLong(stop);
i64 istart = static_cast<BoxedInt*>(start)->n; checkAndThrowCAPIException();
i64 istop = static_cast<BoxedInt*>(stop)->n;
return new BoxedXrange(istart, istop, 1); return new BoxedXrange(istart, istop, 1);
} else { } else {
RELEASE_ASSERT(isSubclass(start->cls, int_cls), "%s", getTypeName(start)); i64 istart = PyLong_AsLong(start);
RELEASE_ASSERT(isSubclass(stop->cls, int_cls), "%s", getTypeName(stop)); checkAndThrowCAPIException();
RELEASE_ASSERT(isSubclass(step->cls, int_cls), "%s", getTypeName(step)); i64 istop = PyLong_AsLong(stop);
checkAndThrowCAPIException();
i64 istart = static_cast<BoxedInt*>(start)->n; i64 istep = PyLong_AsLong(step);
i64 istop = static_cast<BoxedInt*>(stop)->n; checkAndThrowCAPIException();
i64 istep = static_cast<BoxedInt*>(step)->n;
RELEASE_ASSERT(istep != 0, "step can't be 0"); RELEASE_ASSERT(istep != 0, "step can't be 0");
return new BoxedXrange(istart, istop, istep); return new BoxedXrange(istart, istop, istep);
} }
......
...@@ -58,8 +58,20 @@ extern "C" long PyInt_AsLong(PyObject* op) noexcept { ...@@ -58,8 +58,20 @@ extern "C" long PyInt_AsLong(PyObject* op) noexcept {
} }
extern "C" Py_ssize_t PyInt_AsSsize_t(PyObject* op) noexcept { extern "C" Py_ssize_t PyInt_AsSsize_t(PyObject* op) noexcept {
RELEASE_ASSERT(isSubclass(op->cls, int_cls), ""); if (op == NULL) {
return static_cast<BoxedInt*>(op)->n; PyErr_SetString(PyExc_TypeError, "an integer is required");
return -1;
}
if (PyInt_Check(op))
return ((BoxedInt*)op)->n;
if (PyLong_Check(op))
return _PyLong_AsSsize_t(op);
#if SIZEOF_SIZE_T == SIZEOF_LONG
return PyInt_AsLong(op);
#else
RELEASE_ASSERT("not implemented", "");
#endif
} }
extern "C" PyObject* PyInt_FromSize_t(size_t ival) noexcept { extern "C" PyObject* PyInt_FromSize_t(size_t ival) noexcept {
...@@ -758,14 +770,18 @@ extern "C" Box* intPowFloat(BoxedInt* lhs, BoxedFloat* rhs) { ...@@ -758,14 +770,18 @@ extern "C" Box* intPowFloat(BoxedInt* lhs, BoxedFloat* rhs) {
return boxFloat(pow(lhs->n, rhs->d)); return boxFloat(pow(lhs->n, rhs->d));
} }
extern "C" Box* intPow(BoxedInt* lhs, Box* rhs) { extern "C" Box* intPow(BoxedInt* lhs, Box* rhs, Box* mod) {
if (!isSubclass(lhs->cls, int_cls)) if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'int' object but received a '%s'", getTypeName(lhs)); raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (isSubclass(rhs->cls, int_cls)) { if (isSubclass(rhs->cls, int_cls)) {
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs); BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return intPowInt(lhs, rhs_int); Box* rtn = intPowInt(lhs, rhs_int);
if (mod == None)
return rtn;
return binop(rtn, mod, AST_TYPE::Mod);
} else if (rhs->cls == float_cls) { } else if (rhs->cls == float_cls) {
RELEASE_ASSERT(mod == None, "");
BoxedFloat* rhs_float = static_cast<BoxedFloat*>(rhs); BoxedFloat* rhs_float = static_cast<BoxedFloat*>(rhs);
return intPowFloat(lhs, rhs_float); return intPowFloat(lhs, rhs_float);
} else { } else {
...@@ -924,6 +940,12 @@ extern "C" Box* intTrunc(BoxedInt* self) { ...@@ -924,6 +940,12 @@ extern "C" Box* intTrunc(BoxedInt* self) {
return self; return self;
} }
extern "C" Box* intIndex(BoxedInt* v) {
if (PyInt_CheckExact(v))
return v;
return boxInt(v->n);
}
static Box* _intNew(Box* val, Box* base) { static Box* _intNew(Box* val, Box* base) {
if (isSubclass(val->cls, int_cls)) { if (isSubclass(val->cls, int_cls)) {
RELEASE_ASSERT(!base, ""); RELEASE_ASSERT(!base, "");
...@@ -1057,7 +1079,8 @@ void setupInt() { ...@@ -1057,7 +1079,8 @@ void setupInt() {
_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__", BOXED_INT, (void*)intModInt, (void*)intMod);
_addFuncIntFloatUnknown("__pow__", (void*)intPowInt, (void*)intPowFloat, (void*)intPow); int_cls->giveAttr("__pow__",
new BoxedFunction(boxRTFunction((void*)intPow, UNKNOWN, 3, 1, false, false), { None }));
_addFuncIntUnknown("__eq__", BOXED_BOOL, (void*)intEqInt, (void*)intEq); _addFuncIntUnknown("__eq__", BOXED_BOOL, (void*)intEqInt, (void*)intEq);
_addFuncIntUnknown("__ne__", BOXED_BOOL, (void*)intNeInt, (void*)intNe); _addFuncIntUnknown("__ne__", BOXED_BOOL, (void*)intNeInt, (void*)intNe);
...@@ -1081,6 +1104,7 @@ void setupInt() { ...@@ -1081,6 +1104,7 @@ void setupInt() {
int_cls->giveAttr("__oct__", new BoxedFunction(boxRTFunction((void*)intOct, STR, 1))); int_cls->giveAttr("__oct__", new BoxedFunction(boxRTFunction((void*)intOct, STR, 1)));
int_cls->giveAttr("__trunc__", new BoxedFunction(boxRTFunction((void*)intTrunc, BOXED_INT, 1))); int_cls->giveAttr("__trunc__", new BoxedFunction(boxRTFunction((void*)intTrunc, BOXED_INT, 1)));
int_cls->giveAttr("__index__", new BoxedFunction(boxRTFunction((void*)intIndex, BOXED_INT, 1)));
int_cls->giveAttr( int_cls->giveAttr(
"__new__", new BoxedFunction(boxRTFunction((void*)intNew, UNKNOWN, 3, 2, false, false), { boxInt(0), NULL })); "__new__", new BoxedFunction(boxRTFunction((void*)intNew, UNKNOWN, 3, 2, false, false), { boxInt(0), NULL }));
......
...@@ -192,8 +192,11 @@ extern "C" Box* listGetitemSlice(BoxedList* self, BoxedSlice* slice) { ...@@ -192,8 +192,11 @@ extern "C" Box* listGetitemSlice(BoxedList* self, BoxedSlice* slice) {
extern "C" Box* listGetitem(BoxedList* self, Box* slice) { extern "C" Box* listGetitem(BoxedList* self, Box* slice) {
assert(isSubclass(self->cls, list_cls)); assert(isSubclass(self->cls, list_cls));
if (isSubclass(slice->cls, int_cls)) { if (PyIndex_Check(slice)) {
return listGetitemInt(self, static_cast<BoxedInt*>(slice)); Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
throwCAPIException();
return listGetitemUnboxed(self, i);
} else if (slice->cls == slice_cls) { } else if (slice->cls == slice_cls) {
return listGetitemSlice(self, static_cast<BoxedSlice*>(slice)); return listGetitemSlice(self, static_cast<BoxedSlice*>(slice));
} else { } else {
...@@ -212,23 +215,23 @@ static void _listSetitem(BoxedList* self, int64_t n, Box* v) { ...@@ -212,23 +215,23 @@ static void _listSetitem(BoxedList* self, int64_t n, Box* v) {
self->elts->elts[n] = v; self->elts->elts[n] = v;
} }
extern "C" Box* listSetitemInt(BoxedList* self, BoxedInt* slice, Box* v) { extern "C" Box* listSetitemUnboxed(BoxedList* self, int64_t n, Box* v) {
// I think r lock is ok here, since we don't change the list structure: // I think r lock is ok here, since we don't change the list structure:
LOCK_REGION(self->lock.asRead()); LOCK_REGION(self->lock.asRead());
assert(isSubclass(self->cls, list_cls)); assert(isSubclass(self->cls, list_cls));
assert(isSubclass(slice->cls, int_cls));
int64_t n = slice->n;
_listSetitem(self, n, v); _listSetitem(self, n, v);
return None; return None;
} }
extern "C" Box* listSetitemInt(BoxedList* self, BoxedInt* slice, Box* v) {
assert(isSubclass(slice->cls, int_cls));
return listSetitemUnboxed(self, slice->n, v);
}
extern "C" int PyList_SetItem(PyObject* op, Py_ssize_t i, PyObject* newitem) noexcept { extern "C" int PyList_SetItem(PyObject* op, Py_ssize_t i, PyObject* newitem) noexcept {
assert(isSubclass(op->cls, list_cls)); assert(isSubclass(op->cls, list_cls));
try { try {
_listSetitem(static_cast<BoxedList*>(op), i, newitem); listSetitemUnboxed(static_cast<BoxedList*>(op), i, newitem);
} catch (ExcInfo e) { } catch (ExcInfo e) {
abort(); abort();
} }
...@@ -460,8 +463,12 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) { ...@@ -460,8 +463,12 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
extern "C" Box* listSetitem(BoxedList* self, Box* slice, Box* v) { extern "C" Box* listSetitem(BoxedList* self, Box* slice, Box* v) {
assert(isSubclass(self->cls, list_cls)); assert(isSubclass(self->cls, list_cls));
if (isSubclass(slice->cls, int_cls)) { if (PyIndex_Check(slice)) {
return listSetitemInt(self, static_cast<BoxedInt*>(slice), v); Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
throwCAPIException();
listSetitemUnboxed(self, i, v);
return None;
} else if (slice->cls == slice_cls) { } else if (slice->cls == slice_cls) {
return listSetitemSlice(self, static_cast<BoxedSlice*>(slice), v); return listSetitemSlice(self, static_cast<BoxedSlice*>(slice), v);
} else { } else {
...@@ -492,9 +499,11 @@ extern "C" Box* listDelitem(BoxedList* self, Box* slice) { ...@@ -492,9 +499,11 @@ extern "C" Box* listDelitem(BoxedList* self, Box* slice) {
LOCK_REGION(self->lock.asWrite()); LOCK_REGION(self->lock.asWrite());
Box* rtn; Box* rtn;
if (PyIndex_Check(slice)) {
if (isSubclass(slice->cls, int_cls)) { Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
rtn = listDelitemInt(self, static_cast<BoxedInt*>(slice)); if (i == -1 && PyErr_Occurred())
throwCAPIException();
rtn = listDelitemInt(self, (BoxedInt*)boxInt(i));
} else if (slice->cls == slice_cls) { } else if (slice->cls == slice_cls) {
rtn = listDelitemSlice(self, static_cast<BoxedSlice*>(slice)); rtn = listDelitemSlice(self, static_cast<BoxedSlice*>(slice));
} else { } else {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "core/stats.h" #include "core/stats.h"
#include "core/types.h" #include "core/types.h"
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/capi.h"
#include "runtime/inline/boxing.h" #include "runtime/inline/boxing.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
...@@ -104,12 +105,58 @@ extern "C" PY_LONG_LONG PyLong_AsLongLongAndOverflow(PyObject* obj, int* overflo ...@@ -104,12 +105,58 @@ extern "C" PY_LONG_LONG PyLong_AsLongLongAndOverflow(PyObject* obj, int* overflo
extern "C" PyObject* PyLong_FromString(const char* str, char** pend, int base) noexcept { extern "C" PyObject* PyLong_FromString(const char* str, char** pend, int base) noexcept {
RELEASE_ASSERT(pend == NULL, "unsupported"); RELEASE_ASSERT(pend == NULL, "unsupported");
// See comment in _longNew int sign = 1;
RELEASE_ASSERT(base >= 0, "unsupported"); if ((base != 0 && base < 2) || base > 36) {
PyErr_SetString(PyExc_ValueError, "long() arg 2 must be >= 2 and <= 36");
return NULL;
}
while (*str != '\0' && isspace(Py_CHARMASK(*str)))
str++;
if (*str == '+')
++str;
else if (*str == '-') {
++str;
sign = -1;
}
while (*str != '\0' && isspace(Py_CHARMASK(*str)))
str++;
if (base == 0) {
/* No base given. Deduce the base from the contents
of the string */
if (str[0] != '0')
base = 10;
else if (str[1] == 'x' || str[1] == 'X')
base = 16;
else if (str[1] == 'o' || str[1] == 'O')
base = 8;
else if (str[1] == 'b' || str[1] == 'B')
base = 2;
else
/* "old" (C-style) octal literal, still valid in
2.x, although illegal in 3.x */
base = 8;
}
/* Whether or not we were deducing the base, skip leading chars
as needed */
if (str[0] == '0'
&& ((base == 16 && (str[1] == 'x' || str[1] == 'X')) || (base == 8 && (str[1] == 'o' || str[1] == 'O'))
|| (base == 2 && (str[1] == 'b' || str[1] == 'B'))))
str += 2;
BoxedLong* rtn = new BoxedLong(); BoxedLong* rtn = new BoxedLong();
int r = mpz_init_set_str(rtn->n, str, base); if (str[strlen(str) - 1] == 'L') {
RELEASE_ASSERT(r == 0, ""); std::string without_l(str, strlen(str) - 1);
int r = mpz_init_set_str(rtn->n, without_l.c_str(), base);
RELEASE_ASSERT(r == 0, "");
} else {
int r = mpz_init_set_str(rtn->n, str, base);
RELEASE_ASSERT(r == 0, "");
}
if (sign == -1)
mpz_neg(rtn->n, rtn->n);
return rtn; return rtn;
} }
...@@ -441,18 +488,8 @@ BoxedLong* _longNew(Box* val, Box* _base) { ...@@ -441,18 +488,8 @@ BoxedLong* _longNew(Box* val, Box* _base) {
raiseExcHelper(TypeError, "long() can't convert non-string with explicit base"); raiseExcHelper(TypeError, "long() can't convert non-string with explicit base");
BoxedString* s = static_cast<BoxedString*>(val); BoxedString* s = static_cast<BoxedString*>(val);
if (base == 0) { rtn = (BoxedLong*)PyLong_FromString(s->s.str().c_str(), NULL, base);
// mpz_init_set_str has the ability to auto-detect the base, but I doubt it's checkAndThrowCAPIException();
// quite the same as Python's (ex might be missing octal or binary)
Py_FatalError("unimplemented");
}
if (base < 2 || base > 36) {
raiseExcHelper(TypeError, "long() arg2 must be >= 2 and <= 36");
}
int r = mpz_init_set_str(rtn->n, s->data(), base);
RELEASE_ASSERT(r == 0, "");
} else { } else {
if (isSubclass(val->cls, long_cls)) { if (isSubclass(val->cls, long_cls)) {
BoxedLong* l = static_cast<BoxedLong*>(val); BoxedLong* l = static_cast<BoxedLong*>(val);
...@@ -920,6 +957,51 @@ Box* longDiv(BoxedLong* v1, Box* _v2) { ...@@ -920,6 +957,51 @@ Box* longDiv(BoxedLong* v1, Box* _v2) {
} }
} }
Box* longMod(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__mod__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
if (mpz_cmp_si(v2->n, 0) == 0)
raiseExcHelper(ZeroDivisionError, "long division or modulo by zero");
BoxedLong* r = new BoxedLong();
mpz_init(r->n);
mpz_mmod(r->n, v1->n, v2->n);
return r;
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
if (v2->n == 0)
raiseExcHelper(ZeroDivisionError, "long division or modulo by zero");
BoxedLong* r = new BoxedLong();
mpz_init_set_si(r->n, v2->n);
mpz_mmod(r->n, v1->n, r->n);
return r;
} else {
return NotImplemented;
}
}
Box* longRMod(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__rmod__' requires a 'long' object but received a '%s'",
getTypeName(v1));
Box* lhs = _v2;
BoxedLong* rhs = v1;
if (isSubclass(lhs->cls, long_cls)) {
return longMod((BoxedLong*)lhs, rhs);
} else if (isSubclass(lhs->cls, int_cls)) {
return longMod(boxLong(((BoxedInt*)lhs)->n), rhs);
} else {
return NotImplemented;
}
}
extern "C" Box* longDivmod(BoxedLong* lhs, Box* _rhs) { extern "C" Box* longDivmod(BoxedLong* lhs, Box* _rhs) {
if (!isSubclass(lhs->cls, long_cls)) if (!isSubclass(lhs->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__div__' requires a 'long' object but received a '%s'", raiseExcHelper(TypeError, "descriptor '__div__' requires a 'long' object but received a '%s'",
...@@ -1018,27 +1100,45 @@ Box* longRTrueDiv(BoxedLong* v1, Box* _v2) { ...@@ -1018,27 +1100,45 @@ Box* longRTrueDiv(BoxedLong* v1, Box* _v2) {
return boxFloat(lhs / (double)rhs); return boxFloat(lhs / (double)rhs);
} }
Box* longPow(BoxedLong* v1, Box* _v2) { Box* longPow(BoxedLong* v1, Box* _v2, Box* _v3) {
if (!isSubclass(v1->cls, long_cls)) if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'long' object but received a '%s'", getTypeName(v1)); raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'long' object but received a '%s'", getTypeName(v1));
BoxedLong* mod = nullptr;
if (_v3 != None) {
if (isSubclass(_v3->cls, int_cls))
mod = boxLong(((BoxedInt*)_v3)->n);
else {
RELEASE_ASSERT(_v3->cls == long_cls, "");
mod = (BoxedLong*)_v3;
}
RELEASE_ASSERT(mpz_sgn(mod->n) >= 0, "");
}
if (isSubclass(_v2->cls, long_cls)) { if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2); BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
BoxedLong* r = new BoxedLong();
mpz_init(r->n);
RELEASE_ASSERT(mpz_sgn(v2->n) >= 0, ""); RELEASE_ASSERT(mpz_sgn(v2->n) >= 0, "");
RELEASE_ASSERT(mpz_fits_ulong_p(v2->n), "");
uint64_t n2 = mpz_get_ui(v2->n);
BoxedLong* r = new BoxedLong(); if (mod) {
mpz_init(r->n); mpz_powm(r->n, v1->n, v2->n, mod->n);
mpz_pow_ui(r->n, v1->n, n2); } else {
RELEASE_ASSERT(mpz_fits_ulong_p(v2->n), "");
uint64_t n2 = mpz_get_ui(v2->n);
mpz_pow_ui(r->n, v1->n, n2);
}
return r; return r;
} else if (isSubclass(_v2->cls, int_cls)) { } else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2); BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
RELEASE_ASSERT(v2->n >= 0, ""); RELEASE_ASSERT(v2->n >= 0, "");
BoxedLong* r = new BoxedLong(); BoxedLong* r = new BoxedLong();
mpz_init(r->n); mpz_init(r->n);
mpz_pow_ui(r->n, v1->n, v2->n); if (mod)
mpz_powm_ui(r->n, v1->n, v2->n, mod->n);
else
mpz_pow_ui(r->n, v1->n, v2->n);
return r; return r;
} else { } else {
return NotImplemented; return NotImplemented;
...@@ -1101,6 +1201,53 @@ void customised_free(void* ptr, size_t size) { ...@@ -1101,6 +1201,53 @@ void customised_free(void* ptr, size_t size) {
gc::gc_free(ptr); gc::gc_free(ptr);
} }
extern "C" Box* longIndex(BoxedLong* v) noexcept {
if (PyLong_CheckExact(v))
return v;
BoxedLong* rtn = new BoxedLong();
mpz_init_set(rtn->n, v->n);
return rtn;
}
static int convert_binop(PyObject* v, PyObject* w, PyLongObject** a, PyLongObject** b) noexcept {
if (PyLong_Check(v)) {
*a = (PyLongObject*)v;
Py_INCREF(v);
} else if (PyInt_Check(v)) {
*a = (PyLongObject*)PyLong_FromLong(PyInt_AS_LONG(v));
} else {
return 0;
}
if (PyLong_Check(w)) {
*b = (PyLongObject*)w;
Py_INCREF(w);
} else if (PyInt_Check(w)) {
*b = (PyLongObject*)PyLong_FromLong(PyInt_AS_LONG(w));
} else {
Py_DECREF(*a);
return 0;
}
return 1;
}
#define CONVERT_BINOP(v, w, a, b) \
do { \
if (!convert_binop(v, w, a, b)) { \
Py_INCREF(Py_NotImplemented); \
return Py_NotImplemented; \
} \
} while (0)
static PyObject* long_pow(PyObject* v, PyObject* w, PyObject* x) noexcept {
try {
PyLongObject* a, *b;
CONVERT_BINOP(v, w, &a, &b);
return longPow((BoxedLong*)a, (BoxedLong*)b, x);
} catch (ExcInfo e) {
abort();
}
}
void setupLong() { void setupLong() {
mp_set_memory_functions(customised_allocation, customised_realloc, customised_free); mp_set_memory_functions(customised_allocation, customised_realloc, customised_free);
...@@ -1114,6 +1261,8 @@ void setupLong() { ...@@ -1114,6 +1261,8 @@ void setupLong() {
long_cls->giveAttr("__rdiv__", new BoxedFunction(boxRTFunction((void*)longRdiv, UNKNOWN, 2))); long_cls->giveAttr("__rdiv__", new BoxedFunction(boxRTFunction((void*)longRdiv, UNKNOWN, 2)));
long_cls->giveAttr("__truediv__", new BoxedFunction(boxRTFunction((void*)longTrueDiv, UNKNOWN, 2))); long_cls->giveAttr("__truediv__", new BoxedFunction(boxRTFunction((void*)longTrueDiv, UNKNOWN, 2)));
long_cls->giveAttr("__rtruediv__", new BoxedFunction(boxRTFunction((void*)longRTrueDiv, UNKNOWN, 2))); long_cls->giveAttr("__rtruediv__", new BoxedFunction(boxRTFunction((void*)longRTrueDiv, UNKNOWN, 2)));
long_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)longMod, UNKNOWN, 2)));
long_cls->giveAttr("__rmod__", new BoxedFunction(boxRTFunction((void*)longRMod, UNKNOWN, 2)));
long_cls->giveAttr("__divmod__", new BoxedFunction(boxRTFunction((void*)longDivmod, UNKNOWN, 2))); long_cls->giveAttr("__divmod__", new BoxedFunction(boxRTFunction((void*)longDivmod, UNKNOWN, 2)));
...@@ -1123,7 +1272,8 @@ void setupLong() { ...@@ -1123,7 +1272,8 @@ void setupLong() {
long_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)longAdd, UNKNOWN, 2))); long_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)longAdd, UNKNOWN, 2)));
long_cls->giveAttr("__radd__", long_cls->getattr("__add__")); long_cls->giveAttr("__radd__", long_cls->getattr("__add__"));
long_cls->giveAttr("__pow__", new BoxedFunction(boxRTFunction((void*)longPow, UNKNOWN, 2))); long_cls->giveAttr("__pow__",
new BoxedFunction(boxRTFunction((void*)longPow, UNKNOWN, 3, 1, false, false), { None }));
long_cls->giveAttr("__and__", new BoxedFunction(boxRTFunction((void*)longAnd, UNKNOWN, 2))); long_cls->giveAttr("__and__", new BoxedFunction(boxRTFunction((void*)longAnd, UNKNOWN, 2)));
long_cls->giveAttr("__rand__", long_cls->getattr("__and__")); long_cls->giveAttr("__rand__", long_cls->getattr("__and__"));
...@@ -1154,7 +1304,10 @@ void setupLong() { ...@@ -1154,7 +1304,10 @@ void setupLong() {
long_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)longHash, BOXED_INT, 1))); long_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)longHash, BOXED_INT, 1)));
long_cls->giveAttr("__trunc__", new BoxedFunction(boxRTFunction((void*)longTrunc, UNKNOWN, 1))); long_cls->giveAttr("__trunc__", new BoxedFunction(boxRTFunction((void*)longTrunc, UNKNOWN, 1)));
long_cls->giveAttr("__index__", new BoxedFunction(boxRTFunction((void*)longIndex, LONG, 1)));
long_cls->freeze(); long_cls->freeze();
long_cls->tp_as_number->nb_power = long_pow;
} }
} }
...@@ -47,7 +47,7 @@ Box* longAdd(BoxedLong* lhs, Box* rhs); ...@@ -47,7 +47,7 @@ Box* longAdd(BoxedLong* lhs, Box* rhs);
Box* longSub(BoxedLong* lhs, Box* rhs); Box* longSub(BoxedLong* lhs, Box* rhs);
Box* longMul(BoxedLong* lhs, Box* rhs); Box* longMul(BoxedLong* lhs, Box* rhs);
Box* longDiv(BoxedLong* lhs, Box* rhs); Box* longDiv(BoxedLong* lhs, Box* rhs);
Box* longPow(BoxedLong* lhs, Box* rhs); Box* longPow(BoxedLong* lhs, Box* rhs, Box* mod = None);
Box* longLshift(BoxedLong* lhs, Box* rhs); Box* longLshift(BoxedLong* lhs, Box* rhs);
Box* longRshift(BoxedLong* lhs, Box* rhs); Box* longRshift(BoxedLong* lhs, Box* rhs);
......
...@@ -326,6 +326,7 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset ...@@ -326,6 +326,7 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
tp_flags |= Py_TPFLAGS_HAVE_GC; tp_flags |= Py_TPFLAGS_HAVE_GC;
tp_flags |= Py_TPFLAGS_HAVE_WEAKREFS; tp_flags |= Py_TPFLAGS_HAVE_WEAKREFS;
tp_flags |= Py_TPFLAGS_HAVE_RICHCOMPARE; tp_flags |= Py_TPFLAGS_HAVE_RICHCOMPARE;
tp_flags |= Py_TPFLAGS_HAVE_INDEX;
if (base && (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER)) if (base && (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER))
tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
......
...@@ -2240,9 +2240,10 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) { ...@@ -2240,9 +2240,10 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) {
extern "C" Box* strGetitem(BoxedString* self, Box* slice) { extern "C" Box* strGetitem(BoxedString* self, Box* slice) {
assert(isSubclass(self->cls, str_cls)); assert(isSubclass(self->cls, str_cls));
if (isSubclass(slice->cls, int_cls)) { if (PyIndex_Check(slice)) {
BoxedInt* islice = static_cast<BoxedInt*>(slice); Py_ssize_t n = PyNumber_AsSsize_t(slice, PyExc_IndexError);
int64_t n = islice->n; if (n == -1 && PyErr_Occurred())
throwCAPIException();
int size = self->size(); int size = self->size();
if (n < 0) if (n < 0)
n = size + n; n = size + n;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "core/stats.h" #include "core/stats.h"
#include "core/types.h" #include "core/types.h"
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/capi.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
...@@ -146,9 +147,12 @@ int BoxedTuple::Resize(BoxedTuple** pv, size_t newsize) noexcept { ...@@ -146,9 +147,12 @@ int BoxedTuple::Resize(BoxedTuple** pv, size_t newsize) noexcept {
Box* tupleGetitem(BoxedTuple* self, Box* slice) { Box* tupleGetitem(BoxedTuple* self, Box* slice) {
assert(self->cls == tuple_cls); assert(self->cls == tuple_cls);
if (isSubclass(slice->cls, int_cls)) if (PyIndex_Check(slice)) {
return tupleGetitemInt(self, static_cast<BoxedInt*>(slice)); Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
else if (slice->cls == slice_cls) if (i == -1 && PyErr_Occurred())
throwCAPIException();
return tupleGetitemUnboxed(self, i);
} else if (slice->cls == slice_cls)
return tupleGetitemSlice(self, static_cast<BoxedSlice*>(slice)); return tupleGetitemSlice(self, static_cast<BoxedSlice*>(slice));
else else
raiseExcHelper(TypeError, "tuple indices must be integers, not %s", getTypeName(slice)); raiseExcHelper(TypeError, "tuple indices must be integers, not %s", getTypeName(slice));
......
...@@ -956,16 +956,61 @@ extern "C" int PySlice_GetIndices(PySliceObject* r, Py_ssize_t length, Py_ssize_ ...@@ -956,16 +956,61 @@ extern "C" int PySlice_GetIndices(PySliceObject* r, Py_ssize_t length, Py_ssize_
extern "C" int PySlice_GetIndicesEx(PySliceObject* _r, Py_ssize_t length, Py_ssize_t* start, Py_ssize_t* stop, extern "C" int PySlice_GetIndicesEx(PySliceObject* _r, Py_ssize_t length, Py_ssize_t* start, Py_ssize_t* stop,
Py_ssize_t* step, Py_ssize_t* slicelength) noexcept { Py_ssize_t* step, Py_ssize_t* slicelength) noexcept {
try { BoxedSlice* r = (BoxedSlice*)_r;
BoxedSlice* r = (BoxedSlice*)_r; RELEASE_ASSERT(r->cls == slice_cls, "");
assert(r->cls == slice_cls);
// parseSlice has the exact same behaviour as CPythons PySlice_GetIndicesEx apart from throwing c++ exceptions /* this is harder to get right than you might think */
// on error.
parseSlice(r, length, start, stop, step, slicelength); Py_ssize_t defstart, defstop;
} catch (ExcInfo e) {
setCAPIException(e); if (r->step == Py_None) {
return -1; *step = 1;
} else {
if (!_PyEval_SliceIndex(r->step, step))
return -1;
if (*step == 0) {
PyErr_SetString(PyExc_ValueError, "slice step cannot be zero");
return -1;
}
} }
defstart = *step < 0 ? length - 1 : 0;
defstop = *step < 0 ? -1 : length;
if (r->start == Py_None) {
*start = defstart;
} else {
if (!_PyEval_SliceIndex(r->start, start))
return -1;
if (*start < 0)
*start += length;
if (*start < 0)
*start = (*step < 0) ? -1 : 0;
if (*start >= length)
*start = (*step < 0) ? length - 1 : length;
}
if (r->stop == Py_None) {
*stop = defstop;
} else {
if (!_PyEval_SliceIndex(r->stop, stop))
return -1;
if (*stop < 0)
*stop += length;
if (*stop < 0)
*stop = (*step < 0) ? -1 : 0;
if (*stop >= length)
*stop = (*step < 0) ? length - 1 : length;
}
if ((*step < 0 && *stop >= *start) || (*step > 0 && *start >= *stop)) {
*slicelength = 0;
} else if (*step < 0) {
*slicelength = (*stop - *start + 1) / (*step) + 1;
} else {
*slicelength = (*stop - *start - 1) / (*step) + 1;
}
return 0; return 0;
} }
......
...@@ -15,84 +15,15 @@ ...@@ -15,84 +15,15 @@
#include "runtime/util.h" #include "runtime/util.h"
#include "core/options.h" #include "core/options.h"
#include "runtime/capi.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
namespace pyston { namespace pyston {
// Provides the exact same behaviour as CPythons PySlice_GetIndicesEx apart from throwing c++ exceptions on error
void parseSlice(BoxedSlice* slice, int size, i64* out_start, i64* out_stop, i64* out_step, i64* out_length) { void parseSlice(BoxedSlice* slice, int size, i64* out_start, i64* out_stop, i64* out_step, i64* out_length) {
BoxedSlice* sslice = static_cast<BoxedSlice*>(slice); int ret = PySlice_GetIndicesEx((PySliceObject*)slice, size, out_start, out_stop, out_step, out_length);
if (ret == -1)
Box* start = sslice->start; throwCAPIException();
assert(start);
Box* stop = sslice->stop;
assert(stop);
Box* step = sslice->step;
assert(step);
RELEASE_ASSERT(isSubclass(start->cls, int_cls) || start->cls == none_cls, "");
RELEASE_ASSERT(isSubclass(stop->cls, int_cls) || stop->cls == none_cls, "");
RELEASE_ASSERT(isSubclass(step->cls, int_cls) || step->cls == none_cls, "");
int64_t istart;
int64_t istop;
int64_t istep = 1;
if (isSubclass(step->cls, int_cls)) {
istep = static_cast<BoxedInt*>(step)->n;
if (istep == 0) {
raiseExcHelper(ValueError, "slice step cannot be zero");
}
}
if (isSubclass(start->cls, int_cls)) {
istart = static_cast<BoxedInt*>(start)->n;
if (istart < 0)
istart = size + istart;
} else {
if (istep > 0)
istart = 0;
else
istart = size - 1;
}
if (isSubclass(stop->cls, int_cls)) {
istop = static_cast<BoxedInt*>(stop)->n;
if (istop < 0)
istop = size + istop;
} else {
if (istep > 0)
istop = size;
else
istop = -1;
}
if (istep > 0) {
if (istart < 0)
istart = 0;
if (istop > size)
istop = size;
} else {
if (istart >= size)
istart = size - 1;
if (istop < 0)
istop = -1;
}
*out_start = istart;
*out_stop = istop;
*out_step = istep;
if (out_length) {
// This is adapted from CPython's PySlice_GetIndicesEx.
if ((istep < 0 && istop >= istart) || (istep > 0 && istart >= istop))
*out_length = 0;
else if (istep < 0)
*out_length = (istop - istart + 1) / istep + 1;
else
*out_length = (istop - istart - 1) / istep + 1;
RELEASE_ASSERT(*out_length >= 0, "negative length, should never happen");
}
} }
} }
...@@ -40,6 +40,8 @@ print isinstance(1, int) ...@@ -40,6 +40,8 @@ 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))
print pow(11, 42)
print pow(11, 42, 75)
print divmod(5, 2) print divmod(5, 2)
print divmod(5L, -2) print divmod(5L, -2)
try: try:
......
# expected: fail
# - long % int
import sys import sys
P = 1000000007 P = 1000000007
......
class Index(object):
def __init__(self, i):
self.i = i
def __index__(self):
print "called __index__"
return self.i
s = "String"
l = [1, 2, "List"]
t = (1, 2, "Tuple")
print s[Index(2L)]
print l[Index(2L)]
print t[Index(2L)]
...@@ -13,6 +13,9 @@ for i in xrange(1, 12): ...@@ -13,6 +13,9 @@ for i in xrange(1, 12):
print 1 ** 0 print 1 ** 0
print 0 ** 0 print 0 ** 0
print -1 ** 0 print -1 ** 0
print (11).__pow__(5, 50)
print (11).__pow__(32, 50)
print (11).__index__()
for i in (-10, 10, 0, -15): for i in (-10, 10, 0, -15):
print i, i.__hex__(), i.__oct__() print i, i.__hex__(), i.__oct__()
......
...@@ -4,6 +4,7 @@ print l * 5 ...@@ -4,6 +4,7 @@ print l * 5
l[0] = 1 l[0] = 1
print l print l
print l[2] print l[2]
print l[2L]
l = range(5) l = range(5)
while l: while l:
......
...@@ -13,6 +13,7 @@ def test(a, b): ...@@ -13,6 +13,7 @@ def test(a, b):
print a - b, b - a, a.__sub__(b), b.__sub__(a) print a - b, b - a, a.__sub__(b), b.__sub__(a)
print a * b, b * a, a.__mul__(b), b.__mul__(a) print a * b, b * a, a.__mul__(b), b.__mul__(a)
print a / b, b / a, a.__div__(b), b.__div__(a) print a / b, b / a, a.__div__(b), b.__div__(a)
print a % b, b % a, a.__mod__(b), b.__mod__(a)
print repr(a), repr(b), a < b, a > b, a <= b, a >= b, a == b, a != b print repr(a), repr(b), a < b, a > b, a <= b, a >= b, a == b, a != b
if not isinstance(a, float) and not isinstance(b, float): if not isinstance(a, float) and not isinstance(b, float):
print a ^ b, a | b, a & b print a ^ b, a | b, a & b
...@@ -55,10 +56,15 @@ print ~(-10L) ...@@ -55,10 +56,15 @@ print ~(-10L)
print -(1L) print -(1L)
print 1L**2L print 1L**2L
print 1L**2 print 1L**2
print (11L).__pow__(32, 50L)
print (11L).__index__()
print long("100", 16) print long("100", 16)
print long("100", 10) print long("100", 10)
print long("100", 26) print long("100", 26)
print long("0x100", 16), long("0100", 8), long("0b100", 2)
print long("0x100", 0), long("0100", 0), long("0b100", 0)
print long("0b100", 16), long("0b100L", 0), long("-0b100L", 0)
print long(-1.1) print long(-1.1)
print long(1.9) print long(1.9)
print long(-1.9) print long(-1.9)
......
...@@ -133,6 +133,7 @@ except TypeError, e: ...@@ -133,6 +133,7 @@ except TypeError, e:
t = (1, "2") t = (1, "2")
print t[0] print t[0]
print t[1] print t[1]
print t[1L]
t = (1, 2, 'a', 'b', 'c') t = (1, 2, 'a', 'b', 'c')
print t[::-1] print t[::-1]
......
...@@ -15,3 +15,6 @@ for i in xrange(10, -10, -3): ...@@ -15,3 +15,6 @@ for i in xrange(10, -10, -3):
for i in xrange(0): for i in xrange(0):
print i print i
for i in xrange(10L, 15L, 1L):
print i
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