Merge branch 'master' of github.com:micropython/micropython
This commit is contained in:
commit
1aa2c10263
@ -145,7 +145,9 @@ 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_PERCENT)) {
|
||||
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)) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, python_floor_divide(arg0, arg1));
|
||||
if (arg1 != 0) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, python_floor_divide(arg0, arg1));
|
||||
}
|
||||
} else {
|
||||
// shouldn't happen
|
||||
assert(0);
|
||||
|
2
py/obj.c
2
py/obj.c
@ -62,7 +62,7 @@ void mp_obj_print_exception(mp_obj_t exc) {
|
||||
}
|
||||
}
|
||||
}
|
||||
mp_obj_print(exc, PRINT_REPR);
|
||||
mp_obj_print(exc, PRINT_EXC);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
4
py/obj.h
4
py/obj.h
@ -141,7 +141,9 @@ typedef mp_obj_t (*mp_fun_var_t)(uint n, const mp_obj_t *);
|
||||
typedef mp_obj_t (*mp_fun_kw_t)(uint n, const mp_obj_t *, mp_map_t *);
|
||||
|
||||
typedef enum {
|
||||
PRINT_STR, PRINT_REPR
|
||||
PRINT_STR,
|
||||
PRINT_REPR,
|
||||
PRINT_EXC, // Special format for printing exception in unhandled exception message
|
||||
} mp_print_kind_t;
|
||||
|
||||
typedef void (*mp_print_fun_t)(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o, mp_print_kind_t kind);
|
||||
|
@ -11,42 +11,34 @@
|
||||
#include "runtime.h"
|
||||
#include "runtime0.h"
|
||||
|
||||
// This is unified class for C-level and Python-level exceptions
|
||||
// Python-level exceptions have empty ->msg and all arguments are in
|
||||
// args tuple. C-level exceptions likely have ->msg set, and args is empty.
|
||||
typedef struct _mp_obj_exception_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t traceback; // a list object, holding (file,line,block) as numbers (not Python objects); a hack for now
|
||||
vstr_t *msg;
|
||||
mp_obj_tuple_t args;
|
||||
} mp_obj_exception_t;
|
||||
|
||||
// Instance of GeneratorExit exception - needed by generator.close()
|
||||
// This would belong to objgenerator.c, but to keep mp_obj_exception_t
|
||||
// definition module-private so far, have it here.
|
||||
const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, MP_OBJ_NULL, NULL, {{&mp_type_tuple}, 0}};
|
||||
const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, MP_OBJ_NULL, {{&mp_type_tuple}, 0}};
|
||||
|
||||
STATIC void mp_obj_exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
mp_obj_exception_t *o = o_in;
|
||||
if (o->msg != NULL) {
|
||||
print(env, "%s: %s", qstr_str(o->base.type->name), vstr_str(o->msg));
|
||||
} else {
|
||||
// Yes, that's how CPython has it
|
||||
// TODO now that exceptions are classes and instances, I think this needs to be changed to match CPython
|
||||
if (kind == PRINT_REPR) {
|
||||
print(env, "%s", qstr_str(o->base.type->name));
|
||||
}
|
||||
if (kind == PRINT_STR) {
|
||||
if (o->args.len == 0) {
|
||||
print(env, "");
|
||||
return;
|
||||
} else if (o->args.len == 1) {
|
||||
mp_obj_print_helper(print, env, o->args.items[0], PRINT_STR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
tuple_print(print, env, &o->args, kind);
|
||||
if (kind == PRINT_REPR) {
|
||||
print(env, "%s", qstr_str(o->base.type->name));
|
||||
} else if (kind == PRINT_EXC) {
|
||||
print(env, "%s: ", qstr_str(o->base.type->name));
|
||||
}
|
||||
if (kind == PRINT_STR || kind == PRINT_EXC) {
|
||||
if (o->args.len == 0) {
|
||||
print(env, "");
|
||||
return;
|
||||
} else if (o->args.len == 1) {
|
||||
mp_obj_print_helper(print, env, o->args.items[0], PRINT_STR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
tuple_print(print, env, &o->args, kind);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
|
||||
@ -59,7 +51,6 @@ STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_
|
||||
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, n_args);
|
||||
o->base.type = type;
|
||||
o->traceback = MP_OBJ_NULL;
|
||||
o->msg = NULL;
|
||||
o->args.base.type = &mp_type_tuple;
|
||||
o->args.len = n_args;
|
||||
memcpy(o->args.items, args, n_args * sizeof(mp_obj_t));
|
||||
@ -185,7 +176,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
|
||||
*/
|
||||
|
||||
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) {
|
||||
return mp_obj_new_exception_msg_varg(exc_type, NULL);
|
||||
return mp_obj_new_exception_args(exc_type, 0, NULL);
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args) {
|
||||
@ -202,22 +193,25 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
|
||||
assert(exc_type->make_new == mp_obj_exception_make_new);
|
||||
|
||||
// make exception object
|
||||
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, 0);
|
||||
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, 1);
|
||||
o->base.type = exc_type;
|
||||
o->traceback = MP_OBJ_NULL;
|
||||
o->args.base.type = &mp_type_tuple;
|
||||
o->args.len = 0;
|
||||
o->args.len = 1;
|
||||
|
||||
if (fmt == NULL) {
|
||||
// no message
|
||||
o->msg = NULL;
|
||||
assert(0);
|
||||
} else {
|
||||
// render exception message
|
||||
o->msg = vstr_new();
|
||||
// render exception message and store as .args[0]
|
||||
// TODO: optimize bufferbloat
|
||||
vstr_t *vstr = vstr_new();
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vstr_vprintf(o->msg, fmt, ap);
|
||||
vstr_vprintf(vstr, fmt, ap);
|
||||
va_end(ap);
|
||||
o->args.items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
|
||||
vstr_free(vstr);
|
||||
}
|
||||
|
||||
return o;
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
@ -23,7 +25,13 @@ STATIC void float_print(void (*print)(void *env, const char *fmt, ...), void *en
|
||||
format_float(o->value, buf, sizeof(buf), 'g', 6, '\0');
|
||||
print(env, "%s", buf);
|
||||
#else
|
||||
print(env, "%.8g", (double) o->value);
|
||||
char buf[32];
|
||||
sprintf(buf, "%.8g", (double) o->value);
|
||||
print(env, buf);
|
||||
if (strchr(buf, '.') == NULL) {
|
||||
// Python floats always have decimal point
|
||||
print(env, ".0");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -103,13 +111,15 @@ mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs_in) {
|
||||
case MP_BINARY_OP_INPLACE_SUBTRACT: lhs_val -= rhs_val; break;
|
||||
case MP_BINARY_OP_MULTIPLY:
|
||||
case MP_BINARY_OP_INPLACE_MULTIPLY: lhs_val *= rhs_val; break;
|
||||
/* TODO floor(?) the value
|
||||
// TODO: verify that C floor matches Python semantics
|
||||
case MP_BINARY_OP_FLOOR_DIVIDE:
|
||||
case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: val = lhs_val / rhs_val; break;
|
||||
*/
|
||||
case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:
|
||||
lhs_val = MICROPY_FLOAT_C_FUN(floor)(lhs_val / rhs_val);
|
||||
goto check_zero_division;
|
||||
case MP_BINARY_OP_TRUE_DIVIDE:
|
||||
case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:
|
||||
lhs_val /= rhs_val;
|
||||
check_zero_division:
|
||||
if (isinf(lhs_val)){ // check for division by zero
|
||||
nlr_jump(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "float division by zero"));
|
||||
}
|
||||
@ -119,7 +129,8 @@ mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs_in) {
|
||||
case MP_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val);
|
||||
case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val);
|
||||
|
||||
return NULL; // op not supported
|
||||
default:
|
||||
return NULL; // op not supported
|
||||
}
|
||||
return mp_obj_new_float(lhs_val);
|
||||
}
|
||||
|
13
py/runtime.c
13
py/runtime.c
@ -348,13 +348,20 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
}
|
||||
case MP_BINARY_OP_FLOOR_DIVIDE:
|
||||
case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:
|
||||
{
|
||||
if (rhs_val == 0) {
|
||||
goto zero_division;
|
||||
}
|
||||
lhs_val = python_floor_divide(lhs_val, rhs_val);
|
||||
break;
|
||||
}
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
case MP_BINARY_OP_TRUE_DIVIDE:
|
||||
case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val);
|
||||
case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:
|
||||
if (rhs_val == 0) {
|
||||
zero_division:
|
||||
nlr_jump(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero"));
|
||||
}
|
||||
return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val);
|
||||
#endif
|
||||
|
||||
case MP_BINARY_OP_MODULO:
|
||||
|
@ -1,3 +1,16 @@
|
||||
# basic float
|
||||
x = 1 / 2
|
||||
print(x)
|
||||
|
||||
print(1.0 // 2)
|
||||
print(2.0 // 2)
|
||||
|
||||
try:
|
||||
1.0 / 0
|
||||
except ZeroDivisionError:
|
||||
print("ZeroDivisionError")
|
||||
|
||||
try:
|
||||
1.0 // 0
|
||||
except ZeroDivisionError:
|
||||
print("ZeroDivisionError")
|
||||
|
9
tests/basics/int-divzero.py
Normal file
9
tests/basics/int-divzero.py
Normal file
@ -0,0 +1,9 @@
|
||||
try:
|
||||
1 / 0
|
||||
except ZeroDivisionError:
|
||||
print("ZeroDivisionError")
|
||||
|
||||
try:
|
||||
1 // 0
|
||||
except ZeroDivisionError:
|
||||
print("ZeroDivisionError")
|
Loading…
Reference in New Issue
Block a user