heyuanjie87 5 лет назад
Родитель
Сommit
1cb032fb2b
100 измененных файлов с 3672 добавлено и 2254 удалено
  1. 46 47
      py/argcheck.c
  2. 16 11
      py/asmarm.c
  3. 2 0
      py/asmarm.h
  4. 3 3
      py/asmbase.c
  5. 2 2
      py/asmbase.h
  6. 2 2
      py/asmthumb.c
  7. 60 30
      py/asmthumb.h
  8. 20 15
      py/asmx64.c
  9. 26 21
      py/asmx64.h
  10. 33 26
      py/asmx86.c
  11. 23 20
      py/asmx86.h
  12. 3 3
      py/asmxtensa.c
  13. 9 0
      py/asmxtensa.h
  14. 25 25
      py/bc.c
  15. 83 83
      py/bc.h
  16. 5 5
      py/bc0.h
  17. 134 94
      py/binary.c
  18. 1 0
      py/builtin.h
  19. 15 8
      py/builtinevex.c
  20. 14 14
      py/builtinhelp.c
  21. 26 30
      py/builtinimport.c
  22. 183 136
      py/compile.c
  23. 52 16
      py/dynruntime.h
  24. 1 0
      py/dynruntime.mk
  25. 2 2
      py/emit.h
  26. 10 14
      py/emitbc.c
  27. 14 14
      py/emitglue.c
  28. 61 47
      py/emitinlinethumb.c
  29. 16 14
      py/emitinlinextensa.c
  30. 148 75
      py/emitnative.c
  31. 17 8
      py/formatfloat.c
  32. 1 1
      py/frozenmod.c
  33. 84 62
      py/gc.c
  34. 34 19
      py/grammar.h
  35. 41 20
      py/lexer.c
  36. 1 0
      py/lexer.h
  37. 205 0
      py/makecompresseddata.py
  38. 26 24
      py/makemoduledefs.py
  39. 68 53
      py/makeqstrdata.py
  40. 100 18
      py/makeqstrdefs.py
  41. 27 7
      py/makeversionhdr.py
  42. 21 18
      py/malloc.c
  43. 2 12
      py/map.c
  44. 114 22
      py/misc.h
  45. 0 5
      py/mkenv.mk
  46. 49 8
      py/mkrules.mk
  47. 1 1
      py/modarray.c
  48. 43 35
      py/modbuiltins.c
  49. 19 19
      py/modcmath.c
  50. 1 1
      py/modcollections.c
  51. 4 4
      py/modgc.c
  52. 14 9
      py/modio.c
  53. 57 20
      py/modmath.c
  54. 27 17
      py/modmicropython.c
  55. 6 6
      py/modstruct.c
  56. 8 8
      py/modsys.c
  57. 8 8
      py/modthread.c
  58. 8 8
      py/moduerrno.c
  59. 134 32
      py/mpconfig.h
  60. 6 0
      py/mphal.h
  61. 31 30
      py/mpprint.c
  62. 2 2
      py/mpprint.h
  63. 7 2
      py/mpstate.h
  64. 4 4
      py/mpthread.h
  65. 73 50
      py/mpz.c
  66. 13 7
      py/mpz.h
  67. 44 46
      py/nativeglue.c
  68. 6 6
      py/nativeglue.h
  69. 1 1
      py/nlr.c
  70. 4 0
      py/nlr.h
  71. 72 72
      py/nlrpowerpc.c
  72. 80 80
      py/nlrthumb.c
  73. 52 52
      py/nlrx64.c
  74. 29 31
      py/nlrx86.c
  75. 29 29
      py/nlrxtensa.c
  76. 206 133
      py/obj.c
  77. 249 108
      py/obj.h
  78. 28 23
      py/objarray.c
  79. 10 0
      py/objarray.h
  80. 2 2
      py/objattrtuple.c
  81. 20 7
      py/objbool.c
  82. 4 4
      py/objboundmeth.c
  83. 2 2
      py/objcell.c
  84. 3 2
      py/objclosure.c
  85. 27 17
      py/objcomplex.c
  86. 3 3
      py/objdeque.c
  87. 51 29
      py/objdict.c
  88. 4 4
      py/objenumerate.c
  89. 114 39
      py/objexcept.c
  90. 8 8
      py/objexcept.h
  91. 62 53
      py/objfloat.c
  92. 21 13
      py/objfun.c
  93. 20 18
      py/objgenerator.c
  94. 2 2
      py/objgetitemiter.c
  95. 34 30
      py/objint.c
  96. 6 6
      py/objint.h
  97. 18 12
      py/objint_longlong.c
  98. 66 30
      py/objint_mpz.c
  99. 39 33
      py/objlist.c
  100. 65 62
      py/objmodule.c

+ 46 - 47
py/argcheck.c

@@ -38,40 +38,40 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
     size_t n_args_max = (sig >> 1) & 0xffff;
 
     if (n_kw && !takes_kw) {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_arg_error_terse_mismatch();
-        } else {
-            mp_raise_TypeError("function doesn't take keyword arguments");
-        }
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_arg_error_terse_mismatch();
+        #else
+        mp_raise_TypeError(MP_ERROR_TEXT("function doesn't take keyword arguments"));
+        #endif
     }
 
     if (n_args_min == n_args_max) {
         if (n_args != n_args_min) {
-            if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-                mp_arg_error_terse_mismatch();
-            } else {
-                nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                    "function takes %d positional arguments but %d were given",
-                    n_args_min, n_args));
-            }
+            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+            mp_arg_error_terse_mismatch();
+            #else
+            mp_raise_msg_varg(&mp_type_TypeError,
+                MP_ERROR_TEXT("function takes %d positional arguments but %d were given"),
+                n_args_min, n_args);
+            #endif
         }
     } else {
         if (n_args < n_args_min) {
-            if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-                mp_arg_error_terse_mismatch();
-            } else {
-                nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                    "function missing %d required positional arguments",
-                    n_args_min - n_args));
-            }
+            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+            mp_arg_error_terse_mismatch();
+            #else
+            mp_raise_msg_varg(&mp_type_TypeError,
+                MP_ERROR_TEXT("function missing %d required positional arguments"),
+                n_args_min - n_args);
+            #endif
         } else if (n_args > n_args_max) {
-            if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-                mp_arg_error_terse_mismatch();
-            } else {
-                nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                    "function expected at most %d arguments, got %d",
-                    n_args_max, n_args));
-            }
+            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+            mp_arg_error_terse_mismatch();
+            #else
+            mp_raise_msg_varg(&mp_type_TypeError,
+                MP_ERROR_TEXT("function expected at most %d arguments, got %d"),
+                n_args_max, n_args);
+            #endif
         }
     }
 }
@@ -90,12 +90,11 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
             mp_map_elem_t *kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qst), MP_MAP_LOOKUP);
             if (kw == NULL) {
                 if (allowed[i].flags & MP_ARG_REQUIRED) {
-                    if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-                        mp_arg_error_terse_mismatch();
-                    } else {
-                        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                            "'%q' argument required", allowed[i].qst));
-                    }
+                    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+                    mp_arg_error_terse_mismatch();
+                    #else
+                    mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("'%q' argument required"), allowed[i].qst);
+                    #endif
                 }
                 out_vals[i] = allowed[i].defval;
                 continue;
@@ -114,21 +113,21 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
         }
     }
     if (pos_found < n_pos) {
-        extra_positional:
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_arg_error_terse_mismatch();
-        } else {
-            // TODO better error message
-            mp_raise_TypeError("extra positional arguments given");
-        }
+    extra_positional:
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_arg_error_terse_mismatch();
+        #else
+        // TODO better error message
+        mp_raise_TypeError(MP_ERROR_TEXT("extra positional arguments given"));
+        #endif
     }
     if (kws_found < kws->used) {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_arg_error_terse_mismatch();
-        } else {
-            // TODO better error message
-            mp_raise_TypeError("extra keyword arguments given");
-        }
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_arg_error_terse_mismatch();
+        #else
+        // TODO better error message
+        mp_raise_TypeError(MP_ERROR_TEXT("extra keyword arguments given"));
+        #endif
     }
 }
 
@@ -139,11 +138,11 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args,
 }
 
 NORETURN void mp_arg_error_terse_mismatch(void) {
-    mp_raise_TypeError("argument num/types mismatch");
+    mp_raise_TypeError(MP_ERROR_TEXT("argument num/types mismatch"));
 }
 
 #if MICROPY_CPYTHON_COMPAT
 NORETURN void mp_arg_error_unimpl_kw(void) {
-    mp_raise_NotImplementedError("keyword argument(s) not yet implemented - use normal args instead");
+    mp_raise_NotImplementedError(MP_ERROR_TEXT("keyword argument(s) not yet implemented - use normal args instead"));
 }
 #endif

+ 16 - 11
py/asmarm.c

@@ -40,20 +40,20 @@
 
 void asm_arm_end_pass(asm_arm_t *as) {
     if (as->base.pass == MP_ASM_PASS_EMIT) {
-#if defined(__linux__) && defined(__GNUC__)
+        #if defined(__linux__) && defined(__GNUC__)
         char *start = mp_asm_base_get_code(&as->base);
         char *end = start + mp_asm_base_get_code_size(&as->base);
         __builtin___clear_cache(start, end);
-#elif defined(__arm__)
+        #elif defined(__arm__)
         // flush I- and D-cache
-        asm volatile(
-                "0:"
-                "mrc p15, 0, r15, c7, c10, 3\n"
-                "bne 0b\n"
-                "mov r0, #0\n"
-                "mcr p15, 0, r0, c7, c7, 0\n"
-                : : : "r0", "cc");
-#endif
+        asm volatile (
+            "0:"
+            "mrc p15, 0, r15, c7, c10, 3\n"
+            "bne 0b\n"
+            "mov r0, #0\n"
+            "mcr p15, 0, r0, c7, c7, 0\n"
+            : : : "r0", "cc");
+        #endif
     }
 }
 
@@ -61,7 +61,7 @@ void asm_arm_end_pass(asm_arm_t *as) {
 STATIC void emit(asm_arm_t *as, uint op) {
     uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);
     if (c != NULL) {
-        *(uint32_t*)c = op;
+        *(uint32_t *)c = op;
     }
 }
 
@@ -303,6 +303,11 @@ void asm_arm_lsl_reg_reg(asm_arm_t *as, uint rd, uint rs) {
     emit_al(as, 0x1a00010 | (rd << 12) | (rs << 8) | rd);
 }
 
+void asm_arm_lsr_reg_reg(asm_arm_t *as, uint rd, uint rs) {
+    // mov rd, rd, lsr rs
+    emit_al(as, 0x1a00030 | (rd << 12) | (rs << 8) | rd);
+}
+
 void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs) {
     // mov rd, rd, asr rs
     emit_al(as, 0x1a00050 | (rd << 12) | (rs << 8) | rd);

+ 2 - 0
py/asmarm.h

@@ -101,6 +101,7 @@ void asm_arm_orr_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
 void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num);
 void asm_arm_mov_reg_pcrel(asm_arm_t *as, uint reg_dest, uint label);
 void asm_arm_lsl_reg_reg(asm_arm_t *as, uint rd, uint rs);
+void asm_arm_lsr_reg_reg(asm_arm_t *as, uint rd, uint rs);
 void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs);
 
 // memory
@@ -187,6 +188,7 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src);
 #define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_arm_mov_reg_pcrel((as), (reg_dest), (label))
 
 #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_arm_lsl_reg_reg((as), (reg_dest), (reg_shift))
+#define ASM_LSR_REG_REG(as, reg_dest, reg_shift) asm_arm_lsr_reg_reg((as), (reg_dest), (reg_shift))
 #define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_arm_asr_reg_reg((as), (reg_dest), (reg_shift))
 #define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_arm_orr_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
 #define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_arm_eor_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))

+ 3 - 3
py/asmbase.c

@@ -51,7 +51,7 @@ void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) {
         memset(as->label_offsets, -1, as->max_num_labels * sizeof(size_t));
     } else {
         // allocating executable RAM is platform specific
-        MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
+        MP_PLAT_ALLOC_EXEC(as->code_offset, (void **)&as->code_base, &as->code_size);
         assert(as->code_base != NULL);
     }
     as->pass = pass;
@@ -84,12 +84,12 @@ void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label) {
 }
 
 // align must be a multiple of 2
-void mp_asm_base_align(mp_asm_base_t* as, unsigned int align) {
+void mp_asm_base_align(mp_asm_base_t *as, unsigned int align) {
     as->code_offset = (as->code_offset + align - 1) & (~(align - 1));
 }
 
 // this function assumes a little endian machine
-void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val) {
+void mp_asm_base_data(mp_asm_base_t *as, unsigned int bytesize, uintptr_t val) {
     uint8_t *c = mp_asm_base_get_cur_to_write_bytes(as, bytesize);
     if (c != NULL) {
         for (unsigned int i = 0; i < bytesize; i++) {

+ 2 - 2
py/asmbase.h

@@ -47,8 +47,8 @@ void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code);
 void mp_asm_base_start_pass(mp_asm_base_t *as, int pass);
 uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write);
 void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label);
-void mp_asm_base_align(mp_asm_base_t* as, unsigned int align);
-void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val);
+void mp_asm_base_align(mp_asm_base_t *as, unsigned int align);
+void mp_asm_base_data(mp_asm_base_t *as, unsigned int bytesize, uintptr_t val);
 
 static inline size_t mp_asm_base_get_code_pos(mp_asm_base_t *as) {
     return as->code_offset;

+ 2 - 2
py/asmthumb.c

@@ -377,7 +377,7 @@ void asm_thumb_b_label(asm_thumb_t *as, uint label) {
         }
     } else {
         // is a forwards jump, so need to assume it's large
-        large_jump:
+    large_jump:
         asm_thumb_op32(as, OP_BW_HI(rel), OP_BW_LO(rel));
     }
 }
@@ -396,7 +396,7 @@ void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) {
         }
     } else {
         // is a forwards jump, so need to assume it's large
-        large_jump:
+    large_jump:
         asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel));
     }
 }

+ 60 - 30
py/asmthumb.h

@@ -80,12 +80,19 @@ void asm_thumb_exit(asm_thumb_t *as);
 
 #define ASM_THUMB_OP_IT (0xbf00)
 #define ASM_THUMB_OP_ITE_EQ (0xbf0c)
+#define ASM_THUMB_OP_ITE_NE (0xbf14)
 #define ASM_THUMB_OP_ITE_CS (0xbf2c)
+#define ASM_THUMB_OP_ITE_CC (0xbf34)
 #define ASM_THUMB_OP_ITE_MI (0xbf4c)
+#define ASM_THUMB_OP_ITE_PL (0xbf54)
 #define ASM_THUMB_OP_ITE_VS (0xbf6c)
+#define ASM_THUMB_OP_ITE_VC (0xbf74)
 #define ASM_THUMB_OP_ITE_HI (0xbf8c)
+#define ASM_THUMB_OP_ITE_LS (0xbf94)
 #define ASM_THUMB_OP_ITE_GE (0xbfac)
+#define ASM_THUMB_OP_ITE_LT (0xbfb4)
 #define ASM_THUMB_OP_ITE_GT (0xbfcc)
+#define ASM_THUMB_OP_ITE_LE (0xbfd4)
 
 #define ASM_THUMB_OP_NOP        (0xbf00)
 #define ASM_THUMB_OP_WFI        (0xbf30)
@@ -95,8 +102,9 @@ void asm_thumb_exit(asm_thumb_t *as);
 void asm_thumb_op16(asm_thumb_t *as, uint op);
 void asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2);
 
-static inline void asm_thumb_it_cc(asm_thumb_t *as, uint cc, uint mask)
-    { asm_thumb_op16(as, ASM_THUMB_OP_IT | (cc << 4) | mask); }
+static inline void asm_thumb_it_cc(asm_thumb_t *as, uint cc, uint mask) {
+    asm_thumb_op16(as, ASM_THUMB_OP_IT | (cc << 4) | mask);
+}
 
 // FORMAT 1: move shifted register
 
@@ -129,14 +137,18 @@ static inline void asm_thumb_format_2(asm_thumb_t *as, uint op, uint rlo_dest, u
     asm_thumb_op16(as, ASM_THUMB_FORMAT_2_ENCODE(op, rlo_dest, rlo_src, src_b));
 }
 
-static inline void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b)
-    { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_ADD | ASM_THUMB_FORMAT_2_REG_OPERAND, rlo_dest, rlo_src_a, rlo_src_b); }
-static inline void asm_thumb_add_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, int i3_src)
-    { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_ADD | ASM_THUMB_FORMAT_2_IMM_OPERAND, rlo_dest, rlo_src_a, i3_src); }
-static inline void asm_thumb_sub_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b)
-    { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_SUB | ASM_THUMB_FORMAT_2_REG_OPERAND, rlo_dest, rlo_src_a, rlo_src_b); }
-static inline void asm_thumb_sub_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, int i3_src)
-    { asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_SUB | ASM_THUMB_FORMAT_2_IMM_OPERAND, rlo_dest, rlo_src_a, i3_src); }
+static inline void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {
+    asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_ADD | ASM_THUMB_FORMAT_2_REG_OPERAND, rlo_dest, rlo_src_a, rlo_src_b);
+}
+static inline void asm_thumb_add_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, int i3_src) {
+    asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_ADD | ASM_THUMB_FORMAT_2_IMM_OPERAND, rlo_dest, rlo_src_a, i3_src);
+}
+static inline void asm_thumb_sub_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {
+    asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_SUB | ASM_THUMB_FORMAT_2_REG_OPERAND, rlo_dest, rlo_src_a, rlo_src_b);
+}
+static inline void asm_thumb_sub_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, int i3_src) {
+    asm_thumb_format_2(as, ASM_THUMB_FORMAT_2_SUB | ASM_THUMB_FORMAT_2_IMM_OPERAND, rlo_dest, rlo_src_a, i3_src);
+}
 
 // FORMAT 3: move/compare/add/subtract immediate
 // These instructions all do zero extension of the i8 value
@@ -153,10 +165,18 @@ static inline void asm_thumb_format_3(asm_thumb_t *as, uint op, uint rlo, int i8
     asm_thumb_op16(as, ASM_THUMB_FORMAT_3_ENCODE(op, rlo, i8));
 }
 
-static inline void asm_thumb_mov_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_MOV, rlo, i8); }
-static inline void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_CMP, rlo, i8); }
-static inline void asm_thumb_add_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_ADD, rlo, i8); }
-static inline void asm_thumb_sub_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_SUB, rlo, i8); }
+static inline void asm_thumb_mov_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {
+    asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_MOV, rlo, i8);
+}
+static inline void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {
+    asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_CMP, rlo, i8);
+}
+static inline void asm_thumb_add_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {
+    asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_ADD, rlo, i8);
+}
+static inline void asm_thumb_sub_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {
+    asm_thumb_format_3(as, ASM_THUMB_FORMAT_3_SUB, rlo, i8);
+}
 
 // FORMAT 4: ALU operations
 
@@ -179,7 +199,9 @@ static inline void asm_thumb_sub_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm
 
 void asm_thumb_format_4(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src);
 
-static inline void asm_thumb_cmp_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src) { asm_thumb_format_4(as, ASM_THUMB_FORMAT_4_CMP, rlo_dest, rlo_src); }
+static inline void asm_thumb_cmp_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src) {
+    asm_thumb_format_4(as, ASM_THUMB_FORMAT_4_CMP, rlo_dest, rlo_src);
+}
 
 // FORMAT 5: hi register operations (add, cmp, mov, bx)
 // For add/cmp/mov, at least one of the args must be a high register
@@ -219,21 +241,28 @@ static inline void asm_thumb_bx_reg(asm_thumb_t *as, uint r_src) {
 #define ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset) \
     ((op) | (((offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
 
-static inline void asm_thumb_format_9_10(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_base, uint offset)
-    { asm_thumb_op16(as, ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset)); }
-
-static inline void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset)
-    { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_src, rlo_base, word_offset); }
-static inline void asm_thumb_strb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset)
-    { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_src, rlo_base, byte_offset); }
-static inline void asm_thumb_strh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset)
-    { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_STRH, rlo_src, rlo_base, byte_offset); }
-static inline void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset)
-    { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_dest, rlo_base, word_offset); }
-static inline void asm_thumb_ldrb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset)
-    { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER , rlo_dest, rlo_base, byte_offset); }
-static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset)
-    { asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_LDRH, rlo_dest, rlo_base, byte_offset); }
+static inline void asm_thumb_format_9_10(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_base, uint offset) {
+    asm_thumb_op16(as, ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset));
+}
+
+static inline void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset) {
+    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_src, rlo_base, word_offset);
+}
+static inline void asm_thumb_strb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) {
+    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_src, rlo_base, byte_offset);
+}
+static inline void asm_thumb_strh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) {
+    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_STRH, rlo_src, rlo_base, byte_offset);
+}
+static inline void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset) {
+    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_dest, rlo_base, word_offset);
+}
+static inline void asm_thumb_ldrb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) {
+    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_dest, rlo_base, byte_offset);
+}
+static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) {
+    asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_LDRH, rlo_dest, rlo_base, byte_offset);
+}
 
 // TODO convert these to above format style
 
@@ -323,6 +352,7 @@ void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp); // convenien
 #define ASM_MOV_REG_PCREL(as, rlo_dest, label) asm_thumb_mov_reg_pcrel((as), (rlo_dest), (label))
 
 #define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSL, (reg_dest), (reg_shift))
+#define ASM_LSR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSR, (reg_dest), (reg_shift))
 #define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ASR, (reg_dest), (reg_shift))
 #define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ORR, (reg_dest), (reg_src))
 #define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_EOR, (reg_dest), (reg_src))

+ 20 - 15
py/asmx64.c

@@ -63,15 +63,16 @@
 #define OPCODE_SUB_R64_FROM_RM64 (0x29)
 #define OPCODE_SUB_I32_FROM_RM64 (0x81) /* /5 */
 #define OPCODE_SUB_I8_FROM_RM64  (0x83) /* /5 */
-//#define OPCODE_SHL_RM32_BY_I8    (0xc1) /* /4 */
-//#define OPCODE_SHR_RM32_BY_I8    (0xc1) /* /5 */
-//#define OPCODE_SAR_RM32_BY_I8    (0xc1) /* /7 */
+// #define OPCODE_SHL_RM32_BY_I8    (0xc1) /* /4 */
+// #define OPCODE_SHR_RM32_BY_I8    (0xc1) /* /5 */
+// #define OPCODE_SAR_RM32_BY_I8    (0xc1) /* /7 */
 #define OPCODE_SHL_RM64_CL       (0xd3) /* /4 */
+#define OPCODE_SHR_RM64_CL       (0xd3) /* /5 */
 #define OPCODE_SAR_RM64_CL       (0xd3) /* /7 */
-//#define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */
-//#define OPCODE_CMP_I8_WITH_RM32  (0x83) /* /7 */
+// #define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */
+// #define OPCODE_CMP_I8_WITH_RM32  (0x83) /* /7 */
 #define OPCODE_CMP_R64_WITH_RM64 (0x39) /* /r */
-//#define OPCODE_CMP_RM32_WITH_R32 (0x3b)
+// #define OPCODE_CMP_RM32_WITH_R32 (0x3b)
 #define OPCODE_TEST_R8_WITH_RM8  (0x84) /* /r */
 #define OPCODE_TEST_R64_WITH_RM64 (0x85) /* /r */
 #define OPCODE_JMP_REL8          (0xeb)
@@ -123,14 +124,14 @@ static inline byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int n) {
 }
 
 STATIC void asm_x64_write_byte_1(asm_x64_t *as, byte b1) {
-    byte* c = asm_x64_get_cur_to_write_bytes(as, 1);
+    byte *c = asm_x64_get_cur_to_write_bytes(as, 1);
     if (c != NULL) {
         c[0] = b1;
     }
 }
 
 STATIC void asm_x64_write_byte_2(asm_x64_t *as, byte b1, byte b2) {
-    byte* c = asm_x64_get_cur_to_write_bytes(as, 2);
+    byte *c = asm_x64_get_cur_to_write_bytes(as, 2);
     if (c != NULL) {
         c[0] = b1;
         c[1] = b2;
@@ -138,7 +139,7 @@ STATIC void asm_x64_write_byte_2(asm_x64_t *as, byte b1, byte b2) {
 }
 
 STATIC void asm_x64_write_byte_3(asm_x64_t *as, byte b1, byte b2, byte b3) {
-    byte* c = asm_x64_get_cur_to_write_bytes(as, 3);
+    byte *c = asm_x64_get_cur_to_write_bytes(as, 3);
     if (c != NULL) {
         c[0] = b1;
         c[1] = b2;
@@ -147,7 +148,7 @@ STATIC void asm_x64_write_byte_3(asm_x64_t *as, byte b1, byte b2, byte b3) {
 }
 
 STATIC void asm_x64_write_word32(asm_x64_t *as, int w32) {
-    byte* c = asm_x64_get_cur_to_write_bytes(as, 4);
+    byte *c = asm_x64_get_cur_to_write_bytes(as, 4);
     if (c != NULL) {
         c[0] = IMM32_L0(w32);
         c[1] = IMM32_L1(w32);
@@ -157,7 +158,7 @@ STATIC void asm_x64_write_word32(asm_x64_t *as, int w32) {
 }
 
 STATIC void asm_x64_write_word64(asm_x64_t *as, int64_t w64) {
-    byte* c = asm_x64_get_cur_to_write_bytes(as, 8);
+    byte *c = asm_x64_get_cur_to_write_bytes(as, 8);
     if (c != NULL) {
         c[0] = IMM32_L0(w64);
         c[1] = IMM32_L1(w64);
@@ -378,11 +379,15 @@ void asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
     asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_XOR_R64_TO_RM64);
 }
 
-void asm_x64_shl_r64_cl(asm_x64_t* as, int dest_r64) {
+void asm_x64_shl_r64_cl(asm_x64_t *as, int dest_r64) {
     asm_x64_generic_r64_r64(as, dest_r64, 4, OPCODE_SHL_RM64_CL);
 }
 
-void asm_x64_sar_r64_cl(asm_x64_t* as, int dest_r64) {
+void asm_x64_shr_r64_cl(asm_x64_t *as, int dest_r64) {
+    asm_x64_generic_r64_r64(as, dest_r64, 5, OPCODE_SHR_RM64_CL);
+}
+
+void asm_x64_sar_r64_cl(asm_x64_t *as, int dest_r64) {
     asm_x64_generic_r64_r64(as, dest_r64, 7, OPCODE_SAR_RM64_CL);
 }
 
@@ -500,7 +505,7 @@ void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) {
         }
     } else {
         // is a forwards jump, so need to assume it's large
-        large_jump:
+    large_jump:
         rel -= 5;
         asm_x64_write_byte_1(as, OPCODE_JMP_REL32);
         asm_x64_write_word32(as, rel);
@@ -522,7 +527,7 @@ void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) {
         }
     } else {
         // is a forwards jump, so need to assume it's large
-        large_jump:
+    large_jump:
         rel -= 6;
         asm_x64_write_byte_2(as, OPCODE_JCC_REL32_A, OPCODE_JCC_REL32_B | jcc_type);
         asm_x64_write_word32(as, rel);

+ 26 - 21
py/asmx64.h

@@ -61,10 +61,13 @@
 
 // condition codes, used for jcc and setcc (despite their j-name!)
 #define ASM_X64_CC_JB  (0x2) // below, unsigned
+#define ASM_X64_CC_JAE (0x3) // above or equal, unsigned
 #define ASM_X64_CC_JZ  (0x4)
 #define ASM_X64_CC_JE  (0x4)
 #define ASM_X64_CC_JNZ (0x5)
 #define ASM_X64_CC_JNE (0x5)
+#define ASM_X64_CC_JBE (0x6) // below or equal, unsigned
+#define ASM_X64_CC_JA  (0x7) // above, unsigned
 #define ASM_X64_CC_JL  (0xc) // less, signed
 #define ASM_X64_CC_JGE (0xd) // greater or equal, signed
 #define ASM_X64_CC_JLE (0xe) // less or equal, signed
@@ -79,12 +82,12 @@ static inline void asm_x64_end_pass(asm_x64_t *as) {
     (void)as;
 }
 
-void asm_x64_nop(asm_x64_t* as);
-void asm_x64_push_r64(asm_x64_t* as, int src_r64);
-void asm_x64_pop_r64(asm_x64_t* as, int dest_r64);
-void asm_x64_mov_r64_r64(asm_x64_t* as, int dest_r64, int src_r64);
+void asm_x64_nop(asm_x64_t *as);
+void asm_x64_push_r64(asm_x64_t *as, int src_r64);
+void asm_x64_pop_r64(asm_x64_t *as, int dest_r64);
+void asm_x64_mov_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
 size_t asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64);
-void asm_x64_mov_i64_to_r64(asm_x64_t* as, int64_t src_i64, int dest_r64);
+void asm_x64_mov_i64_to_r64(asm_x64_t *as, int64_t src_i64, int dest_r64);
 void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64);
 void asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
 void asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
@@ -97,25 +100,26 @@ void asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest
 void asm_x64_and_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
 void asm_x64_or_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
 void asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
-void asm_x64_shl_r64_cl(asm_x64_t* as, int dest_r64);
-void asm_x64_sar_r64_cl(asm_x64_t* as, int dest_r64);
-void asm_x64_add_r64_r64(asm_x64_t* as, int dest_r64, int src_r64);
-void asm_x64_sub_r64_r64(asm_x64_t* as, int dest_r64, int src_r64);
-void asm_x64_mul_r64_r64(asm_x64_t* as, int dest_r64, int src_r64);
-void asm_x64_cmp_r64_with_r64(asm_x64_t* as, int src_r64_a, int src_r64_b);
-void asm_x64_test_r8_with_r8(asm_x64_t* as, int src_r64_a, int src_r64_b);
+void asm_x64_shl_r64_cl(asm_x64_t *as, int dest_r64);
+void asm_x64_shr_r64_cl(asm_x64_t *as, int dest_r64);
+void asm_x64_sar_r64_cl(asm_x64_t *as, int dest_r64);
+void asm_x64_add_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
+void asm_x64_sub_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
+void asm_x64_mul_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
+void asm_x64_cmp_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b);
+void asm_x64_test_r8_with_r8(asm_x64_t *as, int src_r64_a, int src_r64_b);
 void asm_x64_test_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b);
-void asm_x64_setcc_r8(asm_x64_t* as, int jcc_type, int dest_r8);
+void asm_x64_setcc_r8(asm_x64_t *as, int jcc_type, int dest_r8);
 void asm_x64_jmp_reg(asm_x64_t *as, int src_r64);
-void asm_x64_jmp_label(asm_x64_t* as, mp_uint_t label);
-void asm_x64_jcc_label(asm_x64_t* as, int jcc_type, mp_uint_t label);
-void asm_x64_entry(asm_x64_t* as, int num_locals);
-void asm_x64_exit(asm_x64_t* as);
-void asm_x64_mov_local_to_r64(asm_x64_t* as, int src_local_num, int dest_r64);
-void asm_x64_mov_r64_to_local(asm_x64_t* as, int src_r64, int dest_local_num);
-void asm_x64_mov_local_addr_to_r64(asm_x64_t* as, int local_num, int dest_r64);
+void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label);
+void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label);
+void asm_x64_entry(asm_x64_t *as, int num_locals);
+void asm_x64_exit(asm_x64_t *as);
+void asm_x64_mov_local_to_r64(asm_x64_t *as, int src_local_num, int dest_r64);
+void asm_x64_mov_r64_to_local(asm_x64_t *as, int src_r64, int dest_local_num);
+void asm_x64_mov_local_addr_to_r64(asm_x64_t *as, int local_num, int dest_r64);
 void asm_x64_mov_reg_pcrel(asm_x64_t *as, int dest_r64, mp_uint_t label);
-void asm_x64_call_ind(asm_x64_t* as, size_t fun_id, int temp_r32);
+void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r32);
 
 // Holds a pointer to mp_fun_table
 #define ASM_X64_REG_FUN_TABLE ASM_X64_REG_RBP
@@ -190,6 +194,7 @@ void asm_x64_call_ind(asm_x64_t* as, size_t fun_id, int temp_r32);
 #define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_x64_mov_reg_pcrel((as), (reg_dest), (label))
 
 #define ASM_LSL_REG(as, reg) asm_x64_shl_r64_cl((as), (reg))
+#define ASM_LSR_REG(as, reg) asm_x64_shr_r64_cl((as), (reg))
 #define ASM_ASR_REG(as, reg) asm_x64_sar_r64_cl((as), (reg))
 #define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_x64_or_r64_r64((as), (reg_dest), (reg_src))
 #define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_x64_xor_r64_r64((as), (reg_dest), (reg_src))

+ 33 - 26
py/asmx86.c

@@ -41,13 +41,13 @@
 
 #define OPCODE_NOP               (0x90)
 #define OPCODE_PUSH_R32          (0x50)
-//#define OPCODE_PUSH_I32          (0x68)
-//#define OPCODE_PUSH_M32          (0xff) /* /6 */
+// #define OPCODE_PUSH_I32          (0x68)
+// #define OPCODE_PUSH_M32          (0xff) /* /6 */
 #define OPCODE_POP_R32           (0x58)
 #define OPCODE_RET               (0xc3)
-//#define OPCODE_MOV_I8_TO_R8      (0xb0) /* +rb */
+// #define OPCODE_MOV_I8_TO_R8      (0xb0) /* +rb */
 #define OPCODE_MOV_I32_TO_R32    (0xb8)
-//#define OPCODE_MOV_I32_TO_RM32   (0xc7)
+// #define OPCODE_MOV_I32_TO_RM32   (0xc7)
 #define OPCODE_MOV_R8_TO_RM8     (0x88) /* /r */
 #define OPCODE_MOV_R32_TO_RM32   (0x89) /* /r */
 #define OPCODE_MOV_RM32_TO_R32   (0x8b) /* /r */
@@ -63,15 +63,16 @@
 #define OPCODE_SUB_R32_FROM_RM32 (0x29)
 #define OPCODE_SUB_I32_FROM_RM32 (0x81) /* /5 */
 #define OPCODE_SUB_I8_FROM_RM32  (0x83) /* /5 */
-//#define OPCODE_SHL_RM32_BY_I8    (0xc1) /* /4 */
-//#define OPCODE_SHR_RM32_BY_I8    (0xc1) /* /5 */
-//#define OPCODE_SAR_RM32_BY_I8    (0xc1) /* /7 */
+// #define OPCODE_SHL_RM32_BY_I8    (0xc1) /* /4 */
+// #define OPCODE_SHR_RM32_BY_I8    (0xc1) /* /5 */
+// #define OPCODE_SAR_RM32_BY_I8    (0xc1) /* /7 */
 #define OPCODE_SHL_RM32_CL       (0xd3) /* /4 */
+#define OPCODE_SHR_RM32_CL       (0xd3) /* /5 */
 #define OPCODE_SAR_RM32_CL       (0xd3) /* /7 */
-//#define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */
-//#define OPCODE_CMP_I8_WITH_RM32  (0x83) /* /7 */
+// #define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */
+// #define OPCODE_CMP_I8_WITH_RM32  (0x83) /* /7 */
 #define OPCODE_CMP_R32_WITH_RM32 (0x39)
-//#define OPCODE_CMP_RM32_WITH_R32 (0x3b)
+// #define OPCODE_CMP_RM32_WITH_R32 (0x3b)
 #define OPCODE_TEST_R8_WITH_RM8  (0x84) /* /r */
 #define OPCODE_TEST_R32_WITH_RM32 (0x85) /* /r */
 #define OPCODE_JMP_REL8          (0xeb)
@@ -103,14 +104,14 @@
 #define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)
 
 STATIC void asm_x86_write_byte_1(asm_x86_t *as, byte b1) {
-    byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 1);
+    byte *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 1);
     if (c != NULL) {
         c[0] = b1;
     }
 }
 
 STATIC void asm_x86_write_byte_2(asm_x86_t *as, byte b1, byte b2) {
-    byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 2);
+    byte *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 2);
     if (c != NULL) {
         c[0] = b1;
         c[1] = b2;
@@ -118,7 +119,7 @@ STATIC void asm_x86_write_byte_2(asm_x86_t *as, byte b1, byte b2) {
 }
 
 STATIC void asm_x86_write_byte_3(asm_x86_t *as, byte b1, byte b2, byte b3) {
-    byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 3);
+    byte *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 3);
     if (c != NULL) {
         c[0] = b1;
         c[1] = b2;
@@ -127,7 +128,7 @@ STATIC void asm_x86_write_byte_3(asm_x86_t *as, byte b1, byte b2, byte b3) {
 }
 
 STATIC void asm_x86_write_word32(asm_x86_t *as, int w32) {
-    byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);
+    byte *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);
     if (c != NULL) {
         c[0] = IMM32_L0(w32);
         c[1] = IMM32_L1(w32);
@@ -255,11 +256,15 @@ void asm_x86_xor_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {
     asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_XOR_R32_TO_RM32);
 }
 
-void asm_x86_shl_r32_cl(asm_x86_t* as, int dest_r32) {
+void asm_x86_shl_r32_cl(asm_x86_t *as, int dest_r32) {
     asm_x86_generic_r32_r32(as, dest_r32, 4, OPCODE_SHL_RM32_CL);
 }
 
-void asm_x86_sar_r32_cl(asm_x86_t* as, int dest_r32) {
+void asm_x86_shr_r32_cl(asm_x86_t *as, int dest_r32) {
+    asm_x86_generic_r32_r32(as, dest_r32, 5, OPCODE_SHR_RM32_CL);
+}
+
+void asm_x86_sar_r32_cl(asm_x86_t *as, int dest_r32) {
     asm_x86_generic_r32_r32(as, dest_r32, 7, OPCODE_SAR_RM32_CL);
 }
 
@@ -368,7 +373,7 @@ void asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label) {
         }
     } else {
         // is a forwards jump, so need to assume it's large
-        large_jump:
+    large_jump:
         rel -= 5;
         asm_x86_write_byte_1(as, OPCODE_JMP_REL32);
         asm_x86_write_word32(as, rel);
@@ -390,7 +395,7 @@ void asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label) {
         }
     } else {
         // is a forwards jump, so need to assume it's large
-        large_jump:
+    large_jump:
         rel -= 6;
         asm_x86_write_byte_2(as, OPCODE_JCC_REL32_A, OPCODE_JCC_REL32_B | jcc_type);
         asm_x86_write_word32(as, rel);
@@ -403,7 +408,7 @@ void asm_x86_entry(asm_x86_t *as, int num_locals) {
     asm_x86_push_r32(as, ASM_X86_REG_EBX);
     asm_x86_push_r32(as, ASM_X86_REG_ESI);
     asm_x86_push_r32(as, ASM_X86_REG_EDI);
-    num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary
+    num_locals |= 3; // make it odd so stack is aligned on 16 byte boundary
     asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, num_locals * WORD_SIZE);
     as->num_locals = num_locals;
 }
@@ -488,8 +493,7 @@ void asm_x86_push_local(asm_x86_t *as, int local_num) {
     asm_x86_push_disp(as, ASM_X86_REG_ESP, asm_x86_local_offset_from_esp(as, local_num));
 }
 
-void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32)
-{
+void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32) {
     asm_x86_mov_r32_r32(as, temp_r32, ASM_X86_REG_ESP);
     asm_x86_add_i32_to_r32(as, asm_x86_local_offset_from_esp(as, local_num), temp_r32);
     asm_x86_push_r32(as, temp_r32);
@@ -497,11 +501,14 @@ void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32)
 #endif
 
 void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r32) {
-    // TODO align stack on 16-byte boundary before the call
-    assert(n_args <= 5);
-    if (n_args > 4) {
-        asm_x86_push_r32(as, ASM_X86_REG_ARG_5);
+    assert(n_args <= 4);
+
+    // Align stack on 16-byte boundary during the call
+    unsigned int align = ((n_args + 3) & ~3) - n_args;
+    if (align) {
+        asm_x86_sub_r32_i32(as, ASM_X86_REG_ESP, align * WORD_SIZE);
     }
+
     if (n_args > 3) {
         asm_x86_push_r32(as, ASM_X86_REG_ARG_4);
     }
@@ -521,7 +528,7 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r
 
     // the caller must clean up the stack
     if (n_args > 0) {
-        asm_x86_add_i32_to_r32(as, WORD_SIZE * n_args, ASM_X86_REG_ESP);
+        asm_x86_add_i32_to_r32(as, (n_args + align) * WORD_SIZE, ASM_X86_REG_ESP);
     }
 }
 

+ 23 - 20
py/asmx86.h

@@ -60,14 +60,16 @@
 #define ASM_X86_REG_ARG_2 ASM_X86_REG_ECX
 #define ASM_X86_REG_ARG_3 ASM_X86_REG_EDX
 #define ASM_X86_REG_ARG_4 ASM_X86_REG_EBX
-#define ASM_X86_REG_ARG_5 ASM_X86_REG_ESI
 
 // condition codes, used for jcc and setcc (despite their j-name!)
 #define ASM_X86_CC_JB  (0x2) // below, unsigned
+#define ASM_X86_CC_JAE (0x3) // above or equal, unsigned
 #define ASM_X86_CC_JZ  (0x4)
 #define ASM_X86_CC_JE  (0x4)
 #define ASM_X86_CC_JNZ (0x5)
 #define ASM_X86_CC_JNE (0x5)
+#define ASM_X86_CC_JBE (0x6) // below or equal, unsigned
+#define ASM_X86_CC_JA  (0x7) // above, unsigned
 #define ASM_X86_CC_JL  (0xc) // less, signed
 #define ASM_X86_CC_JGE (0xd) // greater or equal, signed
 #define ASM_X86_CC_JLE (0xe) // less or equal, signed
@@ -82,7 +84,7 @@ static inline void asm_x86_end_pass(asm_x86_t *as) {
     (void)as;
 }
 
-void asm_x86_mov_r32_r32(asm_x86_t* as, int dest_r32, int src_r32);
+void asm_x86_mov_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
 size_t asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32);
 void asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
 void asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
@@ -93,26 +95,27 @@ void asm_x86_mov_mem32_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest
 void asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
 void asm_x86_or_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
 void asm_x86_xor_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
-void asm_x86_shl_r32_cl(asm_x86_t* as, int dest_r32);
-void asm_x86_sar_r32_cl(asm_x86_t* as, int dest_r32);
-void asm_x86_add_r32_r32(asm_x86_t* as, int dest_r32, int src_r32);
-void asm_x86_sub_r32_r32(asm_x86_t* as, int dest_r32, int src_r32);
-void asm_x86_mul_r32_r32(asm_x86_t* as, int dest_r32, int src_r32);
-void asm_x86_cmp_r32_with_r32(asm_x86_t* as, int src_r32_a, int src_r32_b);
-void asm_x86_test_r8_with_r8(asm_x86_t* as, int src_r32_a, int src_r32_b);
-void asm_x86_test_r32_with_r32(asm_x86_t* as, int src_r32_a, int src_r32_b);
-void asm_x86_setcc_r8(asm_x86_t* as, mp_uint_t jcc_type, int dest_r8);
+void asm_x86_shl_r32_cl(asm_x86_t *as, int dest_r32);
+void asm_x86_shr_r32_cl(asm_x86_t *as, int dest_r32);
+void asm_x86_sar_r32_cl(asm_x86_t *as, int dest_r32);
+void asm_x86_add_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
+void asm_x86_sub_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
+void asm_x86_mul_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
+void asm_x86_cmp_r32_with_r32(asm_x86_t *as, int src_r32_a, int src_r32_b);
+void asm_x86_test_r8_with_r8(asm_x86_t *as, int src_r32_a, int src_r32_b);
+void asm_x86_test_r32_with_r32(asm_x86_t *as, int src_r32_a, int src_r32_b);
+void asm_x86_setcc_r8(asm_x86_t *as, mp_uint_t jcc_type, int dest_r8);
 void asm_x86_jmp_reg(asm_x86_t *as, int src_r86);
-void asm_x86_jmp_label(asm_x86_t* as, mp_uint_t label);
-void asm_x86_jcc_label(asm_x86_t* as, mp_uint_t jcc_type, mp_uint_t label);
-void asm_x86_entry(asm_x86_t* as, int num_locals);
-void asm_x86_exit(asm_x86_t* as);
+void asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label);
+void asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label);
+void asm_x86_entry(asm_x86_t *as, int num_locals);
+void asm_x86_exit(asm_x86_t *as);
 void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32);
-void asm_x86_mov_local_to_r32(asm_x86_t* as, int src_local_num, int dest_r32);
-void asm_x86_mov_r32_to_local(asm_x86_t* as, int src_r32, int dest_local_num);
-void asm_x86_mov_local_addr_to_r32(asm_x86_t* as, int local_num, int dest_r32);
+void asm_x86_mov_local_to_r32(asm_x86_t *as, int src_local_num, int dest_r32);
+void asm_x86_mov_r32_to_local(asm_x86_t *as, int src_r32, int dest_local_num);
+void asm_x86_mov_local_addr_to_r32(asm_x86_t *as, int local_num, int dest_r32);
 void asm_x86_mov_reg_pcrel(asm_x86_t *as, int dest_r64, mp_uint_t label);
-void asm_x86_call_ind(asm_x86_t* as, size_t fun_id, mp_uint_t n_args, int temp_r32);
+void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r32);
 
 // Holds a pointer to mp_fun_table
 #define ASM_X86_REG_FUN_TABLE ASM_X86_REG_EBP
@@ -129,7 +132,6 @@ void asm_x86_call_ind(asm_x86_t* as, size_t fun_id, mp_uint_t n_args, int temp_r
 #define REG_ARG_2 ASM_X86_REG_ARG_2
 #define REG_ARG_3 ASM_X86_REG_ARG_3
 #define REG_ARG_4 ASM_X86_REG_ARG_4
-#define REG_ARG_5 ASM_X86_REG_ARG_5
 
 // caller-save, so can be used as temporaries
 #define REG_TEMP0 ASM_X86_REG_EAX
@@ -187,6 +189,7 @@ void asm_x86_call_ind(asm_x86_t* as, size_t fun_id, mp_uint_t n_args, int temp_r
 #define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_x86_mov_reg_pcrel((as), (reg_dest), (label))
 
 #define ASM_LSL_REG(as, reg) asm_x86_shl_r32_cl((as), (reg))
+#define ASM_LSR_REG(as, reg) asm_x86_shr_r32_cl((as), (reg))
 #define ASM_ASR_REG(as, reg) asm_x86_sar_r32_cl((as), (reg))
 #define ASM_OR_REG_REG(as, reg_dest, reg_src) asm_x86_or_r32_r32((as), (reg_dest), (reg_src))
 #define ASM_XOR_REG_REG(as, reg_dest, reg_src) asm_x86_xor_r32_r32((as), (reg_dest), (reg_src))

+ 3 - 3
py/asmxtensa.c

@@ -65,7 +65,7 @@ void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) {
     // jump over the constants
     asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4);
     mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte
-    as->const_table = (uint32_t*)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4);
+    as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4);
 
     // adjust the stack-pointer to store a0, a12, a13, a14, a15 and locals, 16-byte aligned
     as->stack_adjust = (((ASM_XTENSA_NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15;
@@ -105,7 +105,7 @@ void asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals) {
     // jump over the constants
     asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4);
     mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte
-    as->const_table = (uint32_t*)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4);
+    as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4);
 
     as->stack_adjust = 32 + ((((ASM_XTENSA_NUM_REGS_SAVED_WIN + num_locals) * WORD_SIZE) + 15) & ~15);
     asm_xtensa_op_entry(as, ASM_XTENSA_REG_A1, as->stack_adjust);
@@ -173,7 +173,7 @@ void asm_xtensa_setcc_reg_reg_reg(asm_xtensa_t *as, uint cond, uint reg_dest, ui
 
 size_t asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) {
     // load the constant
-    uint32_t const_table_offset = (uint8_t*)as->const_table - as->base.code_base;
+    uint32_t const_table_offset = (uint8_t *)as->const_table - as->base.code_base;
     size_t loc = const_table_offset + as->cur_const * WORD_SIZE;
     asm_xtensa_op_l32r(as, reg_dest, as->base.code_offset, loc);
     // store the constant in the table

+ 9 - 0
py/asmxtensa.h

@@ -243,6 +243,10 @@ static inline void asm_xtensa_op_sll(asm_xtensa_t *as, uint reg_dest, uint reg_s
     asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 1, 10, reg_dest, reg_src, 0));
 }
 
+static inline void asm_xtensa_op_srl(asm_xtensa_t *as, uint reg_dest, uint reg_src) {
+    asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 1, 9, reg_dest, 0, reg_src));
+}
+
 static inline void asm_xtensa_op_sra(asm_xtensa_t *as, uint reg_dest, uint reg_src) {
     asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRR(0, 1, 11, reg_dest, 0, reg_src));
 }
@@ -372,6 +376,11 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx);
         asm_xtensa_op_ssl((as), (reg_shift)); \
         asm_xtensa_op_sll((as), (reg_dest), (reg_dest)); \
     } while (0)
+#define ASM_LSR_REG_REG(as, reg_dest, reg_shift) \
+    do { \
+        asm_xtensa_op_ssr((as), (reg_shift)); \
+        asm_xtensa_op_srl((as), (reg_dest), (reg_dest)); \
+    } while (0)
 #define ASM_ASR_REG_REG(as, reg_dest, reg_shift) \
     do { \
         asm_xtensa_op_ssr((as), (reg_shift)); \

+ 25 - 25
py/bc.c

@@ -75,21 +75,21 @@ const byte *mp_decode_uint_skip(const byte *ptr) {
 #endif
 
 STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {
-#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
     // generic message, used also for other argument issues
     (void)f;
     (void)expected;
     (void)given;
     mp_arg_error_terse_mismatch();
-#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
+    #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
     (void)f;
-    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-        "function takes %d positional arguments but %d were given", expected, given));
-#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
-    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-        "%q() takes %d positional arguments but %d were given",
-        mp_obj_fun_get_name(MP_OBJ_FROM_PTR(f)), expected, given));
-#endif
+    mp_raise_msg_varg(&mp_type_TypeError,
+        MP_ERROR_TEXT("function takes %d positional arguments but %d were given"), expected, given);
+    #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
+    mp_raise_msg_varg(&mp_type_TypeError,
+        MP_ERROR_TEXT("%q() takes %d positional arguments but %d were given"),
+        mp_obj_fun_get_name(MP_OBJ_FROM_PTR(f)), expected, given);
+    #endif
 }
 
 #if DEBUG_PRINT
@@ -195,7 +195,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
         }
 
         // get pointer to arg_names array
-        const mp_obj_t *arg_names = (const mp_obj_t*)self->const_table;
+        const mp_obj_t *arg_names = (const mp_obj_t *)self->const_table;
 
         for (size_t i = 0; i < n_kw; i++) {
             // the keys in kwargs are expected to be qstr objects
@@ -203,8 +203,8 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
             for (size_t j = 0; j < n_pos_args + n_kwonly_args; j++) {
                 if (wanted_arg_name == arg_names[j]) {
                     if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
-                        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                            "function got multiple values for argument '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name)));
+                        mp_raise_msg_varg(&mp_type_TypeError,
+                            MP_ERROR_TEXT("function got multiple values for argument '%q'"), MP_OBJ_QSTR_VALUE(wanted_arg_name));
                     }
                     code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
                     goto continue2;
@@ -212,15 +212,15 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
             }
             // Didn't find name match with positional args
             if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) {
-                if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-                    mp_raise_TypeError("unexpected keyword argument");
-                } else {
-                    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                        "unexpected keyword argument '%q'", MP_OBJ_QSTR_VALUE(wanted_arg_name)));
-                }
+                #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+                mp_raise_TypeError(MP_ERROR_TEXT("unexpected keyword argument"));
+                #else
+                mp_raise_msg_varg(&mp_type_TypeError,
+                    MP_ERROR_TEXT("unexpected keyword argument '%q'"), MP_OBJ_QSTR_VALUE(wanted_arg_name));
+                #endif
             }
             mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
-continue2:;
+        continue2:;
         }
 
         DEBUG_printf("Args with kws flattened: ");
@@ -241,8 +241,8 @@ continue2:;
         // Check that all mandatory positional args are specified
         while (d < &code_state->state[n_state]) {
             if (*d++ == MP_OBJ_NULL) {
-                nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                    "function missing required positional argument #%d", &code_state->state[n_state] - d));
+                mp_raise_msg_varg(&mp_type_TypeError,
+                    MP_ERROR_TEXT("function missing required positional argument #%d"), &code_state->state[n_state] - d);
             }
         }
 
@@ -252,13 +252,13 @@ continue2:;
             if (code_state->state[n_state - 1 - n_pos_args - i] == MP_OBJ_NULL) {
                 mp_map_elem_t *elem = NULL;
                 if ((scope_flags & MP_SCOPE_FLAG_DEFKWARGS) != 0) {
-                    elem = mp_map_lookup(&((mp_obj_dict_t*)MP_OBJ_TO_PTR(self->extra_args[n_def_pos_args]))->map, arg_names[n_pos_args + i], MP_MAP_LOOKUP);
+                    elem = mp_map_lookup(&((mp_obj_dict_t *)MP_OBJ_TO_PTR(self->extra_args[n_def_pos_args]))->map, arg_names[n_pos_args + i], MP_MAP_LOOKUP);
                 }
                 if (elem != NULL) {
                     code_state->state[n_state - 1 - n_pos_args - i] = elem->value;
                 } else {
-                    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                        "function missing required keyword argument '%q'", MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i])));
+                    mp_raise_msg_varg(&mp_type_TypeError,
+                        MP_ERROR_TEXT("function missing required keyword argument '%q'"), MP_OBJ_QSTR_VALUE(arg_names[n_pos_args + i]));
                 }
             }
         }
@@ -266,7 +266,7 @@ continue2:;
     } else {
         // no keyword arguments given
         if (n_kwonly_args != 0) {
-            mp_raise_TypeError("function missing keyword-only argument");
+            mp_raise_TypeError(MP_ERROR_TEXT("function missing keyword-only argument"));
         }
         if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) {
             *var_pos_kw_args = mp_obj_new_dict(0);

+ 83 - 83
py/bc.h

@@ -72,94 +72,94 @@
 //  constN          : obj
 
 #define MP_BC_PRELUDE_SIG_ENCODE(S, E, scope, out_byte, out_env) \
-do {                                                            \
-    /*// Get values to store in prelude */                      \
-    size_t F = scope->scope_flags & MP_SCOPE_FLAG_ALL_SIG;      \
-    size_t A = scope->num_pos_args;                             \
-    size_t K = scope->num_kwonly_args;                          \
-    size_t D = scope->num_def_pos_args;                         \
+    do {                                                            \
+        /*// Get values to store in prelude */                      \
+        size_t F = scope->scope_flags & MP_SCOPE_FLAG_ALL_SIG;      \
+        size_t A = scope->num_pos_args;                             \
+        size_t K = scope->num_kwonly_args;                          \
+        size_t D = scope->num_def_pos_args;                         \
                                                                 \
-    /* Adjust S to shrink range, to compress better */          \
-    S -= 1;                                                     \
+        /* Adjust S to shrink range, to compress better */          \
+        S -= 1;                                                     \
                                                                 \
-    /* Encode prelude */                                        \
-    /* xSSSSEAA */                                              \
-    uint8_t z = (S & 0xf) << 3 | (E & 1) << 2 | (A & 3);        \
-    S >>= 4;                                                    \
-    E >>= 1;                                                    \
-    A >>= 2;                                                    \
-    while (S | E | F | A | K | D) {                             \
-        out_byte(out_env, 0x80 | z);                            \
-        /* xFSSKAED */                                          \
-        z = (F & 1) << 6 | (S & 3) << 4 | (K & 1) << 3          \
-            | (A & 1) << 2 | (E & 1) << 1 | (D & 1);            \
-        S >>= 2;                                                \
-        E >>= 1;                                                \
-        F >>= 1;                                                \
-        A >>= 1;                                                \
-        K >>= 1;                                                \
-        D >>= 1;                                                \
-    }                                                           \
-    out_byte(out_env, z);                                       \
-} while (0)
+        /* Encode prelude */                                        \
+        /* xSSSSEAA */                                              \
+        uint8_t z = (S & 0xf) << 3 | (E & 1) << 2 | (A & 3);        \
+        S >>= 4;                                                    \
+        E >>= 1;                                                    \
+        A >>= 2;                                                    \
+        while (S | E | F | A | K | D) {                             \
+            out_byte(out_env, 0x80 | z);                            \
+            /* xFSSKAED */                                          \
+            z = (F & 1) << 6 | (S & 3) << 4 | (K & 1) << 3          \
+                | (A & 1) << 2 | (E & 1) << 1 | (D & 1);            \
+            S >>= 2;                                                \
+            E >>= 1;                                                \
+            F >>= 1;                                                \
+            A >>= 1;                                                \
+            K >>= 1;                                                \
+            D >>= 1;                                                \
+        }                                                           \
+        out_byte(out_env, z);                                       \
+    } while (0)
 
 #define MP_BC_PRELUDE_SIG_DECODE_INTO(ip, S, E, F, A, K, D)     \
-do {                                                            \
-    uint8_t z = *(ip)++;                                        \
-    /* xSSSSEAA */                                              \
-    S = (z >> 3) & 0xf;                                         \
-    E = (z >> 2) & 0x1;                                         \
-    F = 0;                                                      \
-    A = z & 0x3;                                                \
-    K = 0;                                                      \
-    D = 0;                                                      \
-    for (unsigned n = 0; z & 0x80; ++n) {                       \
-        z = *(ip)++;                                            \
-        /* xFSSKAED */                                          \
-        S |= (z & 0x30) << (2 * n);                             \
-        E |= (z & 0x02) << n;                                   \
-        F |= ((z & 0x40) >> 6) << n;                            \
-        A |= (z & 0x4) << n;                                    \
-        K |= ((z & 0x08) >> 3) << n;                            \
-        D |= (z & 0x1) << n;                                    \
-    }                                                           \
-    S += 1;                                                     \
-} while (0)
+    do {                                                            \
+        uint8_t z = *(ip)++;                                        \
+        /* xSSSSEAA */                                              \
+        S = (z >> 3) & 0xf;                                         \
+        E = (z >> 2) & 0x1;                                         \
+        F = 0;                                                      \
+        A = z & 0x3;                                                \
+        K = 0;                                                      \
+        D = 0;                                                      \
+        for (unsigned n = 0; z & 0x80; ++n) {                       \
+            z = *(ip)++;                                            \
+            /* xFSSKAED */                                          \
+            S |= (z & 0x30) << (2 * n);                             \
+            E |= (z & 0x02) << n;                                   \
+            F |= ((z & 0x40) >> 6) << n;                            \
+            A |= (z & 0x4) << n;                                    \
+            K |= ((z & 0x08) >> 3) << n;                            \
+            D |= (z & 0x1) << n;                                    \
+        }                                                           \
+        S += 1;                                                     \
+    } while (0)
 
 #define MP_BC_PRELUDE_SIG_DECODE(ip) \
     size_t n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args; \
     MP_BC_PRELUDE_SIG_DECODE_INTO(ip, n_state, n_exc_stack, scope_flags, n_pos_args, n_kwonly_args, n_def_pos_args)
 
 #define MP_BC_PRELUDE_SIZE_ENCODE(I, C, out_byte, out_env)      \
-do {                                                            \
-    /* Encode bit-wise as: xIIIIIIC */                          \
-    uint8_t z = 0;                                              \
-    do {                                                        \
-        z = (I & 0x3f) << 1 | (C & 1);                          \
-        C >>= 1;                                                \
-        I >>= 6;                                                \
-        if (C | I) {                                            \
-            z |= 0x80;                                          \
-        }                                                       \
-        out_byte(out_env, z);                                   \
-    } while (C | I);                                            \
-} while (0)
+    do {                                                            \
+        /* Encode bit-wise as: xIIIIIIC */                          \
+        uint8_t z = 0;                                              \
+        do {                                                        \
+            z = (I & 0x3f) << 1 | (C & 1);                          \
+            C >>= 1;                                                \
+            I >>= 6;                                                \
+            if (C | I) {                                            \
+                z |= 0x80;                                          \
+            }                                                       \
+            out_byte(out_env, z);                                   \
+        } while (C | I);                                            \
+    } while (0)
 
 #define MP_BC_PRELUDE_SIZE_DECODE_INTO(ip, I, C)                \
-do {                                                            \
-    uint8_t z;                                                  \
-    C = 0;                                                      \
-    I = 0;                                                      \
-    for (unsigned n = 0;; ++n) {                                \
-        z = *(ip)++;                                            \
-        /* xIIIIIIC */                                          \
-        C |= (z & 1) << n;                                      \
-        I |= ((z & 0x7e) >> 1) << (6 * n);                      \
-        if (!(z & 0x80)) {                                      \
-            break;                                              \
-        }                                                       \
-    }                                                           \
-} while (0)
+    do {                                                            \
+        uint8_t z;                                                  \
+        C = 0;                                                      \
+        I = 0;                                                      \
+        for (unsigned n = 0;; ++n) {                                \
+            z = *(ip)++;                                            \
+            /* xIIIIIIC */                                          \
+            C |= (z & 1) << n;                                      \
+            I |= ((z & 0x7e) >> 1) << (6 * n);                      \
+            if (!(z & 0x80)) {                                      \
+                break;                                              \
+            }                                                       \
+        }                                                           \
+    } while (0)
 
 #define MP_BC_PRELUDE_SIZE_DECODE(ip) \
     size_t n_info, n_cell; \
@@ -216,7 +216,7 @@ typedef struct _mp_code_state_t {
     // Variable-length
     mp_obj_t state[0];
     // Variable-length, never accessed by name, only as (void*)(state + n_state)
-    //mp_exc_stack_t exc_state[0];
+    // mp_exc_stack_t exc_state[0];
 } mp_code_state_t;
 
 mp_uint_t mp_decode_uint(const byte **ptr);
@@ -226,16 +226,16 @@ const byte *mp_decode_uint_skip(const byte *ptr);
 mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc);
 mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args);
 void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args);
-void mp_bytecode_print(const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table);
-void mp_bytecode_print2(const byte *code, size_t len, const mp_uint_t *const_table);
-const byte *mp_bytecode_print_str(const byte *ip);
-#define mp_bytecode_print_inst(code, const_table) mp_bytecode_print2(code, 1, const_table)
+void mp_bytecode_print(const mp_print_t *print, const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table);
+void mp_bytecode_print2(const mp_print_t *print, const byte *code, size_t len, const mp_uint_t *const_table);
+const byte *mp_bytecode_print_str(const mp_print_t *print, const byte *ip);
+#define mp_bytecode_print_inst(print, code, const_table) mp_bytecode_print2(print, code, 1, const_table)
 
 // Helper macros to access pointer with least significant bits holding flags
-#define MP_TAGPTR_PTR(x) ((void*)((uintptr_t)(x) & ~((uintptr_t)3)))
+#define MP_TAGPTR_PTR(x) ((void *)((uintptr_t)(x) & ~((uintptr_t)3)))
 #define MP_TAGPTR_TAG0(x) ((uintptr_t)(x) & 1)
 #define MP_TAGPTR_TAG1(x) ((uintptr_t)(x) & 2)
-#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((uintptr_t)(ptr) | (tag)))
+#define MP_TAGPTR_MAKE(ptr, tag) ((void *)((uintptr_t)(ptr) | (tag)))
 
 #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE
 

+ 5 - 5
py/bc0.h

@@ -48,15 +48,15 @@
 #define MP_BC_BASE_BYTE_O                   (0x50) // LLLLSSDTTTTTEEFF
 #define MP_BC_BASE_BYTE_E                   (0x60) // --BREEEYYI------
 #define MP_BC_LOAD_CONST_SMALL_INT_MULTI    (0x70) // LLLLLLLLLLLLLLLL
-                                         // (0x80) // LLLLLLLLLLLLLLLL
-                                         // (0x90) // LLLLLLLLLLLLLLLL
-                                         // (0xa0) // LLLLLLLLLLLLLLLL
+//                                          (0x80) // LLLLLLLLLLLLLLLL
+//                                          (0x90) // LLLLLLLLLLLLLLLL
+//                                          (0xa0) // LLLLLLLLLLLLLLLL
 #define MP_BC_LOAD_FAST_MULTI               (0xb0) // LLLLLLLLLLLLLLLL
 #define MP_BC_STORE_FAST_MULTI              (0xc0) // SSSSSSSSSSSSSSSS
 #define MP_BC_UNARY_OP_MULTI                (0xd0) // OOOOOOO
 #define MP_BC_BINARY_OP_MULTI               (0xd7) //        OOOOOOOOO
-                                         // (0xe0) // OOOOOOOOOOOOOOOO
-                                         // (0xf0) // OOOOOOOOOO------
+//                                          (0xe0) // OOOOOOOOOOOOOOOO
+//                                          (0xf0) // OOOOOOOOOO------
 
 #define MP_BC_LOAD_CONST_SMALL_INT_MULTI_NUM (64)
 #define MP_BC_LOAD_CONST_SMALL_INT_MULTI_EXCESS (16)

+ 134 - 94
py/binary.c

@@ -46,24 +46,40 @@ size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) {
     size_t size = 0;
     int align = 1;
     switch (struct_type) {
-        case '<': case '>':
+        case '<':
+        case '>':
             switch (val_type) {
-                case 'b': case 'B':
-                    size = 1; break;
-                case 'h': case 'H':
-                    size = 2; break;
-                case 'i': case 'I':
-                    size = 4; break;
-                case 'l': case 'L':
-                    size = 4; break;
-                case 'q': case 'Q':
-                    size = 8; break;
-                case 'P': case 'O': case 'S':
-                    size = sizeof(void*); break;
+                case 'b':
+                case 'B':
+                    size = 1;
+                    break;
+                case 'h':
+                case 'H':
+                    size = 2;
+                    break;
+                case 'i':
+                case 'I':
+                    size = 4;
+                    break;
+                case 'l':
+                case 'L':
+                    size = 4;
+                    break;
+                case 'q':
+                case 'Q':
+                    size = 8;
+                    break;
+                case 'P':
+                case 'O':
+                case 'S':
+                    size = sizeof(void *);
+                    break;
                 case 'f':
-                    size = sizeof(float); break;
+                    size = sizeof(float);
+                    break;
                 case 'd':
-                    size = sizeof(double); break;
+                    size = sizeof(double);
+                    break;
             }
             break;
         case '@': {
@@ -76,35 +92,50 @@ size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) {
             // particular (or any) ABI.
             switch (val_type) {
                 case BYTEARRAY_TYPECODE:
-                case 'b': case 'B':
-                    align = size = 1; break;
-                case 'h': case 'H':
+                case 'b':
+                case 'B':
+                    align = size = 1;
+                    break;
+                case 'h':
+                case 'H':
                     align = alignof(short);
-                    size = sizeof(short); break;
-                case 'i': case 'I':
+                    size = sizeof(short);
+                    break;
+                case 'i':
+                case 'I':
                     align = alignof(int);
-                    size = sizeof(int); break;
-                case 'l': case 'L':
+                    size = sizeof(int);
+                    break;
+                case 'l':
+                case 'L':
                     align = alignof(long);
-                    size = sizeof(long); break;
-                case 'q': case 'Q':
+                    size = sizeof(long);
+                    break;
+                case 'q':
+                case 'Q':
                     align = alignof(long long);
-                    size = sizeof(long long); break;
-                case 'P': case 'O': case 'S':
-                    align = alignof(void*);
-                    size = sizeof(void*); break;
+                    size = sizeof(long long);
+                    break;
+                case 'P':
+                case 'O':
+                case 'S':
+                    align = alignof(void *);
+                    size = sizeof(void *);
+                    break;
                 case 'f':
                     align = alignof(float);
-                    size = sizeof(float); break;
+                    size = sizeof(float);
+                    break;
                 case 'd':
                     align = alignof(double);
-                    size = sizeof(double); break;
+                    size = sizeof(double);
+                    break;
             }
         }
     }
 
     if (size == 0) {
-        mp_raise_ValueError("bad typecode");
+        mp_raise_ValueError(MP_ERROR_TEXT("bad typecode"));
     }
 
     if (palign != NULL) {
@@ -117,44 +148,44 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) {
     mp_int_t val = 0;
     switch (typecode) {
         case 'b':
-            val = ((signed char*)p)[index];
+            val = ((signed char *)p)[index];
             break;
         case BYTEARRAY_TYPECODE:
         case 'B':
-            val = ((unsigned char*)p)[index];
+            val = ((unsigned char *)p)[index];
             break;
         case 'h':
-            val = ((short*)p)[index];
+            val = ((short *)p)[index];
             break;
         case 'H':
-            val = ((unsigned short*)p)[index];
+            val = ((unsigned short *)p)[index];
             break;
         case 'i':
-            return mp_obj_new_int(((int*)p)[index]);
+            return mp_obj_new_int(((int *)p)[index]);
         case 'I':
-            return mp_obj_new_int_from_uint(((unsigned int*)p)[index]);
+            return mp_obj_new_int_from_uint(((unsigned int *)p)[index]);
         case 'l':
-            return mp_obj_new_int(((long*)p)[index]);
+            return mp_obj_new_int(((long *)p)[index]);
         case 'L':
-            return mp_obj_new_int_from_uint(((unsigned long*)p)[index]);
+            return mp_obj_new_int_from_uint(((unsigned long *)p)[index]);
         #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
         case 'q':
-            return mp_obj_new_int_from_ll(((long long*)p)[index]);
+            return mp_obj_new_int_from_ll(((long long *)p)[index]);
         case 'Q':
-            return mp_obj_new_int_from_ull(((unsigned long long*)p)[index]);
+            return mp_obj_new_int_from_ull(((unsigned long long *)p)[index]);
         #endif
-#if MICROPY_PY_BUILTINS_FLOAT
+        #if MICROPY_PY_BUILTINS_FLOAT
         case 'f':
-            return mp_obj_new_float(((float*)p)[index]);
+            return mp_obj_new_float_from_f(((float *)p)[index]);
         case 'd':
-            return mp_obj_new_float(((double*)p)[index]);
-#endif
+            return mp_obj_new_float_from_d(((double *)p)[index]);
+        #endif
         // Extension to CPython: array of objects
         case 'O':
-            return ((mp_obj_t*)p)[index];
+            return ((mp_obj_t *)p)[index];
         // Extension to CPython: array of pointers
         case 'P':
-            return mp_obj_new_int((mp_int_t)(uintptr_t)((void**)p)[index]);
+            return mp_obj_new_int((mp_int_t)(uintptr_t)((void **)p)[index]);
     }
     return MP_OBJ_NEW_SMALL_INT(val);
 }
@@ -206,16 +237,20 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte *
     if (val_type == 'O') {
         return (mp_obj_t)(mp_uint_t)val;
     } else if (val_type == 'S') {
-        const char *s_val = (const char*)(uintptr_t)(mp_uint_t)val;
+        const char *s_val = (const char *)(uintptr_t)(mp_uint_t)val;
         return mp_obj_new_str(s_val, strlen(s_val));
-#if MICROPY_PY_BUILTINS_FLOAT
+    #if MICROPY_PY_BUILTINS_FLOAT
     } else if (val_type == 'f') {
-        union { uint32_t i; float f; } fpu = {val};
-        return mp_obj_new_float(fpu.f);
+        union { uint32_t i;
+                float f;
+        } fpu = {val};
+        return mp_obj_new_float_from_f(fpu.f);
     } else if (val_type == 'd') {
-        union { uint64_t i; double f; } fpu = {val};
-        return mp_obj_new_float(fpu.f);
-#endif
+        union { uint64_t i;
+                double f;
+        } fpu = {val};
+        return mp_obj_new_float_from_d(fpu.f);
+    #endif
     } else if (is_signed(val_type)) {
         if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) {
             return mp_obj_new_int((mp_int_t)val);
@@ -236,13 +271,13 @@ void mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val
         memcpy(dest, &val, val_sz);
     } else if (MP_ENDIANNESS_BIG && big_endian) {
         // only copy the least-significant val_sz bytes
-        memcpy(dest, (byte*)&val + sizeof(mp_uint_t) - val_sz, val_sz);
+        memcpy(dest, (byte *)&val + sizeof(mp_uint_t) - val_sz, val_sz);
     } else {
         const byte *src;
         if (MP_ENDIANNESS_LITTLE) {
-            src = (const byte*)&val + val_sz;
+            src = (const byte *)&val + val_sz;
         } else {
-            src = (const byte*)&val + sizeof(mp_uint_t);
+            src = (const byte *)&val + sizeof(mp_uint_t);
         }
         while (val_sz--) {
             *dest++ = *--src;
@@ -271,16 +306,21 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p
         case 'O':
             val = (mp_uint_t)val_in;
             break;
-#if MICROPY_PY_BUILTINS_FLOAT
+        #if MICROPY_PY_BUILTINS_FLOAT
         case 'f': {
-            union { uint32_t i; float f; } fp_sp;
-            fp_sp.f = mp_obj_get_float(val_in);
+            union { uint32_t i;
+                    float f;
+            } fp_sp;
+            fp_sp.f = mp_obj_get_float_to_f(val_in);
             val = fp_sp.i;
             break;
         }
         case 'd': {
-            union { uint64_t i64; uint32_t i32[2]; double f; } fp_dp;
-            fp_dp.f = mp_obj_get_float(val_in);
+            union { uint64_t i64;
+                    uint32_t i32[2];
+                    double f;
+            } fp_dp;
+            fp_dp.f = mp_obj_get_float_to_d(val_in);
             if (BYTES_PER_WORD == 8) {
                 val = fp_dp.i64;
             } else {
@@ -291,25 +331,25 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p
             }
             break;
         }
-#endif
+        #endif
         default:
             #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
             if (mp_obj_is_type(val_in, &mp_type_int)) {
                 mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p);
                 return;
-            } else
+            }
             #endif
-            {
-                val = mp_obj_get_int(val_in);
-                // zero/sign extend if needed
-                if (BYTES_PER_WORD < 8 && size > sizeof(val)) {
-                    int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00;
-                    memset(p, c, size);
-                    if (struct_type == '>') {
-                        p += size - sizeof(val);
-                    }
+
+            val = mp_obj_get_int(val_in);
+            // zero/sign extend if needed
+            if (BYTES_PER_WORD < 8 && size > sizeof(val)) {
+                int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00;
+                memset(p, c, size);
+                if (struct_type == '>') {
+                    p += size - sizeof(val);
                 }
             }
+            break;
     }
 
     mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val);
@@ -317,24 +357,24 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p
 
 void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in) {
     switch (typecode) {
-#if MICROPY_PY_BUILTINS_FLOAT
+        #if MICROPY_PY_BUILTINS_FLOAT
         case 'f':
-            ((float*)p)[index] = mp_obj_get_float(val_in);
+            ((float *)p)[index] = mp_obj_get_float_to_f(val_in);
             break;
         case 'd':
-            ((double*)p)[index] = mp_obj_get_float(val_in);
+            ((double *)p)[index] = mp_obj_get_float_to_d(val_in);
             break;
-#endif
+        #endif
         // Extension to CPython: array of objects
         case 'O':
-            ((mp_obj_t*)p)[index] = val_in;
+            ((mp_obj_t *)p)[index] = val_in;
             break;
         default:
             #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
             if (mp_obj_is_type(val_in, &mp_type_int)) {
                 size_t size = mp_binary_get_size('@', typecode, NULL);
                 mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG,
-                    size, (uint8_t*)p + index * size);
+                    size, (uint8_t *)p + index * size);
                 return;
             }
             #endif
@@ -345,49 +385,49 @@ void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_
 void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val) {
     switch (typecode) {
         case 'b':
-            ((signed char*)p)[index] = val;
+            ((signed char *)p)[index] = val;
             break;
         case BYTEARRAY_TYPECODE:
         case 'B':
-            ((unsigned char*)p)[index] = val;
+            ((unsigned char *)p)[index] = val;
             break;
         case 'h':
-            ((short*)p)[index] = val;
+            ((short *)p)[index] = val;
             break;
         case 'H':
-            ((unsigned short*)p)[index] = val;
+            ((unsigned short *)p)[index] = val;
             break;
         case 'i':
-            ((int*)p)[index] = val;
+            ((int *)p)[index] = val;
             break;
         case 'I':
-            ((unsigned int*)p)[index] = val;
+            ((unsigned int *)p)[index] = val;
             break;
         case 'l':
-            ((long*)p)[index] = val;
+            ((long *)p)[index] = val;
             break;
         case 'L':
-            ((unsigned long*)p)[index] = val;
+            ((unsigned long *)p)[index] = val;
             break;
         #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
         case 'q':
-            ((long long*)p)[index] = val;
+            ((long long *)p)[index] = val;
             break;
         case 'Q':
-            ((unsigned long long*)p)[index] = val;
+            ((unsigned long long *)p)[index] = val;
             break;
         #endif
-#if MICROPY_PY_BUILTINS_FLOAT
+        #if MICROPY_PY_BUILTINS_FLOAT
         case 'f':
-            ((float*)p)[index] = val;
+            ((float *)p)[index] = (float)val;
             break;
         case 'd':
-            ((double*)p)[index] = val;
+            ((double *)p)[index] = (double)val;
             break;
-#endif
+        #endif
         // Extension to CPython: array of pointers
         case 'P':
-            ((void**)p)[index] = (void*)(uintptr_t)val;
+            ((void **)p)[index] = (void *)(uintptr_t)val;
             break;
     }
 }

+ 1 - 0
py/builtin.h

@@ -103,6 +103,7 @@ extern const mp_obj_module_t mp_module_thread;
 extern const mp_obj_dict_t mp_module_builtins_globals;
 
 // extmod modules
+extern const mp_obj_module_t mp_module_uasyncio;
 extern const mp_obj_module_t mp_module_uerrno;
 extern const mp_obj_module_t mp_module_uctypes;
 extern const mp_obj_module_t mp_module_uzlib;

+ 15 - 8
py/builtinevex.c

@@ -90,11 +90,17 @@ STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) {
     qstr mode = mp_obj_str_get_qstr(args[2]);
     mp_parse_input_kind_t parse_input_kind;
     switch (mode) {
-        case MP_QSTR_single: parse_input_kind = MP_PARSE_SINGLE_INPUT; break;
-        case MP_QSTR_exec: parse_input_kind = MP_PARSE_FILE_INPUT; break;
-        case MP_QSTR_eval: parse_input_kind = MP_PARSE_EVAL_INPUT; break;
+        case MP_QSTR_single:
+            parse_input_kind = MP_PARSE_SINGLE_INPUT;
+            break;
+        case MP_QSTR_exec:
+            parse_input_kind = MP_PARSE_FILE_INPUT;
+            break;
+        case MP_QSTR_eval:
+            parse_input_kind = MP_PARSE_EVAL_INPUT;
+            break;
         default:
-            mp_raise_ValueError("bad compile mode");
+            mp_raise_ValueError(MP_ERROR_TEXT("bad compile mode"));
     }
 
     mp_obj_code_t *code = m_new_obj(mp_obj_code_t);
@@ -130,17 +136,18 @@ STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_i
     }
     #endif
 
-    size_t str_len;
-    const char *str = mp_obj_str_get_data(args[0], &str_len);
+    // Extract the source code.
+    mp_buffer_info_t bufinfo;
+    mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
 
     // create the lexer
     // MP_PARSE_SINGLE_INPUT is used to indicate a file input
     mp_lexer_t *lex;
     if (MICROPY_PY_BUILTINS_EXECFILE && parse_input_kind == MP_PARSE_SINGLE_INPUT) {
-        lex = mp_lexer_new_from_file(str);
+        lex = mp_lexer_new_from_file(bufinfo.buf);
         parse_input_kind = MP_PARSE_FILE_INPUT;
     } else {
-        lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0);
+        lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, bufinfo.buf, bufinfo.len, 0);
     }
 
     return mp_parse_compile_execute(lex, parse_input_kind, globals, locals);

+ 14 - 14
py/builtinhelp.c

@@ -33,18 +33,18 @@
 #if MICROPY_PY_BUILTINS_HELP
 
 const char mp_help_default_text[] =
-"Welcome to MicroPython!\n"
-"\n"
-"For online docs please visit http://docs.micropython.org/\n"
-"\n"
-"Control commands:\n"
-"  CTRL-A        -- on a blank line, enter raw REPL mode\n"
-"  CTRL-B        -- on a blank line, enter normal REPL mode\n"
-"  CTRL-C        -- interrupt a running program\n"
-"  CTRL-D        -- on a blank line, exit or do a soft reset\n"
-"  CTRL-E        -- on a blank line, enter paste mode\n"
-"\n"
-"For further help on a specific object, type help(obj)\n"
+    "Welcome to MicroPython!\n"
+    "\n"
+    "For online docs please visit http://docs.micropython.org/\n"
+    "\n"
+    "Control commands:\n"
+    "  CTRL-A        -- on a blank line, enter raw REPL mode\n"
+    "  CTRL-B        -- on a blank line, enter normal REPL mode\n"
+    "  CTRL-C        -- interrupt a running program\n"
+    "  CTRL-D        -- on a blank line, exit or do a soft reset\n"
+    "  CTRL-E        -- on a blank line, enter paste mode\n"
+    "\n"
+    "For further help on a specific object, type help(obj)\n"
 ;
 
 STATIC void mp_help_print_info_about_object(mp_obj_t name_o, mp_obj_t value) {
@@ -91,7 +91,7 @@ STATIC void mp_help_print_modules(void) {
     #endif
 
     // sort the list so it's printed in alphabetical order
-    mp_obj_list_sort(1, &list, (mp_map_t*)&mp_const_empty_map);
+    mp_obj_list_sort(1, &list, (mp_map_t *)&mp_const_empty_map);
 
     // print the list of modules in a column-first order
     #define NUM_COLUMNS (4)
@@ -134,7 +134,7 @@ STATIC void mp_help_print_obj(const mp_obj_t obj) {
     }
     #endif
 
-    mp_obj_type_t *type = mp_obj_get_type(obj);
+    const mp_obj_type_t *type = mp_obj_get_type(obj);
 
     // try to print something sensible about the given object
     mp_print_str(MP_PYTHON_PRINTER, "object ");

+ 26 - 30
py/builtinimport.c

@@ -96,19 +96,13 @@ STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
 }
 
 STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
-#if MICROPY_PY_SYS
+    #if MICROPY_PY_SYS
     // extract the list of paths
     size_t path_num;
     mp_obj_t *path_items;
     mp_obj_list_get(mp_sys_path, &path_num, &path_items);
 
-    if (path_num == 0) {
-#endif
-        // mp_sys_path is empty, so just use the given file name
-        vstr_add_strn(dest, file_str, file_len);
-        return stat_dir_or_file(dest);
-#if MICROPY_PY_SYS
-    } else {
+    if (path_num != 0) {
         // go through each path looking for a directory or file
         for (size_t i = 0; i < path_num; i++) {
             vstr_reset(dest);
@@ -128,7 +122,11 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d
         // could not find a directory or file
         return MP_IMPORT_STAT_NO_EXIST;
     }
-#endif
+    #endif
+
+    // mp_sys_path is empty, so just use the given file name
+    vstr_add_strn(dest, file_str, file_len);
+    return stat_dir_or_file(dest);
 }
 
 #if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER
@@ -145,7 +143,7 @@ STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex) {
 #endif
 
 #if MICROPY_PERSISTENT_CODE_LOAD || MICROPY_MODULE_FROZEN_MPY
-STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, const char* source_name) {
+STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code, const char *source_name) {
     (void)source_name;
 
     #if MICROPY_PY___FILE__
@@ -230,7 +228,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
     }
     #else
     // If we get here then the file was not frozen and we can't compile scripts.
-    mp_raise_msg(&mp_type_ImportError, "script compilation not supported");
+    mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("script compilation not supported"));
     #endif
 }
 
@@ -246,14 +244,14 @@ STATIC void chop_component(const char *start, const char **end) {
 }
 
 mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
-#if DEBUG_PRINT
+    #if DEBUG_PRINT
     DEBUG_printf("__import__:\n");
     for (size_t i = 0; i < n_args; i++) {
         DEBUG_printf("  ");
         mp_obj_print(args[i], PRINT_REPR);
         DEBUG_printf("\n");
     }
-#endif
+    #endif
 
     mp_obj_t module_name = args[0];
     mp_obj_t fromtuple = mp_const_none;
@@ -292,12 +290,12 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
         mp_map_elem_t *elem = mp_map_lookup(globals_map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP);
         bool is_pkg = (elem != NULL);
 
-#if DEBUG_PRINT
+        #if DEBUG_PRINT
         DEBUG_printf("Current module/package: ");
         mp_obj_print(this_name_q, PRINT_REPR);
         DEBUG_printf(", is_package: %d", is_pkg);
         DEBUG_printf("\n");
-#endif
+        #endif
 
         size_t this_name_l;
         const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l);
@@ -315,7 +313,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
 
         // We must have some component left over to import from
         if (p == this_name) {
-            mp_raise_ValueError("cannot perform relative import");
+            mp_raise_ValueError(MP_ERROR_TEXT("can't perform relative import"));
         }
 
         uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);
@@ -398,12 +396,11 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
                 #endif
                 if (module_obj == MP_OBJ_NULL) {
                     // couldn't find the file, so fail
-                    if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-                        mp_raise_msg(&mp_type_ImportError, "module not found");
-                    } else {
-                        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError,
-                            "no module named '%q'", mod_name));
-                    }
+                    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+                    mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
+                    #else
+                    mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), mod_name);
+                    #endif
                 }
             } else {
                 // found the file, so get the module
@@ -443,7 +440,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
                     vstr_add_char(&path, PATH_SEP_CHAR);
                     vstr_add_str(&path, "__init__.py");
                     if (stat_file_py_or_mpy(&path) != MP_IMPORT_STAT_FILE) {
-                        //mp_warning("%s is imported as namespace package", vstr_str(&path));
+                        // mp_warning("%s is imported as namespace package", vstr_str(&path));
                     } else {
                         do_load(module_obj, &path);
                     }
@@ -481,7 +478,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
 mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
     // Check that it's not a relative import
     if (n_args >= 5 && MP_OBJ_SMALL_INT_VALUE(args[4]) != 0) {
-        mp_raise_NotImplementedError("relative import");
+        mp_raise_NotImplementedError(MP_ERROR_TEXT("relative import"));
     }
 
     // Check if module already exists, and return it if it does
@@ -502,12 +499,11 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
     #endif
 
     // Couldn't find the module, so fail
-    if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-        mp_raise_msg(&mp_type_ImportError, "module not found");
-    } else {
-        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError,
-            "no module named '%q'", module_name_qstr));
-    }
+    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+    mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
+    #else
+    mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), module_name_qstr);
+    #endif
 }
 
 #endif // MICROPY_ENABLE_EXTERNAL_IMPORT

Разница между файлами не показана из-за своего большого размера
+ 183 - 136
py/compile.c


+ 52 - 16
py/dynruntime.h

@@ -31,6 +31,11 @@
 
 #include "py/nativeglue.h"
 #include "py/objstr.h"
+#include "py/objtype.h"
+
+#if !MICROPY_ENABLE_DYNRUNTIME
+#error "dynruntime.h included in non-dynamic-module build."
+#endif
 
 #undef MP_ROM_QSTR
 #undef MP_OBJ_QSTR_VALUE
@@ -72,18 +77,18 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {
 /******************************************************************************/
 // Types and objects
 
-#define MP_OBJ_NEW_QSTR(x) MP_OBJ_NEW_QSTR_ ## x
+#define MP_OBJ_NEW_QSTR(x) MP_OBJ_NEW_QSTR_##x
 
 #define mp_type_type                        (*mp_fun_table.type_type)
 #define mp_type_str                         (*mp_fun_table.type_str)
 #define mp_type_list                        (*mp_fun_table.type_list)
-#define mp_type_EOFError                    (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_EOFError)))
-#define mp_type_IndexError                  (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_IndexError)))
-#define mp_type_KeyError                    (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_KeyError)))
-#define mp_type_NotImplementedError         (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_NotImplementedError)))
-#define mp_type_RuntimeError                (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_RuntimeError)))
-#define mp_type_TypeError                   (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_TypeError)))
-#define mp_type_ValueError                  (*(mp_obj_type_t*)(mp_load_global(MP_QSTR_ValueError)))
+#define mp_type_EOFError                    (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_EOFError)))
+#define mp_type_IndexError                  (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_IndexError)))
+#define mp_type_KeyError                    (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_KeyError)))
+#define mp_type_NotImplementedError         (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_NotImplementedError)))
+#define mp_type_RuntimeError                (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_RuntimeError)))
+#define mp_type_TypeError                   (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_TypeError)))
+#define mp_type_ValueError                  (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_ValueError)))
 
 #define mp_stream_read_obj                  (*mp_fun_table.stream_read_obj)
 #define mp_stream_readinto_obj              (*mp_fun_table.stream_readinto_obj)
@@ -106,9 +111,10 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {
 #define mp_obj_new_list(n, items)           (mp_fun_table.new_list((n), (items)))
 
 #define mp_obj_get_type(o)                  (mp_fun_table.obj_get_type((o)))
+#define mp_obj_cast_to_native_base(o, t)    (mp_obj_cast_to_native_base_dyn((o), (t)))
 #define mp_obj_get_int(o)                   (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_INT))
 #define mp_obj_get_int_truncated(o)         (mp_fun_table.native_from_obj(o, MP_NATIVE_TYPE_UINT))
-#define mp_obj_str_get_str(s)               ((void*)mp_fun_table.native_from_obj(s, MP_NATIVE_TYPE_PTR))
+#define mp_obj_str_get_str(s)               (mp_obj_str_get_data_dyn((s), NULL))
 #define mp_obj_str_get_data(o, len)         (mp_obj_str_get_data_dyn((o), (len)))
 #define mp_get_buffer_raise(o, bufinfo, fl) (mp_fun_table.get_buffer_raise((o), (bufinfo), (fl)))
 #define mp_get_stream_raise(s, flags)       (mp_fun_table.get_stream_raise((s), (flags)))
@@ -117,18 +123,35 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {
 #define mp_obj_subscr(base, index, val)     (mp_fun_table.obj_subscr((base), (index), (val)))
 #define mp_obj_list_append(list, item)      (mp_fun_table.list_append((list), (item)))
 
-static inline mp_obj_t mp_obj_new_str_of_type_dyn(const mp_obj_type_t *type, const byte* data, size_t len) {
+static inline mp_obj_t mp_obj_new_str_of_type_dyn(const mp_obj_type_t *type, const byte *data, size_t len) {
     if (type == &mp_type_str) {
-        return mp_obj_new_str((const char*)data, len);
+        return mp_obj_new_str((const char *)data, len);
     } else {
         return mp_obj_new_bytes(data, len);
     }
 }
 
+static inline mp_obj_t mp_obj_cast_to_native_base_dyn(mp_obj_t self_in, mp_const_obj_t native_type) {
+    const mp_obj_type_t *self_type = mp_obj_get_type(self_in);
+
+    if (MP_OBJ_FROM_PTR(self_type) == native_type) {
+        return self_in;
+    } else if (self_type->parent != native_type) {
+        // The self_in object is not a direct descendant of native_type, so fail the cast.
+        // This is a very simple version of mp_obj_is_subclass_fast that could be improved.
+        return MP_OBJ_NULL;
+    } else {
+        mp_obj_instance_t *self = (mp_obj_instance_t *)MP_OBJ_TO_PTR(self_in);
+        return self->subobj[0];
+    }
+}
+
 static inline void *mp_obj_str_get_data_dyn(mp_obj_t o, size_t *l) {
     mp_buffer_info_t bufinfo;
     mp_get_buffer_raise(o, &bufinfo, MP_BUFFER_READ);
-    *l = bufinfo.len;
+    if (l != NULL) {
+        *l = bufinfo.len;
+    }
     return bufinfo.buf;
 }
 
@@ -140,9 +163,15 @@ static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {
 /******************************************************************************/
 // General runtime functions
 
-#define mp_load_name(qst)           (mp_fun_table.load_name(qst))
-#define mp_load_global(qst)         (mp_fun_table.load_global(qst))
-#define mp_store_global(qst, obj)   (mp_fun_table.store_global((qst), (obj)))
+#define mp_load_name(qst)                 (mp_fun_table.load_name((qst)))
+#define mp_load_global(qst)               (mp_fun_table.load_global((qst)))
+#define mp_load_attr(base, attr)          (mp_fun_table.load_attr((base), (attr)))
+#define mp_load_method(base, attr, dest)  (mp_fun_table.load_method((base), (attr), (dest)))
+#define mp_load_super_method(attr, dest)  (mp_fun_table.load_super_method((attr), (dest)))
+#define mp_store_name(qst, obj)           (mp_fun_table.store_name((qst), (obj)))
+#define mp_store_global(qst, obj)         (mp_fun_table.store_global((qst), (obj)))
+#define mp_store_attr(base, attr, val)    (mp_fun_table.store_attr((base), (attr), (val)))
+
 #define mp_unary_op(op, obj)        (mp_fun_table.unary_op((op), (obj)))
 #define mp_binary_op(op, lhs, rhs)  (mp_fun_table.binary_op((op), (lhs), (rhs)))
 
@@ -160,7 +189,7 @@ static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {
     mp_raw_code_t rc; \
     rc.kind = MP_CODE_NATIVE_VIPER; \
     rc.scope_flags = 0; \
-    rc.const_table = (void*)self->const_table; \
+    rc.const_table = (void *)self->const_table; \
     (void)rc;
 
 #define MP_DYNRUNTIME_INIT_EXIT \
@@ -170,6 +199,13 @@ static inline mp_obj_t mp_obj_len_dyn(mp_obj_t o) {
 #define MP_DYNRUNTIME_MAKE_FUNCTION(f) \
     (mp_make_function_from_raw_code((rc.fun_data = (f), &rc), MP_OBJ_NULL, MP_OBJ_NULL))
 
+#define mp_import_name(name, fromlist, level) \
+    (mp_fun_table.import_name((name), (fromlist), (level)))
+#define mp_import_from(module, name) \
+    (mp_fun_table.import_from((module), (name)))
+#define mp_import_all(module) \
+    (mp_fun_table.import_all((module))
+
 /******************************************************************************/
 // Exceptions
 

+ 1 - 0
py/dynruntime.mk

@@ -27,6 +27,7 @@ CFLAGS += -std=c99
 CFLAGS += -Os
 CFLAGS += -Wall -Werror -DNDEBUG
 CFLAGS += -DNO_QSTR
+CFLAGS += -DMICROPY_ENABLE_DYNRUNTIME
 CFLAGS += -DMP_CONFIGFILE='<$(CONFIG_H)>'
 CFLAGS += -fpic -fno-common
 CFLAGS += -U _FORTIFY_SOURCE # prevent use of __*_chk libc functions

+ 2 - 2
py/emit.h

@@ -99,7 +99,7 @@ typedef struct _mp_emit_method_table_id_ops_t {
 
 typedef struct _emit_method_table_t {
     #if MICROPY_DYNAMIC_COMPILER
-    emit_t *(*emit_new)(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
+    emit_t *(*emit_new)(mp_obj_t * error_slot, uint *label_slot, mp_uint_t max_num_labels);
     void (*emit_free)(emit_t *emit);
     #endif
 
@@ -188,7 +188,7 @@ emit_t *emit_native_arm_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t ma
 emit_t *emit_native_xtensa_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
 emit_t *emit_native_xtensawin_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
 
-void emit_bc_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels);
+void emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels);
 
 void emit_bc_free(emit_t *emit);
 void emit_native_x64_free(emit_t *emit);

+ 10 - 14
py/emitbc.c

@@ -110,7 +110,6 @@ STATIC void emit_write_uint(emit_t *emit, emit_allocator_t allocator, mp_uint_t
 
 // all functions must go through this one to emit code info
 STATIC byte *emit_get_cur_to_write_code_info(emit_t *emit, int num_bytes_to_write) {
-    //printf("emit %d\n", num_bytes_to_write);
     if (emit->pass < MP_PASS_EMIT) {
         emit->code_info_offset += num_bytes_to_write;
         return emit->dummy_data;
@@ -122,7 +121,7 @@ STATIC byte *emit_get_cur_to_write_code_info(emit_t *emit, int num_bytes_to_writ
     }
 }
 
-STATIC void emit_write_code_info_byte(emit_t* emit, byte val) {
+STATIC void emit_write_code_info_byte(emit_t *emit, byte val) {
     *emit_get_cur_to_write_code_info(emit, 1) = val;
 }
 
@@ -140,7 +139,6 @@ STATIC void emit_write_code_info_qstr(emit_t *emit, qstr qst) {
 #if MICROPY_ENABLE_SOURCE_LINE
 STATIC void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_skip, mp_uint_t lines_to_skip) {
     assert(bytes_to_skip > 0 || lines_to_skip > 0);
-    //printf("  %d %d\n", bytes_to_skip, lines_to_skip);
     while (bytes_to_skip > 0 || lines_to_skip > 0) {
         mp_uint_t b, l;
         if (lines_to_skip <= 6 || bytes_to_skip > 0xf) {
@@ -169,7 +167,6 @@ STATIC void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_sk
 
 // all functions must go through this one to emit byte code
 STATIC byte *emit_get_cur_to_write_bytecode(emit_t *emit, int num_bytes_to_write) {
-    //printf("emit %d\n", num_bytes_to_write);
     if (emit->pass < MP_PASS_EMIT) {
         emit->bytecode_offset += num_bytes_to_write;
         return emit->dummy_data;
@@ -233,7 +230,7 @@ STATIC void emit_write_bytecode_byte_const(emit_t *emit, int stack_adj, byte b,
 }
 #endif
 
-STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, int stack_adj, byte b, qstr qst) {
+STATIC void emit_write_bytecode_byte_qstr(emit_t *emit, int stack_adj, byte b, qstr qst) {
     #if MICROPY_PERSISTENT_CODE
     assert((qst >> 16) == 0);
     mp_emit_bc_adjust_stack_size(emit, stack_adj);
@@ -255,7 +252,7 @@ STATIC void emit_write_bytecode_byte_obj(emit_t *emit, int stack_adj, byte b, mp
     // aligns the pointer so it is friendly to GC
     emit_write_bytecode_byte(emit, stack_adj, b);
     emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(mp_obj_t));
-    mp_obj_t *c = (mp_obj_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_obj_t));
+    mp_obj_t *c = (mp_obj_t *)emit_get_cur_to_write_bytecode(emit, sizeof(mp_obj_t));
     // Verify thar c is already uint-aligned
     assert(c == MP_ALIGN(c, sizeof(mp_obj_t)));
     *c = obj;
@@ -270,10 +267,10 @@ STATIC void emit_write_bytecode_byte_raw_code(emit_t *emit, int stack_adj, byte
     #else
     // aligns the pointer so it is friendly to GC
     emit_write_bytecode_byte(emit, stack_adj, b);
-    emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(void*));
-    void **c = (void**)emit_get_cur_to_write_bytecode(emit, sizeof(void*));
+    emit->bytecode_offset = (size_t)MP_ALIGN(emit->bytecode_offset, sizeof(void *));
+    void **c = (void **)emit_get_cur_to_write_bytecode(emit, sizeof(void *));
     // Verify thar c is already uint-aligned
-    assert(c == MP_ALIGN(c, sizeof(void*)));
+    assert(c == MP_ALIGN(c, sizeof(void *)));
     *c = rc;
     #endif
     #if MICROPY_PY_SYS_SETTRACE
@@ -470,8 +467,7 @@ void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) {
 }
 
 void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) {
-    //printf("source: line %d -> %d  offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset);
-#if MICROPY_ENABLE_SOURCE_LINE
+    #if MICROPY_ENABLE_SOURCE_LINE
     if (MP_STATE_VM(mp_optimise_value) >= 3) {
         // If we compile with -O3, don't store line numbers.
         return;
@@ -483,10 +479,10 @@ void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) {
         emit->last_source_line_offset = emit->bytecode_offset;
         emit->last_source_line = source_line;
     }
-#else
+    #else
     (void)emit;
     (void)source_line;
-#endif
+    #endif
 }
 
 void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) {
@@ -944,4 +940,4 @@ const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = {
 };
 #endif
 
-#endif //MICROPY_ENABLE_COMPILER
+#endif // MICROPY_ENABLE_COMPILER

+ 14 - 14
py/emitglue.c

@@ -84,17 +84,17 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
     mp_prof_extract_prelude(code, prelude);
     #endif
 
-#ifdef DEBUG_PRINT
+    #ifdef DEBUG_PRINT
     #if !MICROPY_DEBUG_PRINTERS
     const size_t len = 0;
     #endif
     DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " flags=%x\n", code, len, (uint)scope_flags);
-#endif
-#if MICROPY_DEBUG_PRINTERS
+    #endif
+    #if MICROPY_DEBUG_PRINTERS
     if (mp_verbose_flag >= 2) {
-        mp_bytecode_print(rc, code, len, const_table);
+        mp_bytecode_print(&mp_plat_print, rc, code, len, const_table);
     }
-#endif
+    #endif
 }
 
 #if MICROPY_EMIT_MACHINE_CODE
@@ -120,28 +120,28 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
     rc->prelude_offset = prelude_offset;
     rc->n_obj = n_obj;
     rc->n_raw_code = n_raw_code;
-    rc->n_qstr= n_qstr;
+    rc->n_qstr = n_qstr;
     rc->qstr_link = qstr_link;
     #endif
 
-#ifdef DEBUG_PRINT
+    #ifdef DEBUG_PRINT
     DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, (uint)scope_flags);
     for (mp_uint_t i = 0; i < fun_len; i++) {
         if (i > 0 && i % 16 == 0) {
             DEBUG_printf("\n");
         }
-        DEBUG_printf(" %02x", ((byte*)fun_data)[i]);
+        DEBUG_printf(" %02x", ((byte *)fun_data)[i]);
     }
     DEBUG_printf("\n");
 
-#ifdef WRITE_CODE
+    #ifdef WRITE_CODE
     FILE *fp_write_code = fopen("out-code", "wb");
     fwrite(fun_data, fun_len, 1, fp_write_code);
     fclose(fp_write_code);
-#endif
-#else
+    #endif
+    #else
     (void)fun_len;
-#endif
+    #endif
 }
 #endif
 
@@ -164,7 +164,7 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar
             fun = mp_obj_new_fun_native(def_args, def_kw_args, rc->fun_data, rc->const_table);
             // Check for a generator function, and if so change the type of the object
             if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
-                ((mp_obj_base_t*)MP_OBJ_TO_PTR(fun))->type = &mp_type_native_gen_wrap;
+                ((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_native_gen_wrap;
             }
             break;
         #endif
@@ -179,7 +179,7 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, mp_obj_t def_ar
             fun = mp_obj_new_fun_bc(def_args, def_kw_args, rc->fun_data, rc->const_table);
             // check for generator functions and if so change the type of the object
             if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
-                ((mp_obj_base_t*)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap;
+                ((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap;
             }
 
             #if MICROPY_PY_SYS_SETTRACE

+ 61 - 47
py/emitinlinethumb.c

@@ -39,14 +39,14 @@ typedef enum {
 // define rules with a compile function
 #define DEF_RULE(rule, comp, kind, ...) PN_##rule,
 #define DEF_RULE_NC(rule, kind, ...)
-#include "py/grammar.h"
+    #include "py/grammar.h"
 #undef DEF_RULE
 #undef DEF_RULE_NC
     PN_const_object, // special node for a constant, generic Python object
 // define rules without a compile function
 #define DEF_RULE(rule, comp, kind, ...)
 #define DEF_RULE_NC(rule, kind, ...) PN_##rule,
-#include "py/grammar.h"
+    #include "py/grammar.h"
 #undef DEF_RULE
 #undef DEF_RULE_NC
 } pn_kind_t;
@@ -59,7 +59,7 @@ struct _emit_inline_asm_t {
     qstr *label_lookup;
 };
 
-STATIC void emit_inline_thumb_error_msg(emit_inline_asm_t *emit, const char *msg) {
+STATIC void emit_inline_thumb_error_msg(emit_inline_asm_t *emit, mp_rom_error_text_t msg) {
     *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);
 }
 
@@ -99,17 +99,17 @@ STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit, mp_uint_t type_s
 
 STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) {
     if (n_params > 4) {
-        emit_inline_thumb_error_msg(emit, "can only have up to 4 parameters to Thumb assembly");
+        emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT("can only have up to 4 parameters to Thumb assembly"));
         return 0;
     }
     for (mp_uint_t i = 0; i < n_params; i++) {
         if (!MP_PARSE_NODE_IS_ID(pn_params[i])) {
-            emit_inline_thumb_error_msg(emit, "parameters must be registers in sequence r0 to r3");
+            emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence r0 to r3"));
             return 0;
         }
         const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));
-        if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) {
-            emit_inline_thumb_error_msg(emit, "parameters must be registers in sequence r0 to r3");
+        if (!(strlen(p) == 2 && p[0] == 'r' && (mp_uint_t)p[1] == '0' + i)) {
+            emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence r0 to r3"));
             return 0;
         }
     }
@@ -131,7 +131,9 @@ STATIC bool emit_inline_thumb_label(emit_inline_asm_t *emit, mp_uint_t label_num
     return true;
 }
 
-typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t;
+typedef struct _reg_name_t { byte reg;
+                             byte name[3];
+} reg_name_t;
 STATIC const reg_name_t reg_name_table[] = {
     {0, "r0\0"},
     {1, "r1\0"},
@@ -157,7 +159,9 @@ STATIC const reg_name_t reg_name_table[] = {
 };
 
 #define MAX_SPECIAL_REGISTER_NAME_LENGTH 7
-typedef struct _special_reg_name_t { byte reg; char name[MAX_SPECIAL_REGISTER_NAME_LENGTH + 1]; } special_reg_name_t;
+typedef struct _special_reg_name_t { byte reg;
+                                     char name[MAX_SPECIAL_REGISTER_NAME_LENGTH + 1];
+} special_reg_name_t;
 STATIC const special_reg_name_t special_reg_name_table[] = {
     {5, "IPSR"},
     {17, "BASEPRI"},
@@ -185,7 +189,7 @@ STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_n
             if (r->reg > max_reg) {
                 emit_inline_thumb_error_exc(emit,
                     mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
-                        "'%s' expects at most r%d", op, max_reg));
+                        MP_ERROR_TEXT("'%s' expects at most r%d"), op, max_reg));
                 return 0;
             } else {
                 return r->reg;
@@ -194,7 +198,7 @@ STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_n
     }
     emit_inline_thumb_error_exc(emit,
         mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
-            "'%s' expects a register", op));
+            MP_ERROR_TEXT("'%s' expects a register"), op));
     return 0;
 }
 
@@ -208,7 +212,7 @@ STATIC mp_uint_t get_arg_special_reg(emit_inline_asm_t *emit, const char *op, mp
     }
     emit_inline_thumb_error_exc(emit,
         mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
-            "'%s' expects a special register", op));
+            MP_ERROR_TEXT("'%s' expects a special register"), op));
     return 0;
 }
 
@@ -226,8 +230,8 @@ STATIC mp_uint_t get_arg_vfpreg(emit_inline_asm_t *emit, const char *op, mp_pars
         }
         if (regno > 31) {
             emit_inline_thumb_error_exc(emit,
-                 mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
-                       "'%s' expects at most r%d", op, 31));
+                mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
+                    MP_ERROR_TEXT("'%s' expects at most r%d"), op, 31));
             return 0;
         } else {
             return regno;
@@ -235,8 +239,8 @@ STATIC mp_uint_t get_arg_vfpreg(emit_inline_asm_t *emit, const char *op, mp_pars
     }
 malformed:
     emit_inline_thumb_error_exc(emit,
-         mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
-            "'%s' expects an FPU register", op));
+        mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
+            MP_ERROR_TEXT("'%s' expects an FPU register"), op));
     return 0;
 }
 #endif
@@ -248,7 +252,7 @@ STATIC mp_uint_t get_arg_reglist(emit_inline_asm_t *emit, const char *op, mp_par
         goto bad_arg;
     }
 
-    mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
+    mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
     assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 1); // should always be
     pn = pns->nodes[0];
 
@@ -258,10 +262,10 @@ STATIC mp_uint_t get_arg_reglist(emit_inline_asm_t *emit, const char *op, mp_par
         // set with one element
         reglist |= 1 << get_arg_reg(emit, op, pn, 15);
     } else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
-        pns = (mp_parse_node_struct_t*)pn;
+        pns = (mp_parse_node_struct_t *)pn;
         if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) {
             assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should succeed
-            mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
+            mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1];
             if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_dictorsetmaker_list) {
                 // set with multiple elements
 
@@ -289,19 +293,19 @@ STATIC mp_uint_t get_arg_reglist(emit_inline_asm_t *emit, const char *op, mp_par
     return reglist;
 
 bad_arg:
-    emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects {r0, r1, ...}", op));
+    emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' expects {r0, r1, ...}"), op));
     return 0;
 }
 
 STATIC uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, uint32_t fit_mask) {
     mp_obj_t o;
     if (!mp_parse_node_get_int_maybe(pn, &o)) {
-        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an integer", op));
+        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' expects an integer"), op));
         return 0;
     }
     uint32_t i = mp_obj_get_int_truncated(o);
     if ((i & (~fit_mask)) != 0) {
-        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' integer 0x%x doesn't fit in mask 0x%x", op, i, fit_mask));
+        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' integer 0x%x doesn't fit in mask 0x%x"), op, i, fit_mask));
         return 0;
     }
     return i;
@@ -311,11 +315,11 @@ STATIC bool get_arg_addr(emit_inline_asm_t *emit, const char *op, mp_parse_node_
     if (!MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_bracket)) {
         goto bad_arg;
     }
-    mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
+    mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
     if (!MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
         goto bad_arg;
     }
-    pns = (mp_parse_node_struct_t*)pns->nodes[0];
+    pns = (mp_parse_node_struct_t *)pns->nodes[0];
     if (MP_PARSE_NODE_STRUCT_NUM_NODES(pns) != 2) {
         goto bad_arg;
     }
@@ -325,13 +329,13 @@ STATIC bool get_arg_addr(emit_inline_asm_t *emit, const char *op, mp_parse_node_
     return true;
 
 bad_arg:
-    emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an address of the form [a, b]", op));
+    emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' expects an address of the form [a, b]"), op));
     return false;
 }
 
 STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {
     if (!MP_PARSE_NODE_IS_ID(pn)) {
-        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a label", op));
+        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' expects a label"), op));
         return 0;
     }
     qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
@@ -342,12 +346,14 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
     }
     // only need to have the labels on the last pass
     if (emit->pass == MP_PASS_EMIT) {
-        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "label '%q' not defined", label_qstr));
+        emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("label '%q' not defined"), label_qstr));
     }
     return 0;
 }
 
-typedef struct _cc_name_t { byte cc; byte name[2]; } cc_name_t;
+typedef struct _cc_name_t { byte cc;
+                            byte name[2];
+} cc_name_t;
 STATIC const cc_name_t cc_name_table[] = {
     { ASM_THUMB_CC_EQ, "eq" },
     { ASM_THUMB_CC_NE, "ne" },
@@ -365,7 +371,9 @@ STATIC const cc_name_t cc_name_table[] = {
     { ASM_THUMB_CC_LE, "le" },
 };
 
-typedef struct _format_4_op_t { byte op; char name[3]; } format_4_op_t;
+typedef struct _format_4_op_t { byte op;
+                                char name[3];
+} format_4_op_t;
 #define X(x) (((x) >> 4) & 0xff) // only need 1 byte to distinguish these ops
 STATIC const format_4_op_t format_4_op_table[] = {
     { X(ASM_THUMB_FORMAT_4_EOR), "eor" },
@@ -387,7 +395,9 @@ STATIC const format_4_op_t format_4_op_table[] = {
 #undef X
 
 // name is actually a qstr, which should fit in 16 bits
-typedef struct _format_9_10_op_t { uint16_t op; uint16_t name; } format_9_10_op_t;
+typedef struct _format_9_10_op_t { uint16_t op;
+                                   uint16_t name;
+} format_9_10_op_t;
 #define X(x) (x)
 STATIC const format_9_10_op_t format_9_10_op_table[] = {
     { X(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER), MP_QSTR_ldr },
@@ -401,7 +411,9 @@ STATIC const format_9_10_op_t format_9_10_op_table[] = {
 
 #if MICROPY_EMIT_INLINE_THUMB_FLOAT
 // actual opcodes are: 0xee00 | op.hi_nibble, 0x0a00 | op.lo_nibble
-typedef struct _format_vfp_op_t { byte op; char name[3]; } format_vfp_op_t;
+typedef struct _format_vfp_op_t { byte op;
+                                  char name[3];
+} format_vfp_op_t;
 STATIC const format_vfp_op_t format_vfp_op_table[] = {
     { 0x30, "add" },
     { 0x34, "sub" },
@@ -425,7 +437,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
     // "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3
 
     size_t op_len;
-    const char *op_str = (const char*)qstr_data(op, &op_len);
+    const char *op_str = (const char *)qstr_data(op, &op_len);
 
     #if MICROPY_EMIT_INLINE_THUMB_FLOAT
     if (op_str[0] == 'v') {
@@ -434,7 +446,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
             mp_uint_t op_code = 0x0ac0, op_code_hi;
             if (op == MP_QSTR_vcmp) {
                 op_code_hi = 0xeeb4;
-                op_vfp_twoargs:;
+            op_vfp_twoargs:;
                 mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]);
                 mp_uint_t vm = get_arg_vfpreg(emit, op_str, pn_args[1]);
                 asm_thumb_op32(&emit->as,
@@ -485,7 +497,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
                     0x0a10 | (r_arm << 12) | ((vm & 1) << 7));
             } else if (op == MP_QSTR_vldr) {
                 op_code_hi = 0xed90;
-                op_vldr_vstr:;
+            op_vldr_vstr:;
                 mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]);
                 mp_parse_node_t pn_base, pn_offset;
                 if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) {
@@ -521,8 +533,10 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
         } else {
             goto unknown_op;
         }
-    } else
+        return;
+    }
     #endif
+
     if (n_args == 0) {
         if (op == MP_QSTR_nop) {
             asm_thumb_op16(&emit->as, ASM_THUMB_OP_NOP);
@@ -547,8 +561,8 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
             mp_uint_t r = get_arg_reg(emit, op_str, pn_args[0], 15);
             asm_thumb_op16(&emit->as, 0x4700 | (r << 3));
         } else if (op_str[0] == 'b' && (op_len == 3
-                    || (op_len == 5 && op_str[3] == '_'
-                        && (op_str[4] == 'n' || (ARMV7M && op_str[4] == 'w'))))) {
+                                        || (op_len == 5 && op_str[3] == '_'
+                                            && (op_str[4] == 'n' || (ARMV7M && op_str[4] == 'w'))))) {
             mp_uint_t cc = -1;
             for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) {
                 if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) {
@@ -637,7 +651,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
                 op_code_hi = 0xfab0;
                 op_code = 0xf080;
                 mp_uint_t rd, rm;
-                op_clz_rbit:
+            op_clz_rbit:
                 rd = get_arg_reg(emit, op_str, pn_args[0], 15);
                 rm = get_arg_reg(emit, op_str, pn_args[1], 15);
                 asm_thumb_op32(&emit->as, op_code_hi | rm, op_code | (rd << 8) | rm);
@@ -645,7 +659,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
                 op_code_hi = 0xfa90;
                 op_code = 0xf0a0;
                 goto op_clz_rbit;
-            } else if (ARMV7M && op == MP_QSTR_mrs){
+            } else if (ARMV7M && op == MP_QSTR_mrs) {
                 mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 12);
                 mp_uint_t reg_src = get_arg_special_reg(emit, op_str, pn_args[1]);
                 asm_thumb_op32(&emit->as, 0xf3ef, 0x8000 | (reg_dest << 8) | reg_src);
@@ -653,7 +667,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
                 if (op == MP_QSTR_and_) {
                     op_code = ASM_THUMB_FORMAT_4_AND;
                     mp_uint_t reg_dest, reg_src;
-                    op_format_4:
+                op_format_4:
                     reg_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
                     reg_src = get_arg_reg(emit, op_str, pn_args[1], 7);
                     asm_thumb_format_4(&emit->as, op_code, reg_dest, reg_src);
@@ -674,7 +688,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
             if (op == MP_QSTR_mov) {
                 op_code = ASM_THUMB_FORMAT_3_MOV;
                 mp_uint_t rlo_dest, i8_src;
-                op_format_3:
+            op_format_3:
                 rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
                 i8_src = get_arg_i(emit, op_str, pn_args[1], 0xff);
                 asm_thumb_format_3(&emit->as, op_code, rlo_dest, i8_src);
@@ -690,7 +704,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
             } else if (ARMV7M && op == MP_QSTR_movw) {
                 op_code = ASM_THUMB_OP_MOVW;
                 mp_uint_t reg_dest;
-                op_movw_movt:
+            op_movw_movt:
                 reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
                 int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff);
                 asm_thumb_mov_reg_i16(&emit->as, op_code, reg_dest, i_src);
@@ -743,7 +757,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
         if (op == MP_QSTR_lsl) {
             op_code = ASM_THUMB_FORMAT_1_LSL;
             mp_uint_t rlo_dest, rlo_src, i5;
-            op_format_1:
+        op_format_1:
             rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
             rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7);
             i5 = get_arg_i(emit, op_str, pn_args[2], 0x1f);
@@ -757,7 +771,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
         } else if (op == MP_QSTR_add) {
             op_code = ASM_THUMB_FORMAT_2_ADD;
             mp_uint_t rlo_dest, rlo_src;
-            op_format_2:
+        op_format_2:
             rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
             rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7);
             int src_b;
@@ -772,7 +786,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
         } else if (ARMV7M && op == MP_QSTR_sdiv) {
             op_code = 0xfb90; // sdiv high part
             mp_uint_t rd, rn, rm;
-            op_sdiv_udiv:
+        op_sdiv_udiv:
             rd = get_arg_reg(emit, op_str, pn_args[0], 15);
             rn = get_arg_reg(emit, op_str, pn_args[1], 15);
             rm = get_arg_reg(emit, op_str, pn_args[2], 15);
@@ -803,11 +817,11 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
     return;
 
 unknown_op:
-    emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "unsupported Thumb instruction '%s' with %d arguments", op_str, n_args));
+    emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("unsupported Thumb instruction '%s' with %d arguments"), op_str, n_args));
     return;
 
 branch_not_in_range:
-    emit_inline_thumb_error_msg(emit, "branch not in range");
+    emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT("branch not in range"));
     return;
 }
 

+ 16 - 14
py/emitinlinextensa.c

@@ -43,7 +43,7 @@ struct _emit_inline_asm_t {
     qstr *label_lookup;
 };
 
-STATIC void emit_inline_xtensa_error_msg(emit_inline_asm_t *emit, const char *msg) {
+STATIC void emit_inline_xtensa_error_msg(emit_inline_asm_t *emit, mp_rom_error_text_t msg) {
     *emit->error_slot = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);
 }
 
@@ -83,17 +83,17 @@ STATIC void emit_inline_xtensa_end_pass(emit_inline_asm_t *emit, mp_uint_t type_
 
 STATIC mp_uint_t emit_inline_xtensa_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) {
     if (n_params > 4) {
-        emit_inline_xtensa_error_msg(emit, "can only have up to 4 parameters to Xtensa assembly");
+        emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("can only have up to 4 parameters to Xtensa assembly"));
         return 0;
     }
     for (mp_uint_t i = 0; i < n_params; i++) {
         if (!MP_PARSE_NODE_IS_ID(pn_params[i])) {
-            emit_inline_xtensa_error_msg(emit, "parameters must be registers in sequence a2 to a5");
+            emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence a2 to a5"));
             return 0;
         }
         const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));
-        if (!(strlen(p) == 2 && p[0] == 'a' && p[1] == '2' + i)) {
-            emit_inline_xtensa_error_msg(emit, "parameters must be registers in sequence a2 to a5");
+        if (!(strlen(p) == 2 && p[0] == 'a' && (mp_uint_t)p[1] == '2' + i)) {
+            emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence a2 to a5"));
             return 0;
         }
     }
@@ -115,7 +115,9 @@ STATIC bool emit_inline_xtensa_label(emit_inline_asm_t *emit, mp_uint_t label_nu
     return true;
 }
 
-typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t;
+typedef struct _reg_name_t { byte reg;
+                             byte name[3];
+} reg_name_t;
 STATIC const reg_name_t reg_name_table[] = {
     {0, "a0\0"},
     {1, "a1\0"},
@@ -159,19 +161,19 @@ STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_n
     }
     emit_inline_xtensa_error_exc(emit,
         mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
-            "'%s' expects a register", op));
+            MP_ERROR_TEXT("'%s' expects a register"), op));
     return 0;
 }
 
 STATIC uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, int min, int max) {
     mp_obj_t o;
     if (!mp_parse_node_get_int_maybe(pn, &o)) {
-        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects an integer", op));
+        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' expects an integer"), op));
         return 0;
     }
     uint32_t i = mp_obj_get_int_truncated(o);
     if (min != max && ((int)i < min || (int)i > max)) {
-        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' integer %d isn't within range %d..%d", op, i, min, max));
+        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' integer %d isn't within range %d..%d"), op, i, min, max));
         return 0;
     }
     return i;
@@ -179,7 +181,7 @@ STATIC uint32_t get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node
 
 STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {
     if (!MP_PARSE_NODE_IS_ID(pn)) {
-        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects a label", op));
+        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("'%s' expects a label"), op));
         return 0;
     }
     qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
@@ -190,7 +192,7 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
     }
     // only need to have the labels on the last pass
     if (emit->pass == MP_PASS_EMIT) {
-        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "label '%q' not defined", label_qstr));
+        emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("label '%q' not defined"), label_qstr));
     }
     return 0;
 }
@@ -242,7 +244,7 @@ STATIC const opcode_table_3arg_t opcode_table_3arg[] = {
 
 STATIC void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) {
     size_t op_len;
-    const char *op_str = (const char*)qstr_data(op, &op_len);
+    const char *op_str = (const char *)qstr_data(op, &op_len);
 
     if (n_args == 0) {
         if (op == MP_QSTR_ret_n) {
@@ -324,12 +326,12 @@ STATIC void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
     return;
 
 unknown_op:
-    emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "unsupported Xtensa instruction '%s' with %d arguments", op_str, n_args));
+    emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("unsupported Xtensa instruction '%s' with %d arguments"), op_str, n_args));
     return;
 
     /*
 branch_not_in_range:
-    emit_inline_xtensa_error_msg(emit, "branch not in range");
+    emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("branch not in range"));
     return;
     */
 }

+ 148 - 75
py/emitnative.c

@@ -135,7 +135,7 @@
 
 #define EMIT_NATIVE_VIPER_TYPE_ERROR(emit, ...) do { \
         *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \
-    } while (0)
+} while (0)
 
 typedef enum {
     STACK_VALUE,
@@ -163,15 +163,25 @@ typedef enum {
 
 STATIC qstr vtype_to_qstr(vtype_kind_t vtype) {
     switch (vtype) {
-        case VTYPE_PYOBJ: return MP_QSTR_object;
-        case VTYPE_BOOL: return MP_QSTR_bool;
-        case VTYPE_INT: return MP_QSTR_int;
-        case VTYPE_UINT: return MP_QSTR_uint;
-        case VTYPE_PTR: return MP_QSTR_ptr;
-        case VTYPE_PTR8: return MP_QSTR_ptr8;
-        case VTYPE_PTR16: return MP_QSTR_ptr16;
-        case VTYPE_PTR32: return MP_QSTR_ptr32;
-        case VTYPE_PTR_NONE: default: return MP_QSTR_None;
+        case VTYPE_PYOBJ:
+            return MP_QSTR_object;
+        case VTYPE_BOOL:
+            return MP_QSTR_bool;
+        case VTYPE_INT:
+            return MP_QSTR_int;
+        case VTYPE_UINT:
+            return MP_QSTR_uint;
+        case VTYPE_PTR:
+            return MP_QSTR_ptr;
+        case VTYPE_PTR8:
+            return MP_QSTR_ptr8;
+        case VTYPE_PTR16:
+            return MP_QSTR_ptr16;
+        case VTYPE_PTR32:
+            return MP_QSTR_ptr32;
+        case VTYPE_PTR_NONE:
+        default:
+            return MP_QSTR_None;
     }
 }
 
@@ -244,7 +254,7 @@ STATIC void emit_native_global_exc_entry(emit_t *emit);
 STATIC void emit_native_global_exc_exit(emit_t *emit);
 STATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj);
 
-emit_t *EXPORT_FUN(new)(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels) {
+emit_t *EXPORT_FUN(new)(mp_obj_t * error_slot, uint *label_slot, mp_uint_t max_num_labels) {
     emit_t *emit = m_new0(emit_t, 1);
     emit->error_slot = error_slot;
     emit->label_slot = label_slot;
@@ -257,7 +267,7 @@ emit_t *EXPORT_FUN(new)(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_nu
     return emit;
 }
 
-void EXPORT_FUN(free)(emit_t *emit) {
+void EXPORT_FUN(free)(emit_t * emit) {
     mp_asm_base_deinit(&emit->as->base, false);
     m_del_obj(ASM_T, emit->as);
     m_del(exc_stack_entry_t, emit->exc_stack, emit->exc_stack_alloc);
@@ -733,14 +743,14 @@ STATIC void adjust_stack(emit_t *emit, mp_int_t stack_size_delta) {
     if (emit->pass > MP_PASS_SCOPE && emit->stack_size > emit->scope->stack_size) {
         emit->scope->stack_size = emit->stack_size;
     }
-#ifdef DEBUG_PRINT
+    #ifdef DEBUG_PRINT
     DEBUG_printf("  adjust_stack; stack_size=%d+%d; stack now:", emit->stack_size - stack_size_delta, stack_size_delta);
     for (int i = 0; i < emit->stack_size; i++) {
         stack_info_t *si = &emit->stack_info[i];
         DEBUG_printf(" (v=%d k=%d %d)", si->vtype, si->kind, si->data.u_reg);
     }
     DEBUG_printf("\n");
-#endif
+    #endif
 }
 
 STATIC void emit_native_adjust_stack_size(emit_t *emit, mp_int_t delta) {
@@ -831,7 +841,7 @@ STATIC vtype_kind_t load_reg_stack_imm(emit_t *emit, int reg_dest, const stack_i
         } else if (si->vtype == VTYPE_PTR_NONE) {
             emit_native_mov_reg_const(emit, reg_dest, MP_F_CONST_NONE_OBJ);
         } else {
-            mp_raise_NotImplementedError("conversion to object");
+            mp_raise_NotImplementedError(MP_ERROR_TEXT("conversion to object"));
         }
         return VTYPE_PYOBJ;
     }
@@ -1132,8 +1142,8 @@ STATIC void emit_native_label_assign(emit_t *emit, mp_uint_t l) {
 
     bool is_finally = false;
     if (emit->exc_stack_size > 0) {
-       exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1];
-       is_finally = e->is_finally && e->label == l;
+        exc_stack_entry_t *e = &emit->exc_stack[emit->exc_stack_size - 1];
+        is_finally = e->is_finally && e->label == l;
     }
 
     if (is_finally) {
@@ -1405,7 +1415,7 @@ STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
     DEBUG_printf("load_fast(%s, " UINT_FMT ")\n", qstr_str(qst), local_num);
     vtype_kind_t vtype = emit->local_vtype[local_num];
     if (vtype == VTYPE_UNBOUND) {
-        EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "local '%q' used before type known", qst);
+        EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT("local '%q' used before type known"), qst);
     }
     emit_native_pre(emit);
     if (local_num < REG_LOCAL_NUM && CAN_USE_REGS_FOR_LOCALS(emit)) {
@@ -1580,7 +1590,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
                 }
                 default:
                     EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                        "can't load from '%q'", vtype_to_qstr(vtype_base));
+                        MP_ERROR_TEXT("can't load from '%q'"), vtype_to_qstr(vtype_base));
             }
         } else {
             // index is not an immediate
@@ -1590,7 +1600,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
             emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
             if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) {
                 EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                    "can't load with '%q' index", vtype_to_qstr(vtype_index));
+                    MP_ERROR_TEXT("can't load with '%q' index"), vtype_to_qstr(vtype_index));
             }
             switch (vtype_base) {
                 case VTYPE_PTR8: {
@@ -1618,7 +1628,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
                 }
                 default:
                     EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                        "can't load from '%q'", vtype_to_qstr(vtype_base));
+                        MP_ERROR_TEXT("can't load from '%q'"), vtype_to_qstr(vtype_base));
             }
         }
         emit_post_push_reg(emit, VTYPE_INT, REG_RET);
@@ -1642,7 +1652,7 @@ STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num)
     } else if (emit->local_vtype[local_num] != vtype) {
         // type of local is not the same as object stored in it
         EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-            "local '%q' has type '%q' but source is '%q'",
+            MP_ERROR_TEXT("local '%q' has type '%q' but source is '%q'"),
             qst, vtype_to_qstr(emit->local_vtype[local_num]), vtype_to_qstr(vtype));
     }
 }
@@ -1743,7 +1753,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
             #endif
             if (vtype_value != VTYPE_BOOL && vtype_value != VTYPE_INT && vtype_value != VTYPE_UINT) {
                 EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                    "can't store '%q'", vtype_to_qstr(vtype_value));
+                    MP_ERROR_TEXT("can't store '%q'"), vtype_to_qstr(vtype_value));
             }
             switch (vtype_base) {
                 case VTYPE_PTR8: {
@@ -1809,7 +1819,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
                 }
                 default:
                     EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                        "can't store to '%q'", vtype_to_qstr(vtype_base));
+                        MP_ERROR_TEXT("can't store to '%q'"), vtype_to_qstr(vtype_base));
             }
         } else {
             // index is not an immediate
@@ -1820,7 +1830,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
             emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1);
             if (vtype_index != VTYPE_INT && vtype_index != VTYPE_UINT) {
                 EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                    "can't store with '%q' index", vtype_to_qstr(vtype_index));
+                    MP_ERROR_TEXT("can't store with '%q' index"), vtype_to_qstr(vtype_index));
             }
             #if N_X86
             // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
@@ -1830,7 +1840,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
             #endif
             if (vtype_value != VTYPE_BOOL && vtype_value != VTYPE_INT && vtype_value != VTYPE_UINT) {
                 EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                    "can't store '%q'", vtype_to_qstr(vtype_value));
+                    MP_ERROR_TEXT("can't store '%q'"), vtype_to_qstr(vtype_value));
             }
             switch (vtype_base) {
                 case VTYPE_PTR8: {
@@ -1870,7 +1880,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
                 }
                 default:
                     EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                        "can't store to '%q'", vtype_to_qstr(vtype_base));
+                        MP_ERROR_TEXT("can't store to '%q'"), vtype_to_qstr(vtype_base));
             }
         }
 
@@ -1992,7 +2002,7 @@ STATIC void emit_native_jump_helper(emit_t *emit, bool cond, mp_uint_t label, bo
         }
         if (!(vtype == VTYPE_BOOL || vtype == VTYPE_INT || vtype == VTYPE_UINT)) {
             EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                "can't implicitly convert '%q' to 'bool'", vtype_to_qstr(vtype));
+                MP_ERROR_TEXT("can't implicitly convert '%q' to 'bool'"), vtype_to_qstr(vtype));
         }
     }
     // For non-pop need to save the vtype so that emit_native_adjust_stack_size
@@ -2058,7 +2068,7 @@ STATIC void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t exc
             ASM_MOV_REG_PCREL(emit->as, REG_RET, label & ~MP_EMIT_BREAK_FROM_FOR);
             ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_RET);
             // Cancel any active exception (see also emit_native_pop_except_jump)
-            emit_native_mov_reg_const(emit, REG_RET, MP_F_CONST_NONE_OBJ);
+            ASM_MOV_REG_IMM(emit->as, REG_RET, (mp_uint_t)MP_OBJ_NULL);
             ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_RET);
             // Jump to the innermost active finally
             label = first_finally->label;
@@ -2153,9 +2163,8 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) {
 
     ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); // get exc
 
-    // Check if exc is None and jump to non-exc handler if it is
-    emit_native_mov_reg_const(emit, REG_ARG_2, MP_F_CONST_NONE_OBJ);
-    ASM_JUMP_IF_REG_EQ(emit->as, REG_ARG_1, REG_ARG_2, *emit->label_slot + 2);
+    // Check if exc is MP_OBJ_NULL (i.e. zero) and jump to non-exc handler if it is
+    ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, *emit->label_slot + 2, false);
 
     ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_2, REG_ARG_1, 0); // get type(exc)
     emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_2); // push type(exc)
@@ -2175,9 +2184,9 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) {
     emit_call(emit, MP_F_OBJ_IS_TRUE);
     ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, *emit->label_slot + 1, true);
 
-    // Replace exception with None
+    // Replace exception with MP_OBJ_NULL.
     emit_native_label_assign(emit, *emit->label_slot);
-    emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ);
+    ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL);
     ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0);
 
     // end of with cleanup nlr_catch block
@@ -2255,7 +2264,7 @@ STATIC void emit_native_for_iter_end(emit_t *emit) {
 STATIC void emit_native_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) {
     if (within_exc_handler) {
         // Cancel any active exception so subsequent handlers don't see it
-        emit_native_mov_reg_const(emit, REG_TEMP0, MP_F_CONST_NONE_OBJ);
+        ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL);
         ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0);
     } else {
         emit_native_leave_exc_stack(emit, false);
@@ -2272,7 +2281,7 @@ STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) {
     } else {
         adjust_stack(emit, 1);
         EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-            "unary op %q not implemented", mp_unary_op_method_name[op]);
+            MP_ERROR_TEXT("unary op %q not implemented"), mp_unary_op_method_name[op]);
     }
 }
 
@@ -2280,7 +2289,8 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
     DEBUG_printf("binary_op(" UINT_FMT ")\n", op);
     vtype_kind_t vtype_lhs = peek_vtype(emit, 1);
     vtype_kind_t vtype_rhs = peek_vtype(emit, 0);
-    if (vtype_lhs == VTYPE_INT && vtype_rhs == VTYPE_INT) {
+    if ((vtype_lhs == VTYPE_INT || vtype_lhs == VTYPE_UINT)
+        && (vtype_rhs == VTYPE_INT || vtype_rhs == VTYPE_UINT)) {
         // for integers, inplace and normal ops are equivalent, so use just normal ops
         if (MP_BINARY_OP_INPLACE_OR <= op && op <= MP_BINARY_OP_INPLACE_POWER) {
             op += MP_BINARY_OP_OR - MP_BINARY_OP_INPLACE_OR;
@@ -2297,9 +2307,13 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
             if (op == MP_BINARY_OP_LSHIFT) {
                 ASM_LSL_REG(emit->as, REG_RET);
             } else {
-                ASM_ASR_REG(emit->as, REG_RET);
+                if (vtype_lhs == VTYPE_UINT) {
+                    ASM_LSR_REG(emit->as, REG_RET);
+                } else {
+                    ASM_ASR_REG(emit->as, REG_RET);
+                }
             }
-            emit_post_push_reg(emit, VTYPE_INT, REG_RET);
+            emit_post_push_reg(emit, vtype_lhs, REG_RET);
             return;
         }
         #endif
@@ -2307,6 +2321,10 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
         // special cases for floor-divide and module because we dispatch to helper functions
         if (op == MP_BINARY_OP_FLOOR_DIVIDE || op == MP_BINARY_OP_MODULO) {
             emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_2, &vtype_lhs, REG_ARG_1);
+            if (vtype_lhs != VTYPE_INT) {
+                EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
+                    MP_ERROR_TEXT("div/mod not implemented for uint"), mp_binary_op_method_name[op]);
+            }
             if (op == MP_BINARY_OP_FLOOR_DIVIDE) {
                 emit_call(emit, MP_F_SMALL_INT_FLOOR_DIVIDE);
             } else {
@@ -2319,33 +2337,41 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
         int reg_rhs = REG_ARG_3;
         emit_pre_pop_reg_flexible(emit, &vtype_rhs, &reg_rhs, REG_RET, REG_ARG_2);
         emit_pre_pop_reg(emit, &vtype_lhs, REG_ARG_2);
+
         #if !(N_X64 || N_X86)
-        if (op == MP_BINARY_OP_LSHIFT) {
-            ASM_LSL_REG_REG(emit->as, REG_ARG_2, reg_rhs);
-            emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
-        } else if (op == MP_BINARY_OP_RSHIFT) {
-            ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
-            emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
-        } else
+        if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_RSHIFT) {
+            if (op == MP_BINARY_OP_LSHIFT) {
+                ASM_LSL_REG_REG(emit->as, REG_ARG_2, reg_rhs);
+            } else {
+                if (vtype_lhs == VTYPE_UINT) {
+                    ASM_LSR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
+                } else {
+                    ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
+                }
+            }
+            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
+            return;
+        }
         #endif
+
         if (op == MP_BINARY_OP_OR) {
             ASM_OR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
-            emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
+            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
         } else if (op == MP_BINARY_OP_XOR) {
             ASM_XOR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
-            emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
+            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
         } else if (op == MP_BINARY_OP_AND) {
             ASM_AND_REG_REG(emit->as, REG_ARG_2, reg_rhs);
-            emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
+            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
         } else if (op == MP_BINARY_OP_ADD) {
             ASM_ADD_REG_REG(emit->as, REG_ARG_2, reg_rhs);
-            emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
+            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
         } else if (op == MP_BINARY_OP_SUBTRACT) {
             ASM_SUB_REG_REG(emit->as, REG_ARG_2, reg_rhs);
-            emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
+            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
         } else if (op == MP_BINARY_OP_MULTIPLY) {
             ASM_MUL_REG_REG(emit->as, REG_ARG_2, reg_rhs);
-            emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
+            emit_post_push_reg(emit, vtype_lhs, REG_ARG_2);
         } else if (MP_BINARY_OP_LESS <= op && op <= MP_BINARY_OP_NOT_EQUAL) {
             // comparison ops are (in enum order):
             //  MP_BINARY_OP_LESS
@@ -2354,11 +2380,26 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
             //  MP_BINARY_OP_LESS_EQUAL
             //  MP_BINARY_OP_MORE_EQUAL
             //  MP_BINARY_OP_NOT_EQUAL
+
+            if (vtype_lhs != vtype_rhs) {
+                EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT("comparison of int and uint"));
+            }
+
+            size_t op_idx = op - MP_BINARY_OP_LESS + (vtype_lhs == VTYPE_UINT ? 0 : 6);
+
             need_reg_single(emit, REG_RET, 0);
             #if N_X64
             asm_x64_xor_r64_r64(emit->as, REG_RET, REG_RET);
             asm_x64_cmp_r64_with_r64(emit->as, reg_rhs, REG_ARG_2);
-            static byte ops[6] = {
+            static byte ops[6 + 6] = {
+                // unsigned
+                ASM_X64_CC_JB,
+                ASM_X64_CC_JA,
+                ASM_X64_CC_JE,
+                ASM_X64_CC_JBE,
+                ASM_X64_CC_JAE,
+                ASM_X64_CC_JNE,
+                // signed
                 ASM_X64_CC_JL,
                 ASM_X64_CC_JG,
                 ASM_X64_CC_JE,
@@ -2366,11 +2407,19 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
                 ASM_X64_CC_JGE,
                 ASM_X64_CC_JNE,
             };
-            asm_x64_setcc_r8(emit->as, ops[op - MP_BINARY_OP_LESS], REG_RET);
+            asm_x64_setcc_r8(emit->as, ops[op_idx], REG_RET);
             #elif N_X86
             asm_x86_xor_r32_r32(emit->as, REG_RET, REG_RET);
             asm_x86_cmp_r32_with_r32(emit->as, reg_rhs, REG_ARG_2);
-            static byte ops[6] = {
+            static byte ops[6 + 6] = {
+                // unsigned
+                ASM_X86_CC_JB,
+                ASM_X86_CC_JA,
+                ASM_X86_CC_JE,
+                ASM_X86_CC_JBE,
+                ASM_X86_CC_JAE,
+                ASM_X86_CC_JNE,
+                // signed
                 ASM_X86_CC_JL,
                 ASM_X86_CC_JG,
                 ASM_X86_CC_JE,
@@ -2378,24 +2427,39 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
                 ASM_X86_CC_JGE,
                 ASM_X86_CC_JNE,
             };
-            asm_x86_setcc_r8(emit->as, ops[op - MP_BINARY_OP_LESS], REG_RET);
+            asm_x86_setcc_r8(emit->as, ops[op_idx], REG_RET);
             #elif N_THUMB
             asm_thumb_cmp_rlo_rlo(emit->as, REG_ARG_2, reg_rhs);
-            static uint16_t ops[6] = {
-                ASM_THUMB_OP_ITE_GE,
-                ASM_THUMB_OP_ITE_GT,
+            static uint16_t ops[6 + 6] = {
+                // unsigned
+                ASM_THUMB_OP_ITE_CC,
+                ASM_THUMB_OP_ITE_HI,
                 ASM_THUMB_OP_ITE_EQ,
+                ASM_THUMB_OP_ITE_LS,
+                ASM_THUMB_OP_ITE_CS,
+                ASM_THUMB_OP_ITE_NE,
+                // signed
+                ASM_THUMB_OP_ITE_LT,
                 ASM_THUMB_OP_ITE_GT,
-                ASM_THUMB_OP_ITE_GE,
                 ASM_THUMB_OP_ITE_EQ,
+                ASM_THUMB_OP_ITE_LE,
+                ASM_THUMB_OP_ITE_GE,
+                ASM_THUMB_OP_ITE_NE,
             };
-            static byte ret[6] = { 0, 1, 1, 0, 1, 0, };
-            asm_thumb_op16(emit->as, ops[op - MP_BINARY_OP_LESS]);
-            asm_thumb_mov_rlo_i8(emit->as, REG_RET, ret[op - MP_BINARY_OP_LESS]);
-            asm_thumb_mov_rlo_i8(emit->as, REG_RET, ret[op - MP_BINARY_OP_LESS] ^ 1);
+            asm_thumb_op16(emit->as, ops[op_idx]);
+            asm_thumb_mov_rlo_i8(emit->as, REG_RET, 1);
+            asm_thumb_mov_rlo_i8(emit->as, REG_RET, 0);
             #elif N_ARM
             asm_arm_cmp_reg_reg(emit->as, REG_ARG_2, reg_rhs);
-            static uint ccs[6] = {
+            static uint ccs[6 + 6] = {
+                // unsigned
+                ASM_ARM_CC_CC,
+                ASM_ARM_CC_HI,
+                ASM_ARM_CC_EQ,
+                ASM_ARM_CC_LS,
+                ASM_ARM_CC_CS,
+                ASM_ARM_CC_NE,
+                // signed
                 ASM_ARM_CC_LT,
                 ASM_ARM_CC_GT,
                 ASM_ARM_CC_EQ,
@@ -2403,9 +2467,17 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
                 ASM_ARM_CC_GE,
                 ASM_ARM_CC_NE,
             };
-            asm_arm_setcc_reg(emit->as, REG_RET, ccs[op - MP_BINARY_OP_LESS]);
+            asm_arm_setcc_reg(emit->as, REG_RET, ccs[op_idx]);
             #elif N_XTENSA || N_XTENSAWIN
-            static uint8_t ccs[6] = {
+            static uint8_t ccs[6 + 6] = {
+                // unsigned
+                ASM_XTENSA_CC_LTU,
+                0x80 | ASM_XTENSA_CC_LTU, // for GTU we'll swap args
+                ASM_XTENSA_CC_EQ,
+                0x80 | ASM_XTENSA_CC_GEU, // for LEU we'll swap args
+                ASM_XTENSA_CC_GEU,
+                ASM_XTENSA_CC_NE,
+                // signed
                 ASM_XTENSA_CC_LT,
                 0x80 | ASM_XTENSA_CC_LT, // for GT we'll swap args
                 ASM_XTENSA_CC_EQ,
@@ -2413,21 +2485,21 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
                 ASM_XTENSA_CC_GE,
                 ASM_XTENSA_CC_NE,
             };
-            uint8_t cc = ccs[op - MP_BINARY_OP_LESS];
+            uint8_t cc = ccs[op_idx];
             if ((cc & 0x80) == 0) {
                 asm_xtensa_setcc_reg_reg_reg(emit->as, cc, REG_RET, REG_ARG_2, reg_rhs);
             } else {
                 asm_xtensa_setcc_reg_reg_reg(emit->as, cc & ~0x80, REG_RET, reg_rhs, REG_ARG_2);
             }
             #else
-                #error not implemented
+            #error not implemented
             #endif
             emit_post_push_reg(emit, VTYPE_BOOL, REG_RET);
         } else {
             // TODO other ops not yet implemented
             adjust_stack(emit, 1);
             EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                "binary op %q not implemented", mp_binary_op_method_name[op]);
+                MP_ERROR_TEXT("binary op %q not implemented"), mp_binary_op_method_name[op]);
         }
     } else if (vtype_lhs == VTYPE_PYOBJ && vtype_rhs == VTYPE_PYOBJ) {
         emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_3, &vtype_lhs, REG_ARG_2);
@@ -2448,7 +2520,7 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
     } else {
         adjust_stack(emit, -1);
         EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-            "can't do binary op between '%q' and '%q'",
+            MP_ERROR_TEXT("can't do binary op between '%q' and '%q'"),
             vtype_to_qstr(vtype_lhs), vtype_to_qstr(vtype_rhs));
     }
 }
@@ -2626,7 +2698,7 @@ STATIC void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_u
                 break;
             default:
                 // this can happen when casting a cast: int(int)
-                mp_raise_NotImplementedError("casting");
+                mp_raise_NotImplementedError(MP_ERROR_TEXT("casting"));
         }
     } else {
         assert(vtype_fun == VTYPE_PYOBJ);
@@ -2690,7 +2762,7 @@ STATIC void emit_native_return_value(emit_t *emit) {
             emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_PARENT_RET : REG_ARG_1);
             if (vtype != return_vtype) {
                 EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
-                    "return expected '%q' but got '%q'",
+                    MP_ERROR_TEXT("return expected '%q' but got '%q'"),
                     vtype_to_qstr(return_vtype), vtype_to_qstr(vtype));
             }
         }
@@ -2719,7 +2791,7 @@ STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) {
     vtype_kind_t vtype_exc;
     emit_pre_pop_reg(emit, &vtype_exc, REG_ARG_1); // arg1 = object to raise
     if (vtype_exc != VTYPE_PYOBJ) {
-        EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "must raise an object");
+        EMIT_NATIVE_VIPER_TYPE_ERROR(emit, MP_ERROR_TEXT("must raise an object"));
     }
     // TODO probably make this 1 call to the runtime (which could even call convert, native_raise(obj, type))
     emit_call(emit, MP_F_NATIVE_RAISE);
@@ -2729,7 +2801,7 @@ STATIC void emit_native_yield(emit_t *emit, int kind) {
     // Note: 1 (yield) or 3 (yield from) labels are reserved for this function, starting at *emit->label_slot
 
     if (emit->do_viper_types) {
-        mp_raise_NotImplementedError("native yield");
+        mp_raise_NotImplementedError(MP_ERROR_TEXT("native yield"));
     }
     emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
 
@@ -2775,6 +2847,7 @@ STATIC void emit_native_yield(emit_t *emit, int kind) {
                 // Found active handler, get its PC
                 ASM_MOV_REG_PCREL(emit->as, REG_RET, e->label);
                 ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_PC(emit), REG_RET);
+                break;
             }
         }
     }

+ 17 - 8
py/formatfloat.c

@@ -68,11 +68,20 @@ union floatbits {
     float f;
     uint32_t u;
 };
-static inline int fp_signbit(float x) { union floatbits fb = {x}; return fb.u & FLT_SIGN_MASK; }
+static inline int fp_signbit(float x) {
+    union floatbits fb = {x};
+    return fb.u & FLT_SIGN_MASK;
+}
 #define fp_isnan(x) isnan(x)
 #define fp_isinf(x) isinf(x)
-static inline int fp_iszero(float x) { union floatbits fb = {x}; return fb.u == 0; }
-static inline int fp_isless1(float x) { union floatbits fb = {x}; return fb.u < 0x3f800000; }
+static inline int fp_iszero(float x) {
+    union floatbits fb = {x};
+    return fb.u == 0;
+}
+static inline int fp_isless1(float x) {
+    union floatbits fb = {x};
+    return fb.u < 0x3f800000;
+}
 
 #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
 
@@ -91,15 +100,15 @@ static inline int fp_isless1(float x) { union floatbits fb = {x}; return fb.u <
 
 static const FPTYPE g_pos_pow[] = {
     #if FPDECEXP > 32
-    1e256, 1e128, 1e64,
+    MICROPY_FLOAT_CONST(1e256), MICROPY_FLOAT_CONST(1e128), MICROPY_FLOAT_CONST(1e64),
     #endif
-    1e32, 1e16, 1e8, 1e4, 1e2, 1e1
+    MICROPY_FLOAT_CONST(1e32), MICROPY_FLOAT_CONST(1e16), MICROPY_FLOAT_CONST(1e8), MICROPY_FLOAT_CONST(1e4), MICROPY_FLOAT_CONST(1e2), MICROPY_FLOAT_CONST(1e1)
 };
 static const FPTYPE g_neg_pow[] = {
     #if FPDECEXP > 32
-    1e-256, 1e-128, 1e-64,
+    MICROPY_FLOAT_CONST(1e-256), MICROPY_FLOAT_CONST(1e-128), MICROPY_FLOAT_CONST(1e-64),
     #endif
-    1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1
+    MICROPY_FLOAT_CONST(1e-32), MICROPY_FLOAT_CONST(1e-16), MICROPY_FLOAT_CONST(1e-8), MICROPY_FLOAT_CONST(1e-4), MICROPY_FLOAT_CONST(1e-2), MICROPY_FLOAT_CONST(1e-1)
 };
 
 int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
@@ -282,7 +291,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
         if (fmt == 'e' && prec > (buf_remaining - FPMIN_BUF_SIZE)) {
             prec = buf_remaining - FPMIN_BUF_SIZE;
         }
-        if (fmt == 'g'){
+        if (fmt == 'g') {
             // Truncate precision to prevent buffer overflow
             if (prec + (FPMIN_BUF_SIZE - 1) > buf_remaining) {
                 prec = buf_remaining - (FPMIN_BUF_SIZE - 1);

+ 1 - 1
py/frozenmod.c

@@ -146,7 +146,7 @@ int mp_find_frozen_module(const char *str, size_t len, void **data) {
     #if MICROPY_MODULE_FROZEN_MPY
     const mp_raw_code_t *rc = mp_find_frozen_mpy(str, len);
     if (rc != NULL) {
-        *data = (void*)rc;
+        *data = (void *)rc;
         return MP_FROZEN_MPY;
     }
     #endif

+ 84 - 62
py/gc.c

@@ -82,7 +82,7 @@
 #define ATB_HEAD_TO_MARK(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
 #define ATB_MARK_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
 
-#define BLOCK_FROM_PTR(ptr) (((byte*)(ptr) - MP_STATE_MEM(gc_pool_start)) / BYTES_PER_BLOCK)
+#define BLOCK_FROM_PTR(ptr) (((byte *)(ptr) - MP_STATE_MEM(gc_pool_start)) / BYTES_PER_BLOCK)
 #define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (uintptr_t)MP_STATE_MEM(gc_pool_start)))
 #define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB)
 
@@ -108,43 +108,43 @@
 // TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
 void gc_init(void *start, void *end) {
     // align end pointer on block boundary
-    end = (void*)((uintptr_t)end & (~(BYTES_PER_BLOCK - 1)));
-    DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte*)end - (byte*)start);
+    end = (void *)((uintptr_t)end & (~(BYTES_PER_BLOCK - 1)));
+    DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte *)end - (byte *)start);
 
     // calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes):
     // T = A + F + P
     //     F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB
     //     P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK
     // => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK)
-    size_t total_byte_len = (byte*)end - (byte*)start;
-#if MICROPY_ENABLE_FINALISER
+    size_t total_byte_len = (byte *)end - (byte *)start;
+    #if MICROPY_ENABLE_FINALISER
     MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK);
-#else
+    #else
     MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
-#endif
+    #endif
 
-    MP_STATE_MEM(gc_alloc_table_start) = (byte*)start;
+    MP_STATE_MEM(gc_alloc_table_start) = (byte *)start;
 
-#if MICROPY_ENABLE_FINALISER
+    #if MICROPY_ENABLE_FINALISER
     size_t gc_finaliser_table_byte_len = (MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
     MP_STATE_MEM(gc_finaliser_table_start) = MP_STATE_MEM(gc_alloc_table_start) + MP_STATE_MEM(gc_alloc_table_byte_len);
-#endif
+    #endif
 
     size_t gc_pool_block_len = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB;
-    MP_STATE_MEM(gc_pool_start) = (byte*)end - gc_pool_block_len * BYTES_PER_BLOCK;
+    MP_STATE_MEM(gc_pool_start) = (byte *)end - gc_pool_block_len * BYTES_PER_BLOCK;
     MP_STATE_MEM(gc_pool_end) = end;
 
-#if MICROPY_ENABLE_FINALISER
+    #if MICROPY_ENABLE_FINALISER
     assert(MP_STATE_MEM(gc_pool_start) >= MP_STATE_MEM(gc_finaliser_table_start) + gc_finaliser_table_byte_len);
-#endif
+    #endif
 
     // clear ATBs
     memset(MP_STATE_MEM(gc_alloc_table_start), 0, MP_STATE_MEM(gc_alloc_table_byte_len));
 
-#if MICROPY_ENABLE_FINALISER
+    #if MICROPY_ENABLE_FINALISER
     // clear FTBs
     memset(MP_STATE_MEM(gc_finaliser_table_start), 0, gc_finaliser_table_byte_len);
-#endif
+    #endif
 
     // set last free ATB index to start of heap
     MP_STATE_MEM(gc_last_free_atb_index) = 0;
@@ -161,15 +161,15 @@ void gc_init(void *start, void *end) {
     MP_STATE_MEM(gc_alloc_amount) = 0;
     #endif
 
-    #if MICROPY_PY_THREAD
+    #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL
     mp_thread_mutex_init(&MP_STATE_MEM(gc_mutex));
     #endif
 
     DEBUG_printf("GC layout:\n");
     DEBUG_printf("  alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_alloc_table_start), MP_STATE_MEM(gc_alloc_table_byte_len), MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB);
-#if MICROPY_ENABLE_FINALISER
+    #if MICROPY_ENABLE_FINALISER
     DEBUG_printf("  finaliser table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_finaliser_table_start), gc_finaliser_table_byte_len, gc_finaliser_table_byte_len * BLOCKS_PER_FTB);
-#endif
+    #endif
     DEBUG_printf("  pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_pool_start), gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len);
 }
 
@@ -191,9 +191,9 @@ bool gc_is_locked(void) {
 
 // ptr should be of type void*
 #define VERIFY_PTR(ptr) ( \
-        ((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) == 0      /* must be aligned on a block */ \
-        && ptr >= (void*)MP_STATE_MEM(gc_pool_start)     /* must be above start of pool */ \
-        && ptr < (void*)MP_STATE_MEM(gc_pool_end)        /* must be below end of pool */ \
+    ((uintptr_t)(ptr) & (BYTES_PER_BLOCK - 1)) == 0          /* must be aligned on a block */ \
+    && ptr >= (void *)MP_STATE_MEM(gc_pool_start)        /* must be above start of pool */ \
+    && ptr < (void *)MP_STATE_MEM(gc_pool_end)           /* must be below end of pool */ \
     )
 
 #ifndef TRACE_MARK
@@ -219,8 +219,8 @@ STATIC void gc_mark_subtree(size_t block) {
         } while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
 
         // check this block's children
-        void **ptrs = (void**)PTR_FROM_BLOCK(block);
-        for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void*); i > 0; i--, ptrs++) {
+        void **ptrs = (void **)PTR_FROM_BLOCK(block);
+        for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void *); i > 0; i--, ptrs++) {
             void *ptr = *ptrs;
             if (VERIFY_PTR(ptr)) {
                 // Mark and push this pointer
@@ -271,9 +271,9 @@ STATIC void gc_sweep(void) {
     for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
         switch (ATB_GET_KIND(block)) {
             case AT_HEAD:
-#if MICROPY_ENABLE_FINALISER
+                #if MICROPY_ENABLE_FINALISER
                 if (FTB_GET(block)) {
-                    mp_obj_base_t *obj = (mp_obj_base_t*)PTR_FROM_BLOCK(block);
+                    mp_obj_base_t *obj = (mp_obj_base_t *)PTR_FROM_BLOCK(block);
                     if (obj->type != NULL) {
                         // if the object has a type then see if it has a __del__ method
                         mp_obj_t dest[2];
@@ -292,19 +292,20 @@ STATIC void gc_sweep(void) {
                     // clear finaliser flag
                     FTB_CLEAR(block);
                 }
-#endif
+                #endif
                 free_tail = 1;
                 DEBUG_printf("gc_sweep(%p)\n", PTR_FROM_BLOCK(block));
                 #if MICROPY_PY_GC_COLLECT_RETVAL
                 MP_STATE_MEM(gc_collected)++;
                 #endif
                 // fall through to free the head
+                MP_FALLTHROUGH
 
             case AT_TAIL:
                 if (free_tail) {
                     ATB_ANY_TO_FREE(block);
                     #if CLEAR_ON_SWEEP
-                    memset((void*)PTR_FROM_BLOCK(block), 0, BYTES_PER_BLOCK);
+                    memset((void *)PTR_FROM_BLOCK(block), 0, BYTES_PER_BLOCK);
                     #endif
                 }
                 break;
@@ -328,15 +329,15 @@ void gc_collect_start(void) {
     // Trace root pointers.  This relies on the root pointers being organised
     // correctly in the mp_state_ctx structure.  We scan nlr_top, dict_locals,
     // dict_globals, then the root pointer section of mp_state_vm.
-    void **ptrs = (void**)(void*)&mp_state_ctx;
+    void **ptrs = (void **)(void *)&mp_state_ctx;
     size_t root_start = offsetof(mp_state_ctx_t, thread.dict_locals);
     size_t root_end = offsetof(mp_state_ctx_t, vm.qstr_last_chunk);
-    gc_collect_root(ptrs + root_start / sizeof(void*), (root_end - root_start) / sizeof(void*));
+    gc_collect_root(ptrs + root_start / sizeof(void *), (root_end - root_start) / sizeof(void *));
 
     #if MICROPY_ENABLE_PYSTACK
     // Trace root pointers from the Python stack.
-    ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start);
-    gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*));
+    ptrs = (void **)(void *)MP_STATE_THREAD(pystack_start);
+    gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void *));
     #endif
 }
 
@@ -473,10 +474,12 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) {
         n_free = 0;
         for (i = MP_STATE_MEM(gc_last_free_atb_index); i < MP_STATE_MEM(gc_alloc_table_byte_len); i++) {
             byte a = MP_STATE_MEM(gc_alloc_table_start)[i];
+            // *FORMAT-OFF*
             if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; }
             if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; }
             if (ATB_2_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 2; goto found; } } else { n_free = 0; }
             if (ATB_3_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 3; goto found; } } else { n_free = 0; }
+            // *FORMAT-ON*
         }
 
         GC_EXIT();
@@ -516,7 +519,7 @@ found:
 
     // get pointer to first block
     // we must create this pointer before unlocking the GC so a collection can find it
-    void *ret_ptr = (void*)(MP_STATE_MEM(gc_pool_start) + start_block * BYTES_PER_BLOCK);
+    void *ret_ptr = (void *)(MP_STATE_MEM(gc_pool_start) + start_block * BYTES_PER_BLOCK);
     DEBUG_printf("gc_alloc(%p)\n", ret_ptr);
 
     #if MICROPY_GC_ALLOC_THRESHOLD
@@ -527,20 +530,20 @@ found:
 
     #if MICROPY_GC_CONSERVATIVE_CLEAR
     // be conservative and zero out all the newly allocated blocks
-    memset((byte*)ret_ptr, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK);
+    memset((byte *)ret_ptr, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK);
     #else
     // zero out the additional bytes of the newly allocated blocks
     // This is needed because the blocks may have previously held pointers
     // to the heap and will not be set to something else if the caller
     // doesn't actually use the entire block.  As such they will continue
     // to point to the heap and may prevent other blocks from being reclaimed.
-    memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
+    memset((byte *)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
     #endif
 
     #if MICROPY_ENABLE_FINALISER
     if (has_finaliser) {
         // clear type pointer in case it is never set
-        ((mp_obj_base_t*)ret_ptr)->type = NULL;
+        ((mp_obj_base_t *)ret_ptr)->type = NULL;
         // set mp_obj flag only if it has a finaliser
         GC_ENTER();
         FTB_SET(start_block);
@@ -641,11 +644,11 @@ void *gc_realloc(void *ptr, mp_uint_t n_bytes) {
         if (ptr == NULL) {
             has_finaliser = false;
         } else {
-#if MICROPY_ENABLE_FINALISER
+            #if MICROPY_ENABLE_FINALISER
             has_finaliser = FTB_GET(BLOCK_FROM_PTR((mp_uint_t)ptr));
-#else
+            #else
             has_finaliser = false;
-#endif
+            #endif
         }
         void *ptr2 = gc_alloc(n_bytes, has_finaliser);
         if (ptr2 == NULL) {
@@ -694,7 +697,7 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
     // free blocks to satisfy the realloc.  Note that we need to compute the
     // total size of the existing memory chunk so we can correctly and
     // efficiently shrink it (see below for shrinking code).
-    size_t n_free   = 0;
+    size_t n_free = 0;
     size_t n_blocks = 1; // counting HEAD block
     size_t max_block = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB;
     for (size_t bl = block + n_blocks; bl < max_block; bl++) {
@@ -753,10 +756,10 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
 
         #if MICROPY_GC_CONSERVATIVE_CLEAR
         // be conservative and zero out all the newly allocated blocks
-        memset((byte*)ptr_in + n_blocks * BYTES_PER_BLOCK, 0, (new_blocks - n_blocks) * BYTES_PER_BLOCK);
+        memset((byte *)ptr_in + n_blocks * BYTES_PER_BLOCK, 0, (new_blocks - n_blocks) * BYTES_PER_BLOCK);
         #else
         // zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc)
-        memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
+        memset((byte *)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
         #endif
 
         #if EXTENSIVE_HEAP_PROFILING
@@ -800,7 +803,7 @@ void gc_dump_info(void) {
     mp_printf(&mp_plat_print, "GC: total: %u, used: %u, free: %u\n",
         (uint)info.total, (uint)info.used, (uint)info.free);
     mp_printf(&mp_plat_print, " No. of 1-blocks: %u, 2-blocks: %u, max blk sz: %u, max free sz: %u\n",
-           (uint)info.num_1block, (uint)info.num_2block, (uint)info.max_block, (uint)info.max_free);
+        (uint)info.num_1block, (uint)info.num_2block, (uint)info.max_block, (uint)info.max_free);
 }
 
 void gc_dump_alloc_table(void) {
@@ -832,12 +835,14 @@ void gc_dump_alloc_table(void) {
             }
             // print header for new line of blocks
             // (the cast to uint32_t is for 16-bit ports)
-            //mp_printf(&mp_plat_print, "\n%05x: ", (uint)(PTR_FROM_BLOCK(bl) & (uint32_t)0xfffff));
+            // mp_printf(&mp_plat_print, "\n%05x: ", (uint)(PTR_FROM_BLOCK(bl) & (uint32_t)0xfffff));
             mp_printf(&mp_plat_print, "\n%05x: ", (uint)((bl * BYTES_PER_BLOCK) & (uint32_t)0xfffff));
         }
         int c = ' ';
         switch (ATB_GET_KIND(bl)) {
-            case AT_FREE: c = '.'; break;
+            case AT_FREE:
+                c = '.';
+                break;
             /* this prints out if the object is reachable from BSS or STACK (for unix only)
             case AT_HEAD: {
                 c = 'h';
@@ -866,35 +871,48 @@ void gc_dump_alloc_table(void) {
             */
             /* this prints the uPy object type of the head block */
             case AT_HEAD: {
-                void **ptr = (void**)(MP_STATE_MEM(gc_pool_start) + bl * BYTES_PER_BLOCK);
-                if (*ptr == &mp_type_tuple) { c = 'T'; }
-                else if (*ptr == &mp_type_list) { c = 'L'; }
-                else if (*ptr == &mp_type_dict) { c = 'D'; }
-                else if (*ptr == &mp_type_str || *ptr == &mp_type_bytes) { c = 'S'; }
+                void **ptr = (void **)(MP_STATE_MEM(gc_pool_start) + bl * BYTES_PER_BLOCK);
+                if (*ptr == &mp_type_tuple) {
+                    c = 'T';
+                } else if (*ptr == &mp_type_list) {
+                    c = 'L';
+                } else if (*ptr == &mp_type_dict) {
+                    c = 'D';
+                } else if (*ptr == &mp_type_str || *ptr == &mp_type_bytes) {
+                    c = 'S';
+                }
                 #if MICROPY_PY_BUILTINS_BYTEARRAY
-                else if (*ptr == &mp_type_bytearray) { c = 'A'; }
+                else if (*ptr == &mp_type_bytearray) {
+                    c = 'A';
+                }
                 #endif
                 #if MICROPY_PY_ARRAY
-                else if (*ptr == &mp_type_array) { c = 'A'; }
+                else if (*ptr == &mp_type_array) {
+                    c = 'A';
+                }
                 #endif
                 #if MICROPY_PY_BUILTINS_FLOAT
-                else if (*ptr == &mp_type_float) { c = 'F'; }
+                else if (*ptr == &mp_type_float) {
+                    c = 'F';
+                }
                 #endif
-                else if (*ptr == &mp_type_fun_bc) { c = 'B'; }
-                else if (*ptr == &mp_type_module) { c = 'M'; }
-                else {
+                else if (*ptr == &mp_type_fun_bc) {
+                    c = 'B';
+                } else if (*ptr == &mp_type_module) {
+                    c = 'M';
+                } else {
                     c = 'h';
                     #if 0
                     // This code prints "Q" for qstr-pool data, and "q" for qstr-str
                     // data.  It can be useful to see how qstrs are being allocated,
                     // but is disabled by default because it is very slow.
                     for (qstr_pool_t *pool = MP_STATE_VM(last_pool); c == 'h' && pool != NULL; pool = pool->prev) {
-                        if ((qstr_pool_t*)ptr == pool) {
+                        if ((qstr_pool_t *)ptr == pool) {
                             c = 'Q';
                             break;
                         }
                         for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {
-                            if ((const byte*)ptr == *q) {
+                            if ((const byte *)ptr == *q) {
                                 c = 'q';
                                 break;
                             }
@@ -904,8 +922,12 @@ void gc_dump_alloc_table(void) {
                 }
                 break;
             }
-            case AT_TAIL: c = '='; break;
-            case AT_MARK: c = 'm'; break;
+            case AT_TAIL:
+                c = '=';
+                break;
+            case AT_MARK:
+                c = 'm';
+                break;
         }
         mp_printf(&mp_plat_print, "%c", c);
     }
@@ -931,11 +953,11 @@ void gc_test(void) {
         p2[1] = p;
         ptrs[0] = p2;
     }
-    for (int i = 0; i < 25; i+=2) {
+    for (int i = 0; i < 25; i += 2) {
         mp_uint_t *p = gc_alloc(i, false);
         printf("p=%p\n", p);
         if (i & 3) {
-            //ptrs[i] = p;
+            // ptrs[i] = p;
         }
     }
 
@@ -943,7 +965,7 @@ void gc_test(void) {
     gc_dump_alloc_table();
     printf("Starting GC...\n");
     gc_collect_start();
-    gc_collect_root(ptrs, sizeof(ptrs) / sizeof(void*));
+    gc_collect_root(ptrs, sizeof(ptrs) / sizeof(void *));
     gc_collect_end();
     printf("After GC:\n");
     gc_dump_alloc_table();

+ 34 - 19
py/grammar.h

@@ -3,7 +3,7 @@
  *
  * The MIT License (MIT)
  *
- * Copyright (c) 2013-2015 Damien P. George
+ * Copyright (c) 2013-2020 Damien P. George
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -24,10 +24,17 @@
  * THE SOFTWARE.
  */
 
+// *FORMAT-OFF*
+
 // rules for writing rules:
 // - zero_or_more is implemented using opt_rule around a one_or_more rule
 // - don't put opt_rule in arguments of or rule; instead, wrap the call to this or rule in opt_rule
 
+// Generic sub-rules used by multiple rules below.
+
+DEF_RULE_NC(generic_colon_test, and_ident(2), tok(DEL_COLON), rule(test))
+DEF_RULE_NC(generic_equal_test, and_ident(2), tok(DEL_EQUAL), rule(test))
+
 // # Start symbols for the grammar:
 // #       single_input is a single interactive statement;
 // #       file_input is a module or sequence of commands read from an input file;
@@ -69,19 +76,16 @@ DEF_RULE_NC(funcdefrettype, and_ident(2), tok(DEL_MINUS_MORE), rule(test))
 // note: typedargslist lets through more than is allowed, compiler does further checks
 DEF_RULE_NC(typedargslist, list_with_end, rule(typedargslist_item), tok(DEL_COMMA))
 DEF_RULE_NC(typedargslist_item, or(3), rule(typedargslist_name), rule(typedargslist_star), rule(typedargslist_dbl_star))
-DEF_RULE_NC(typedargslist_name, and_ident(3), tok(NAME), opt_rule(typedargslist_colon), opt_rule(typedargslist_equal))
+DEF_RULE_NC(typedargslist_name, and_ident(3), tok(NAME), opt_rule(generic_colon_test), opt_rule(generic_equal_test))
 DEF_RULE_NC(typedargslist_star, and(2), tok(OP_STAR), opt_rule(tfpdef))
-DEF_RULE_NC(typedargslist_dbl_star, and(3), tok(OP_DBL_STAR), tok(NAME), opt_rule(typedargslist_colon))
-DEF_RULE_NC(typedargslist_colon, and_ident(2), tok(DEL_COLON), rule(test))
-DEF_RULE_NC(typedargslist_equal, and_ident(2), tok(DEL_EQUAL), rule(test))
-DEF_RULE_NC(tfpdef, and(2), tok(NAME), opt_rule(typedargslist_colon))
+DEF_RULE_NC(typedargslist_dbl_star, and(3), tok(OP_DBL_STAR), tok(NAME), opt_rule(generic_colon_test))
+DEF_RULE_NC(tfpdef, and(2), tok(NAME), opt_rule(generic_colon_test))
 // note: varargslist lets through more than is allowed, compiler does further checks
 DEF_RULE_NC(varargslist, list_with_end, rule(varargslist_item), tok(DEL_COMMA))
 DEF_RULE_NC(varargslist_item, or(3), rule(varargslist_name), rule(varargslist_star), rule(varargslist_dbl_star))
-DEF_RULE_NC(varargslist_name, and_ident(2), tok(NAME), opt_rule(varargslist_equal))
+DEF_RULE_NC(varargslist_name, and_ident(2), tok(NAME), opt_rule(generic_equal_test))
 DEF_RULE_NC(varargslist_star, and(2), tok(OP_STAR), opt_rule(vfpdef))
 DEF_RULE_NC(varargslist_dbl_star, and(2), tok(OP_DBL_STAR), tok(NAME))
-DEF_RULE_NC(varargslist_equal, and_ident(2), tok(DEL_EQUAL), rule(test))
 DEF_RULE_NC(vfpdef, and_ident(1), tok(NAME))
 
 // stmt: compound_stmt | simple_stmt
@@ -94,20 +98,22 @@ DEF_RULE_NC(simple_stmt, and_ident(2), rule(simple_stmt_2), tok(NEWLINE))
 DEF_RULE(simple_stmt_2, c(generic_all_nodes), list_with_end, rule(small_stmt), tok(DEL_SEMICOLON))
 
 // small_stmt: expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt
-// expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*)
+// expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*)
 // testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
+// annassign: ':' test ['=' (yield_expr|testlist_star_expr)]
 // augassign: '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='
-// # For normal assignments, additional restrictions enforced by the interpreter
+// # For normal and annotated assignments, additional restrictions enforced by the interpreter
 
 DEF_RULE_NC(small_stmt, or(8), rule(del_stmt), rule(pass_stmt), rule(flow_stmt), rule(import_stmt), rule(global_stmt), rule(nonlocal_stmt), rule(assert_stmt), rule(expr_stmt))
 DEF_RULE(expr_stmt, c(expr_stmt), and(2), rule(testlist_star_expr), opt_rule(expr_stmt_2))
-DEF_RULE_NC(expr_stmt_2, or(2), rule(expr_stmt_augassign), rule(expr_stmt_assign_list))
+DEF_RULE_NC(expr_stmt_2, or(3), rule(annassign), rule(expr_stmt_augassign), rule(expr_stmt_assign_list))
 DEF_RULE_NC(expr_stmt_augassign, and_ident(2), rule(augassign), rule(expr_stmt_6))
 DEF_RULE_NC(expr_stmt_assign_list, one_or_more, rule(expr_stmt_assign))
 DEF_RULE_NC(expr_stmt_assign, and_ident(2), tok(DEL_EQUAL), rule(expr_stmt_6))
 DEF_RULE_NC(expr_stmt_6, or(2), rule(yield_expr), rule(testlist_star_expr))
 DEF_RULE(testlist_star_expr, c(generic_tuple), list_with_end, rule(testlist_star_expr_2), tok(DEL_COMMA))
 DEF_RULE_NC(testlist_star_expr_2, or(2), rule(star_expr), rule(test))
+DEF_RULE_NC(annassign, and(3), tok(DEL_COLON), rule(test), opt_rule(expr_stmt_assign))
 DEF_RULE_NC(augassign, or(13), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DEL_STAR_EQUAL), tok(DEL_AT_EQUAL), tok(DEL_SLASH_EQUAL), tok(DEL_PERCENT_EQUAL), tok(DEL_AMPERSAND_EQUAL), tok(DEL_PIPE_EQUAL), tok(DEL_CARET_EQUAL), tok(DEL_DBL_LESS_EQUAL), tok(DEL_DBL_MORE_EQUAL), tok(DEL_DBL_STAR_EQUAL), tok(DEL_DBL_SLASH_EQUAL))
 
 // del_stmt: 'del' exprlist
@@ -182,10 +188,10 @@ DEF_RULE_NC(async_stmt_2, or(3), rule(funcdef), rule(with_stmt), rule(for_stmt))
 #else
 DEF_RULE_NC(compound_stmt, or(8), rule(if_stmt), rule(while_stmt), rule(for_stmt), rule(try_stmt), rule(with_stmt), rule(funcdef), rule(classdef), rule(decorated))
 #endif
-DEF_RULE(if_stmt, c(if_stmt), and(6), tok(KW_IF), rule(test), tok(DEL_COLON), rule(suite), opt_rule(if_stmt_elif_list), opt_rule(else_stmt))
+DEF_RULE(if_stmt, c(if_stmt), and(6), tok(KW_IF), rule(namedexpr_test), tok(DEL_COLON), rule(suite), opt_rule(if_stmt_elif_list), opt_rule(else_stmt))
 DEF_RULE_NC(if_stmt_elif_list, one_or_more, rule(if_stmt_elif))
-DEF_RULE_NC(if_stmt_elif, and(4), tok(KW_ELIF), rule(test), tok(DEL_COLON), rule(suite))
-DEF_RULE(while_stmt, c(while_stmt), and(5), tok(KW_WHILE), rule(test), tok(DEL_COLON), rule(suite), opt_rule(else_stmt))
+DEF_RULE_NC(if_stmt_elif, and(4), tok(KW_ELIF), rule(namedexpr_test), tok(DEL_COLON), rule(suite))
+DEF_RULE(while_stmt, c(while_stmt), and(5), tok(KW_WHILE), rule(namedexpr_test), tok(DEL_COLON), rule(suite), opt_rule(else_stmt))
 DEF_RULE(for_stmt, c(for_stmt), and(7), tok(KW_FOR), rule(exprlist), tok(KW_IN), rule(testlist), tok(DEL_COLON), rule(suite), opt_rule(else_stmt))
 DEF_RULE(try_stmt, c(try_stmt), and(4), tok(KW_TRY), tok(DEL_COLON), rule(suite), rule(try_stmt_2))
 DEF_RULE_NC(try_stmt_2, or(2), rule(try_stmt_except_and_more), rule(try_stmt_finally))
@@ -208,6 +214,12 @@ DEF_RULE(suite_block_stmts, c(generic_all_nodes), one_or_more, rule(stmt))
 // lambdef: 'lambda' [varargslist] ':' test
 // lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
 
+#if MICROPY_PY_ASSIGN_EXPR
+DEF_RULE(namedexpr_test, c(namedexpr), and_ident(2), rule(test), opt_rule(namedexpr_test_2))
+DEF_RULE_NC(namedexpr_test_2, and_ident(2), tok(OP_ASSIGN), rule(test))
+#else
+DEF_RULE_NC(namedexpr_test, or(1), rule(test))
+#endif
 DEF_RULE_NC(test, or(2), rule(lambdef), rule(test_if_expr))
 DEF_RULE(test_if_expr, c(test_if_expr), and_ident(2), rule(or_test), opt_rule(test_if_else))
 DEF_RULE_NC(test_if_else, and(4), tok(KW_IF), rule(or_test), tok(KW_ELSE), rule(test))
@@ -274,7 +286,7 @@ DEF_RULE_NC(atom_2b, or(2), rule(yield_expr), rule(testlist_comp))
 DEF_RULE(atom_bracket, c(atom_bracket), and(3), tok(DEL_BRACKET_OPEN), opt_rule(testlist_comp), tok(DEL_BRACKET_CLOSE))
 DEF_RULE(atom_brace, c(atom_brace), and(3), tok(DEL_BRACE_OPEN), opt_rule(dictorsetmaker), tok(DEL_BRACE_CLOSE))
 DEF_RULE_NC(testlist_comp, and_ident(2), rule(testlist_comp_2), opt_rule(testlist_comp_3))
-DEF_RULE_NC(testlist_comp_2, or(2), rule(star_expr), rule(test))
+DEF_RULE_NC(testlist_comp_2, or(2), rule(star_expr), rule(namedexpr_test))
 DEF_RULE_NC(testlist_comp_3, or(2), rule(comp_for), rule(testlist_comp_3b))
 DEF_RULE_NC(testlist_comp_3b, and_ident(2), tok(DEL_COMMA), opt_rule(testlist_comp_3c))
 DEF_RULE_NC(testlist_comp_3c, list_with_end, rule(testlist_comp_2), tok(DEL_COMMA))
@@ -310,8 +322,7 @@ DEF_RULE(testlist, c(generic_tuple), list_with_end, rule(test), tok(DEL_COMMA))
 // TODO dictorsetmaker lets through more than is allowed
 DEF_RULE_NC(dictorsetmaker, and_ident(2), rule(dictorsetmaker_item), opt_rule(dictorsetmaker_tail))
 #if MICROPY_PY_BUILTINS_SET
-DEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and_ident(2), rule(test), opt_rule(dictorsetmaker_colon))
-DEF_RULE_NC(dictorsetmaker_colon, and_ident(2), tok(DEL_COLON), rule(test))
+DEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and_ident(2), rule(test), opt_rule(generic_colon_test))
 #else
 DEF_RULE(dictorsetmaker_item, c(dictorsetmaker_item), and(3), rule(test), tok(DEL_COLON), rule(test))
 #endif
@@ -340,8 +351,12 @@ DEF_RULE_NC(arglist_dbl_star, and(2), tok(OP_DBL_STAR), rule(test))
 // comp_if: 'if' test_nocond [comp_iter]
 
 DEF_RULE_NC(argument, and_ident(2), rule(test), opt_rule(argument_2))
-DEF_RULE_NC(argument_2, or(2), rule(comp_for), rule(argument_3))
-DEF_RULE_NC(argument_3, and_ident(2), tok(DEL_EQUAL), rule(test))
+#if MICROPY_PY_ASSIGN_EXPR
+DEF_RULE_NC(argument_2, or(3), rule(comp_for), rule(generic_equal_test), rule(argument_3))
+DEF_RULE_NC(argument_3, and(2), tok(OP_ASSIGN), rule(test))
+#else
+DEF_RULE_NC(argument_2, or(2), rule(comp_for), rule(generic_equal_test))
+#endif
 DEF_RULE_NC(comp_iter, or(2), rule(comp_for), rule(comp_if))
 DEF_RULE_NC(comp_for, and_blank(5), tok(KW_FOR), rule(exprlist), tok(KW_IN), rule(or_test), opt_rule(comp_iter))
 DEF_RULE_NC(comp_if, and(3), tok(KW_IF), rule(test_nocond), opt_rule(comp_iter))

+ 41 - 20
py/lexer.c

@@ -105,9 +105,9 @@ STATIC bool is_following_odigit(mp_lexer_t *lex) {
 
 STATIC bool is_string_or_bytes(mp_lexer_t *lex) {
     return is_char_or(lex, '\'', '\"')
-        || (is_char_or3(lex, 'r', 'u', 'b') && is_char_following_or(lex, '\'', '\"'))
-        || ((is_char_and(lex, 'r', 'b') || is_char_and(lex, 'b', 'r'))
-            && is_char_following_following_or(lex, '\'', '\"'));
+           || (is_char_or3(lex, 'r', 'u', 'b') && is_char_following_or(lex, '\'', '\"'))
+           || ((is_char_and(lex, 'r', 'b') || is_char_and(lex, 'b', 'r'))
+               && is_char_following_following_or(lex, '\'', '\"'));
 }
 
 // to easily parse utf-8 identifiers we allow any raw byte with high bit set
@@ -174,7 +174,8 @@ STATIC void indent_pop(mp_lexer_t *lex) {
 // this means if the start of two ops are the same then they are equal til the last char
 
 STATIC const char *const tok_enc =
-    "()[]{},:;~" // singles
+    "()[]{},;~"   // singles
+    ":e="         // : :=
     "<e=c<e="     // < <= << <<=
     ">e=c>e="     // > >= >> >>=
     "*e=c*e="     // * *= ** **=
@@ -194,8 +195,9 @@ STATIC const uint8_t tok_enc_kind[] = {
     MP_TOKEN_DEL_PAREN_OPEN, MP_TOKEN_DEL_PAREN_CLOSE,
     MP_TOKEN_DEL_BRACKET_OPEN, MP_TOKEN_DEL_BRACKET_CLOSE,
     MP_TOKEN_DEL_BRACE_OPEN, MP_TOKEN_DEL_BRACE_CLOSE,
-    MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_COLON, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_OP_TILDE,
+    MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_OP_TILDE,
 
+    MP_TOKEN_DEL_COLON, MP_TOKEN_OP_ASSIGN,
     MP_TOKEN_OP_LESS, MP_TOKEN_OP_LESS_EQUAL, MP_TOKEN_OP_DBL_LESS, MP_TOKEN_DEL_DBL_LESS_EQUAL,
     MP_TOKEN_OP_MORE, MP_TOKEN_OP_MORE_EQUAL, MP_TOKEN_OP_DBL_MORE, MP_TOKEN_DEL_DBL_MORE_EQUAL,
     MP_TOKEN_OP_STAR, MP_TOKEN_DEL_STAR_EQUAL, MP_TOKEN_OP_DBL_STAR, MP_TOKEN_DEL_DBL_STAR_EQUAL,
@@ -307,17 +309,36 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) {
                     switch (c) {
                         // note: "c" can never be MP_LEXER_EOF because next_char
                         // always inserts a newline at the end of the input stream
-                        case '\n': c = MP_LEXER_EOF; break; // backslash escape the newline, just 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 '\n':
+                            c = MP_LEXER_EOF;
+                            break;                          // backslash escape the newline, just 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 'u':
                         case 'U':
                             if (lex->tok_kind == MP_TOKEN_BYTES) {
@@ -326,8 +347,8 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) {
                                 break;
                             }
                             // Otherwise fall through.
-                        case 'x':
-                        {
+                            MP_FALLTHROUGH
+                        case 'x': {
                             mp_uint_t num = 0;
                             if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) {
                                 // not enough hex chars for escape sequence
@@ -342,7 +363,7 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) {
                             // 3MB of text; even gzip-compressed and with minimal structure, it'll take
                             // roughly half a meg of storage. This form of Unicode escape may be added
                             // later on, but it's definitely not a priority right now. -- CJA 20140607
-                            mp_raise_NotImplementedError("unicode name escapes");
+                            mp_raise_NotImplementedError(MP_ERROR_TEXT("unicode name escapes"));
                             break;
                         default:
                             if (c >= '0' && c <= '7') {
@@ -707,7 +728,7 @@ mp_lexer_t *mp_lexer_new(qstr src_name, mp_reader_t reader) {
 
 mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, size_t len, size_t free_len) {
     mp_reader_t reader;
-    mp_reader_new_mem(&reader, (const byte*)str, len, free_len);
+    mp_reader_new_mem(&reader, (const byte *)str, len, free_len);
     return mp_lexer_new(src_name, reader);
 }
 

+ 1 - 0
py/lexer.h

@@ -96,6 +96,7 @@ typedef enum _mp_token_kind_t {
     MP_TOKEN_KW_WITH,
     MP_TOKEN_KW_YIELD,
 
+    MP_TOKEN_OP_ASSIGN,
     MP_TOKEN_OP_TILDE,
 
     // Order of these 6 matches corresponding mp_binary_op_t operator

+ 205 - 0
py/makecompresseddata.py

@@ -0,0 +1,205 @@
+from __future__ import print_function
+
+import collections
+import re
+import sys
+
+import gzip
+import zlib
+
+
+_COMPRESSED_MARKER = 0xFF
+
+
+def check_non_ascii(msg):
+    for c in msg:
+        if ord(c) >= 0x80:
+            print(
+                'Unable to generate compressed data: message "{}" contains a non-ascii character "{}".'.format(
+                    msg, c
+                ),
+                file=sys.stderr,
+            )
+            sys.exit(1)
+
+
+# Replace <char><space> with <char | 0x80>.
+# Trival scheme to demo/test.
+def space_compression(error_strings):
+    for line in error_strings:
+        check_non_ascii(line)
+        result = ""
+        for i in range(len(line)):
+            if i > 0 and line[i] == " ":
+                result = result[:-1]
+                result += "\\{:03o}".format(ord(line[i - 1]))
+            else:
+                result += line[i]
+        error_strings[line] = result
+    return None
+
+
+# Replace common words with <0x80 | index>.
+# Index is into a table of words stored as aaaaa<0x80|a>bbb<0x80|b>...
+# Replaced words are assumed to have spaces either side to avoid having to store the spaces in the compressed strings.
+def word_compression(error_strings):
+    topn = collections.Counter()
+
+    for line in error_strings.keys():
+        check_non_ascii(line)
+        for word in line.split(" "):
+            topn[word] += 1
+
+    # Order not just by frequency, but by expected saving. i.e. prefer a longer string that is used less frequently.
+    # Use the word itself for ties so that compression is deterministic.
+    def bytes_saved(item):
+        w, n = item
+        return -((len(w) + 1) * (n - 1)), w
+
+    top128 = sorted(topn.items(), key=bytes_saved)[:128]
+
+    index = [w for w, _ in top128]
+    index_lookup = {w: i for i, w in enumerate(index)}
+
+    for line in error_strings.keys():
+        result = ""
+        need_space = False
+        for word in line.split(" "):
+            if word in index_lookup:
+                result += "\\{:03o}".format(0b10000000 | index_lookup[word])
+                need_space = False
+            else:
+                if need_space:
+                    result += " "
+                need_space = True
+                result += word
+        error_strings[line] = result.strip()
+
+    return "".join(w[:-1] + "\\{:03o}".format(0b10000000 | ord(w[-1])) for w in index)
+
+
+# Replace chars in text with variable length bit sequence.
+# For comparison only (the table is not emitted).
+def huffman_compression(error_strings):
+    # https://github.com/tannewt/huffman
+    import huffman
+
+    all_strings = "".join(error_strings)
+    cb = huffman.codebook(collections.Counter(all_strings).items())
+
+    for line in error_strings:
+        b = "1"
+        for c in line:
+            b += cb[c]
+        n = len(b)
+        if n % 8 != 0:
+            n += 8 - (n % 8)
+        result = ""
+        for i in range(0, n, 8):
+            result += "\\{:03o}".format(int(b[i : i + 8], 2))
+        if len(result) > len(line) * 4:
+            result = line
+        error_strings[line] = result
+
+    # TODO: This would be the prefix lengths and the table ordering.
+    return "_" * (10 + len(cb))
+
+
+# Replace common N-letter sequences with <0x80 | index>, where
+# the common sequences are stored in a separate table.
+# This isn't very useful, need a smarter way to find top-ngrams.
+def ngram_compression(error_strings):
+    topn = collections.Counter()
+    N = 2
+
+    for line in error_strings.keys():
+        check_non_ascii(line)
+        if len(line) < N:
+            continue
+        for i in range(0, len(line) - N, N):
+            topn[line[i : i + N]] += 1
+
+    def bytes_saved(item):
+        w, n = item
+        return -(len(w) * (n - 1))
+
+    top128 = sorted(topn.items(), key=bytes_saved)[:128]
+
+    index = [w for w, _ in top128]
+    index_lookup = {w: i for i, w in enumerate(index)}
+
+    for line in error_strings.keys():
+        result = ""
+        for i in range(0, len(line) - N + 1, N):
+            word = line[i : i + N]
+            if word in index_lookup:
+                result += "\\{:03o}".format(0b10000000 | index_lookup[word])
+            else:
+                result += word
+        if len(line) % N != 0:
+            result += line[len(line) - len(line) % N :]
+        error_strings[line] = result.strip()
+
+    return "".join(index)
+
+
+def main(collected_path, fn):
+    error_strings = collections.OrderedDict()
+    max_uncompressed_len = 0
+    num_uses = 0
+
+    # Read in all MP_ERROR_TEXT strings.
+    with open(collected_path, "r") as f:
+        for line in f:
+            line = line.strip()
+            if not line:
+                continue
+            num_uses += 1
+            error_strings[line] = None
+            max_uncompressed_len = max(max_uncompressed_len, len(line))
+
+    # So that objexcept.c can figure out how big the buffer needs to be.
+    print("#define MP_MAX_UNCOMPRESSED_TEXT_LEN ({})".format(max_uncompressed_len))
+
+    # Run the compression.
+    compressed_data = fn(error_strings)
+
+    # Print the data table.
+    print('MP_COMPRESSED_DATA("{}")'.format(compressed_data))
+
+    # Print the replacements.
+    for uncomp, comp in error_strings.items():
+        if uncomp == comp:
+            prefix = ""
+        else:
+            prefix = "\\{:03o}".format(_COMPRESSED_MARKER)
+        print('MP_MATCH_COMPRESSED("{}", "{}{}")'.format(uncomp, prefix, comp))
+
+    # Used to calculate the "true" length of the (escaped) compressed strings.
+    def unescape(s):
+        return re.sub(r"\\\d\d\d", "!", s)
+
+    # Stats. Note this doesn't include the cost of the decompressor code.
+    uncomp_len = sum(len(s) + 1 for s in error_strings.keys())
+    comp_len = sum(1 + len(unescape(s)) + 1 for s in error_strings.values())
+    data_len = len(compressed_data) + 1 if compressed_data else 0
+    print("// Total input length:      {}".format(uncomp_len))
+    print("// Total compressed length: {}".format(comp_len))
+    print("// Total data length:       {}".format(data_len))
+    print("// Predicted saving:        {}".format(uncomp_len - comp_len - data_len))
+
+    # Somewhat meaningless comparison to zlib/gzip.
+    all_input_bytes = "\\0".join(error_strings.keys()).encode()
+    print()
+    if hasattr(gzip, "compress"):
+        gzip_len = len(gzip.compress(all_input_bytes)) + num_uses * 4
+        print("// gzip length:             {}".format(gzip_len))
+        print("// Percentage of gzip:      {:.1f}%".format(100 * (comp_len + data_len) / gzip_len))
+    if hasattr(zlib, "compress"):
+        zlib_len = len(zlib.compress(all_input_bytes)) + num_uses * 4
+        print("// zlib length:             {}".format(zlib_len))
+        print("// Percentage of zlib:      {:.1f}%".format(100 * (comp_len + data_len) / zlib_len))
+
+
+if __name__ == "__main__":
+    main(sys.argv[1], word_compression)

+ 26 - 24
py/makemoduledefs.py

@@ -13,14 +13,11 @@ import os
 import argparse
 
 
-pattern = re.compile(
-    r"[\n;]\s*MP_REGISTER_MODULE\((.*?),\s*(.*?),\s*(.*?)\);",
-    flags=re.DOTALL
-)
+pattern = re.compile(r"[\n;]\s*MP_REGISTER_MODULE\((.*?),\s*(.*?),\s*(.*?)\);", flags=re.DOTALL)
 
 
 def find_c_file(obj_file, vpath):
-    """ Search vpaths for the c file that matches the provided object_file.
+    """Search vpaths for the c file that matches the provided object_file.
 
     :param str obj_file: object file to find the matching c file for
     :param List[str] vpath: List of base paths, similar to gcc vpath
@@ -28,7 +25,7 @@ def find_c_file(obj_file, vpath):
     """
     c_file = None
     relative_c_file = os.path.splitext(obj_file)[0] + ".c"
-    relative_c_file = relative_c_file.lstrip('/\\')
+    relative_c_file = relative_c_file.lstrip("/\\")
     for p in vpath:
         possible_c_file = os.path.join(p, relative_c_file)
         if os.path.exists(possible_c_file):
@@ -39,7 +36,7 @@ def find_c_file(obj_file, vpath):
 
 
 def find_module_registrations(c_file):
-    """ Find any MP_REGISTER_MODULE definitions in the provided c file.
+    """Find any MP_REGISTER_MODULE definitions in the provided c file.
 
     :param str c_file: path to c file to check
     :return: List[(module_name, obj_module, enabled_define)]
@@ -50,12 +47,12 @@ def find_module_registrations(c_file):
         # No c file to match the object file, skip
         return set()
 
-    with io.open(c_file, encoding='utf-8') as c_file_obj:
+    with io.open(c_file, encoding="utf-8") as c_file_obj:
         return set(re.findall(pattern, c_file_obj.read()))
 
 
 def generate_module_table_header(modules):
-    """ Generate header with module table entries for builtin modules.
+    """Generate header with module table entries for builtin modules.
 
     :param List[(module_name, obj_module, enabled_define)] modules: module defs
     :return: None
@@ -67,15 +64,20 @@ def generate_module_table_header(modules):
     for module_name, obj_module, enabled_define in modules:
         mod_def = "MODULE_DEF_{}".format(module_name.upper())
         mod_defs.append(mod_def)
-        print((
-            "#if ({enabled_define})\n"
-            "    extern const struct _mp_obj_module_t {obj_module};\n"
-            "    #define {mod_def} {{ MP_ROM_QSTR({module_name}), MP_ROM_PTR(&{obj_module}) }},\n"
-            "#else\n"
-            "    #define {mod_def}\n"
-            "#endif\n"
-            ).format(module_name=module_name, obj_module=obj_module,
-                     enabled_define=enabled_define, mod_def=mod_def)
+        print(
+            (
+                "#if ({enabled_define})\n"
+                "    extern const struct _mp_obj_module_t {obj_module};\n"
+                "    #define {mod_def} {{ MP_ROM_QSTR({module_name}), MP_ROM_PTR(&{obj_module}) }},\n"
+                "#else\n"
+                "    #define {mod_def}\n"
+                "#endif\n"
+            ).format(
+                module_name=module_name,
+                obj_module=obj_module,
+                enabled_define=enabled_define,
+                mod_def=mod_def,
+            )
         )
 
     print("\n#define MICROPY_REGISTERED_MODULES \\")
@@ -88,13 +90,13 @@ def generate_module_table_header(modules):
 
 def main():
     parser = argparse.ArgumentParser()
-    parser.add_argument("--vpath", default=".",
-                        help="comma separated list of folders to search for c files in")
-    parser.add_argument("files", nargs="*",
-                        help="list of c files to search")
+    parser.add_argument(
+        "--vpath", default=".", help="comma separated list of folders to search for c files in"
+    )
+    parser.add_argument("files", nargs="*", help="list of c files to search")
     args = parser.parse_args()
 
-    vpath = [p.strip() for p in args.vpath.split(',')]
+    vpath = [p.strip() for p in args.vpath.split(",")]
 
     modules = set()
     for obj_file in args.files:
@@ -104,5 +106,5 @@ def main():
     generate_module_table_header(sorted(modules))
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()

+ 68 - 53
py/makeqstrdata.py

@@ -13,49 +13,50 @@ import sys
 #   - iterating through bytes is different
 #   - codepoint2name lives in a different module
 import platform
-if platform.python_version_tuple()[0] == '2':
+
+if platform.python_version_tuple()[0] == "2":
     bytes_cons = lambda val, enc=None: bytearray(val)
     from htmlentitydefs import codepoint2name
-elif platform.python_version_tuple()[0] == '3':
+elif platform.python_version_tuple()[0] == "3":
     bytes_cons = bytes
     from html.entities import codepoint2name
 # end compatibility code
 
-codepoint2name[ord('-')] = 'hyphen';
+codepoint2name[ord("-")] = "hyphen"
 
 # add some custom names to map characters that aren't in HTML
-codepoint2name[ord(' ')] = 'space'
-codepoint2name[ord('\'')] = 'squot'
-codepoint2name[ord(',')] = 'comma'
-codepoint2name[ord('.')] = 'dot'
-codepoint2name[ord(':')] = 'colon'
-codepoint2name[ord(';')] = 'semicolon'
-codepoint2name[ord('/')] = 'slash'
-codepoint2name[ord('%')] = 'percent'
-codepoint2name[ord('#')] = 'hash'
-codepoint2name[ord('(')] = 'paren_open'
-codepoint2name[ord(')')] = 'paren_close'
-codepoint2name[ord('[')] = 'bracket_open'
-codepoint2name[ord(']')] = 'bracket_close'
-codepoint2name[ord('{')] = 'brace_open'
-codepoint2name[ord('}')] = 'brace_close'
-codepoint2name[ord('*')] = 'star'
-codepoint2name[ord('!')] = 'bang'
-codepoint2name[ord('\\')] = 'backslash'
-codepoint2name[ord('+')] = 'plus'
-codepoint2name[ord('$')] = 'dollar'
-codepoint2name[ord('=')] = 'equals'
-codepoint2name[ord('?')] = 'question'
-codepoint2name[ord('@')] = 'at_sign'
-codepoint2name[ord('^')] = 'caret'
-codepoint2name[ord('|')] = 'pipe'
-codepoint2name[ord('~')] = 'tilde'
+codepoint2name[ord(" ")] = "space"
+codepoint2name[ord("'")] = "squot"
+codepoint2name[ord(",")] = "comma"
+codepoint2name[ord(".")] = "dot"
+codepoint2name[ord(":")] = "colon"
+codepoint2name[ord(";")] = "semicolon"
+codepoint2name[ord("/")] = "slash"
+codepoint2name[ord("%")] = "percent"
+codepoint2name[ord("#")] = "hash"
+codepoint2name[ord("(")] = "paren_open"
+codepoint2name[ord(")")] = "paren_close"
+codepoint2name[ord("[")] = "bracket_open"
+codepoint2name[ord("]")] = "bracket_close"
+codepoint2name[ord("{")] = "brace_open"
+codepoint2name[ord("}")] = "brace_close"
+codepoint2name[ord("*")] = "star"
+codepoint2name[ord("!")] = "bang"
+codepoint2name[ord("\\")] = "backslash"
+codepoint2name[ord("+")] = "plus"
+codepoint2name[ord("$")] = "dollar"
+codepoint2name[ord("=")] = "equals"
+codepoint2name[ord("?")] = "question"
+codepoint2name[ord("@")] = "at_sign"
+codepoint2name[ord("^")] = "caret"
+codepoint2name[ord("|")] = "pipe"
+codepoint2name[ord("~")] = "tilde"
 
 # static qstrs, should be sorted
 
 static_qstr_list = [
     "",
-    "__dir__", # Put __dir__ after empty qstr for builtin dir() to work
+    "__dir__",  # Put __dir__ after empty qstr for builtin dir() to work
     "\n",
     " ",
     "*",
@@ -229,15 +230,18 @@ def compute_hash(qstr, bytes_hash):
     # Make sure that valid hash is never zero, zero means "hash not computed"
     return (hash & ((1 << (8 * bytes_hash)) - 1)) or 1
 
+
 def qstr_escape(qst):
     def esc_char(m):
         c = ord(m.group(0))
         try:
             name = codepoint2name[c]
         except KeyError:
-            name = '0x%02x' % c
-        return "_" + name + '_'
-    return re.sub(r'[^A-Za-z0-9_]', esc_char, qst)
+            name = "0x%02x" % c
+        return "_" + name + "_"
+
+    return re.sub(r"[^A-Za-z0-9_]", esc_char, qst)
+
 
 def parse_input_headers(infiles):
     qcfgs = {}
@@ -257,22 +261,22 @@ def parse_input_headers(infiles):
 
     # read the qstrs in from the input files
     for infile in infiles:
-        with open(infile, 'rt') as f:
+        with open(infile, "rt") as f:
             for line in f:
                 line = line.strip()
 
                 # is this a config line?
-                match = re.match(r'^QCFG\((.+), (.+)\)', line)
+                match = re.match(r"^QCFG\((.+), (.+)\)", line)
                 if match:
                     value = match.group(2)
-                    if value[0] == '(' and value[-1] == ')':
+                    if value[0] == "(" and value[-1] == ")":
                         # strip parenthesis from config value
                         value = value[1:-1]
                     qcfgs[match.group(1)] = value
                     continue
 
                 # is this a QSTR line?
-                match = re.match(r'^Q\((.*)\)$', line)
+                match = re.match(r"^Q\((.*)\)$", line)
                 if not match:
                     continue
 
@@ -280,10 +284,10 @@ def parse_input_headers(infiles):
                 qstr = match.group(1)
 
                 # special cases to specify control characters
-                if qstr == '\\n':
-                    qstr = '\n'
-                elif qstr == '\\r\\n':
-                    qstr = '\r\n'
+                if qstr == "\\n":
+                    qstr = "\n"
+                elif qstr == "\\r\\n":
+                    qstr = "\r\n"
 
                 # work out the corresponding qstr name
                 ident = qstr_escape(qstr)
@@ -312,43 +316,54 @@ def parse_input_headers(infiles):
 
     return qcfgs, qstrs
 
+
 def make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr):
-    qbytes = bytes_cons(qstr, 'utf8')
+    qbytes = bytes_cons(qstr, "utf8")
     qlen = len(qbytes)
     qhash = compute_hash(qbytes, cfg_bytes_hash)
-    if all(32 <= ord(c) <= 126 and c != '\\' and c != '"' for c in qstr):
+    if all(32 <= ord(c) <= 126 and c != "\\" and c != '"' for c in qstr):
         # qstr is all printable ASCII so render it as-is (for easier debugging)
         qdata = qstr
     else:
         # qstr contains non-printable codes so render entire thing as hex pairs
-        qdata = ''.join(('\\x%02x' % b) for b in qbytes)
+        qdata = "".join(("\\x%02x" % b) for b in qbytes)
     if qlen >= (1 << (8 * cfg_bytes_len)):
-        print('qstr is too long:', qstr)
+        print("qstr is too long:", qstr)
         assert False
-    qlen_str = ('\\x%02x' * cfg_bytes_len) % tuple(((qlen >> (8 * i)) & 0xff) for i in range(cfg_bytes_len))
-    qhash_str = ('\\x%02x' * cfg_bytes_hash) % tuple(((qhash >> (8 * i)) & 0xff) for i in range(cfg_bytes_hash))
+    qlen_str = ("\\x%02x" * cfg_bytes_len) % tuple(
+        ((qlen >> (8 * i)) & 0xFF) for i in range(cfg_bytes_len)
+    )
+    qhash_str = ("\\x%02x" * cfg_bytes_hash) % tuple(
+        ((qhash >> (8 * i)) & 0xFF) for i in range(cfg_bytes_hash)
+    )
     return '(const byte*)"%s%s" "%s"' % (qhash_str, qlen_str, qdata)
 
+
 def print_qstr_data(qcfgs, qstrs):
     # get config variables
-    cfg_bytes_len = int(qcfgs['BYTES_IN_LEN'])
-    cfg_bytes_hash = int(qcfgs['BYTES_IN_HASH'])
+    cfg_bytes_len = int(qcfgs["BYTES_IN_LEN"])
+    cfg_bytes_hash = int(qcfgs["BYTES_IN_HASH"])
 
     # print out the starter of the generated C header file
-    print('// This file was automatically generated by makeqstrdata.py')
-    print('')
+    print("// This file was automatically generated by makeqstrdata.py")
+    print("")
 
     # add NULL qstr with no hash or data
-    print('QDEF(MP_QSTRnull, (const byte*)"%s%s" "")' % ('\\x00' * cfg_bytes_hash, '\\x00' * cfg_bytes_len))
+    print(
+        'QDEF(MP_QSTRnull, (const byte*)"%s%s" "")'
+        % ("\\x00" * cfg_bytes_hash, "\\x00" * cfg_bytes_len)
+    )
 
     # go through each qstr and print it out
     for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]):
         qbytes = make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr)
-        print('QDEF(MP_QSTR_%s, %s)' % (ident, qbytes))
+        print("QDEF(MP_QSTR_%s, %s)" % (ident, qbytes))
+
 
 def do_work(infiles):
     qcfgs, qstrs = parse_input_headers(infiles)
     print_qstr_data(qcfgs, qstrs)
 
+
 if __name__ == "__main__":
     do_work(sys.argv[1:])

+ 100 - 18
py/makeqstrdefs.py

@@ -8,53 +8,95 @@ This script works with Python 2.6, 2.7, 3.3 and 3.4.
 from __future__ import print_function
 
 import re
+import subprocess
 import sys
 import io
 import os
 
 
+# Extract MP_QSTR_FOO macros.
+_MODE_QSTR = "qstr"
+
+# Extract MP_COMPRESSED_ROM_TEXT("") macros.  (Which come from MP_ERROR_TEXT)
+_MODE_COMPRESS = "compress"
+
+
+def preprocess():
+    if any(src in args.dependencies for src in args.changed_sources):
+        sources = args.sources
+    elif any(args.changed_sources):
+        sources = args.changed_sources
+    else:
+        sources = args.sources
+    csources = []
+    cxxsources = []
+    for source in sources:
+        if source.endswith(".cpp"):
+            cxxsources.append(source)
+        else:
+            csources.append(source)
+    try:
+        os.makedirs(os.path.dirname(args.output[0]))
+    except OSError:
+        pass
+    with open(args.output[0], "w") as out_file:
+        if csources:
+            subprocess.check_call(args.pp + args.cflags + csources, stdout=out_file)
+        if cxxsources:
+            subprocess.check_call(args.pp + args.cxxflags + cxxsources, stdout=out_file)
+
+
 def write_out(fname, output):
     if output:
         for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]:
             fname = fname.replace(m, r)
-        with open(args.output_dir + "/" + fname + ".qstr", "w") as f:
+        with open(args.output_dir + "/" + fname + "." + args.mode, "w") as f:
             f.write("\n".join(output) + "\n")
 
+
 def process_file(f):
     re_line = re.compile(r"#[line]*\s\d+\s\"([^\"]+)\"")
-    re_qstr = re.compile(r'MP_QSTR_[_a-zA-Z0-9]+')
+    if args.mode == _MODE_QSTR:
+        re_match = re.compile(r"MP_QSTR_[_a-zA-Z0-9]+")
+    elif args.mode == _MODE_COMPRESS:
+        re_match = re.compile(r'MP_COMPRESSED_ROM_TEXT\("([^"]*)"\)')
     output = []
     last_fname = None
     for line in f:
         if line.isspace():
             continue
         # match gcc-like output (# n "file") and msvc-like output (#line n "file")
-        if line.startswith(('# ', '#line')):
+        if line.startswith(("# ", "#line")):
             m = re_line.match(line)
             assert m is not None
             fname = m.group(1)
-            if not fname.endswith(".c"):
+            if os.path.splitext(fname)[1] not in [".c", ".cpp"]:
                 continue
             if fname != last_fname:
                 write_out(last_fname, output)
                 output = []
                 last_fname = fname
             continue
-        for match in re_qstr.findall(line):
-            name = match.replace('MP_QSTR_', '')
-            output.append('Q(' + name + ')')
+        for match in re_match.findall(line):
+            if args.mode == _MODE_QSTR:
+                name = match.replace("MP_QSTR_", "")
+                output.append("Q(" + name + ")")
+            elif args.mode == _MODE_COMPRESS:
+                output.append(match)
 
-    write_out(last_fname, output)
+    if last_fname:
+        write_out(last_fname, output)
     return ""
 
 
 def cat_together():
     import glob
     import hashlib
+
     hasher = hashlib.md5()
     all_lines = []
     outf = open(args.output_dir + "/out", "wb")
-    for fname in glob.glob(args.output_dir + "/*.qstr"):
+    for fname in glob.glob(args.output_dir + "/*." + args.mode):
         with open(fname, "rb") as f:
             lines = f.readlines()
             all_lines += lines
@@ -64,15 +106,18 @@ def cat_together():
     outf.close()
     hasher.update(all_lines)
     new_hash = hasher.hexdigest()
-    #print(new_hash)
+    # print(new_hash)
     old_hash = None
     try:
         with open(args.output_file + ".hash") as f:
             old_hash = f.read()
     except IOError:
         pass
+    mode_full = "QSTR"
+    if args.mode == _MODE_COMPRESS:
+        mode_full = "Compressed data"
     if old_hash != new_hash:
-        print("QSTR updated")
+        print(mode_full, "updated")
         try:
             # rename below might fail if file exists
             os.remove(args.output_file)
@@ -82,21 +127,58 @@ def cat_together():
         with open(args.output_file + ".hash", "w") as f:
             f.write(new_hash)
     else:
-        print("QSTR not updated")
+        print(mode_full, "not updated")
 
 
 if __name__ == "__main__":
-    if len(sys.argv) != 5:
-        print('usage: %s command input_filename output_dir output_file' % sys.argv[0])
+    if len(sys.argv) < 6:
+        print("usage: %s command mode input_filename output_dir output_file" % sys.argv[0])
         sys.exit(2)
 
     class Args:
         pass
+
     args = Args()
     args.command = sys.argv[1]
-    args.input_filename = sys.argv[2]
-    args.output_dir = sys.argv[3]
-    args.output_file = sys.argv[4]
+
+    if args.command == "pp":
+        named_args = {
+            s: []
+            for s in [
+                "pp",
+                "output",
+                "cflags",
+                "cxxflags",
+                "sources",
+                "changed_sources",
+                "dependencies",
+            ]
+        }
+
+        for arg in sys.argv[1:]:
+            if arg in named_args:
+                current_tok = arg
+            else:
+                named_args[current_tok].append(arg)
+
+        if not named_args["pp"] or len(named_args["output"]) != 1:
+            print("usage: %s %s ..." % (sys.argv[0], " ... ".join(named_args)))
+            sys.exit(2)
+
+        for k, v in named_args.items():
+            setattr(args, k, v)
+
+        preprocess()
+        sys.exit(0)
+
+    args.mode = sys.argv[2]
+    args.input_filename = sys.argv[3]  # Unused for command=cat
+    args.output_dir = sys.argv[4]
+    args.output_file = None if len(sys.argv) == 5 else sys.argv[5]  # Unused for command=split
+
+    if args.mode not in (_MODE_QSTR, _MODE_COMPRESS):
+        print("error: mode %s unrecognised" % sys.argv[2])
+        sys.exit(2)
 
     try:
         os.makedirs(args.output_dir)
@@ -104,7 +186,7 @@ if __name__ == "__main__":
         pass
 
     if args.command == "split":
-        with io.open(args.input_filename, encoding='utf-8') as infile:
+        with io.open(args.input_filename, encoding="utf-8") as infile:
             process_file(infile)
 
     if args.command == "cat":

+ 27 - 7
py/makeversionhdr.py

@@ -11,6 +11,7 @@ import os
 import datetime
 import subprocess
 
+
 def get_version_info_from_git():
     # Python 2.6 doesn't have check_output, so check for that
     try:
@@ -21,7 +22,11 @@ def get_version_info_from_git():
 
     # Note: git describe doesn't work if no tag is available
     try:
-        git_tag = subprocess.check_output(["git", "describe", "--dirty", "--always"], stderr=subprocess.STDOUT, universal_newlines=True).strip()
+        git_tag = subprocess.check_output(
+            ["git", "describe", "--dirty", "--always", "--match", "v[1-9].*"],
+            stderr=subprocess.STDOUT,
+            universal_newlines=True,
+        ).strip()
     except subprocess.CalledProcessError as er:
         if er.returncode == 128:
             # git exit code of 128 means no repository found
@@ -30,7 +35,11 @@ def get_version_info_from_git():
     except OSError:
         return None
     try:
-        git_hash = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], stderr=subprocess.STDOUT, universal_newlines=True).strip()
+        git_hash = subprocess.check_output(
+            ["git", "rev-parse", "--short", "HEAD"],
+            stderr=subprocess.STDOUT,
+            universal_newlines=True,
+        ).strip()
     except subprocess.CalledProcessError:
         git_hash = "unknown"
     except OSError:
@@ -38,9 +47,13 @@ def get_version_info_from_git():
 
     try:
         # Check if there are any modified files.
-        subprocess.check_call(["git", "diff", "--no-ext-diff", "--quiet", "--exit-code"], stderr=subprocess.STDOUT)
+        subprocess.check_call(
+            ["git", "diff", "--no-ext-diff", "--quiet", "--exit-code"], stderr=subprocess.STDOUT
+        )
         # Check if there are any staged files.
-        subprocess.check_call(["git", "diff-index", "--cached", "--quiet", "HEAD", "--"], stderr=subprocess.STDOUT)
+        subprocess.check_call(
+            ["git", "diff-index", "--cached", "--quiet", "HEAD", "--"], stderr=subprocess.STDOUT
+        )
     except subprocess.CalledProcessError:
         git_hash += "-dirty"
     except OSError:
@@ -48,6 +61,7 @@ def get_version_info_from_git():
 
     return git_tag, git_hash
 
+
 def get_version_info_from_docs_conf():
     with open(os.path.join(os.path.dirname(sys.argv[0]), "..", "docs", "conf.py")) as f:
         for line in f:
@@ -57,6 +71,7 @@ def get_version_info_from_docs_conf():
                 return git_tag, "<no hash>"
     return None
 
+
 def make_version_header(filename):
     # Get version info using git, with fallback to docs/conf.py
     info = get_version_info_from_git()
@@ -71,12 +86,16 @@ def make_version_header(filename):
 #define MICROPY_GIT_TAG "%s"
 #define MICROPY_GIT_HASH "%s"
 #define MICROPY_BUILD_DATE "%s"
-""" % (git_tag, git_hash, datetime.date.today().strftime("%Y-%m-%d"))
+""" % (
+        git_tag,
+        git_hash,
+        datetime.date.today().strftime("%Y-%m-%d"),
+    )
 
     # Check if the file contents changed from last time
     write_file = True
     if os.path.isfile(filename):
-        with open(filename, 'r') as f:
+        with open(filename, "r") as f:
             existing_data = f.read()
         if existing_data == file_data:
             write_file = False
@@ -84,8 +103,9 @@ def make_version_header(filename):
     # Only write the file if we need to
     if write_file:
         print("GEN %s" % filename)
-        with open(filename, 'w') as f:
+        with open(filename, "w") as f:
             f.write(file_data)
 
+
 if __name__ == "__main__":
     make_version_header(sys.argv[1])

+ 21 - 18
py/malloc.c

@@ -87,22 +87,22 @@ void *m_malloc(size_t num_bytes) {
     if (ptr == NULL && num_bytes != 0) {
         m_malloc_fail(num_bytes);
     }
-#if MICROPY_MEM_STATS
+    #if MICROPY_MEM_STATS
     MP_STATE_MEM(total_bytes_allocated) += num_bytes;
     MP_STATE_MEM(current_bytes_allocated) += num_bytes;
     UPDATE_PEAK();
-#endif
+    #endif
     DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
     return ptr;
 }
 
 void *m_malloc_maybe(size_t num_bytes) {
     void *ptr = malloc(num_bytes);
-#if MICROPY_MEM_STATS
+    #if MICROPY_MEM_STATS
     MP_STATE_MEM(total_bytes_allocated) += num_bytes;
     MP_STATE_MEM(current_bytes_allocated) += num_bytes;
     UPDATE_PEAK();
-#endif
+    #endif
     DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
     return ptr;
 }
@@ -113,11 +113,11 @@ void *m_malloc_with_finaliser(size_t num_bytes) {
     if (ptr == NULL && num_bytes != 0) {
         m_malloc_fail(num_bytes);
     }
-#if MICROPY_MEM_STATS
+    #if MICROPY_MEM_STATS
     MP_STATE_MEM(total_bytes_allocated) += num_bytes;
     MP_STATE_MEM(current_bytes_allocated) += num_bytes;
     UPDATE_PEAK();
-#endif
+    #endif
     DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
     return ptr;
 }
@@ -133,15 +133,16 @@ void *m_malloc0(size_t num_bytes) {
 }
 
 #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
-void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
+void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes)
 #else
-void *m_realloc(void *ptr, size_t new_num_bytes) {
+void *m_realloc(void *ptr, size_t new_num_bytes)
 #endif
+{
     void *new_ptr = realloc(ptr, new_num_bytes);
     if (new_ptr == NULL && new_num_bytes != 0) {
         m_malloc_fail(new_num_bytes);
     }
-#if MICROPY_MEM_STATS
+    #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
@@ -151,7 +152,7 @@ void *m_realloc(void *ptr, size_t new_num_bytes) {
     MP_STATE_MEM(total_bytes_allocated) += diff;
     MP_STATE_MEM(current_bytes_allocated) += diff;
     UPDATE_PEAK();
-#endif
+    #endif
     #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
     DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
     #else
@@ -161,12 +162,13 @@ void *m_realloc(void *ptr, size_t new_num_bytes) {
 }
 
 #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
-void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move) {
+void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move)
 #else
-void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move) {
+void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move)
 #endif
+{
     void *new_ptr = realloc_ext(ptr, new_num_bytes, allow_move);
-#if MICROPY_MEM_STATS
+    #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
@@ -179,7 +181,7 @@ void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move) {
         MP_STATE_MEM(current_bytes_allocated) += diff;
         UPDATE_PEAK();
     }
-#endif
+    #endif
     #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
     DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
     #else
@@ -189,14 +191,15 @@ void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move) {
 }
 
 #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
-void m_free(void *ptr, size_t num_bytes) {
+void m_free(void *ptr, size_t num_bytes)
 #else
-void m_free(void *ptr) {
+void m_free(void *ptr)
 #endif
+{
     free(ptr);
-#if MICROPY_MEM_STATS
+    #if MICROPY_MEM_STATS
     MP_STATE_MEM(current_bytes_allocated) -= num_bytes;
-#endif
+    #endif
     #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
     DEBUG_printf("free %p, %d\n", ptr, num_bytes);
     #else

+ 2 - 12
py/map.c

@@ -40,17 +40,6 @@
 #define DEBUG_printf(...) (void)0
 #endif
 
-// Fixed empty map. Useful when need to call kw-receiving functions
-// without any keywords from C, etc.
-const mp_map_t mp_const_empty_map = {
-    .all_keys_are_qstrs = 0,
-    .is_fixed = 1,
-    .is_ordered = 1,
-    .used = 0,
-    .alloc = 0,
-    .table = NULL,
-};
-
 // This table of sizes is used to control the growth of hash tables.
 // The first set of sizes are chosen so the allocation fits exactly in a
 // 4-word GC block, and it's not so important for these small values to be
@@ -96,7 +85,7 @@ void mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table) {
     map->all_keys_are_qstrs = 1;
     map->is_fixed = 1;
     map->is_ordered = 1;
-    map->table = (mp_map_elem_t*)table;
+    map->table = (mp_map_elem_t *)table;
 }
 
 // Differentiate from mp_map_clear() - semantics is different
@@ -177,6 +166,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
                     --map->used;
                     memmove(elem, elem + 1, (top - elem - 1) * sizeof(*elem));
                     // put the found element after the end so the caller can access it if needed
+                    // note: caller must NULL the value so the GC can clean up (e.g. see dict_get_helper).
                     elem = &map->table[map->used];
                     elem->key = MP_OBJ_NULL;
                     elem->value = value;

+ 114 - 22
py/misc.h

@@ -57,28 +57,28 @@ typedef unsigned int uint;
 
 // TODO make a lazy m_renew that can increase by a smaller amount than requested (but by at least 1 more element)
 
-#define m_new(type, num) ((type*)(m_malloc(sizeof(type) * (num))))
-#define m_new_maybe(type, num) ((type*)(m_malloc_maybe(sizeof(type) * (num))))
-#define m_new0(type, num) ((type*)(m_malloc0(sizeof(type) * (num))))
+#define m_new(type, num) ((type *)(m_malloc(sizeof(type) * (num))))
+#define m_new_maybe(type, num) ((type *)(m_malloc_maybe(sizeof(type) * (num))))
+#define m_new0(type, num) ((type *)(m_malloc0(sizeof(type) * (num))))
 #define m_new_obj(type) (m_new(type, 1))
 #define m_new_obj_maybe(type) (m_new_maybe(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)))
+#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))))
-#define m_new_obj_var_with_finaliser(type, var_type, var_num) ((type*)m_malloc_with_finaliser(sizeof(type) + sizeof(var_type) * (var_num)))
+#define m_new_obj_with_finaliser(type) ((type *)(m_malloc_with_finaliser(sizeof(type))))
+#define m_new_obj_var_with_finaliser(type, var_type, var_num) ((type *)m_malloc_with_finaliser(sizeof(type) + sizeof(var_type) * (var_num)))
 #else
 #define m_new_obj_with_finaliser(type) m_new_obj(type)
 #define m_new_obj_var_with_finaliser(type, var_type, var_num) m_new_obj_var(type, var_type, var_num)
 #endif
 #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
-#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, allow_move) ((type*)(m_realloc_maybe((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num), (allow_move))))
+#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, allow_move) ((type *)(m_realloc_maybe((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num), (allow_move))))
 #define m_del(type, ptr, num) m_free(ptr, sizeof(type) * (num))
 #define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num)))
 #else
-#define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (new_num))))
-#define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type*)(m_realloc_maybe((ptr), sizeof(type) * (new_num), (allow_move))))
+#define m_renew(type, ptr, old_num, new_num) ((type *)(m_realloc((ptr), sizeof(type) * (new_num))))
+#define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type *)(m_realloc_maybe((ptr), sizeof(type) * (new_num), (allow_move))))
 #define m_del(type, ptr, num) ((void)(num), m_free(ptr))
 #define m_del_var(obj_type, var_type, var_num, ptr) ((void)(var_num), m_free(ptr))
 #endif
@@ -111,7 +111,7 @@ size_t m_get_peak_bytes_allocated(void);
 #define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
 // align ptr to the nearest multiple of "alignment"
-#define MP_ALIGN(ptr, alignment) (void*)(((uintptr_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1))
+#define MP_ALIGN(ptr, alignment) (void *)(((uintptr_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1))
 
 /** unichar / UTF-8 *********************************************/
 
@@ -129,9 +129,16 @@ unichar utf8_get_char(const byte *s);
 const byte *utf8_next_char(const byte *s);
 size_t utf8_charlen(const byte *str, size_t len);
 #else
-static inline unichar utf8_get_char(const byte *s) { return *s; }
-static inline const byte *utf8_next_char(const byte *s) { return s + 1; }
-static inline size_t utf8_charlen(const byte *str, size_t len) { (void)str; return len; }
+static inline unichar utf8_get_char(const byte *s) {
+    return *s;
+}
+static inline const byte *utf8_next_char(const byte *s) {
+    return s + 1;
+}
+static inline size_t utf8_charlen(const byte *str, size_t len) {
+    (void)str;
+    return len;
+}
 #endif
 
 bool unichar_isspace(unichar c);
@@ -140,6 +147,7 @@ bool unichar_isprint(unichar c);
 bool unichar_isdigit(unichar c);
 bool unichar_isxdigit(unichar c);
 bool unichar_isident(unichar c);
+bool unichar_isalnum(unichar c);
 bool unichar_isupper(unichar c);
 bool unichar_islower(unichar c);
 unichar unichar_tolower(unichar c);
@@ -168,9 +176,15 @@ void vstr_init_print(vstr_t *vstr, size_t alloc, struct _mp_print_t *print);
 void vstr_clear(vstr_t *vstr);
 vstr_t *vstr_new(size_t alloc);
 void vstr_free(vstr_t *vstr);
-static inline void vstr_reset(vstr_t *vstr) { vstr->len = 0; }
-static inline char *vstr_str(vstr_t *vstr) { return vstr->buf; }
-static inline size_t vstr_len(vstr_t *vstr) { return vstr->len; }
+static inline void vstr_reset(vstr_t *vstr) {
+    vstr->len = 0;
+}
+static inline char *vstr_str(vstr_t *vstr) {
+    return vstr->buf;
+}
+static inline size_t vstr_len(vstr_t *vstr) {
+    return vstr->len;
+}
 void vstr_hint_size(vstr_t *vstr, size_t size);
 char *vstr_extend(vstr_t *vstr, size_t size);
 char *vstr_add_len(vstr_t *vstr, size_t len);
@@ -191,10 +205,10 @@ void vstr_printf(vstr_t *vstr, const char *fmt, ...);
 #define CHECKBUF(buf, max_size) char buf[max_size + 1]; size_t buf##_len = max_size; char *buf##_p = buf;
 #define CHECKBUF_RESET(buf, max_size) buf##_len = max_size; buf##_p = buf;
 #define CHECKBUF_APPEND(buf, src, src_len) \
-        { size_t l = MIN(src_len, buf##_len); \
-        memcpy(buf##_p, src, l); \
-        buf##_len -= l; \
-        buf##_p += l; }
+    { size_t l = MIN(src_len, buf##_len); \
+      memcpy(buf##_p, src, l); \
+      buf##_len -= l; \
+      buf##_p += l; }
 #define CHECKBUF_APPEND_0(buf) { *buf##_p = 0; }
 #define CHECKBUF_LEN(buf) (buf##_p - buf)
 
@@ -210,14 +224,92 @@ extern mp_uint_t mp_verbose_flag;
 /** float internals *************/
 
 #if MICROPY_PY_BUILTINS_FLOAT
+
 #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
 #define MP_FLOAT_EXP_BITS (11)
 #define MP_FLOAT_FRAC_BITS (52)
+typedef uint64_t mp_float_uint_t;
 #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
 #define MP_FLOAT_EXP_BITS (8)
 #define MP_FLOAT_FRAC_BITS (23)
+typedef uint32_t mp_float_uint_t;
 #endif
+
 #define MP_FLOAT_EXP_BIAS ((1 << (MP_FLOAT_EXP_BITS - 1)) - 1)
+
+typedef union _mp_float_union_t {
+    mp_float_t f;
+    #if MP_ENDIANNESS_LITTLE
+    struct {
+        mp_float_uint_t frc : MP_FLOAT_FRAC_BITS;
+        mp_float_uint_t exp : MP_FLOAT_EXP_BITS;
+        mp_float_uint_t sgn : 1;
+    } p;
+    #else
+    struct {
+        mp_float_uint_t sgn : 1;
+        mp_float_uint_t exp : MP_FLOAT_EXP_BITS;
+        mp_float_uint_t frc : MP_FLOAT_FRAC_BITS;
+    } p;
+    #endif
+    mp_float_uint_t i;
+} mp_float_union_t;
+
 #endif // MICROPY_PY_BUILTINS_FLOAT
 
+/** ROM string compression *************/
+
+#if MICROPY_ROM_TEXT_COMPRESSION
+
+#ifdef NO_QSTR
+
+// Compression enabled but doing QSTR extraction.
+// So leave MP_COMPRESSED_ROM_TEXT in place for makeqstrdefs.py / makecompresseddata.py to find them.
+
+#else
+
+// Compression enabled and doing a regular build.
+// Map MP_COMPRESSED_ROM_TEXT to the compressed strings.
+
+// Force usage of the MP_ERROR_TEXT macro by requiring an opaque type.
+typedef struct {
+    #ifdef __clang__
+    // Fix "error: empty struct has size 0 in C, size 1 in C++".
+    char dummy;
+    #endif
+} *mp_rom_error_text_t;
+
+#include <string.h>
+
+inline __attribute__((always_inline)) const char *MP_COMPRESSED_ROM_TEXT(const char *msg) {
+    // "genhdr/compressed.data.h" contains an invocation of the MP_MATCH_COMPRESSED macro for each compressed string.
+    // The giant if(strcmp) tree is optimized by the compiler, which turns this into a direct return of the compressed data.
+    #define MP_MATCH_COMPRESSED(a, b) if (strcmp(msg, a) == 0) { return b; } else
+
+    // It also contains a single invocation of the MP_COMPRESSED_DATA macro, we don't need that here.
+    #define MP_COMPRESSED_DATA(x)
+
+    #include "genhdr/compressed.data.h"
+
+#undef MP_COMPRESSED_DATA
+#undef MP_MATCH_COMPRESSED
+
+    return msg;
+}
+
+#endif
+
+#else
+
+// Compression not enabled, just make it a no-op.
+
+typedef const char *mp_rom_error_text_t;
+#define MP_COMPRESSED_ROM_TEXT(x) x
+
+#endif // MICROPY_ROM_TEXT_COMPRESSION
+
+// Might add more types of compressed text in the future.
+// For now, forward directly to MP_COMPRESSED_ROM_TEXT.
+#define MP_ERROR_TEXT(x) (mp_rom_error_text_t)MP_COMPRESSED_ROM_TEXT(x)
+
 #endif // MICROPY_INCLUDED_PY_MISC_H

+ 0 - 5
py/mkenv.mk

@@ -55,11 +55,6 @@ OBJCOPY = $(CROSS_COMPILE)objcopy
 SIZE = $(CROSS_COMPILE)size
 STRIP = $(CROSS_COMPILE)strip
 AR = $(CROSS_COMPILE)ar
-ifeq ($(MICROPY_FORCE_32BIT),1)
-CC += -m32
-CXX += -m32
-LD += -m32
-endif
 
 MAKE_MANIFEST = $(PYTHON) $(TOP)/tools/makemanifest.py
 MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py

+ 49 - 8
py/mkrules.mk

@@ -4,6 +4,24 @@ THIS_MAKEFILE = $(lastword $(MAKEFILE_LIST))
 include $(dir $(THIS_MAKEFILE))mkenv.mk
 endif
 
+# Extra deps that need to happen before object compilation.
+OBJ_EXTRA_ORDER_DEPS =
+
+ifeq ($(MICROPY_ROM_TEXT_COMPRESSION),1)
+# If compression is enabled, trigger the build of compressed.data.h...
+OBJ_EXTRA_ORDER_DEPS += $(HEADER_BUILD)/compressed.data.h
+# ...and enable the MP_COMPRESSED_ROM_TEXT macro (used by MP_ERROR_TEXT).
+CFLAGS += -DMICROPY_ROM_TEXT_COMPRESSION=1
+endif
+
+# QSTR generation uses the same CFLAGS, with these modifications.
+QSTR_GEN_FLAGS = -DNO_QSTR -I$(BUILD)/tmp
+# Note: := to force evalulation immediately.
+QSTR_GEN_CFLAGS := $(CFLAGS)
+QSTR_GEN_CFLAGS += $(QSTR_GEN_FLAGS)
+QSTR_GEN_CXXFLAGS := $(CXXFLAGS)
+QSTR_GEN_CXXFLAGS += $(QSTR_GEN_FLAGS)
+
 # This file expects that OBJ contains a list of all of the object files.
 # The directory portion of each object file is used to locate the source
 # and should not contain any ..'s but rather be relative to the top of the
@@ -42,15 +60,28 @@ $(Q)$(CC) $(CFLAGS) -c -MD -o $@ $<
   $(RM) -f $(@:.o=.d)
 endef
 
+define compile_cxx
+$(ECHO) "CXX $<"
+$(Q)$(CXX) $(CXXFLAGS) -c -MD -o $@ $<
+@# The following fixes the dependency file.
+@# See http://make.paulandlesley.org/autodep.html for details.
+@# Regex adjusted from the above to play better with Windows paths, etc.
+@$(CP) $(@:.o=.d) $(@:.o=.P); \
+  $(SED) -e 's/#.*//' -e 's/^.*:  *//' -e 's/ *\\$$//' \
+      -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \
+  $(RM) -f $(@:.o=.d)
+endef
+
 vpath %.c . $(TOP) $(USER_C_MODULES)
 $(BUILD)/%.o: %.c
 	$(call compile_c)
 
-QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR
-QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp
-
 vpath %.c . $(TOP) $(USER_C_MODULES)
 
+vpath %.cpp . $(TOP) $(USER_C_MODULES)
+$(BUILD)/%.o: %.cpp
+	$(call compile_cxx)
+
 $(BUILD)/%.pp: %.c
 	$(ECHO) "PreProcess $<"
 	$(Q)$(CPP) $(CFLAGS) -Wp,-C,-dD,-dI -o $@ $<
@@ -64,25 +95,35 @@ $(BUILD)/%.pp: %.c
 # the right .o's to get recompiled if the generated.h file changes. Adding
 # an order-only dependency to all of the .o's will cause the generated .h
 # to get built before we try to compile any of them.
-$(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h
+$(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h $(OBJ_EXTRA_ORDER_DEPS)
 
-# The logic for qstr regeneration is:
+# The logic for qstr regeneration (applied by makeqstrdefs.py) is:
 # - if anything in QSTR_GLOBAL_DEPENDENCIES is newer, then process all source files ($^)
 # - else, if list of newer prerequisites ($?) is not empty, then process just these ($?)
 # - else, process all source files ($^) [this covers "make -B" which can set $? to empty]
 # See more information about this process in docs/develop/qstr.rst.
 $(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(QSTR_GLOBAL_REQUIREMENTS)
 	$(ECHO) "GEN $@"
-	$(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) >$(HEADER_BUILD)/qstr.i.last
+	$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py pp $(CPP) output $(HEADER_BUILD)/qstr.i.last cflags $(QSTR_GEN_CFLAGS) cxxflags $(QSTR_GEN_CXXFLAGS) sources $^ dependencies $(QSTR_GLOBAL_DEPENDENCIES) changed_sources $?
 
 $(HEADER_BUILD)/qstr.split: $(HEADER_BUILD)/qstr.i.last
 	$(ECHO) "GEN $@"
-	$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py split $(HEADER_BUILD)/qstr.i.last $(HEADER_BUILD)/qstr $(QSTR_DEFS_COLLECTED)
+	$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py split qstr $< $(HEADER_BUILD)/qstr _
 	$(Q)$(TOUCH) $@
 
 $(QSTR_DEFS_COLLECTED): $(HEADER_BUILD)/qstr.split
 	$(ECHO) "GEN $@"
-	$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py cat $(HEADER_BUILD)/qstr.i.last $(HEADER_BUILD)/qstr $(QSTR_DEFS_COLLECTED)
+	$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py cat qstr _ $(HEADER_BUILD)/qstr $@
+
+# Compressed error strings.
+$(HEADER_BUILD)/compressed.split: $(HEADER_BUILD)/qstr.i.last
+	$(ECHO) "GEN $@"
+	$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py split compress $< $(HEADER_BUILD)/compress _
+	$(Q)$(TOUCH) $@
+
+$(HEADER_BUILD)/compressed.collected: $(HEADER_BUILD)/compressed.split
+	$(ECHO) "GEN $@"
+	$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py cat compress _ $(HEADER_BUILD)/compress $@
 
 # $(sort $(var)) removes duplicates
 #

+ 1 - 1
py/modarray.c

@@ -37,7 +37,7 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_array_globals, mp_module_array_globals_tab
 
 const mp_obj_module_t mp_module_uarray = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_array_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_array_globals,
 };
 
 MP_REGISTER_MODULE(MP_QSTR_uarray, mp_module_uarray, MICROPY_PY_ARRAY);

+ 43 - 35
py/modbuiltins.c

@@ -140,7 +140,8 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
     uint8_t str[4];
     int len = 0;
     if (c < 0x80) {
-        *str = c; len = 1;
+        *str = c;
+        len = 1;
     } else if (c < 0x800) {
         str[0] = (c >> 6) | 0xC0;
         str[1] = (c & 0x3F) | 0x80;
@@ -157,16 +158,16 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
         str[3] = (c & 0x3F) | 0x80;
         len = 4;
     } else {
-        mp_raise_ValueError("chr() arg not in range(0x110000)");
+        mp_raise_ValueError(MP_ERROR_TEXT("chr() arg not in range(0x110000)"));
     }
-    return mp_obj_new_str_via_qstr((char*)str, len);
+    return mp_obj_new_str_via_qstr((char *)str, len);
     #else
     mp_int_t ord = mp_obj_get_int(o_in);
     if (0 <= ord && ord <= 0xff) {
         uint8_t str[1] = {ord};
-        return mp_obj_new_str_via_qstr((char*)str, 1);
+        return mp_obj_new_str_via_qstr((char *)str, 1);
     } else {
-        mp_raise_ValueError("chr() arg not in range(256)");
+        mp_raise_ValueError(MP_ERROR_TEXT("chr() arg not in range(256)"));
     }
     #endif
 }
@@ -244,10 +245,10 @@ STATIC mp_obj_t mp_builtin_input(size_t n_args, const mp_obj_t *args) {
     vstr_init(&line, 16);
     int ret = mp_hal_readline(&line, "");
     if (ret == CHAR_CTRL_C) {
-        nlr_raise(mp_obj_new_exception(&mp_type_KeyboardInterrupt));
+        mp_raise_type(&mp_type_KeyboardInterrupt);
     }
     if (line.len == 0 && ret == CHAR_CTRL_D) {
-        nlr_raise(mp_obj_new_exception(&mp_type_EOFError));
+        mp_raise_type(&mp_type_EOFError);
     }
     return mp_obj_new_str_from_vstr(&mp_type_str, &line);
 }
@@ -285,7 +286,7 @@ STATIC mp_obj_t mp_builtin_min_max(size_t n_args, const mp_obj_t *args, mp_map_t
             if (default_elem != NULL) {
                 best_obj = default_elem->value;
             } else {
-                mp_raise_ValueError("arg is an empty sequence");
+                mp_raise_ValueError(MP_ERROR_TEXT("arg is an empty sequence"));
             }
         }
         return best_obj;
@@ -321,7 +322,7 @@ STATIC mp_obj_t mp_builtin_next(size_t n_args, const mp_obj_t *args) {
     if (n_args == 1) {
         mp_obj_t ret = mp_iternext_allow_raise(args[0]);
         if (ret == MP_OBJ_STOP_ITERATION) {
-            nlr_raise(mp_obj_new_exception(&mp_type_StopIteration));
+            mp_raise_type(&mp_type_StopIteration);
         } else {
             return ret;
         }
@@ -335,7 +336,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_next_obj, 1, 2, mp_builtin_next);
 STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
     mp_obj_t ret = mp_iternext_allow_raise(o);
     if (ret == MP_OBJ_STOP_ITERATION) {
-        nlr_raise(mp_obj_new_exception(&mp_type_StopIteration));
+        mp_raise_type(&mp_type_StopIteration);
     } else {
         return ret;
     }
@@ -355,7 +356,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct);
 
 STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
     size_t len;
-    const byte *str = (const byte*)mp_obj_str_get_data(o_in, &len);
+    const byte *str = (const byte *)mp_obj_str_get_data(o_in, &len);
     #if MICROPY_PY_BUILTINS_STR_UNICODE
     if (mp_obj_is_str(o_in)) {
         len = utf8_charlen(str, len);
@@ -371,26 +372,27 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
         }
     }
 
-    if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-        mp_raise_TypeError("ord expects a character");
-    } else {
-        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-            "ord() expected a character, but string of length %d found", (int)len));
-    }
+    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+    mp_raise_TypeError(MP_ERROR_TEXT("ord expects a character"));
+    #else
+    mp_raise_msg_varg(&mp_type_TypeError,
+        MP_ERROR_TEXT("ord() expected a character, but string of length %d found"), (int)len);
+    #endif
 }
 MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord);
 
 STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) {
     switch (n_args) {
-        case 2: return mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]);
+        case 2:
+            return mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]);
         default:
-#if !MICROPY_PY_BUILTINS_POW3
-            mp_raise_msg(&mp_type_NotImplementedError, "3-arg pow() not supported");
-#elif MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_MPZ
+            #if !MICROPY_PY_BUILTINS_POW3
+            mp_raise_NotImplementedError(MP_ERROR_TEXT("3-arg pow() not supported"));
+            #elif MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_MPZ
             return mp_binary_op(MP_BINARY_OP_MODULO, mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]), args[2]);
-#else
+            #else
             return mp_obj_int_pow3(args[0], args[1], args[2]);
-#endif
+            #endif
     }
 }
 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow);
@@ -485,7 +487,7 @@ STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) {
         }
 
         mp_obj_t mult = mp_binary_op(MP_BINARY_OP_POWER, MP_OBJ_NEW_SMALL_INT(10), MP_OBJ_NEW_SMALL_INT(-num_dig));
-        mp_obj_t half_mult =  mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, mult, MP_OBJ_NEW_SMALL_INT(2));
+        mp_obj_t half_mult = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, mult, MP_OBJ_NEW_SMALL_INT(2));
         mp_obj_t modulo = mp_binary_op(MP_BINARY_OP_MODULO, o_in, mult);
         mp_obj_t rounded = mp_binary_op(MP_BINARY_OP_SUBTRACT, o_in, modulo);
         if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, half_mult, modulo))) {
@@ -503,29 +505,33 @@ STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) {
         }
         #endif
     }
-#if MICROPY_PY_BUILTINS_FLOAT
+    #if MICROPY_PY_BUILTINS_FLOAT
     mp_float_t val = mp_obj_get_float(o_in);
     if (n_args > 1) {
         mp_int_t num_dig = mp_obj_get_int(args[1]);
-        mp_float_t mult = MICROPY_FLOAT_C_FUN(pow)(10, num_dig);
+        mp_float_t mult = MICROPY_FLOAT_C_FUN(pow)(10, (mp_float_t)num_dig);
         // TODO may lead to overflow
         mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val * mult) / mult;
         return mp_obj_new_float(rounded);
     }
     mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val);
     return mp_obj_new_int_from_float(rounded);
-#else
+    #else
     mp_int_t r = mp_obj_get_int(o_in);
     return mp_obj_new_int(r);
-#endif
+    #endif
 }
 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj, 1, 2, mp_builtin_round);
 
 STATIC mp_obj_t mp_builtin_sum(size_t n_args, const mp_obj_t *args) {
     mp_obj_t value;
     switch (n_args) {
-        case 1: value = MP_OBJ_NEW_SMALL_INT(0); break;
-        default: value = args[1]; break;
+        case 1:
+            value = MP_OBJ_NEW_SMALL_INT(0);
+            break;
+        default:
+            value = args[1];
+            break;
     }
     mp_obj_iter_buf_t iter_buf;
     mp_obj_t iterable = mp_getiter(args[0], &iter_buf);
@@ -539,7 +545,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum);
 
 STATIC mp_obj_t mp_builtin_sorted(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
     if (n_args > 1) {
-        mp_raise_TypeError("must use keyword argument for key function");
+        mp_raise_TypeError(MP_ERROR_TEXT("must use keyword argument for key function"));
     }
     mp_obj_t self = mp_type_list.make_new(&mp_type_list, 1, 0, args);
     mp_obj_list_sort(1, &self, kwargs);
@@ -552,7 +558,11 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted);
 static inline mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t defval) {
     mp_obj_t dest[2];
     // use load_method, raising or not raising exception
-    ((defval == MP_OBJ_NULL) ? mp_load_method : mp_load_method_maybe)(base, attr, dest);
+    if (defval == MP_OBJ_NULL) {
+        mp_load_method(base, attr, dest);
+    } else {
+        mp_load_method_protected(base, attr, dest, false);
+    }
     if (dest[0] == MP_OBJ_NULL) {
         return defval;
     } else if (dest[1] == MP_OBJ_NULL) {
@@ -762,8 +772,6 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_ViperTypeError), MP_ROM_PTR(&mp_type_ViperTypeError) },
     #endif
     { MP_ROM_QSTR(MP_QSTR_ZeroDivisionError), MP_ROM_PTR(&mp_type_ZeroDivisionError) },
-    // Somehow CPython managed to have OverflowError not inherit from ValueError ;-/
-    // TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation
 
     // Extra builtins as defined by a port
     MICROPY_PORT_BUILTINS
@@ -773,5 +781,5 @@ MP_DEFINE_CONST_DICT(mp_module_builtins_globals, mp_module_builtins_globals_tabl
 
 const mp_obj_module_t mp_module_builtins = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_builtins_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_builtins_globals,
 };

+ 19 - 19
py/modcmath.c

@@ -43,7 +43,7 @@ STATIC mp_obj_t mp_cmath_polar(mp_obj_t z_obj) {
     mp_float_t real, imag;
     mp_obj_get_complex(z_obj, &real, &imag);
     mp_obj_t tuple[2] = {
-        mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real*real + imag*imag)),
+        mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real * real + imag * imag)),
         mp_obj_new_float(MICROPY_FLOAT_C_FUN(atan2)(imag, real)),
     };
     return mp_obj_new_tuple(2, tuple);
@@ -72,7 +72,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp);
 STATIC mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
     mp_float_t real, imag;
     mp_obj_get_complex(z_obj, &real, &imag);
-    return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log)(real*real + imag*imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real));
+    return mp_obj_new_complex(MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(log)(real * real + imag * imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real));
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);
 
@@ -81,7 +81,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);
 STATIC mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
     mp_float_t real, imag;
     mp_obj_get_complex(z_obj, &real, &imag);
-    return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log10)(real*real + imag*imag), 0.4342944819032518 * MICROPY_FLOAT_C_FUN(atan2)(imag, real));
+    return mp_obj_new_complex(MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(log10)(real * real + imag * imag), MICROPY_FLOAT_CONST(0.4342944819032518) * MICROPY_FLOAT_C_FUN(atan2)(imag, real));
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);
 #endif
@@ -90,8 +90,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);
 STATIC mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
     mp_float_t real, imag;
     mp_obj_get_complex(z_obj, &real, &imag);
-    mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real*real + imag*imag, 0.25);
-    mp_float_t theta = 0.5 * MICROPY_FLOAT_C_FUN(atan2)(imag, real);
+    mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real * real + imag * imag, MICROPY_FLOAT_CONST(0.25));
+    mp_float_t theta = MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(atan2)(imag, real);
     return mp_obj_new_complex(sqrt_abs * MICROPY_FLOAT_C_FUN(cos)(theta), sqrt_abs * MICROPY_FLOAT_C_FUN(sin)(theta));
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt);
@@ -125,28 +125,28 @@ STATIC const mp_rom_map_elem_t mp_module_cmath_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_cmath_log10_obj) },
     #endif
     { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_cmath_sqrt_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_cmath_acos_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_cmath_asin_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_cmath_atan_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_cmath_acos_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_cmath_asin_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_cmath_atan_obj) },
     { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_cmath_cos_obj) },
     { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_cmath_sin_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_cmath_tan_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_cmath_acosh_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_cmath_asinh_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_cmath_atanh_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_cmath_cosh_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_cmath_sinh_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_cmath_tanh_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_cmath_isfinite_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_cmath_isinf_obj) },
-    //{ MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_cmath_isnan_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_cmath_tan_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_cmath_acosh_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_cmath_asinh_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_cmath_atanh_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_cmath_cosh_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_cmath_sinh_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_cmath_tanh_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_cmath_isfinite_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_cmath_isinf_obj) },
+    // { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_cmath_isnan_obj) },
 };
 
 STATIC MP_DEFINE_CONST_DICT(mp_module_cmath_globals, mp_module_cmath_globals_table);
 
 const mp_obj_module_t mp_module_cmath = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_cmath_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_cmath_globals,
 };
 
 #endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH

+ 1 - 1
py/modcollections.c

@@ -43,7 +43,7 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_collections_globals, mp_module_collections
 
 const mp_obj_module_t mp_module_collections = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_collections_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_collections_globals,
 };
 
 #endif // MICROPY_PY_COLLECTIONS

+ 4 - 4
py/modgc.c

@@ -33,11 +33,11 @@
 // collect(): run a garbage collection
 STATIC mp_obj_t py_gc_collect(void) {
     gc_collect();
-#if MICROPY_PY_GC_COLLECT_RETVAL
+    #if MICROPY_PY_GC_COLLECT_RETVAL
     return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_collected));
-#else
+    #else
     return mp_const_none;
-#endif
+    #endif
 }
 MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
 
@@ -112,7 +112,7 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_gc_globals, mp_module_gc_globals_table);
 
 const mp_obj_module_t mp_module_gc = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_gc_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_gc_globals,
 };
 
 #endif

+ 14 - 9
py/modio.c

@@ -59,12 +59,17 @@ STATIC mp_uint_t iobase_read_write(mp_obj_t obj, void *buf, mp_uint_t size, int
     mp_load_method(obj, qst, dest);
     mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, size, buf};
     dest[2] = MP_OBJ_FROM_PTR(&ar);
-    mp_obj_t ret = mp_call_method_n_kw(1, 0, dest);
-    if (ret == mp_const_none) {
+    mp_obj_t ret_obj = mp_call_method_n_kw(1, 0, dest);
+    if (ret_obj == mp_const_none) {
         *errcode = MP_EAGAIN;
         return MP_STREAM_ERROR;
+    }
+    mp_int_t ret = mp_obj_get_int(ret_obj);
+    if (ret >= 0) {
+        return ret;
     } else {
-        return mp_obj_get_int(ret);
+        *errcode = -ret;
+        return MP_STREAM_ERROR;
     }
 }
 STATIC mp_uint_t iobase_read(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) {
@@ -72,7 +77,7 @@ STATIC mp_uint_t iobase_read(mp_obj_t obj, void *buf, mp_uint_t size, int *errco
 }
 
 STATIC mp_uint_t iobase_write(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode) {
-    return iobase_read_write(obj, (void*)buf, size, errcode, MP_QSTR_write);
+    return iobase_read_write(obj, (void *)buf, size, errcode, MP_QSTR_write);
 }
 
 STATIC mp_uint_t iobase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode) {
@@ -144,7 +149,7 @@ STATIC mp_uint_t bufwriter_write(mp_obj_t self_in, const void *buf, mp_uint_t si
         // is word-aligned, to guard against obscure cases when it matters, e.g.
         // https://github.com/micropython/micropython/issues/1863
         memcpy(self->buf + self->len, buf, rem);
-        buf = (byte*)buf + rem;
+        buf = (byte *)buf + rem;
         size -= rem;
         mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->alloc, errcode);
         (void)out_sz;
@@ -195,7 +200,7 @@ STATIC const mp_obj_type_t bufwriter_type = {
     .name = MP_QSTR_BufferedWriter,
     .make_new = bufwriter_make_new,
     .protocol = &bufwriter_stream_p,
-    .locals_dict = (mp_obj_dict_t*)&bufwriter_locals_dict,
+    .locals_dict = (mp_obj_dict_t *)&bufwriter_locals_dict,
 };
 #endif // MICROPY_PY_IO_BUFFEREDWRITER
 
@@ -231,14 +236,14 @@ STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) {
         mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
         o->base.type = &mp_type_bytesio;
         o->vstr = m_new_obj(vstr_t);
-        vstr_init_fixed_buf(o->vstr, len + 1, (char*)data);
+        vstr_init_fixed_buf(o->vstr, len + 1, (char *)data);
         o->vstr->len = len;
         o->pos = 0;
         return MP_OBJ_FROM_PTR(o);
     }
 
     mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len);
-    return mp_builtin_open(1, &path_out, (mp_map_t*)&mp_const_empty_map);
+    return mp_builtin_open(1, &path_out, (mp_map_t *)&mp_const_empty_map);
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream);
 #endif
@@ -273,7 +278,7 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_io_globals, mp_module_io_globals_table);
 
 const mp_obj_module_t mp_module_io = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_io_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_io_globals,
 };
 
 #endif

+ 57 - 20
py/modmath.c

@@ -34,9 +34,11 @@
 // M_PI is not part of the math.h standard and may not be defined
 // And by defining our own we can ensure it uses the correct const format.
 #define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846)
+#define MP_PI_4 MICROPY_FLOAT_CONST(0.78539816339744830962)
+#define MP_3_PI_4 MICROPY_FLOAT_CONST(2.35619449019234492885)
 
 STATIC NORETURN void math_error(void) {
-    mp_raise_ValueError("math domain error");
+    mp_raise_ValueError(MP_ERROR_TEXT("math domain error"));
 }
 
 STATIC mp_obj_t math_generic_1(mp_obj_t x_obj, mp_float_t (*f)(mp_float_t)) {
@@ -59,30 +61,30 @@ STATIC mp_obj_t math_generic_2(mp_obj_t x_obj, mp_obj_t y_obj, mp_float_t (*f)(m
 }
 
 #define MATH_FUN_1(py_name, c_name) \
-    STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { \
+    STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { \
         return math_generic_1(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \
     } \
-    STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
+    STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);
 
 #define MATH_FUN_1_TO_BOOL(py_name, c_name) \
-    STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_bool(c_name(mp_obj_get_float(x_obj))); } \
-    STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
+    STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { return mp_obj_new_bool(c_name(mp_obj_get_float(x_obj))); } \
+    STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);
 
 #define MATH_FUN_1_TO_INT(py_name, c_name) \
-    STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int_from_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
-    STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
+    STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { return mp_obj_new_int_from_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
+    STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);
 
 #define MATH_FUN_2(py_name, c_name) \
-    STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \
+    STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \
         return math_generic_2(x_obj, y_obj, MICROPY_FLOAT_C_FUN(c_name)); \
     } \
-    STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name);
+    STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_##py_name##_obj, mp_math_##py_name);
 
 #define MATH_FUN_2_FLT_INT(py_name, c_name) \
-    STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \
+    STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \
         return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_int(y_obj))); \
     } \
-    STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name);
+    STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_##py_name##_obj, mp_math_##py_name);
 
 #if MP_NEED_LOG2
 #undef log2
@@ -96,7 +98,19 @@ mp_float_t MICROPY_FLOAT_C_FUN(log2)(mp_float_t x) {
 // sqrt(x): returns the square root of x
 MATH_FUN_1(sqrt, sqrt)
 // pow(x, y): returns x to the power of y
+#if MICROPY_PY_MATH_POW_FIX_NAN
+mp_float_t pow_func(mp_float_t x, mp_float_t y) {
+    // pow(base, 0) returns 1 for any base, even when base is NaN
+    // pow(+1, exponent) returns 1 for any exponent, even when exponent is NaN
+    if (x == MICROPY_FLOAT_CONST(1.0) || y == MICROPY_FLOAT_CONST(0.0)) {
+        return MICROPY_FLOAT_CONST(1.0);
+    }
+    return MICROPY_FLOAT_C_FUN(pow)(x, y);
+}
+MATH_FUN_2(pow, pow_func)
+#else
 MATH_FUN_2(pow, pow)
+#endif
 // exp(x)
 MATH_FUN_1(exp, exp)
 #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
@@ -132,7 +146,17 @@ MATH_FUN_1(asin, asin)
 // atan(x)
 MATH_FUN_1(atan, atan)
 // atan2(y, x)
+#if MICROPY_PY_MATH_ATAN2_FIX_INFNAN
+mp_float_t atan2_func(mp_float_t x, mp_float_t y) {
+    if (isinf(x) && isinf(y)) {
+        return copysign(y < 0 ? MP_3_PI_4 : MP_PI_4, x);
+    }
+    return atan2(x, y);
+}
+MATH_FUN_2(atan2, atan2_func)
+#else
 MATH_FUN_2(atan2, atan2)
+#endif
 // ceil(x)
 MATH_FUN_1_TO_INT(ceil, ceil)
 // copysign(x, y)
@@ -146,9 +170,16 @@ STATIC mp_float_t MICROPY_FLOAT_C_FUN(fabs_func)(mp_float_t x) {
 }
 MATH_FUN_1(fabs, fabs_func)
 // floor(x)
-MATH_FUN_1_TO_INT(floor, floor) //TODO: delegate to x.__floor__() if x is not a float
+MATH_FUN_1_TO_INT(floor, floor) // TODO: delegate to x.__floor__() if x is not a float
 // fmod(x, y)
+#if MICROPY_PY_MATH_FMOD_FIX_INFNAN
+mp_float_t fmod_func(mp_float_t x, mp_float_t y) {
+    return (!isinf(x) && isinf(y)) ? x : fmod(x, y);
+}
+MATH_FUN_2(fmod, fmod_func)
+#else
 MATH_FUN_2(fmod, fmod)
+#endif
 // isfinite(x)
 MATH_FUN_1_TO_BOOL(isfinite, isfinite)
 // isinf(x)
@@ -169,14 +200,14 @@ MATH_FUN_1(gamma, tgamma)
 // lgamma(x): return the natural logarithm of the gamma function of x
 MATH_FUN_1(lgamma, lgamma)
 #endif
-//TODO: fsum
+// TODO: fsum
 
 #if MICROPY_PY_MATH_ISCLOSE
 STATIC mp_obj_t mp_math_isclose(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     enum { ARG_a, ARG_b, ARG_rel_tol, ARG_abs_tol };
     static const mp_arg_t allowed_args[] = {
-        {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ},
-        {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ},
+        {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
+        {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
         {MP_QSTR_rel_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
         {MP_QSTR_abs_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(0)}},
     };
@@ -223,7 +254,7 @@ STATIC mp_obj_t mp_math_log(size_t n_args, const mp_obj_t *args) {
         if (base <= (mp_float_t)0.0) {
             math_error();
         } else if (base == (mp_float_t)1.0) {
-            mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero");
+            mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero"));
         }
         return mp_obj_new_float(l / MICROPY_FLOAT_C_FUN(log)(base));
     }
@@ -246,7 +277,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp);
 // modf(x)
 STATIC mp_obj_t mp_math_modf(mp_obj_t x_obj) {
     mp_float_t int_part = 0.0;
-    mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(mp_obj_get_float(x_obj), &int_part);
+    mp_float_t x = mp_obj_get_float(x_obj);
+    mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(x, &int_part);
+    #if MICROPY_PY_MATH_MODF_FIX_NEGZERO
+    if (fractional_part == MICROPY_FLOAT_CONST(0.0)) {
+        fractional_part = copysign(fractional_part, x);
+    }
+    #endif
     mp_obj_t tuple[2];
     tuple[0] = mp_obj_new_float(fractional_part);
     tuple[1] = mp_obj_new_float(int_part);
@@ -294,7 +331,7 @@ STATIC mp_obj_t mp_math_factorial_inner(mp_uint_t start, mp_uint_t end) {
 STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) {
     mp_int_t max = mp_obj_get_int(x_obj);
     if (max < 0) {
-        mp_raise_msg(&mp_type_ValueError, "negative factorial");
+        mp_raise_ValueError(MP_ERROR_TEXT("negative factorial"));
     } else if (max == 0) {
         return MP_OBJ_NEW_SMALL_INT(1);
     }
@@ -308,7 +345,7 @@ STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) {
 STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) {
     mp_int_t max = mp_obj_get_int(x_obj);
     if (max < 0) {
-        mp_raise_msg(&mp_type_ValueError, "negative factorial");
+        mp_raise_ValueError(MP_ERROR_TEXT("negative factorial"));
     } else if (max <= 1) {
         return MP_OBJ_NEW_SMALL_INT(1);
     }
@@ -392,7 +429,7 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_math_globals, mp_module_math_globals_table
 
 const mp_obj_module_t mp_module_math = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_math_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_math_globals,
 };
 
 #endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH

+ 27 - 17
py/modmicropython.c

@@ -68,25 +68,25 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem
 
 mp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args) {
     (void)args;
-#if MICROPY_MEM_STATS
+    #if MICROPY_MEM_STATS
     mp_printf(&mp_plat_print, "mem: total=" UINT_FMT ", current=" UINT_FMT ", peak=" UINT_FMT "\n",
         (mp_uint_t)m_get_total_bytes_allocated(), (mp_uint_t)m_get_current_bytes_allocated(), (mp_uint_t)m_get_peak_bytes_allocated());
-#endif
-#if MICROPY_STACK_CHECK
+    #endif
+    #if MICROPY_STACK_CHECK
     mp_printf(&mp_plat_print, "stack: " UINT_FMT " out of " UINT_FMT "\n",
         mp_stack_usage(), (mp_uint_t)MP_STATE_THREAD(stack_limit));
-#else
+    #else
     mp_printf(&mp_plat_print, "stack: " UINT_FMT "\n", mp_stack_usage());
-#endif
-#if MICROPY_ENABLE_GC
+    #endif
+    #if MICROPY_ENABLE_GC
     gc_dump_info();
     if (n_args == 1) {
         // arg given means dump gc allocation table
         gc_dump_alloc_table();
     }
-#else
+    #else
     (void)n_args;
-#endif
+    #endif
     return mp_const_none;
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_mem_info_obj, 0, 1, mp_micropython_mem_info);
@@ -130,9 +130,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_lock_obj, mp_micropython_he
 
 STATIC mp_obj_t mp_micropython_heap_unlock(void) {
     gc_unlock();
-    return mp_const_none;
+    return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_lock_depth));
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_unlock_obj, mp_micropython_heap_unlock);
+
+#if MICROPY_PY_MICROPYTHON_HEAP_LOCKED
+STATIC mp_obj_t mp_micropython_heap_locked(void) {
+    return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_lock_depth));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_locked_obj, mp_micropython_heap_locked);
+#endif
 #endif
 
 #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
@@ -150,7 +157,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd
 #if MICROPY_ENABLE_SCHEDULER
 STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) {
     if (!mp_sched_schedule(function, arg)) {
-        mp_raise_msg(&mp_type_RuntimeError, "schedule queue full");
+        mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("schedule queue full"));
     }
     return mp_const_none;
 }
@@ -163,27 +170,30 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = {
     #if MICROPY_ENABLE_COMPILER
     { MP_ROM_QSTR(MP_QSTR_opt_level), MP_ROM_PTR(&mp_micropython_opt_level_obj) },
     #endif
-#if MICROPY_PY_MICROPYTHON_MEM_INFO
-#if MICROPY_MEM_STATS
+    #if MICROPY_PY_MICROPYTHON_MEM_INFO
+    #if MICROPY_MEM_STATS
     { MP_ROM_QSTR(MP_QSTR_mem_total), MP_ROM_PTR(&mp_micropython_mem_total_obj) },
     { MP_ROM_QSTR(MP_QSTR_mem_current), MP_ROM_PTR(&mp_micropython_mem_current_obj) },
     { MP_ROM_QSTR(MP_QSTR_mem_peak), MP_ROM_PTR(&mp_micropython_mem_peak_obj) },
-#endif
+    #endif
     { MP_ROM_QSTR(MP_QSTR_mem_info), MP_ROM_PTR(&mp_micropython_mem_info_obj) },
     { MP_ROM_QSTR(MP_QSTR_qstr_info), MP_ROM_PTR(&mp_micropython_qstr_info_obj) },
-#endif
+    #endif
     #if MICROPY_PY_MICROPYTHON_STACK_USE
     { MP_ROM_QSTR(MP_QSTR_stack_use), MP_ROM_PTR(&mp_micropython_stack_use_obj) },
     #endif
-#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
+    #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
     { MP_ROM_QSTR(MP_QSTR_alloc_emergency_exception_buf), MP_ROM_PTR(&mp_alloc_emergency_exception_buf_obj) },
-#endif
+    #endif
     #if MICROPY_ENABLE_PYSTACK
     { MP_ROM_QSTR(MP_QSTR_pystack_use), MP_ROM_PTR(&mp_micropython_pystack_use_obj) },
     #endif
     #if MICROPY_ENABLE_GC
     { MP_ROM_QSTR(MP_QSTR_heap_lock), MP_ROM_PTR(&mp_micropython_heap_lock_obj) },
     { MP_ROM_QSTR(MP_QSTR_heap_unlock), MP_ROM_PTR(&mp_micropython_heap_unlock_obj) },
+    #if MICROPY_PY_MICROPYTHON_HEAP_LOCKED
+    { MP_ROM_QSTR(MP_QSTR_heap_locked), MP_ROM_PTR(&mp_micropython_heap_locked_obj) },
+    #endif
     #endif
     #if MICROPY_KBD_EXCEPTION
     { MP_ROM_QSTR(MP_QSTR_kbd_intr), MP_ROM_PTR(&mp_micropython_kbd_intr_obj) },
@@ -197,5 +207,5 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_micropython_globals, mp_module_micropython
 
 const mp_obj_module_t mp_module_micropython = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_micropython_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_micropython_globals,
 };

+ 6 - 6
py/modstruct.c

@@ -141,7 +141,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {
             // negative offsets are relative to the end of the buffer
             offset = bufinfo.len + offset;
             if (offset < 0) {
-                mp_raise_ValueError("buffer too small");
+                mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
             }
         }
         p += offset;
@@ -150,7 +150,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {
 
     // Check that the input buffer is big enough to unpack all the values
     if (p + total_sz > end_p) {
-        mp_raise_ValueError("buffer too small");
+        mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
     }
 
     for (size_t i = 0; i < num_items;) {
@@ -217,7 +217,7 @@ STATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t *args) {
     mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
     vstr_t vstr;
     vstr_init_len(&vstr, size);
-    byte *p = (byte*)vstr.buf;
+    byte *p = (byte *)vstr.buf;
     memset(p, 0, size);
     struct_pack_into_internal(args[0], p, n_args - 1, &args[1]);
     return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
@@ -232,7 +232,7 @@ STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) {
         // negative offsets are relative to the end of the buffer
         offset = (mp_int_t)bufinfo.len + offset;
         if (offset < 0) {
-            mp_raise_ValueError("buffer too small");
+            mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
         }
     }
     byte *p = (byte *)bufinfo.buf;
@@ -242,7 +242,7 @@ STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) {
     // Check that the output buffer is big enough to hold all the values
     mp_int_t sz = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
     if (p + sz > end_p) {
-        mp_raise_ValueError("buffer too small");
+        mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
     }
 
     struct_pack_into_internal(args[0], p, n_args - 3, &args[3]);
@@ -263,7 +263,7 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_struct_globals, mp_module_struct_globals_t
 
 const mp_obj_module_t mp_module_ustruct = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_struct_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_struct_globals,
 };
 
 #endif

+ 8 - 8
py/modsys.c

@@ -53,7 +53,7 @@ const mp_print_t mp_sys_stdout_print = {&mp_sys_stdout_obj, mp_stream_write_adap
 #endif
 
 // version - Python language version that this implementation conforms to, as a string
-STATIC const MP_DEFINE_STR_OBJ(version_obj, "3.4.0");
+STATIC const MP_DEFINE_STR_OBJ(mp_sys_version_obj, "3.4.0");
 
 // version_info - Python language version that this implementation conforms to, as a tuple of ints
 #define I(n) MP_OBJ_NEW_SMALL_INT(n)
@@ -89,8 +89,8 @@ STATIC MP_DEFINE_ATTRTUPLE(
     mp_sys_implementation_obj,
     impl_fields,
     2 + MICROPY_PERSISTENT_CODE_LOAD,
-        SYS_IMPLEMENTATION_ELEMS
-);
+    SYS_IMPLEMENTATION_ELEMS
+    );
 #else
 STATIC const mp_rom_obj_tuple_t mp_sys_implementation_obj = {
     {&mp_type_tuple},
@@ -105,7 +105,7 @@ STATIC const mp_rom_obj_tuple_t mp_sys_implementation_obj = {
 
 #ifdef MICROPY_PY_SYS_PLATFORM
 // platform - the platform that MicroPython is running on
-STATIC const MP_DEFINE_STR_OBJ(platform_obj, MICROPY_PY_SYS_PLATFORM);
+STATIC const MP_DEFINE_STR_OBJ(mp_sys_platform_obj, MICROPY_PY_SYS_PLATFORM);
 #endif
 
 // exit([retval]): raise SystemExit, with optional argument given to the exception
@@ -189,11 +189,11 @@ STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = {
 
     { MP_ROM_QSTR(MP_QSTR_path), MP_ROM_PTR(&MP_STATE_VM(mp_sys_path_obj)) },
     { MP_ROM_QSTR(MP_QSTR_argv), MP_ROM_PTR(&MP_STATE_VM(mp_sys_argv_obj)) },
-    { MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&version_obj) },
+    { MP_ROM_QSTR(MP_QSTR_version), MP_ROM_PTR(&mp_sys_version_obj) },
     { MP_ROM_QSTR(MP_QSTR_version_info), MP_ROM_PTR(&mp_sys_version_info_obj) },
     { MP_ROM_QSTR(MP_QSTR_implementation), MP_ROM_PTR(&mp_sys_implementation_obj) },
     #ifdef MICROPY_PY_SYS_PLATFORM
-    { MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_obj) },
+    { MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&mp_sys_platform_obj) },
     #endif
     #if MP_ENDIANNESS_LITTLE
     { MP_ROM_QSTR(MP_QSTR_byteorder), MP_ROM_QSTR(MP_QSTR_little) },
@@ -210,7 +210,7 @@ STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = {
     // of "one" bits in sys.maxsize.
     { MP_ROM_QSTR(MP_QSTR_maxsize), MP_ROM_INT(MP_SMALL_INT_MAX) },
     #else
-    { MP_ROM_QSTR(MP_QSTR_maxsize), MP_ROM_PTR(&mp_maxsize_obj) },
+    { MP_ROM_QSTR(MP_QSTR_maxsize), MP_ROM_PTR(&mp_sys_maxsize_obj) },
     #endif
     #endif
 
@@ -252,7 +252,7 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_sys_globals, mp_module_sys_globals_table);
 
 const mp_obj_module_t mp_module_sys = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_sys_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_sys_globals,
 };
 
 #endif

+ 8 - 8
py/modthread.c

@@ -120,7 +120,7 @@ STATIC MP_DEFINE_CONST_DICT(thread_lock_locals_dict, thread_lock_locals_dict_tab
 STATIC const mp_obj_type_t mp_type_thread_lock = {
     { &mp_type_type },
     .name = MP_QSTR_lock,
-    .locals_dict = (mp_obj_dict_t*)&thread_lock_locals_dict,
+    .locals_dict = (mp_obj_dict_t *)&thread_lock_locals_dict,
 };
 
 /****************************************************************/
@@ -157,7 +157,7 @@ typedef struct _thread_entry_args_t {
 STATIC void *thread_entry(void *args_in) {
     // Execution begins here for a new thread.  We do not have the GIL.
 
-    thread_entry_args_t *args = (thread_entry_args_t*)args_in;
+    thread_entry_args_t *args = (thread_entry_args_t *)args_in;
 
     mp_state_thread_t ts;
     mp_thread_set_state(&ts);
@@ -193,7 +193,7 @@ STATIC void *thread_entry(void *args_in) {
     } else {
         // uncaught exception
         // check for SystemExit
-        mp_obj_base_t *exc = (mp_obj_base_t*)nlr.ret_val;
+        mp_obj_base_t *exc = (mp_obj_base_t *)nlr.ret_val;
         if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
             // swallow exception silently
         } else {
@@ -235,9 +235,9 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args)
     } else {
         // positional and keyword arguments
         if (mp_obj_get_type(args[2]) != &mp_type_dict) {
-            mp_raise_TypeError("expecting a dict for keyword args");
+            mp_raise_TypeError(MP_ERROR_TEXT("expecting a dict for keyword args"));
         }
-        mp_map_t *map = &((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[2]))->map;
+        mp_map_t *map = &((mp_obj_dict_t *)MP_OBJ_TO_PTR(args[2]))->map;
         th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used);
         th_args->n_kw = map->used;
         // copy across the keyword arguments
@@ -249,7 +249,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args)
         }
     }
 
-    // copy agross the positional arguments
+    // copy across the positional arguments
     th_args->n_args = pos_args_len;
     memcpy(th_args->args, pos_args_items, pos_args_len * sizeof(mp_obj_t));
 
@@ -271,7 +271,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args)
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_start_new_thread_obj, 2, 3, mod_thread_start_new_thread);
 
 STATIC mp_obj_t mod_thread_exit(void) {
-    nlr_raise(mp_obj_new_exception(&mp_type_SystemExit));
+    mp_raise_type(&mp_type_SystemExit);
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_exit_obj, mod_thread_exit);
 
@@ -294,7 +294,7 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_thread_globals, mp_module_thread_globals_t
 
 const mp_obj_module_t mp_module_thread = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_thread_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_thread_globals,
 };
 
 #endif // MICROPY_PY_THREAD

+ 8 - 8
py/moduerrno.c

@@ -63,9 +63,9 @@
 
 #if MICROPY_PY_UERRNO_ERRORCODE
 STATIC const mp_rom_map_elem_t errorcode_table[] = {
-    #define X(e) { MP_ROM_INT(MP_ ## e), MP_ROM_QSTR(MP_QSTR_## e) },
+    #define X(e) { MP_ROM_INT(MP_##e), MP_ROM_QSTR(MP_QSTR_##e) },
     MICROPY_PY_UERRNO_LIST
-    #undef X
+#undef X
 };
 
 STATIC const mp_obj_dict_t errorcode_dict = {
@@ -76,7 +76,7 @@ STATIC const mp_obj_dict_t errorcode_dict = {
         .is_ordered = 1,
         .used = MP_ARRAY_SIZE(errorcode_table),
         .alloc = MP_ARRAY_SIZE(errorcode_table),
-        .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)errorcode_table,
+        .table = (mp_map_elem_t *)(mp_rom_map_elem_t *)errorcode_table,
     },
 };
 #endif
@@ -87,22 +87,22 @@ STATIC const mp_rom_map_elem_t mp_module_uerrno_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR_errorcode), MP_ROM_PTR(&errorcode_dict) },
     #endif
 
-    #define X(e) { MP_ROM_QSTR(MP_QSTR_## e), MP_ROM_INT(MP_ ## e) },
+    #define X(e) { MP_ROM_QSTR(MP_QSTR_##e), MP_ROM_INT(MP_##e) },
     MICROPY_PY_UERRNO_LIST
-    #undef X
+#undef X
 };
 
 STATIC MP_DEFINE_CONST_DICT(mp_module_uerrno_globals, mp_module_uerrno_globals_table);
 
 const mp_obj_module_t mp_module_uerrno = {
     .base = { &mp_type_module },
-    .globals = (mp_obj_dict_t*)&mp_module_uerrno_globals,
+    .globals = (mp_obj_dict_t *)&mp_module_uerrno_globals,
 };
 
 qstr mp_errno_to_str(mp_obj_t errno_val) {
     #if MICROPY_PY_UERRNO_ERRORCODE
     // We have the errorcode dict so can do a lookup using the hash map
-    mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&errorcode_dict.map, errno_val, MP_MAP_LOOKUP);
+    mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&errorcode_dict.map, errno_val, MP_MAP_LOOKUP);
     if (elem == NULL) {
         return MP_QSTRnull;
     } else {
@@ -119,4 +119,4 @@ qstr mp_errno_to_str(mp_obj_t errno_val) {
     #endif
 }
 
-#endif //MICROPY_PY_UERRNO
+#endif // MICROPY_PY_UERRNO

+ 134 - 32
py/mpconfig.h

@@ -28,14 +28,14 @@
 
 // Current version of MicroPython
 #define MICROPY_VERSION_MAJOR 1
-#define MICROPY_VERSION_MINOR 12
+#define MICROPY_VERSION_MINOR 13
 #define MICROPY_VERSION_MICRO 0
 
 // Combined version as a 32-bit number for convenience
 #define MICROPY_VERSION ( \
     MICROPY_VERSION_MAJOR << 16 \
-    | MICROPY_VERSION_MINOR << 8 \
-    | MICROPY_VERSION_MICRO)
+        | MICROPY_VERSION_MINOR << 8 \
+        | MICROPY_VERSION_MICRO)
 
 // String version
 #define MICROPY_VERSION_STRING \
@@ -70,25 +70,28 @@
 
 // A MicroPython object is a machine word having the following form:
 //  - xxxx...xxx1 : a small int, bits 1 and above are the value
-//  - xxxx...xx10 : a qstr, bits 2 and above are the value
+//  - xxxx...x010 : a qstr, bits 3 and above are the value
+//  - xxxx...x110 : an immediate object, bits 3 and above are the value
 //  - xxxx...xx00 : a pointer to an mp_obj_base_t (unless a fake object)
 #define MICROPY_OBJ_REPR_A (0)
 
 // A MicroPython object is a machine word having the following form:
 //  - xxxx...xx01 : a small int, bits 2 and above are the value
-//  - xxxx...xx11 : a qstr, bits 2 and above are the value
+//  - xxxx...x011 : a qstr, bits 3 and above are the value
+//  - xxxx...x111 : an immediate object, bits 3 and above are the value
 //  - xxxx...xxx0 : a pointer to an mp_obj_base_t (unless a fake object)
 #define MICROPY_OBJ_REPR_B (1)
 
 // A MicroPython object is a machine word having the following form (called R):
 //  - iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int with 31-bit signed value
-//  - 01111111 1qqqqqqq qqqqqqqq qqqqq110 str with 20-bit qstr value
+//  - 01111111 1qqqqqqq qqqqqqqq qqqq0110 str with 19-bit qstr value
+//  - 01111111 10000000 00000000 ssss1110 immediate object with 4-bit value
 //  - s1111111 10000000 00000000 00000010 +/- inf
 //  - s1111111 1xxxxxxx xxxxxxxx xxxxx010 nan, x != 0
 //  - seeeeeee efffffff ffffffff ffffff10 30-bit fp, e != 0xff
 //  - pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment)
-// Str and float stored as O = R + 0x80800000, retrieved as R = O - 0x80800000.
-// This makes strs easier to encode/decode as they have zeros in the top 9 bits.
+// Str, immediate and float stored as O = R + 0x80800000, retrieved as R = O - 0x80800000.
+// This makes strs/immediates easier to encode/decode as they have zeros in the top 9 bits.
 // This scheme only works with 32-bit word size and float enabled.
 #define MICROPY_OBJ_REPR_C (2)
 
@@ -98,6 +101,7 @@
 //  - 01111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000 normalised nan
 //  - 01111111 11111101 iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int
 //  - 01111111 11111110 00000000 00000000 qqqqqqqq qqqqqqqq qqqqqqqq qqqqqqq1 str
+//  - 01111111 11111111 ss000000 00000000 00000000 00000000 00000000 00000000 immediate object
 //  - 01111111 11111100 00000000 00000000 pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment)
 // Stored as O = R + 0x8004000000000000, retrieved as R = O - 0x8004000000000000.
 // This makes pointers have all zeros in the top 32 bits.
@@ -109,6 +113,13 @@
 #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_A)
 #endif
 
+// Whether to encode None/False/True as immediate objects instead of pointers to
+// real objects.  Reduces code size by a decent amount without hurting
+// performance, for all representations except D on some architectures.
+#ifndef MICROPY_OBJ_IMMEDIATE_OBJS
+#define MICROPY_OBJ_IMMEDIATE_OBJS (MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D)
+#endif
+
 /*****************************************************************************/
 /* Memory allocation policy                                                  */
 
@@ -340,6 +351,18 @@
 // Convenience definition for whether any native or inline assembler emitter is enabled
 #define MICROPY_EMIT_MACHINE_CODE (MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM)
 
+// Whether native relocatable code loaded from .mpy files is explicitly tracked
+// so that the GC cannot reclaim it.  Needed on architectures that allocate
+// executable memory on the MicroPython heap and don't explicitly track this
+// data some other way.
+#ifndef MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE
+#if !MICROPY_EMIT_MACHINE_CODE || defined(MP_PLAT_ALLOC_EXEC) || defined(MP_PLAT_COMMIT_EXEC)
+#define MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE (0)
+#else
+#define MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE (1)
+#endif
+#endif
+
 /*****************************************************************************/
 /* Compiler configuration                                                    */
 
@@ -431,6 +454,11 @@
 #define MICROPY_DEBUG_MP_OBJ_SENTINELS (0)
 #endif
 
+// Whether to print parse rule names (rather than integers) in mp_parse_node_print
+#ifndef MICROPY_DEBUG_PARSE_RULE_NAME
+#define MICROPY_DEBUG_PARSE_RULE_NAME (0)
+#endif
+
 // Whether to enable a simple VM stack overflow check
 #ifndef MICROPY_DEBUG_VM_STACK_OVERFLOW
 #define MICROPY_DEBUG_VM_STACK_OVERFLOW (0)
@@ -539,9 +567,9 @@
 #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
 #endif
 #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
-#   ifndef MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
-#   define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)   // 0 - implies dynamic allocation
-#   endif
+#ifndef MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
+#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)      // 0 - implies dynamic allocation
+#endif
 #endif
 
 // Whether to provide the mp_kbd_exception object, and micropython.kbd_intr function
@@ -560,11 +588,31 @@
 #define MICROPY_HELPER_REPL (0)
 #endif
 
+// Allow enabling debug prints after each REPL line
+#ifndef MICROPY_REPL_INFO
+#define MICROPY_REPL_INFO (0)
+#endif
+
 // Whether to include emacs-style readline behavior in REPL
 #ifndef MICROPY_REPL_EMACS_KEYS
 #define MICROPY_REPL_EMACS_KEYS (0)
 #endif
 
+// Whether to include emacs-style word movement/kill readline behavior in REPL.
+// This adds Alt+F, Alt+B, Alt+D and Alt+Backspace for forward-word, backward-word, forward-kill-word
+// and backward-kill-word, respectively.
+#ifndef MICROPY_REPL_EMACS_WORDS_MOVE
+#define MICROPY_REPL_EMACS_WORDS_MOVE (0)
+#endif
+
+// Whether to include extra convenience keys for word movement/kill in readline REPL.
+// This adds Ctrl+Right, Ctrl+Left and Ctrl+W for forward-word, backward-word and backward-kill-word
+// respectively. Ctrl+Delete is not implemented because it's a very different escape sequence.
+// Depends on MICROPY_REPL_EMACS_WORDS_MOVE.
+#ifndef MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
+#define MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE (0)
+#endif
+
 // Whether to implement auto-indent in REPL
 #ifndef MICROPY_REPL_AUTO_INDENT
 #define MICROPY_REPL_AUTO_INDENT (0)
@@ -698,7 +746,7 @@ typedef double mp_float_t;
 
 // Whether to support module-level __getattr__ (see PEP 562)
 #ifndef MICROPY_MODULE_GETATTR
-#define MICROPY_MODULE_GETATTR (0)
+#define MICROPY_MODULE_GETATTR (1)
 #endif
 
 // Whether module weak links are supported
@@ -804,6 +852,11 @@ typedef double mp_float_t;
 #define MICROPY_PY_ASYNC_AWAIT (1)
 #endif
 
+// Support for assignment expressions with := (see PEP 572, Python 3.8+)
+#ifndef MICROPY_PY_ASSIGN_EXPR
+#define MICROPY_PY_ASSIGN_EXPR (1)
+#endif
+
 // Non-standard .pend_throw() method for generators, allowing for
 // Future-like behavior with respect to exception handling: an
 // exception set with .pend_throw() will activate on the next call
@@ -889,6 +942,11 @@ typedef double mp_float_t;
 #define MICROPY_PY_BUILTINS_SLICE_ATTRS (0)
 #endif
 
+// Whether to support the .indices(len) method on slice objects
+#ifndef MICROPY_PY_BUILTINS_SLICE_INDICES
+#define MICROPY_PY_BUILTINS_SLICE_INDICES (0)
+#endif
+
 // Whether to support frozenset object
 #ifndef MICROPY_PY_BUILTINS_FROZENSET
 #define MICROPY_PY_BUILTINS_FROZENSET (0)
@@ -923,11 +981,6 @@ typedef double mp_float_t;
 #define MICROPY_PY_BUILTINS_ROUND_INT (0)
 #endif
 
-// Whether to support timeout exceptions (like socket.timeout)
-#ifndef MICROPY_PY_BUILTINS_TIMEOUTERROR
-#define MICROPY_PY_BUILTINS_TIMEOUTERROR (0)
-#endif
-
 // Whether to support complete set of special methods for user
 // classes, or only the most used ones. "Inplace" methods are
 // controlled by MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS below.
@@ -1033,6 +1086,11 @@ typedef double mp_float_t;
 #define MICROPY_PY_MICROPYTHON_STACK_USE (MICROPY_PY_MICROPYTHON_MEM_INFO)
 #endif
 
+// Whether to provide the "micropython.heap_locked" function
+#ifndef MICROPY_PY_MICROPYTHON_HEAP_LOCKED
+#define MICROPY_PY_MICROPYTHON_HEAP_LOCKED (0)
+#endif
+
 // Whether to provide "array" module. Note that large chunk of the
 // underlying code is shared with "bytearray" builtin type, so to
 // get real savings, it should be disabled too.
@@ -1092,6 +1150,26 @@ typedef double mp_float_t;
 #define MICROPY_PY_MATH_ISCLOSE (0)
 #endif
 
+// Whether to provide fix for atan2 Inf handling.
+#ifndef MICROPY_PY_MATH_ATAN2_FIX_INFNAN
+#define MICROPY_PY_MATH_ATAN2_FIX_INFNAN (0)
+#endif
+
+// Whether to provide fix for fmod Inf handling.
+#ifndef MICROPY_PY_MATH_FMOD_FIX_INFNAN
+#define MICROPY_PY_MATH_FMOD_FIX_INFNAN (0)
+#endif
+
+// Whether to provide fix for modf negative zero handling.
+#ifndef MICROPY_PY_MATH_MODF_FIX_NEGZERO
+#define MICROPY_PY_MATH_MODF_FIX_NEGZERO (0)
+#endif
+
+// Whether to provide fix for pow(1, NaN) and pow(NaN, 0), which both should be 1 not NaN.
+#ifndef MICROPY_PY_MATH_POW_FIX_NAN
+#define MICROPY_PY_MATH_POW_FIX_NAN (0)
+#endif
+
 // Whether to provide "cmath" module
 #ifndef MICROPY_PY_CMATH
 #define MICROPY_PY_CMATH (0)
@@ -1250,6 +1328,10 @@ typedef double mp_float_t;
 
 // Extended modules
 
+#ifndef MICROPY_PY_UASYNCIO
+#define MICROPY_PY_UASYNCIO (0)
+#endif
+
 #ifndef MICROPY_PY_UCTYPES
 #define MICROPY_PY_UCTYPES (0)
 #endif
@@ -1402,6 +1484,17 @@ typedef double mp_float_t;
 #define MICROPY_PORT_ROOT_POINTERS
 #endif
 
+/*****************************************************************************/
+/* Hooks for a port to wrap functions with attributes                        */
+
+#ifndef MICROPY_WRAP_MP_KEYBOARD_INTERRUPT
+#define MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(f) f
+#endif
+
+#ifndef MICROPY_WRAP_MP_SCHED_SCHEDULE
+#define MICROPY_WRAP_MP_SCHED_SCHEDULE(f) f
+#endif
+
 /*****************************************************************************/
 /* Miscellaneous settings                                                    */
 
@@ -1432,7 +1525,9 @@ typedef double mp_float_t;
 #define BYTES_PER_WORD (sizeof(mp_uint_t))
 #endif
 
+#ifndef BITS_PER_BYTE
 #define BITS_PER_BYTE (8)
+#endif
 #define BITS_PER_WORD (BITS_PER_BYTE * BYTES_PER_WORD)
 // mp_int_t value with most significant bit set
 #define WORD_MSBIT_HIGH (((mp_uint_t)1) << (BYTES_PER_WORD * 8 - 1))
@@ -1444,7 +1539,7 @@ typedef double mp_float_t;
 #elif defined(MP_ENDIANNESS_BIG)
 #define MP_ENDIANNESS_LITTLE (!MP_ENDIANNESS_BIG)
 #else
-  // Endianness not defined by port so try to autodetect it.
+// Endianness not defined by port so try to autodetect it.
   #if defined(__BYTE_ORDER__)
     #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
       #define MP_ENDIANNESS_LITTLE (1)
@@ -1507,7 +1602,7 @@ typedef double mp_float_t;
 #define UINT_FMT "%u"
 #define INT_FMT "%d"
 #endif
-#endif //INT_FMT
+#endif // INT_FMT
 
 // Modifier for function which doesn't return
 #ifndef NORETURN
@@ -1548,35 +1643,42 @@ typedef double mp_float_t;
 #endif
 #endif
 
+// Explicitly annotate switch case fall throughs
+#if defined(__GNUC__) && __GNUC__ >= 7
+#define MP_FALLTHROUGH __attribute__((fallthrough));
+#else
+#define MP_FALLTHROUGH
+#endif
+
 #ifndef MP_HTOBE16
 #if MP_ENDIANNESS_LITTLE
-# define MP_HTOBE16(x) ((uint16_t)( (((x) & 0xff) << 8) | (((x) >> 8) & 0xff) ))
-# define MP_BE16TOH(x) MP_HTOBE16(x)
+#define MP_HTOBE16(x) ((uint16_t)((((x) & 0xff) << 8) | (((x) >> 8) & 0xff)))
+#define MP_BE16TOH(x) MP_HTOBE16(x)
 #else
-# define MP_HTOBE16(x) (x)
-# define MP_BE16TOH(x) (x)
+#define MP_HTOBE16(x) (x)
+#define MP_BE16TOH(x) (x)
 #endif
 #endif
 
 #ifndef MP_HTOBE32
 #if MP_ENDIANNESS_LITTLE
-# define MP_HTOBE32(x) ((uint32_t)( (((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8)  & 0xff00) | (((x) >> 24) & 0xff) ))
-# define MP_BE32TOH(x) MP_HTOBE32(x)
+#define MP_HTOBE32(x) ((uint32_t)((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff)))
+#define MP_BE32TOH(x) MP_HTOBE32(x)
 #else
-# define MP_HTOBE32(x) (x)
-# define MP_BE32TOH(x) (x)
+#define MP_HTOBE32(x) (x)
+#define MP_BE32TOH(x) (x)
 #endif
 #endif
 
 // Warning categories are by default implemented as strings, though
 // hook is left for a port to define them as something else.
 #if MICROPY_WARNINGS_CATEGORY
-# ifndef MP_WARN_CAT
-# define MP_WARN_CAT(x) #x
-# endif
+#ifndef MP_WARN_CAT
+#define MP_WARN_CAT(x) #x
+#endif
 #else
-# undef MP_WARN_CAT
-# define MP_WARN_CAT(x) (NULL)
+#undef MP_WARN_CAT
+#define MP_WARN_CAT(x) (NULL)
 #endif
 
 // Feature dependency check.

+ 6 - 0
py/mphal.h

@@ -26,6 +26,7 @@
 #ifndef MICROPY_INCLUDED_PY_MPHAL_H
 #define MICROPY_INCLUDED_PY_MPHAL_H
 
+#include <stdint.h>
 #include "py/mpconfig.h"
 
 #ifdef MICROPY_MPHALPORT_H
@@ -74,6 +75,11 @@ mp_uint_t mp_hal_ticks_us(void);
 mp_uint_t mp_hal_ticks_cpu(void);
 #endif
 
+#ifndef mp_hal_time_ns
+// Nanoseconds since the Epoch.
+uint64_t mp_hal_time_ns(void);
+#endif
+
 // If port HAL didn't define its own pin API, use generic
 // "virtual pin" API from the core.
 #ifndef mp_hal_pin_obj_t

+ 31 - 30
py/mpprint.c

@@ -269,14 +269,14 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char
         // We add the pad in this function, so since the pad goes after
         // the sign & prefix, we format without a prefix
         str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size,
-                                   x, base, NULL, base_char, comma);
+            x, base, NULL, base_char, comma);
         if (*str == '-') {
             sign = *str++;
             fmt_size--;
         }
     } else {
         str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size,
-                                   x, base, prefix, base_char, comma);
+            x, base, prefix, base_char, comma);
     }
 
     int spaces_before = 0;
@@ -347,8 +347,7 @@ int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, c
 
     if (flags & PF_FLAG_SHOW_SIGN) {
         sign = '+';
-    }
-    else
+    } else
     if (flags & PF_FLAG_SPACE_SIGN) {
         sign = ' ';
     }
@@ -411,14 +410,20 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
         int flags = 0;
         char fill = ' ';
         while (*fmt != '\0') {
-            if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST;
-            else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN;
-            else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN;
-            else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ;
-            else if (*fmt == '0') {
+            if (*fmt == '-') {
+                flags |= PF_FLAG_LEFT_ADJUST;
+            } else if (*fmt == '+') {
+                flags |= PF_FLAG_SHOW_SIGN;
+            } else if (*fmt == ' ') {
+                flags |= PF_FLAG_SPACE_SIGN;
+            } else if (*fmt == '!') {
+                flags |= PF_FLAG_NO_TRAILZ;
+            } else if (*fmt == '0') {
                 flags |= PF_FLAG_PAD_AFTER_SIGN;
                 fill = '0';
-            } else break;
+            } else {
+                break;
+            }
             ++fmt;
         }
 
@@ -470,26 +475,23 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
                     chrs += mp_print_strn(print, "false", 5, flags, fill, width);
                 }
                 break;
-            case 'c':
-            {
+            case 'c': {
                 char str = va_arg(args, int);
                 chrs += mp_print_strn(print, &str, 1, flags, fill, width);
                 break;
             }
-            case 'q':
-            {
+            case 'q': {
                 qstr qst = va_arg(args, qstr);
                 size_t len;
-                const char *str = (const char*)qstr_data(qst, &len);
+                const char *str = (const char *)qstr_data(qst, &len);
                 if (prec < 0) {
                     prec = len;
                 }
                 chrs += mp_print_strn(print, str, prec, flags, fill, width);
                 break;
             }
-            case 's':
-            {
-                const char *str = va_arg(args, const char*);
+            case 's': {
+                const char *str = va_arg(args, const char *);
                 #ifndef NDEBUG
                 // With debugging enabled, catch printing of null string pointers
                 if (prec != 0 && str == NULL) {
@@ -532,26 +534,25 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
                 // Use unsigned long int to work on both ILP32 and LP64 systems
                 chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width);
                 break;
-#if MICROPY_PY_BUILTINS_FLOAT
+            #if MICROPY_PY_BUILTINS_FLOAT
             case 'e':
             case 'E':
             case 'f':
             case 'F':
             case 'g':
-            case 'G':
-            {
-#if ((MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT) || (MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE))
-                mp_float_t f = va_arg(args, double);
+            case 'G': {
+                #if ((MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT) || (MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE))
+                mp_float_t f = (mp_float_t)va_arg(args, double);
                 chrs += mp_print_float(print, f, *fmt, flags, fill, width, prec);
-#else
-#error Unknown MICROPY FLOAT IMPL
-#endif
+                #else
+                #error Unknown MICROPY FLOAT IMPL
+                #endif
                 break;
             }
-#endif
-            // Because 'l' is eaten above, another 'l' means %ll.  We need to support
-            // this length specifier for OBJ_REPR_D (64-bit NaN boxing).
-            // TODO Either enable this unconditionally, or provide a specific config var.
+            #endif
+                // Because 'l' is eaten above, another 'l' means %ll.  We need to support
+                // this length specifier for OBJ_REPR_D (64-bit NaN boxing).
+                // TODO Either enable this unconditionally, or provide a specific config var.
             #if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64)
             case 'l': {
                 unsigned long long int arg_value = va_arg(args, unsigned long long int);

+ 2 - 2
py/mpprint.h

@@ -40,9 +40,9 @@
 #define PF_FLAG_SHOW_OCTAL_LETTER (0x200)
 
 #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
-#    define MP_PYTHON_PRINTER &mp_sys_stdout_print
+#define MP_PYTHON_PRINTER &mp_sys_stdout_print
 #else
-#    define MP_PYTHON_PRINTER &mp_plat_print
+#define MP_PYTHON_PRINTER &mp_plat_print
 #endif
 
 typedef void (*mp_print_strn_t)(void *data, const char *str, size_t len);

+ 7 - 2
py/mpstate.h

@@ -98,7 +98,7 @@ typedef struct _mp_state_mem_t {
     size_t gc_collected;
     #endif
 
-    #if MICROPY_PY_THREAD
+    #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL
     // This is a global mutex used to make the GC thread-safe.
     mp_thread_mutex_t gc_mutex;
     #endif
@@ -167,6 +167,11 @@ typedef struct _mp_state_vm_t {
     mp_obj_dict_t *mp_module_builtins_override_dict;
     #endif
 
+    #if MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE
+    // An mp_obj_list_t that tracks relocated native code to prevent the GC from reclaiming them.
+    mp_obj_t track_reloc_code_list;
+    #endif
+
     // include any root pointers defined by a port
     MICROPY_PORT_ROOT_POINTERS
 
@@ -203,7 +208,7 @@ typedef struct _mp_state_vm_t {
     size_t qstr_last_alloc;
     size_t qstr_last_used;
 
-    #if MICROPY_PY_THREAD
+    #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL
     // This is a global mutex used to make qstr interning thread-safe.
     mp_thread_mutex_t qstr_mutex;
     #endif

+ 4 - 4
py/mpthread.h

@@ -30,17 +30,17 @@
 
 #if MICROPY_PY_THREAD
 
+struct _mp_state_thread_t;
+
 #ifdef MICROPY_MPTHREADPORT_H
 #include MICROPY_MPTHREADPORT_H
 #else
 #include <mpthreadport.h>
 #endif
 
-struct _mp_state_thread_t;
-
 struct _mp_state_thread_t *mp_thread_get_state(void);
-void mp_thread_set_state(void *state);
-void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size);
+void mp_thread_set_state(struct _mp_state_thread_t *state);
+void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size);
 void mp_thread_start(void);
 void mp_thread_finish(void);
 void mp_thread_mutex_init(mp_thread_mutex_t *mutex);

+ 73 - 50
py/mpz.c

@@ -60,13 +60,21 @@ STATIC size_t mpn_remove_trailing_zeros(mpz_dig_t *oidig, mpz_dig_t *idig) {
    assumes i, j are normalised
 */
 STATIC int mpn_cmp(const mpz_dig_t *idig, size_t ilen, const mpz_dig_t *jdig, size_t jlen) {
-    if (ilen < jlen) { return -1; }
-    if (ilen > jlen) { return 1; }
+    if (ilen < jlen) {
+        return -1;
+    }
+    if (ilen > jlen) {
+        return 1;
+    }
 
     for (idig += ilen, jdig += ilen; ilen > 0; --ilen) {
         mpz_dbl_dig_signed_t cmp = (mpz_dbl_dig_t)*(--idig) - (mpz_dbl_dig_t)*(--jdig);
-        if (cmp < 0) { return -1; }
-        if (cmp > 0) { return 1; }
+        if (cmp < 0) {
+            return -1;
+        }
+        if (cmp > 0) {
+            return 1;
+        }
     }
 
     return 0;
@@ -228,7 +236,7 @@ STATIC size_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, const mpz_dig_t *k
    can have i, j, k pointing to same memory
 */
 STATIC size_t mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
-                            mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
+    mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
     mpz_dig_t *oidig = idig;
     mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;
     mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
@@ -289,7 +297,7 @@ STATIC size_t mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const
 #if MICROPY_OPT_MPZ_BITWISE
 
 STATIC size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
-                            mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
+    mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
     mpz_dig_t *oidig = idig;
     mpz_dbl_dig_t carryi = 1;
     mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
@@ -319,7 +327,7 @@ STATIC size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, co
 #else
 
 STATIC size_t mpn_or_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
-                            mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
+    mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
     mpz_dig_t *oidig = idig;
     mpz_dig_t imask = (0 == carryi) ? 0 : DIG_MASK;
     mpz_dig_t jmask = (0 == carryj) ? 0 : DIG_MASK;
@@ -378,7 +386,7 @@ STATIC size_t mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const
    can have i, j, k pointing to same memory
 */
 STATIC size_t mpn_xor_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, size_t jlen, const mpz_dig_t *kdig, size_t klen,
-                              mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
+    mpz_dbl_dig_t carryi, mpz_dbl_dig_t carryj, mpz_dbl_dig_t carryk) {
     mpz_dig_t *oidig = idig;
 
     for (; jlen > 0; ++idig, ++jdig) {
@@ -771,20 +779,7 @@ void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
 
 #if MICROPY_PY_BUILTINS_FLOAT
 void mpz_set_from_float(mpz_t *z, mp_float_t src) {
-#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
-typedef uint64_t mp_float_int_t;
-#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
-typedef uint32_t mp_float_int_t;
-#endif
-    union {
-        mp_float_t f;
-        #if MP_ENDIANNESS_LITTLE
-        struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p;
-        #else
-        struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p;
-        #endif
-    } u = {src};
-
+    mp_float_union_t u = {src};
     z->neg = u.p.sgn;
     if (u.p.exp == 0) {
         // value == 0 || value < 1
@@ -806,7 +801,7 @@ typedef uint32_t mp_float_int_t;
             const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE;
             const unsigned int rem = adj_exp % DIG_SIZE;
             int dig_ind, shft;
-            mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << MP_FLOAT_FRAC_BITS);
+            mp_float_uint_t frc = u.p.frc | ((mp_float_uint_t)1 << MP_FLOAT_FRAC_BITS);
 
             if (adj_exp < MP_FLOAT_FRAC_BITS) {
                 shft = 0;
@@ -825,16 +820,16 @@ typedef uint32_t mp_float_int_t;
                 z->dig[dig_ind++] = (frc << shft) & DIG_MASK;
                 frc >>= DIG_SIZE - shft;
             }
-#if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1)
+            #if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1)
             while (dig_ind != dig_cnt) {
                 z->dig[dig_ind++] = frc & DIG_MASK;
                 frc >>= DIG_SIZE;
             }
-#else
+            #else
             if (dig_ind != dig_cnt) {
                 z->dig[dig_ind] = frc;
             }
-#endif
+            #endif
         }
     }
 }
@@ -857,7 +852,7 @@ size_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigne
 
     z->len = 0;
     for (; cur < top; ++cur) { // XXX UTF8 next char
-        //mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char
+        // mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char
         mp_uint_t v = *cur;
         if ('0' <= v && v <= '9') {
             v -= '0';
@@ -948,28 +943,48 @@ int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
 mp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
     mp_int_t cmp;
     if (z->neg == 0) {
-        if (sml_int < 0) return 1;
+        if (sml_int < 0) {
+            return 1;
+        }
         if (sml_int == 0) {
-            if (z->len == 0) return 0;
+            if (z->len == 0) {
+                return 0;
+            }
             return 1;
         }
-        if (z->len == 0) return -1;
+        if (z->len == 0) {
+            return -1;
+        }
         assert(sml_int < (1 << DIG_SIZE));
-        if (z->len != 1) return 1;
+        if (z->len != 1) {
+            return 1;
+        }
         cmp = z->dig[0] - sml_int;
     } else {
-        if (sml_int > 0) return -1;
+        if (sml_int > 0) {
+            return -1;
+        }
         if (sml_int == 0) {
-            if (z->len == 0) return 0;
+            if (z->len == 0) {
+                return 0;
+            }
             return -1;
         }
-        if (z->len == 0) return 1;
+        if (z->len == 0) {
+            return 1;
+        }
         assert(sml_int > -(1 << DIG_SIZE));
-        if (z->len != 1) return -1;
+        if (z->len != 1) {
+            return -1;
+        }
         cmp = -z->dig[0] - sml_int;
     }
-    if (cmp < 0) return -1;
-    if (cmp > 0) return 1;
+    if (cmp < 0) {
+        return -1;
+    }
+    if (cmp > 0) {
+        return 1;
+    }
     return 0;
 }
 #endif
@@ -1207,7 +1222,7 @@ void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
     } else {
         mpz_need_dig(dest, lhs->len + 1);
         dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
-                                 lhs->neg == rhs->neg, 0 != lhs->neg, 0 != rhs->neg);
+            lhs->neg == rhs->neg, 0 != lhs->neg, 0 != rhs->neg);
         dest->neg = lhs->neg & rhs->neg;
     }
 
@@ -1215,7 +1230,7 @@ void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
 
     mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
     dest->len = mpn_and_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
-                             (lhs->neg == rhs->neg) ? lhs->neg : 0, lhs->neg, rhs->neg);
+        (lhs->neg == rhs->neg) ? lhs->neg : 0, lhs->neg, rhs->neg);
     dest->neg = lhs->neg & rhs->neg;
 
     #endif
@@ -1241,7 +1256,7 @@ void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
     } else {
         mpz_need_dig(dest, lhs->len + 1);
         dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
-                                 0 != lhs->neg, 0 != rhs->neg);
+            0 != lhs->neg, 0 != rhs->neg);
         dest->neg = 1;
     }
 
@@ -1249,7 +1264,7 @@ void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
 
     mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
     dest->len = mpn_or_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
-                             (lhs->neg || rhs->neg), lhs->neg, rhs->neg);
+        (lhs->neg || rhs->neg), lhs->neg, rhs->neg);
     dest->neg = lhs->neg | rhs->neg;
 
     #endif
@@ -1279,7 +1294,7 @@ void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
     } else {
         mpz_need_dig(dest, lhs->len + 1);
         dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len, 1,
-                                0 == lhs->neg, 0 == rhs->neg);
+            0 == lhs->neg, 0 == rhs->neg);
         dest->neg = 1;
     }
 
@@ -1287,7 +1302,7 @@ void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
 
     mpz_need_dig(dest, lhs->len + (lhs->neg || rhs->neg));
     dest->len = mpn_xor_neg(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len,
-                             (lhs->neg != rhs->neg), 0 == lhs->neg, 0 == rhs->neg);
+        (lhs->neg != rhs->neg), 0 == lhs->neg, 0 == rhs->neg);
     dest->neg = lhs->neg ^ rhs->neg;
 
     #endif
@@ -1376,7 +1391,8 @@ void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t
 
     mpz_t *x = mpz_clone(lhs);
     mpz_t *n = mpz_clone(rhs);
-    mpz_t quo; mpz_init_zero(&quo);
+    mpz_t quo;
+    mpz_init_zero(&quo);
 
     while (n->len > 0) {
         if ((n->dig[0] & 1) != 0) {
@@ -1419,7 +1435,8 @@ mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
 
     mpz_t *a = mpz_clone(z1);
     mpz_t *b = mpz_clone(z2);
-    mpz_t c; mpz_init_zero(&c);
+    mpz_t c;
+    mpz_init_zero(&c);
     a->neg = 0;
     b->neg = 0;
 
@@ -1430,7 +1447,9 @@ mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
                 mpz_deinit(&c);
                 return b;
             }
-            mpz_t *t = a; a = b; b = t;
+            mpz_t *t = a;
+            a = b;
+            b = t;
         }
         if (!(b->len >= 2 || (b->len == 1 && b->dig[0] > 1))) { // compute b > 0; could be mpz_cmp_small_int(b, 1) > 0
             break;
@@ -1497,7 +1516,8 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m
     if (lhs->neg != rhs->neg) {
         dest_quo->neg = 1;
         if (!mpz_is_zero(dest_rem)) {
-            mpz_t mpzone; mpz_init_from_int(&mpzone, -1);
+            mpz_t mpzone;
+            mpz_init_from_int(&mpzone, -1);
             mpz_add_inpl(dest_quo, dest_quo, &mpzone);
             mpz_add_inpl(dest_rem, dest_rem, rhs);
         }
@@ -1512,7 +1532,8 @@ these functions are unused
 */
 mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {
     mpz_t *quo = mpz_zero();
-    mpz_t rem; mpz_init_zero(&rem);
+    mpz_t rem;
+    mpz_init_zero(&rem);
     mpz_divmod_inpl(quo, &rem, lhs, rhs);
     mpz_deinit(&rem);
     return quo;
@@ -1522,7 +1543,8 @@ mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs) {
    can have lhs, rhs the same
 */
 mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
-    mpz_t quo; mpz_init_zero(&quo);
+    mpz_t quo;
+    mpz_init_zero(&quo);
     mpz_t *rem = mpz_zero();
     mpz_divmod_inpl(&quo, rem, lhs, rhs);
     mpz_deinit(&quo);
@@ -1659,8 +1681,9 @@ size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, ch
     char *s = str;
     if (ilen == 0) {
         if (prefix) {
-            while (*prefix)
+            while (*prefix) {
                 *s++ = *prefix++;
+            }
         }
         *s++ = '0';
         *s = '\0';

+ 13 - 7
py/mpz.h

@@ -46,10 +46,10 @@
 
 #ifndef MPZ_DIG_SIZE
   #if defined(__x86_64__) || defined(_WIN64)
-    // 64-bit machine, using 32-bit storage for digits
+// 64-bit machine, using 32-bit storage for digits
     #define MPZ_DIG_SIZE (32)
   #else
-    // default: 32-bit machine, using 16-bit storage for digits
+// default: 32-bit machine, using 16-bit storage for digits
     #define MPZ_DIG_SIZE (16)
   #endif
 #endif
@@ -93,13 +93,13 @@ typedef int8_t mpz_dbl_dig_signed_t;
 typedef struct _mpz_t {
     size_t neg : 1;
     size_t fixed_dig : 1;
-    size_t alloc : 8 * sizeof(size_t) - 2;
+    size_t alloc : (8 * sizeof(size_t) - 2);
     size_t len;
     mpz_dig_t *dig;
 } mpz_t;
 
 // convenience macro to declare an mpz with a digit array from the stack, initialised by an integer
-#define MPZ_CONST_INT(z, val) mpz_t z; mpz_dig_t z ## _digits[MPZ_NUM_DIG_FOR_INT]; mpz_init_fixed_from_int(&z, z_digits, MPZ_NUM_DIG_FOR_INT, val);
+#define MPZ_CONST_INT(z, val) mpz_t z; mpz_dig_t z##_digits[MPZ_NUM_DIG_FOR_INT]; mpz_init_fixed_from_int(&z, z_digits, MPZ_NUM_DIG_FOR_INT, val);
 
 void mpz_init_zero(mpz_t *z);
 void mpz_init_from_int(mpz_t *z, mp_int_t val);
@@ -115,8 +115,12 @@ void mpz_set_from_float(mpz_t *z, mp_float_t src);
 size_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigned int base);
 void mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf);
 
-static inline bool mpz_is_zero(const mpz_t *z) { return z->len == 0; }
-static inline bool mpz_is_neg(const mpz_t *z) { return z->len != 0 && z->neg != 0; }
+static inline bool mpz_is_zero(const mpz_t *z) {
+    return z->len == 0;
+}
+static inline bool mpz_is_neg(const mpz_t *z) {
+    return z->len != 0 && z->neg != 0;
+}
 int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs);
 
 void mpz_abs_inpl(mpz_t *dest, const mpz_t *z);
@@ -134,7 +138,9 @@ void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
 void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
 void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs);
 
-static inline size_t mpz_max_num_bits(const mpz_t *z) { return z->len * MPZ_DIG_SIZE; }
+static inline size_t mpz_max_num_bits(const mpz_t *z) {
+    return z->len * MPZ_DIG_SIZE;
+}
 mp_int_t mpz_hash(const mpz_t *z);
 bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value);
 bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value);

+ 44 - 46
py/nativeglue.c

@@ -44,15 +44,24 @@
 
 int mp_native_type_from_qstr(qstr qst) {
     switch (qst) {
-        case MP_QSTR_object: return MP_NATIVE_TYPE_OBJ;
-        case MP_QSTR_bool: return MP_NATIVE_TYPE_BOOL;
-        case MP_QSTR_int: return MP_NATIVE_TYPE_INT;
-        case MP_QSTR_uint: return MP_NATIVE_TYPE_UINT;
-        case MP_QSTR_ptr: return MP_NATIVE_TYPE_PTR;
-        case MP_QSTR_ptr8: return MP_NATIVE_TYPE_PTR8;
-        case MP_QSTR_ptr16: return MP_NATIVE_TYPE_PTR16;
-        case MP_QSTR_ptr32: return MP_NATIVE_TYPE_PTR32;
-        default: return -1;
+        case MP_QSTR_object:
+            return MP_NATIVE_TYPE_OBJ;
+        case MP_QSTR_bool:
+            return MP_NATIVE_TYPE_BOOL;
+        case MP_QSTR_int:
+            return MP_NATIVE_TYPE_INT;
+        case MP_QSTR_uint:
+            return MP_NATIVE_TYPE_UINT;
+        case MP_QSTR_ptr:
+            return MP_NATIVE_TYPE_PTR;
+        case MP_QSTR_ptr8:
+            return MP_NATIVE_TYPE_PTR8;
+        case MP_QSTR_ptr16:
+            return MP_NATIVE_TYPE_PTR16;
+        case MP_QSTR_ptr32:
+            return MP_NATIVE_TYPE_PTR32;
+        default:
+            return -1;
     }
 }
 
@@ -60,10 +69,13 @@ int mp_native_type_from_qstr(qstr qst) {
 mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) {
     DEBUG_printf("mp_native_from_obj(%p, " UINT_FMT ")\n", obj, type);
     switch (type & 0xf) {
-        case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj;
-        case MP_NATIVE_TYPE_BOOL: return mp_obj_is_true(obj);
+        case MP_NATIVE_TYPE_OBJ:
+            return (mp_uint_t)obj;
+        case MP_NATIVE_TYPE_BOOL:
+            return mp_obj_is_true(obj);
         case MP_NATIVE_TYPE_INT:
-        case MP_NATIVE_TYPE_UINT: return mp_obj_get_int_truncated(obj);
+        case MP_NATIVE_TYPE_UINT:
+            return mp_obj_get_int_truncated(obj);
         default: { // cast obj to a pointer
             mp_buffer_info_t bufinfo;
             if (mp_get_buffer(obj, &bufinfo, MP_BUFFER_READ)) {
@@ -84,10 +96,14 @@ mp_uint_t mp_native_from_obj(mp_obj_t obj, mp_uint_t type) {
 mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) {
     DEBUG_printf("mp_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type);
     switch (type & 0xf) {
-        case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val;
-        case MP_NATIVE_TYPE_BOOL: return mp_obj_new_bool(val);
-        case MP_NATIVE_TYPE_INT: return mp_obj_new_int(val);
-        case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val);
+        case MP_NATIVE_TYPE_OBJ:
+            return (mp_obj_t)val;
+        case MP_NATIVE_TYPE_BOOL:
+            return mp_obj_new_bool(val);
+        case MP_NATIVE_TYPE_INT:
+            return mp_obj_new_int(val);
+        case MP_NATIVE_TYPE_UINT:
+            return mp_obj_new_int_from_uint(val);
         default: // a pointer
             // we return just the value of the pointer as an integer
             return mp_obj_new_int_from_uint(val);
@@ -102,13 +118,13 @@ mp_obj_t mp_native_to_obj(mp_uint_t val, mp_uint_t type) {
 mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items) {
     (void)n_args;
     (void)items;
-    mp_raise_msg(&mp_type_RuntimeError, "set unsupported");
+    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("set unsupported"));
 }
 
 void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) {
     (void)self_in;
     (void)item;
-    mp_raise_msg(&mp_type_RuntimeError, "set unsupported");
+    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("set unsupported"));
 }
 #endif
 
@@ -117,7 +133,7 @@ mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) {
     (void)ostart;
     (void)ostop;
     (void)ostep;
-    mp_raise_msg(&mp_type_RuntimeError, "slice unsupported");
+    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("slice unsupported"));
 }
 #endif
 
@@ -211,53 +227,35 @@ STATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *re
     return false;
 }
 
-#if MICROPY_PY_BUILTINS_FLOAT
-
-STATIC mp_obj_t mp_obj_new_float_from_f(float f) {
-    return mp_obj_new_float((mp_float_t)f);
-}
-
-STATIC mp_obj_t mp_obj_new_float_from_d(double d) {
-    return mp_obj_new_float((mp_float_t)d);
-}
-
-STATIC float mp_obj_get_float_to_f(mp_obj_t o) {
-    return (float)mp_obj_get_float(o);
-}
-
-STATIC double mp_obj_get_float_to_d(mp_obj_t o) {
-    return (double)mp_obj_get_float(o);
-}
-
-#else
+#if !MICROPY_PY_BUILTINS_FLOAT
 
 STATIC mp_obj_t mp_obj_new_float_from_f(float f) {
     (void)f;
-    mp_raise_msg(&mp_type_RuntimeError, "float unsupported");
+    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("float unsupported"));
 }
 
 STATIC mp_obj_t mp_obj_new_float_from_d(double d) {
     (void)d;
-    mp_raise_msg(&mp_type_RuntimeError, "float unsupported");
+    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("float unsupported"));
 }
 
 STATIC float mp_obj_get_float_to_f(mp_obj_t o) {
     (void)o;
-    mp_raise_msg(&mp_type_RuntimeError, "float unsupported");
+    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("float unsupported"));
 }
 
 STATIC double mp_obj_get_float_to_d(mp_obj_t o) {
     (void)o;
-    mp_raise_msg(&mp_type_RuntimeError, "float unsupported");
+    mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("float unsupported"));
 }
 
 #endif
 
-// these must correspond to the respective enum in runtime0.h
+// these must correspond to the respective enum in nativeglue.h
 const mp_fun_table_t mp_fun_table = {
-    &mp_const_none_obj,
-    &mp_const_false_obj,
-    &mp_const_true_obj,
+    mp_const_none,
+    mp_const_false,
+    mp_const_true,
     mp_native_from_obj,
     mp_native_to_obj,
     mp_native_swap_globals,

+ 6 - 6
py/nativeglue.h

@@ -91,7 +91,7 @@ typedef struct _mp_fun_table_t {
     mp_const_obj_t const_true;
     mp_uint_t (*native_from_obj)(mp_obj_t obj, mp_uint_t type);
     mp_obj_t (*native_to_obj)(mp_uint_t val, mp_uint_t type);
-    mp_obj_dict_t *(*swap_globals)(mp_obj_dict_t *new_globals);
+    mp_obj_dict_t *(*swap_globals)(mp_obj_dict_t * new_globals);
     mp_obj_t (*load_name)(qstr qst);
     mp_obj_t (*load_global)(qstr qst);
     mp_obj_t (*load_build_class)(void);
@@ -135,7 +135,7 @@ typedef struct _mp_fun_table_t {
     mp_int_t (*small_int_floor_divide)(mp_int_t num, mp_int_t denom);
     mp_int_t (*small_int_modulo)(mp_int_t dividend, mp_int_t divisor);
     bool (*yield_from)(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *ret_value);
-    void *setjmp;
+    void *setjmp_;
     // Additional entries for dynamic runtime, starts at index 50
     void *(*memset_)(void *s, int c, size_t n);
     void *(*memmove_)(void *dest, const void *src, size_t n);
@@ -145,10 +145,10 @@ typedef struct _mp_fun_table_t {
     #if defined(__GNUC__)
     NORETURN // Only certain compilers support no-return attributes in function pointer declarations
     #endif
-    void (*raise_msg)(const mp_obj_type_t *exc_type, const char *msg);
-    mp_obj_type_t *(*obj_get_type)(mp_const_obj_t o_in);
-    mp_obj_t (*obj_new_str)(const char* data, size_t len);
-    mp_obj_t (*obj_new_bytes)(const byte* data, size_t len);
+    void (*raise_msg)(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg);
+    const mp_obj_type_t *(*obj_get_type)(mp_const_obj_t o_in);
+    mp_obj_t (*obj_new_str)(const char *data, size_t len);
+    mp_obj_t (*obj_new_bytes)(const byte *data, size_t len);
     mp_obj_t (*obj_new_bytearray_by_ref)(size_t n, void *items);
     mp_obj_t (*obj_new_float_from_f)(float f);
     mp_obj_t (*obj_new_float_from_d)(double d);

+ 1 - 1
py/nlr.c

@@ -30,7 +30,7 @@
 // When not using setjmp, nlr_push_tail is called from inline asm so needs special care
 #if MICROPY_NLR_X86 && MICROPY_NLR_OS_WINDOWS
 // On these 32-bit platforms make sure nlr_push_tail doesn't have a leading underscore
-unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail");
+unsigned int nlr_push_tail(nlr_buf_t *nlr) asm ("nlr_push_tail");
 #else
 // LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as used
 __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);

+ 4 - 0
py/nlr.h

@@ -42,6 +42,8 @@
 #define MICROPY_NLR_NUM_REGS_XTENSA         (10)
 #define MICROPY_NLR_NUM_REGS_XTENSAWIN      (17)
 
+// *FORMAT-OFF*
+
 // If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch
 #if !MICROPY_NLR_SETJMP
 // A lot of nlr-related things need different treatment on Windows
@@ -83,6 +85,8 @@
 #endif
 #endif
 
+// *FORMAT-ON*
+
 #if MICROPY_NLR_SETJMP
 #include <setjmp.h>
 #endif

+ 72 - 72
py/nlrpowerpc.c

@@ -34,44 +34,44 @@
 
 unsigned int nlr_push(nlr_buf_t *nlr) {
 
-    __asm__ volatile(
-    "li     4, 0x4eed ; "      // Store canary
-    "std    4,  0x00(%0) ;"
-    "std    0,  0x08(%0) ;"
-    "std    1,  0x10(%0) ;"
-    "std    2,  0x18(%0) ;"
-    "std    14, 0x20(%0) ;"
-    "std    15, 0x28(%0) ;"
-    "std    16, 0x30(%0) ;"
-    "std    17, 0x38(%0) ;"
-    "std    18, 0x40(%0) ;"
-    "std    19, 0x48(%0) ;"
-    "std    20, 0x50(%0) ;"
-    "std    21, 0x58(%0) ;"
-    "std    22, 0x60(%0) ;"
-    "std    23, 0x68(%0) ;"
-    "std    24, 0x70(%0) ;"
-    "std    25, 0x78(%0) ;"
-    "std    26, 0x80(%0) ;"
-    "std    27, 0x88(%0) ;"
-    "std    28, 0x90(%0) ;"
-    "std    29, 0x98(%0) ;"
-    "std    30, 0xA0(%0) ;"
-    "std    31, 0xA8(%0) ;"
+    __asm__ volatile (
+        "li     4, 0x4eed ; "  // Store canary
+        "std    4,  0x00(%0) ;"
+        "std    0,  0x08(%0) ;"
+        "std    1,  0x10(%0) ;"
+        "std    2,  0x18(%0) ;"
+        "std    14, 0x20(%0) ;"
+        "std    15, 0x28(%0) ;"
+        "std    16, 0x30(%0) ;"
+        "std    17, 0x38(%0) ;"
+        "std    18, 0x40(%0) ;"
+        "std    19, 0x48(%0) ;"
+        "std    20, 0x50(%0) ;"
+        "std    21, 0x58(%0) ;"
+        "std    22, 0x60(%0) ;"
+        "std    23, 0x68(%0) ;"
+        "std    24, 0x70(%0) ;"
+        "std    25, 0x78(%0) ;"
+        "std    26, 0x80(%0) ;"
+        "std    27, 0x88(%0) ;"
+        "std    28, 0x90(%0) ;"
+        "std    29, 0x98(%0) ;"
+        "std    30, 0xA0(%0) ;"
+        "std    31, 0xA8(%0) ;"
 
-    "mfcr   4 ; "
-    "std    4, 0xB0(%0) ;"
-    "mflr   4 ;"
-    "std    4, 0xB8(%0) ;"
-    "li     4, nlr_push_tail@l ;"
-    "oris   4, 4, nlr_push_tail@h ;"
-    "mtctr  4 ;"
-    "mr    3, %1 ; "
-    "bctr  ;"
-    :
-    : "r"(&nlr->regs), "r"(nlr)
-    :
-    );
+        "mfcr   4 ; "
+        "std    4, 0xB0(%0) ;"
+        "mflr   4 ;"
+        "std    4, 0xB8(%0) ;"
+        "li     4, nlr_push_tail@l ;"
+        "oris   4, 4, nlr_push_tail@h ;"
+        "mtctr  4 ;"
+        "mr    3, %1 ; "
+        "bctr  ;"
+        :
+        : "r" (&nlr->regs), "r" (nlr)
+        :
+        );
 
     return 0;
 }
@@ -79,41 +79,41 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
 NORETURN void nlr_jump(void *val) {
     MP_NLR_JUMP_HEAD(val, top)
 
-    __asm__ volatile(
-    "ld    3, 0x0(%0) ;"
-    "cmpdi 3, 0x4eed ; " // Check canary
-    "bne   . ; "
-    "ld    0,  0x08(%0) ;"
-    "ld    1,  0x10(%0) ;"
-    "ld    2,  0x18(%0) ;"
-    "ld    14, 0x20(%0) ;"
-    "ld    15, 0x28(%0) ;"
-    "ld    16, 0x30(%0) ;"
-    "ld    17, 0x38(%0) ;"
-    "ld    18, 0x40(%0) ;"
-    "ld    19, 0x48(%0) ;"
-    "ld    20, 0x50(%0) ;"
-    "ld    21, 0x58(%0) ;"
-    "ld    22, 0x60(%0) ;"
-    "ld    23, 0x68(%0) ;"
-    "ld    24, 0x70(%0) ;"
-    "ld    25, 0x78(%0) ;"
-    "ld    26, 0x80(%0) ;"
-    "ld    27, 0x88(%0) ;"
-    "ld    28, 0x90(%0) ;"
-    "ld    29, 0x98(%0) ;"
-    "ld    30, 0xA0(%0) ;"
-    "ld    31, 0xA8(%0) ;"
-    "ld    3,  0xB0(%0) ;"
-    "mtcr  3 ;"
-    "ld    3, 0xB8(%0) ;"
-    "mtlr  3 ; "
-    "li    3, 1;"
-    "blr ;"
-    :
-    : "r"(&top->regs)
-    :
-    );
+    __asm__ volatile (
+        "ld    3, 0x0(%0) ;"
+        "cmpdi 3, 0x4eed ; " // Check canary
+        "bne   . ; "
+        "ld    0,  0x08(%0) ;"
+        "ld    1,  0x10(%0) ;"
+        "ld    2,  0x18(%0) ;"
+        "ld    14, 0x20(%0) ;"
+        "ld    15, 0x28(%0) ;"
+        "ld    16, 0x30(%0) ;"
+        "ld    17, 0x38(%0) ;"
+        "ld    18, 0x40(%0) ;"
+        "ld    19, 0x48(%0) ;"
+        "ld    20, 0x50(%0) ;"
+        "ld    21, 0x58(%0) ;"
+        "ld    22, 0x60(%0) ;"
+        "ld    23, 0x68(%0) ;"
+        "ld    24, 0x70(%0) ;"
+        "ld    25, 0x78(%0) ;"
+        "ld    26, 0x80(%0) ;"
+        "ld    27, 0x88(%0) ;"
+        "ld    28, 0x90(%0) ;"
+        "ld    29, 0x98(%0) ;"
+        "ld    30, 0xA0(%0) ;"
+        "ld    31, 0xA8(%0) ;"
+        "ld    3,  0xB0(%0) ;"
+        "mtcr  3 ;"
+        "ld    3, 0xB8(%0) ;"
+        "mtlr  3 ; "
+        "li    3, 1;"
+        "blr ;"
+        :
+        : "r" (&top->regs)
+        :
+        );
 
     MP_UNREACHABLE;
 }

+ 80 - 80
py/nlrthumb.c

@@ -39,51 +39,51 @@
 __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
 
     __asm volatile (
-    "str    r4, [r0, #12]       \n" // store r4 into nlr_buf
-    "str    r5, [r0, #16]       \n" // store r5 into nlr_buf
-    "str    r6, [r0, #20]       \n" // store r6 into nlr_buf
-    "str    r7, [r0, #24]       \n" // store r7 into nlr_buf
+        "str    r4, [r0, #12]       \n" // store r4 into nlr_buf
+        "str    r5, [r0, #16]       \n" // store r5 into nlr_buf
+        "str    r6, [r0, #20]       \n" // store r6 into nlr_buf
+        "str    r7, [r0, #24]       \n" // store r7 into nlr_buf
 
-#if !defined(__thumb2__)
-    "mov    r1, r8              \n"
-    "str    r1, [r0, #28]       \n" // store r8 into nlr_buf
-    "mov    r1, r9              \n"
-    "str    r1, [r0, #32]       \n" // store r9 into nlr_buf
-    "mov    r1, r10             \n"
-    "str    r1, [r0, #36]       \n" // store r10 into nlr_buf
-    "mov    r1, r11             \n"
-    "str    r1, [r0, #40]       \n" // store r11 into nlr_buf
-    "mov    r1, r13             \n"
-    "str    r1, [r0, #44]       \n" // store r13=sp into nlr_buf
-    "mov    r1, lr              \n"
-    "str    r1, [r0, #8]        \n" // store lr into nlr_buf
-#else
-    "str    r8, [r0, #28]       \n" // store r8 into nlr_buf
-    "str    r9, [r0, #32]       \n" // store r9 into nlr_buf
-    "str    r10, [r0, #36]      \n" // store r10 into nlr_buf
-    "str    r11, [r0, #40]      \n" // store r11 into nlr_buf
-    "str    r13, [r0, #44]      \n" // store r13=sp into nlr_buf
-    #if MICROPY_NLR_NUM_REGS == 16
-    "vstr   d8, [r0, #48]       \n" // store s16-s17 into nlr_buf
-    "vstr   d9, [r0, #56]       \n" // store s18-s19 into nlr_buf
-    "vstr   d10, [r0, #64]      \n" // store s20-s21 into nlr_buf
-    #endif
-    "str    lr, [r0, #8]        \n" // store lr into nlr_buf
-#endif
+        #if !defined(__thumb2__)
+        "mov    r1, r8              \n"
+        "str    r1, [r0, #28]       \n" // store r8 into nlr_buf
+        "mov    r1, r9              \n"
+        "str    r1, [r0, #32]       \n" // store r9 into nlr_buf
+        "mov    r1, r10             \n"
+        "str    r1, [r0, #36]       \n" // store r10 into nlr_buf
+        "mov    r1, r11             \n"
+        "str    r1, [r0, #40]       \n" // store r11 into nlr_buf
+        "mov    r1, r13             \n"
+        "str    r1, [r0, #44]       \n" // store r13=sp into nlr_buf
+        "mov    r1, lr              \n"
+        "str    r1, [r0, #8]        \n" // store lr into nlr_buf
+        #else
+        "str    r8, [r0, #28]       \n" // store r8 into nlr_buf
+        "str    r9, [r0, #32]       \n" // store r9 into nlr_buf
+        "str    r10, [r0, #36]      \n" // store r10 into nlr_buf
+        "str    r11, [r0, #40]      \n" // store r11 into nlr_buf
+        "str    r13, [r0, #44]      \n" // store r13=sp into nlr_buf
+        #if MICROPY_NLR_NUM_REGS == 16
+        "vstr   d8, [r0, #48]       \n" // store s16-s17 into nlr_buf
+        "vstr   d9, [r0, #56]       \n" // store s18-s19 into nlr_buf
+        "vstr   d10, [r0, #64]      \n" // store s20-s21 into nlr_buf
+        #endif
+        "str    lr, [r0, #8]        \n" // store lr into nlr_buf
+        #endif
 
-#if !defined(__thumb2__)
-    "ldr    r1, nlr_push_tail_var \n"
-    "bx     r1                  \n" // do the rest in C
-    ".align 2                   \n"
-    "nlr_push_tail_var: .word nlr_push_tail \n"
-#else
-    #if defined(__APPLE__) || defined(__MACH__)
-    "b      _nlr_push_tail      \n" // do the rest in C
-    #else
-    "b      nlr_push_tail       \n" // do the rest in C
-    #endif
-#endif
-    );
+        #if !defined(__thumb2__)
+        "ldr    r1, nlr_push_tail_var \n"
+        "bx     r1                  \n" // do the rest in C
+        ".align 2                   \n"
+        "nlr_push_tail_var: .word nlr_push_tail \n"
+        #else
+        #if defined(__APPLE__) || defined(__MACH__)
+        "b      _nlr_push_tail      \n" // do the rest in C
+        #else
+        "b      nlr_push_tail       \n" // do the rest in C
+        #endif
+        #endif
+        );
 
     #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
     // Older versions of gcc give an error when naked functions don't return a value
@@ -96,44 +96,44 @@ NORETURN void nlr_jump(void *val) {
     MP_NLR_JUMP_HEAD(val, top)
 
     __asm volatile (
-    "mov    r0, %0              \n" // r0 points to nlr_buf
-    "ldr    r4, [r0, #12]       \n" // load r4 from nlr_buf
-    "ldr    r5, [r0, #16]       \n" // load r5 from nlr_buf
-    "ldr    r6, [r0, #20]       \n" // load r6 from nlr_buf
-    "ldr    r7, [r0, #24]       \n" // load r7 from nlr_buf
+        "mov    r0, %0              \n" // r0 points to nlr_buf
+        "ldr    r4, [r0, #12]       \n" // load r4 from nlr_buf
+        "ldr    r5, [r0, #16]       \n" // load r5 from nlr_buf
+        "ldr    r6, [r0, #20]       \n" // load r6 from nlr_buf
+        "ldr    r7, [r0, #24]       \n" // load r7 from nlr_buf
 
-#if !defined(__thumb2__)
-    "ldr    r1, [r0, #28]       \n" // load r8 from nlr_buf
-    "mov    r8, r1              \n"
-    "ldr    r1, [r0, #32]       \n" // load r9 from nlr_buf
-    "mov    r9, r1              \n"
-    "ldr    r1, [r0, #36]       \n" // load r10 from nlr_buf
-    "mov    r10, r1             \n"
-    "ldr    r1, [r0, #40]       \n" // load r11 from nlr_buf
-    "mov    r11, r1             \n"
-    "ldr    r1, [r0, #44]       \n" // load r13=sp from nlr_buf
-    "mov    r13, r1             \n"
-    "ldr    r1, [r0, #8]        \n" // load lr from nlr_buf
-    "mov    lr, r1              \n"
-#else
-    "ldr    r8, [r0, #28]       \n" // load r8 from nlr_buf
-    "ldr    r9, [r0, #32]       \n" // load r9 from nlr_buf
-    "ldr    r10, [r0, #36]      \n" // load r10 from nlr_buf
-    "ldr    r11, [r0, #40]      \n" // load r11 from nlr_buf
-    "ldr    r13, [r0, #44]      \n" // load r13=sp from nlr_buf
-    #if MICROPY_NLR_NUM_REGS == 16
-    "vldr   d8, [r0, #48]       \n" // load s16-s17 from nlr_buf
-    "vldr   d9, [r0, #56]       \n" // load s18-s19 from nlr_buf
-    "vldr   d10, [r0, #64]      \n" // load s20-s21 from nlr_buf
-    #endif
-    "ldr    lr, [r0, #8]        \n" // load lr from nlr_buf
-#endif
-    "movs   r0, #1              \n" // return 1, non-local return
-    "bx     lr                  \n" // return
-    :                               // output operands
-    : "r"(top)                      // input operands
-    :                               // clobbered registers
-    );
+        #if !defined(__thumb2__)
+        "ldr    r1, [r0, #28]       \n" // load r8 from nlr_buf
+        "mov    r8, r1              \n"
+        "ldr    r1, [r0, #32]       \n" // load r9 from nlr_buf
+        "mov    r9, r1              \n"
+        "ldr    r1, [r0, #36]       \n" // load r10 from nlr_buf
+        "mov    r10, r1             \n"
+        "ldr    r1, [r0, #40]       \n" // load r11 from nlr_buf
+        "mov    r11, r1             \n"
+        "ldr    r1, [r0, #44]       \n" // load r13=sp from nlr_buf
+        "mov    r13, r1             \n"
+        "ldr    r1, [r0, #8]        \n" // load lr from nlr_buf
+        "mov    lr, r1              \n"
+        #else
+        "ldr    r8, [r0, #28]       \n" // load r8 from nlr_buf
+        "ldr    r9, [r0, #32]       \n" // load r9 from nlr_buf
+        "ldr    r10, [r0, #36]      \n" // load r10 from nlr_buf
+        "ldr    r11, [r0, #40]      \n" // load r11 from nlr_buf
+        "ldr    r13, [r0, #44]      \n" // load r13=sp from nlr_buf
+        #if MICROPY_NLR_NUM_REGS == 16
+        "vldr   d8, [r0, #48]       \n" // load s16-s17 from nlr_buf
+        "vldr   d9, [r0, #56]       \n" // load s18-s19 from nlr_buf
+        "vldr   d10, [r0, #64]      \n" // load s20-s21 from nlr_buf
+        #endif
+        "ldr    lr, [r0, #8]        \n" // load lr from nlr_buf
+        #endif
+        "movs   r0, #1              \n" // return 1, non-local return
+        "bx     lr                  \n" // return
+        :                           // output operands
+        : "r" (top)                 // input operands
+        :                           // clobbered registers
+        );
 
     MP_UNREACHABLE
 }

+ 52 - 52
py/nlrx64.c

@@ -41,41 +41,41 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
     #if MICROPY_NLR_OS_WINDOWS
 
     __asm volatile (
-    "movq   (%rsp), %rax        \n" // load return %rip
-    "movq   %rax, 16(%rcx)      \n" // store %rip into nlr_buf
-    "movq   %rbp, 24(%rcx)      \n" // store %rbp into nlr_buf
-    "movq   %rsp, 32(%rcx)      \n" // store %rsp into nlr_buf
-    "movq   %rbx, 40(%rcx)      \n" // store %rbx into nlr_buf
-    "movq   %r12, 48(%rcx)      \n" // store %r12 into nlr_buf
-    "movq   %r13, 56(%rcx)      \n" // store %r13 into nlr_buf
-    "movq   %r14, 64(%rcx)      \n" // store %r14 into nlr_buf
-    "movq   %r15, 72(%rcx)      \n" // store %r15 into nlr_buf
-    "movq   %rdi, 80(%rcx)      \n" // store %rdr into nlr_buf
-    "movq   %rsi, 88(%rcx)      \n" // store %rsi into nlr_buf
-    "jmp    nlr_push_tail       \n" // do the rest in C
-    );
+        "movq   (%rsp), %rax        \n" // load return %rip
+        "movq   %rax, 16(%rcx)      \n" // store %rip into nlr_buf
+        "movq   %rbp, 24(%rcx)      \n" // store %rbp into nlr_buf
+        "movq   %rsp, 32(%rcx)      \n" // store %rsp into nlr_buf
+        "movq   %rbx, 40(%rcx)      \n" // store %rbx into nlr_buf
+        "movq   %r12, 48(%rcx)      \n" // store %r12 into nlr_buf
+        "movq   %r13, 56(%rcx)      \n" // store %r13 into nlr_buf
+        "movq   %r14, 64(%rcx)      \n" // store %r14 into nlr_buf
+        "movq   %r15, 72(%rcx)      \n" // store %r15 into nlr_buf
+        "movq   %rdi, 80(%rcx)      \n" // store %rdr into nlr_buf
+        "movq   %rsi, 88(%rcx)      \n" // store %rsi into nlr_buf
+        "jmp    nlr_push_tail       \n" // do the rest in C
+        );
 
     #else
 
     __asm volatile (
-    #if defined(__APPLE__) || defined(__MACH__)
-    "pop    %rbp                \n" // undo function's prelude
-    #endif
-    "movq   (%rsp), %rax        \n" // load return %rip
-    "movq   %rax, 16(%rdi)      \n" // store %rip into nlr_buf
-    "movq   %rbp, 24(%rdi)      \n" // store %rbp into nlr_buf
-    "movq   %rsp, 32(%rdi)      \n" // store %rsp into nlr_buf
-    "movq   %rbx, 40(%rdi)      \n" // store %rbx into nlr_buf
-    "movq   %r12, 48(%rdi)      \n" // store %r12 into nlr_buf
-    "movq   %r13, 56(%rdi)      \n" // store %r13 into nlr_buf
-    "movq   %r14, 64(%rdi)      \n" // store %r14 into nlr_buf
-    "movq   %r15, 72(%rdi)      \n" // store %r15 into nlr_buf
-    #if defined(__APPLE__) || defined(__MACH__)
-    "jmp    _nlr_push_tail      \n" // do the rest in C
-    #else
-    "jmp    nlr_push_tail       \n" // do the rest in C
-    #endif
-    );
+        #if defined(__APPLE__) || defined(__MACH__)
+        "pop    %rbp                \n" // undo function's prelude
+        #endif
+        "movq   (%rsp), %rax        \n" // load return %rip
+        "movq   %rax, 16(%rdi)      \n" // store %rip into nlr_buf
+        "movq   %rbp, 24(%rdi)      \n" // store %rbp into nlr_buf
+        "movq   %rsp, 32(%rdi)      \n" // store %rsp into nlr_buf
+        "movq   %rbx, 40(%rdi)      \n" // store %rbx into nlr_buf
+        "movq   %r12, 48(%rdi)      \n" // store %r12 into nlr_buf
+        "movq   %r13, 56(%rdi)      \n" // store %r13 into nlr_buf
+        "movq   %r14, 64(%rdi)      \n" // store %r14 into nlr_buf
+        "movq   %r15, 72(%rdi)      \n" // store %r15 into nlr_buf
+        #if defined(__APPLE__) || defined(__MACH__)
+        "jmp    _nlr_push_tail      \n" // do the rest in C
+        #else
+        "jmp    nlr_push_tail       \n" // do the rest in C
+        #endif
+        );
 
     #endif
 
@@ -86,27 +86,27 @@ NORETURN void nlr_jump(void *val) {
     MP_NLR_JUMP_HEAD(val, top)
 
     __asm volatile (
-    "movq   %0, %%rcx           \n" // %rcx points to nlr_buf
-    #if MICROPY_NLR_OS_WINDOWS
-    "movq   88(%%rcx), %%rsi    \n" // load saved %rsi
-    "movq   80(%%rcx), %%rdi    \n" // load saved %rdr
-    #endif
-    "movq   72(%%rcx), %%r15    \n" // load saved %r15
-    "movq   64(%%rcx), %%r14    \n" // load saved %r14
-    "movq   56(%%rcx), %%r13    \n" // load saved %r13
-    "movq   48(%%rcx), %%r12    \n" // load saved %r12
-    "movq   40(%%rcx), %%rbx    \n" // load saved %rbx
-    "movq   32(%%rcx), %%rsp    \n" // load saved %rsp
-    "movq   24(%%rcx), %%rbp    \n" // load saved %rbp
-    "movq   16(%%rcx), %%rax    \n" // load saved %rip
-    "movq   %%rax, (%%rsp)      \n" // store saved %rip to stack
-    "xorq   %%rax, %%rax        \n" // clear return register
-    "inc    %%al                \n" // increase to make 1, non-local return
-    "ret                        \n" // return
-    :                               // output operands
-    : "r"(top)                      // input operands
-    :                               // clobbered registers
-    );
+        "movq   %0, %%rcx           \n" // %rcx points to nlr_buf
+        #if MICROPY_NLR_OS_WINDOWS
+        "movq   88(%%rcx), %%rsi    \n" // load saved %rsi
+        "movq   80(%%rcx), %%rdi    \n" // load saved %rdr
+        #endif
+        "movq   72(%%rcx), %%r15    \n" // load saved %r15
+        "movq   64(%%rcx), %%r14    \n" // load saved %r14
+        "movq   56(%%rcx), %%r13    \n" // load saved %r13
+        "movq   48(%%rcx), %%r12    \n" // load saved %r12
+        "movq   40(%%rcx), %%rbx    \n" // load saved %rbx
+        "movq   32(%%rcx), %%rsp    \n" // load saved %rsp
+        "movq   24(%%rcx), %%rbp    \n" // load saved %rbp
+        "movq   16(%%rcx), %%rax    \n" // load saved %rip
+        "movq   %%rax, (%%rsp)      \n" // store saved %rip to stack
+        "xorq   %%rax, %%rax        \n" // clear return register
+        "inc    %%al                \n" // increase to make 1, non-local return
+        "ret                        \n" // return
+        :                           // output operands
+        : "r" (top)                 // input operands
+        :                           // clobbered registers
+        );
 
     MP_UNREACHABLE
 }

+ 29 - 31
py/nlrx86.c

@@ -34,7 +34,7 @@
 //  ebx, esi, edi, ebp, esp, eip
 
 #if MICROPY_NLR_OS_WINDOWS
-unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail");
+unsigned int nlr_push_tail(nlr_buf_t *nlr) asm ("nlr_push_tail");
 #else
 __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);
 #endif
@@ -56,24 +56,22 @@ __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);
 __attribute__((naked))
 #endif
 unsigned int nlr_push(nlr_buf_t *nlr) {
-    #if !USE_NAKED
     (void)nlr;
-    #endif
 
     __asm volatile (
-    #if UNDO_PRELUDE
-    "pop    %ebp                \n" // undo function's prelude
-    #endif
-    "mov    4(%esp), %edx       \n" // load nlr_buf
-    "mov    (%esp), %eax        \n" // load return %eip
-    "mov    %eax, 8(%edx)       \n" // store %eip into nlr_buf
-    "mov    %ebp, 12(%edx)      \n" // store %ebp into nlr_buf
-    "mov    %esp, 16(%edx)      \n" // store %esp into nlr_buf
-    "mov    %ebx, 20(%edx)      \n" // store %ebx into nlr_buf
-    "mov    %edi, 24(%edx)      \n" // store %edi into nlr_buf
-    "mov    %esi, 28(%edx)      \n" // store %esi into nlr_buf
-    "jmp    nlr_push_tail       \n" // do the rest in C
-    );
+        #if UNDO_PRELUDE
+        "pop    %ebp                \n" // undo function's prelude
+        #endif
+        "mov    4(%esp), %edx       \n" // load nlr_buf
+        "mov    (%esp), %eax        \n" // load return %eip
+        "mov    %eax, 8(%edx)       \n" // store %eip into nlr_buf
+        "mov    %ebp, 12(%edx)      \n" // store %ebp into nlr_buf
+        "mov    %esp, 16(%edx)      \n" // store %esp into nlr_buf
+        "mov    %ebx, 20(%edx)      \n" // store %ebx into nlr_buf
+        "mov    %edi, 24(%edx)      \n" // store %edi into nlr_buf
+        "mov    %esi, 28(%edx)      \n" // store %esi into nlr_buf
+        "jmp    nlr_push_tail       \n" // do the rest in C
+        );
 
     #if !USE_NAKED
     return 0; // needed to silence compiler warning
@@ -84,21 +82,21 @@ NORETURN void nlr_jump(void *val) {
     MP_NLR_JUMP_HEAD(val, top)
 
     __asm volatile (
-    "mov    %0, %%edx           \n" // %edx points to nlr_buf
-    "mov    28(%%edx), %%esi    \n" // load saved %esi
-    "mov    24(%%edx), %%edi    \n" // load saved %edi
-    "mov    20(%%edx), %%ebx    \n" // load saved %ebx
-    "mov    16(%%edx), %%esp    \n" // load saved %esp
-    "mov    12(%%edx), %%ebp    \n" // load saved %ebp
-    "mov    8(%%edx), %%eax     \n" // load saved %eip
-    "mov    %%eax, (%%esp)      \n" // store saved %eip to stack
-    "xor    %%eax, %%eax        \n" // clear return register
-    "inc    %%al                \n" // increase to make 1, non-local return
-    "ret                        \n" // return
-    :                               // output operands
-    : "r"(top)                      // input operands
-    :                               // clobbered registers
-    );
+        "mov    %0, %%edx           \n" // %edx points to nlr_buf
+        "mov    28(%%edx), %%esi    \n" // load saved %esi
+        "mov    24(%%edx), %%edi    \n" // load saved %edi
+        "mov    20(%%edx), %%ebx    \n" // load saved %ebx
+        "mov    16(%%edx), %%esp    \n" // load saved %esp
+        "mov    12(%%edx), %%ebp    \n" // load saved %ebp
+        "mov    8(%%edx), %%eax     \n" // load saved %eip
+        "mov    %%eax, (%%esp)      \n" // store saved %eip to stack
+        "xor    %%eax, %%eax        \n" // clear return register
+        "inc    %%al                \n" // increase to make 1, non-local return
+        "ret                        \n" // return
+        :                           // output operands
+        : "r" (top)                 // input operands
+        :                           // clobbered registers
+        );
 
     MP_UNREACHABLE
 }

+ 29 - 29
py/nlrxtensa.c

@@ -39,18 +39,18 @@
 unsigned int nlr_push(nlr_buf_t *nlr) {
 
     __asm volatile (
-    "s32i.n  a0, a2, 8          \n" // save regs...
-    "s32i.n  a1, a2, 12         \n"
-    "s32i.n  a8, a2, 16         \n"
-    "s32i.n  a9, a2, 20         \n"
-    "s32i.n  a10, a2, 24        \n"
-    "s32i.n  a11, a2, 28        \n"
-    "s32i.n  a12, a2, 32        \n"
-    "s32i.n  a13, a2, 36        \n"
-    "s32i.n  a14, a2, 40        \n"
-    "s32i.n  a15, a2, 44        \n"
-    "j      nlr_push_tail       \n" // do the rest in C
-    );
+        "s32i.n  a0, a2, 8          \n" // save regs...
+        "s32i.n  a1, a2, 12         \n"
+        "s32i.n  a8, a2, 16         \n"
+        "s32i.n  a9, a2, 20         \n"
+        "s32i.n  a10, a2, 24        \n"
+        "s32i.n  a11, a2, 28        \n"
+        "s32i.n  a12, a2, 32        \n"
+        "s32i.n  a13, a2, 36        \n"
+        "s32i.n  a14, a2, 40        \n"
+        "s32i.n  a15, a2, 44        \n"
+        "j      nlr_push_tail       \n" // do the rest in C
+        );
 
     return 0; // needed to silence compiler warning
 }
@@ -59,23 +59,23 @@ NORETURN void nlr_jump(void *val) {
     MP_NLR_JUMP_HEAD(val, top)
 
     __asm volatile (
-    "mov.n   a2, %0             \n" // a2 points to nlr_buf
-    "l32i.n  a0, a2, 8          \n" // restore regs...
-    "l32i.n  a1, a2, 12         \n"
-    "l32i.n  a8, a2, 16         \n"
-    "l32i.n  a9, a2, 20         \n"
-    "l32i.n  a10, a2, 24        \n"
-    "l32i.n  a11, a2, 28        \n"
-    "l32i.n  a12, a2, 32        \n"
-    "l32i.n  a13, a2, 36        \n"
-    "l32i.n  a14, a2, 40        \n"
-    "l32i.n  a15, a2, 44        \n"
-    "movi.n a2, 1               \n" // return 1, non-local return
-    "ret.n                      \n" // return
-    :                               // output operands
-    : "r"(top)                      // input operands
-    :                               // clobbered registers
-    );
+        "mov.n   a2, %0             \n" // a2 points to nlr_buf
+        "l32i.n  a0, a2, 8          \n" // restore regs...
+        "l32i.n  a1, a2, 12         \n"
+        "l32i.n  a8, a2, 16         \n"
+        "l32i.n  a9, a2, 20         \n"
+        "l32i.n  a10, a2, 24        \n"
+        "l32i.n  a11, a2, 28        \n"
+        "l32i.n  a12, a2, 32        \n"
+        "l32i.n  a13, a2, 36        \n"
+        "l32i.n  a14, a2, 40        \n"
+        "l32i.n  a15, a2, 44        \n"
+        "movi.n a2, 1               \n" // return 1, non-local return
+        "ret.n                      \n" // return
+        :                           // output operands
+        : "r" (top)                 // input operands
+        :                           // clobbered registers
+        );
 
     MP_UNREACHABLE
 }

+ 206 - 133
py/obj.c

@@ -37,19 +37,62 @@
 #include "py/stackctrl.h"
 #include "py/stream.h" // for mp_obj_print
 
-mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
+const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
+    #if MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A
+
+    if (mp_obj_is_obj(o_in)) {
+        const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
+        return o->type;
+    } else {
+        static const mp_obj_type_t *const types[] = {
+            NULL, &mp_type_int, &mp_type_str, &mp_type_int,
+            NULL, &mp_type_int, &mp_type_NoneType, &mp_type_int,
+            NULL, &mp_type_int, &mp_type_str, &mp_type_int,
+            NULL, &mp_type_int, &mp_type_bool, &mp_type_int,
+        };
+        return types[(uintptr_t)o_in & 0xf];
+    }
+
+    #elif MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
+
     if (mp_obj_is_small_int(o_in)) {
-        return (mp_obj_type_t*)&mp_type_int;
-    } else if (mp_obj_is_qstr(o_in)) {
-        return (mp_obj_type_t*)&mp_type_str;
+        return &mp_type_int;
+    } else if (mp_obj_is_obj(o_in)) {
+        const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
+        return o->type;
     #if MICROPY_PY_BUILTINS_FLOAT
+    } else if ((((mp_uint_t)(o_in)) & 0xff800007) != 0x00000006) {
+        return &mp_type_float;
+    #endif
+    } else {
+        static const mp_obj_type_t *const types[] = {
+            &mp_type_str, &mp_type_NoneType, &mp_type_str, &mp_type_bool,
+        };
+        return types[((uintptr_t)o_in >> 3) & 3];
+    }
+
+    #else
+
+    if (mp_obj_is_small_int(o_in)) {
+        return &mp_type_int;
+    } else if (mp_obj_is_qstr(o_in)) {
+        return &mp_type_str;
+        #if MICROPY_PY_BUILTINS_FLOAT && ( \
+            MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D)
     } else if (mp_obj_is_float(o_in)) {
-        return (mp_obj_type_t*)&mp_type_float;
+        return &mp_type_float;
+        #endif
+    #if MICROPY_OBJ_IMMEDIATE_OBJS
+    } else if (mp_obj_is_immediate_obj(o_in)) {
+        static const mp_obj_type_t *const types[2] = {&mp_type_NoneType, &mp_type_bool};
+        return types[MP_OBJ_IMMEDIATE_OBJ_VALUE(o_in) & 1];
     #endif
     } else {
         const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
-        return (mp_obj_type_t*)o->type;
+        return o->type;
     }
+
+    #endif
 }
 
 const char *mp_obj_get_type_str(mp_const_obj_t o_in) {
@@ -59,15 +102,15 @@ const char *mp_obj_get_type_str(mp_const_obj_t o_in) {
 void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
     // There can be data structures nested too deep, or just recursive
     MP_STACK_CHECK();
-#ifndef NDEBUG
+    #ifndef NDEBUG
     if (o_in == MP_OBJ_NULL) {
         mp_print_str(print, "(nil)");
         return;
     }
-#endif
-    mp_obj_type_t *type = mp_obj_get_type(o_in);
+    #endif
+    const mp_obj_type_t *type = mp_obj_get_type(o_in);
     if (type->print != NULL) {
-        type->print((mp_print_t*)print, o_in, kind);
+        type->print((mp_print_t *)print, o_in, kind);
     } else {
         mp_printf(print, "<%q>", type->name);
     }
@@ -86,11 +129,11 @@ void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) {
             assert(n % 3 == 0);
             mp_print_str(print, "Traceback (most recent call last):\n");
             for (int i = n - 3; i >= 0; i -= 3) {
-#if MICROPY_ENABLE_SOURCE_LINE
+                #if MICROPY_ENABLE_SOURCE_LINE
                 mp_printf(print, "  File \"%q\", line %d", values[i], (int)values[i + 1]);
-#else
+                #else
                 mp_printf(print, "  File \"%q\"", values[i]);
-#endif
+                #endif
                 // the block name can be NULL if it's unknown
                 qstr block = values[i + 2];
                 if (block == MP_QSTRnull) {
@@ -119,7 +162,7 @@ bool mp_obj_is_true(mp_obj_t arg) {
             return 1;
         }
     } else {
-        mp_obj_type_t *type = mp_obj_get_type(arg);
+        const mp_obj_type_t *type = mp_obj_get_type(arg);
         if (type->unary_op != NULL) {
             mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg);
             if (result != MP_OBJ_NULL) {
@@ -139,14 +182,14 @@ bool mp_obj_is_true(mp_obj_t arg) {
 }
 
 bool mp_obj_is_callable(mp_obj_t o_in) {
-    mp_call_fun_t call = mp_obj_get_type(o_in)->call;
+    const mp_call_fun_t call = mp_obj_get_type(o_in)->call;
     if (call != mp_obj_instance_call) {
         return call != NULL;
     }
     return mp_obj_instance_is_callable(o_in);
 }
 
-// This function implements the '==' operator (and so the inverse of '!=').
+// This function implements the '==' and '!=' operators.
 //
 // From the Python language reference:
 // (https://docs.python.org/3/reference/expressions.html#not-in)
@@ -159,67 +202,89 @@ bool mp_obj_is_callable(mp_obj_t o_in) {
 // Furthermore, from the v3.4.2 code for object.c: "Practical amendments: If rich
 // comparison returns NotImplemented, == and != are decided by comparing the object
 // pointer."
-bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
-    // Float (and complex) NaN is never equal to anything, not even itself,
-    // so we must have a special check here to cover those cases.
-    if (o1 == o2
-        #if MICROPY_PY_BUILTINS_FLOAT
-        && !mp_obj_is_float(o1)
-        #endif
-        #if MICROPY_PY_BUILTINS_COMPLEX
-        && !mp_obj_is_type(o1, &mp_type_complex)
-        #endif
-        ) {
-        return true;
-    }
-    if (o1 == mp_const_none || o2 == mp_const_none) {
-        return false;
-    }
-
-    // fast path for small ints
-    if (mp_obj_is_small_int(o1)) {
-        if (mp_obj_is_small_int(o2)) {
-            // both SMALL_INT, and not equal if we get here
-            return false;
-        } else {
-            mp_obj_t temp = o2; o2 = o1; o1 = temp;
-            // o2 is now the SMALL_INT, o1 is not
-            // fall through to generic op
-        }
+mp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2) {
+    mp_obj_t local_true = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_false : mp_const_true;
+    mp_obj_t local_false = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_true : mp_const_false;
+    int pass_number = 0;
+
+    // Shortcut for very common cases
+    if (o1 == o2 &&
+        (mp_obj_is_small_int(o1) || !(mp_obj_get_type(o1)->flags & MP_TYPE_FLAG_EQ_NOT_REFLEXIVE))) {
+        return local_true;
     }
 
     // fast path for strings
     if (mp_obj_is_str(o1)) {
         if (mp_obj_is_str(o2)) {
             // both strings, use special function
-            return mp_obj_str_equal(o1, o2);
+            return mp_obj_str_equal(o1, o2) ? local_true : local_false;
+        #if MICROPY_PY_STR_BYTES_CMP_WARN
+        } else if (mp_obj_is_type(o2, &mp_type_bytes)) {
+        str_bytes_cmp:
+            mp_warning(MP_WARN_CAT(BytesWarning), "Comparison between bytes and str");
+            return local_false;
+        #endif
         } else {
-            // a string is never equal to anything else
-            goto str_cmp_err;
+            goto skip_one_pass;
         }
-    } else if (mp_obj_is_str(o2)) {
+    #if MICROPY_PY_STR_BYTES_CMP_WARN
+    } else if (mp_obj_is_str(o2) && mp_obj_is_type(o1, &mp_type_bytes)) {
         // o1 is not a string (else caught above), so the objects are not equal
-    str_cmp_err:
-        #if MICROPY_PY_STR_BYTES_CMP_WARN
-        if (mp_obj_is_type(o1, &mp_type_bytes) || mp_obj_is_type(o2, &mp_type_bytes)) {
-            mp_warning(MP_WARN_CAT(BytesWarning), "Comparison between bytes and str");
+        goto str_bytes_cmp;
+    #endif
+    }
+
+    // fast path for small ints
+    if (mp_obj_is_small_int(o1)) {
+        if (mp_obj_is_small_int(o2)) {
+            // both SMALL_INT, and not equal if we get here
+            return local_false;
+        } else {
+            goto skip_one_pass;
         }
-        #endif
-        return false;
     }
 
     // generic type, call binary_op(MP_BINARY_OP_EQUAL)
-    mp_obj_type_t *type = mp_obj_get_type(o1);
-    if (type->binary_op != NULL) {
-        mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2);
-        if (r != MP_OBJ_NULL) {
-            return r == mp_const_true ? true : false;
+    while (pass_number < 2) {
+        const mp_obj_type_t *type = mp_obj_get_type(o1);
+        // If a full equality test is not needed and the other object is a different
+        // type then we don't need to bother trying the comparison.
+        if (type->binary_op != NULL &&
+            ((type->flags & MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE) || mp_obj_get_type(o2) == type)) {
+            // CPython is asymmetric: it will try __eq__ if there's no __ne__ but not the
+            // other way around.  If the class doesn't need a full test we can skip __ne__.
+            if (op == MP_BINARY_OP_NOT_EQUAL && (type->flags & MP_TYPE_FLAG_EQ_HAS_NEQ_TEST)) {
+                mp_obj_t r = type->binary_op(MP_BINARY_OP_NOT_EQUAL, o1, o2);
+                if (r != MP_OBJ_NULL) {
+                    return r;
+                }
+            }
+
+            // Try calling __eq__.
+            mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2);
+            if (r != MP_OBJ_NULL) {
+                if (op == MP_BINARY_OP_EQUAL) {
+                    return r;
+                } else {
+                    return mp_obj_is_true(r) ? local_true : local_false;
+                }
+            }
         }
+
+    skip_one_pass:
+        // Try the other way around if none of the above worked
+        ++pass_number;
+        mp_obj_t temp = o1;
+        o1 = o2;
+        o2 = temp;
     }
 
-    // equality not implemented, and objects are not the same object, so
-    // they are defined as not equal
-    return false;
+    // equality not implemented, so fall back to pointer conparison
+    return (o1 == o2) ? local_true : local_false;
+}
+
+bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
+    return mp_obj_is_true(mp_obj_equal_not_equal(MP_BINARY_OP_EQUAL, o1, o2));
 }
 
 mp_int_t mp_obj_get_int(mp_const_obj_t arg) {
@@ -275,7 +340,7 @@ bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value) {
     } else if (arg == mp_const_true) {
         val = 1;
     } else if (mp_obj_is_small_int(arg)) {
-        val = MP_OBJ_SMALL_INT_VALUE(arg);
+        val = (mp_float_t)MP_OBJ_SMALL_INT_VALUE(arg);
     #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
     } else if (mp_obj_is_type(arg, &mp_type_int)) {
         val = mp_obj_int_as_float_impl(arg);
@@ -294,19 +359,19 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) {
     mp_float_t val;
 
     if (!mp_obj_get_float_maybe(arg, &val)) {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_raise_TypeError("can't convert to float");
-        } else {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                "can't convert %s to float", mp_obj_get_type_str(arg)));
-        }
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_raise_TypeError(MP_ERROR_TEXT("can't convert to float"));
+        #else
+        mp_raise_msg_varg(&mp_type_TypeError,
+            MP_ERROR_TEXT("can't convert %s to float"), mp_obj_get_type_str(arg));
+        #endif
     }
 
     return val;
 }
 
 #if MICROPY_PY_BUILTINS_COMPLEX
-void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
+bool mp_obj_get_complex_maybe(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
     if (arg == mp_const_false) {
         *real = 0;
         *imag = 0;
@@ -314,7 +379,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
         *real = 1;
         *imag = 0;
     } else if (mp_obj_is_small_int(arg)) {
-        *real = MP_OBJ_SMALL_INT_VALUE(arg);
+        *real = (mp_float_t)MP_OBJ_SMALL_INT_VALUE(arg);
         *imag = 0;
     #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
     } else if (mp_obj_is_type(arg, &mp_type_int)) {
@@ -327,12 +392,19 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
     } else if (mp_obj_is_type(arg, &mp_type_complex)) {
         mp_obj_complex_get(arg, real, imag);
     } else {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_raise_TypeError("can't convert to complex");
-        } else {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                "can't convert %s to complex", mp_obj_get_type_str(arg)));
-        }
+        return false;
+    }
+    return true;
+}
+
+void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
+    if (!mp_obj_get_complex_maybe(arg, real, imag)) {
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_raise_TypeError(MP_ERROR_TEXT("can't convert to complex"));
+        #else
+        mp_raise_msg_varg(&mp_type_TypeError,
+            MP_ERROR_TEXT("can't convert %s to complex"), mp_obj_get_type_str(arg));
+        #endif
     }
 }
 #endif
@@ -345,12 +417,12 @@ void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) {
     } else if (mp_obj_is_type(o, &mp_type_list)) {
         mp_obj_list_get(o, len, items);
     } else {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_raise_TypeError("expected tuple/list");
-        } else {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                "object '%s' isn't a tuple or list", mp_obj_get_type_str(o)));
-        }
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_raise_TypeError(MP_ERROR_TEXT("expected tuple/list"));
+        #else
+        mp_raise_msg_varg(&mp_type_TypeError,
+            MP_ERROR_TEXT("object '%s' isn't a tuple or list"), mp_obj_get_type_str(o));
+        #endif
     }
 }
 
@@ -359,12 +431,12 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) {
     size_t seq_len;
     mp_obj_get_array(o, &seq_len, items);
     if (seq_len != len) {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_raise_ValueError("tuple/list has wrong length");
-        } else {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
-                "requested length %d but object has length %d", (int)len, (int)seq_len));
-        }
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_raise_ValueError(MP_ERROR_TEXT("tuple/list has wrong length"));
+        #else
+        mp_raise_msg_varg(&mp_type_ValueError,
+            MP_ERROR_TEXT("requested length %d but object has length %d"), (int)len, (int)seq_len);
+        #endif
     }
 }
 
@@ -374,13 +446,13 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool
     if (mp_obj_is_small_int(index)) {
         i = MP_OBJ_SMALL_INT_VALUE(index);
     } else if (!mp_obj_get_int_maybe(index, &i)) {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_raise_TypeError("indices must be integers");
-        } else {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                "%q indices must be integers, not %s",
-                type->name, mp_obj_get_type_str(index)));
-        }
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_raise_TypeError(MP_ERROR_TEXT("indices must be integers"));
+        #else
+        mp_raise_msg_varg(&mp_type_TypeError,
+            MP_ERROR_TEXT("%q indices must be integers, not %s"),
+            type->name, mp_obj_get_type_str(index));
+        #endif
     }
 
     if (i < 0) {
@@ -394,12 +466,11 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool
         }
     } else {
         if (i < 0 || (mp_uint_t)i >= len) {
-            if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-                mp_raise_msg(&mp_type_IndexError, "index out of range");
-            } else {
-                nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError,
-                    "%q index out of range", type->name));
-            }
+            #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+            mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("index out of range"));
+            #else
+            mp_raise_msg_varg(&mp_type_IndexError, MP_ERROR_TEXT("%q index out of range"), type->name);
+            #endif
         }
     }
 
@@ -429,12 +500,12 @@ mp_obj_t mp_obj_id(mp_obj_t o_in) {
 mp_obj_t mp_obj_len(mp_obj_t o_in) {
     mp_obj_t len = mp_obj_len_maybe(o_in);
     if (len == MP_OBJ_NULL) {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_raise_TypeError("object has no len");
-        } else {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
-        }
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_raise_TypeError(MP_ERROR_TEXT("object has no len"));
+        #else
+        mp_raise_msg_varg(&mp_type_TypeError,
+            MP_ERROR_TEXT("object of type '%s' has no len()"), mp_obj_get_type_str(o_in));
+        #endif
     } else {
         return len;
     }
@@ -443,15 +514,15 @@ mp_obj_t mp_obj_len(mp_obj_t o_in) {
 // may return MP_OBJ_NULL
 mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
     if (
-#if !MICROPY_PY_BUILTINS_STR_UNICODE
+        #if !MICROPY_PY_BUILTINS_STR_UNICODE
         // It's simple - unicode is slow, non-unicode is fast
         mp_obj_is_str(o_in) ||
-#endif
+        #endif
         mp_obj_is_type(o_in, &mp_type_bytes)) {
         GET_STR_LEN(o_in, l);
         return MP_OBJ_NEW_SMALL_INT(l);
     } else {
-        mp_obj_type_t *type = mp_obj_get_type(o_in);
+        const mp_obj_type_t *type = mp_obj_get_type(o_in);
         if (type->unary_op != NULL) {
             return type->unary_op(MP_UNARY_OP_LEN, o_in);
         } else {
@@ -461,7 +532,7 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
 }
 
 mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
-    mp_obj_type_t *type = mp_obj_get_type(base);
+    const mp_obj_type_t *type = mp_obj_get_type(base);
     if (type->subscr != NULL) {
         mp_obj_t ret = type->subscr(base, index, value);
         if (ret != MP_OBJ_NULL) {
@@ -470,26 +541,26 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
         // TODO: call base classes here?
     }
     if (value == MP_OBJ_NULL) {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_raise_TypeError("object doesn't support item deletion");
-        } else {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                "'%s' object doesn't support item deletion", mp_obj_get_type_str(base)));
-        }
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item deletion"));
+        #else
+        mp_raise_msg_varg(&mp_type_TypeError,
+            MP_ERROR_TEXT("'%s' object doesn't support item deletion"), mp_obj_get_type_str(base));
+        #endif
     } else if (value == MP_OBJ_SENTINEL) {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_raise_TypeError("object isn't subscriptable");
-        } else {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                "'%s' object isn't subscriptable", mp_obj_get_type_str(base)));
-        }
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_raise_TypeError(MP_ERROR_TEXT("object isn't subscriptable"));
+        #else
+        mp_raise_msg_varg(&mp_type_TypeError,
+            MP_ERROR_TEXT("'%s' object isn't subscriptable"), mp_obj_get_type_str(base));
+        #endif
     } else {
-        if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
-            mp_raise_TypeError("object doesn't support item assignment");
-        } else {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
-                "'%s' object doesn't support item assignment", mp_obj_get_type_str(base)));
-        }
+        #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
+        mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item assignment"));
+        #else
+        mp_raise_msg_varg(&mp_type_TypeError,
+            MP_ERROR_TEXT("'%s' object doesn't support item assignment"), mp_obj_get_type_str(base));
+        #endif
     }
 }
 
@@ -506,7 +577,7 @@ mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf) {
 }
 
 bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
-    mp_obj_type_t *type = mp_obj_get_type(obj);
+    const mp_obj_type_t *type = mp_obj_get_type(obj);
     if (type->buffer_p.get_buffer == NULL) {
         return false;
     }
@@ -519,13 +590,15 @@ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
 
 void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
     if (!mp_get_buffer(obj, bufinfo, flags)) {
-        mp_raise_TypeError("object with buffer protocol required");
+        mp_raise_TypeError(MP_ERROR_TEXT("object with buffer protocol required"));
     }
 }
 
 mp_obj_t mp_generic_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
     switch (op) {
-        case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in);
-        default: return MP_OBJ_NULL; // op not supported
+        case MP_UNARY_OP_HASH:
+            return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in);
+        default:
+            return MP_OBJ_NULL;      // op not supported
     }
 }

+ 249 - 108
py/obj.h

@@ -26,6 +26,8 @@
 #ifndef MICROPY_INCLUDED_PY_OBJ_H
 #define MICROPY_INCLUDED_PY_OBJ_H
 
+#include <assert.h>
+
 #include "py/mpconfig.h"
 #include "py/misc.h"
 #include "py/qstr.h"
@@ -66,13 +68,13 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
 // as many as we can to MP_OBJ_NULL because it's cheaper to load/compare 0.
 
 #if MICROPY_DEBUG_MP_OBJ_SENTINELS
-#define MP_OBJ_NULL             (MP_OBJ_FROM_PTR((void*)0))
-#define MP_OBJ_STOP_ITERATION   (MP_OBJ_FROM_PTR((void*)4))
-#define MP_OBJ_SENTINEL         (MP_OBJ_FROM_PTR((void*)8))
+#define MP_OBJ_NULL             (MP_OBJ_FROM_PTR((void *)0))
+#define MP_OBJ_STOP_ITERATION   (MP_OBJ_FROM_PTR((void *)4))
+#define MP_OBJ_SENTINEL         (MP_OBJ_FROM_PTR((void *)8))
 #else
-#define MP_OBJ_NULL             (MP_OBJ_FROM_PTR((void*)0))
-#define MP_OBJ_STOP_ITERATION   (MP_OBJ_FROM_PTR((void*)0))
-#define MP_OBJ_SENTINEL         (MP_OBJ_FROM_PTR((void*)4))
+#define MP_OBJ_NULL             (MP_OBJ_FROM_PTR((void *)0))
+#define MP_OBJ_STOP_ITERATION   (MP_OBJ_FROM_PTR((void *)0))
+#define MP_OBJ_SENTINEL         (MP_OBJ_FROM_PTR((void *)4))
 #endif
 
 // These macros/inline functions operate on objects and depend on the
@@ -81,15 +83,23 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
 
 #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A
 
-static inline bool mp_obj_is_small_int(mp_const_obj_t o)
-    { return ((((mp_int_t)(o)) & 1) != 0); }
+static inline bool mp_obj_is_small_int(mp_const_obj_t o) {
+    return (((mp_int_t)(o)) & 1) != 0;
+}
 #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
 #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1))
 
-static inline bool mp_obj_is_qstr(mp_const_obj_t o)
-    { return ((((mp_int_t)(o)) & 3) == 2); }
-#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2)
-#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 2))
+static inline bool mp_obj_is_qstr(mp_const_obj_t o) {
+    return (((mp_int_t)(o)) & 7) == 2;
+}
+#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3)
+#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 2))
+
+static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
+    return (((mp_int_t)(o)) & 7) == 6;
+}
+#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 3)
+#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) ((mp_obj_t)(((val) << 3) | 6))
 
 #if MICROPY_PY_BUILTINS_FLOAT
 #define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj)
@@ -102,20 +112,29 @@ mp_float_t mp_obj_float_get(mp_obj_t self_in);
 mp_obj_t mp_obj_new_float(mp_float_t value);
 #endif
 
-static inline bool mp_obj_is_obj(mp_const_obj_t o)
-    { return ((((mp_int_t)(o)) & 3) == 0); }
+static inline bool mp_obj_is_obj(mp_const_obj_t o) {
+    return (((mp_int_t)(o)) & 3) == 0;
+}
 
 #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B
 
-static inline bool mp_obj_is_small_int(mp_const_obj_t o)
-    { return ((((mp_int_t)(o)) & 3) == 1); }
+static inline bool mp_obj_is_small_int(mp_const_obj_t o) {
+    return (((mp_int_t)(o)) & 3) == 1;
+}
 #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 2)
 #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 2) | 1))
 
-static inline bool mp_obj_is_qstr(mp_const_obj_t o)
-    { return ((((mp_int_t)(o)) & 3) == 3); }
-#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2)
-#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 3))
+static inline bool mp_obj_is_qstr(mp_const_obj_t o) {
+    return (((mp_int_t)(o)) & 7) == 3;
+}
+#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3)
+#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 3))
+
+static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
+    return (((mp_int_t)(o)) & 7) == 7;
+}
+#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 3)
+#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) ((mp_obj_t)(((val) << 3) | 7))
 
 #if MICROPY_PY_BUILTINS_FLOAT
 #define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj)
@@ -128,13 +147,15 @@ mp_float_t mp_obj_float_get(mp_obj_t self_in);
 mp_obj_t mp_obj_new_float(mp_float_t value);
 #endif
 
-static inline bool mp_obj_is_obj(mp_const_obj_t o)
-    { return ((((mp_int_t)(o)) & 1) == 0); }
+static inline bool mp_obj_is_obj(mp_const_obj_t o) {
+    return (((mp_int_t)(o)) & 1) == 0;
+}
 
 #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
 
-static inline bool mp_obj_is_small_int(mp_const_obj_t o)
-    { return ((((mp_int_t)(o)) & 1) != 0); }
+static inline bool mp_obj_is_small_int(mp_const_obj_t o) {
+    return (((mp_int_t)(o)) & 1) != 0;
+}
 #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
 #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1))
 
@@ -142,8 +163,9 @@ static inline bool mp_obj_is_small_int(mp_const_obj_t o)
 #define mp_const_float_e MP_ROM_PTR((mp_obj_t)(((0x402df854 & ~3) | 2) + 0x80800000))
 #define mp_const_float_pi MP_ROM_PTR((mp_obj_t)(((0x40490fdb & ~3) | 2) + 0x80800000))
 
-static inline bool mp_obj_is_float(mp_const_obj_t o)
-    { return (((mp_uint_t)(o)) & 3) == 2 && (((mp_uint_t)(o)) & 0xff800007) != 0x00000006; }
+static inline bool mp_obj_is_float(mp_const_obj_t o) {
+    return (((mp_uint_t)(o)) & 3) == 2 && (((mp_uint_t)(o)) & 0xff800007) != 0x00000006;
+}
 static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {
     union {
         mp_float_t f;
@@ -160,25 +182,41 @@ static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
 }
 #endif
 
-static inline bool mp_obj_is_qstr(mp_const_obj_t o)
-    { return (((mp_uint_t)(o)) & 0xff800007) == 0x00000006; }
-#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3)
-#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 0x00000006))
+static inline bool mp_obj_is_qstr(mp_const_obj_t o) {
+    return (((mp_uint_t)(o)) & 0xff80000f) == 0x00000006;
+}
+#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 4)
+#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 4) | 0x00000006))
 
-static inline bool mp_obj_is_obj(mp_const_obj_t o)
-    { return ((((mp_int_t)(o)) & 3) == 0); }
+static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
+    return (((mp_uint_t)(o)) & 0xff80000f) == 0x0000000e;
+}
+#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 4)
+#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) ((mp_obj_t)(((val) << 4) | 0xe))
+
+static inline bool mp_obj_is_obj(mp_const_obj_t o) {
+    return (((mp_int_t)(o)) & 3) == 0;
+}
 
 #elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
 
-static inline bool mp_obj_is_small_int(mp_const_obj_t o)
-    { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0001000000000000); }
+static inline bool mp_obj_is_small_int(mp_const_obj_t o) {
+    return (((uint64_t)(o)) & 0xffff000000000000) == 0x0001000000000000;
+}
 #define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)((o) << 16)) >> 17)
 #define MP_OBJ_NEW_SMALL_INT(small_int) (((((uint64_t)(small_int)) & 0x7fffffffffff) << 1) | 0x0001000000000001)
 
-static inline bool mp_obj_is_qstr(mp_const_obj_t o)
-    { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0002000000000000); }
+static inline bool mp_obj_is_qstr(mp_const_obj_t o) {
+    return (((uint64_t)(o)) & 0xffff000000000000) == 0x0002000000000000;
+}
 #define MP_OBJ_QSTR_VALUE(o) ((((uint32_t)(o)) >> 1) & 0xffffffff)
-#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 1) | 0x0002000000000001))
+#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)(((uint64_t)(((uint32_t)(qst)) << 1)) | 0x0002000000000001))
+
+static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
+    return (((uint64_t)(o)) & 0xffff000000000000) == 0x0003000000000000;
+}
+#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) ((((uint32_t)(o)) >> 46) & 3)
+#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) (((uint64_t)(val) << 46) | 0x0003000000000000)
 
 #if MICROPY_PY_BUILTINS_FLOAT
 
@@ -208,13 +246,17 @@ static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
 }
 #endif
 
-static inline bool mp_obj_is_obj(mp_const_obj_t o)
-    { return ((((uint64_t)(o)) & 0xffff000000000000) == 0x0000000000000000); }
-#define MP_OBJ_TO_PTR(o) ((void*)(uintptr_t)(o))
+static inline bool mp_obj_is_obj(mp_const_obj_t o) {
+    return (((uint64_t)(o)) & 0xffff000000000000) == 0x0000000000000000;
+}
+#define MP_OBJ_TO_PTR(o) ((void *)(uintptr_t)(o))
 #define MP_OBJ_FROM_PTR(p) ((mp_obj_t)((uintptr_t)(p)))
 
 // rom object storage needs special handling to widen 32-bit pointer to 64-bits
-typedef union _mp_rom_obj_t { uint64_t u64; struct { const void *lo, *hi; } u32; } mp_rom_obj_t;
+typedef union _mp_rom_obj_t { uint64_t u64;
+                              struct { const void *lo, *hi;
+                              } u32;
+} mp_rom_obj_t;
 #define MP_ROM_INT(i) {MP_OBJ_NEW_SMALL_INT(i)}
 #define MP_ROM_QSTR(q) {MP_OBJ_NEW_QSTR(q)}
 #if MP_ENDIANNESS_LITTLE
@@ -232,7 +274,7 @@ typedef union _mp_rom_obj_t { uint64_t u64; struct { const void *lo, *hi; } u32;
 
 // Cast mp_obj_t to object pointer
 #ifndef MP_OBJ_TO_PTR
-#define MP_OBJ_TO_PTR(o) ((void*)o)
+#define MP_OBJ_TO_PTR(o) ((void *)o)
 #endif
 
 // Cast object pointer to mp_obj_t
@@ -242,6 +284,24 @@ typedef union _mp_rom_obj_t { uint64_t u64; struct { const void *lo, *hi; } u32;
 
 // Macros to create objects that are stored in ROM.
 
+#ifndef MP_ROM_NONE
+#if MICROPY_OBJ_IMMEDIATE_OBJS
+#define MP_ROM_NONE mp_const_none
+#else
+#define MP_ROM_NONE MP_ROM_PTR(&mp_const_none_obj)
+#endif
+#endif
+
+#ifndef MP_ROM_FALSE
+#if MICROPY_OBJ_IMMEDIATE_OBJS
+#define MP_ROM_FALSE mp_const_false
+#define MP_ROM_TRUE mp_const_true
+#else
+#define MP_ROM_FALSE MP_ROM_PTR(&mp_const_false_obj)
+#define MP_ROM_TRUE MP_ROM_PTR(&mp_const_true_obj)
+#endif
+#endif
+
 #ifndef MP_ROM_INT
 typedef mp_const_obj_t mp_rom_obj_t;
 #define MP_ROM_INT(i) MP_OBJ_NEW_SMALL_INT(i)
@@ -271,25 +331,25 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t;
 
 #define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \
     const mp_obj_fun_builtin_fixed_t obj_name = \
-        {{&mp_type_fun_builtin_0}, .fun._0 = fun_name}
+    {{&mp_type_fun_builtin_0}, .fun._0 = fun_name}
 #define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) \
     const mp_obj_fun_builtin_fixed_t obj_name = \
-        {{&mp_type_fun_builtin_1}, .fun._1 = fun_name}
+    {{&mp_type_fun_builtin_1}, .fun._1 = fun_name}
 #define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) \
     const mp_obj_fun_builtin_fixed_t obj_name = \
-        {{&mp_type_fun_builtin_2}, .fun._2 = fun_name}
+    {{&mp_type_fun_builtin_2}, .fun._2 = fun_name}
 #define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) \
     const mp_obj_fun_builtin_fixed_t obj_name = \
-        {{&mp_type_fun_builtin_3}, .fun._3 = fun_name}
+    {{&mp_type_fun_builtin_3}, .fun._3 = fun_name}
 #define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) \
     const mp_obj_fun_builtin_var_t obj_name = \
-        {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, false), .fun.var = fun_name}
+    {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, false), .fun.var = fun_name}
 #define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) \
     const mp_obj_fun_builtin_var_t obj_name = \
-        {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, false), .fun.var = fun_name}
+    {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, false), .fun.var = fun_name}
 #define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \
     const mp_obj_fun_builtin_var_t obj_name = \
-        {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name}
+    {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name}
 
 // These macros are used to define constant map/dict objects
 // You can put "static" in front of the definition to make it local
@@ -301,7 +361,7 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t;
         .is_ordered = 1, \
         .used = MP_ARRAY_SIZE(table_name), \
         .alloc = MP_ARRAY_SIZE(table_name), \
-        .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)table_name, \
+        .table = (mp_map_elem_t *)(mp_rom_map_elem_t *)table_name, \
     }
 
 #define MP_DEFINE_CONST_DICT(dict_name, table_name) \
@@ -313,7 +373,7 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t;
             .is_ordered = 1, \
             .used = MP_ARRAY_SIZE(table_name), \
             .alloc = MP_ARRAY_SIZE(table_name), \
-            .table = (mp_map_elem_t*)(mp_rom_map_elem_t*)table_name, \
+            .table = (mp_map_elem_t *)(mp_rom_map_elem_t *)table_name, \
         }, \
     }
 
@@ -345,15 +405,10 @@ typedef struct _mp_rom_map_elem_t {
     mp_rom_obj_t value;
 } mp_rom_map_elem_t;
 
-// TODO maybe have a truncated mp_map_t for fixed tables, since alloc=used
-// put alloc last in the structure, so the truncated version does not need it
-// this would save 1 ROM word for all ROM objects that have a locals_dict
-// would also need a trucated dict structure
-
 typedef struct _mp_map_t {
     size_t all_keys_are_qstrs : 1;
-    size_t is_fixed : 1;    // a fixed array that can't be modified; must also be ordered
-    size_t is_ordered : 1;  // an ordered array
+    size_t is_fixed : 1;    // if set, table is fixed/read-only and can't be modified
+    size_t is_ordered : 1;  // if set, table is an ordered array, not a hash map
     size_t used : (8 * sizeof(size_t) - 3);
     size_t alloc;
     mp_map_elem_t *table;
@@ -367,9 +422,10 @@ typedef enum _mp_map_lookup_kind_t {
     MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND = 3, // only valid for mp_set_lookup
 } mp_map_lookup_kind_t;
 
-extern const mp_map_t mp_const_empty_map;
-
-static inline bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); }
+static inline bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) {
+    assert(pos < map->alloc);
+    return (map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL;
+}
 
 void mp_map_init(mp_map_t *map, size_t n);
 void mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table);
@@ -388,7 +444,9 @@ typedef struct _mp_set_t {
     mp_obj_t *table;
 } mp_set_t;
 
-static inline bool mp_set_slot_is_filled(const mp_set_t *set, size_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); }
+static inline bool mp_set_slot_is_filled(const mp_set_t *set, size_t pos) {
+    return (set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL;
+}
 
 void mp_set_init(mp_set_t *set, size_t n);
 mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);
@@ -406,6 +464,23 @@ typedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *);
 // this arg to mp_map_lookup().
 typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *);
 
+// Flags for type behaviour (mp_obj_type_t.flags)
+// If MP_TYPE_FLAG_EQ_NOT_REFLEXIVE is clear then __eq__ is reflexive (A==A returns True).
+// If MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE is clear then the type can't be equal to an
+// instance of any different class that also clears this flag.  If this flag is set
+// then the type may check for equality against a different type.
+// If MP_TYPE_FLAG_EQ_HAS_NEQ_TEST is clear then the type only implements the __eq__
+// operator and not the __ne__ operator.  If it's set then __ne__ may be implemented.
+// If MP_TYPE_FLAG_BINDS_SELF is set then the type as a method binds self as the first arg.
+// If MP_TYPE_FLAG_BUILTIN_FUN is set then the type is a built-in function type.
+#define MP_TYPE_FLAG_IS_SUBCLASSED (0x0001)
+#define MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002)
+#define MP_TYPE_FLAG_EQ_NOT_REFLEXIVE (0x0004)
+#define MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE (0x0008)
+#define MP_TYPE_FLAG_EQ_HAS_NEQ_TEST (0x0010)
+#define MP_TYPE_FLAG_BINDS_SELF (0x0020)
+#define MP_TYPE_FLAG_BUILTIN_FUN (0x0040)
+
 typedef enum {
     PRINT_STR = 0,
     PRINT_REPR = 1,
@@ -435,18 +510,9 @@ typedef mp_obj_t (*mp_getiter_fun_t)(mp_obj_t self_in, mp_obj_iter_buf_t *iter_b
 
 // Buffer protocol
 typedef struct _mp_buffer_info_t {
-    // if we'd bother to support various versions of structure
-    // (with different number of fields), we can distinguish
-    // them with ver = sizeof(struct). Cons: overkill for *micro*?
-    //int ver; // ?
-
     void *buf;      // can be NULL if len == 0
     size_t len;     // in bytes
     int typecode;   // as per binary.h
-
-    // Rationale: to load arbitrary-sized sprites directly to LCD
-    // Cons: a bit adhoc usecase
-    // int stride;
 } mp_buffer_info_t;
 #define MP_BUFFER_READ  (1)
 #define MP_BUFFER_WRITE (2)
@@ -589,7 +655,6 @@ extern const mp_obj_type_t mp_type_MemoryError;
 extern const mp_obj_type_t mp_type_NameError;
 extern const mp_obj_type_t mp_type_NotImplementedError;
 extern const mp_obj_type_t mp_type_OSError;
-extern const mp_obj_type_t mp_type_TimeoutError;
 extern const mp_obj_type_t mp_type_OverflowError;
 extern const mp_obj_type_t mp_type_RuntimeError;
 extern const mp_obj_type_t mp_type_StopAsyncIteration;
@@ -602,47 +667,71 @@ extern const mp_obj_type_t mp_type_ValueError;
 extern const mp_obj_type_t mp_type_ViperTypeError;
 extern const mp_obj_type_t mp_type_ZeroDivisionError;
 
-// Constant objects, globally accessible
-// The macros are for convenience only
+// Constant objects, globally accessible: None, False, True
+// These should always be accessed via the below macros.
+#if MICROPY_OBJ_IMMEDIATE_OBJS
+// None is even while False/True are odd so their types can be distinguished with 1 bit.
+#define mp_const_none MP_OBJ_NEW_IMMEDIATE_OBJ(0)
+#define mp_const_false MP_OBJ_NEW_IMMEDIATE_OBJ(1)
+#define mp_const_true MP_OBJ_NEW_IMMEDIATE_OBJ(3)
+#else
 #define mp_const_none (MP_OBJ_FROM_PTR(&mp_const_none_obj))
 #define mp_const_false (MP_OBJ_FROM_PTR(&mp_const_false_obj))
 #define mp_const_true (MP_OBJ_FROM_PTR(&mp_const_true_obj))
-#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj))
-#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj))
-#define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj))
 extern const struct _mp_obj_none_t mp_const_none_obj;
 extern const struct _mp_obj_bool_t mp_const_false_obj;
 extern const struct _mp_obj_bool_t mp_const_true_obj;
+#endif
+
+// Constant objects, globally accessible: b'', (), {}, Ellipsis, NotImplemented, GeneratorExit()
+// The below macros are for convenience only.
+#define mp_const_empty_bytes (MP_OBJ_FROM_PTR(&mp_const_empty_bytes_obj))
+#define mp_const_empty_tuple (MP_OBJ_FROM_PTR(&mp_const_empty_tuple_obj))
+#define mp_const_notimplemented (MP_OBJ_FROM_PTR(&mp_const_notimplemented_obj))
 extern const struct _mp_obj_str_t mp_const_empty_bytes_obj;
 extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj;
+extern const struct _mp_obj_dict_t mp_const_empty_dict_obj;
 extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj;
 extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj;
 extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj;
 
+// Fixed empty map. Useful when calling keyword-receiving functions
+// without any keywords from C, etc.
+#define mp_const_empty_map (mp_const_empty_dict_obj.map)
+
 // General API for objects
 
 // These macros are derived from more primitive ones and are used to
 // check for more specific object types.
 // Note: these are kept as macros because inline functions sometimes use much
 // more code space than the equivalent macros, depending on the compiler.
-#define mp_obj_is_type(o, t) (mp_obj_is_obj(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that
+#define mp_obj_is_type(o, t) (mp_obj_is_obj(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that
+#if MICROPY_OBJ_IMMEDIATE_OBJS
+// bool's are immediates, not real objects, so test for the 2 possible values.
+#define mp_obj_is_bool(o) ((o) == mp_const_false || (o) == mp_const_true)
+#else
+#define mp_obj_is_bool(o) mp_obj_is_type(o, &mp_type_bool)
+#endif
 #define mp_obj_is_int(o) (mp_obj_is_small_int(o) || mp_obj_is_type(o, &mp_type_int))
 #define mp_obj_is_str(o) (mp_obj_is_qstr(o) || mp_obj_is_type(o, &mp_type_str))
-#define mp_obj_is_str_or_bytes(o) (mp_obj_is_qstr(o) || (mp_obj_is_obj(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op))
-#define mp_obj_is_fun(o) (mp_obj_is_obj(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function))
+#define mp_obj_is_str_or_bytes(o) (mp_obj_is_qstr(o) || (mp_obj_is_obj(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op))
+#define mp_obj_is_dict_or_ordereddict(o) (mp_obj_is_obj(o) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->make_new == mp_obj_dict_make_new)
+#define mp_obj_is_fun(o) (mp_obj_is_obj(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function))
 
 mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict);
-static inline mp_obj_t mp_obj_new_bool(mp_int_t x) { return x ? mp_const_true : mp_const_false; }
+static inline mp_obj_t mp_obj_new_bool(mp_int_t x) {
+    return x ? mp_const_true : mp_const_false;
+}
 mp_obj_t mp_obj_new_cell(mp_obj_t obj);
 mp_obj_t mp_obj_new_int(mp_int_t value);
 mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value);
 mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base);
 mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception)
 mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception)
-mp_obj_t mp_obj_new_str(const char* data, size_t len);
-mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len);
+mp_obj_t mp_obj_new_str(const char *data, size_t len);
+mp_obj_t mp_obj_new_str_via_qstr(const char *data, size_t len);
 mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr);
-mp_obj_t mp_obj_new_bytes(const byte* data, size_t len);
+mp_obj_t mp_obj_new_bytes(const byte *data, size_t len);
 mp_obj_t mp_obj_new_bytearray(size_t n, void *items);
 mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items);
 #if MICROPY_PY_BUILTINS_FLOAT
@@ -652,8 +741,11 @@ mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
 mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);
 mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
 mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args);
-mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
-mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
+mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg);
+mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
+#ifdef va_start
+mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list arg); // same fmt restrictions as above
+#endif
 mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table);
 mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table);
 mp_obj_t mp_obj_new_fun_asm(size_t n_args, const void *fun_data, mp_uint_t type_sig);
@@ -669,10 +761,10 @@ mp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf);
 mp_obj_t mp_obj_new_module(qstr module_name);
 mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items);
 
-mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in);
+const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in);
 const char *mp_obj_get_type_str(mp_const_obj_t o_in);
 bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects
-mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t native_type);
+mp_obj_t mp_obj_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type);
 
 void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
 void mp_obj_print(mp_obj_t o, mp_print_kind_t kind);
@@ -680,9 +772,12 @@ void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc);
 
 bool mp_obj_is_true(mp_obj_t arg);
 bool mp_obj_is_callable(mp_obj_t o_in);
+mp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2);
 bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);
 
-static inline bool mp_obj_is_integer(mp_const_obj_t o) { return mp_obj_is_int(o) || mp_obj_is_type(o, &mp_type_bool); } // returns true if o is bool, small int or long int
+static inline bool mp_obj_is_integer(mp_const_obj_t o) {
+    return mp_obj_is_int(o) || mp_obj_is_bool(o);
+}                                                                                                        // returns true if o is bool, small int or long int
 mp_int_t mp_obj_get_int(mp_const_obj_t arg);
 mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg);
 bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value);
@@ -690,6 +785,7 @@ bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value);
 mp_float_t mp_obj_get_float(mp_obj_t self_in);
 bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value);
 void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
+bool mp_obj_get_complex_maybe(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
 #endif
 void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items); // *items may point inside a GC block
 void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items); // *items may point inside a GC block
@@ -709,6 +805,8 @@ void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj);
 mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in);
 // Will raise exception if value doesn't fit into mp_int_t
 mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in);
+// Will raise exception if value is negative or doesn't fit into mp_uint_t
+mp_uint_t mp_obj_int_get_uint_checked(mp_const_obj_t self_in);
 
 // exception
 #define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new)
@@ -734,10 +832,45 @@ void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t s
 
 #if MICROPY_PY_BUILTINS_FLOAT
 // float
+#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
+static inline float mp_obj_get_float_to_f(mp_obj_t o) {
+    return mp_obj_get_float(o);
+}
+
+static inline double mp_obj_get_float_to_d(mp_obj_t o) {
+    return (double)mp_obj_get_float(o);
+}
+
+static inline mp_obj_t mp_obj_new_float_from_f(float o) {
+    return mp_obj_new_float(o);
+}
+
+static inline mp_obj_t mp_obj_new_float_from_d(double o) {
+    return mp_obj_new_float((mp_float_t)o);
+}
+#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
+static inline float mp_obj_get_float_to_f(mp_obj_t o) {
+    return (float)mp_obj_get_float(o);
+}
+
+static inline double mp_obj_get_float_to_d(mp_obj_t o) {
+    return mp_obj_get_float(o);
+}
+
+static inline mp_obj_t mp_obj_new_float_from_f(float o) {
+    return mp_obj_new_float((mp_float_t)o);
+}
+
+static inline mp_obj_t mp_obj_new_float_from_d(double o) {
+    return mp_obj_new_float(o);
+}
+#endif
 #if MICROPY_FLOAT_HIGH_QUALITY_HASH
 mp_int_t mp_float_hash(mp_float_t val);
 #else
-static inline mp_int_t mp_float_hash(mp_float_t val) { return (mp_int_t)val; }
+static inline mp_int_t mp_float_hash(mp_float_t val) {
+    return (mp_int_t)val;
+}
 #endif
 mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported
 
@@ -766,20 +899,35 @@ typedef struct _mp_obj_dict_t {
     mp_obj_base_t base;
     mp_map_t map;
 } mp_obj_dict_t;
+mp_obj_t mp_obj_dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
 void mp_obj_dict_init(mp_obj_dict_t *dict, size_t n_args);
 size_t mp_obj_dict_len(mp_obj_t self_in);
 mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index);
 mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
 mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key);
+mp_obj_t mp_obj_dict_copy(mp_obj_t self_in);
 static inline mp_map_t *mp_obj_dict_get_map(mp_obj_t dict) {
-    return &((mp_obj_dict_t*)MP_OBJ_TO_PTR(dict))->map;
+    return &((mp_obj_dict_t *)MP_OBJ_TO_PTR(dict))->map;
 }
 
 // set
 void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
 
+// slice indexes resolved to particular sequence
+typedef struct {
+    mp_int_t start;
+    mp_int_t stop;
+    mp_int_t step;
+} mp_bound_slice_t;
+
 // slice
-void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step);
+typedef struct _mp_obj_slice_t {
+    mp_obj_base_t base;
+    mp_obj_t start;
+    mp_obj_t stop;
+    mp_obj_t step;
+} mp_obj_slice_t;
+void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result);
 
 // functions
 
@@ -815,7 +963,7 @@ typedef struct _mp_obj_module_t {
     mp_obj_dict_t *globals;
 } mp_obj_module_t;
 static inline mp_obj_dict_t *mp_obj_module_get_globals(mp_obj_t module) {
-    return ((mp_obj_module_t*)MP_OBJ_TO_PTR(module))->globals;
+    return ((mp_obj_module_t *)MP_OBJ_TO_PTR(module))->globals;
 }
 // check if given module object is a package
 bool mp_obj_is_package(mp_obj_t module);
@@ -836,13 +984,6 @@ const mp_obj_t *mp_obj_property_get(mp_obj_t self_in);
 
 // sequence helpers
 
-// slice indexes resolved to particular sequence
-typedef struct {
-    mp_uint_t start;
-    mp_uint_t stop;
-    mp_int_t step;
-} mp_bound_slice_t;
-
 void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest);
 #if MICROPY_PY_BUILTINS_SLICE
 bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes);
@@ -854,19 +995,19 @@ bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp
 mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args);
 mp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value);
 mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes);
+
 // Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems
-#define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte*)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz))
+#define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte *)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz))
+
+// Note: dest and slice regions may overlap
 #define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_sz) \
-    /*printf("memcpy(%p, %p, %d)\n", dest + beg, slice, slice_len * (item_sz));*/ \
-    memcpy(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); \
-    /*printf("memmove(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * (item_sz));*/ \
-    memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), (dest_len - end) * (item_sz));
+    memmove(((char *)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); \
+    memmove(((char *)dest) + (beg + slice_len) * (item_sz), ((char *)dest) + (end) * (item_sz), (dest_len - end) * (item_sz));
 
 // Note: dest and slice regions may overlap
 #define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_sz) \
-    /*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * (item_sz));*/ \
-    memmove(((char*)dest) + (beg + slice_len) * (item_sz), ((char*)dest) + (end) * (item_sz), ((dest_len) + (len_adj) - ((beg) + (slice_len))) * (item_sz)); \
-    memmove(((char*)dest) + (beg) * (item_sz), slice, slice_len * (item_sz));
+    memmove(((char *)dest) + (beg + slice_len) * (item_sz), ((char *)dest) + (end) * (item_sz), ((dest_len) + (len_adj) - ((beg) + (slice_len))) * (item_sz)); \
+    memmove(((char *)dest) + (beg) * (item_sz), slice, slice_len * (item_sz));
 
 // Provide translation for legacy API
 #define MP_OBJ_IS_SMALL_INT mp_obj_is_small_int

+ 28 - 23
py/objarray.c

@@ -117,10 +117,10 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
     // other arrays can only be raw-initialised from bytes and bytearray objects
     mp_buffer_info_t bufinfo;
     if (((MICROPY_PY_BUILTINS_BYTEARRAY
-            && typecode == BYTEARRAY_TYPECODE)
-        || (MICROPY_PY_ARRAY
-            && (mp_obj_is_type(initializer, &mp_type_bytes)
-                || (MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(initializer, &mp_type_bytearray)))))
+          && typecode == BYTEARRAY_TYPECODE)
+         || (MICROPY_PY_ARRAY
+             && (mp_obj_is_type(initializer, &mp_type_bytes)
+                 || (MICROPY_PY_BUILTINS_BYTEARRAY && mp_obj_is_type(initializer, &mp_type_bytearray)))))
         && mp_get_buffer(initializer, &bufinfo, MP_BUFFER_READ)) {
         // construct array from raw bytes
         // we round-down the len to make it a multiple of sz (CPython raises error)
@@ -249,9 +249,12 @@ STATIC void memoryview_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
 STATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
     mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);
     switch (op) {
-        case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->len != 0);
-        case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(o->len);
-        default: return MP_OBJ_NULL; // op not supported
+        case MP_UNARY_OP_BOOL:
+            return mp_obj_new_bool(o->len != 0);
+        case MP_UNARY_OP_LEN:
+            return MP_OBJ_NEW_SMALL_INT(o->len);
+        default:
+            return MP_OBJ_NULL;      // op not supported
     }
 }
 
@@ -272,7 +275,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
 
             // note: lhs->len is element count of lhs, lhs_bufinfo.len is byte count
             mp_obj_array_t *res = array_new(lhs_bufinfo.typecode, lhs->len + rhs_len);
-            mp_seq_cat((byte*)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte);
+            mp_seq_cat((byte *)res->items, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_len * sz, byte);
             return MP_OBJ_FROM_PTR(res);
         }
 
@@ -371,7 +374,7 @@ STATIC mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) {
     }
 
     // extend
-    mp_seq_copy((byte*)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte);
+    mp_seq_copy((byte *)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte);
     self->len += len;
 
     return mp_const_none;
@@ -388,11 +391,11 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
         return MP_OBJ_NULL; // op not supported
     } else {
         mp_obj_array_t *o = MP_OBJ_TO_PTR(self_in);
-#if MICROPY_PY_BUILTINS_SLICE
+        #if MICROPY_PY_BUILTINS_SLICE
         if (mp_obj_is_type(index_in, &mp_type_slice)) {
             mp_bound_slice_t slice;
             if (!mp_seq_get_fast_slice_indexes(o->len, index_in, &slice)) {
-                mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported");
+                mp_raise_NotImplementedError(MP_ERROR_TEXT("only slices with step=1 (aka None) are supported"));
             }
             if (value != MP_OBJ_SENTINEL) {
                 #if MICROPY_PY_ARRAY_SLICE_ASSIGN
@@ -400,18 +403,18 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
                 size_t src_len;
                 void *src_items;
                 size_t item_sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
-                if (mp_obj_is_obj(value) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) {
+                if (mp_obj_is_obj(value) && ((mp_obj_base_t *)MP_OBJ_TO_PTR(value))->type->subscr == array_subscr) {
                     // value is array, bytearray or memoryview
                     mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value);
                     if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) {
                     compat_error:
-                        mp_raise_ValueError("lhs and rhs should be compatible");
+                        mp_raise_ValueError(MP_ERROR_TEXT("lhs and rhs should be compatible"));
                     }
                     src_len = src_slice->len;
                     src_items = src_slice->items;
                     #if MICROPY_PY_BUILTINS_MEMORYVIEW
                     if (mp_obj_is_type(value, &mp_type_memoryview)) {
-                        src_items = (uint8_t*)src_items + (src_slice->memview_offset * item_sz);
+                        src_items = (uint8_t *)src_items + (src_slice->memview_offset * item_sz);
                     }
                     #endif
                 } else if (mp_obj_is_type(value, &mp_type_bytes)) {
@@ -423,12 +426,12 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
                     src_len = bufinfo.len;
                     src_items = bufinfo.buf;
                 } else {
-                    mp_raise_NotImplementedError("array/bytes required on right side");
+                    mp_raise_NotImplementedError(MP_ERROR_TEXT("array/bytes required on right side"));
                 }
 
                 // TODO: check src/dst compat
                 mp_int_t len_adj = src_len - (slice.stop - slice.start);
-                uint8_t* dest_items = o->items;
+                uint8_t *dest_items = o->items;
                 #if MICROPY_PY_BUILTINS_MEMORYVIEW
                 if (o->base.type == &mp_type_memoryview) {
                     if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
@@ -442,7 +445,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
                 }
                 #endif
                 if (len_adj > 0) {
-                    if (len_adj > o->free) {
+                    if ((size_t)len_adj > o->free) {
                         // TODO: alloc policy; at the moment we go conservative
                         o->items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz);
                         o->free = len_adj;
@@ -479,11 +482,11 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
             #endif
             {
                 res = array_new(o->typecode, slice.stop - slice.start);
-                memcpy(res->items, (uint8_t*)o->items + slice.start * sz, (slice.stop - slice.start) * sz);
+                memcpy(res->items, (uint8_t *)o->items + slice.start * sz, (slice.stop - slice.start) * sz);
             }
             return MP_OBJ_FROM_PTR(res);
         } else
-#endif
+        #endif
         {
             size_t index = mp_get_index(o->base.type, o->len, index_in, false);
             #if MICROPY_PY_BUILTINS_MEMORYVIEW
@@ -519,7 +522,7 @@ STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_ui
             // read-only memoryview
             return 1;
         }
-        bufinfo->buf = (uint8_t*)bufinfo->buf + (size_t)o->memview_offset * sz;
+        bufinfo->buf = (uint8_t *)bufinfo->buf + (size_t)o->memview_offset * sz;
     }
     #else
     (void)flags;
@@ -550,13 +553,14 @@ const mp_obj_type_t mp_type_array = {
     .binary_op = array_binary_op,
     .subscr = array_subscr,
     .buffer_p = { .get_buffer = array_get_buffer },
-    .locals_dict = (mp_obj_dict_t*)&array_locals_dict,
+    .locals_dict = (mp_obj_dict_t *)&array_locals_dict,
 };
 #endif
 
 #if MICROPY_PY_BUILTINS_BYTEARRAY
 const mp_obj_type_t mp_type_bytearray = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,
     .name = MP_QSTR_bytearray,
     .print = array_print,
     .make_new = bytearray_make_new,
@@ -565,13 +569,14 @@ const mp_obj_type_t mp_type_bytearray = {
     .binary_op = array_binary_op,
     .subscr = array_subscr,
     .buffer_p = { .get_buffer = array_get_buffer },
-    .locals_dict = (mp_obj_dict_t*)&array_locals_dict,
+    .locals_dict = (mp_obj_dict_t *)&array_locals_dict,
 };
 #endif
 
 #if MICROPY_PY_BUILTINS_MEMORYVIEW
 const mp_obj_type_t mp_type_memoryview = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,
     .name = MP_QSTR_memoryview,
     .make_new = memoryview_make_new,
     .getiter = array_iterator_new,
@@ -639,7 +644,7 @@ STATIC const mp_obj_type_t array_it_type = {
 STATIC mp_obj_t array_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf) {
     assert(sizeof(mp_obj_array_t) <= sizeof(mp_obj_iter_buf_t));
     mp_obj_array_t *array = MP_OBJ_TO_PTR(array_in);
-    mp_obj_array_it_t *o = (mp_obj_array_it_t*)iter_buf;
+    mp_obj_array_it_t *o = (mp_obj_array_it_t *)iter_buf;
     o->base.type = &array_it_type;
     o->array = array;
     o->offset = 0;

+ 10 - 0
py/objarray.h

@@ -49,4 +49,14 @@ typedef struct _mp_obj_array_t {
     void *items;
 } mp_obj_array_t;
 
+#if MICROPY_PY_BUILTINS_MEMORYVIEW
+static inline void mp_obj_memoryview_init(mp_obj_array_t *self, size_t typecode, size_t offset, size_t len, void *items) {
+    self->base.type = &mp_type_memoryview;
+    self->typecode = typecode;
+    self->free = offset;
+    self->len = len;
+    self->items = items;
+}
+#endif
+
 #endif // MICROPY_INCLUDED_PY_OBJARRAY_H

+ 2 - 2
py/objattrtuple.c

@@ -51,7 +51,7 @@ void mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields,
 STATIC void mp_obj_attrtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
     (void)kind;
     mp_obj_tuple_t *o = MP_OBJ_TO_PTR(o_in);
-    const qstr *fields = (const qstr*)MP_OBJ_TO_PTR(o->items[o->len]);
+    const qstr *fields = (const qstr *)MP_OBJ_TO_PTR(o->items[o->len]);
     mp_obj_attrtuple_print_helper(print, fields, o);
 }
 
@@ -60,7 +60,7 @@ STATIC void mp_obj_attrtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
         // load attribute
         mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in);
         size_t len = self->len;
-        const qstr *fields = (const qstr*)MP_OBJ_TO_PTR(self->items[len]);
+        const qstr *fields = (const qstr *)MP_OBJ_TO_PTR(self->items[len]);
         for (size_t i = 0; i < len; i++) {
             if (fields[i] == attr) {
                 dest[0] = self->items[i];

+ 20 - 7
py/objbool.c

@@ -28,21 +28,31 @@
 
 #include "py/runtime.h"
 
+#if MICROPY_OBJ_IMMEDIATE_OBJS
+
+#define BOOL_VALUE(o) ((o) == mp_const_false ? 0 : 1)
+
+#else
+
+#define BOOL_VALUE(o) (((mp_obj_bool_t *)MP_OBJ_TO_PTR(o))->value)
+
 typedef struct _mp_obj_bool_t {
     mp_obj_base_t base;
     bool value;
 } mp_obj_bool_t;
 
+#endif
+
 STATIC void bool_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
-    mp_obj_bool_t *self = MP_OBJ_TO_PTR(self_in);
+    bool value = BOOL_VALUE(self_in);
     if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
-        if (self->value) {
+        if (value) {
             mp_print_str(print, "true");
         } else {
             mp_print_str(print, "false");
         }
     } else {
-        if (self->value) {
+        if (value) {
             mp_print_str(print, "True");
         } else {
             mp_print_str(print, "False");
@@ -65,17 +75,18 @@ STATIC mp_obj_t bool_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
     if (op == MP_UNARY_OP_LEN) {
         return MP_OBJ_NULL;
     }
-    mp_obj_bool_t *self = MP_OBJ_TO_PTR(o_in);
-    return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(self->value));
+    bool value = BOOL_VALUE(o_in);
+    return mp_unary_op(op, MP_OBJ_NEW_SMALL_INT(value));
 }
 
 STATIC mp_obj_t bool_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
-    mp_obj_bool_t *self = MP_OBJ_TO_PTR(lhs_in);
-    return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(self->value), rhs_in);
+    bool value = BOOL_VALUE(lhs_in);
+    return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(value), rhs_in);
 }
 
 const mp_obj_type_t mp_type_bool = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE, // can match all numeric types
     .name = MP_QSTR_bool,
     .print = bool_print,
     .make_new = bool_make_new,
@@ -83,5 +94,7 @@ const mp_obj_type_t mp_type_bool = {
     .binary_op = bool_binary_op,
 };
 
+#if !MICROPY_OBJ_IMMEDIATE_OBJS
 const mp_obj_bool_t mp_const_false_obj = {{&mp_type_bool}, false};
 const mp_obj_bool_t mp_const_true_obj = {{&mp_type_bool}, true};
+#endif

+ 4 - 4
py/objboundmeth.c

@@ -98,13 +98,13 @@ STATIC void bound_meth_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
 STATIC const mp_obj_type_t mp_type_bound_meth = {
     { &mp_type_type },
     .name = MP_QSTR_bound_method,
-#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
+    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
     .print = bound_meth_print,
-#endif
+    #endif
     .call = bound_meth_call,
-#if MICROPY_PY_FUNCTION_ATTRS
+    #if MICROPY_PY_FUNCTION_ATTRS
     .attr = bound_meth_attr,
-#endif
+    #endif
 };
 
 mp_obj_t mp_obj_new_bound_meth(mp_obj_t meth, mp_obj_t self) {

+ 2 - 2
py/objcell.c

@@ -58,9 +58,9 @@ STATIC void cell_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t k
 STATIC const mp_obj_type_t mp_type_cell = {
     { &mp_type_type },
     .name = MP_QSTR_, // cell representation is just value in < >
-#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
+    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
     .print = cell_print,
-#endif
+    #endif
 };
 
 mp_obj_t mp_obj_new_cell(mp_obj_t obj) {

+ 3 - 2
py/objclosure.c

@@ -80,10 +80,11 @@ STATIC void closure_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_
 
 const mp_obj_type_t closure_type = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF,
     .name = MP_QSTR_closure,
-#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
+    #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
     .print = closure_print,
-#endif
+    #endif
     .call = closure_call,
 };
 

+ 27 - 17
py/objcomplex.c

@@ -45,17 +45,17 @@ typedef struct _mp_obj_complex_t {
 STATIC void complex_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
     (void)kind;
     mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in);
-#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
+    #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
     char buf[16];
     #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
     const int precision = 6;
     #else
     const int precision = 7;
     #endif
-#else
+    #else
     char buf[32];
     const int precision = 16;
-#endif
+    #endif
     if (o->real == 0) {
         mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0');
         mp_printf(print, "%sj", buf);
@@ -117,13 +117,18 @@ STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, si
 STATIC mp_obj_t complex_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
     mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in);
     switch (op) {
-        case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->real != 0 || o->imag != 0);
-        case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mp_float_hash(o->real) ^ mp_float_hash(o->imag));
-        case MP_UNARY_OP_POSITIVE: return o_in;
-        case MP_UNARY_OP_NEGATIVE: return mp_obj_new_complex(-o->real, -o->imag);
+        case MP_UNARY_OP_BOOL:
+            return mp_obj_new_bool(o->real != 0 || o->imag != 0);
+        case MP_UNARY_OP_HASH:
+            return MP_OBJ_NEW_SMALL_INT(mp_float_hash(o->real) ^ mp_float_hash(o->imag));
+        case MP_UNARY_OP_POSITIVE:
+            return o_in;
+        case MP_UNARY_OP_NEGATIVE:
+            return mp_obj_new_complex(-o->real, -o->imag);
         case MP_UNARY_OP_ABS:
-            return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(o->real*o->real + o->imag*o->imag));
-        default: return MP_OBJ_NULL; // op not supported
+            return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(o->real * o->real + o->imag * o->imag));
+        default:
+            return MP_OBJ_NULL;      // op not supported
     }
 }
 
@@ -147,6 +152,7 @@ STATIC void complex_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
 
 const mp_obj_type_t mp_type_complex = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_EQ_NOT_REFLEXIVE | MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,
     .name = MP_QSTR_complex,
     .print = complex_print,
     .make_new = complex_make_new,
@@ -172,7 +178,10 @@ 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(mp_binary_op_t op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in) {
     mp_float_t rhs_real, rhs_imag;
-    mp_obj_get_complex(rhs_in, &rhs_real, &rhs_imag); // can be any type, this function will convert to float (if possible)
+    if (!mp_obj_get_complex_maybe(rhs_in, &rhs_real, &rhs_imag)) {
+        return MP_OBJ_NULL; // op not supported
+    }
+
     switch (op) {
         case MP_BINARY_OP_ADD:
         case MP_BINARY_OP_INPLACE_ADD:
@@ -187,7 +196,7 @@ mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_flo
         case MP_BINARY_OP_MULTIPLY:
         case MP_BINARY_OP_INPLACE_MULTIPLY: {
             mp_float_t real;
-            multiply:
+        multiply:
             real = lhs_real * rhs_real - lhs_imag * rhs_imag;
             lhs_imag = lhs_real * rhs_imag + lhs_imag * rhs_real;
             lhs_real = real;
@@ -195,13 +204,13 @@ mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_flo
         }
         case MP_BINARY_OP_FLOOR_DIVIDE:
         case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:
-            mp_raise_TypeError("can't truncate-divide a complex number");
+            mp_raise_TypeError(MP_ERROR_TEXT("can't truncate-divide a complex number"));
 
         case MP_BINARY_OP_TRUE_DIVIDE:
         case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:
             if (rhs_imag == 0) {
                 if (rhs_real == 0) {
-                    mp_raise_msg(&mp_type_ZeroDivisionError, "complex divide by zero");
+                    mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("complex divide by zero"));
                 }
                 lhs_real /= rhs_real;
                 lhs_imag /= rhs_real;
@@ -210,7 +219,7 @@ mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_flo
                 lhs_imag = -lhs_real / rhs_imag;
                 lhs_real = real;
             } else {
-                mp_float_t rhs_len_sq = rhs_real*rhs_real + rhs_imag*rhs_imag;
+                mp_float_t rhs_len_sq = rhs_real * rhs_real + rhs_imag * rhs_imag;
                 rhs_real /= rhs_len_sq;
                 rhs_imag /= -rhs_len_sq;
                 goto multiply;
@@ -224,12 +233,12 @@ mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_flo
             //        = 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);
+            mp_float_t abs1 = MICROPY_FLOAT_C_FUN(sqrt)(lhs_real * lhs_real + lhs_imag * lhs_imag);
             if (abs1 == 0) {
                 if (rhs_imag == 0 && rhs_real >= 0) {
                     lhs_real = (rhs_real == 0);
                 } else {
-                    mp_raise_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power");
+                    mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("0.0 to a complex power"));
                 }
             } else {
                 mp_float_t ln1 = MICROPY_FLOAT_C_FUN(log)(abs1);
@@ -243,7 +252,8 @@ mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_flo
             break;
         }
 
-        case MP_BINARY_OP_EQUAL: return mp_obj_new_bool(lhs_real == rhs_real && lhs_imag == rhs_imag);
+        case MP_BINARY_OP_EQUAL:
+            return mp_obj_new_bool(lhs_real == rhs_real && lhs_imag == rhs_imag);
 
         default:
             return MP_OBJ_NULL; // op not supported

+ 3 - 3
py/objdeque.c

@@ -102,7 +102,7 @@ STATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) {
     }
 
     if (self->flags & FLAG_CHECK_OVERFLOW && new_i_put == self->i_get) {
-        mp_raise_msg(&mp_type_IndexError, "full");
+        mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("full"));
     }
 
     self->items[self->i_put] = arg;
@@ -122,7 +122,7 @@ STATIC mp_obj_t deque_popleft(mp_obj_t self_in) {
     mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
 
     if (self->i_get == self->i_put) {
-        mp_raise_msg(&mp_type_IndexError, "empty");
+        mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty"));
     }
 
     mp_obj_t ret = self->items[self->i_get];
@@ -161,7 +161,7 @@ const mp_obj_type_t mp_type_deque = {
     .name = MP_QSTR_deque,
     .make_new = deque_make_new,
     .unary_op = deque_unary_op,
-    .locals_dict = (mp_obj_dict_t*)&deque_locals_dict,
+    .locals_dict = (mp_obj_dict_t *)&deque_locals_dict,
 };
 
 #endif // MICROPY_PY_COLLECTIONS_DEQUE

+ 51 - 29
py/objdict.c

@@ -33,7 +33,17 @@
 #include "py/objtype.h"
 #include "py/objstr.h"
 
-#define mp_obj_is_dict_type(o) (mp_obj_is_obj(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new)
+const mp_obj_dict_t mp_const_empty_dict_obj = {
+    .base = { .type = &mp_type_dict },
+    .map = {
+        .all_keys_are_qstrs = 0,
+        .is_fixed = 1,
+        .is_ordered = 1,
+        .used = 0,
+        .alloc = 0,
+        .table = NULL,
+    }
+};
 
 STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
 
@@ -44,13 +54,15 @@ STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, size_t *cur) {
     size_t max = dict->map.alloc;
     mp_map_t *map = &dict->map;
 
-    for (size_t i = *cur; i < max; i++) {
+    size_t i = *cur;
+    for (; i < max; i++) {
         if (mp_map_slot_is_filled(map, i)) {
             *cur = i + 1;
             return &(map->table[i]);
         }
     }
 
+    assert(map->used == 0 || i == max);
     return NULL;
 }
 
@@ -88,7 +100,7 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
     }
 }
 
-STATIC mp_obj_t dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+mp_obj_t mp_obj_dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     mp_obj_t dict_out = mp_obj_new_dict(0);
     mp_obj_dict_t *dict = MP_OBJ_TO_PTR(dict_out);
     dict->base.type = type;
@@ -109,15 +121,18 @@ STATIC mp_obj_t dict_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
 STATIC mp_obj_t dict_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     switch (op) {
-        case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->map.used != 0);
-        case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->map.used);
+        case MP_UNARY_OP_BOOL:
+            return mp_obj_new_bool(self->map.used != 0);
+        case MP_UNARY_OP_LEN:
+            return MP_OBJ_NEW_SMALL_INT(self->map.used);
         #if MICROPY_PY_SYS_GETSIZEOF
         case MP_UNARY_OP_SIZEOF: {
             size_t sz = sizeof(*self) + sizeof(*self->map.table) * self->map.alloc;
             return MP_OBJ_NEW_SMALL_INT(sz);
         }
         #endif
-        default: return MP_OBJ_NULL; // op not supported
+        default:
+            return MP_OBJ_NULL;      // op not supported
     }
 }
 
@@ -141,8 +156,9 @@ STATIC mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_
                     }
                 }
                 return e1 == NULL && e2 == NULL ? mp_const_true : mp_const_false;
-            } else
+            }
             #endif
+
             if (mp_obj_is_type(rhs_in, &mp_type_dict)) {
                 mp_obj_dict_t *rhs = MP_OBJ_TO_PTR(rhs_in);
                 if (o->map.used != rhs->map.used) {
@@ -211,7 +227,7 @@ STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) {
 }
 
 STATIC mp_obj_t dict_clear(mp_obj_t self_in) {
-    mp_check_self(mp_obj_is_dict_type(self_in));
+    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     mp_ensure_not_fixed(self);
 
@@ -221,8 +237,8 @@ STATIC mp_obj_t dict_clear(mp_obj_t self_in) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_clear_obj, dict_clear);
 
-STATIC mp_obj_t dict_copy(mp_obj_t self_in) {
-    mp_check_self(mp_obj_is_dict_type(self_in));
+mp_obj_t mp_obj_dict_copy(mp_obj_t self_in) {
+    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     mp_obj_t other_out = mp_obj_new_dict(self->map.alloc);
     mp_obj_dict_t *other = MP_OBJ_TO_PTR(other_out);
@@ -234,7 +250,7 @@ STATIC mp_obj_t dict_copy(mp_obj_t self_in) {
     memcpy(other->map.table, self->map.table, self->map.alloc * sizeof(mp_map_elem_t));
     return other_out;
 }
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, mp_obj_dict_copy);
 
 #if MICROPY_PY_BUILTINS_DICT_FROMKEYS
 // this is a classmethod
@@ -269,7 +285,7 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromk
 #endif
 
 STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) {
-    mp_check_self(mp_obj_is_dict_type(args[0]));
+    mp_check_self(mp_obj_is_dict_or_ordereddict(args[0]));
     mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
     if (lookup_kind != MP_MAP_LOOKUP) {
         mp_ensure_not_fixed(self);
@@ -314,14 +330,20 @@ STATIC mp_obj_t dict_setdefault(size_t n_args, const mp_obj_t *args) {
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setdefault);
 
 STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
-    mp_check_self(mp_obj_is_dict_type(self_in));
+    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     mp_ensure_not_fixed(self);
+    if (self->map.used == 0) {
+        mp_raise_msg(&mp_type_KeyError, MP_ERROR_TEXT("popitem(): dictionary is empty"));
+    }
     size_t cur = 0;
-    mp_map_elem_t *next = dict_iter_next(self, &cur);
-    if (next == NULL) {
-        mp_raise_msg(&mp_type_KeyError, "popitem(): dictionary is empty");
+    #if MICROPY_PY_COLLECTIONS_ORDEREDDICT
+    if (self->map.is_ordered) {
+        cur = self->map.used - 1;
     }
+    #endif
+    mp_map_elem_t *next = dict_iter_next(self, &cur);
+    assert(next);
     self->map.used--;
     mp_obj_t items[] = {next->key, next->value};
     next->key = MP_OBJ_SENTINEL; // must mark key as sentinel to indicate that it was deleted
@@ -333,7 +355,7 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);
 
 STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
-    mp_check_self(mp_obj_is_dict_type(args[0]));
+    mp_check_self(mp_obj_is_dict_or_ordereddict(args[0]));
     mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
     mp_ensure_not_fixed(self);
 
@@ -342,12 +364,12 @@ STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwarg
     if (n_args == 2) {
         // given a positional argument
 
-        if (mp_obj_is_dict_type(args[1])) {
+        if (mp_obj_is_dict_or_ordereddict(args[1])) {
             // update from other dictionary (make sure other is not self)
             if (args[1] != args[0]) {
                 size_t cur = 0;
                 mp_map_elem_t *elem = NULL;
-                while ((elem = dict_iter_next((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[1]), &cur)) != NULL) {
+                while ((elem = dict_iter_next((mp_obj_dict_t *)MP_OBJ_TO_PTR(args[1]), &cur)) != NULL) {
                     mp_map_lookup(&self->map, elem->key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = elem->value;
                 }
             }
@@ -363,7 +385,7 @@ STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwarg
                 if (key == MP_OBJ_STOP_ITERATION
                     || value == MP_OBJ_STOP_ITERATION
                     || stop != MP_OBJ_STOP_ITERATION) {
-                    mp_raise_ValueError("dict update sequence has wrong length");
+                    mp_raise_ValueError(MP_ERROR_TEXT("dict update sequence has wrong length"));
                 } else {
                     mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
                 }
@@ -443,7 +465,7 @@ STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in, mp_obj_iter_buf_t *iter_buf)
     assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t));
     mp_check_self(mp_obj_is_type(view_in, &dict_view_type));
     mp_obj_dict_view_t *view = MP_OBJ_TO_PTR(view_in);
-    mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t*)iter_buf;
+    mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t *)iter_buf;
     o->base.type = &dict_view_it_type;
     o->kind = view->kind;
     o->dict = view->dict;
@@ -500,7 +522,7 @@ STATIC mp_obj_t mp_obj_new_dict_view(mp_obj_t dict, mp_dict_view_kind_t kind) {
 }
 
 STATIC mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) {
-    mp_check_self(mp_obj_is_dict_type(self_in));
+    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     return mp_obj_new_dict_view(self_in, kind);
 }
 
@@ -524,8 +546,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values);
 
 STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
     assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t));
-    mp_check_self(mp_obj_is_dict_type(self_in));
-    mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t*)iter_buf;
+    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
+    mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t *)iter_buf;
     o->base.type = &dict_view_it_type;
     o->kind = MP_DICT_VIEW_KEYS;
     o->dict = self_in;
@@ -561,12 +583,12 @@ const mp_obj_type_t mp_type_dict = {
     { &mp_type_type },
     .name = MP_QSTR_dict,
     .print = dict_print,
-    .make_new = dict_make_new,
+    .make_new = mp_obj_dict_make_new,
     .unary_op = dict_unary_op,
     .binary_op = dict_binary_op,
     .subscr = dict_subscr,
     .getiter = dict_getiter,
-    .locals_dict = (mp_obj_dict_t*)&dict_locals_dict,
+    .locals_dict = (mp_obj_dict_t *)&dict_locals_dict,
 };
 
 #if MICROPY_PY_COLLECTIONS_ORDEREDDICT
@@ -574,13 +596,13 @@ const mp_obj_type_t mp_type_ordereddict = {
     { &mp_type_type },
     .name = MP_QSTR_OrderedDict,
     .print = dict_print,
-    .make_new = dict_make_new,
+    .make_new = mp_obj_dict_make_new,
     .unary_op = dict_unary_op,
     .binary_op = dict_binary_op,
     .subscr = dict_subscr,
     .getiter = dict_getiter,
     .parent = &mp_type_dict,
-    .locals_dict = (mp_obj_dict_t*)&dict_locals_dict,
+    .locals_dict = (mp_obj_dict_t *)&dict_locals_dict,
 };
 #endif
 
@@ -601,7 +623,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) {
 }
 
 mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
-    mp_check_self(mp_obj_is_dict_type(self_in));
+    mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
     mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
     mp_ensure_not_fixed(self);
     mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;

+ 4 - 4
py/objenumerate.c

@@ -40,7 +40,7 @@ typedef struct _mp_obj_enumerate_t {
 STATIC mp_obj_t enumerate_iternext(mp_obj_t self_in);
 
 STATIC mp_obj_t enumerate_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
-#if MICROPY_CPYTHON_COMPAT
+    #if MICROPY_CPYTHON_COMPAT
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_iterable, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
         { MP_QSTR_start, MP_ARG_INT, {.u_int = 0} },
@@ -51,20 +51,20 @@ STATIC mp_obj_t enumerate_make_new(const mp_obj_type_t *type, size_t n_args, siz
         mp_arg_val_t iterable, start;
     } arg_vals;
     mp_arg_parse_all_kw_array(n_args, n_kw, args,
-        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&arg_vals);
+        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&arg_vals);
 
     // create enumerate object
     mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t);
     o->base.type = type;
     o->iter = mp_getiter(arg_vals.iterable.u_obj, NULL);
     o->cur = arg_vals.start.u_int;
-#else
+    #else
     mp_arg_check_num(n_args, n_kw, 1, 2, false);
     mp_obj_enumerate_t *o = m_new_obj(mp_obj_enumerate_t);
     o->base.type = type;
     o->iter = mp_getiter(args[0], NULL);
     o->cur = n_args > 1 ? mp_obj_get_int(args[1]) : 0;
-#endif
+    #endif
 
     return MP_OBJ_FROM_PTR(o);
 }

+ 114 - 39
py/objexcept.c

@@ -38,6 +38,16 @@
 #include "py/gc.h"
 #include "py/mperrno.h"
 
+#if MICROPY_ROM_TEXT_COMPRESSION && !defined(NO_QSTR)
+// Extract the MP_MAX_UNCOMPRESSED_TEXT_LEN macro from "genhdr/compressed.data.h".
+// Only need this if compression enabled and in a regular build (i.e. not during QSTR extraction).
+#define MP_MATCH_COMPRESSED(...) // Ignore
+#define MP_COMPRESSED_DATA(...) // Ignore
+#include "genhdr/compressed.data.h"
+#undef MP_MATCH_COMPRESSED
+#undef MP_COMPRESSED_DATA
+#endif
+
 // Number of items per traceback entry (file, line, block)
 #define TRACEBACK_ENTRY_LEN (3)
 
@@ -57,8 +67,9 @@
 #define EMG_BUF_TUPLE_OFFSET        (EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE)
 #define EMG_BUF_TUPLE_SIZE(n_args)  (sizeof(mp_obj_tuple_t) + n_args * sizeof(mp_obj_t))
 #define EMG_BUF_STR_OFFSET          (EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(1))
+#define EMG_BUF_STR_BUF_OFFSET      (EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t))
 
-#   if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0
+#if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0
 #define mp_emergency_exception_buf_size MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
 
 void mp_init_emergency_exception_buf(void) {
@@ -100,6 +111,40 @@ mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {
 #endif
 #endif  // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
 
+STATIC void decompress_error_text_maybe(mp_obj_exception_t *o) {
+    #if MICROPY_ROM_TEXT_COMPRESSION
+    if (o->args->len == 1 && mp_obj_is_type(o->args->items[0], &mp_type_str)) {
+        mp_obj_str_t *o_str = MP_OBJ_TO_PTR(o->args->items[0]);
+        if (MP_IS_COMPRESSED_ROM_STRING(o_str->data)) {
+            byte *buf = m_new_maybe(byte, MP_MAX_UNCOMPRESSED_TEXT_LEN + 1);
+            if (!buf) {
+                #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
+                // Try and use the emergency exception buf if enough space is available.
+                buf = (byte *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_STR_BUF_OFFSET);
+                size_t avail = (uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - buf;
+                if (avail < MP_MAX_UNCOMPRESSED_TEXT_LEN + 1) {
+                    // No way to decompress, fallback to no message text.
+                    o->args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;
+                    return;
+                }
+                #else
+                o->args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;
+                return;
+                #endif
+            }
+            mp_decompress_rom_string(buf, (mp_rom_error_text_t)o_str->data);
+            o_str->data = buf;
+            o_str->len = strlen((const char *)buf);
+            o_str->hash = 0;
+        }
+        // Lazily compute the string hash.
+        if (o_str->hash == 0) {
+            o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
+        }
+    }
+    #endif
+}
+
 void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
     mp_obj_exception_t *o = MP_OBJ_TO_PTR(o_in);
     mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS;
@@ -112,6 +157,8 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin
         mp_print_str(print, ": ");
     }
 
+    decompress_error_text_maybe(o);
+
     if (k == PRINT_STR || k == PRINT_EXC) {
         if (o->args == NULL || o->args->len == 0) {
             mp_print_str(print, "");
@@ -131,6 +178,7 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin
             return;
         }
     }
+
     mp_obj_tuple_print(print, MP_OBJ_FROM_PTR(o->args), kind);
 }
 
@@ -150,7 +198,7 @@ mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, siz
     mp_obj_tuple_t *o_tuple;
     if (n_args == 0) {
         // No args, can use the empty tuple straightaway
-        o_tuple = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj;
+        o_tuple = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;
     } else {
         // Try to allocate memory for the tuple containing the args
         o_tuple = m_new_obj_var_maybe(mp_obj_tuple_t, mp_obj_t, n_args);
@@ -160,15 +208,15 @@ mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, siz
         // reserved room (after the traceback data) for a tuple with 1 element.
         // Otherwise we are free to use the whole buffer after the traceback data.
         if (o_tuple == NULL && mp_emergency_exception_buf_size >=
-            EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(n_args)) {
-            o_tuple = (mp_obj_tuple_t*)
-                ((uint8_t*)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_TUPLE_OFFSET);
+            (mp_int_t)(EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(n_args))) {
+            o_tuple = (mp_obj_tuple_t *)
+                ((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_TUPLE_OFFSET);
         }
         #endif
 
         if (o_tuple == NULL) {
             // No memory for a tuple, fallback to an empty tuple
-            o_tuple = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj;
+            o_tuple = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj;
         } else {
             // Have memory for a tuple so populate it
             o_tuple->base.type = &mp_type_tuple;
@@ -189,6 +237,7 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) {
     if (self->args->len == 0) {
         return mp_const_none;
     } else {
+        decompress_error_text_maybe(self);
         return self->args->items[0];
     }
 }
@@ -210,6 +259,7 @@ void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
         return;
     }
     if (attr == MP_QSTR_args) {
+        decompress_error_text_maybe(self);
         dest[0] = MP_OBJ_FROM_PTR(self->args);
     } else if (self->base.type == &mp_type_StopIteration && attr == MP_QSTR_value) {
         dest[0] = mp_obj_exception_get_value(self_in);
@@ -224,6 +274,8 @@ const mp_obj_type_t mp_type_BaseException = {
     .attr = mp_obj_exception_attr,
 };
 
+// *FORMAT-OFF*
+
 // List of all exceptions, arranged as in the table at:
 // http://docs.python.org/3/library/exceptions.html
 MP_DEFINE_EXCEPTION(SystemExit, BaseException)
@@ -241,10 +293,8 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
   MP_DEFINE_EXCEPTION(AssertionError, Exception)
   MP_DEFINE_EXCEPTION(AttributeError, Exception)
   //MP_DEFINE_EXCEPTION(BufferError, Exception)
-  //MP_DEFINE_EXCEPTION(EnvironmentError, Exception) use OSError instead
   MP_DEFINE_EXCEPTION(EOFError, Exception)
   MP_DEFINE_EXCEPTION(ImportError, Exception)
-  //MP_DEFINE_EXCEPTION(IOError, Exception) use OSError instead
   MP_DEFINE_EXCEPTION(LookupError, Exception)
     MP_DEFINE_EXCEPTION(IndexError, LookupError)
     MP_DEFINE_EXCEPTION(KeyError, LookupError)
@@ -254,9 +304,6 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
     MP_DEFINE_EXCEPTION(UnboundLocalError, NameError)
     */
   MP_DEFINE_EXCEPTION(OSError, Exception)
-#if MICROPY_PY_BUILTINS_TIMEOUTERROR
-    MP_DEFINE_EXCEPTION(TimeoutError, OSError)
-#endif
     /*
     MP_DEFINE_EXCEPTION(BlockingIOError, OSError)
     MP_DEFINE_EXCEPTION(ChildProcessError, OSError)
@@ -270,6 +317,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
     MP_DEFINE_EXCEPTION(NotADirectoryError, OSError)
     MP_DEFINE_EXCEPTION(PermissionError, OSError)
     MP_DEFINE_EXCEPTION(ProcessLookupError, OSError)
+    MP_DEFINE_EXCEPTION(TimeoutError, OSError)
     MP_DEFINE_EXCEPTION(FileExistsError, OSError)
     MP_DEFINE_EXCEPTION(FileNotFoundError, OSError)
     MP_DEFINE_EXCEPTION(ReferenceError, Exception)
@@ -305,21 +353,25 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
     MP_DEFINE_EXCEPTION(ResourceWarning, Warning)
     */
 
+// *FORMAT-ON*
+
 mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type) {
-    return mp_obj_new_exception_args(exc_type, 0, NULL);
+    assert(exc_type->make_new == mp_obj_exception_make_new);
+    return mp_obj_exception_make_new(exc_type, 0, 0, NULL);
 }
 
 // "Optimized" version for common(?) case of having 1 exception arg
 mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) {
-    return mp_obj_new_exception_args(exc_type, 1, &arg);
+    assert(exc_type->make_new == mp_obj_exception_make_new);
+    return mp_obj_exception_make_new(exc_type, 1, 0, &arg);
 }
 
 mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args) {
     assert(exc_type->make_new == mp_obj_exception_make_new);
-    return exc_type->make_new(exc_type, n_args, 0, args);
+    return mp_obj_exception_make_new(exc_type, n_args, 0, args);
 }
 
-mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg) {
+mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg) {
     // Check that the given type is an exception type
     assert(exc_type->make_new == mp_obj_exception_make_new);
 
@@ -331,8 +383,8 @@ mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg
     // that buffer to store the string object, reserving room at the start for the
     // traceback and 1-tuple.
     if (o_str == NULL
-        && mp_emergency_exception_buf_size >= EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t)) {
-        o_str = (mp_obj_str_t*)((uint8_t*)MP_STATE_VM(mp_emergency_exception_buf)
+        && mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t))) {
+        o_str = (mp_obj_str_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf)
             + EMG_BUF_STR_OFFSET);
     }
     #endif
@@ -344,9 +396,13 @@ mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg
 
     // Create the string object and call mp_obj_exception_make_new to create the exception
     o_str->base.type = &mp_type_str;
-    o_str->len = strlen(msg);
-    o_str->data = (const byte*)msg;
+    o_str->len = strlen((const char *)msg);
+    o_str->data = (const byte *)msg;
+    #if MICROPY_ROM_TEXT_COMPRESSION
+    o_str->hash = 0; // will be computed only if string object is accessed
+    #else
     o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
+    #endif
     mp_obj_t arg = MP_OBJ_FROM_PTR(o_str);
     return mp_obj_exception_make_new(exc_type, 1, 0, &arg);
 }
@@ -384,7 +440,15 @@ STATIC void exc_add_strn(void *data, const char *str, size_t len) {
     pr->len += len;
 }
 
-mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) {
+mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    mp_obj_t exc = mp_obj_new_exception_msg_vlist(exc_type, fmt, args);
+    va_end(args);
+    return exc;
+}
+
+mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list args) {
     assert(fmt != NULL);
 
     // Check that the given type is an exception type
@@ -392,7 +456,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
 
     // Try to allocate memory for the message
     mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);
-    size_t o_str_alloc = strlen(fmt) + 1;
+    size_t o_str_alloc = strlen((const char *)fmt) + 1;
     byte *o_str_buf = m_new_maybe(byte, o_str_alloc);
 
     bool used_emg_buf = false;
@@ -401,34 +465,41 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
     // that buffer to store the string object and its data (at least 16 bytes for
     // the string data), reserving room at the start for the traceback and 1-tuple.
     if ((o_str == NULL || o_str_buf == NULL)
-        && mp_emergency_exception_buf_size >= EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t) + 16) {
+        && mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t) + 16)) {
         used_emg_buf = true;
-        o_str = (mp_obj_str_t*)((uint8_t*)MP_STATE_VM(mp_emergency_exception_buf)
-            + EMG_BUF_STR_OFFSET);
-        o_str_buf = (byte*)&o_str[1];
-        o_str_alloc = (uint8_t*)MP_STATE_VM(mp_emergency_exception_buf)
-            + mp_emergency_exception_buf_size - o_str_buf;
+        o_str = (mp_obj_str_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_STR_OFFSET);
+        o_str_buf = (byte *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_STR_BUF_OFFSET);
+        o_str_alloc = (uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - o_str_buf;
     }
     #endif
 
     if (o_str == NULL) {
-        // No memory for the string object so create the exception with no args
+        // No memory for the string object so create the exception with no args.
+        // The exception will only have a type and no message (compression is irrelevant).
         return mp_obj_exception_make_new(exc_type, 0, 0, NULL);
     }
 
     if (o_str_buf == NULL) {
         // No memory for the string buffer: assume that the fmt string is in ROM
-        // and use that data as the data of the string
+        // and use that data as the data of the string.
+        // The string will point directly to the compressed data -- will need to be decompressed
+        // prior to display (this case is identical to mp_obj_new_exception_msg above).
         o_str->len = o_str_alloc - 1; // will be equal to strlen(fmt)
-        o_str->data = (const byte*)fmt;
+        o_str->data = (const byte *)fmt;
     } else {
-        // We have some memory to format the string
+        // We have some memory to format the string.
+        // TODO: Optimise this to format-while-decompressing (and not require the temp stack space).
         struct _exc_printer_t exc_pr = {!used_emg_buf, o_str_alloc, 0, o_str_buf};
         mp_print_t print = {&exc_pr, exc_add_strn};
-        va_list ap;
-        va_start(ap, fmt);
-        mp_vprintf(&print, fmt, ap);
-        va_end(ap);
+        const char *fmt2 = (const char *)fmt;
+        #if MICROPY_ROM_TEXT_COMPRESSION
+        byte decompressed[MP_MAX_UNCOMPRESSED_TEXT_LEN];
+        if (MP_IS_COMPRESSED_ROM_STRING(fmt)) {
+            mp_decompress_rom_string(decompressed, fmt);
+            fmt2 = (const char *)decompressed;
+        }
+        #endif
+        mp_vprintf(&print, fmt2, args);
         exc_pr.buf[exc_pr.len] = '\0';
         o_str->len = exc_pr.len;
         o_str->data = exc_pr.buf;
@@ -436,7 +507,11 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
 
     // Create the string object and call mp_obj_exception_make_new to create the exception
     o_str->base.type = &mp_type_str;
+    #if MICROPY_ROM_TEXT_COMPRESSION
+    o_str->hash = 0; // will be computed only if string object is accessed
+    #else
     o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
+    #endif
     mp_obj_t arg = MP_OBJ_FROM_PTR(o_str);
     return mp_obj_exception_make_new(exc_type, 1, 0, &arg);
 }
@@ -478,7 +553,7 @@ bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type) {
     if (mp_obj_is_native_exception_instance(self_in)) { \
         self = MP_OBJ_TO_PTR(self_in); \
     } else { \
-        self = MP_OBJ_TO_PTR(((mp_obj_instance_t*)MP_OBJ_TO_PTR(self_in))->subobj[0]); \
+        self = MP_OBJ_TO_PTR(((mp_obj_instance_t *)MP_OBJ_TO_PTR(self_in))->subobj[0]); \
     }
 
 void mp_obj_exception_clear_traceback(mp_obj_t self_in) {
@@ -498,9 +573,9 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
         self->traceback_data = m_new_maybe(size_t, TRACEBACK_ENTRY_LEN);
         if (self->traceback_data == NULL) {
             #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
-            if (mp_emergency_exception_buf_size >= EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE) {
+            if (mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE)) {
                 // There is room in the emergency buffer for traceback data
-                size_t *tb = (size_t*)((uint8_t*)MP_STATE_VM(mp_emergency_exception_buf)
+                size_t *tb = (size_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf)
                     + EMG_BUF_TRACEBACK_OFFSET);
                 self->traceback_data = tb;
                 self->traceback_alloc = EMG_BUF_TRACEBACK_SIZE / sizeof(size_t);
@@ -519,7 +594,7 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs
         self->traceback_len = 0;
     } else if (self->traceback_len + TRACEBACK_ENTRY_LEN > self->traceback_alloc) {
         #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
-        if (self->traceback_data == (size_t*)MP_STATE_VM(mp_emergency_exception_buf)) {
+        if (self->traceback_data == (size_t *)MP_STATE_VM(mp_emergency_exception_buf)) {
             // Can't resize the emergency buffer
             return;
         }

+ 8 - 8
py/objexcept.h

@@ -41,13 +41,13 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin
 void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
 
 #define MP_DEFINE_EXCEPTION(exc_name, base_name) \
-const mp_obj_type_t mp_type_ ## exc_name = { \
-    { &mp_type_type }, \
-    .name = MP_QSTR_ ## exc_name, \
-    .print = mp_obj_exception_print, \
-    .make_new = mp_obj_exception_make_new, \
-    .attr = mp_obj_exception_attr, \
-    .parent = &mp_type_ ## base_name, \
-};
+    const mp_obj_type_t mp_type_##exc_name = { \
+        { &mp_type_type }, \
+        .name = MP_QSTR_##exc_name, \
+        .print = mp_obj_exception_print, \
+        .make_new = mp_obj_exception_make_new, \
+        .attr = mp_obj_exception_attr, \
+        .parent = &mp_type_##base_name, \
+    };
 
 #endif // MICROPY_INCLUDED_PY_OBJEXCEPT_H

+ 62 - 53
py/objfloat.c

@@ -52,29 +52,17 @@ typedef struct _mp_obj_float_t {
     mp_float_t value;
 } mp_obj_float_t;
 
-const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, M_E};
-const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, M_PI};
+const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, (mp_float_t)M_E};
+const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, (mp_float_t)M_PI};
 
 #endif
 
+#define MICROPY_FLOAT_ZERO MICROPY_FLOAT_CONST(0.0)
+
 #if MICROPY_FLOAT_HIGH_QUALITY_HASH
 // must return actual integer value if it fits in mp_int_t
 mp_int_t mp_float_hash(mp_float_t src) {
-#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
-typedef uint64_t mp_float_uint_t;
-#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
-typedef uint32_t mp_float_uint_t;
-#endif
-    union {
-        mp_float_t f;
-        #if MP_ENDIANNESS_LITTLE
-        struct { mp_float_uint_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p;
-        #else
-        struct { mp_float_uint_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p;
-        #endif
-        mp_float_uint_t i;
-    } u = {.f = src};
-
+    mp_float_union_t u = {.f = src};
     mp_int_t val;
     const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;
     if (adj_exp < 0) {
@@ -109,17 +97,17 @@ typedef uint32_t mp_float_uint_t;
 STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
     (void)kind;
     mp_float_t o_val = mp_obj_float_get(o_in);
-#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
+    #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
     char buf[16];
     #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
     const int precision = 6;
     #else
     const int precision = 7;
     #endif
-#else
+    #else
     char buf[32];
     const int precision = 16;
-#endif
+    #endif
     mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0');
     mp_print_str(print, buf);
     if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) {
@@ -156,10 +144,14 @@ STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size
 STATIC mp_obj_t float_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
     mp_float_t val = mp_obj_float_get(o_in);
     switch (op) {
-        case MP_UNARY_OP_BOOL: return mp_obj_new_bool(val != 0);
-        case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mp_float_hash(val));
-        case MP_UNARY_OP_POSITIVE: return o_in;
-        case MP_UNARY_OP_NEGATIVE: return mp_obj_new_float(-val);
+        case MP_UNARY_OP_BOOL:
+            return mp_obj_new_bool(val != 0);
+        case MP_UNARY_OP_HASH:
+            return MP_OBJ_NEW_SMALL_INT(mp_float_hash(val));
+        case MP_UNARY_OP_POSITIVE:
+            return o_in;
+        case MP_UNARY_OP_NEGATIVE:
+            return mp_obj_new_float(-val);
         case MP_UNARY_OP_ABS: {
             if (signbit(val)) {
                 return mp_obj_new_float(-val);
@@ -167,24 +159,24 @@ STATIC mp_obj_t float_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
                 return o_in;
             }
         }
-        default: return MP_OBJ_NULL; // op not supported
+        default:
+            return MP_OBJ_NULL;      // op not supported
     }
 }
 
 STATIC mp_obj_t float_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
     mp_float_t lhs_val = mp_obj_float_get(lhs_in);
-#if MICROPY_PY_BUILTINS_COMPLEX
+    #if MICROPY_PY_BUILTINS_COMPLEX
     if (mp_obj_is_type(rhs_in, &mp_type_complex)) {
         return mp_obj_complex_binary_op(op, lhs_val, 0, rhs_in);
-    } else
-#endif
-    {
-        return mp_obj_float_binary_op(op, lhs_val, rhs_in);
     }
+    #endif
+    return mp_obj_float_binary_op(op, lhs_val, rhs_in);
 }
 
 const mp_obj_type_t mp_type_float = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_EQ_NOT_REFLEXIVE | MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,
     .name = MP_QSTR_float,
     .print = float_print,
     .make_new = float_make_new,
@@ -218,24 +210,24 @@ STATIC void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) {
     mp_float_t div = (*x - mod) / *y;
 
     // Python specs require that mod has same sign as second operand
-    if (mod == 0.0) {
-        mod = MICROPY_FLOAT_C_FUN(copysign)(0.0, *y);
+    if (mod == MICROPY_FLOAT_ZERO) {
+        mod = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *y);
     } else {
-        if ((mod < 0.0) != (*y < 0.0)) {
+        if ((mod < MICROPY_FLOAT_ZERO) != (*y < MICROPY_FLOAT_ZERO)) {
             mod += *y;
-            div -= 1.0;
+            div -= MICROPY_FLOAT_CONST(1.0);
         }
     }
 
     mp_float_t floordiv;
-    if (div == 0.0) {
+    if (div == MICROPY_FLOAT_ZERO) {
         // if division is zero, take the correct sign of zero
-        floordiv = MICROPY_FLOAT_C_FUN(copysign)(0.0, *x / *y);
+        floordiv = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *x / *y);
     } else {
         // Python specs require that x == (x//y)*y + (x%y)
         floordiv = MICROPY_FLOAT_C_FUN(floor)(div);
-        if (div - floordiv > 0.5) {
-            floordiv += 1.0;
+        if (div - floordiv > MICROPY_FLOAT_CONST(0.5)) {
+            floordiv += MICROPY_FLOAT_CONST(1.0);
         }
     }
 
@@ -252,16 +244,22 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t
 
     switch (op) {
         case MP_BINARY_OP_ADD:
-        case MP_BINARY_OP_INPLACE_ADD: lhs_val += rhs_val; break;
+        case MP_BINARY_OP_INPLACE_ADD:
+            lhs_val += rhs_val;
+            break;
         case MP_BINARY_OP_SUBTRACT:
-        case MP_BINARY_OP_INPLACE_SUBTRACT: lhs_val -= rhs_val; break;
+        case MP_BINARY_OP_INPLACE_SUBTRACT:
+            lhs_val -= rhs_val;
+            break;
         case MP_BINARY_OP_MULTIPLY:
-        case MP_BINARY_OP_INPLACE_MULTIPLY: lhs_val *= rhs_val; break;
+        case MP_BINARY_OP_INPLACE_MULTIPLY:
+            lhs_val *= rhs_val;
+            break;
         case MP_BINARY_OP_FLOOR_DIVIDE:
         case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:
             if (rhs_val == 0) {
-                zero_division_error:
-                mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero");
+            zero_division_error:
+                mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero"));
             }
             // Python specs require that x == (x//y)*y + (x%y) so we must
             // call divmod to compute the correct floor division, which
@@ -277,15 +275,15 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t
             break;
         case MP_BINARY_OP_MODULO:
         case MP_BINARY_OP_INPLACE_MODULO:
-            if (rhs_val == 0) {
+            if (rhs_val == MICROPY_FLOAT_ZERO) {
                 goto zero_division_error;
             }
             lhs_val = MICROPY_FLOAT_C_FUN(fmod)(lhs_val, rhs_val);
             // Python specs require that mod has same sign as second operand
-            if (lhs_val == 0.0) {
+            if (lhs_val == MICROPY_FLOAT_ZERO) {
                 lhs_val = MICROPY_FLOAT_C_FUN(copysign)(0.0, rhs_val);
             } else {
-                if ((lhs_val < 0.0) != (rhs_val < 0.0)) {
+                if ((lhs_val < MICROPY_FLOAT_ZERO) != (rhs_val < MICROPY_FLOAT_ZERO)) {
                     lhs_val += rhs_val;
                 }
             }
@@ -295,13 +293,19 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t
             if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) {
                 goto zero_division_error;
             }
-            if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val)) {
+            if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val) && !isnan(rhs_val)) {
                 #if MICROPY_PY_BUILTINS_COMPLEX
                 return mp_obj_complex_binary_op(MP_BINARY_OP_POWER, lhs_val, 0, rhs_in);
                 #else
-                mp_raise_ValueError("complex values not supported");
+                mp_raise_ValueError(MP_ERROR_TEXT("complex values not supported"));
                 #endif
             }
+            #if MICROPY_PY_MATH_POW_FIX_NAN // Also see modmath.c.
+            if (lhs_val == MICROPY_FLOAT_CONST(1.0) || rhs_val == MICROPY_FLOAT_CONST(0.0)) {
+                lhs_val = MICROPY_FLOAT_CONST(1.0);
+                break;
+            }
+            #endif
             lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val);
             break;
         case MP_BINARY_OP_DIVMOD: {
@@ -315,11 +319,16 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t
             };
             return mp_obj_new_tuple(2, tuple);
         }
-        case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val);
-        case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val);
-        case MP_BINARY_OP_EQUAL: return mp_obj_new_bool(lhs_val == rhs_val);
-        case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val);
-        case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val);
+        case MP_BINARY_OP_LESS:
+            return mp_obj_new_bool(lhs_val < rhs_val);
+        case MP_BINARY_OP_MORE:
+            return mp_obj_new_bool(lhs_val > rhs_val);
+        case MP_BINARY_OP_EQUAL:
+            return mp_obj_new_bool(lhs_val == rhs_val);
+        case MP_BINARY_OP_LESS_EQUAL:
+            return mp_obj_new_bool(lhs_val <= rhs_val);
+        case MP_BINARY_OP_MORE_EQUAL:
+            return mp_obj_new_bool(lhs_val >= rhs_val);
 
         default:
             return MP_OBJ_NULL; // op not supported

+ 21 - 13
py/objfun.c

@@ -58,6 +58,7 @@ STATIC mp_obj_t fun_builtin_0_call(mp_obj_t self_in, size_t n_args, size_t n_kw,
 
 const mp_obj_type_t mp_type_fun_builtin_0 = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,
     .name = MP_QSTR_function,
     .call = fun_builtin_0_call,
     .unary_op = mp_generic_unary_op,
@@ -72,6 +73,7 @@ STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw,
 
 const mp_obj_type_t mp_type_fun_builtin_1 = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,
     .name = MP_QSTR_function,
     .call = fun_builtin_1_call,
     .unary_op = mp_generic_unary_op,
@@ -86,6 +88,7 @@ STATIC mp_obj_t fun_builtin_2_call(mp_obj_t self_in, size_t n_args, size_t n_kw,
 
 const mp_obj_type_t mp_type_fun_builtin_2 = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,
     .name = MP_QSTR_function,
     .call = fun_builtin_2_call,
     .unary_op = mp_generic_unary_op,
@@ -100,6 +103,7 @@ STATIC mp_obj_t fun_builtin_3_call(mp_obj_t self_in, size_t n_args, size_t n_kw,
 
 const mp_obj_type_t mp_type_fun_builtin_3 = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,
     .name = MP_QSTR_function,
     .call = fun_builtin_3_call,
     .unary_op = mp_generic_unary_op,
@@ -130,6 +134,7 @@ STATIC mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_k
 
 const mp_obj_type_t mp_type_fun_builtin_var = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_BUILTIN_FUN,
     .name = MP_QSTR_function,
     .call = fun_builtin_var_call,
     .unary_op = mp_generic_unary_op,
@@ -188,7 +193,7 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) {
 // With this macro you can tune the maximum number of function state bytes
 // that will be allocated on the stack.  Any function that needs more
 // than this will try to use the heap, with fallback to stack allocation.
-#define VM_MAX_STATE_ON_STACK (11 * sizeof(mp_uint_t))
+#define VM_MAX_STATE_ON_STACK (sizeof(mp_uint_t) * 11)
 
 #define DECODE_CODESTATE_SIZE(bytecode, n_state_out_var, state_size_out_var) \
     { \
@@ -198,7 +203,7 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) {
                                     \
         /* state size in bytes */                                                 \
         state_size_out_var = n_state_out_var * sizeof(mp_obj_t)                   \
-                           + n_exc_stack * sizeof(mp_exc_stack_t);                \
+            + n_exc_stack * sizeof(mp_exc_stack_t);                \
     }
 
 #define INIT_CODESTATE(code_state, _fun_bc, _n_state, n_args, n_kw, args) \
@@ -355,15 +360,16 @@ void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
 
 const mp_obj_type_t mp_type_fun_bc = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF,
     .name = MP_QSTR_function,
-#if MICROPY_CPYTHON_COMPAT
+    #if MICROPY_CPYTHON_COMPAT
     .print = fun_bc_print,
-#endif
+    #endif
     .call = fun_bc_call,
     .unary_op = mp_generic_unary_op,
-#if MICROPY_PY_FUNCTION_ATTRS
+    #if MICROPY_PY_FUNCTION_ATTRS
     .attr = mp_obj_fun_bc_attr,
-#endif
+    #endif
 };
 
 mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table) {
@@ -400,19 +406,20 @@ mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args_in, mp_obj_t def_kw_args, const byt
 STATIC mp_obj_t fun_native_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     MP_STACK_CHECK();
     mp_obj_fun_bc_t *self = self_in;
-    mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void*)self->bytecode);
+    mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void *)self->bytecode);
     return fun(self_in, n_args, n_kw, args);
 }
 
 STATIC const mp_obj_type_t mp_type_fun_native = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF,
     .name = MP_QSTR_function,
     .call = fun_native_call,
     .unary_op = mp_generic_unary_op,
 };
 
 mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table) {
-    mp_obj_fun_bc_t *o = mp_obj_new_fun_bc(def_args_in, def_kw_args, (const byte*)fun_data, const_table);
+    mp_obj_fun_bc_t *o = mp_obj_new_fun_bc(def_args_in, def_kw_args, (const byte *)fun_data, const_table);
     o->base.type = &mp_type_fun_native;
     return o;
 }
@@ -455,13 +462,13 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
         size_t l;
         return (mp_uint_t)mp_obj_str_get_data(obj, &l);
     } else {
-        mp_obj_type_t *type = mp_obj_get_type(obj);
-#if MICROPY_PY_BUILTINS_FLOAT
+        const mp_obj_type_t *type = mp_obj_get_type(obj);
+        #if MICROPY_PY_BUILTINS_FLOAT
         if (type == &mp_type_float) {
             // convert float to int (could also pass in float registers)
             return (mp_int_t)mp_obj_float_get(obj);
-        } else
-#endif
+        }
+        #endif
         if (type == &mp_type_tuple || type == &mp_type_list) {
             // pointer to start of tuple (could pass length, but then could use len(x) for that)
             size_t len;
@@ -505,7 +512,7 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
             convert_obj_for_inline_asm(args[1]),
             convert_obj_for_inline_asm(args[2]),
             convert_obj_for_inline_asm(args[3])
-        );
+            );
     }
 
     return mp_native_to_obj(ret, self->type_sig);
@@ -513,6 +520,7 @@ STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
 
 STATIC const mp_obj_type_t mp_type_fun_asm = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF,
     .name = MP_QSTR_function,
     .call = fun_asm_call,
     .unary_op = mp_generic_unary_op,

+ 20 - 18
py/objgenerator.c

@@ -36,7 +36,7 @@
 #include "py/stackctrl.h"
 
 // Instance of GeneratorExit exception - needed by generator.close()
-const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj};
+const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t *)&mp_const_empty_tuple_obj};
 
 /******************************************************************************/
 /* generator wrapper                                                          */
@@ -73,6 +73,7 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons
 
 const mp_obj_type_t mp_type_gen_wrap = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF,
     .name = MP_QSTR_generator,
     .call = gen_wrap_call,
     .unary_op = mp_generic_unary_op,
@@ -91,11 +92,11 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k
     mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in);
 
     // Determine start of prelude, and extract n_state from it
-    uintptr_t prelude_offset = ((uintptr_t*)self_fun->bytecode)[0];
+    uintptr_t prelude_offset = ((uintptr_t *)self_fun->bytecode)[0];
     #if MICROPY_EMIT_NATIVE_PRELUDE_AS_BYTES_OBJ
     // Prelude is in bytes object in const_table, at index prelude_offset
     mp_obj_str_t *prelude_bytes = MP_OBJ_TO_PTR(self_fun->const_table[prelude_offset]);
-    prelude_offset = (const byte*)prelude_bytes->data - self_fun->bytecode;
+    prelude_offset = (const byte *)prelude_bytes->data - self_fun->bytecode;
     #endif
     const uint8_t *ip = self_fun->bytecode + prelude_offset;
     size_t n_state, n_exc_stack_unused, scope_flags, n_pos_args, n_kwonly_args, n_def_args;
@@ -110,7 +111,7 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k
     // Parse the input arguments and set up the code state
     o->pend_exc = mp_const_none;
     o->code_state.fun_bc = self_fun;
-    o->code_state.ip = (const byte*)prelude_offset;
+    o->code_state.ip = (const byte *)prelude_offset;
     o->code_state.n_state = n_state;
     mp_setup_code_state(&o->code_state, n_args, n_kw, args);
 
@@ -118,14 +119,15 @@ STATIC mp_obj_t native_gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_k
     o->code_state.exc_sp_idx = MP_CODE_STATE_EXC_SP_IDX_SENTINEL;
 
     // Prepare the generator instance for execution
-    uintptr_t start_offset = ((uintptr_t*)self_fun->bytecode)[1];
-    o->code_state.ip = MICROPY_MAKE_POINTER_CALLABLE((void*)(self_fun->bytecode + start_offset));
+    uintptr_t start_offset = ((uintptr_t *)self_fun->bytecode)[1];
+    o->code_state.ip = MICROPY_MAKE_POINTER_CALLABLE((void *)(self_fun->bytecode + start_offset));
 
     return MP_OBJ_FROM_PTR(o);
 }
 
 const mp_obj_type_t mp_type_native_gen_wrap = {
     { &mp_type_type },
+    .flags = MP_TYPE_FLAG_BINDS_SELF,
     .name = MP_QSTR_generator,
     .call = native_gen_wrap_call,
     .unary_op = mp_generic_unary_op,
@@ -157,7 +159,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
 
     // Ensure the generator cannot be reentered during execution
     if (self->pend_exc == MP_OBJ_NULL) {
-        mp_raise_ValueError("generator already executing");
+        mp_raise_ValueError(MP_ERROR_TEXT("generator already executing"));
     }
 
     #if MICROPY_PY_GENERATOR_PEND_THROW
@@ -170,7 +172,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
     // If the generator is started, allow sending a value.
     if (self->code_state.sp == self->code_state.state - 1) {
         if (send_value != mp_const_none) {
-            mp_raise_TypeError("can't send non-None value to a just-started generator");
+            mp_raise_TypeError(MP_ERROR_TEXT("can't send non-None value to a just-started generator"));
         }
     } else {
         *self->code_state.sp = send_value;
@@ -188,9 +190,9 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
     #if MICROPY_EMIT_NATIVE
     if (self->code_state.exc_sp_idx == MP_CODE_STATE_EXC_SP_IDX_SENTINEL) {
         // A native generator, with entry point 2 words into the "bytecode" pointer
-        typedef uintptr_t (*mp_fun_native_gen_t)(void*, mp_obj_t);
-        mp_fun_native_gen_t fun = MICROPY_MAKE_POINTER_CALLABLE((const void*)(self->code_state.fun_bc->bytecode + 2 * sizeof(uintptr_t)));
-        ret_kind = fun((void*)&self->code_state, throw_value);
+        typedef uintptr_t (*mp_fun_native_gen_t)(void *, mp_obj_t);
+        mp_fun_native_gen_t fun = MICROPY_MAKE_POINTER_CALLABLE((const void *)(self->code_state.fun_bc->bytecode + 2 * sizeof(uintptr_t)));
+        ret_kind = fun((void *)&self->code_state, throw_value);
     } else
     #endif
     {
@@ -225,7 +227,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
             *ret_val = self->code_state.state[0];
             // PEP479: if StopIteration is raised inside a generator it is replaced with RuntimeError
             if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(*ret_val)), MP_OBJ_FROM_PTR(&mp_type_StopIteration))) {
-                *ret_val = mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator raised StopIteration");
+                *ret_val = mp_obj_new_exception_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("generator raised StopIteration"));
             }
             break;
         }
@@ -243,7 +245,7 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o
             if (ret == mp_const_none || ret == MP_OBJ_STOP_ITERATION) {
                 return MP_OBJ_STOP_ITERATION;
             } else {
-                nlr_raise(mp_obj_new_exception_args(&mp_type_StopIteration, 1, &ret));
+                nlr_raise(mp_obj_new_exception_arg1(&mp_type_StopIteration, ret));
             }
 
         case MP_VM_RETURN_YIELD:
@@ -261,7 +263,7 @@ STATIC mp_obj_t gen_instance_iternext(mp_obj_t self_in) {
 STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) {
     mp_obj_t ret = gen_resume_and_raise(self_in, send_value, MP_OBJ_NULL);
     if (ret == MP_OBJ_STOP_ITERATION) {
-        nlr_raise(mp_obj_new_exception(&mp_type_StopIteration));
+        mp_raise_type(&mp_type_StopIteration);
     } else {
         return ret;
     }
@@ -288,7 +290,7 @@ STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) {
 
     mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc);
     if (ret == MP_OBJ_STOP_ITERATION) {
-        nlr_raise(mp_obj_new_exception(&mp_type_StopIteration));
+        mp_raise_type(&mp_type_StopIteration);
     } else {
         return ret;
     }
@@ -299,7 +301,7 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) {
     mp_obj_t ret;
     switch (mp_obj_gen_resume(self_in, mp_const_none, MP_OBJ_FROM_PTR(&mp_const_GeneratorExit_obj), &ret)) {
         case MP_VM_RETURN_YIELD:
-            mp_raise_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit");
+            mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("generator ignored GeneratorExit"));
 
         // Swallow GeneratorExit (== successful close), and re-raise any other
         case MP_VM_RETURN_EXCEPTION:
@@ -320,7 +322,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close);
 STATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) {
     mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
     if (self->pend_exc == MP_OBJ_NULL) {
-        mp_raise_ValueError("generator already executing");
+        mp_raise_ValueError(MP_ERROR_TEXT("generator already executing"));
     }
     mp_obj_t prev = self->pend_exc;
     self->pend_exc = exc_in;
@@ -347,5 +349,5 @@ const mp_obj_type_t mp_type_gen_instance = {
     .unary_op = mp_generic_unary_op,
     .getiter = mp_identity_getiter,
     .iternext = gen_instance_iternext,
-    .locals_dict = (mp_obj_dict_t*)&gen_instance_locals_dict,
+    .locals_dict = (mp_obj_dict_t *)&gen_instance_locals_dict,
 };

+ 2 - 2
py/objgetitemiter.c

@@ -46,7 +46,7 @@ STATIC mp_obj_t it_iternext(mp_obj_t self_in) {
         return value;
     } else {
         // an exception was raised
-        mp_obj_type_t *t = (mp_obj_type_t*)((mp_obj_base_t*)nlr.ret_val)->type;
+        mp_obj_type_t *t = (mp_obj_type_t *)((mp_obj_base_t *)nlr.ret_val)->type;
         if (t == &mp_type_StopIteration || t == &mp_type_IndexError) {
             // return MP_OBJ_STOP_ITERATION instead of raising
             return MP_OBJ_STOP_ITERATION;
@@ -67,7 +67,7 @@ STATIC const mp_obj_type_t it_type = {
 // args are those returned from mp_load_method_maybe (ie either an attribute or a method)
 mp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf) {
     assert(sizeof(mp_obj_getitem_iter_t) <= sizeof(mp_obj_iter_buf_t));
-    mp_obj_getitem_iter_t *o = (mp_obj_getitem_iter_t*)iter_buf;
+    mp_obj_getitem_iter_t *o = (mp_obj_getitem_iter_t *)iter_buf;
     o->base.type = &it_type;
     o->args[0] = args[0];
     o->args[1] = args[1];

+ 34 - 30
py/objint.c

@@ -57,10 +57,10 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args,
                 size_t l;
                 const char *s = mp_obj_str_get_data(args[0], &l);
                 return mp_parse_num_integer(s, l, 0, NULL);
-#if MICROPY_PY_BUILTINS_FLOAT
+            #if MICROPY_PY_BUILTINS_FLOAT
             } else if (mp_obj_is_float(args[0])) {
                 return mp_obj_new_int_from_float(mp_obj_float_get(args[0]));
-#endif
+            #endif
             } else {
                 return mp_unary_op(MP_UNARY_OP_INT, args[0]);
             }
@@ -86,26 +86,26 @@ typedef enum {
 STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) {
     union {
         mp_float_t f;
-#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
+        #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
         uint32_t i;
-#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
+        #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
         uint32_t i[2];
-#endif
+        #endif
     } u = {val};
 
     uint32_t e;
-#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
+    #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
     e = u.i;
-#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
+    #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
     e = u.i[MP_ENDIANNESS_LITTLE];
-#endif
+    #endif
 #define MP_FLOAT_SIGN_SHIFT_I32 ((MP_FLOAT_FRAC_BITS + MP_FLOAT_EXP_BITS) % 32)
 #define MP_FLOAT_EXP_SHIFT_I32 (MP_FLOAT_FRAC_BITS % 32)
 
     if (e & (1U << MP_FLOAT_SIGN_SHIFT_I32)) {
-#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
+        #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
         e |= u.i[MP_ENDIANNESS_BIG] != 0;
-#endif
+        #endif
         if ((e & ~(1 << MP_FLOAT_SIGN_SHIFT_I32)) == 0) {
             // handle case of -0 (when sign is set but rest of bits are zero)
             e = 0;
@@ -120,26 +120,30 @@ STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) {
     if (e <= ((8 * sizeof(uintptr_t) + MP_FLOAT_EXP_BIAS - 3) << MP_FLOAT_EXP_SHIFT_I32)) {
         return MP_FP_CLASS_FIT_SMALLINT;
     }
-#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
+    #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
     if (e <= (((sizeof(long long) * BITS_PER_BYTE) + MP_FLOAT_EXP_BIAS - 2) << MP_FLOAT_EXP_SHIFT_I32)) {
         return MP_FP_CLASS_FIT_LONGINT;
     }
-#endif
-#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
+    #endif
+    #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
     return MP_FP_CLASS_FIT_LONGINT;
-#else
+    #else
     return MP_FP_CLASS_OVERFLOW;
-#endif
+    #endif
 }
 #undef MP_FLOAT_SIGN_SHIFT_I32
 #undef MP_FLOAT_EXP_SHIFT_I32
 
 mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
-    int cl = fpclassify(val);
-    if (cl == FP_INFINITE) {
-        mp_raise_msg(&mp_type_OverflowError, "can't convert inf to int");
-    } else if (cl == FP_NAN) {
-        mp_raise_ValueError("can't convert NaN to int");
+    mp_float_union_t u = {val};
+    // IEEE-754: if biased exponent is all 1 bits...
+    if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) {
+        // ...then number is Inf (positive or negative) if fraction is 0, else NaN.
+        if (u.p.frc == 0) {
+            mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("can't convert inf to int"));
+        } else {
+            mp_raise_ValueError(MP_ERROR_TEXT("can't convert NaN to int"));
+        }
     } else {
         mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val);
         if (icl == MP_FP_CLASS_FIT_SMALLINT) {
@@ -156,7 +160,7 @@ mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
             return mp_obj_new_int_from_ll((long long)val);
         #endif
         } else {
-            mp_raise_ValueError("float too big");
+            mp_raise_ValueError(MP_ERROR_TEXT("float too big"));
         }
         #endif
     }
@@ -218,7 +222,7 @@ size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char co
 // The resulting formatted string will be returned from this function and the
 // formatted size will be in *fmt_size.
 char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,
-                           int base, const char *prefix, char base_char, char comma) {
+    int base, const char *prefix, char base_char, char comma) {
     fmt_int_t num;
     #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
     // Only have small ints; get the integer value to format.
@@ -321,19 +325,19 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
 
 // This is called only with strings whose value doesn't fit in SMALL_INT
 mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) {
-    mp_raise_msg(&mp_type_OverflowError, "long int not supported in this build");
+    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("long int not supported in this build"));
     return mp_const_none;
 }
 
 // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT)
 mp_obj_t mp_obj_new_int_from_ll(long long val) {
-    mp_raise_msg(&mp_type_OverflowError, "small int overflow");
+    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow"));
     return mp_const_none;
 }
 
 // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT)
 mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) {
-    mp_raise_msg(&mp_type_OverflowError, "small int overflow");
+    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow"));
     return mp_const_none;
 }
 
@@ -343,7 +347,7 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
     if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) {
         return MP_OBJ_NEW_SMALL_INT(value);
     }
-    mp_raise_msg(&mp_type_OverflowError, "small int overflow");
+    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow"));
     return mp_const_none;
 }
 
@@ -351,7 +355,7 @@ mp_obj_t mp_obj_new_int(mp_int_t value) {
     if (MP_SMALL_INT_FITS(value)) {
         return MP_OBJ_NEW_SMALL_INT(value);
     }
-    mp_raise_msg(&mp_type_OverflowError, "small int overflow");
+    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow"));
     return mp_const_none;
 }
 
@@ -392,7 +396,7 @@ STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {
     mp_buffer_info_t bufinfo;
     mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
 
-    const byte* buf = (const byte*)bufinfo.buf;
+    const byte *buf = (const byte *)bufinfo.buf;
     int delta = 1;
     if (args[2] == MP_OBJ_NEW_QSTR(MP_QSTR_little)) {
         buf += bufinfo.len - 1;
@@ -428,7 +432,7 @@ STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) {
 
     vstr_t vstr;
     vstr_init_len(&vstr, len);
-    byte *data = (byte*)vstr.buf;
+    byte *data = (byte *)vstr.buf;
     memset(data, 0, len);
 
     #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
@@ -460,5 +464,5 @@ const mp_obj_type_t mp_type_int = {
     .make_new = mp_obj_int_make_new,
     .unary_op = mp_obj_int_unary_op,
     .binary_op = mp_obj_int_binary_op,
-    .locals_dict = (mp_obj_dict_t*)&int_locals_dict,
+    .locals_dict = (mp_obj_dict_t *)&int_locals_dict,
 };

+ 6 - 6
py/objint.h

@@ -31,14 +31,14 @@
 
 typedef struct _mp_obj_int_t {
     mp_obj_base_t base;
-#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
+    #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
     mp_longint_impl_t val;
-#elif MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
+    #elif MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
     mpz_t mpz;
-#endif
+    #endif
 } mp_obj_int_t;
 
-extern const mp_obj_int_t mp_maxsize_obj;
+extern const mp_obj_int_t mp_sys_maxsize_obj;
 
 #if MICROPY_PY_BUILTINS_FLOAT
 mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in);
@@ -50,9 +50,9 @@ mp_obj_int_t *mp_obj_int_new_mpz(void);
 
 void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
 char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,
-                           int base, const char *prefix, char base_char, char comma);
+    int base, const char *prefix, char base_char, char comma);
 char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,
-                                int base, const char *prefix, char base_char, char comma);
+    int base, const char *prefix, char base_char, char comma);
 mp_int_t mp_obj_int_hash(mp_obj_t self_in);
 mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf);
 void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf);

+ 18 - 12
py/objint_longlong.c

@@ -40,7 +40,7 @@
 
 #if MICROPY_PY_SYS_MAXSIZE
 // Export value for sys.maxsize
-const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX};
+const mp_obj_int_t mp_sys_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX};
 #endif
 
 mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) {
@@ -95,15 +95,20 @@ int mp_obj_int_sign(mp_obj_t self_in) {
 mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
     mp_obj_int_t *o = o_in;
     switch (op) {
-        case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->val != 0);
+        case MP_UNARY_OP_BOOL:
+            return mp_obj_new_bool(o->val != 0);
 
         // truncate value to fit in mp_int_t, which gives the same hash as
         // small int if the value fits without truncation
-        case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT((mp_int_t)o->val);
+        case MP_UNARY_OP_HASH:
+            return MP_OBJ_NEW_SMALL_INT((mp_int_t)o->val);
 
-        case MP_UNARY_OP_POSITIVE: return o_in;
-        case MP_UNARY_OP_NEGATIVE: return mp_obj_new_int_from_ll(-o->val);
-        case MP_UNARY_OP_INVERT: return mp_obj_new_int_from_ll(~o->val);
+        case MP_UNARY_OP_POSITIVE:
+            return o_in;
+        case MP_UNARY_OP_NEGATIVE:
+            return mp_obj_new_int_from_ll(-o->val);
+        case MP_UNARY_OP_INVERT:
+            return mp_obj_new_int_from_ll(~o->val);
         case MP_UNARY_OP_ABS: {
             mp_obj_int_t *self = MP_OBJ_TO_PTR(o_in);
             if (self->val >= 0) {
@@ -114,7 +119,8 @@ mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
             self->val = -self->val;
             return MP_OBJ_FROM_PTR(self);
         }
-        default: return MP_OBJ_NULL; // op not supported
+        default:
+            return MP_OBJ_NULL;      // op not supported
     }
 }
 
@@ -126,13 +132,13 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
         lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in);
     } else {
         assert(mp_obj_is_type(lhs_in, &mp_type_int));
-        lhs_val = ((mp_obj_int_t*)lhs_in)->val;
+        lhs_val = ((mp_obj_int_t *)lhs_in)->val;
     }
 
     if (mp_obj_is_small_int(rhs_in)) {
         rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in);
     } else if (mp_obj_is_type(rhs_in, &mp_type_int)) {
-        rhs_val = ((mp_obj_int_t*)rhs_in)->val;
+        rhs_val = ((mp_obj_int_t *)rhs_in)->val;
     } else {
         // delegate to generic function to check for extra cases
         return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
@@ -184,7 +190,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
                 #if MICROPY_PY_BUILTINS_FLOAT
                 return mp_obj_float_binary_op(op, lhs_val, rhs_in);
                 #else
-                mp_raise_ValueError("negative power with no float support");
+                mp_raise_ValueError(MP_ERROR_TEXT("negative power with no float support"));
                 #endif
             }
             long long ans = 1;
@@ -217,7 +223,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
     }
 
 zero_division:
-    mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero");
+    mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero"));
 }
 
 mp_obj_t mp_obj_new_int(mp_int_t value) {
@@ -246,7 +252,7 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) {
 mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) {
     // TODO raise an exception if the unsigned long long won't fit
     if (val >> (sizeof(unsigned long long) * 8 - 1) != 0) {
-        mp_raise_msg(&mp_type_OverflowError, "ulonglong too large");
+        mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("ulonglong too large"));
     }
     mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
     o->base.type = &mp_type_int;

+ 66 - 30
py/objint_mpz.c

@@ -41,6 +41,7 @@
 
 #if MICROPY_PY_SYS_MAXSIZE
 // Export value for sys.maxsize
+// *FORMAT-OFF*
 #define DIG_MASK ((MPZ_LONG_1 << MPZ_DIG_SIZE) - 1)
 STATIC const mpz_dig_t maxsize_dig[] = {
     #define NUM_DIG 1
@@ -64,9 +65,10 @@ STATIC const mpz_dig_t maxsize_dig[] = {
      #endif
     #endif
 };
-const mp_obj_int_t mp_maxsize_obj = {
+// *FORMAT-ON*
+const mp_obj_int_t mp_sys_maxsize_obj = {
     {&mp_type_int},
-    {.fixed_dig = 1, .len = NUM_DIG, .alloc = NUM_DIG, .dig = (mpz_dig_t*)maxsize_dig}
+    {.fixed_dig = 1, .len = NUM_DIG, .alloc = NUM_DIG, .dig = (mpz_dig_t *)maxsize_dig}
 };
 #undef DIG_MASK
 #undef NUM_DIG
@@ -89,7 +91,7 @@ mp_obj_int_t *mp_obj_int_new_mpz(void) {
 //
 // This particular routine should only be called for the mpz representation of the int.
 char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,
-                                int base, const char *prefix, char base_char, char comma) {
+    int base, const char *prefix, char base_char, char comma) {
     assert(mp_obj_is_type(self_in, &mp_type_int));
     const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);
 
@@ -142,11 +144,20 @@ int mp_obj_int_sign(mp_obj_t self_in) {
 mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
     mp_obj_int_t *o = MP_OBJ_TO_PTR(o_in);
     switch (op) {
-        case MP_UNARY_OP_BOOL: return mp_obj_new_bool(!mpz_is_zero(&o->mpz));
-        case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mpz_hash(&o->mpz));
-        case MP_UNARY_OP_POSITIVE: return o_in;
-        case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_neg_inpl(&o2->mpz, &o->mpz); return MP_OBJ_FROM_PTR(o2); }
-        case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz(); mpz_not_inpl(&o2->mpz, &o->mpz); return MP_OBJ_FROM_PTR(o2); }
+        case MP_UNARY_OP_BOOL:
+            return mp_obj_new_bool(!mpz_is_zero(&o->mpz));
+        case MP_UNARY_OP_HASH:
+            return MP_OBJ_NEW_SMALL_INT(mpz_hash(&o->mpz));
+        case MP_UNARY_OP_POSITIVE:
+            return o_in;
+        case MP_UNARY_OP_NEGATIVE: { mp_obj_int_t *o2 = mp_obj_int_new_mpz();
+                                     mpz_neg_inpl(&o2->mpz, &o->mpz);
+                                     return MP_OBJ_FROM_PTR(o2);
+        }
+        case MP_UNARY_OP_INVERT: { mp_obj_int_t *o2 = mp_obj_int_new_mpz();
+                                   mpz_not_inpl(&o2->mpz, &o->mpz);
+                                   return MP_OBJ_FROM_PTR(o2);
+        }
         case MP_UNARY_OP_ABS: {
             mp_obj_int_t *self = MP_OBJ_TO_PTR(o_in);
             if (self->mpz.neg == 0) {
@@ -156,7 +167,8 @@ mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
             mpz_abs_inpl(&self2->mpz, &self->mpz);
             return MP_OBJ_FROM_PTR(self2);
         }
-        default: return MP_OBJ_NULL; // op not supported
+        default:
+            return MP_OBJ_NULL;      // op not supported
     }
 }
 
@@ -172,7 +184,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
         zlhs = &z_int;
     } else {
         assert(mp_obj_is_type(lhs_in, &mp_type_int));
-        zlhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(lhs_in))->mpz;
+        zlhs = &((mp_obj_int_t *)MP_OBJ_TO_PTR(lhs_in))->mpz;
     }
 
     // if rhs is small int, then lhs was not (otherwise mp_binary_op handles it)
@@ -180,21 +192,21 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
         mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(rhs_in));
         zrhs = &z_int;
     } else if (mp_obj_is_type(rhs_in, &mp_type_int)) {
-        zrhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(rhs_in))->mpz;
-#if MICROPY_PY_BUILTINS_FLOAT
+        zrhs = &((mp_obj_int_t *)MP_OBJ_TO_PTR(rhs_in))->mpz;
+    #if MICROPY_PY_BUILTINS_FLOAT
     } else if (mp_obj_is_float(rhs_in)) {
         return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in);
-#if MICROPY_PY_BUILTINS_COMPLEX
+    #endif
+    #if MICROPY_PY_BUILTINS_COMPLEX
     } else if (mp_obj_is_type(rhs_in, &mp_type_complex)) {
         return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in);
-#endif
-#endif
+    #endif
     } else {
         // delegate to generic function to check for extra cases
         return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
     }
 
-#if MICROPY_PY_BUILTINS_FLOAT
+    #if MICROPY_PY_BUILTINS_FLOAT
     if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) {
         if (mpz_is_zero(zrhs)) {
             goto zero_division_error;
@@ -202,8 +214,8 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
         mp_float_t flhs = mpz_as_float(zlhs);
         mp_float_t frhs = mpz_as_float(zrhs);
         return mp_obj_new_float(flhs / frhs);
-    } else
-#endif
+    }
+    #endif
 
     if (op >= MP_BINARY_OP_INPLACE_OR && op < MP_BINARY_OP_CONTAINS) {
         mp_obj_int_t *res = mp_obj_int_new_mpz();
@@ -224,10 +236,11 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
             case MP_BINARY_OP_FLOOR_DIVIDE:
             case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: {
                 if (mpz_is_zero(zrhs)) {
-                    zero_division_error:
-                    mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero");
+                zero_division_error:
+                    mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero"));
                 }
-                mpz_t rem; mpz_init_zero(&rem);
+                mpz_t rem;
+                mpz_init_zero(&rem);
                 mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs);
                 mpz_deinit(&rem);
                 break;
@@ -237,7 +250,8 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
                 if (mpz_is_zero(zrhs)) {
                     goto zero_division_error;
                 }
-                mpz_t quo; mpz_init_zero(&quo);
+                mpz_t quo;
+                mpz_init_zero(&quo);
                 mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs);
                 mpz_deinit(&quo);
                 break;
@@ -262,7 +276,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
             case MP_BINARY_OP_INPLACE_RSHIFT: {
                 mp_int_t irhs = mp_obj_int_get_checked(rhs_in);
                 if (irhs < 0) {
-                    mp_raise_ValueError("negative shift count");
+                    mp_raise_ValueError(MP_ERROR_TEXT("negative shift count"));
                 }
                 if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) {
                     mpz_shl_inpl(&res->mpz, zlhs, irhs);
@@ -278,7 +292,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
                     #if MICROPY_PY_BUILTINS_FLOAT
                     return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in);
                     #else
-                    mp_raise_ValueError("negative power with no float support");
+                    mp_raise_ValueError(MP_ERROR_TEXT("negative power with no float support"));
                     #endif
                 }
                 mpz_pow_inpl(&res->mpz, zlhs, zrhs);
@@ -331,10 +345,10 @@ STATIC mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) {
 
 mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent,  mp_obj_t modulus) {
     if (!mp_obj_is_int(base) || !mp_obj_is_int(exponent) || !mp_obj_is_int(modulus)) {
-        mp_raise_TypeError("pow() with 3 arguments requires integers");
+        mp_raise_TypeError(MP_ERROR_TEXT("pow() with 3 arguments requires integers"));
     } else {
         mp_obj_t result = mp_obj_new_int_from_ull(0); // Use the _from_ull version as this forces an mpz int
-        mp_obj_int_t *res_p = (mp_obj_int_t *) MP_OBJ_TO_PTR(result);
+        mp_obj_int_t *res_p = (mp_obj_int_t *)MP_OBJ_TO_PTR(result);
 
         mpz_t l_temp, r_temp, m_temp;
         mpz_t *lhs = mp_mpz_for_int(base,     &l_temp);
@@ -343,9 +357,15 @@ mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent,  mp_obj_t modulus) {
 
         mpz_pow3_inpl(&(res_p->mpz), lhs, rhs, mod);
 
-        if (lhs == &l_temp) { mpz_deinit(lhs); }
-        if (rhs == &r_temp) { mpz_deinit(rhs); }
-        if (mod == &m_temp) { mpz_deinit(mod); }
+        if (lhs == &l_temp) {
+            mpz_deinit(lhs);
+        }
+        if (rhs == &r_temp) {
+            mpz_deinit(rhs);
+        }
+        if (mod == &m_temp) {
+            mpz_deinit(mod);
+        }
         return result;
     }
 }
@@ -406,9 +426,25 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
             return value;
         } else {
             // overflow
-            mp_raise_msg(&mp_type_OverflowError, "overflow converting long int to machine word");
+            mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting long int to machine word"));
+        }
+    }
+}
+
+mp_uint_t mp_obj_int_get_uint_checked(mp_const_obj_t self_in) {
+    if (mp_obj_is_small_int(self_in)) {
+        if (MP_OBJ_SMALL_INT_VALUE(self_in) >= 0) {
+            return MP_OBJ_SMALL_INT_VALUE(self_in);
+        }
+    } else {
+        const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);
+        mp_uint_t value;
+        if (mpz_as_uint_checked(&self->mpz, &value)) {
+            return value;
         }
     }
+
+    mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting long int to machine word"));
 }
 
 #if MICROPY_PY_BUILTINS_FLOAT

+ 39 - 33
py/objlist.c

@@ -88,15 +88,18 @@ STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, size_
 STATIC mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
     mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
     switch (op) {
-        case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0);
-        case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len);
+        case MP_UNARY_OP_BOOL:
+            return mp_obj_new_bool(self->len != 0);
+        case MP_UNARY_OP_LEN:
+            return MP_OBJ_NEW_SMALL_INT(self->len);
         #if MICROPY_PY_SYS_GETSIZEOF
         case MP_UNARY_OP_SIZEOF: {
             size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc;
             return MP_OBJ_NEW_SMALL_INT(sz);
         }
         #endif
-        default: return MP_OBJ_NULL; // op not supported
+        default:
+            return MP_OBJ_NULL;      // op not supported
     }
 }
 
@@ -153,7 +156,7 @@ STATIC mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
 STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
     if (value == MP_OBJ_NULL) {
         // delete
-#if MICROPY_PY_BUILTINS_SLICE
+        #if MICROPY_PY_BUILTINS_SLICE
         if (mp_obj_is_type(index, &mp_type_slice)) {
             mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
             mp_bound_slice_t slice;
@@ -162,22 +165,21 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
             }
 
             mp_int_t len_adj = slice.start - slice.stop;
-            //printf("Len adj: %d\n", len_adj);
             assert(len_adj <= 0);
-            mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items/*NULL*/, 0, sizeof(*self->items));
+            mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items /*NULL*/, 0, sizeof(*self->items));
             // Clear "freed" elements at the end of list
             mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items));
             self->len += len_adj;
             return mp_const_none;
         }
-#endif
+        #endif
         mp_obj_t args[2] = {self_in, index};
         list_pop(2, args);
         return mp_const_none;
     } else if (value == MP_OBJ_SENTINEL) {
         // load
         mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
-#if MICROPY_PY_BUILTINS_SLICE
+        #if MICROPY_PY_BUILTINS_SLICE
         if (mp_obj_is_type(index, &mp_type_slice)) {
             mp_bound_slice_t slice;
             if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
@@ -187,21 +189,21 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
             mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t);
             return MP_OBJ_FROM_PTR(res);
         }
-#endif
+        #endif
         size_t index_val = mp_get_index(self->base.type, self->len, index, false);
         return self->items[index_val];
     } else {
-#if MICROPY_PY_BUILTINS_SLICE
+        #if MICROPY_PY_BUILTINS_SLICE
         if (mp_obj_is_type(index, &mp_type_slice)) {
             mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
-            size_t value_len; mp_obj_t *value_items;
+            size_t value_len;
+            mp_obj_t *value_items;
             mp_obj_get_array(value, &value_len, &value_items);
             mp_bound_slice_t slice_out;
             if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) {
                 mp_raise_NotImplementedError(NULL);
             }
             mp_int_t len_adj = value_len - (slice_out.stop - slice_out.start);
-            //printf("Len adj: %d\n", len_adj);
             if (len_adj > 0) {
                 if (self->len + len_adj > self->alloc) {
                     // TODO: Might optimize memory copies here by checking if block can
@@ -221,7 +223,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
             self->len += len_adj;
             return mp_const_none;
         }
-#endif
+        #endif
         mp_obj_list_store(self_in, index, value);
         return mp_const_none;
     }
@@ -268,7 +270,7 @@ STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) {
     mp_check_self(mp_obj_is_type(args[0], &mp_type_list));
     mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]);
     if (self->len == 0) {
-        mp_raise_msg(&mp_type_IndexError, "pop from empty list");
+        mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("pop from empty list"));
     }
     size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false);
     mp_obj_t ret = self->items[index];
@@ -277,7 +279,7 @@ STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) {
     // Clear stale pointer from slot which just got freed to prevent GC issues
     self->items[self->len] = MP_OBJ_NULL;
     if (self->alloc > LIST_MIN_ALLOC && self->alloc > 2 * self->len) {
-        self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc/2);
+        self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc / 2);
         self->alloc /= 2;
     }
     return ret;
@@ -290,9 +292,13 @@ STATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj
         mp_obj_t *t = tail;
         mp_obj_t v = key_fn == MP_OBJ_NULL ? tail[0] : mp_call_function_1(key_fn, tail[0]); // get pivot using key_fn
         for (;;) {
-            do ++h; while (h < t && mp_binary_op(MP_BINARY_OP_LESS, key_fn == MP_OBJ_NULL ? h[0] : mp_call_function_1(key_fn, h[0]), v) == binop_less_result);
-            do --t; while (h < t && mp_binary_op(MP_BINARY_OP_LESS, v, key_fn == MP_OBJ_NULL ? t[0] : mp_call_function_1(key_fn, t[0])) == binop_less_result);
-            if (h >= t) break;
+            do {++h;
+            } while (h < t && mp_binary_op(MP_BINARY_OP_LESS, key_fn == MP_OBJ_NULL ? h[0] : mp_call_function_1(key_fn, h[0]), v) == binop_less_result);
+            do {--t;
+            } while (h < t && mp_binary_op(MP_BINARY_OP_LESS, v, key_fn == MP_OBJ_NULL ? t[0] : mp_call_function_1(key_fn, t[0])) == binop_less_result);
+            if (h >= t) {
+                break;
+            }
             mp_obj_t x = h[0];
             h[0] = t[0];
             t[0] = x;
@@ -314,7 +320,7 @@ STATIC void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj
 // TODO Python defines sort to be stable but ours is not
 mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     static const mp_arg_t allowed_args[] = {
-        { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
+        { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
         { MP_QSTR_reverse, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
     };
 
@@ -323,15 +329,15 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
         mp_arg_val_t key, reverse;
     } args;
     mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
-        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
+        MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);
 
     mp_check_self(mp_obj_is_type(pos_args[0], &mp_type_list));
     mp_obj_list_t *self = MP_OBJ_TO_PTR(pos_args[0]);
 
     if (self->len > 1) {
         mp_quicksort(self->items, self->items + self->len - 1,
-                     args.key.u_obj == mp_const_none ? MP_OBJ_NULL : args.key.u_obj,
-                     args.reverse.u_bool ? mp_const_false : mp_const_true);
+            args.key.u_obj == mp_const_none ? MP_OBJ_NULL : args.key.u_obj,
+            args.reverse.u_bool ? mp_const_false : mp_const_true);
     }
 
     return mp_const_none;
@@ -371,19 +377,19 @@ STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) {
     // insert has its own strange index logic
     mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx);
     if (index < 0) {
-         index += self->len;
+        index += self->len;
     }
     if (index < 0) {
-         index = 0;
+        index = 0;
     }
     if ((size_t)index > self->len) {
-         index = self->len;
+        index = self->len;
     }
 
     mp_obj_list_append(self_in, mp_const_none);
 
-    for (mp_int_t i = self->len-1; i > index; i--) {
-         self->items[i] = self->items[i-1];
+    for (mp_int_t i = self->len - 1; i > index; i--) {
+        self->items[i] = self->items[i - 1];
     }
     self->items[index] = obj;
 
@@ -404,10 +410,10 @@ STATIC mp_obj_t list_reverse(mp_obj_t self_in) {
     mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
 
     mp_int_t len = self->len;
-    for (mp_int_t i = 0; i < len/2; i++) {
-         mp_obj_t a = self->items[i];
-         self->items[i] = self->items[len-i-1];
-         self->items[len-i-1] = a;
+    for (mp_int_t i = 0; i < len / 2; i++) {
+        mp_obj_t a = self->items[i];
+        self->items[i] = self->items[len - i - 1];
+        self->items[len - i - 1] = a;
     }
 
     return mp_const_none;
@@ -450,7 +456,7 @@ const mp_obj_type_t mp_type_list = {
     .binary_op = list_binary_op,
     .subscr = list_subscr,
     .getiter = list_getiter,
-    .locals_dict = (mp_obj_dict_t*)&list_locals_dict,
+    .locals_dict = (mp_obj_dict_t *)&list_locals_dict,
 };
 
 void mp_obj_list_init(mp_obj_list_t *o, size_t n) {
@@ -520,7 +526,7 @@ STATIC mp_obj_t list_it_iternext(mp_obj_t self_in) {
 
 mp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t *iter_buf) {
     assert(sizeof(mp_obj_list_it_t) <= sizeof(mp_obj_iter_buf_t));
-    mp_obj_list_it_t *o = (mp_obj_list_it_t*)iter_buf;
+    mp_obj_list_it_t *o = (mp_obj_list_it_t *)iter_buf;
     o->base.type = &mp_type_polymorph_iter;
     o->iternext = list_it_iternext;
     o->list = list;

+ 65 - 62
py/objmodule.c

@@ -33,7 +33,7 @@
 #include "py/runtime.h"
 #include "py/builtin.h"
 
-// #include "genhdr/moduledefs.h"
+#include "genhdr/moduledefs.h"
 
 STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     (void)kind;
@@ -45,7 +45,7 @@ STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin
         module_name = mp_obj_str_get_str(elem->value);
     }
 
-#if MICROPY_PY___FILE__
+    #if MICROPY_PY___FILE__
     // If we store __file__ to imported modules then try to lookup this
     // symbol to give more information about the module.
     elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP);
@@ -53,7 +53,7 @@ STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin
         mp_printf(print, "<module '%s' from '%s'>", module_name, mp_obj_str_get_str(elem->value));
         return;
     }
-#endif
+    #endif
 
     mp_printf(print, "<module '%s'>", module_name);
 }
@@ -140,93 +140,96 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
     { MP_ROM_QSTR(MP_QSTR_builtins), MP_ROM_PTR(&mp_module_builtins) },
     { MP_ROM_QSTR(MP_QSTR_micropython), MP_ROM_PTR(&mp_module_micropython) },
 
-#if MICROPY_PY_IO
+    #if MICROPY_PY_IO
     { MP_ROM_QSTR(MP_QSTR_uio), MP_ROM_PTR(&mp_module_io) },
-#endif
-#if MICROPY_PY_COLLECTIONS
+    #endif
+    #if MICROPY_PY_COLLECTIONS
     { MP_ROM_QSTR(MP_QSTR_ucollections), MP_ROM_PTR(&mp_module_collections) },
-#endif
-#if MICROPY_PY_STRUCT
+    #endif
+    #if MICROPY_PY_STRUCT
     { MP_ROM_QSTR(MP_QSTR_ustruct), MP_ROM_PTR(&mp_module_ustruct) },
-#endif
+    #endif
 
-#if MICROPY_PY_BUILTINS_FLOAT
-#if MICROPY_PY_MATH
+    #if MICROPY_PY_BUILTINS_FLOAT
+    #if MICROPY_PY_MATH
     { MP_ROM_QSTR(MP_QSTR_math), MP_ROM_PTR(&mp_module_math) },
-#endif
-#if MICROPY_PY_BUILTINS_COMPLEX && MICROPY_PY_CMATH
+    #endif
+    #if MICROPY_PY_BUILTINS_COMPLEX && MICROPY_PY_CMATH
     { MP_ROM_QSTR(MP_QSTR_cmath), MP_ROM_PTR(&mp_module_cmath) },
-#endif
-#endif
-#if MICROPY_PY_SYS
-    { MP_ROM_QSTR(MP_QSTR_sys), MP_ROM_PTR(&mp_module_sys) },
-#endif
-#if MICROPY_PY_GC && MICROPY_ENABLE_GC
+    #endif
+    #endif
+    #if MICROPY_PY_SYS
+    { MP_ROM_QSTR(MP_QSTR_usys), MP_ROM_PTR(&mp_module_sys) },
+    #endif
+    #if MICROPY_PY_GC && MICROPY_ENABLE_GC
     { MP_ROM_QSTR(MP_QSTR_gc), MP_ROM_PTR(&mp_module_gc) },
-#endif
-#if MICROPY_PY_THREAD
+    #endif
+    #if MICROPY_PY_THREAD
     { MP_ROM_QSTR(MP_QSTR__thread), MP_ROM_PTR(&mp_module_thread) },
-#endif
+    #endif
 
     // extmod modules
 
-#if MICROPY_PY_UERRNO
+    #if MICROPY_PY_UASYNCIO
+    { MP_ROM_QSTR(MP_QSTR__uasyncio), MP_ROM_PTR(&mp_module_uasyncio) },
+    #endif
+    #if MICROPY_PY_UERRNO
     { MP_ROM_QSTR(MP_QSTR_uerrno), MP_ROM_PTR(&mp_module_uerrno) },
-#endif
-#if MICROPY_PY_UCTYPES
+    #endif
+    #if MICROPY_PY_UCTYPES
     { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) },
-#endif
-#if MICROPY_PY_UZLIB
+    #endif
+    #if MICROPY_PY_UZLIB
     { MP_ROM_QSTR(MP_QSTR_uzlib), MP_ROM_PTR(&mp_module_uzlib) },
-#endif
-#if MICROPY_PY_UJSON
+    #endif
+    #if MICROPY_PY_UJSON
     { MP_ROM_QSTR(MP_QSTR_ujson), MP_ROM_PTR(&mp_module_ujson) },
-#endif
-#if MICROPY_PY_URE
+    #endif
+    #if MICROPY_PY_URE
     { MP_ROM_QSTR(MP_QSTR_ure), MP_ROM_PTR(&mp_module_ure) },
-#endif
-#if MICROPY_PY_UHEAPQ
+    #endif
+    #if MICROPY_PY_UHEAPQ
     { MP_ROM_QSTR(MP_QSTR_uheapq), MP_ROM_PTR(&mp_module_uheapq) },
-#endif
-#if MICROPY_PY_UTIMEQ
+    #endif
+    #if MICROPY_PY_UTIMEQ
     { MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&mp_module_utimeq) },
-#endif
-#if MICROPY_PY_UHASHLIB
+    #endif
+    #if MICROPY_PY_UHASHLIB
     { MP_ROM_QSTR(MP_QSTR_uhashlib), MP_ROM_PTR(&mp_module_uhashlib) },
-#endif
-#if MICROPY_PY_UCRYPTOLIB
+    #endif
+    #if MICROPY_PY_UCRYPTOLIB
     { MP_ROM_QSTR(MP_QSTR_ucryptolib), MP_ROM_PTR(&mp_module_ucryptolib) },
-#endif
-#if MICROPY_PY_UBINASCII
+    #endif
+    #if MICROPY_PY_UBINASCII
     { MP_ROM_QSTR(MP_QSTR_ubinascii), MP_ROM_PTR(&mp_module_ubinascii) },
-#endif
-#if MICROPY_PY_URANDOM
+    #endif
+    #if MICROPY_PY_URANDOM
     { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mp_module_urandom) },
-#endif
-#if MICROPY_PY_USELECT
+    #endif
+    #if MICROPY_PY_USELECT
     { MP_ROM_QSTR(MP_QSTR_uselect), MP_ROM_PTR(&mp_module_uselect) },
-#endif
-#if MICROPY_PY_USSL
+    #endif
+    #if MICROPY_PY_USSL
     { MP_ROM_QSTR(MP_QSTR_ussl), MP_ROM_PTR(&mp_module_ussl) },
-#endif
-#if MICROPY_PY_LWIP
+    #endif
+    #if MICROPY_PY_LWIP
     { MP_ROM_QSTR(MP_QSTR_lwip), MP_ROM_PTR(&mp_module_lwip) },
-#endif
-#if MICROPY_PY_UWEBSOCKET
+    #endif
+    #if MICROPY_PY_UWEBSOCKET
     { MP_ROM_QSTR(MP_QSTR_uwebsocket), MP_ROM_PTR(&mp_module_uwebsocket) },
-#endif
-#if MICROPY_PY_WEBREPL
+    #endif
+    #if MICROPY_PY_WEBREPL
     { MP_ROM_QSTR(MP_QSTR__webrepl), MP_ROM_PTR(&mp_module_webrepl) },
-#endif
-#if MICROPY_PY_FRAMEBUF
+    #endif
+    #if MICROPY_PY_FRAMEBUF
     { MP_ROM_QSTR(MP_QSTR_framebuf), MP_ROM_PTR(&mp_module_framebuf) },
-#endif
-#if MICROPY_PY_BTREE
+    #endif
+    #if MICROPY_PY_BTREE
     { MP_ROM_QSTR(MP_QSTR_btree), MP_ROM_PTR(&mp_module_btree) },
-#endif
-#if MICROPY_PY_BLUETOOTH
+    #endif
+    #if MICROPY_PY_BLUETOOTH
     { MP_ROM_QSTR(MP_QSTR_ubluetooth), MP_ROM_PTR(&mp_module_ubluetooth) },
-#endif
+    #endif
 
     // extra builtin modules as defined by a port
     MICROPY_PORT_BUILTIN_MODULES
@@ -247,7 +250,7 @@ mp_obj_t mp_module_get(qstr module_name) {
 
     if (el == NULL) {
         // module not found, look for builtin module names
-        el = mp_map_lookup((mp_map_t*)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
+        el = mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP);
         if (el == NULL) {
             return MP_OBJ_NULL;
         }
@@ -267,7 +270,7 @@ void mp_module_register(qstr qst, mp_obj_t module) {
 // Search for u"foo" in built-in modules, return MP_OBJ_NULL if not found
 mp_obj_t mp_module_search_umodule(const char *module_str) {
     for (size_t i = 0; i < MP_ARRAY_SIZE(mp_builtin_module_table); ++i) {
-        const mp_map_elem_t *entry = (const mp_map_elem_t*)&mp_builtin_module_table[i];
+        const mp_map_elem_t *entry = (const mp_map_elem_t *)&mp_builtin_module_table[i];
         const char *key = qstr_str(MP_OBJ_QSTR_VALUE(entry->key));
         if (key[0] == 'u' && strcmp(&key[1], module_str) == 0) {
             return (mp_obj_t)entry->value;

Некоторые файлы не были показаны из-за большого количества измененных файлов