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)) {
|
} 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));
|
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)) {
|
} 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 {
|
} else {
|
||||||
// shouldn't happen
|
// shouldn't happen
|
||||||
assert(0);
|
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");
|
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 mp_obj_t (*mp_fun_kw_t)(uint n, const mp_obj_t *, mp_map_t *);
|
||||||
|
|
||||||
typedef enum {
|
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;
|
} 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);
|
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 "runtime.h"
|
||||||
#include "runtime0.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 {
|
typedef struct _mp_obj_exception_t {
|
||||||
mp_obj_base_t base;
|
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
|
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_tuple_t args;
|
||||||
} mp_obj_exception_t;
|
} mp_obj_exception_t;
|
||||||
|
|
||||||
// Instance of GeneratorExit exception - needed by generator.close()
|
// Instance of GeneratorExit exception - needed by generator.close()
|
||||||
// This would belong to objgenerator.c, but to keep mp_obj_exception_t
|
// This would belong to objgenerator.c, but to keep mp_obj_exception_t
|
||||||
// definition module-private so far, have it here.
|
// 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) {
|
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;
|
mp_obj_exception_t *o = o_in;
|
||||||
if (o->msg != NULL) {
|
if (kind == PRINT_REPR) {
|
||||||
print(env, "%s: %s", qstr_str(o->base.type->name), vstr_str(o->msg));
|
print(env, "%s", qstr_str(o->base.type->name));
|
||||||
} else {
|
} else if (kind == PRINT_EXC) {
|
||||||
// Yes, that's how CPython has it
|
print(env, "%s: ", qstr_str(o->base.type->name));
|
||||||
// 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_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) {
|
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);
|
mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, n_args);
|
||||||
o->base.type = type;
|
o->base.type = type;
|
||||||
o->traceback = MP_OBJ_NULL;
|
o->traceback = MP_OBJ_NULL;
|
||||||
o->msg = NULL;
|
|
||||||
o->args.base.type = &mp_type_tuple;
|
o->args.base.type = &mp_type_tuple;
|
||||||
o->args.len = n_args;
|
o->args.len = n_args;
|
||||||
memcpy(o->args.items, args, n_args * sizeof(mp_obj_t));
|
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) {
|
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) {
|
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);
|
assert(exc_type->make_new == mp_obj_exception_make_new);
|
||||||
|
|
||||||
// make exception object
|
// 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->base.type = exc_type;
|
||||||
o->traceback = MP_OBJ_NULL;
|
o->traceback = MP_OBJ_NULL;
|
||||||
o->args.base.type = &mp_type_tuple;
|
o->args.base.type = &mp_type_tuple;
|
||||||
o->args.len = 0;
|
o->args.len = 1;
|
||||||
|
|
||||||
if (fmt == NULL) {
|
if (fmt == NULL) {
|
||||||
// no message
|
// no message
|
||||||
o->msg = NULL;
|
assert(0);
|
||||||
} else {
|
} else {
|
||||||
// render exception message
|
// render exception message and store as .args[0]
|
||||||
o->msg = vstr_new();
|
// TODO: optimize bufferbloat
|
||||||
|
vstr_t *vstr = vstr_new();
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vstr_vprintf(o->msg, fmt, ap);
|
vstr_vprintf(vstr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
o->args.items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
|
||||||
|
vstr_free(vstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.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');
|
format_float(o->value, buf, sizeof(buf), 'g', 6, '\0');
|
||||||
print(env, "%s", buf);
|
print(env, "%s", buf);
|
||||||
#else
|
#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
|
#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_INPLACE_SUBTRACT: lhs_val -= rhs_val; break;
|
||||||
case MP_BINARY_OP_MULTIPLY:
|
case MP_BINARY_OP_MULTIPLY:
|
||||||
case MP_BINARY_OP_INPLACE_MULTIPLY: lhs_val *= rhs_val; break;
|
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_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_TRUE_DIVIDE:
|
||||||
case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:
|
case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:
|
||||||
lhs_val /= rhs_val;
|
lhs_val /= rhs_val;
|
||||||
|
check_zero_division:
|
||||||
if (isinf(lhs_val)){ // check for division by zero
|
if (isinf(lhs_val)){ // check for division by zero
|
||||||
nlr_jump(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "float 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_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val);
|
||||||
case MP_BINARY_OP_MORE_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);
|
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_FLOOR_DIVIDE:
|
||||||
case MP_BINARY_OP_INPLACE_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);
|
lhs_val = python_floor_divide(lhs_val, rhs_val);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
#if MICROPY_ENABLE_FLOAT
|
#if MICROPY_ENABLE_FLOAT
|
||||||
case MP_BINARY_OP_TRUE_DIVIDE:
|
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
|
#endif
|
||||||
|
|
||||||
case MP_BINARY_OP_MODULO:
|
case MP_BINARY_OP_MODULO:
|
||||||
|
|
|
@ -1,3 +1,16 @@
|
||||||
# basic float
|
# basic float
|
||||||
x = 1 / 2
|
x = 1 / 2
|
||||||
print(x)
|
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")
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
try:
|
||||||
|
1 / 0
|
||||||
|
except ZeroDivisionError:
|
||||||
|
print("ZeroDivisionError")
|
||||||
|
|
||||||
|
try:
|
||||||
|
1 // 0
|
||||||
|
except ZeroDivisionError:
|
||||||
|
print("ZeroDivisionError")
|
Loading…
Reference in New Issue