summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--py/builtin.c8
-rw-r--r--py/compile.c30
-rw-r--r--py/intdivmod.c24
-rw-r--r--py/intdivmod.h4
-rw-r--r--py/malloc.c6
-rw-r--r--py/misc.h1
-rw-r--r--py/obj.c11
-rw-r--r--py/obj.h2
-rw-r--r--py/objbool.c10
-rw-r--r--py/objdict.c22
-rw-r--r--py/objexcept.c3
-rw-r--r--py/objint.c45
-rw-r--r--py/objint.h7
-rw-r--r--py/objint_longlong.c16
-rw-r--r--py/objint_mpz.c22
-rw-r--r--py/objstr.c162
-rw-r--r--py/py.mk2
-rw-r--r--py/runtime.c65
-rw-r--r--py/smallint.c53
-rw-r--r--py/smallint.h5
-rw-r--r--py/vm.c4
-rw-r--r--tests/basics/memoryerror.py6
-rw-r--r--tests/basics/string-format-modulo.py22
-rw-r--r--tests/io/file-with.py9
-rw-r--r--tests/misc/rge-sm.py2
-rwxr-xr-xtests/run-tests5
-rw-r--r--unix/main.c5
27 files changed, 376 insertions, 175 deletions
diff --git a/py/builtin.c b/py/builtin.c
index 67b0e46a66..145bc65b14 100644
--- a/py/builtin.c
+++ b/py/builtin.c
@@ -231,7 +231,7 @@ STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) {
mp_obj_t max_obj = NULL;
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
- if (max_obj == NULL || mp_obj_less(max_obj, item)) {
+ if (max_obj == NULL || mp_binary_op(MP_BINARY_OP_LESS, max_obj, item)) {
max_obj = item;
}
}
@@ -243,7 +243,7 @@ STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) {
// given many args
mp_obj_t max_obj = args[0];
for (int i = 1; i < n_args; i++) {
- if (mp_obj_less(max_obj, args[i])) {
+ if (mp_binary_op(MP_BINARY_OP_LESS, max_obj, args[i])) {
max_obj = args[i];
}
}
@@ -260,7 +260,7 @@ STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) {
mp_obj_t min_obj = NULL;
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
- if (min_obj == NULL || mp_obj_less(item, min_obj)) {
+ if (min_obj == NULL || mp_binary_op(MP_BINARY_OP_LESS, item, min_obj)) {
min_obj = item;
}
}
@@ -272,7 +272,7 @@ STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) {
// given many args
mp_obj_t min_obj = args[0];
for (int i = 1; i < n_args; i++) {
- if (mp_obj_less(args[i], min_obj)) {
+ if (mp_binary_op(MP_BINARY_OP_LESS, args[i], min_obj)) {
min_obj = args[i];
}
}
diff --git a/py/compile.c b/py/compile.c
index 3273abe40e..6ede842397 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -17,7 +17,7 @@
#include "obj.h"
#include "compile.h"
#include "runtime.h"
-#include "intdivmod.h"
+#include "smallint.h"
// TODO need to mangle __attr names
@@ -115,38 +115,38 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
- machine_int_t res;
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
- res = arg0 + arg1;
+ arg0 += arg1;
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_MINUS)) {
- res = arg0 - arg1;
+ arg0 -= arg1;
} else {
// shouldn't happen
assert(0);
- res = 0;
}
- if (MP_PARSE_FITS_SMALL_INT(res)) {
- pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, res);
+ if (MP_PARSE_FITS_SMALL_INT(arg0)) {
+ pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
}
}
break;
case PN_term:
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
- int arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
- int arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
+ machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
+ machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
-#if MICROPY_EMIT_CPYTHON
- // can overflow; enabled only to compare with CPython
- pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 * arg1);
-#endif
+ if (!mp_small_int_mul_overflow(arg0, arg1)) {
+ arg0 *= arg1;
+ if (MP_PARSE_FITS_SMALL_INT(arg0)) {
+ pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
+ }
+ }
} 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)) {
- 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, mp_small_int_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));
+ pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_floor_divide(arg0, arg1));
}
} else {
// shouldn't happen
diff --git a/py/intdivmod.c b/py/intdivmod.c
deleted file mode 100644
index 4cb363b511..0000000000
--- a/py/intdivmod.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "mpconfig.h"
-
-machine_int_t python_modulo(machine_int_t dividend, machine_int_t divisor) {
- machine_int_t lsign = (dividend >= 0) ? 1 :-1;
- machine_int_t rsign = (divisor >= 0) ? 1 :-1;
- dividend %= divisor;
- if (lsign != rsign) {
- dividend += divisor;
- }
- return dividend;
-}
-
-
-machine_int_t python_floor_divide(machine_int_t num, machine_int_t denom) {
- machine_int_t lsign = num > 0 ? 1 : -1;
- machine_int_t rsign = denom > 0 ? 1 : -1;
- if (lsign == -1) {num *= -1;}
- if (rsign == -1) {denom *= -1;}
- if (lsign != rsign){
- return - ( num + denom - 1) / denom;
- } else {
- return num / denom;
- }
-}
diff --git a/py/intdivmod.h b/py/intdivmod.h
deleted file mode 100644
index 7716bd21e9..0000000000
--- a/py/intdivmod.h
+++ /dev/null
@@ -1,4 +0,0 @@
-// Functions for integer modulo and floor division
-
-machine_int_t python_modulo(machine_int_t dividend, machine_int_t divisor);
-machine_int_t python_floor_divide(machine_int_t num, machine_int_t denom);
diff --git a/py/malloc.c b/py/malloc.c
index 27eaac1088..4cf1b71db0 100644
--- a/py/malloc.c
+++ b/py/malloc.c
@@ -41,8 +41,7 @@ void *m_malloc(int num_bytes) {
}
void *ptr = malloc(num_bytes);
if (ptr == NULL) {
- printf("could not allocate memory, allocating %d bytes\n", num_bytes);
- return NULL;
+ return m_malloc_fail(num_bytes);
}
#if MICROPY_MEM_STATS
total_bytes_allocated += num_bytes;
@@ -68,8 +67,7 @@ void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes) {
}
void *new_ptr = realloc(ptr, new_num_bytes);
if (new_ptr == NULL) {
- printf("could not allocate memory, reallocating %d bytes\n", new_num_bytes);
- return NULL;
+ return m_malloc_fail(new_num_bytes);
}
#if MICROPY_MEM_STATS
// At first thought, "Total bytes allocated" should only grow,
diff --git a/py/misc.h b/py/misc.h
index 35081f18e9..662513eb1a 100644
--- a/py/misc.h
+++ b/py/misc.h
@@ -36,6 +36,7 @@ void *m_malloc(int num_bytes);
void *m_malloc0(int num_bytes);
void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes);
void m_free(void *ptr, int num_bytes);
+void *m_malloc_fail(int num_bytes);
int m_get_total_bytes_allocated(void);
int m_get_current_bytes_allocated(void);
diff --git a/py/obj.c b/py/obj.c
index bf3e1d50e1..e177782a8b 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -178,17 +178,6 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
}
}
-bool mp_obj_less(mp_obj_t o1, mp_obj_t o2) {
- if (MP_OBJ_IS_SMALL_INT(o1) && MP_OBJ_IS_SMALL_INT(o2)) {
- mp_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1);
- mp_small_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2);
- return i1 < i2;
- } else {
- assert(0);
- return false;
- }
-}
-
machine_int_t mp_obj_get_int(mp_obj_t arg) {
if (arg == mp_const_false) {
return 0;
diff --git a/py/obj.h b/py/obj.h
index f5ce873d6b..82b7bdadd8 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -306,6 +306,7 @@ extern const struct _mp_obj_bool_t mp_const_false_obj;
extern const struct _mp_obj_bool_t mp_const_true_obj;
extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj;
extern const struct _mp_obj_ellipsis_t mp_const_ellipsis_obj;
+extern const struct _mp_obj_exception_t mp_const_MemoryError_obj;
extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj;
// General API for objects
@@ -356,7 +357,6 @@ int mp_obj_is_true(mp_obj_t arg);
bool mp_obj_is_callable(mp_obj_t o_in);
machine_int_t mp_obj_hash(mp_obj_t o_in);
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);
-bool mp_obj_less(mp_obj_t o1, mp_obj_t o2);
machine_int_t mp_obj_get_int(mp_obj_t arg);
bool mp_obj_get_int_maybe(mp_obj_t arg, machine_int_t *value);
diff --git a/py/objbool.c b/py/objbool.c
index 6afb6e950d..84aa5a781a 100644
--- a/py/objbool.c
+++ b/py/objbool.c
@@ -1,3 +1,4 @@
+#include <stdlib.h>
#include "nlr.h"
#include "misc.h"
@@ -43,12 +44,21 @@ STATIC mp_obj_t bool_unary_op(int op, mp_obj_t o_in) {
}
}
+STATIC mp_obj_t bool_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ if (MP_BINARY_OP_OR <= op && op <= MP_BINARY_OP_NOT_EQUAL) {
+ return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_is_true(lhs_in)), rhs_in);
+ }
+ // operation not supported
+ return MP_OBJ_NULL;
+}
+
const mp_obj_type_t mp_type_bool = {
{ &mp_type_type },
.name = MP_QSTR_bool,
.print = bool_print,
.make_new = bool_make_new,
.unary_op = bool_unary_op,
+ .binary_op = bool_binary_op,
};
const mp_obj_bool_t mp_const_false_obj = {{&mp_type_bool}, false};
diff --git a/py/objdict.c b/py/objdict.c
index afd1d0da0f..ad8c137489 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -32,8 +32,26 @@ STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env
}
STATIC mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
- // TODO create from an iterable!
- return mp_obj_new_dict(0);
+ mp_obj_t dict;
+ switch (n_args) {
+ case 0:
+ dict = mp_obj_new_dict(0);
+ break;
+
+ case 1:
+ // TODO create dict from an iterable!
+ assert(false);
+
+ default:
+ nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "dict takes at most 1 argument"));
+ }
+
+ // add to the new dict any keyword args
+ for (const mp_obj_t *a = args + n_args; n_kw > 0; n_kw--, a += 2) {
+ mp_obj_dict_store(dict, a[0], a[1]);
+ }
+
+ return dict;
}
STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) {
diff --git a/py/objexcept.c b/py/objexcept.c
index 0efc21d360..11651025f0 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -17,6 +17,9 @@ typedef struct _mp_obj_exception_t {
mp_obj_tuple_t args;
} mp_obj_exception_t;
+// Instance of MemoryError exception - needed by mp_malloc_fail
+const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, MP_OBJ_NULL, {{&mp_type_tuple}, 0}};
+
// 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.
diff --git a/py/objint.c b/py/objint.c
index 3a853eab80..1ea6a4f647 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -17,9 +17,8 @@
#include <math.h>
#endif
-// This dispatcher function is expected to be independent of the implementation
-// of long int
-STATIC mp_obj_t int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+// This dispatcher function is expected to be independent of the implementation of long int
+STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
// TODO check n_kw == 0
switch (n_args) {
@@ -56,26 +55,20 @@ STATIC mp_obj_t int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
-void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
print(env, INT_FMT, MP_OBJ_SMALL_INT_VALUE(self_in));
}
}
// This is called for operations on SMALL_INT that are not handled by mp_unary_op
-mp_obj_t int_unary_op(int op, mp_obj_t o_in) {
+mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
return MP_OBJ_NULL;
}
// This is called for operations on SMALL_INT that are not handled by mp_binary_op
-mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
- if (op == MP_BINARY_OP_MULTIPLY) {
- if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
- // multiply is commutative for these types, so delegate to them
- return mp_binary_op(op, rhs_in, lhs_in);
- }
- }
- return MP_OBJ_NULL;
+mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
}
// This is called only with strings whose value doesn't fit in SMALL_INT
@@ -124,11 +117,29 @@ mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
+// This dispatcher function is expected to be independent of the implementation of long int
+// It handles the extra cases for integer-like arithmetic
+mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ if (rhs_in == mp_const_false) {
+ // false acts as 0
+ return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(0));
+ } else if (rhs_in == mp_const_true) {
+ // true acts as 0
+ return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));
+ } else if (op == MP_BINARY_OP_MULTIPLY) {
+ if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
+ // multiply is commutative for these types, so delegate to them
+ return mp_binary_op(op, rhs_in, lhs_in);
+ }
+ }
+ return MP_OBJ_NULL;
+}
+
const mp_obj_type_t mp_type_int = {
{ &mp_type_type },
.name = MP_QSTR_int,
- .print = int_print,
- .make_new = int_make_new,
- .unary_op = int_unary_op,
- .binary_op = int_binary_op,
+ .print = mp_obj_int_print,
+ .make_new = mp_obj_int_make_new,
+ .unary_op = mp_obj_int_unary_op,
+ .binary_op = mp_obj_int_binary_op,
};
diff --git a/py/objint.h b/py/objint.h
index 53ee49e7db..fe7f60a2d4 100644
--- a/py/objint.h
+++ b/py/objint.h
@@ -7,6 +7,7 @@ typedef struct _mp_obj_int_t {
#endif
} mp_obj_int_t;
-void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
-mp_obj_t int_unary_op(int op, mp_obj_t o_in);
-mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
+void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
+mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in);
+mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
+mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
diff --git a/py/objint_longlong.c b/py/objint_longlong.c
index acbd477a9a..f4a65ce1d4 100644
--- a/py/objint_longlong.c
+++ b/py/objint_longlong.c
@@ -21,7 +21,7 @@
#define SUFFIX ""
#endif
-void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
print(env, INT_FMT, MP_OBJ_SMALL_INT_VALUE(self_in));
} else {
@@ -30,7 +30,7 @@ void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj
}
}
-mp_obj_t int_unary_op(int op, mp_obj_t o_in) {
+mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
mp_obj_int_t *o = o_in;
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(o->val != 0);
@@ -41,7 +41,7 @@ mp_obj_t int_unary_op(int op, mp_obj_t o_in) {
}
}
-mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
long long lhs_val;
long long rhs_val;
@@ -58,14 +58,8 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
} else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) {
rhs_val = ((mp_obj_int_t*)rhs_in)->val;
} else {
- if (op == MP_BINARY_OP_MULTIPLY) {
- if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
- // multiply is commutative for these types, so delegate to them
- return mp_binary_op(op, rhs_in, lhs_in);
- }
- }
- // unsupported operation/type
- return MP_OBJ_NULL;
+ // delegate to generic function to check for extra cases
+ return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
}
switch (op) {
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index 25a069cf93..f4504415d6 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -22,7 +22,7 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
return o;
}
-void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
print(env, INT_FMT, MP_OBJ_SMALL_INT_VALUE(self_in));
} else {
@@ -34,7 +34,7 @@ void int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj
}
}
-mp_obj_t int_unary_op(int op, mp_obj_t o_in) {
+mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
mp_obj_int_t *o = o_in;
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(!mpz_is_zero(&o->mpz));
@@ -45,7 +45,7 @@ mp_obj_t int_unary_op(int op, mp_obj_t o_in) {
}
}
-mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
const mpz_t *zlhs;
const mpz_t *zrhs;
mpz_t z_int;
@@ -75,14 +75,8 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in);
#endif
} else {
- if (op == MP_BINARY_OP_MULTIPLY) {
- if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
- // multiply is commutative for these types, so delegate to them
- return mp_binary_op(op, rhs_in, lhs_in);
- }
- }
- // unsupported operation/type
- return MP_OBJ_NULL;
+ // delegate to generic function to check for extra cases
+ return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
}
if (0) {
@@ -113,7 +107,7 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
case MP_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 (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);
@@ -127,8 +121,8 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
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) {
+ // 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/objstr.c b/py/objstr.c
index a3f2d6075d..74f993a0b1 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -894,32 +894,162 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
assert(MP_OBJ_IS_STR(pattern));
GET_STR_DATA_LEN(pattern, str, len);
+ const byte *start_str = str;
int arg_i = 0;
vstr_t *vstr = vstr_new();
+ pfenv_t pfenv_vstr;
+ pfenv_vstr.data = vstr;
+ pfenv_vstr.print_strn = pfenv_vstr_add_strn;
+
for (const byte *top = str + len; str < top; str++) {
+ if (*str != '%') {
+ vstr_add_char(vstr, *str);
+ continue;
+ }
+ if (++str >= top) {
+ break;
+ }
if (*str == '%') {
- if (++str >= top) {
- break;
- }
- if (*str == '%') {
- vstr_add_char(vstr, '%');
+ vstr_add_char(vstr, '%');
+ continue;
+ }
+ if (arg_i >= n_args) {
+ nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string"));
+ }
+ int flags = 0;
+ char fill = ' ';
+ bool alt = false;
+ while (str < top) {
+ if (*str == '-') flags |= PF_FLAG_LEFT_ADJUST;
+ else if (*str == '+') flags |= PF_FLAG_SHOW_SIGN;
+ else if (*str == ' ') flags |= PF_FLAG_SPACE_SIGN;
+ else if (*str == '#') alt = true;
+ else if (*str == '0') {
+ flags |= PF_FLAG_PAD_AFTER_SIGN;
+ fill = '0';
+ } else break;
+ str++;
+ }
+ // parse width, if it exists
+ int width = 0;
+ if (str < top) {
+ if (*str == '*') {
+ width = mp_obj_get_int(args[arg_i++]);
+ str++;
} else {
- if (arg_i >= n_args) {
- nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string"));
+ for (; str < top && '0' <= *str && *str <= '9'; str++) {
+ width = width * 10 + *str - '0';
}
- switch (*str) {
- case 's':
- mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[arg_i], PRINT_STR);
- break;
- case 'r':
- mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[arg_i], PRINT_REPR);
+ }
+ }
+ int prec = -1;
+ if (str < top && *str == '.') {
+ if (++str < top) {
+ if (*str == '*') {
+ prec = mp_obj_get_int(args[arg_i++]);
+ str++;
+ } else {
+ prec = 0;
+ for (; str < top && '0' <= *str && *str <= '9'; str++) {
+ prec = prec * 10 + *str - '0';
+ }
+ }
+ }
+ }
+
+ if (str >= top) {
+ nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "incomplete format"));
+ }
+ mp_obj_t arg = args[arg_i];
+ switch (*str) {
+ case 'c':
+ if (MP_OBJ_IS_STR(arg)) {
+ uint len;
+ const char *s = mp_obj_str_get_data(arg, &len);
+ if (len != 1) {
+ nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "%c requires int or char"));
break;
+ }
+ pfenv_print_strn(&pfenv_vstr, s, 1, flags, ' ', width);
+ break;
+ }
+ if (arg_looks_integer(arg)) {
+ char ch = mp_obj_get_int(arg);
+ pfenv_print_strn(&pfenv_vstr, &ch, 1, flags, ' ', width);
+ break;
+ }
+#if MICROPY_ENABLE_FLOAT
+ // This is what CPython reports, so we report the same.
+ if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
+ nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "integer argument expected, got float"));
+
+ }
+#endif
+ nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "an integer is required"));
+ break;
+
+ case 'd':
+ case 'i':
+ case 'u':
+ pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 10, 'a', flags, fill, width);
+ break;
+
+#if MICROPY_ENABLE_FLOAT
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), *str, flags, fill, width, prec);
+ break;
+#endif
+
+ case 'o':
+ if (alt) {
+ flags |= PF_FLAG_SHOW_PREFIX;
+ }
+ pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 8, 'a', flags, fill, width);
+ break;
+
+ case 'r':
+ case 's':
+ {
+ vstr_t *arg_vstr = vstr_new();
+ mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf,
+ arg_vstr, arg, *str == 'r' ? PRINT_REPR : PRINT_STR);
+ uint len = vstr_len(arg_vstr);
+ if (prec < 0) {
+ prec = len;
+ }
+ if (len > prec) {
+ len = prec;
}
- arg_i++;
+ pfenv_print_strn(&pfenv_vstr, vstr_str(arg_vstr), len, flags, ' ', width);
+ vstr_free(arg_vstr);
+ break;
}
- } else {
- vstr_add_char(vstr, *str);
+
+ case 'x':
+ if (alt) {
+ flags |= PF_FLAG_SHOW_PREFIX;
+ }
+ pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 16, 'a', flags, fill, width);
+ break;
+
+ case 'X':
+ if (alt) {
+ flags |= PF_FLAG_SHOW_PREFIX;
+ }
+ pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 16, 'A', flags, fill, width);
+ break;
+
+ default:
+ nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "unsupported format character '%c' (0x%x) at index %d",
+ *str, *str, str - start_str));
}
+ arg_i++;
}
if (arg_i != n_args) {
diff --git a/py/py.mk b/py/py.mk
index 6a331fedcb..08cfc189ad 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -84,7 +84,7 @@ PY_O_BASENAME = \
vm.o \
showbc.o \
repl.o \
- intdivmod.o \
+ smallint.o \
pfenv.o \
# prepend the build destination prefix to the py object files
diff --git a/py/runtime.c b/py/runtime.c
index d9e2298c4c..a5f45a2fb4 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -16,7 +16,7 @@
#include "builtin.h"
#include "builtintables.h"
#include "bc.h"
-#include "intdivmod.h"
+#include "smallint.h"
#include "objgenerator.h"
#if 0 // print debugging info
@@ -289,7 +289,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
// If long long type exists and is larger than machine_int_t, then
// we can use the following code to perform overflow-checked multiplication.
- // Otherwise (eg in x64 case) we must use the branching code below.
+ // Otherwise (eg in x64 case) we must use mp_small_int_mul_overflow.
#if 0
// compute result using long long precision
long long res = (long long)lhs_val * (long long)rhs_val;
@@ -302,36 +302,14 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
}
#endif
- if (lhs_val > 0) { // lhs_val is positive
- if (rhs_val > 0) { // lhs_val and rhs_val are positive
- if (lhs_val > (MP_SMALL_INT_MAX / rhs_val)) {
- goto mul_overflow;
- }
- } else { // lhs_val positive, rhs_val nonpositive
- if (rhs_val < (MP_SMALL_INT_MIN / lhs_val)) {
- goto mul_overflow;
- }
- } // lhs_val positive, rhs_val nonpositive
- } else { // lhs_val is nonpositive
- if (rhs_val > 0) { // lhs_val is nonpositive, rhs_val is positive
- if (lhs_val < (MP_SMALL_INT_MIN / rhs_val)) {
- goto mul_overflow;
- }
- } else { // lhs_val and rhs_val are nonpositive
- if (lhs_val != 0 && rhs_val < (MP_SMALL_INT_MAX / lhs_val)) {
- goto mul_overflow;
- }
- } // End if lhs_val and rhs_val are nonpositive
- } // End if lhs_val is nonpositive
-
- // use standard precision
- return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val);
-
- mul_overflow:
- // use higher precision
- lhs = mp_obj_new_int_from_ll(lhs_val);
- goto generic_binary_op;
-
+ if (mp_small_int_mul_overflow(lhs_val, rhs_val)) {
+ // use higher precision
+ lhs = mp_obj_new_int_from_ll(lhs_val);
+ goto generic_binary_op;
+ } else {
+ // use standard precision
+ return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val);
+ }
break;
}
case MP_BINARY_OP_FLOOR_DIVIDE:
@@ -339,7 +317,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
if (rhs_val == 0) {
goto zero_division;
}
- lhs_val = python_floor_divide(lhs_val, rhs_val);
+ lhs_val = mp_small_int_floor_divide(lhs_val, rhs_val);
break;
#if MICROPY_ENABLE_FLOAT
@@ -352,11 +330,11 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
#endif
case MP_BINARY_OP_MODULO:
- case MP_BINARY_OP_INPLACE_MODULO:
- {
- lhs_val = python_modulo(lhs_val, rhs_val);
+ case MP_BINARY_OP_INPLACE_MODULO: {
+ lhs_val = mp_small_int_modulo(lhs_val, rhs_val);
break;
}
+
case MP_BINARY_OP_POWER:
case MP_BINARY_OP_INPLACE_POWER:
if (rhs_val < 0) {
@@ -370,21 +348,19 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
machine_int_t ans = 1;
while (rhs_val > 0) {
if (rhs_val & 1) {
- machine_int_t old = ans;
- ans *= lhs_val;
- if (ans < old) {
+ if (mp_small_int_mul_overflow(ans, lhs_val)) {
goto power_overflow;
}
+ ans *= lhs_val;
}
if (rhs_val == 1) {
break;
}
rhs_val /= 2;
- machine_int_t old = lhs_val;
- lhs_val *= lhs_val;
- if (lhs_val < old) {
+ if (mp_small_int_mul_overflow(lhs_val, lhs_val)) {
goto power_overflow;
}
+ lhs_val *= lhs_val;
}
lhs_val = ans;
}
@@ -1034,6 +1010,11 @@ void mp_globals_set(mp_map_t *m) {
map_globals = m;
}
+void *m_malloc_fail(int num_bytes) {
+ DEBUG_printf("memory allocation failed, allocating %d bytes\n", num_bytes);
+ nlr_jump((mp_obj_t)&mp_const_MemoryError_obj);
+}
+
// these must correspond to the respective enum
void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_load_const_dec,
diff --git a/py/smallint.c b/py/smallint.c
new file mode 100644
index 0000000000..ac0cf2f5f9
--- /dev/null
+++ b/py/smallint.c
@@ -0,0 +1,53 @@
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+
+bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y) {
+ // Check for multiply overflow; see CERT INT32-C
+ if (x > 0) { // x is positive
+ if (y > 0) { // x and y are positive
+ if (x > (MP_SMALL_INT_MAX / y)) {
+ return true;
+ }
+ } else { // x positive, y nonpositive
+ if (y < (MP_SMALL_INT_MIN / x)) {
+ return true;
+ }
+ } // x positive, y nonpositive
+ } else { // x is nonpositive
+ if (y > 0) { // x is nonpositive, y is positive
+ if (x < (MP_SMALL_INT_MIN / y)) {
+ return true;
+ }
+ } else { // x and y are nonpositive
+ if (x != 0 && y < (MP_SMALL_INT_MAX / x)) {
+ return true;
+ }
+ } // End if x and y are nonpositive
+ } // End if x is nonpositive
+ return false;
+}
+
+machine_int_t mp_small_int_modulo(machine_int_t dividend, machine_int_t divisor) {
+ machine_int_t lsign = (dividend >= 0) ? 1 :-1;
+ machine_int_t rsign = (divisor >= 0) ? 1 :-1;
+ dividend %= divisor;
+ if (lsign != rsign) {
+ dividend += divisor;
+ }
+ return dividend;
+}
+
+
+machine_int_t mp_small_int_floor_divide(machine_int_t num, machine_int_t denom) {
+ machine_int_t lsign = num > 0 ? 1 : -1;
+ machine_int_t rsign = denom > 0 ? 1 : -1;
+ if (lsign == -1) {num *= -1;}
+ if (rsign == -1) {denom *= -1;}
+ if (lsign != rsign){
+ return - ( num + denom - 1) / denom;
+ } else {
+ return num / denom;
+ }
+}
diff --git a/py/smallint.h b/py/smallint.h
new file mode 100644
index 0000000000..14234fa7b8
--- /dev/null
+++ b/py/smallint.h
@@ -0,0 +1,5 @@
+// Functions for small integer arithmetic
+
+bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y);
+machine_int_t mp_small_int_modulo(machine_int_t dividend, machine_int_t divisor);
+machine_int_t mp_small_int_floor_divide(machine_int_t num, machine_int_t denom);
diff --git a/py/vm.c b/py/vm.c
index 69f350f9fd..6186bbcefb 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -849,8 +849,8 @@ yield:
// set file and line number that the exception occurred at
// TODO: don't set traceback for exceptions re-raised by END_FINALLY.
// But consider how to handle nested exceptions.
- // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj)
- if (mp_obj_is_exception_instance(nlr.ret_val) && nlr.ret_val != &mp_const_GeneratorExit_obj) {
+ // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj)
+ if (mp_obj_is_exception_instance(nlr.ret_val) && nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) {
machine_uint_t code_info_size = code_info[0] | (code_info[1] << 8) | (code_info[2] << 16) | (code_info[3] << 24);
qstr source_file = code_info[4] | (code_info[5] << 8) | (code_info[6] << 16) | (code_info[7] << 24);
qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24);
diff --git a/tests/basics/memoryerror.py b/tests/basics/memoryerror.py
new file mode 100644
index 0000000000..b4be420c31
--- /dev/null
+++ b/tests/basics/memoryerror.py
@@ -0,0 +1,6 @@
+l = list(range(10000))
+try:
+ 100000000 * l
+except MemoryError:
+ print('MemoryError')
+print(len(l), l[0], l[-1])
diff --git a/tests/basics/string-format-modulo.py b/tests/basics/string-format-modulo.py
index 0b50c2674a..82cbdddc7e 100644
--- a/tests/basics/string-format-modulo.py
+++ b/tests/basics/string-format-modulo.py
@@ -20,3 +20,25 @@ try:
print("=%s=" % (1, 2))
except TypeError:
print("TypeError")
+
+print("%c" % 48)
+print("%c" % 'a')
+print("%10s" % 'abc')
+print("%-10s" % 'abc')
+print("%d" % 10)
+print("%+d" % 10)
+print("% d" % 10)
+print("%d" % -10)
+print("%x" % 18)
+print("%o" % 18)
+print("%X" % 18)
+print("%#x" % 18)
+print("%#X" % 18)
+print("%#6x" % 18)
+print("%#06x" % 18)
+print("%e" % 1.23456)
+print("%E" % 1.23456)
+print("%f" % 1.23456)
+print("%F" % 1.23456)
+print("%g" % 1.23456)
+print("%G" % 1.23456)
diff --git a/tests/io/file-with.py b/tests/io/file-with.py
index 2350721641..ee1e702422 100644
--- a/tests/io/file-with.py
+++ b/tests/io/file-with.py
@@ -10,3 +10,12 @@ except:
# Note: CPython and us throw different exception trying to read from
# close file.
print("can't read file after with")
+
+
+# Regression test: test that exception in with initialization properly
+# thrown and doesn't crash.
+try:
+ with open('__non_existent', 'r'):
+ pass
+except OSError:
+ print("OSError")
diff --git a/tests/misc/rge-sm.py b/tests/misc/rge-sm.py
index 40c6029b47..1860f7a318 100644
--- a/tests/misc/rge-sm.py
+++ b/tests/misc/rge-sm.py
@@ -111,4 +111,4 @@ def singleTraj(system, trajStart, h=0.02, tend=1.0):
#phaseDiagram(sysSM, (lambda i, j: [0.354, 0.654, 1.278, 0.8 + 0.2 * i, 0.1 + 0.1 * j]), (lambda a: (a[4], a[5])), h=0.1, tend=math.log(10**17))
# initial conditions at M_Z
-singleTraj(sysSM, [0.354, 0.654, 1.278, 0.983, 0.131], h=0.1, tend=math.log(10**17)) # true values
+singleTraj(sysSM, [0.354, 0.654, 1.278, 0.983, 0.131], h=0.5, tend=math.log(10**17)) # true values
diff --git a/tests/run-tests b/tests/run-tests
index 5be8192971..22ddbe58ed 100755
--- a/tests/run-tests
+++ b/tests/run-tests
@@ -5,8 +5,11 @@ import subprocess
import sys
from glob import glob
+# Tests require at least CPython 3.3. If your default python3 executable
+# is of lower version, you can point MICROPY_CPYTHON3 environment var
+# to the correct executable.
if os.name == 'nt':
- CPYTHON3 = 'python3.exe'
+ CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe')
MP_PY = '../windows/micropython.exe'
else:
CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3')
diff --git a/unix/main.c b/unix/main.c
index 228c4746a5..911d908b1a 100644
--- a/unix/main.c
+++ b/unix/main.c
@@ -30,7 +30,8 @@
#if MICROPY_ENABLE_GC
// Heap size of GC heap (if enabled)
-long heap_size = 128*1024;
+// Make it larger on a 64 bit machine, because pointers are larger.
+long heap_size = 128*1024 * (sizeof(machine_uint_t) / 4);
#endif
// Stack top at the start of program
@@ -96,7 +97,7 @@ static void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind
static char *strjoin(const char *s1, int sep_char, const char *s2) {
int l1 = strlen(s1);
int l2 = strlen(s2);
- char *s = m_new(char, l1 + l2 + 2);
+ char *s = malloc(l1 + l2 + 2);
memcpy(s, s1, l1);
if (sep_char != 0) {
s[l1] = sep_char;