summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--py/asmthumb.c14
-rw-r--r--py/asmthumb.h10
-rw-r--r--py/compile.c247
-rw-r--r--py/emit.h31
-rw-r--r--py/emitbc.c51
-rw-r--r--py/emitcpy.c41
-rw-r--r--py/emitinlinethumb.c2
-rw-r--r--py/emitnative.c39
-rw-r--r--py/emitpass1.c7
-rw-r--r--py/lexer.c107
-rw-r--r--py/lexerunix.c50
-rw-r--r--py/malloc.c34
-rw-r--r--py/misc.h4
-rw-r--r--py/modstruct.c2
-rw-r--r--py/mpconfig.h5
-rw-r--r--py/obj.h4
-rw-r--r--py/objcomplex.c29
-rw-r--r--py/objexcept.c59
-rw-r--r--py/objfloat.c2
-rw-r--r--py/objfun.c10
-rw-r--r--py/parse.c66
-rw-r--r--py/parse.h1
-rw-r--r--py/parsehelper.c8
-rw-r--r--py/runtime.c15
-rw-r--r--py/unicode.c2
-rw-r--r--py/vm.c26
-rw-r--r--stmhal/Makefile3
-rw-r--r--stmhal/modstm.c120
-rw-r--r--stmhal/modstm.h1
-rw-r--r--stmhal/mpconfigport.h7
-rw-r--r--stmhal/qstrdefsport.h16
-rw-r--r--tests/basics/compare-multi.py4
-rw-r--r--tests/basics/fun-defargs2.py6
-rw-r--r--unix/main.c10
34 files changed, 739 insertions, 294 deletions
diff --git a/py/asmthumb.c b/py/asmthumb.c
index f37b1ff8fe..e8c8927a9c 100644
--- a/py/asmthumb.c
+++ b/py/asmthumb.c
@@ -22,7 +22,7 @@ struct _asm_thumb_t {
byte *code_base;
byte dummy_data[8];
- int max_num_labels;
+ uint max_num_labels;
int *label_offsets;
int num_locals;
uint push_reglist;
@@ -212,7 +212,7 @@ void asm_thumb_exit(asm_thumb_t *as) {
asm_thumb_write_op16(as, OP_POP_RLIST_PC(as->push_reglist));
}
-void asm_thumb_label_assign(asm_thumb_t *as, int label) {
+void asm_thumb_label_assign(asm_thumb_t *as, uint label) {
assert(label < as->max_num_labels);
if (as->pass == ASM_THUMB_PASS_2) {
// assign label offset
@@ -225,7 +225,7 @@ void asm_thumb_label_assign(asm_thumb_t *as, int label) {
}
}
-STATIC int get_label_dest(asm_thumb_t *as, int label) {
+STATIC int get_label_dest(asm_thumb_t *as, uint label) {
assert(label < as->max_num_labels);
return as->label_offsets[label];
}
@@ -308,7 +308,7 @@ void asm_thumb_ite_ge(asm_thumb_t *as) {
#define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff))
-void asm_thumb_b_n(asm_thumb_t *as, int label) {
+void asm_thumb_b_n(asm_thumb_t *as, uint label) {
int dest = get_label_dest(as, label);
int rel = dest - as->code_offset;
rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
@@ -321,7 +321,7 @@ void asm_thumb_b_n(asm_thumb_t *as, int label) {
#define OP_BCC_N(cond, byte_offset) (0xd000 | ((cond) << 8) | (((byte_offset) >> 1) & 0x00ff))
-void asm_thumb_bcc_n(asm_thumb_t *as, int cond, int label) {
+void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label) {
int dest = get_label_dest(as, label);
int rel = dest - as->code_offset;
rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
@@ -380,7 +380,7 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num)
#define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff))
#define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff))
-void asm_thumb_b_label(asm_thumb_t *as, int label) {
+void asm_thumb_b_label(asm_thumb_t *as, uint label) {
int dest = get_label_dest(as, label);
int rel = dest - as->code_offset;
rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
@@ -403,7 +403,7 @@ void asm_thumb_b_label(asm_thumb_t *as, int label) {
#define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 14) & 0x003f))
#define OP_BCC_W_LO(byte_offset) (0x8000 | ((byte_offset) & 0x2000) | (((byte_offset) >> 1) & 0x0fff))
-void asm_thumb_bcc_label(asm_thumb_t *as, int cond, int label) {
+void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) {
int dest = get_label_dest(as, label);
int rel = dest - as->code_offset;
rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
diff --git a/py/asmthumb.h b/py/asmthumb.h
index 60a86ea50b..f9226f1eb0 100644
--- a/py/asmthumb.h
+++ b/py/asmthumb.h
@@ -53,7 +53,7 @@ void *asm_thumb_get_code(asm_thumb_t *as);
void asm_thumb_entry(asm_thumb_t *as, int num_locals);
void asm_thumb_exit(asm_thumb_t *as);
-void asm_thumb_label_assign(asm_thumb_t *as, int label);
+void asm_thumb_label_assign(asm_thumb_t *as, uint label);
// argument order follows ARM, in general dest is first
// note there is a difference between movw and mov.w, and many others!
@@ -67,8 +67,8 @@ void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int
void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b);
void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8);
void asm_thumb_ite_ge(asm_thumb_t *as);
-void asm_thumb_b_n(asm_thumb_t *as, int label);
-void asm_thumb_bcc_n(asm_thumb_t *as, int cond, int label);
+void asm_thumb_b_n(asm_thumb_t *as, uint label);
+void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label);
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32_src); // convenience
void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience
@@ -76,7 +76,7 @@ void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src);
void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience
void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience
-void asm_thumb_b_label(asm_thumb_t *as, int label); // convenience ?
-void asm_thumb_bcc_label(asm_thumb_t *as, int cc, int label); // convenience: picks narrow or wide branch
+void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience ?
+void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch
void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp); // convenience ?
diff --git a/py/compile.c b/py/compile.c
index 3ea6dd3a61..4738c0ae55 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -43,10 +43,10 @@ typedef struct _compiler_t {
uint8_t had_error; // try to keep compiler clean from nlr
uint8_t func_arg_is_super; // used to compile special case of super() function call
- int next_label;
+ uint next_label;
- int break_label;
- int continue_label;
+ uint break_label;
+ uint continue_label;
int break_continue_except_level;
uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
@@ -78,6 +78,19 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
comp->had_error = true;
}
+STATIC const mp_map_elem_t mp_constants_table[] = {
+ // Extra constants as defined by a port
+ MICROPY_EXTRA_CONSTANTS
+};
+
+STATIC const mp_map_t mp_constants_map = {
+ .all_keys_are_qstrs = 1,
+ .table_is_fixed_array = 1,
+ .used = sizeof(mp_constants_table) / sizeof(mp_map_elem_t),
+ .alloc = sizeof(mp_constants_table) / sizeof(mp_map_elem_t),
+ .table = (mp_map_elem_t*)mp_constants_table,
+};
+
mp_parse_node_t fold_constants(mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
@@ -168,10 +181,12 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
}
break;
-#if MICROPY_EMIT_CPYTHON
case PN_power:
- // can overflow; enabled only to compare with CPython
- if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_NULL(pns->nodes[1]) && !MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
+ if (0) {
+#if MICROPY_EMIT_CPYTHON
+ } else if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_NULL(pns->nodes[1]) && !MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
+ // int**x
+ // can overflow; enabled only to compare with CPython
mp_parse_node_struct_t* pns2 = (mp_parse_node_struct_t*)pns->nodes[2];
if (MP_PARSE_NODE_IS_SMALL_INT(pns2->nodes[0])) {
int power = MP_PARSE_NODE_LEAF_SMALL_INT(pns2->nodes[0]);
@@ -184,9 +199,27 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ans);
}
}
+#endif
+ } else if (MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_trailer_period) && MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
+ // id.id
+ // look it up in constant table, see if it can be replaced with an integer
+ mp_parse_node_struct_t* pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
+ assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));
+ qstr q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
+ qstr q_attr = MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]);
+ mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&mp_constants_map, MP_OBJ_NEW_QSTR(q_base), MP_MAP_LOOKUP);
+ if (elem != NULL) {
+ mp_obj_t dest[2];
+ mp_load_method_maybe(elem->value, q_attr, dest);
+ if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) {
+ machine_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
+ if (MP_PARSE_FITS_SMALL_INT(val)) {
+ pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
+ }
+ }
+ }
}
break;
-#endif
}
}
@@ -196,7 +229,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn);
-STATIC int comp_next_label(compiler_t *comp) {
+STATIC uint comp_next_label(compiler_t *comp) {
return comp->next_label++;
}
@@ -467,7 +500,7 @@ STATIC void cpython_c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test) {
if (jump_if == false) {
- int label2 = comp_next_label(comp);
+ uint label2 = comp_next_label(comp);
for (int i = 0; i < n - 1; i++) {
cpython_c_if_cond(comp, pns->nodes[i], true, label2, true);
}
@@ -485,7 +518,7 @@ STATIC void cpython_c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if
cpython_c_if_cond(comp, pns->nodes[i], false, label, true);
}
} else {
- int label2 = comp_next_label(comp);
+ uint label2 = comp_next_label(comp);
for (int i = 0; i < n - 1; i++) {
cpython_c_if_cond(comp, pns->nodes[i], false, label2, true);
}
@@ -528,7 +561,7 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test) {
if (jump_if == false) {
- int label2 = comp_next_label(comp);
+ uint label2 = comp_next_label(comp);
for (int i = 0; i < n - 1; i++) {
c_if_cond(comp, pns->nodes[i], true, label2);
}
@@ -546,7 +579,7 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la
c_if_cond(comp, pns->nodes[i], false, label);
}
} else {
- int label2 = comp_next_label(comp);
+ uint label2 = comp_next_label(comp);
for (int i = 0; i < n - 1; i++) {
c_if_cond(comp, pns->nodes[i], false, label2);
}
@@ -1202,7 +1235,7 @@ void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
mp_parse_node_struct_t *pns_test_if_expr = (mp_parse_node_struct_t*)pns->nodes[0];
mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns_test_if_expr->nodes[1];
- int l_fail = comp_next_label(comp);
+ uint l_fail = comp_next_label(comp);
c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition
compile_node(comp, pns_test_if_expr->nodes[0]); // success value
EMIT(return_value);
@@ -1236,31 +1269,35 @@ void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
-// q1 holds the base, q2 the full name
-// eg a -> q1=q2=a
-// a.b.c -> q1=a, q2=a.b.c
-void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q1, qstr *q2) {
+// q_base holds the base of the name
+// eg a -> q_base=a
+// a.b.c -> q_base=a
+void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
bool is_as = false;
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_as_name)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
// a name of the form x as y; unwrap it
- *q1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
+ *q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
pn = pns->nodes[0];
is_as = true;
}
- if (MP_PARSE_NODE_IS_ID(pn)) {
+ if (MP_PARSE_NODE_IS_NULL(pn)) {
+ // empty name (eg, from . import x)
+ *q_base = MP_QSTR_;
+ EMIT_ARG(import_name, MP_QSTR_); // import the empty string
+ } else if (MP_PARSE_NODE_IS_ID(pn)) {
// just a simple name
- *q2 = MP_PARSE_NODE_LEAF_ARG(pn);
+ qstr q_full = MP_PARSE_NODE_LEAF_ARG(pn);
if (!is_as) {
- *q1 = *q2;
+ *q_base = q_full;
}
- EMIT_ARG(import_name, *q2);
+ EMIT_ARG(import_name, q_full);
} else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dotted_name) {
// a name of the form a.b.c
if (!is_as) {
- *q1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
+ *q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
}
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
int len = n - 1;
@@ -1278,33 +1315,29 @@ void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q1, qstr *q2) {
memcpy(str_dest, str_src, str_src_len);
str_dest += str_src_len;
}
- *q2 = qstr_build_end(q_ptr);
- EMIT_ARG(import_name, *q2);
+ qstr q_full = qstr_build_end(q_ptr);
+ EMIT_ARG(import_name, q_full);
if (is_as) {
for (int i = 1; i < n; i++) {
EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
}
}
} else {
- // TODO not implemented
- // This covers relative imports starting with dot(s) like "from .foo import"
- compile_syntax_error(comp, pn, "Relative imports not implemented");
- return;
+ // shouldn't happen
+ assert(0);
}
} else {
- // TODO not implemented
- // This covers relative imports with dots only like "from .. import"
- compile_syntax_error(comp, pn, "Relative imports not implemented");
- return;
+ // shouldn't happen
+ assert(0);
}
}
void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) {
- EMIT_ARG(load_const_small_int, 0); // ??
- EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
- qstr q1, q2;
- do_import_name(comp, pn, &q1, &q2);
- EMIT_ARG(store_id, q1);
+ EMIT_ARG(load_const_small_int, 0); // level 0 import
+ EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // not importing from anything
+ qstr q_base;
+ do_import_name(comp, pn, &q_base);
+ EMIT_ARG(store_id, q_base);
}
void compile_import_name(compiler_t *comp, mp_parse_node_struct_t *pns) {
@@ -1312,8 +1345,44 @@ void compile_import_name(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ mp_parse_node_t pn_import_source = pns->nodes[0];
+
+ // extract the preceeding .'s (if any) for a relative import, to compute the import level
+ uint import_level = 0;
+ do {
+ mp_parse_node_t pn_rel;
+ if (MP_PARSE_NODE_IS_TOKEN(pn_import_source) || MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_one_or_more_period_or_ellipsis)) {
+ // This covers relative imports with dots only like "from .. import"
+ pn_rel = pn_import_source;
+ pn_import_source = MP_PARSE_NODE_NULL;
+ } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_import_from_2b)) {
+ // This covers relative imports starting with dot(s) like "from .foo import"
+ mp_parse_node_struct_t *pns_2b = (mp_parse_node_struct_t*)pn_import_source;
+ pn_rel = pns_2b->nodes[0];
+ pn_import_source = pns_2b->nodes[1];
+ assert(!MP_PARSE_NODE_IS_NULL(pn_import_source)); // should not be
+ } else {
+ // Not a relative import
+ break;
+ }
+
+ // get the list of . and/or ...'s
+ mp_parse_node_t *nodes;
+ int n = list_get(&pn_rel, PN_one_or_more_period_or_ellipsis, &nodes);
+
+ // count the total number of .'s
+ for (int i = 0; i < n; i++) {
+ if (MP_PARSE_NODE_IS_TOKEN_KIND(nodes[i], MP_TOKEN_DEL_PERIOD)) {
+ import_level++;
+ } else {
+ // should be an MP_TOKEN_ELLIPSIS
+ import_level += 3;
+ }
+ }
+ } while (0);
+
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
- EMIT_ARG(load_const_small_int, 0); // level 0 for __import__
+ EMIT_ARG(load_const_small_int, import_level);
// build the "fromlist" tuple
#if MICROPY_EMIT_CPYTHON
@@ -1324,12 +1393,12 @@ void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
#endif
// do the import
- qstr dummy_q, id1;
- do_import_name(comp, pns->nodes[0], &dummy_q, &id1);
+ qstr dummy_q;
+ do_import_name(comp, pn_import_source, &dummy_q);
EMIT(import_star);
} else {
- EMIT_ARG(load_const_small_int, 0); // level 0 for __import__
+ EMIT_ARG(load_const_small_int, import_level);
// build the "fromlist" tuple
mp_parse_node_t *pn_nodes;
@@ -1369,8 +1438,8 @@ void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
#endif
// do the import
- qstr dummy_q, id1;
- do_import_name(comp, pns->nodes[0], &dummy_q, &id1);
+ qstr dummy_q;
+ do_import_name(comp, pn_import_source, &dummy_q);
for (int i = 0; i < n; i++) {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name));
mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i];
@@ -1415,7 +1484,7 @@ void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
- int l_end = comp_next_label(comp);
+ uint l_end = comp_next_label(comp);
c_if_cond(comp, pns->nodes[0], true, l_end);
EMIT_ARG(load_global, MP_QSTR_AssertionError); // we load_global instead of load_id, to be consistent with CPython
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
@@ -1430,9 +1499,9 @@ void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
// TODO proper and/or short circuiting
- int l_end = comp_next_label(comp);
+ uint l_end = comp_next_label(comp);
- int l_fail = comp_next_label(comp);
+ uint l_fail = comp_next_label(comp);
c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition
compile_node(comp, pns->nodes[1]); // if block
@@ -1493,10 +1562,10 @@ void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
#define START_BREAK_CONTINUE_BLOCK \
- int old_break_label = comp->break_label; \
- int old_continue_label = comp->continue_label; \
- int break_label = comp_next_label(comp); \
- int continue_label = comp_next_label(comp); \
+ uint old_break_label = comp->break_label; \
+ uint old_continue_label = comp->continue_label; \
+ uint break_label = comp_next_label(comp); \
+ uint continue_label = comp_next_label(comp); \
comp->break_label = break_label; \
comp->continue_label = continue_label; \
comp->break_continue_except_level = comp->cur_except_level;
@@ -1511,7 +1580,7 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
// compared to CPython, we have an optimised version of while loops
#if MICROPY_EMIT_CPYTHON
- int done_label = comp_next_label(comp);
+ uint done_label = comp_next_label(comp);
EMIT_ARG(setup_loop, break_label);
EMIT_ARG(label_assign, continue_label);
c_if_cond(comp, pns->nodes[0], false, done_label); // condition
@@ -1526,7 +1595,7 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
EMIT(pop_block);
}
#else
- int top_label = comp_next_label(comp);
+ uint top_label = comp_next_label(comp);
EMIT_ARG(jump, continue_label);
EMIT_ARG(label_assign, top_label);
compile_node(comp, pns->nodes[1]); // body
@@ -1548,8 +1617,8 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
START_BREAK_CONTINUE_BLOCK
- int top_label = comp_next_label(comp);
- int entry_label = comp_next_label(comp);
+ uint top_label = comp_next_label(comp);
+ uint entry_label = comp_next_label(comp);
// compile: start, duplicated on stack
compile_node(comp, pn_start);
@@ -1559,7 +1628,7 @@ void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var,
EMIT_ARG(label_assign, top_label);
// at this point we actually have 1 less element on the stack
- EMIT_ARG(set_stack_size, EMIT(get_stack_size) - 1);
+ EMIT_ARG(adjust_stack_size, -1);
// store next value to var
c_assign(comp, pn_var, ASSIGN_STORE);
@@ -1646,8 +1715,8 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
START_BREAK_CONTINUE_BLOCK
- int pop_label = comp_next_label(comp);
- int end_label = comp_next_label(comp);
+ uint pop_label = comp_next_label(comp);
+ uint end_label = comp_next_label(comp);
// I don't think our implementation needs SETUP_LOOP/POP_BLOCK for for-statements
#if MICROPY_EMIT_CPYTHON
@@ -1680,29 +1749,28 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_excepts, mp_parse_node_t pn_else) {
- // this function is a bit of a hack at the moment
- // don't understand how the stack works with exceptions, so we force it to return to the correct value
-
// setup code
- int stack_size = EMIT(get_stack_size);
- int l1 = comp_next_label(comp);
- int success_label = comp_next_label(comp);
+ uint l1 = comp_next_label(comp);
+ uint success_label = comp_next_label(comp);
EMIT_ARG(setup_except, l1);
compile_increase_except_level(comp);
compile_node(comp, pn_body); // body
EMIT(pop_block);
- EMIT_ARG(jump, success_label);
- EMIT_ARG(label_assign, l1);
- int l2 = comp_next_label(comp);
+ EMIT_ARG(jump, success_label); // jump over exception handler
+
+ EMIT_ARG(label_assign, l1); // start of exception handler
+ EMIT_ARG(adjust_stack_size, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
+
+ uint l2 = comp_next_label(comp);
for (int i = 0; i < n_except; i++) {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_excepts[i], PN_try_stmt_except)); // should be
mp_parse_node_struct_t *pns_except = (mp_parse_node_struct_t*)pn_excepts[i];
qstr qstr_exception_local = 0;
- int end_finally_label = comp_next_label(comp);
+ uint end_finally_label = comp_next_label(comp);
if (MP_PARSE_NODE_IS_NULL(pns_except->nodes[0])) {
// this is a catch all exception handler
@@ -1737,7 +1805,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
EMIT(pop_top);
- int l3 = 0;
+ uint l3 = 0;
if (qstr_exception_local != 0) {
l3 = comp_next_label(comp);
EMIT_ARG(setup_finally, l3);
@@ -1760,28 +1828,29 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
}
EMIT_ARG(jump, l2);
EMIT_ARG(label_assign, end_finally_label);
+ EMIT_ARG(adjust_stack_size, 3); // stack adjust for the 3 exception items
}
compile_decrease_except_level(comp);
EMIT(end_finally);
+ EMIT_ARG(adjust_stack_size, -5); // stack adjust
EMIT_ARG(label_assign, success_label);
compile_node(comp, pn_else); // else block, can be null
EMIT_ARG(label_assign, l2);
- EMIT_ARG(set_stack_size, stack_size);
}
void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) {
- // don't understand how the stack works with exceptions, so we force it to return to the correct value
- int stack_size = EMIT(get_stack_size);
- int l_finally_block = comp_next_label(comp);
+ uint l_finally_block = comp_next_label(comp);
EMIT_ARG(setup_finally, l_finally_block);
compile_increase_except_level(comp);
if (n_except == 0) {
assert(MP_PARSE_NODE_IS_NULL(pn_else));
+ EMIT_ARG(adjust_stack_size, 3); // stack adjust for possible UNWIND_JUMP state
compile_node(comp, pn_body);
+ EMIT_ARG(adjust_stack_size, -3);
} else {
compile_try_except(comp, pn_body, n_except, pn_except, pn_else);
}
@@ -1792,8 +1861,6 @@ void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except
compile_decrease_except_level(comp);
EMIT(end_finally);
-
- EMIT_ARG(set_stack_size, stack_size);
}
void compile_try_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
@@ -1830,7 +1897,7 @@ void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, m
// no more pre-bits, compile the body of the with
compile_node(comp, body);
} else {
- int l_end = comp_next_label(comp);
+ uint l_end = comp_next_label(comp);
if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[0], PN_with_item)) {
// this pre-bit is of the form "a as b"
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0];
@@ -1987,14 +2054,13 @@ void compile_test_if_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_test_if_else));
mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns->nodes[1];
- int stack_size = EMIT(get_stack_size);
- int l_fail = comp_next_label(comp);
- int l_end = comp_next_label(comp);
+ uint l_fail = comp_next_label(comp);
+ uint l_end = comp_next_label(comp);
c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition
compile_node(comp, pns->nodes[0]); // success value
EMIT_ARG(jump, l_end);
EMIT_ARG(label_assign, l_fail);
- EMIT_ARG(set_stack_size, stack_size); // force stack size reset
+ EMIT_ARG(adjust_stack_size, -1); // adjust stack size
compile_node(comp, pns_test_if_else->nodes[1]); // failure value
EMIT_ARG(label_assign, l_end);
}
@@ -2019,7 +2085,7 @@ void compile_lambdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
void compile_or_test(compiler_t *comp, mp_parse_node_struct_t *pns) {
- int l_end = comp_next_label(comp);
+ uint l_end = comp_next_label(comp);
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
for (int i = 0; i < n; i += 1) {
compile_node(comp, pns->nodes[i]);
@@ -2031,7 +2097,7 @@ void compile_or_test(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) {
- int l_end = comp_next_label(comp);
+ uint l_end = comp_next_label(comp);
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
for (int i = 0; i < n; i += 1) {
compile_node(comp, pns->nodes[i]);
@@ -2048,11 +2114,10 @@ void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) {
- int stack_size = EMIT(get_stack_size);
int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
compile_node(comp, pns->nodes[0]);
bool multi = (num_nodes > 3);
- int l_fail = 0;
+ uint l_fail = 0;
if (multi) {
l_fail = comp_next_label(comp);
}
@@ -2099,13 +2164,13 @@ void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
if (multi) {
- int l_end = comp_next_label(comp);
+ uint l_end = comp_next_label(comp);
EMIT_ARG(jump, l_end);
EMIT_ARG(label_assign, l_fail);
+ EMIT_ARG(adjust_stack_size, 1);
EMIT(rot_two);
EMIT(pop_top);
EMIT_ARG(label_assign, l_end);
- EMIT_ARG(set_stack_size, stack_size + 1); // force stack size
}
}
@@ -2799,8 +2864,8 @@ void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_t pn_iter, mp_parse
// for loop
mp_parse_node_struct_t *pns_comp_for2 = (mp_parse_node_struct_t*)pn_iter;
compile_node(comp, pns_comp_for2->nodes[1]);
- int l_end2 = comp_next_label(comp);
- int l_top2 = comp_next_label(comp);
+ uint l_end2 = comp_next_label(comp);
+ uint l_top2 = comp_next_label(comp);
EMIT(get_iter);
EMIT_ARG(label_assign, l_top2);
EMIT_ARG(for_iter, l_end2);
@@ -2946,8 +3011,8 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
EMIT_ARG(build_set, 0);
}
- int l_end = comp_next_label(comp);
- int l_top = comp_next_label(comp);
+ uint l_end = comp_next_label(comp);
+ uint l_top = comp_next_label(comp);
EMIT_ARG(load_id, qstr_arg);
EMIT_ARG(label_assign, l_top);
EMIT_ARG(for_iter, l_end);
@@ -3066,7 +3131,7 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass
compile_syntax_error(comp, nodes[i], "inline assembler 'label' requires 1 argument");
return;
}
- int lab = comp_next_label(comp);
+ uint lab = comp_next_label(comp);
if (pass > PASS_1) {
EMIT_INLINE_ASM_ARG(label, lab, MP_PARSE_NODE_LEAF_ARG(pn_arg[0]));
}
diff --git a/py/emit.h b/py/emit.h
index 5ce11af92d..738150c656 100644
--- a/py/emit.h
+++ b/py/emit.h
@@ -24,15 +24,14 @@ typedef struct _emit_method_table_t {
void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope);
void (*end_pass)(emit_t *emit);
bool (*last_emit_was_return_value)(emit_t *emit);
- int (*get_stack_size)(emit_t *emit);
- void (*set_stack_size)(emit_t *emit, int size);
+ void (*adjust_stack_size)(emit_t *emit, int delta);
void (*set_line_number)(emit_t *emit, int line);
void (*load_id)(emit_t *emit, qstr qstr);
void (*store_id)(emit_t *emit, qstr qstr);
void (*delete_id)(emit_t *emit, qstr qstr);
- void (*label_assign)(emit_t *emit, int l);
+ void (*label_assign)(emit_t *emit, uint l);
void (*import_name)(emit_t *emit, qstr qstr);
void (*import_from)(emit_t *emit, qstr qstr);
void (*import_star)(emit_t *emit);
@@ -68,21 +67,21 @@ typedef struct _emit_method_table_t {
void (*pop_top)(emit_t *emit);
void (*rot_two)(emit_t *emit);
void (*rot_three)(emit_t *emit);
- void (*jump)(emit_t *emit, int label);
- void (*pop_jump_if_true)(emit_t *emit, int label);
- void (*pop_jump_if_false)(emit_t *emit, int label);
- void (*jump_if_true_or_pop)(emit_t *emit, int label);
- void (*jump_if_false_or_pop)(emit_t *emit, int label);
- void (*setup_loop)(emit_t *emit, int label);
- void (*break_loop)(emit_t *emit, int label, int except_depth);
- void (*continue_loop)(emit_t *emit, int label, int except_depth);
- void (*setup_with)(emit_t *emit, int label);
+ void (*jump)(emit_t *emit, uint label);
+ void (*pop_jump_if_true)(emit_t *emit, uint label);
+ void (*pop_jump_if_false)(emit_t *emit, uint label);
+ void (*jump_if_true_or_pop)(emit_t *emit, uint label);
+ void (*jump_if_false_or_pop)(emit_t *emit, uint label);
+ void (*setup_loop)(emit_t *emit, uint label);
+ void (*break_loop)(emit_t *emit, uint label, int except_depth);
+ void (*continue_loop)(emit_t *emit, uint label, int except_depth);
+ void (*setup_with)(emit_t *emit, uint label);
void (*with_cleanup)(emit_t *emit);
- void (*setup_except)(emit_t *emit, int label);
- void (*setup_finally)(emit_t *emit, int label);
+ void (*setup_except)(emit_t *emit, uint label);
+ void (*setup_finally)(emit_t *emit, uint label);
void (*end_finally)(emit_t *emit);
void (*get_iter)(emit_t *emit);
- void (*for_iter)(emit_t *emit, int label);
+ void (*for_iter)(emit_t *emit, uint label);
void (*for_iter_end)(emit_t *emit);
void (*pop_block)(emit_t *emit);
void (*pop_except)(emit_t *emit);
@@ -136,7 +135,7 @@ typedef struct _emit_inline_asm_method_table_t {
void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope);
void (*end_pass)(emit_inline_asm_t *emit);
int (*count_params)(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params);
- void (*label)(emit_inline_asm_t *emit, int label_num, qstr label_id);
+ void (*label)(emit_inline_asm_t *emit, uint label_num, qstr label_id);
void (*op)(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args);
} emit_inline_asm_method_table_t;
diff --git a/py/emitbc.c b/py/emitbc.c
index 21d1a61863..fc3e5ed622 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -171,7 +171,7 @@ STATIC void emit_write_byte_code_byte_qstr(emit_t* emit, byte b, qstr qstr) {
}
// unsigned labels are relative to ip following this instruction, stored as 16 bits
-STATIC void emit_write_byte_code_byte_unsigned_label(emit_t* emit, byte b1, int label) {
+STATIC void emit_write_byte_code_byte_unsigned_label(emit_t* emit, byte b1, uint label) {
uint byte_code_offset;
if (emit->pass < PASS_3) {
byte_code_offset = 0;
@@ -185,7 +185,7 @@ STATIC void emit_write_byte_code_byte_unsigned_label(emit_t* emit, byte b1, int
}
// signed labels are relative to ip following this instruction, stored as 16 bits, in excess
-STATIC void emit_write_byte_code_byte_signed_label(emit_t* emit, byte b1, int label) {
+STATIC void emit_write_byte_code_byte_signed_label(emit_t* emit, byte b1, uint label) {
int byte_code_offset;
if (emit->pass < PASS_3) {
byte_code_offset = 0;
@@ -232,6 +232,12 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
{
byte* c = emit_get_cur_to_write_byte_code(emit, 4);
uint n_state = scope->num_locals + scope->stack_size;
+ if (n_state == 0) {
+ // Need at least 1 entry in the state, in the case an exception is
+ // propagated through this function, the exception is returned in
+ // the highest slot in the state (fastn[0], see vm.c).
+ n_state = 1;
+ }
c[0] = n_state & 0xff;
c[1] = (n_state >> 8) & 0xff;
c[2] = scope->exc_stack_size & 0xff;
@@ -282,16 +288,12 @@ STATIC void emit_bc_end_pass(emit_t *emit) {
}
}
-bool emit_bc_last_emit_was_return_value(emit_t *emit) {
+STATIC bool emit_bc_last_emit_was_return_value(emit_t *emit) {
return emit->last_emit_was_return_value;
}
-int emit_bc_get_stack_size(emit_t *emit) {
- return emit->stack_size;
-}
-
-STATIC void emit_bc_set_stack_size(emit_t *emit, int size) {
- emit->stack_size = size;
+STATIC void emit_bc_adjust_stack_size(emit_t *emit, int delta) {
+ emit->stack_size += delta;
}
STATIC void emit_bc_set_source_line(emit_t *emit, int source_line) {
@@ -329,7 +331,7 @@ STATIC void emit_bc_pre(emit_t *emit, int stack_size_delta) {
emit->last_emit_was_return_value = false;
}
-STATIC void emit_bc_label_assign(emit_t *emit, int l) {
+STATIC void emit_bc_label_assign(emit_t *emit, uint l) {
emit_bc_pre(emit, 0);
assert(l < emit->max_num_labels);
if (emit->pass == PASS_2) {
@@ -551,37 +553,37 @@ STATIC void emit_bc_rot_three(emit_t *emit) {
emit_write_byte_code_byte(emit, MP_BC_ROT_THREE);
}
-STATIC void emit_bc_jump(emit_t *emit, int label) {
+STATIC void emit_bc_jump(emit_t *emit, uint label) {
emit_bc_pre(emit, 0);
emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP, label);
}
-STATIC void emit_bc_pop_jump_if_true(emit_t *emit, int label) {
+STATIC void emit_bc_pop_jump_if_true(emit_t *emit, uint label) {
emit_bc_pre(emit, -1);
emit_write_byte_code_byte_signed_label(emit, MP_BC_POP_JUMP_IF_TRUE, label);
}
-STATIC void emit_bc_pop_jump_if_false(emit_t *emit, int label) {
+STATIC void emit_bc_pop_jump_if_false(emit_t *emit, uint label) {
emit_bc_pre(emit, -1);
emit_write_byte_code_byte_signed_label(emit, MP_BC_POP_JUMP_IF_FALSE, label);
}
-STATIC void emit_bc_jump_if_true_or_pop(emit_t *emit, int label) {
+STATIC void emit_bc_jump_if_true_or_pop(emit_t *emit, uint label) {
emit_bc_pre(emit, -1);
emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP_IF_TRUE_OR_POP, label);
}
-STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, int label) {
+STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, uint label) {
emit_bc_pre(emit, -1);
emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label);
}
-STATIC void emit_bc_setup_loop(emit_t *emit, int label) {
+STATIC void emit_bc_setup_loop(emit_t *emit, uint label) {
emit_bc_pre(emit, 0);
emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_LOOP, label);
}
-STATIC void emit_bc_unwind_jump(emit_t *emit, int label, int except_depth) {
+STATIC void emit_bc_unwind_jump(emit_t *emit, uint label, int except_depth) {
if (except_depth == 0) {
emit_bc_jump(emit, label);
} else {
@@ -591,7 +593,7 @@ STATIC void emit_bc_unwind_jump(emit_t *emit, int label, int except_depth) {
}
}
-STATIC void emit_bc_setup_with(emit_t *emit, int label) {
+STATIC void emit_bc_setup_with(emit_t *emit, uint label) {
emit_bc_pre(emit, 7);
emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label);
}
@@ -601,13 +603,13 @@ STATIC void emit_bc_with_cleanup(emit_t *emit) {
emit_write_byte_code_byte(emit, MP_BC_WITH_CLEANUP);
}
-STATIC void emit_bc_setup_except(emit_t *emit, int label) {
- emit_bc_pre(emit, 6);
+STATIC void emit_bc_setup_except(emit_t *emit, uint label) {
+ emit_bc_pre(emit, 0);
emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label);
}
-STATIC void emit_bc_setup_finally(emit_t *emit, int label) {
- emit_bc_pre(emit, 6);
+STATIC void emit_bc_setup_finally(emit_t *emit, uint label) {
+ emit_bc_pre(emit, 0);
emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label);
}
@@ -621,7 +623,7 @@ STATIC void emit_bc_get_iter(emit_t *emit) {
emit_write_byte_code_byte(emit, MP_BC_GET_ITER);
}
-STATIC void emit_bc_for_iter(emit_t *emit, int label) {
+STATIC void emit_bc_for_iter(emit_t *emit, uint label) {
emit_bc_pre(emit, 1);
emit_write_byte_code_byte_unsigned_label(emit, MP_BC_FOR_ITER, label);
}
@@ -830,8 +832,7 @@ const emit_method_table_t emit_bc_method_table = {
emit_bc_start_pass,
emit_bc_end_pass,
emit_bc_last_emit_was_return_value,
- emit_bc_get_stack_size,
- emit_bc_set_stack_size,
+ emit_bc_adjust_stack_size,
emit_bc_set_source_line,
emit_bc_load_id,
diff --git a/py/emitcpy.c b/py/emitcpy.c
index 8c608d6a2b..5866d474e9 100644
--- a/py/emitcpy.c
+++ b/py/emitcpy.c
@@ -60,12 +60,8 @@ STATIC bool emit_cpy_last_emit_was_return_value(emit_t *emit) {
return emit->last_emit_was_return_value;
}
-STATIC int emit_cpy_get_stack_size(emit_t *emit) {
- return emit->stack_size;
-}
-
-STATIC void emit_cpy_set_stack_size(emit_t *emit, int size) {
- emit->stack_size = size;
+STATIC void emit_cpy_adjust_stack_size(emit_t *emit, int delta) {
+ emit->stack_size += delta;
}
STATIC void emit_cpy_set_source_line(emit_t *emit, int source_line) {
@@ -100,7 +96,7 @@ static void emit_pre(emit_t *emit, int stack_size_delta, int byte_code_size) {
emit->byte_code_offset += byte_code_size;
}
-STATIC void emit_cpy_label_assign(emit_t *emit, int l) {
+STATIC void emit_cpy_label_assign(emit_t *emit, uint l) {
emit_pre(emit, 0, 0);
assert(l < emit->max_num_labels);
if (emit->pass == PASS_2) {
@@ -402,7 +398,7 @@ STATIC void emit_cpy_rot_three(emit_t *emit) {
}
}
-STATIC void emit_cpy_jump(emit_t *emit, int label) {
+STATIC void emit_cpy_jump(emit_t *emit, uint label) {
emit_pre(emit, 0, 3);
if (emit->pass == PASS_3) {
int dest = emit->label_offsets[label];
@@ -414,49 +410,49 @@ STATIC void emit_cpy_jump(emit_t *emit, int label) {
}
}
-STATIC void emit_cpy_pop_jump_if_true(emit_t *emit, int label) {
+STATIC void emit_cpy_pop_jump_if_true(emit_t *emit, uint label) {
emit_pre(emit, -1, 3);
if (emit->pass == PASS_3) {
printf("POP_JUMP_IF_TRUE %d\n", emit->label_offsets[label]);
}
}
-STATIC void emit_cpy_pop_jump_if_false(emit_t *emit, int label) {
+STATIC void emit_cpy_pop_jump_if_false(emit_t *emit, uint label) {
emit_pre(emit, -1, 3);
if (emit->pass == PASS_3) {
printf("POP_JUMP_IF_FALSE %d\n", emit->label_offsets[label]);
}
}
-STATIC void emit_cpy_jump_if_true_or_pop(emit_t *emit, int label) {
+STATIC void emit_cpy_jump_if_true_or_pop(emit_t *emit, uint label) {
emit_pre(emit, -1, 3);
if (emit->pass == PASS_3) {
printf("JUMP_IF_TRUE_OR_POP %d\n", emit->label_offsets[label]);
}
}
-STATIC void emit_cpy_jump_if_false_or_pop(emit_t *emit, int label) {
+STATIC void emit_cpy_jump_if_false_or_pop(emit_t *emit, uint label) {
emit_pre(emit, -1, 3);
if (emit->pass == PASS_3) {
printf("JUMP_IF_FALSE_OR_POP %d\n", emit->label_offsets[label]);
}
}
-STATIC void emit_cpy_setup_loop(emit_t *emit, int label) {
+STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) {
emit_pre(emit, 0, 3);
if (emit->pass == PASS_3) {
printf("SETUP_LOOP %d\n", emit->label_offsets[label]);
}
}
-STATIC void emit_cpy_break_loop(emit_t *emit, int label, int except_depth) {
+STATIC void emit_cpy_break_loop(emit_t *emit, uint label, int except_depth) {
emit_pre(emit, 0, 1);
if (emit->pass == PASS_3) {
printf("BREAK_LOOP\n");
}
}
-STATIC void emit_cpy_continue_loop(emit_t *emit, int label, int except_depth) {
+STATIC void emit_cpy_continue_loop(emit_t *emit, uint label, int except_depth) {
if (except_depth == 0) {
emit_cpy_jump(emit, label);
} else {
@@ -467,7 +463,7 @@ STATIC void emit_cpy_continue_loop(emit_t *emit, int label, int except_depth) {
}
}
-STATIC void emit_cpy_setup_with(emit_t *emit, int label) {
+STATIC void emit_cpy_setup_with(emit_t *emit, uint label) {
emit_pre(emit, 7, 3);
if (emit->pass == PASS_3) {
printf("SETUP_WITH %d\n", emit->label_offsets[label]);
@@ -481,15 +477,15 @@ STATIC void emit_cpy_with_cleanup(emit_t *emit) {
}
}
-STATIC void emit_cpy_setup_except(emit_t *emit, int label) {
- emit_pre(emit, 6, 3);
+STATIC void emit_cpy_setup_except(emit_t *emit, uint label) {
+ emit_pre(emit, 0, 3);
if (emit->pass == PASS_3) {
printf("SETUP_EXCEPT %d\n", emit->label_offsets[label]);
}
}
-STATIC void emit_cpy_setup_finally(emit_t *emit, int label) {
- emit_pre(emit, 6, 3);
+STATIC void emit_cpy_setup_finally(emit_t *emit, uint label) {
+ emit_pre(emit, 0, 3);
if (emit->pass == PASS_3) {
printf("SETUP_FINALLY %d\n", emit->label_offsets[label]);
}
@@ -509,7 +505,7 @@ STATIC void emit_cpy_get_iter(emit_t *emit) {
}
}
-STATIC void emit_cpy_for_iter(emit_t *emit, int label) {
+STATIC void emit_cpy_for_iter(emit_t *emit, uint label) {
emit_pre(emit, 1, 3);
if (emit->pass == PASS_3) {
printf("FOR_ITER %d\n", emit->label_offsets[label]);
@@ -793,8 +789,7 @@ const emit_method_table_t emit_cpython_method_table = {
emit_cpy_start_pass,
emit_cpy_end_pass,
emit_cpy_last_emit_was_return_value,
- emit_cpy_get_stack_size,
- emit_cpy_set_stack_size,
+ emit_cpy_adjust_stack_size,
emit_cpy_set_source_line,
emit_cpy_load_id,
diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c
index c5136ab371..db1525672f 100644
--- a/py/emitinlinethumb.c
+++ b/py/emitinlinethumb.c
@@ -75,7 +75,7 @@ STATIC int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params,
return n_params;
}
-STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, int label_num, qstr label_id) {
+STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, uint label_num, qstr label_id) {
assert(label_num < emit->max_num_labels);
emit->label_lookup[label_num] = label_id;
asm_thumb_label_assign(emit->as, label_num);
diff --git a/py/emitnative.c b/py/emitnative.c
index e96b12271a..d2a3df25dd 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -295,12 +295,8 @@ STATIC bool emit_native_last_emit_was_return_value(emit_t *emit) {
return emit->last_emit_was_return_value;
}
-STATIC int emit_native_get_stack_size(emit_t *emit) {
- return emit->stack_size;
-}
-
-STATIC void emit_native_set_stack_size(emit_t *emit, int size) {
- emit->stack_size = size;
+STATIC void emit_native_adjust_stack_size(emit_t *emit, int delta) {
+ emit->stack_size += delta;
}
STATIC void emit_native_set_source_line(emit_t *emit, int source_line) {
@@ -585,7 +581,7 @@ STATIC void emit_native_delete_id(emit_t *emit, qstr qstr) {
emit_common_delete_id(emit, &EXPORT_FUN(method_table), emit->scope, qstr);
}
-STATIC void emit_native_label_assign(emit_t *emit, int l) {
+STATIC void emit_native_label_assign(emit_t *emit, uint l) {
emit_native_pre(emit);
// need to commit stack because we can jump here from elsewhere
need_stack_settled(emit);
@@ -920,7 +916,7 @@ STATIC void emit_native_rot_three(emit_t *emit) {
emit_post_push_reg_reg_reg(emit, vtype0, REG_TEMP0, vtype2, REG_TEMP2, vtype1, REG_TEMP1);
}
-STATIC void emit_native_jump(emit_t *emit, int label) {
+STATIC void emit_native_jump(emit_t *emit, uint label) {
emit_native_pre(emit);
#if N_X64
asm_x64_jmp_label(emit->as, label);
@@ -930,7 +926,7 @@ STATIC void emit_native_jump(emit_t *emit, int label) {
emit_post(emit);
}
-STATIC void emit_native_pop_jump_pre_helper(emit_t *emit, int label) {
+STATIC void emit_native_pop_jump_pre_helper(emit_t *emit, uint label) {
vtype_kind_t vtype = peek_vtype(emit);
if (vtype == VTYPE_BOOL) {
emit_pre_pop_reg(emit, &vtype, REG_RET);
@@ -943,7 +939,7 @@ STATIC void emit_native_pop_jump_pre_helper(emit_t *emit, int label) {
}
}
-STATIC void emit_native_pop_jump_if_false(emit_t *emit, int label) {
+STATIC void emit_native_pop_jump_if_false(emit_t *emit, uint label) {
emit_native_pop_jump_pre_helper(emit, label);
#if N_X64
asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
@@ -955,7 +951,7 @@ STATIC void emit_native_pop_jump_if_false(emit_t *emit, int label) {
emit_post(emit);
}
-STATIC void emit_native_pop_jump_if_true(emit_t *emit, int label) {
+STATIC void emit_native_pop_jump_if_true(emit_t *emit, uint label) {
emit_native_pop_jump_pre_helper(emit, label);
#if N_X64
asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
@@ -967,35 +963,35 @@ STATIC void emit_native_pop_jump_if_true(emit_t *emit, int label) {
emit_post(emit);
}
-STATIC void emit_native_jump_if_true_or_pop(emit_t *emit, int label) {
+STATIC void emit_native_jump_if_true_or_pop(emit_t *emit, uint label) {
assert(0);
}
-STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, int label) {
+STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, uint label) {
assert(0);
}
-STATIC void emit_native_setup_loop(emit_t *emit, int label) {
+STATIC void emit_native_setup_loop(emit_t *emit, uint label) {
emit_native_pre(emit);
emit_post(emit);
}
-STATIC void emit_native_break_loop(emit_t *emit, int label, int except_depth) {
+STATIC void emit_native_break_loop(emit_t *emit, uint label, int except_depth) {
emit_native_jump(emit, label); // TODO properly
}
-STATIC void emit_native_continue_loop(emit_t *emit, int label, int except_depth) {
+STATIC void emit_native_continue_loop(emit_t *emit, uint label, int except_depth) {
assert(0);
}
-STATIC void emit_native_setup_with(emit_t *emit, int label) {
+STATIC void emit_native_setup_with(emit_t *emit, uint label) {
// not supported, or could be with runtime call
assert(0);
}
STATIC void emit_native_with_cleanup(emit_t *emit) {
assert(0);
}
-STATIC void emit_native_setup_except(emit_t *emit, int label) {
+STATIC void emit_native_setup_except(emit_t *emit, uint label) {
assert(0);
}
-STATIC void emit_native_setup_finally(emit_t *emit, int label) {
+STATIC void emit_native_setup_finally(emit_t *emit, uint label) {
assert(0);
}
STATIC void emit_native_end_finally(emit_t *emit) {
@@ -1013,7 +1009,7 @@ STATIC void emit_native_get_iter(emit_t *emit) {
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
}
-STATIC void emit_native_for_iter(emit_t *emit, int label) {
+STATIC void emit_native_for_iter(emit_t *emit, uint label) {
emit_native_pre(emit);
vtype_kind_t vtype;
emit_access_stack(emit, 1, &vtype, REG_ARG_1);
@@ -1304,8 +1300,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
emit_native_start_pass,
emit_native_end_pass,
emit_native_last_emit_was_return_value,
- emit_native_get_stack_size,
- emit_native_set_stack_size,
+ emit_native_adjust_stack_size,
emit_native_set_source_line,
emit_native_load_id,
diff --git a/py/emitpass1.c b/py/emitpass1.c
index 6088489410..301c04ebea 100644
--- a/py/emitpass1.c
+++ b/py/emitpass1.c
@@ -35,6 +35,10 @@ STATIC void emit_pass1_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope
STATIC void emit_pass1_end_pass(emit_t *emit) {
}
+STATIC bool emit_pass1_last_emit_was_return_value(emit_t *emit) {
+ return false;
+}
+
STATIC void emit_pass1_load_id(emit_t *emit, qstr qstr) {
// name adding/lookup
bool added;
@@ -99,8 +103,7 @@ const emit_method_table_t emit_pass1_method_table = {
(void*)emit_pass1_dummy,
emit_pass1_start_pass,
emit_pass1_end_pass,
- (void*)emit_pass1_dummy,
- (void*)emit_pass1_dummy,
+ emit_pass1_last_emit_was_return_value,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
diff --git a/py/lexer.c b/py/lexer.c
index 58d54b6980..03605373d0 100644
--- a/py/lexer.c
+++ b/py/lexer.c
@@ -218,8 +218,7 @@ STATIC const char *tok_enc =
"%e=" // % %=
"^e=" // ^ ^=
"=e=" // = ==
- "!E=" // !=
- ".c.E."; // . ...
+ "!E="; // !=
// TODO static assert that number of tokens is less than 256 so we can safely make this table with byte sized entries
STATIC const uint8_t tok_enc_kind[] = {
@@ -240,7 +239,6 @@ STATIC const uint8_t tok_enc_kind[] = {
MP_TOKEN_OP_CARET, MP_TOKEN_DEL_CARET_EQUAL,
MP_TOKEN_DEL_EQUAL, MP_TOKEN_OP_DBL_EQUAL,
MP_TOKEN_OP_NOT_EQUAL,
- MP_TOKEN_DEL_PERIOD, MP_TOKEN_ELLIPSIS,
};
// must have the same order as enum in lexer.h
@@ -455,50 +453,55 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
vstr_add_char(&lex->vstr, CUR_CHAR(lex));
} else {
n_closing = 0;
- if (!is_raw && is_char(lex, '\\')) {
+ if (is_char(lex, '\\')) {
next_char(lex);
unichar c = CUR_CHAR(lex);
- switch (c) {
- case MP_LEXER_CHAR_EOF: break; // TODO a proper error message?
- case '\n': c = MP_LEXER_CHAR_EOF; break; // TODO check this works correctly (we are supposed to ignore it
- case '\\': break;
- case '\'': break;
- case '"': break;
- case 'a': c = 0x07; break;
- case 'b': c = 0x08; break;
- case 't': c = 0x09; break;
- case 'n': c = 0x0a; break;
- case 'v': c = 0x0b; break;
- case 'f': c = 0x0c; break;
- case 'r': c = 0x0d; break;
- case 'x':
- {
- uint num = 0;
- if (!get_hex(lex, 2, &num)) {
- // TODO error message
- assert(0);
- }
- c = num;
- break;
- }
- case 'N': break; // TODO \N{name} only in strings
- case 'u': break; // TODO \uxxxx only in strings
- case 'U': break; // TODO \Uxxxxxxxx only in strings
- default:
- if (c >= '0' && c <= '7') {
- // Octal sequence, 1-3 chars
- int digits = 3;
- int num = c - '0';
- while (is_following_odigit(lex) && --digits != 0) {
- next_char(lex);
- num = num * 8 + (CUR_CHAR(lex) - '0');
+ if (is_raw) {
+ // raw strings allow escaping of quotes, but the backslash is also emitted
+ vstr_add_char(&lex->vstr, '\\');
+ } else {
+ switch (c) {
+ case MP_LEXER_CHAR_EOF: break; // TODO a proper error message?
+ case '\n': c = MP_LEXER_CHAR_EOF; break; // TODO check this works correctly (we are supposed to ignore it
+ case '\\': break;
+ case '\'': break;
+ case '"': break;
+ case 'a': c = 0x07; break;
+ case 'b': c = 0x08; break;
+ case 't': c = 0x09; break;
+ case 'n': c = 0x0a; break;
+ case 'v': c = 0x0b; break;
+ case 'f': c = 0x0c; break;
+ case 'r': c = 0x0d; break;
+ case 'x':
+ {
+ uint num = 0;
+ if (!get_hex(lex, 2, &num)) {
+ // TODO error message
+ assert(0);
}
c = num;
- } else {
- // unrecognised escape character; CPython lets this through verbatim as '\' and then the character
- vstr_add_char(&lex->vstr, '\\');
+ break;
}
- break;
+ case 'N': break; // TODO \N{name} only in strings
+ case 'u': break; // TODO \uxxxx only in strings
+ case 'U': break; // TODO \Uxxxxxxxx only in strings
+ default:
+ if (c >= '0' && c <= '7') {
+ // Octal sequence, 1-3 chars
+ int digits = 3;
+ int num = c - '0';
+ while (is_following_odigit(lex) && --digits != 0) {
+ next_char(lex);
+ num = num * 8 + (CUR_CHAR(lex) - '0');
+ }
+ c = num;
+ } else {
+ // unrecognised escape character; CPython lets this through verbatim as '\' and then the character
+ vstr_add_char(&lex->vstr, '\\');
+ }
+ break;
+ }
}
if (c != MP_LEXER_CHAR_EOF) {
vstr_add_char(&lex->vstr, c);
@@ -555,6 +558,23 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
}
}
+ } else if (is_char(lex, '.')) {
+ // special handling for . and ... operators, because .. is not a valid operator
+
+ // get first char
+ vstr_add_char(&lex->vstr, '.');
+ next_char(lex);
+
+ if (is_char_and(lex, '.', '.')) {
+ vstr_add_char(&lex->vstr, '.');
+ vstr_add_char(&lex->vstr, '.');
+ next_char(lex);
+ next_char(lex);
+ tok->kind = MP_TOKEN_ELLIPSIS;
+ } else {
+ tok->kind = MP_TOKEN_DEL_PERIOD;
+ }
+
} else {
// search for encoded delimiter or operator
@@ -600,6 +620,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
tok_enc_index = t_index;
} else {
tok->kind = MP_TOKEN_INVALID;
+ goto tok_enc_no_match;
}
break;
}
@@ -622,6 +643,8 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
// set token kind
tok->kind = tok_enc_kind[tok_enc_index];
+ tok_enc_no_match:
+
// compute bracket level for implicit line joining
if (tok->kind == MP_TOKEN_DEL_PAREN_OPEN || tok->kind == MP_TOKEN_DEL_BRACKET_OPEN || tok->kind == MP_TOKEN_DEL_BRACE_OPEN) {
lex->nested_bracket_level += 1;
diff --git a/py/lexerunix.c b/py/lexerunix.c
index 73d30f2476..52fbe740ae 100644
--- a/py/lexerunix.c
+++ b/py/lexerunix.c
@@ -13,23 +13,45 @@
#include <sys/stat.h>
#include <sys/types.h>
-mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
- int fd = open(filename, O_RDONLY);
- if (fd < 0) {
- return NULL;
+typedef struct _mp_lexer_file_buf_t {
+ int fd;
+ char buf[20];
+ uint len;
+ uint pos;
+} mp_lexer_file_buf_t;
+
+STATIC unichar file_buf_next_char(mp_lexer_file_buf_t *fb) {
+ if (fb->pos >= fb->len) {
+ if (fb->len < sizeof(fb->buf)) {
+ return MP_LEXER_CHAR_EOF;
+ } else {
+ int n = read(fb->fd, fb->buf, sizeof(fb->buf));
+ if (n <= 0) {
+ return MP_LEXER_CHAR_EOF;
+ }
+ fb->len = n;
+ fb->pos = 0;
+ }
}
- uint size = lseek(fd, 0, SEEK_END);
- lseek(fd, 0, SEEK_SET);
- char *data = m_new(char, size);
- int read_size = read(fd, data, size);
- close(fd);
- if (read_size != size) {
- printf("error reading file %s\n", filename);
- m_del(char, data, size);
+ return fb->buf[fb->pos++];
+}
+
+STATIC void file_buf_close(mp_lexer_file_buf_t *fb) {
+ close(fb->fd);
+ m_del_obj(mp_lexer_file_buf_t, fb);
+}
+
+mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
+ mp_lexer_file_buf_t *fb = m_new_obj(mp_lexer_file_buf_t);
+ fb->fd = open(filename, O_RDONLY);
+ if (fb->fd < 0) {
+ m_del_obj(mp_lexer_file_buf_t, fb);
return NULL;
}
-
- return mp_lexer_new_from_str_len(qstr_from_str(filename), data, size, size);
+ int n = read(fb->fd, fb->buf, sizeof(fb->buf));
+ fb->len = n;
+ fb->pos = 0;
+ return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_char_t)file_buf_next_char, (mp_lexer_stream_close_t)file_buf_close);
}
#endif // MICROPY_ENABLE_LEXER_UNIX
diff --git a/py/malloc.c b/py/malloc.c
index 45e939b6c2..db2578d9ad 100644
--- a/py/malloc.c
+++ b/py/malloc.c
@@ -53,6 +53,20 @@ void *m_malloc(int num_bytes) {
return ptr;
}
+void *m_malloc_maybe(int num_bytes) {
+ void *ptr = malloc(num_bytes);
+ if (ptr == NULL) {
+ return NULL;
+ }
+#if MICROPY_MEM_STATS
+ total_bytes_allocated += num_bytes;
+ current_bytes_allocated += num_bytes;
+ UPDATE_PEAK();
+#endif
+ DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
+ return ptr;
+}
+
#if MICROPY_ENABLE_FINALISER
void *m_malloc_with_finaliser(int num_bytes) {
if (num_bytes == 0) {
@@ -104,6 +118,26 @@ void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes) {
return new_ptr;
}
+void *m_realloc_maybe(void *ptr, int old_num_bytes, int new_num_bytes) {
+ void *new_ptr = realloc(ptr, new_num_bytes);
+ if (new_ptr == NULL) {
+ return NULL;
+ }
+#if MICROPY_MEM_STATS
+ // At first thought, "Total bytes allocated" should only grow,
+ // after all, it's *total*. But consider for example 2K block
+ // shrunk to 1K and then grown to 2K again. It's still 2K
+ // allocated total. If we process only positive increments,
+ // we'll count 3K.
+ int diff = new_num_bytes - old_num_bytes;
+ total_bytes_allocated += diff;
+ current_bytes_allocated += diff;
+ UPDATE_PEAK();
+#endif
+ DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
+ return new_ptr;
+}
+
void m_free(void *ptr, int num_bytes) {
if (ptr != NULL) {
free(ptr);
diff --git a/py/misc.h b/py/misc.h
index 4112a6f0da..002a97ffec 100644
--- a/py/misc.h
+++ b/py/misc.h
@@ -27,20 +27,24 @@ typedef unsigned int uint;
#define m_new0(type, num) ((type*)(m_malloc0(sizeof(type) * (num))))
#define m_new_obj(type) (m_new(type, 1))
#define m_new_obj_var(obj_type, var_type, var_num) ((obj_type*)m_malloc(sizeof(obj_type) + sizeof(var_type) * (var_num)))
+#define m_new_obj_var_maybe(obj_type, var_type, var_num) ((obj_type*)m_malloc_maybe(sizeof(obj_type) + sizeof(var_type) * (var_num)))
#if MICROPY_ENABLE_FINALISER
#define m_new_obj_with_finaliser(type) ((type*)(m_malloc_with_finaliser(sizeof(type))))
#else
#define m_new_obj_with_finaliser(type) m_new_obj(type)
#endif
#define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num))))
+#define m_renew_maybe(type, ptr, old_num, new_num) ((type*)(m_realloc_maybe((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num))))
#define m_del(type, ptr, num) m_free(ptr, sizeof(type) * (num))
#define m_del_obj(type, ptr) (m_del(type, ptr, 1))
#define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num)))
void *m_malloc(int num_bytes);
+void *m_malloc_maybe(int num_bytes);
void *m_malloc_with_finaliser(int num_bytes);
void *m_malloc0(int num_bytes);
void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes);
+void *m_realloc_maybe(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);
diff --git a/py/modstruct.c b/py/modstruct.c
index b5110df1b7..23c2c903de 100644
--- a/py/modstruct.c
+++ b/py/modstruct.c
@@ -38,7 +38,7 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
const char *fmt = mp_obj_str_get_str(fmt_in);
char fmt_type = get_fmt_type(&fmt);
assert(fmt_type == '<'); (void)fmt_type;
- uint size;
+ machine_uint_t size;
for (size = 0; *fmt; fmt++) {
int sz = mp_binary_get_size(*fmt);
// TODO
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 1f2862ab0e..b120c4bb4a 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -150,6 +150,11 @@ typedef double mp_float_t;
#define MICROPY_EXTRA_BUILTIN_MODULES
#endif
+// Additional constant definitions for the compiler - see compile.c:mp_constants_table.
+#ifndef MICROPY_EXTRA_CONSTANTS
+#define MICROPY_EXTRA_CONSTANTS
+#endif
+
/*****************************************************************************/
/* Miscellaneous settings */
diff --git a/py/obj.h b/py/obj.h
index b944d2fcb5..af6ef83189 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -429,11 +429,11 @@ typedef struct _mp_obj_float_t {
mp_float_t value;
} mp_obj_float_t;
mp_float_t mp_obj_float_get(mp_obj_t self_in);
-mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs);
+mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL
// complex
void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
-mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in);
+mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NULL
#endif
// tuple
diff --git a/py/objcomplex.c b/py/objcomplex.c
index 66f971da0e..23c67eb6e1 100644
--- a/py/objcomplex.c
+++ b/py/objcomplex.c
@@ -11,6 +11,8 @@
#if MICROPY_ENABLE_FLOAT
+#include <math.h>
+
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
#include "formatfloat.h"
#endif
@@ -176,6 +178,33 @@ mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_im
}
break;
+ case MP_BINARY_OP_POWER:
+ case MP_BINARY_OP_INPLACE_POWER: {
+ // z1**z2 = exp(z2*ln(z1))
+ // = exp(z2*(ln(|z1|)+i*arg(z1)))
+ // = exp( (x2*ln1 - y2*arg1) + i*(y2*ln1 + x2*arg1) )
+ // = exp(x3 + i*y3)
+ // = exp(x3)*(cos(y3) + i*sin(y3))
+ mp_float_t abs1 = MICROPY_FLOAT_C_FUN(sqrt)(lhs_real*lhs_real + lhs_imag*lhs_imag);
+ if (abs1 == 0) {
+ if (rhs_imag == 0) {
+ lhs_real = 1;
+ rhs_real = 0;
+ } else {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power"));
+ }
+ } else {
+ mp_float_t ln1 = MICROPY_FLOAT_C_FUN(log)(abs1);
+ mp_float_t arg1 = MICROPY_FLOAT_C_FUN(atan2)(lhs_imag, lhs_real);
+ mp_float_t x3 = rhs_real * ln1 - rhs_imag * arg1;
+ mp_float_t y3 = rhs_imag * ln1 + rhs_real * arg1;
+ mp_float_t exp_x3 = MICROPY_FLOAT_C_FUN(exp)(x3);
+ lhs_real = exp_x3 * MICROPY_FLOAT_C_FUN(cos)(y3);
+ lhs_imag = exp_x3 * MICROPY_FLOAT_C_FUN(sin)(y3);
+ }
+ break;
+ }
+
default:
return MP_OBJ_NULL; // op not supported
}
diff --git a/py/objexcept.c b/py/objexcept.c
index 51e7a2615a..781a00405c 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -20,6 +20,9 @@ typedef struct _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}};
+// Local non-heap memory for allocating an exception when we run out of RAM
+STATIC mp_obj_exception_t mp_emergency_exception_obj;
+
// 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.
@@ -51,7 +54,13 @@ STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%s does not take keyword arguments", mp_obj_get_type_str(type_in)));
}
- 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_maybe(mp_obj_exception_t, mp_obj_t, n_args);
+ if (o == NULL) {
+ // Couldn't allocate heap memory; use local data instead.
+ o = &mp_emergency_exception_obj;
+ // We can't store any args.
+ n_args = 0;
+ }
o->base.type = type;
o->traceback = MP_OBJ_NULL;
o->args.base.type = &mp_type_tuple;
@@ -196,25 +205,35 @@ 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, 1);
- o->base.type = exc_type;
- o->traceback = MP_OBJ_NULL;
- o->args.base.type = &mp_type_tuple;
- o->args.len = 1;
-
- if (fmt == NULL) {
- // no message
- assert(0);
+ mp_obj_exception_t *o = m_new_obj_var_maybe(mp_obj_exception_t, mp_obj_t, 1);
+ if (o == NULL) {
+ // Couldn't allocate heap memory; use local data instead.
+ // Unfortunately, we won't be able to format the string...
+ o = &mp_emergency_exception_obj;
+ o->base.type = exc_type;
+ o->traceback = MP_OBJ_NULL;
+ o->args.base.type = &mp_type_tuple;
+ o->args.len = 0;
} else {
- // 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(vstr, fmt, ap);
- va_end(ap);
- o->args.items[0] = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
- vstr_free(vstr);
+ o->base.type = exc_type;
+ o->traceback = MP_OBJ_NULL;
+ o->args.base.type = &mp_type_tuple;
+ o->args.len = 1;
+
+ if (fmt == NULL) {
+ // no message
+ assert(0);
+ } else {
+ // 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(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;
@@ -259,7 +278,7 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block) {
// make sure self_in is an exception instance
// TODO add traceback information to user-defined exceptions (need proper builtin subclassing for that)
- if (mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new) {
+ if (mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new && self_in != &mp_emergency_exception_obj) {
mp_obj_exception_t *self = self_in;
// for traceback, we are just using the list object for convenience, it's not really a list of Python objects
diff --git a/py/objfloat.c b/py/objfloat.c
index 8ccba1024c..1f96ac18e5 100644
--- a/py/objfloat.c
+++ b/py/objfloat.c
@@ -136,7 +136,7 @@ check_zero_division:
case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val);
default:
- return NULL; // op not supported
+ return MP_OBJ_NULL; // op not supported
}
return mp_obj_new_float(lhs_val);
}
diff --git a/py/objfun.c b/py/objfun.c
index 0b0df3ba4d..adf05ce404 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -211,9 +211,13 @@ arg_error:
}
STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
- DEBUG_printf("Input: ");
+ DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw);
+ DEBUG_printf("Input pos args: ");
dump_args(args, n_args);
+ DEBUG_printf("Input kw args: ");
+ dump_args(args + n_args, n_kw * 2);
mp_obj_fun_bc_t *self = self_in;
+ DEBUG_printf("Func n_def_args: %d\n", self->n_def_args);
const mp_obj_t *kwargs = args + n_args;
mp_obj_t *extra_args = self->extra_args + self->n_def_args;
@@ -295,9 +299,9 @@ continue2:;
// Now fill in defaults
mp_obj_t *d = &flat_args[self->n_args - 1];
mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
- for (int i = self->n_def_args; i > 0; i--) {
+ for (int i = self->n_def_args; i > 0; i--, d--, s--) {
if (*d == MP_OBJ_NULL) {
- *d-- = *s--;
+ *d = *s;
}
}
DEBUG_printf("Args after filling defaults: ");
diff --git a/py/parse.c b/py/parse.c
index 1381f1293d..6c899ce56d 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -86,6 +86,8 @@ typedef struct _rule_stack_t {
} rule_stack_t;
typedef struct _parser_t {
+ bool had_memory_error;
+
uint rule_stack_alloc;
uint rule_stack_top;
rule_stack_t *rule_stack;
@@ -97,9 +99,21 @@ typedef struct _parser_t {
mp_lexer_t *lexer;
} parser_t;
+STATIC inline void memory_error(parser_t *parser) {
+ parser->had_memory_error = true;
+}
+
STATIC void push_rule(parser_t *parser, int src_line, const rule_t *rule, int arg_i) {
+ if (parser->had_memory_error) {
+ return;
+ }
if (parser->rule_stack_top >= parser->rule_stack_alloc) {
- parser->rule_stack = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc * 2);
+ rule_stack_t *rs = m_renew_maybe(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc * 2);
+ if (rs == NULL) {
+ memory_error(parser);
+ return;
+ }
+ parser->rule_stack = rs;
parser->rule_stack_alloc *= 2;
}
rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++];
@@ -116,6 +130,7 @@ STATIC void push_rule_from_arg(parser_t *parser, uint arg) {
}
STATIC void pop_rule(parser_t *parser, const rule_t **rule, uint *arg_i, uint *src_line) {
+ assert(!parser->had_memory_error);
parser->rule_stack_top -= 1;
*rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id];
*arg_i = parser->rule_stack[parser->rule_stack_top].arg_i;
@@ -129,15 +144,6 @@ mp_parse_node_t mp_parse_node_new_leaf(machine_int_t kind, machine_int_t arg) {
return (mp_parse_node_t)(kind | (arg << 5));
}
-//int num_parse_nodes_allocated = 0;
-mp_parse_node_struct_t *parse_node_new_struct(int src_line, int rule_id, int num_args) {
- mp_parse_node_struct_t *pn = m_new_obj_var(mp_parse_node_struct_t, mp_parse_node_t, num_args);
- pn->source_line = src_line;
- pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8);
- //num_parse_nodes_allocated += 1;
- return pn;
-}
-
uint mp_parse_node_free(mp_parse_node_t pn) {
uint cnt = 0;
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
@@ -211,18 +217,32 @@ STATIC void result_stack_show(parser_t *parser) {
*/
STATIC mp_parse_node_t pop_result(parser_t *parser) {
+ if (parser->had_memory_error) {
+ return MP_PARSE_NODE_NULL;
+ }
assert(parser->result_stack_top > 0);
return parser->result_stack[--parser->result_stack_top];
}
STATIC mp_parse_node_t peek_result(parser_t *parser, int pos) {
+ if (parser->had_memory_error) {
+ return MP_PARSE_NODE_NULL;
+ }
assert(parser->result_stack_top > pos);
return parser->result_stack[parser->result_stack_top - 1 - pos];
}
STATIC void push_result_node(parser_t *parser, mp_parse_node_t pn) {
+ if (parser->had_memory_error) {
+ return;
+ }
if (parser->result_stack_top >= parser->result_stack_alloc) {
- parser->result_stack = m_renew(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc * 2);
+ mp_parse_node_t *pn = m_renew_maybe(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc * 2);
+ if (pn == NULL) {
+ memory_error(parser);
+ return;
+ }
+ parser->result_stack = pn;
parser->result_stack_alloc *= 2;
}
parser->result_stack[parser->result_stack_top++] = pn;
@@ -283,7 +303,13 @@ STATIC void push_result_token(parser_t *parser, const mp_lexer_t *lex) {
}
STATIC void push_result_rule(parser_t *parser, int src_line, const rule_t *rule, int num_args) {
- mp_parse_node_struct_t *pn = parse_node_new_struct(src_line, rule->rule_id, num_args);
+ mp_parse_node_struct_t *pn = m_new_obj_var_maybe(mp_parse_node_struct_t, mp_parse_node_t, num_args);
+ if (pn == NULL) {
+ memory_error(parser);
+ return;
+ }
+ pn->source_line = src_line;
+ pn->kind_num_nodes = (rule->rule_id & 0xff) | (num_args << 8);
for (int i = num_args; i > 0; i--) {
pn->nodes[i - 1] = pop_result(parser);
}
@@ -296,6 +322,8 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
parser_t *parser = m_new_obj(parser_t);
+ parser->had_memory_error = false;
+
parser->rule_stack_alloc = 64;
parser->rule_stack_top = 0;
parser->rule_stack = m_new(rule_stack_t, parser->rule_stack_alloc);
@@ -327,7 +355,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
for (;;) {
next_rule:
- if (parser->rule_stack_top == 0) {
+ if (parser->rule_stack_top == 0 || parser->had_memory_error) {
break;
}
@@ -596,6 +624,16 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
}
}
+ mp_parse_node_t result;
+
+ // check if we had a memory error
+ if (parser->had_memory_error) {
+ *parse_error_kind_out = MP_PARSE_ERROR_MEMORY;
+ result = MP_PARSE_NODE_NULL;
+ goto finished;
+
+ }
+
// check we are at the end of the token stream
if (!mp_lexer_is_kind(lex, MP_TOKEN_END)) {
goto syntax_error;
@@ -609,7 +647,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, mp_p
// get the root parse node that we created
assert(parser->result_stack_top == 1);
- mp_parse_node_t result = parser->result_stack[0];
+ result = parser->result_stack[0];
finished:
// free the memory that we don't need anymore
diff --git a/py/parse.h b/py/parse.h
index 135de47d13..29bcf36e72 100644
--- a/py/parse.h
+++ b/py/parse.h
@@ -67,6 +67,7 @@ typedef enum {
} mp_parse_input_kind_t;
typedef enum {
+ MP_PARSE_ERROR_MEMORY,
MP_PARSE_ERROR_UNEXPECTED_INDENT,
MP_PARSE_ERROR_UNMATCHED_UNINDENT,
MP_PARSE_ERROR_INVALID_SYNTAX,
diff --git a/py/parsehelper.c b/py/parsehelper.c
index 3177e9a341..e069657b1d 100644
--- a/py/parsehelper.c
+++ b/py/parsehelper.c
@@ -11,6 +11,7 @@
#include "obj.h"
#include "parsehelper.h"
+#define STR_MEMORY "parser could not allocate enough memory"
#define STR_UNEXPECTED_INDENT "unexpected indent"
#define STR_UNMATCHED_UNINDENT "unindent does not match any outer indentation level"
#define STR_INVALID_SYNTAX "invalid syntax"
@@ -18,6 +19,10 @@
void mp_parse_show_exception(mp_lexer_t *lex, mp_parse_error_kind_t parse_error_kind) {
printf(" File \"%s\", line %d, column %d\n", qstr_str(mp_lexer_source_name(lex)), mp_lexer_cur(lex)->src_line, mp_lexer_cur(lex)->src_column);
switch (parse_error_kind) {
+ case MP_PARSE_ERROR_MEMORY:
+ printf("MemoryError: %s\n", STR_MEMORY);
+ break;
+
case MP_PARSE_ERROR_UNEXPECTED_INDENT:
printf("IndentationError: %s\n", STR_UNEXPECTED_INDENT);
break;
@@ -36,6 +41,9 @@ void mp_parse_show_exception(mp_lexer_t *lex, mp_parse_error_kind_t parse_error_
mp_obj_t mp_parse_make_exception(mp_parse_error_kind_t parse_error_kind) {
// TODO add source file and line number to exception?
switch (parse_error_kind) {
+ case MP_PARSE_ERROR_MEMORY:
+ return mp_obj_new_exception_msg(&mp_type_MemoryError, STR_MEMORY);
+
case MP_PARSE_ERROR_UNEXPECTED_INDENT:
return mp_obj_new_exception_msg(&mp_type_IndentationError, STR_UNEXPECTED_INDENT);
diff --git a/py/runtime.c b/py/runtime.c
index ef07e39bff..499905a0fa 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -386,9 +386,19 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
}
#if MICROPY_ENABLE_FLOAT
} else if (MP_OBJ_IS_TYPE(rhs, &mp_type_float)) {
- return mp_obj_float_binary_op(op, lhs_val, rhs);
+ mp_obj_t res = mp_obj_float_binary_op(op, lhs_val, rhs);
+ if (res == MP_OBJ_NULL) {
+ goto unsupported_op;
+ } else {
+ return res;
+ }
} else if (MP_OBJ_IS_TYPE(rhs, &mp_type_complex)) {
- return mp_obj_complex_binary_op(op, lhs_val, 0, rhs);
+ mp_obj_t res = mp_obj_complex_binary_op(op, lhs_val, 0, rhs);
+ if (res == MP_OBJ_NULL) {
+ goto unsupported_op;
+ } else {
+ return res;
+ }
#endif
}
}
@@ -438,6 +448,7 @@ generic_binary_op:
// TODO implement dispatch for reverse binary ops
// TODO specify in error message what the operator is
+unsupported_op:
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"unsupported operand types for binary operator: '%s', '%s'",
mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs)));
diff --git a/py/unicode.c b/py/unicode.c
index a20527cb2b..4bdf03387c 100644
--- a/py/unicode.c
+++ b/py/unicode.c
@@ -22,7 +22,7 @@
// table of attributes for ascii characters
STATIC const uint8_t attr[] = {
0, 0, 0, 0, 0, 0, 0, 0,
- 0, AT_SP, AT_SP, AT_SP, 0, AT_SP, 0, 0,
+ 0, AT_SP, AT_SP, AT_SP, AT_SP, AT_SP, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
AT_SP, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR,
diff --git a/py/vm.c b/py/vm.c
index b9147d1d32..47d6bf8f59 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -12,6 +12,8 @@
#include "bc.h"
#include "objgenerator.h"
+#define DETECT_VM_STACK_OVERFLOW (0)
+
// Value stack grows up (this makes it incompatible with native C stack, but
// makes sure that arguments to functions are in natural order arg1..argN
// (Python semantics mandates left-to-right evaluation order, including for
@@ -74,6 +76,9 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args,
// allocate state for locals and stack
mp_obj_t temp_state[10];
mp_obj_t *state = &temp_state[0];
+#if DETECT_VM_STACK_OVERFLOW
+ n_state += 1;
+#endif
if (n_state > 10) {
state = m_new(mp_obj_t, n_state);
}
@@ -109,6 +114,26 @@ mp_vm_return_kind_t mp_execute_byte_code(const byte *code, const mp_obj_t *args,
// execute the byte code
mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code_2(code, &ip, &state[n_state - 1], &sp, exc_stack, &exc_sp, MP_OBJ_NULL);
+#if DETECT_VM_STACK_OVERFLOW
+ // We can't check the case when an exception is returned in state[n_state - 1]
+ // and there are no arguments, because in this case our detection slot may have
+ // been overwritten by the returned exception (which is allowed).
+ if (!(vm_return_kind == MP_VM_RETURN_EXCEPTION && n_args == 0 && n_args2 == 0)) {
+ // Just check to see that we have at least 1 null object left in the state.
+ bool overflow = true;
+ for (uint i = 0; i < n_state - n_args - n_args2; i++) {
+ if (state[i] == MP_OBJ_NULL) {
+ overflow = false;
+ break;
+ }
+ }
+ if (overflow) {
+ printf("VM stack overflow state=%p n_state+1=%u\n", state, n_state);
+ assert(0);
+ }
+ }
+#endif
+
switch (vm_return_kind) {
case MP_VM_RETURN_NORMAL:
*ret = *sp;
@@ -166,6 +191,7 @@ outer_dispatch_loop:
dispatch_loop:
save_ip = ip;
int op = *ip++;
+ //printf("ip=%p sp=%p op=%u\n", save_ip, sp, op);
switch (op) {
case MP_BC_LOAD_CONST_FALSE:
PUSH(mp_const_false);
diff --git a/stmhal/Makefile b/stmhal/Makefile
index 064db23c35..9789189946 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -77,8 +77,9 @@ SRC_C = \
pyexec.c \
help.c \
input.c \
- modpyb.c \
modos.c \
+ modpyb.c \
+ modstm.c \
modtime.c \
import.c \
lexerfatfs.c \
diff --git a/stmhal/modstm.c b/stmhal/modstm.c
new file mode 100644
index 0000000000..5e72a75bb2
--- /dev/null
+++ b/stmhal/modstm.c
@@ -0,0 +1,120 @@
+#include <stdio.h>
+#include <stdint.h>
+
+#include <stm32f4xx_hal.h>
+
+#include "nlr.h"
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+#include "modstm.h"
+
+STATIC uint32_t get_read_addr(mp_obj_t addr_o, uint align) {
+ uint32_t addr = mp_obj_get_int(addr_o) & 0x7fffffff;
+ if (addr < 0x10000000) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "cannot read from address %08x", addr));
+ }
+ if ((addr & (align - 1)) != 0) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align));
+ }
+ return addr;
+}
+
+STATIC uint32_t get_write_addr(mp_obj_t addr_o, uint align) {
+ uint32_t addr = mp_obj_get_int(addr_o) & 0x7fffffff;
+ if (addr < 0x10000000) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "cannot write to address %08x", addr));
+ }
+ if ((addr & (align - 1)) != 0) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align));
+ }
+ return addr;
+}
+
+STATIC mp_obj_t stm_read8(mp_obj_t addr) {
+ uint32_t a = get_read_addr(addr, 1);
+ uint32_t v = *(uint8_t*)a;
+ return mp_obj_new_int(v);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read8_obj, stm_read8);
+
+STATIC mp_obj_t stm_read16(mp_obj_t addr) {
+ uint32_t a = get_read_addr(addr, 2);
+ uint32_t v = *(uint16_t*)a;
+ return mp_obj_new_int(v);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read16_obj, stm_read16);
+
+STATIC mp_obj_t stm_read32(mp_obj_t addr) {
+ uint32_t a = get_read_addr(addr, 4);
+ uint32_t v = *(uint32_t*)a;
+ return mp_obj_new_int(v);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read32_obj, stm_read32);
+
+STATIC mp_obj_t stm_write8(mp_obj_t addr, mp_obj_t val) {
+ uint32_t a = get_write_addr(addr, 1);
+ uint32_t v = mp_obj_get_int(val);
+ *(uint8_t*)a = v;
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write8_obj, stm_write8);
+
+STATIC mp_obj_t stm_write16(mp_obj_t addr, mp_obj_t val) {
+ uint32_t a = get_write_addr(addr, 2);
+ uint32_t v = mp_obj_get_int(val);
+ *(uint16_t*)a = v;
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write16_obj, stm_write16);
+
+STATIC mp_obj_t stm_write32(mp_obj_t addr, mp_obj_t val) {
+ uint32_t a = get_write_addr(addr, 4);
+ uint32_t v = mp_obj_get_int(val);
+ *(uint32_t*)a = v;
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write32_obj, stm_write32);
+
+STATIC const mp_map_elem_t stm_module_globals_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_stm) },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read8), (mp_obj_t)&stm_read8_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read16), (mp_obj_t)&stm_read16_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read32), (mp_obj_t)&stm_read32_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write8), (mp_obj_t)&stm_write8_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write16), (mp_obj_t)&stm_write16_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write32), (mp_obj_t)&stm_write32_obj },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GPIOA), MP_OBJ_NEW_SMALL_INT(GPIOA_BASE) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GPIOB), MP_OBJ_NEW_SMALL_INT(GPIOB_BASE) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GPIOC), MP_OBJ_NEW_SMALL_INT(GPIOC_BASE) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GPIOD), MP_OBJ_NEW_SMALL_INT(GPIOD_BASE) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GPIO_IDR), MP_OBJ_NEW_SMALL_INT(0x10) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GPIO_BSRRL), MP_OBJ_NEW_SMALL_INT(0x18) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GPIO_BSRRH), MP_OBJ_NEW_SMALL_INT(0x1a) },
+};
+
+STATIC const mp_obj_dict_t stm_module_globals = {
+ .base = {&mp_type_dict},
+ .map = {
+ .all_keys_are_qstrs = 1,
+ .table_is_fixed_array = 1,
+ .used = sizeof(stm_module_globals_table) / sizeof(mp_map_elem_t),
+ .alloc = sizeof(stm_module_globals_table) / sizeof(mp_map_elem_t),
+ .table = (mp_map_elem_t*)stm_module_globals_table,
+ },
+};
+
+const mp_obj_module_t stm_module = {
+ .base = { &mp_type_module },
+ .name = MP_QSTR_stm,
+ .globals = (mp_obj_dict_t*)&stm_module_globals,
+};
diff --git a/stmhal/modstm.h b/stmhal/modstm.h
new file mode 100644
index 0000000000..205cdd2a18
--- /dev/null
+++ b/stmhal/modstm.h
@@ -0,0 +1 @@
+extern const mp_obj_module_t stm_module;
diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h
index 08ba923e40..5529101425 100644
--- a/stmhal/mpconfigport.h
+++ b/stmhal/mpconfigport.h
@@ -31,12 +31,19 @@ extern const struct _mp_obj_fun_native_t mp_builtin_open_obj;
// extra built in modules to add to the list of known ones
extern const struct _mp_obj_module_t os_module;
extern const struct _mp_obj_module_t pyb_module;
+extern const struct _mp_obj_module_t stm_module;
extern const struct _mp_obj_module_t time_module;
#define MICROPY_EXTRA_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_module }, \
+// extra constants
+#define MICROPY_EXTRA_CONSTANTS \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_module }, \
+
// type definitions for the specific machine
#define BYTES_PER_WORD (4)
diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h
index 4eb6ea12a0..546b5b1430 100644
--- a/stmhal/qstrdefsport.h
+++ b/stmhal/qstrdefsport.h
@@ -130,3 +130,19 @@ Q(sleep)
// for input
Q(input)
+
+// for stm module
+Q(stm)
+Q(read8)
+Q(read16)
+Q(read32)
+Q(write8)
+Q(write16)
+Q(write32)
+Q(GPIOA)
+Q(GPIOB)
+Q(GPIOC)
+Q(GPIOD)
+Q(GPIO_IDR)
+Q(GPIO_BSRRL)
+Q(GPIO_BSRRH)
diff --git a/tests/basics/compare-multi.py b/tests/basics/compare-multi.py
new file mode 100644
index 0000000000..1abd18067d
--- /dev/null
+++ b/tests/basics/compare-multi.py
@@ -0,0 +1,4 @@
+print(1 < 2 < 3)
+print(1 < 2 < 3 < 4)
+print(1 > 2 < 3)
+print(1 < 2 > 3)
diff --git a/tests/basics/fun-defargs2.py b/tests/basics/fun-defargs2.py
index c9090a3cd2..8b72ed8b15 100644
--- a/tests/basics/fun-defargs2.py
+++ b/tests/basics/fun-defargs2.py
@@ -11,3 +11,9 @@ foo(1, b=333)
# override with keyword
foo(a=2, b=333)
+
+def foo2(a=1, b=2):
+ print(a, b)
+
+# default and keyword
+foo2(b='two')
diff --git a/unix/main.c b/unix/main.c
index bcc5ffcd76..f18e40a7fa 100644
--- a/unix/main.c
+++ b/unix/main.c
@@ -29,7 +29,8 @@
#include <readline/history.h>
#endif
-// Default emit options
+// Command line options, with their defaults
+bool compile_only = false;
uint emit_opt = MP_EMIT_OPT_NONE;
#if MICROPY_ENABLE_GC
@@ -87,6 +88,10 @@ STATIC void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind
return;
}
+ if (compile_only) {
+ return;
+ }
+
// execute it
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
@@ -226,6 +231,7 @@ int usage(char **argv) {
);
int impl_opts_cnt = 0;
printf(
+" compile-only -- parse and compile only\n"
" emit={bytecode,native,viper} -- set the default code emitter\n"
);
impl_opts_cnt++;
@@ -273,6 +279,8 @@ void pre_process_options(int argc, char **argv) {
exit(usage(argv));
}
if (0) {
+ } else if (strcmp(argv[a + 1], "compile-only") == 0) {
+ compile_only = true;
} else if (strcmp(argv[a + 1], "emit=bytecode") == 0) {
emit_opt = MP_EMIT_OPT_BYTE_CODE;
} else if (strcmp(argv[a + 1], "emit=native") == 0) {