Commit 1aa2c102 authored by Damien George's avatar Damien George
Browse files

Merge branch 'master' of github.com:micropython/micropython

parents 523b5750 6ded55a6
...@@ -145,7 +145,9 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) { ...@@ -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);
......
...@@ -62,7 +62,7 @@ void mp_obj_print_exception(mp_obj_t exc) { ...@@ -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");
} }
......
...@@ -141,7 +141,9 @@ typedef mp_obj_t (*mp_fun_var_t)(uint n, const mp_obj_t *); ...@@ -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 @@ ...@@ -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) { if (kind == PRINT_STR || kind == PRINT_EXC) {
print(env, "%s", qstr_str(o->base.type->name)); if (o->args.len == 0) {
} print(env, "");
if (kind == PRINT_STR) { return;
if (o->args.len == 0) { } else if (o->args.len == 1) {
print(env, ""); mp_obj_print_helper(print, env, o->args.items[0], PRINT_STR);
return; 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);
} }
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_ ...@@ -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) ...@@ -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 ...@@ -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;
......
#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 ...@@ -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) { ...@@ -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) { ...@@ -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);
} }
......
...@@ -348,13 +348,20 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { ...@@ -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:
......
# 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")
try:
1 / 0
except ZeroDivisionError:
print("ZeroDivisionError")
try:
1 // 0
except ZeroDivisionError:
print("ZeroDivisionError")
Supports Markdown
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