Commit a0aa3971 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #545 from kmod/tracebacks

tracebacks, struct.pack
parents 8802a933 b9abde9d
......@@ -292,29 +292,29 @@ def print_stack(f=None, limit=None, file=None):
stack frame at which to start. The optional 'limit' and 'file'
arguments have the same meaning as for print_exception().
"""
if f is not None or limit is not None:
raise NotImplementedError("print_stack() does not currently support the 'f' or 'limit' arguments in Pyston")
try:
raise ZeroDivisionError
except ZeroDivisionError:
# Make use of Pyston's incorrect behavior, that we generate exception tracebacks all the
# way to the top stack frame:
l = format_exception(*sys.exc_info())[1:-2]
for s in l:
_print(file, s, '')
if f is None:
# Pyston change:
"""
try:
raise ZeroDivisionError
except ZeroDivisionError:
f = sys.exc_info()[2].tb_frame.f_back
"""
f = sys._getframe(1)
print_list(extract_stack(f, limit), file)
def format_stack(f=None, limit=None):
"""Shorthand for 'format_list(extract_stack(f, limit))'."""
raise NotImplementedError("This function is currently not implemented in Pyston")
if f is None:
# Pyston change:
"""
try:
raise ZeroDivisionError
except ZeroDivisionError:
f = sys.exc_info()[2].tb_frame.f_back
"""
f = sys._getframe(1)
return format_list(extract_stack(f, limit))
def extract_stack(f=None, limit = None):
......@@ -327,12 +327,15 @@ def extract_stack(f=None, limit = None):
from oldest to newest stack frame.
"""
raise NotImplementedError("This function is currently not implemented in Pyston")
if f is None:
# Pyston change:
"""
try:
raise ZeroDivisionError
except ZeroDivisionError:
f = sys.exc_info()[2].tb_frame.f_back
"""
f = sys._getframe(1)
if limit is None:
if hasattr(sys, 'tracebacklimit'):
limit = sys.tracebacklimit
......
......@@ -345,16 +345,20 @@ extern "C" Box* pow_i64_i64(i64 lhs, i64 rhs) {
}
assert(rhs > 0);
while (rhs) {
while (true) {
if (rhs & 1) {
// TODO: could potentially avoid restarting the entire computation on overflow?
if (__builtin_smull_overflow(rtn, curpow, &rtn))
return longPow(boxLong(lhs), boxLong(orig_rhs));
}
if (__builtin_smull_overflow(curpow, curpow, &curpow))
return longPow(boxLong(lhs), boxLong(orig_rhs));
rhs >>= 1;
if (!rhs)
break;
if (__builtin_smull_overflow(curpow, curpow, &curpow))
return longPow(boxLong(lhs), boxLong(orig_rhs));
}
return boxInt(rtn);
}
......@@ -1031,11 +1035,6 @@ extern "C" Box* intNew(Box* _cls, Box* val, Box* base) {
return new (cls) BoxedInt(n->n);
}
extern "C" Box* intInit(BoxedInt* self, Box* val, Box* args) {
// int.__init__ will actually let you call it with anything
return None;
}
static void _addFuncIntFloatUnknown(const char* name, void* int_func, void* float_func, void* boxed_func) {
std::vector<ConcreteCompilerType*> v_ii, v_if, v_iu;
assert(BOXED_INT);
......@@ -1128,11 +1127,9 @@ void setupInt() {
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(
"__new__", new BoxedFunction(boxRTFunction((void*)intNew, UNKNOWN, 3, 2, false, false), { boxInt(0), NULL }));
int_cls->giveAttr("__init__",
new BoxedFunction(boxRTFunction((void*)intInit, NONE, 2, 1, true, false), { boxInt(0) }));
int_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)intNew, UNKNOWN, 3, 2, false, false,
ParamNames({ "", "x", "base" }, "", "")),
{ boxInt(0), NULL }));
int_cls->giveAttr("real", new (pyston_getset_cls) BoxedGetsetDescriptor(intInt, NULL, NULL));
int_cls->giveAttr("imag", new (pyston_getset_cls) BoxedGetsetDescriptor(int0, NULL, NULL));
......
......@@ -232,11 +232,11 @@ static int64_t asSignedLong(BoxedLong* self) {
static uint64_t asUnsignedLong(BoxedLong* self) {
assert(self->cls == long_cls);
// if this is ever true, we should raise a Python error, but I don't think we should hit it?
assert(mpz_cmp_si(self->n, 0) >= 0);
if (mpz_sgn(self->n) == -1)
raiseExcHelper(OverflowError, "can't convert negative value to unsigned long");
if (!mpz_fits_ulong_p(self->n))
raiseExcHelper(OverflowError, "long int too large to convert to int");
raiseExcHelper(OverflowError, "long int too large to convert");
return mpz_get_ui(self->n);
}
......@@ -259,7 +259,8 @@ extern "C" unsigned long PyLong_AsUnsignedLong(PyObject* vv) noexcept {
try {
return asUnsignedLong(l);
} catch (ExcInfo e) {
abort();
setCAPIException(e);
return -1;
}
}
......@@ -483,11 +484,56 @@ extern "C" void* PyLong_AsVoidPtr(PyObject* vv) noexcept {
extern "C" int _PyLong_AsByteArray(PyLongObject* v, unsigned char* bytes, size_t n, int little_endian,
int is_signed) noexcept {
RELEASE_ASSERT(little_endian == 1, "not implemented");
RELEASE_ASSERT(n == 8, "did not yet check if the behaviour is correct for sizes other than 8");
const mpz_t* op = &((BoxedLong*)v)->n;
mpz_t modified;
int sign = mpz_sgn(*op);
// If the value is zero, then mpz_export won't touch any of the memory, so handle that here:
if (sign == 0) {
memset(bytes, 0, n);
return 0;
}
size_t max_bits = n * 8;
if (is_signed)
max_bits--;
size_t bits;
if (sign == -1) {
if (!is_signed) {
PyErr_SetString(PyExc_OverflowError, "can't convert negative long to unsigned");
return -1;
}
// GMP uses sign-magnitude representation, and mpz_export just returns the magnitude.
// This is the easiest way I could think of to convert to two's complement.
// Note: the common case for this function is n in 1/2/4/8, where we could potentially
// just extract the value and then do the two's complement conversion ourselves. But
// then we would have to worry about endianness, which we don't right now.
mpz_init(modified);
mpz_com(modified, *op);
bits = mpz_sizeinbase(modified, 2);
for (int i = 0; i < 8 * n; i++) {
mpz_combit(modified, i);
}
op = &modified;
} else {
bits = mpz_sizeinbase(*op, 2);
}
if (bits > max_bits) {
if (sign == -1)
mpz_clear(modified);
PyErr_SetString(PyExc_OverflowError, "long too big to convert");
return -1;
}
size_t count = 0;
mpz_export(bytes, &count, -1, n, 0, 0, ((BoxedLong*)v)->n);
RELEASE_ASSERT(count <= n, "overflow handling is not yet implemented");
mpz_export(bytes, &count, 1, n, little_endian ? -1 : 1, 0, *op);
ASSERT(count == 1, "overflow? (%ld %ld)", count, n);
if (sign == -1)
mpz_clear(modified);
return 0;
}
......@@ -897,7 +943,7 @@ Box* longLshift(BoxedLong* v1, Box* _v2) {
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
if (mpz_cmp_si(v2->n, 0) < 0)
if (mpz_sgn(v2->n) < 0)
raiseExcHelper(ValueError, "negative shift count");
uint64_t n = asUnsignedLong(v2);
......@@ -927,7 +973,7 @@ Box* longRshift(BoxedLong* v1, Box* _v2) {
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
if (mpz_cmp_si(v2->n, 0) < 0)
if (mpz_sgn(v2->n) < 0)
raiseExcHelper(ValueError, "negative shift count");
uint64_t n = asUnsignedLong(v2);
......@@ -1013,7 +1059,7 @@ Box* longDiv(BoxedLong* v1, Box* _v2) {
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
if (mpz_cmp_si(v2->n, 0) == 0)
if (mpz_sgn(v2->n) == 0)
raiseExcHelper(ZeroDivisionError, "long division or modulo by zero");
BoxedLong* r = new BoxedLong();
......@@ -1049,7 +1095,7 @@ Box* longMod(BoxedLong* v1, Box* _v2) {
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
if (mpz_cmp_si(v2->n, 0) == 0)
if (mpz_sgn(v2->n) == 0)
raiseExcHelper(ZeroDivisionError, "long division or modulo by zero");
BoxedLong* r = new BoxedLong();
......@@ -1095,7 +1141,7 @@ extern "C" Box* longDivmod(BoxedLong* lhs, Box* _rhs) {
if (isSubclass(_rhs->cls, long_cls)) {
BoxedLong* rhs = static_cast<BoxedLong*>(_rhs);
if (mpz_cmp_si(rhs->n, 0) == 0)
if (mpz_sgn(rhs->n) == 0)
raiseExcHelper(ZeroDivisionError, "long division or modulo by zero");
BoxedLong* q = new BoxedLong();
......@@ -1126,7 +1172,7 @@ Box* longRdiv(BoxedLong* v1, Box* _v2) {
raiseExcHelper(TypeError, "descriptor '__rdiv__' requires a 'long' object but received a '%s'",
getTypeName(v1));
if (mpz_cmp_si(v1->n, 0) == 0)
if (mpz_sgn(v1->n) == 0)
raiseExcHelper(ZeroDivisionError, "long division or modulo by zero");
if (isSubclass(_v2->cls, long_cls)) {
......@@ -1255,7 +1301,7 @@ Box* longNonzero(BoxedLong* self) {
raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'long' object but received a '%s'",
getTypeName(self));
if (mpz_cmp_si(self->n, 0) == 0)
if (mpz_sgn(self->n) == 0)
return False;
return True;
}
......
......@@ -87,3 +87,7 @@ class I(int):
for i1 in [1, I(2), 3, I(4)]:
for i2 in [1, I(2), 3, I(4)]:
print -i1, +i1, ~i1, i1 < i2, i1 <= i2, i1 == i2, i1 > i2, i1 >= i2, i1 != i2, i1 | i2, i1 ^ i2, i1 & i2, i1 * i2, i1 + i2, i1 / i2, i1 - i2, i1 ** i2, i1 // i2
print int("12345", base=16)
print type(2 ** 48)
......@@ -2,3 +2,18 @@ import struct
s = struct.pack("II", 1, 1234)
print repr(s)
print struct.unpack("II", s)
nums = [0, 0x98, -0x12, 0x9876, -0x1234, 0x98765432, -0x12345678, 0x9876543212345678, -0x1234567812345678]
for exp in 7, 8, 15, 16, 31, 32, 63, 64:
nums += [2 ** exp, 2 ** exp - 1, -2 ** exp, -2 ** exp - 1]
for format in "bB?hHiIlLqQP":
for order in [""] + list("@=<>!"):
for num in nums:
try:
spec = "%s%s" % (order, format)
print (spec, hex(num)), repr(struct.pack(spec, num))
except struct.error as e:
print "struct.error:", e
except OverflowError as e:
print "OverflowError:", e
# A test of both the tracebacks we generate and the tracebacks module
# A test of both the tracebacks we generate and the traceback module
#
# (We keep fixing tracebacks in one case to break them in another, so it's time for a test.)
#
......@@ -103,6 +103,15 @@ except:
except:
traceback.print_exc(file=sys.stdout)
def f(n):
if n:
return f(n - 1)
traceback.print_stack(file=sys.stdout)
print
return traceback.format_stack()
print
print ''.join(f(5))
# Output some extra stuff at the end so that it doesn't look like the script crashed with an exception:
print
......
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