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) {
} 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)) {
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);
......
......@@ -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");
}
......
......@@ -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,32 +11,25 @@
#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));
} else if (kind == PRINT_EXC) {
print(env, "%s: ", qstr_str(o->base.type->name));
}
if (kind == PRINT_STR) {
if (kind == PRINT_STR || kind == PRINT_EXC) {
if (o->args.len == 0) {
print(env, "");
return;
......@@ -46,7 +39,6 @@ STATIC void mp_obj_exception_print(void (*print)(void *env, const char *fmt, ...
}
}
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;
......
#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,6 +129,7 @@ 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);
default:
return NULL; // op not supported
}
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) {
}
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:
......
# 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")
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