diff --git a/py/bc.h b/py/bc.h index aac35954d7..0709897750 100644 --- a/py/bc.h +++ b/py/bc.h @@ -4,6 +4,16 @@ typedef enum { MP_VM_RETURN_EXCEPTION, } mp_vm_return_kind_t; +// Exception stack entry +typedef struct _mp_exc_stack { + const byte *handler; + // bit 0 is saved currently_in_except_block value + machine_uint_t val_sp; + // We might only have 2 interesting cases here: SETUP_EXCEPT & SETUP_FINALLY, + // consider storing it in bit 1 of val_sp. TODO: SETUP_WITH? + byte opcode; +} mp_exc_stack; + mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, uint n_state, mp_obj_t *ret); -mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out); +mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out, mp_exc_stack *exc_stack, mp_exc_stack **exc_sp_in_out, volatile mp_obj_t inject_exc); void mp_byte_code_print(const byte *code, int len); diff --git a/py/builtinmath.c b/py/builtinmath.c index 59af5a021d..818ac1d9dd 100644 --- a/py/builtinmath.c +++ b/py/builtinmath.c @@ -9,6 +9,7 @@ #if MICROPY_ENABLE_FLOAT +//TODO: Change macros to check for overflow and raise OverflowError or RangeError #define MATH_FUN_1(py_name, c_name) \ mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); @@ -17,6 +18,10 @@ mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_float(y_obj))); } \ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name); +#define MATH_FUN_BOOL1(py_name, c_name) \ + mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return MP_BOOL(c_name(mp_obj_get_float(x_obj))); } \ + STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); + STATIC const mp_obj_float_t mp_math_e_obj = {{&mp_type_float}, M_E}; STATIC const mp_obj_float_t mp_math_pi_obj = {{&mp_type_float}, M_PI}; @@ -45,13 +50,49 @@ MATH_FUN_2(copysign, copysign) MATH_FUN_1(fabs, fabs) MATH_FUN_1(floor, floor) //TODO: delegate to x.__floor__() if x is not a float MATH_FUN_2(fmod, fmod) -//MATH_FUN_1(frexp, frexp) -//MATH_FUN_1(isfinite, isfinite) -//MATH_FUN_1(isinf, isinf) -//MATH_FUN_1(isnan, isnan) +MATH_FUN_BOOL1(isfinite, isfinite) +MATH_FUN_BOOL1(isinf, isinf) +MATH_FUN_BOOL1(isnan, isnan) MATH_FUN_1(trunc, trunc) +MATH_FUN_2(ldexp, ldexp) +MATH_FUN_1(erf, erf) +MATH_FUN_1(erfc, erfc) +MATH_FUN_1(gamma, gamma) +MATH_FUN_1(lgamma, lgamma) +//TODO: factorial, fsum + +// Functions that return a tuple +mp_obj_t mp_math_frexp(mp_obj_t x_obj){ + machine_int_t int_exponent = 0; + mp_float_t significand = frexp(mp_obj_get_float(x_obj), &int_exponent); + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_float(significand); + tuple[1] = mp_obj_new_int(int_exponent); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp); + +mp_obj_t mp_math_modf(mp_obj_t x_obj){ + mp_float_t int_part = 0.0; + mp_float_t fractional_part = modf(mp_obj_get_float(x_obj), &int_part); + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_float(fractional_part); + tuple[1] = mp_obj_new_float(int_part); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf); + +// Angular conversions +mp_obj_t mp_math_radians(mp_obj_t x_obj){ + return mp_obj_new_float(mp_obj_get_float(x_obj) * M_PI / 180.0); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians); + +mp_obj_t mp_math_degrees(mp_obj_t x_obj){ + return mp_obj_new_float(mp_obj_get_float(x_obj) * 180.0 / M_PI); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_degrees_obj, mp_math_degrees); -//TODO: factorial, fsum, frexp, ldexp, modf STATIC const mp_map_elem_t mp_module_math_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_math) }, @@ -81,12 +122,19 @@ STATIC const mp_map_elem_t mp_module_math_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_copysign), (mp_obj_t)&mp_math_copysign_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_fabs), (mp_obj_t)&mp_math_fabs_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&mp_math_floor_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_fmod), (mp_obj_t)&mp_math_fmod_obj }, - //{ MP_OBJ_NEW_QSTR(MP_QSTR_frexp), (mp_obj_t)&mp_math_frexp_obj }, - //{ MP_OBJ_NEW_QSTR(MP_QSTR_isfinite), (mp_obj_t)&mp_math_isfinite_obj }, - //{ MP_OBJ_NEW_QSTR(MP_QSTR_isinf), (mp_obj_t)&mp_math_isinf_obj }, - //{ MP_OBJ_NEW_QSTR(MP_QSTR_isnan), (mp_obj_t)&mp_math_isnan_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_frexp), (mp_obj_t)&mp_math_frexp_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ldexp), (mp_obj_t)&mp_math_ldexp_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_modf), (mp_obj_t)&mp_math_modf_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isfinite), (mp_obj_t)&mp_math_isfinite_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isinf), (mp_obj_t)&mp_math_isinf_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isnan), (mp_obj_t)&mp_math_isnan_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_trunc), (mp_obj_t)&mp_math_trunc_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_radians), (mp_obj_t)&mp_math_radians_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_degrees), (mp_obj_t)&mp_math_degrees_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_erf), (mp_obj_t)&mp_math_erf_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_erfc), (mp_obj_t)&mp_math_erfc_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_gamma), (mp_obj_t)&mp_math_gamma_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_lgamma), (mp_obj_t)&mp_math_lgamma_obj }, }; STATIC const mp_map_t mp_module_math_globals = { diff --git a/py/compile.c b/py/compile.c index bb688d5d8e..0a10b81768 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "misc.h" #include "mpconfig.h" @@ -15,6 +16,7 @@ #include "obj.h" #include "compile.h" #include "runtime.h" +#include "intdivmod.h" // TODO need to mangle __attr names @@ -140,11 +142,13 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) { } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) { ; // pass } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) { - // XXX implement this properly as Python's % operator acts differently to C's - pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 % arg1); + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, python_modulo(arg0, arg1)); } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) { - // XXX implement this properly as Python's // operator acts differently to C's - pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 / arg1); + //pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, + // floor((mp_float_t)arg0 / arg1)); + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, + python_floor_divide(arg0, arg1)); + } else { // shouldn't happen assert(0); diff --git a/py/obj.h b/py/obj.h index 1daa943447..3217c4a4d1 100644 --- a/py/obj.h +++ b/py/obj.h @@ -184,9 +184,53 @@ struct _mp_obj_type_t { typedef struct _mp_obj_type_t mp_obj_type_t; // Constant types, globally accessible - extern const mp_obj_type_t mp_type_type; + +// Exceptions extern const mp_obj_type_t mp_type_BaseException; +extern const mp_obj_type_t mp_type_ArithmeticError; +extern const mp_obj_type_t mp_type_AssertionError; +extern const mp_obj_type_t mp_type_AttributeError; +extern const mp_obj_type_t mp_type_BufferError; +extern const mp_obj_type_t mp_type_BytesWarning; +extern const mp_obj_type_t mp_type_DeprecationWarning; +extern const mp_obj_type_t mp_type_EOFError; +extern const mp_obj_type_t mp_type_EnvironmentError; +extern const mp_obj_type_t mp_type_Exception; +extern const mp_obj_type_t mp_type_FloatingPointError; +extern const mp_obj_type_t mp_type_FutureWarning; +extern const mp_obj_type_t mp_type_GeneratorExit; +extern const mp_obj_type_t mp_type_IOError; +extern const mp_obj_type_t mp_type_ImportError; +extern const mp_obj_type_t mp_type_ImportWarning; +extern const mp_obj_type_t mp_type_IndentationError; +extern const mp_obj_type_t mp_type_IndexError; +extern const mp_obj_type_t mp_type_KeyError; +extern const mp_obj_type_t mp_type_LookupError; +extern const mp_obj_type_t mp_type_MemoryError; +extern const mp_obj_type_t mp_type_NameError; +extern const mp_obj_type_t mp_type_NotImplementedError; +extern const mp_obj_type_t mp_type_OSError; +extern const mp_obj_type_t mp_type_OverflowError; +extern const mp_obj_type_t mp_type_PendingDeprecationWarning; +extern const mp_obj_type_t mp_type_ReferenceError; +extern const mp_obj_type_t mp_type_ResourceWarning; +extern const mp_obj_type_t mp_type_RuntimeError; +extern const mp_obj_type_t mp_type_RuntimeWarning; +extern const mp_obj_type_t mp_type_SyntaxError; +extern const mp_obj_type_t mp_type_SyntaxWarning; +extern const mp_obj_type_t mp_type_SystemError; +extern const mp_obj_type_t mp_type_SystemExit; +extern const mp_obj_type_t mp_type_TabError; +extern const mp_obj_type_t mp_type_TypeError; +extern const mp_obj_type_t mp_type_UnboundLocalError; +extern const mp_obj_type_t mp_type_UserWarning; +extern const mp_obj_type_t mp_type_ValueError; +extern const mp_obj_type_t mp_type_Warning; +extern const mp_obj_type_t mp_type_ZeroDivisionError; + +extern const mp_obj_type_t mp_type_StopIteration; +/*extern const mp_obj_type_t mp_type_BaseException; extern const mp_obj_type_t mp_type_AssertionError; extern const mp_obj_type_t mp_type_AttributeError; extern const mp_obj_type_t mp_type_ImportError; @@ -201,6 +245,7 @@ extern const mp_obj_type_t mp_type_OverflowError; extern const mp_obj_type_t mp_type_OSError; extern const mp_obj_type_t mp_type_NotImplementedError; extern const mp_obj_type_t mp_type_StopIteration; +extern const mp_obj_type_t mp_type_ZeroDivisionError;*/ // Constant objects, globally accessible diff --git a/py/objexcept.c b/py/objexcept.c index 11177724da..7fd783b3a4 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -77,22 +77,78 @@ const mp_obj_type_t mp_type_ ## exc_name = { \ .bases_tuple = (mp_obj_t)&mp_type_ ## base_name ## _base_tuple, \ }; +// List of all exceptions, arranged as in the table at: +// http://docs.python.org/3.3/library/exceptions.html MP_DEFINE_EXCEPTION_BASE(BaseException) - -MP_DEFINE_EXCEPTION(AssertionError, BaseException) -MP_DEFINE_EXCEPTION(AttributeError, BaseException) -MP_DEFINE_EXCEPTION(ImportError, BaseException) -MP_DEFINE_EXCEPTION(IndentationError, BaseException) -MP_DEFINE_EXCEPTION(IndexError, BaseException) -MP_DEFINE_EXCEPTION(KeyError, BaseException) -MP_DEFINE_EXCEPTION(NameError, BaseException) -MP_DEFINE_EXCEPTION(SyntaxError, BaseException) -MP_DEFINE_EXCEPTION(TypeError, BaseException) -MP_DEFINE_EXCEPTION(ValueError, BaseException) -MP_DEFINE_EXCEPTION(OverflowError, BaseException) -MP_DEFINE_EXCEPTION(OSError, BaseException) -MP_DEFINE_EXCEPTION(NotImplementedError, BaseException) -MP_DEFINE_EXCEPTION(StopIteration, BaseException) +MP_DEFINE_EXCEPTION(SystemExit, BaseException) +//MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException) +MP_DEFINE_EXCEPTION(GeneratorExit, BaseException) +MP_DEFINE_EXCEPTION(Exception, BaseException) + MP_DEFINE_EXCEPTION_BASE(Exception) + MP_DEFINE_EXCEPTION(StopIteration, Exception) + MP_DEFINE_EXCEPTION(ArithmeticError, Exception) + MP_DEFINE_EXCEPTION_BASE(ArithmeticError) + MP_DEFINE_EXCEPTION(FloatingPointError, ArithmeticError) + MP_DEFINE_EXCEPTION(OverflowError, ArithmeticError) + MP_DEFINE_EXCEPTION(ZeroDivisionError, ArithmeticError) + MP_DEFINE_EXCEPTION(AssertionError, Exception) + MP_DEFINE_EXCEPTION(AttributeError, Exception) + MP_DEFINE_EXCEPTION(BufferError, Exception) + MP_DEFINE_EXCEPTION(EnvironmentError, Exception) + MP_DEFINE_EXCEPTION(EOFError, Exception) + MP_DEFINE_EXCEPTION(ImportError, Exception) + MP_DEFINE_EXCEPTION(IOError, Exception) + MP_DEFINE_EXCEPTION(LookupError, Exception) + MP_DEFINE_EXCEPTION_BASE(LookupError) + MP_DEFINE_EXCEPTION(IndexError, LookupError) + MP_DEFINE_EXCEPTION(KeyError, LookupError) + MP_DEFINE_EXCEPTION(MemoryError, Exception) + MP_DEFINE_EXCEPTION(NameError, Exception) + MP_DEFINE_EXCEPTION_BASE(NameError) + MP_DEFINE_EXCEPTION(UnboundLocalError, NameError) + MP_DEFINE_EXCEPTION(OSError, Exception) + // Probably don't need these + /*MP_DEFINE_EXCEPTION_BASE(OSError) + MP_DEFINE_EXCEPTION(BlockingIOError, OSError) + MP_DEFINE_EXCEPTION(ChildProcessError, OSError) + MP_DEFINE_EXCEPTION(ConnectionError, OSError) + MP_DEFINE_EXCEPTION(BrokenPipeError, ConnectionError) + MP_DEFINE_EXCEPTION(ConnectionAbortedError, ConnectionError) + MP_DEFINE_EXCEPTION(ConnectionRefusedError, ConnectionError) + MP_DEFINE_EXCEPTION(ConnectionResetError, ConnectionError) + MP_DEFINE_EXCEPTION(FileExistsError, OSError) + MP_DEFINE_EXCEPTION(FileNotFoundError, OSError) + MP_DEFINE_EXCEPTION(InterruptedError, OSError) + MP_DEFINE_EXCEPTION(IsADirectoryError, OSError) + MP_DEFINE_EXCEPTION(NotADirectoryError, OSError) + MP_DEFINE_EXCEPTION(PermissionError, OSError) + MP_DEFINE_EXCEPTION(ProcessLookupError, OSError) + MP_DEFINE_EXCEPTION(TimeoutError, OSError)*/ + MP_DEFINE_EXCEPTION(ReferenceError, Exception) + MP_DEFINE_EXCEPTION(RuntimeError, Exception) + MP_DEFINE_EXCEPTION_BASE(RuntimeError) + MP_DEFINE_EXCEPTION(NotImplementedError, RuntimeError) + MP_DEFINE_EXCEPTION(SyntaxError, Exception) + MP_DEFINE_EXCEPTION_BASE(SyntaxError) + MP_DEFINE_EXCEPTION(IndentationError, SyntaxError) + MP_DEFINE_EXCEPTION_BASE(IndentationError) + MP_DEFINE_EXCEPTION(TabError, IndentationError) + MP_DEFINE_EXCEPTION(SystemError, Exception) + MP_DEFINE_EXCEPTION(TypeError, Exception) + MP_DEFINE_EXCEPTION(ValueError, Exception) + //TODO: Implement UnicodeErrors which take arguments + MP_DEFINE_EXCEPTION(Warning, Exception) + MP_DEFINE_EXCEPTION_BASE(Warning) + MP_DEFINE_EXCEPTION(DeprecationWarning, Warning) + MP_DEFINE_EXCEPTION(PendingDeprecationWarning, Warning) + MP_DEFINE_EXCEPTION(RuntimeWarning, Warning) + MP_DEFINE_EXCEPTION(SyntaxWarning, Warning) + MP_DEFINE_EXCEPTION(UserWarning, Warning) + MP_DEFINE_EXCEPTION(FutureWarning, Warning) + MP_DEFINE_EXCEPTION(ImportWarning, Warning) + MP_DEFINE_EXCEPTION(UnicodeWarning, Warning) + MP_DEFINE_EXCEPTION(BytesWarning, Warning) + MP_DEFINE_EXCEPTION(ResourceWarning, Warning) mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) { return mp_obj_new_exception_msg_varg(exc_type, NULL); diff --git a/py/objfloat.c b/py/objfloat.c index c51e13e7a1..c4567c4a38 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -1,5 +1,6 @@ #include #include +#include #include "nlr.h" #include "misc.h" @@ -107,8 +108,12 @@ mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs_in) { case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: val = lhs_val / rhs_val; break; */ case RT_BINARY_OP_TRUE_DIVIDE: - case RT_BINARY_OP_INPLACE_TRUE_DIVIDE: lhs_val /= rhs_val; break; - + case RT_BINARY_OP_INPLACE_TRUE_DIVIDE: + lhs_val /= rhs_val; + if (isinf(lhs_val)){ // check for division by zero + nlr_jump(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "float division by zero")); + } + break; case RT_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); case RT_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); case RT_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); diff --git a/py/objgenerator.c b/py/objgenerator.c index 8c4bb595f1..2db04ad742 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -56,8 +56,10 @@ typedef struct _mp_obj_gen_instance_t { const byte *code_info; const byte *ip; mp_obj_t *sp; + mp_exc_stack *exc_sp; uint n_state; - mp_obj_t state[]; + mp_obj_t state[0]; // Variable-length + mp_exc_stack exc_state[0]; // Variable-length } mp_obj_gen_instance_t; void gen_instance_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { @@ -68,7 +70,7 @@ mp_obj_t gen_instance_getiter(mp_obj_t self_in) { return self_in; } -STATIC mp_obj_t gen_next_send(mp_obj_t self_in, mp_obj_t send_value) { +STATIC mp_obj_t gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value) { mp_obj_gen_instance_t *self = self_in; if (self->ip == 0) { return mp_const_stop_iteration; @@ -80,7 +82,9 @@ STATIC mp_obj_t gen_next_send(mp_obj_t self_in, mp_obj_t send_value) { } else { *self->sp = send_value; } - mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code_2(self->code_info, &self->ip, &self->state[self->n_state - 1], &self->sp); + mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code_2(self->code_info, &self->ip, + &self->state[self->n_state - 1], &self->sp, (mp_exc_stack*)(self->state + self->n_state), + &self->exc_sp, throw_value); switch (vm_return_kind) { case MP_VM_RETURN_NORMAL: // Explicitly mark generator as completed. If we don't do this, @@ -100,19 +104,21 @@ STATIC mp_obj_t gen_next_send(mp_obj_t self_in, mp_obj_t send_value) { return *self->sp; case MP_VM_RETURN_EXCEPTION: + self->ip = 0; + nlr_jump(self->state[self->n_state - 1]); + default: - // TODO assert(0); return mp_const_none; } } mp_obj_t gen_instance_iternext(mp_obj_t self_in) { - return gen_next_send(self_in, mp_const_none); + return gen_resume(self_in, mp_const_none, MP_OBJ_NULL); } STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) { - mp_obj_t ret = gen_next_send(self_in, send_value); + mp_obj_t ret = gen_resume(self_in, send_value, MP_OBJ_NULL); if (ret == mp_const_stop_iteration) { nlr_jump(mp_obj_new_exception(&mp_type_StopIteration)); } else { @@ -122,8 +128,21 @@ STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send); +STATIC mp_obj_t gen_instance_throw(uint n_args, const mp_obj_t *args) { + mp_obj_t ret = gen_resume(args[0], mp_const_none, n_args == 2 ? args[1] : args[2]); + if (ret == mp_const_stop_iteration) { + nlr_jump(mp_obj_new_exception(&mp_type_StopIteration)); + } else { + return ret; + } +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gen_instance_throw_obj, 2, 4, gen_instance_throw); + + STATIC const mp_method_t gen_type_methods[] = { { "send", &gen_instance_send_obj }, + { "throw", &gen_instance_throw_obj }, { NULL, NULL }, // end-of-list sentinel }; @@ -137,11 +156,13 @@ const mp_obj_type_t gen_instance_type = { }; mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args) { - mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, mp_obj_t, n_state); + // TODO: 4 is hardcoded number from vm.c, calc exc stack size instead. + mp_obj_gen_instance_t *o = m_new_obj_var(mp_obj_gen_instance_t, byte, n_state * sizeof(mp_obj_t) + 4 * sizeof(mp_exc_stack)); o->base.type = &gen_instance_type; o->code_info = bytecode; o->ip = bytecode; o->sp = &o->state[0] - 1; // sp points to top of stack, which starts off 1 below the state + o->exc_sp = (mp_exc_stack*)(o->state + n_state) - 1; o->n_state = n_state; // copy args to end of state array, in reverse (that's how mp_execute_byte_code_2 needs it) diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 21e3202a95..39ea7ca115 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -1,5 +1,6 @@ #include #include +#include #include "nlr.h" #include "misc.h" @@ -97,15 +98,24 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: { mpz_t rem; mpz_init_zero(&rem); mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); + if (zlhs->neg != zrhs->neg) { + if (!mpz_is_zero(&rem)) { + mpz_t mpzone; mpz_init_from_int(&mpzone, -1); + mpz_add_inpl(&res->mpz, &res->mpz, &mpzone); + } + } mpz_deinit(&rem); break; } case RT_BINARY_OP_MODULO: case RT_BINARY_OP_INPLACE_MODULO: { - // TODO check that this operation matches the CPython operation mpz_t quo; mpz_init_zero(&quo); mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs); mpz_deinit(&quo); + // Check signs and do Python style modulo + if (zlhs->neg != zrhs->neg) { + mpz_add_inpl(&res->mpz, &res->mpz, zrhs); + } break; } diff --git a/py/py.mk b/py/py.mk index 0814176815..add871632f 100644 --- a/py/py.mk +++ b/py/py.mk @@ -78,6 +78,7 @@ PY_O_BASENAME = \ vm.o \ showbc.o \ repl.o \ + intdivmod.o \ # prepend the build destination prefix to the py object files PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 649f89eb1e..96d94d937d 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -34,19 +34,63 @@ Q(Ellipsis) Q(StopIteration) Q(BaseException) +Q(ArithmeticError) Q(AssertionError) Q(AttributeError) +Q(BlockingIOError) +Q(BrokenPipeError) +Q(BufferError) +Q(BytesWarning) +Q(ChildProcessError) +Q(ConnectionAbortedError) +Q(ConnectionError) +Q(ConnectionRefusedError) +Q(ConnectionResetError) +Q(DeprecationWarning) +Q(EOFError) +Q(EnvironmentError) +Q(Exception) +Q(FileExistsError) +Q(FileNotFoundError) +Q(FloatingPointError) +Q(FutureWarning) +Q(GeneratorExit) +Q(IOError) Q(ImportError) +Q(ImportWarning) Q(IndentationError) Q(IndexError) +Q(InterruptedError) +Q(IsADirectoryError) Q(KeyError) +Q(LookupError) +Q(MemoryError) Q(NameError) +Q(NotADirectoryError) Q(NotImplementedError) Q(OSError) -Q(SyntaxError) -Q(TypeError) -Q(ValueError) Q(OverflowError) +Q(PendingDeprecationWarning) +Q(PermissionError) +Q(ProcessLookupError) +Q(ReferenceError) +Q(ResourceWarning) +Q(RuntimeError) +Q(RuntimeWarning) +Q(SyntaxError) +Q(SyntaxWarning) +Q(SystemError) +Q(SystemExit) +Q(TabError) +Q(TimeoutError) +Q(TypeError) +Q(UnboundLocalError) +Q(UnicodeWarning) +Q(UserWarning) +Q(ValueError) +Q(Warning) +Q(ZeroDivisionError) + Q(NoneType) @@ -144,13 +188,21 @@ Q(atan2) Q(ceil) Q(copysign) Q(fabs) -Q(floor) Q(fmod) -Q(frexp) +Q(floor) Q(isfinite) Q(isinf) Q(isnan) Q(trunc) +Q(modf) +Q(frexp) +Q(ldexp) +Q(degrees) +Q(radians) +Q(erf) +Q(erfc) +Q(gamma) +Q(lgamma) Q(mem_total) Q(mem_current) diff --git a/py/runtime.c b/py/runtime.c index 4bcb91c547..94f3190566 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "nlr.h" #include "misc.h" @@ -18,6 +19,7 @@ #include "builtin.h" #include "objarray.h" #include "bc.h" +#include "intdivmod.h" #if 0 // print debugging info #define DEBUG_PRINT (1) @@ -142,22 +144,49 @@ STATIC const mp_builtin_elem_t builtin_table[] = { // built-in exceptions { MP_QSTR_BaseException, (mp_obj_t)&mp_type_BaseException }, + { MP_QSTR_ArithmeticError, (mp_obj_t)&mp_type_ArithmeticError }, { MP_QSTR_AssertionError, (mp_obj_t)&mp_type_AssertionError }, { MP_QSTR_AttributeError, (mp_obj_t)&mp_type_AttributeError }, + { MP_QSTR_BufferError, (mp_obj_t)&mp_type_BufferError }, + { MP_QSTR_BytesWarning, (mp_obj_t)&mp_type_BytesWarning }, + { MP_QSTR_DeprecationWarning, (mp_obj_t)&mp_type_DeprecationWarning }, + { MP_QSTR_EOFError, (mp_obj_t)&mp_type_EOFError }, + { MP_QSTR_EnvironmentError, (mp_obj_t)&mp_type_EnvironmentError }, + { MP_QSTR_Exception, (mp_obj_t)&mp_type_Exception }, + { MP_QSTR_FloatingPointError, (mp_obj_t)&mp_type_FloatingPointError }, + { MP_QSTR_FutureWarning, (mp_obj_t)&mp_type_FutureWarning }, + { MP_QSTR_GeneratorExit, (mp_obj_t)&mp_type_GeneratorExit }, + { MP_QSTR_IOError, (mp_obj_t)&mp_type_IOError }, { MP_QSTR_ImportError, (mp_obj_t)&mp_type_ImportError }, + { MP_QSTR_ImportWarning, (mp_obj_t)&mp_type_ImportWarning }, { MP_QSTR_IndentationError, (mp_obj_t)&mp_type_IndentationError }, { MP_QSTR_IndexError, (mp_obj_t)&mp_type_IndexError }, { MP_QSTR_KeyError, (mp_obj_t)&mp_type_KeyError }, + { MP_QSTR_LookupError, (mp_obj_t)&mp_type_LookupError }, + { MP_QSTR_MemoryError, (mp_obj_t)&mp_type_MemoryError }, { MP_QSTR_NameError, (mp_obj_t)&mp_type_NameError }, + { MP_QSTR_NotImplementedError, (mp_obj_t)&mp_type_NotImplementedError }, + { MP_QSTR_OSError, (mp_obj_t)&mp_type_OSError }, + { MP_QSTR_OverflowError, (mp_obj_t)&mp_type_OverflowError }, + { MP_QSTR_PendingDeprecationWarning, (mp_obj_t)&mp_type_PendingDeprecationWarning }, + { MP_QSTR_ReferenceError, (mp_obj_t)&mp_type_ReferenceError }, + { MP_QSTR_ResourceWarning, (mp_obj_t)&mp_type_ResourceWarning }, + { MP_QSTR_RuntimeError, (mp_obj_t)&mp_type_RuntimeError }, + { MP_QSTR_RuntimeWarning, (mp_obj_t)&mp_type_RuntimeWarning }, { MP_QSTR_SyntaxError, (mp_obj_t)&mp_type_SyntaxError }, + { MP_QSTR_SyntaxWarning, (mp_obj_t)&mp_type_SyntaxWarning }, + { MP_QSTR_SystemError, (mp_obj_t)&mp_type_SystemError }, + { MP_QSTR_SystemExit, (mp_obj_t)&mp_type_SystemExit }, + { MP_QSTR_TabError, (mp_obj_t)&mp_type_TabError }, { MP_QSTR_TypeError, (mp_obj_t)&mp_type_TypeError }, + { MP_QSTR_UnboundLocalError, (mp_obj_t)&mp_type_UnboundLocalError }, + { MP_QSTR_UserWarning, (mp_obj_t)&mp_type_UserWarning }, { MP_QSTR_ValueError, (mp_obj_t)&mp_type_ValueError }, + { MP_QSTR_Warning, (mp_obj_t)&mp_type_Warning }, + { MP_QSTR_ZeroDivisionError, (mp_obj_t)&mp_type_ZeroDivisionError }, + { MP_QSTR_StopIteration, (mp_obj_t)&mp_type_StopIteration }, // Somehow CPython managed to have OverflowError not inherit from ValueError ;-/ // TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation - { MP_QSTR_OverflowError, (mp_obj_t)&mp_type_OverflowError }, - { MP_QSTR_OSError, (mp_obj_t)&mp_type_OSError }, - { MP_QSTR_NotImplementedError, (mp_obj_t)&mp_type_NotImplementedError }, - { MP_QSTR_StopIteration, (mp_obj_t)&mp_type_StopIteration }, // Extra builtins as defined by a port MICROPY_EXTRA_BUILTINS @@ -633,16 +662,22 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { break; } case RT_BINARY_OP_FLOOR_DIVIDE: - case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: lhs_val /= rhs_val; break; + case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: + { + lhs_val = python_floor_divide(lhs_val, rhs_val); + break; + } #if MICROPY_ENABLE_FLOAT case RT_BINARY_OP_TRUE_DIVIDE: case RT_BINARY_OP_INPLACE_TRUE_DIVIDE: return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val); #endif - // TODO implement modulo as specified by Python case RT_BINARY_OP_MODULO: - case RT_BINARY_OP_INPLACE_MODULO: lhs_val %= rhs_val; break; - + case RT_BINARY_OP_INPLACE_MODULO: + { + lhs_val = python_modulo(lhs_val, rhs_val); + break; + } case RT_BINARY_OP_POWER: case RT_BINARY_OP_INPLACE_POWER: if (rhs_val < 0) { diff --git a/py/vm.c b/py/vm.c index 7b78b5fefb..7f4efeea0f 100644 --- a/py/vm.c +++ b/py/vm.c @@ -17,16 +17,6 @@ // top element. // Exception stack also grows up, top element is also pointed at. -// Exception stack entry -typedef struct _mp_exc_stack { - const byte *handler; - // bit 0 is saved currently_in_except_block value - machine_uint_t val_sp; - // We might only have 2 interesting cases here: SETUP_EXCEPT & SETUP_FINALLY, - // consider storing it in bit 1 of val_sp. TODO: SETUP_WITH? - byte opcode; -} mp_exc_stack; - // Exception stack unwind reasons (WHY_* in CPython-speak) // TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds // left to do encoded in the JUMP number @@ -89,8 +79,10 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, } } + mp_exc_stack exc_stack[4]; + mp_exc_stack *exc_sp = &exc_stack[0] - 1; // execute the byte code - mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code_2(code, &ip, &state[n_state - 1], &sp); + mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code_2(code, &ip, &state[n_state - 1], &sp, exc_stack, &exc_sp, MP_OBJ_NULL); switch (vm_return_kind) { case MP_VM_RETURN_NORMAL: @@ -113,7 +105,10 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, // MP_VM_RETURN_NORMAL, sp valid, return value in *sp // MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp // MP_VM_RETURN_EXCEPTION, exception in fastn[0] -mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out) { +mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, + mp_obj_t *fastn, mp_obj_t **sp_in_out, + mp_exc_stack *exc_stack, mp_exc_stack **exc_sp_in_out, + volatile mp_obj_t inject_exc) { // careful: be sure to declare volatile any variables read in the exception handler (written is ok, I think) const byte *ip = *ip_in_out; @@ -123,14 +118,21 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i mp_obj_t obj1, obj2; nlr_buf_t nlr; - volatile machine_uint_t currently_in_except_block = 0; // 0 or 1, to detect nested exceptions - mp_exc_stack exc_stack[4]; - mp_exc_stack *volatile exc_sp = &exc_stack[0] - 1; // stack grows up, exc_sp points to top of stack + volatile machine_uint_t currently_in_except_block = (int)*exc_sp_in_out & 1; // 0 or 1, to detect nested exceptions + mp_exc_stack *volatile exc_sp = (void*)((int)*exc_sp_in_out & ~1); // stack grows up, exc_sp points to top of stack const byte *volatile save_ip = ip; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop) // outer exception handling loop for (;;) { if (nlr_push(&nlr) == 0) { + // If we have exception to inject, now that we finish setting up + // execution context, raise it. This works as if RAISE_VARARGS + // bytecode was executed. + if (inject_exc != MP_OBJ_NULL) { + mp_obj_t t = inject_exc; + inject_exc = MP_OBJ_NULL; + nlr_jump(rt_make_raise_obj(t)); + } // loop to execute byte code for (;;) { dispatch_loop: @@ -434,7 +436,7 @@ unwind_jump: // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH case MP_BC_POP_BLOCK: // we are exiting an exception handler, so pop the last one of the exception-stack - assert(exc_sp >= &exc_stack[0]); + assert(exc_sp >= exc_stack); currently_in_except_block = (exc_sp->val_sp & 1); // restore previous state exc_sp--; // pop back to previous exception handler break; @@ -443,7 +445,7 @@ unwind_jump: case MP_BC_POP_EXCEPT: // TODO need to work out how blocks work etc // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate - assert(exc_sp >= &exc_stack[0]); + assert(exc_sp >= exc_stack); assert(currently_in_except_block); //sp = (mp_obj_t*)(*exc_sp--); //exc_sp--; // discard ip @@ -592,7 +594,7 @@ unwind_return: } nlr_pop(); *sp_in_out = sp; - assert(exc_sp == &exc_stack[0] - 1); + assert(exc_sp == exc_stack - 1); return MP_VM_RETURN_NORMAL; case MP_BC_RAISE_VARARGS: @@ -605,6 +607,7 @@ unwind_return: nlr_pop(); *ip_in_out = ip; *sp_in_out = sp; + *exc_sp_in_out = (void*)((int)exc_sp | currently_in_except_block); return MP_VM_RETURN_YIELD; case MP_BC_IMPORT_NAME: @@ -654,7 +657,7 @@ unwind_return: while (currently_in_except_block) { // nested exception - assert(exc_sp >= &exc_stack[0]); + assert(exc_sp >= exc_stack); // TODO make a proper message for nested exception // at the moment we are just raising the very last exception (the one that caused the nested exception) @@ -664,7 +667,7 @@ unwind_return: exc_sp--; // pop back to previous exception handler } - if (exc_sp >= &exc_stack[0]) { + if (exc_sp >= exc_stack) { // set flag to indicate that we are now handling an exception currently_in_except_block = 1; diff --git a/tests/basics/exceptpoly.py b/tests/basics/exceptpoly.py new file mode 100644 index 0000000000..0e5ac2d1a3 --- /dev/null +++ b/tests/basics/exceptpoly.py @@ -0,0 +1,380 @@ +try: + raise ArithmeticError +except Exception: + print("Caught ArithmeticError via Exception") + +try: + raise ArithmeticError +except ArithmeticError: + print("Caught ArithmeticError") + +try: + raise AssertionError +except Exception: + print("Caught AssertionError via Exception") + +try: + raise AssertionError +except AssertionError: + print("Caught AssertionError") + +try: + raise AttributeError +except Exception: + print("Caught AttributeError via Exception") + +try: + raise AttributeError +except AttributeError: + print("Caught AttributeError") + +try: + raise BufferError +except Exception: + print("Caught BufferError via Exception") + +try: + raise BufferError +except BufferError: + print("Caught BufferError") + +try: + raise BytesWarning +except Warning: + print("Caught BytesWarning via Warning") + +try: + raise BytesWarning +except BytesWarning: + print("Caught BytesWarning") + +try: + raise DeprecationWarning +except Warning: + print("Caught DeprecationWarning via Warning") + +try: + raise DeprecationWarning +except DeprecationWarning: + print("Caught DeprecationWarning") + +try: + raise EOFError +except Exception: + print("Caught EOFError via Exception") + +try: + raise EOFError +except EOFError: + print("Caught EOFError") + +try: + raise EnvironmentError +except Exception: + print("Caught EnvironmentError via Exception") + +try: + raise EnvironmentError +except EnvironmentError: + print("Caught EnvironmentError") + +try: + raise Exception +except BaseException: + print("Caught Exception via BaseException") + +try: + raise Exception +except Exception: + print("Caught Exception") + +try: + raise FloatingPointError +except ArithmeticError: + print("Caught FloatingPointError via ArithmeticError") + +try: + raise FloatingPointError +except FloatingPointError: + print("Caught FloatingPointError") + +try: + raise FutureWarning +except Warning: + print("Caught FutureWarning via Warning") + +try: + raise FutureWarning +except FutureWarning: + print("Caught FutureWarning") + +try: + raise IOError +except Exception: + print("Caught IOError via Exception") + +try: + raise IOError +except IOError: + print("Caught IOError") + +try: + raise ImportError +except Exception: + print("Caught ImportError via Exception") + +try: + raise ImportError +except ImportError: + print("Caught ImportError") + +try: + raise ImportWarning +except Warning: + print("Caught ImportWarning via Warning") + +try: + raise ImportWarning +except ImportWarning: + print("Caught ImportWarning") + +try: + raise IndentationError +except SyntaxError: + print("Caught IndentationError via SyntaxError") + +try: + raise IndentationError +except IndentationError: + print("Caught IndentationError") + +try: + raise IndexError +except LookupError: + print("Caught IndexError via LookupError") + +try: + raise IndexError +except IndexError: + print("Caught IndexError") + +try: + raise KeyError +except LookupError: + print("Caught KeyError via LookupError") + +try: + raise KeyError +except KeyError: + print("Caught KeyError") + +try: + raise LookupError +except Exception: + print("Caught LookupError via Exception") + +try: + raise LookupError +except LookupError: + print("Caught LookupError") + +try: + raise MemoryError +except Exception: + print("Caught MemoryError via Exception") + +try: + raise MemoryError +except MemoryError: + print("Caught MemoryError") + +try: + raise NameError +except Exception: + print("Caught NameError via Exception") + +try: + raise NameError +except NameError: + print("Caught NameError") + +try: + raise NotImplementedError +except RuntimeError: + print("Caught NotImplementedError via RuntimeError") + +try: + raise NotImplementedError +except NotImplementedError: + print("Caught NotImplementedError") + +try: + raise OSError +except Exception: + print("Caught OSError via Exception") + +try: + raise OSError +except OSError: + print("Caught OSError") + +try: + raise OverflowError +except ArithmeticError: + print("Caught OverflowError via ArithmeticError") + +try: + raise OverflowError +except OverflowError: + print("Caught OverflowError") + +try: + raise PendingDeprecationWarning +except Warning: + print("Caught PendingDeprecationWarning via Warning") + +try: + raise PendingDeprecationWarning +except PendingDeprecationWarning: + print("Caught PendingDeprecationWarning") + +try: + raise ReferenceError +except Exception: + print("Caught ReferenceError via Exception") + +try: + raise ReferenceError +except ReferenceError: + print("Caught ReferenceError") + +try: + raise ResourceWarning +except Warning: + print("Caught ResourceWarning via Warning") + +try: + raise ResourceWarning +except ResourceWarning: + print("Caught ResourceWarning") + +try: + raise RuntimeError +except Exception: + print("Caught RuntimeError via Exception") + +try: + raise RuntimeError +except RuntimeError: + print("Caught RuntimeError") + +try: + raise RuntimeWarning +except Warning: + print("Caught RuntimeWarning via Warning") + +try: + raise RuntimeWarning +except RuntimeWarning: + print("Caught RuntimeWarning") + +try: + raise SyntaxError +except Exception: + print("Caught SyntaxError via Exception") + +try: + raise SyntaxError +except SyntaxError: + print("Caught SyntaxError") + +try: + raise SyntaxWarning +except Warning: + print("Caught SyntaxWarning via Warning") + +try: + raise SyntaxWarning +except SyntaxWarning: + print("Caught SyntaxWarning") + +try: + raise SystemError +except Exception: + print("Caught SystemError via Exception") + +try: + raise SystemError +except SystemError: + print("Caught SystemError") + +try: + raise TabError +except IndentationError: + print("Caught TabError via IndentationError") + +try: + raise TabError +except TabError: + print("Caught TabError") + +try: + raise TypeError +except Exception: + print("Caught TypeError via Exception") + +try: + raise TypeError +except TypeError: + print("Caught TypeError") + +try: + raise UnboundLocalError +except NameError: + print("Caught UnboundLocalError via NameError") + +try: + raise UnboundLocalError +except UnboundLocalError: + print("Caught UnboundLocalError") + +try: + raise UserWarning +except Warning: + print("Caught UserWarning via Warning") + +try: + raise UserWarning +except UserWarning: + print("Caught UserWarning") + +try: + raise ValueError +except Exception: + print("Caught ValueError via Exception") + +try: + raise ValueError +except ValueError: + print("Caught ValueError") + +try: + raise Warning +except Exception: + print("Caught Warning via Exception") + +try: + raise Warning +except Warning: + print("Caught Warning") + +try: + raise ZeroDivisionError +except ArithmeticError: + print("Caught ZeroDivisionError via ArithmeticError") + +try: + raise ZeroDivisionError +except ZeroDivisionError: + print("Caught ZeroDivisionError") + diff --git a/tests/basics/floordivide.py b/tests/basics/floordivide.py new file mode 100644 index 0000000000..930313d6c1 --- /dev/null +++ b/tests/basics/floordivide.py @@ -0,0 +1,29 @@ +# check modulo matches python definition + +# This tests compiler version +print(123 // 7) +print(-123 // 7) +print(123 // -7) +print(-123 // -7) + +a = 10000001 +b = 10000000 +print(a // b) +print(a // -b) +print(-a // b) +print(-a // -b) + +if True: + a = 987654321987987987987987987987 + b = 19 + + print(a // b) + print(a // -b) + print(-a // b) + print(-a // -b) + a = 10000000000000000000000000000000000000000000 + b = 100 + print(a // b) + print(a // -b) + print(-a // b) + print(-a // -b) diff --git a/tests/basics/generator-exc.py b/tests/basics/generator-exc.py new file mode 100644 index 0000000000..09aca5d9a0 --- /dev/null +++ b/tests/basics/generator-exc.py @@ -0,0 +1,53 @@ +# Test proper handling of exceptions within generator across yield +def gen(): + try: + yield 1 + raise ValueError + except ValueError: + print("Caught") + yield 2 + +for i in gen(): + print(i) + + +# Test throwing exceptions out of generator +def gen2(): + yield 1 + raise ValueError + yield 2 + yield 3 + +g = gen2() +print(next(g)) +try: + print(next(g)) +except ValueError: + print("ValueError") + +try: + print(next(g)) +except StopIteration: + print("StopIteration") + + +# Test throwing exception into generator +def gen3(): + yield 1 + try: + yield 2 + except ValueError: + print("ValueError received") + yield 3 + yield 4 + yield 5 + +g = gen3() +print(next(g)) +print(next(g)) +print("out of throw:", g.throw(ValueError)) +print(next(g)) +try: + print("out of throw2:", g.throw(ValueError)) +except ValueError: + print("Boomerang ValueError caught") diff --git a/tests/basics/math-fun-bool.py b/tests/basics/math-fun-bool.py new file mode 100644 index 0000000000..cf718d4b80 --- /dev/null +++ b/tests/basics/math-fun-bool.py @@ -0,0 +1,12 @@ +# Test the bool functions from math + +from math import isfinite, isnan, isinf + +test_values = [1, 0, -1, 1.0, 0.0, -1.0, float('NaN'), float('Inf'), + -float('NaN'), -float('Inf')] + +functions = [isfinite, isnan, isinf] + +for val in test_values: + for f in functions: + print(f(val)) diff --git a/tests/basics/math-fun.py b/tests/basics/math-fun.py index f5ffbf40d5..1301dc2a5b 100644 --- a/tests/basics/math-fun.py +++ b/tests/basics/math-fun.py @@ -5,8 +5,6 @@ from math import * test_values = [-100., -1.23456, -1, -0.5, 0.0, 0.5, 1.23456, 100.] p_test_values = [0.1, 0.5, 1.23456] unit_range_test_values = [-1., -0.75, -0.5, -0.25, 0., 0.25, 0.5, 0.75, 1.] -#IEEE_test_values = [1, 0, float('NaN'), float('Inf'), -float('NaN'), -float('Inf')] -#TODO: float('NaN') functions = [(sqrt, p_test_values), (exp, test_values), @@ -30,7 +28,6 @@ functions = [(sqrt, p_test_values), (fabs, test_values), (floor, test_values), #(frexp, test_values), - #(isfinite, [1, 0, float('NaN'), float('Inf')]) (trunc, test_values) ] @@ -42,8 +39,8 @@ binary_functions = [(copysign, [(23., 42.), (-23., 42.), (23., -42.), (-23., -42.), (1., 0.0), (1., -0.0)]) ] -#for function, test_vals in binary_functions: -# for value1, value2 in test_vals: -# print("{:8.7f}".format(function(value1, value2))) +for function, test_vals in binary_functions: + for value1, value2 in test_vals: + print("{:8.7f}".format(function(value1, value2))) diff --git a/tests/basics/modulo.py b/tests/basics/modulo.py new file mode 100644 index 0000000000..4d83db6ec8 --- /dev/null +++ b/tests/basics/modulo.py @@ -0,0 +1,36 @@ +# check modulo matches python definition +# This test compiler version +print(123 % 7) +print(-123 % 7) +print(123 % -7) +print(-123 % -7) + +a = 321 +b = 19 +print(a % b) +print(a % -b) +print(-a % b) +print(-a % -b) + + +a = 987654321987987987987987987987 +b = 19 + +print(a % b) +print(a % -b) +print(-a % b) +print(-a % -b) + +if False: + print(1.23456 % 0.7) + print(-1.23456 % 0.7) + print(1.23456 % -0.7) + print(-1.23456 % -0.7) + + a = 1.23456 + b = 0.7 + print(a % b) + print(a % -b) + print(-a % b) + print(-a % -b) +