From 10d92873c38211db27aa58dd1114298994543f7d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 11:21:03 -0600 Subject: [PATCH 01/32] Don't generate QSTRs for wrong identifiers MP_REGISTER_MODULE would use identifiers like "MODULE_DEF_MP_QSTR___FUTURE__" which would in turn cause a QSTR to be generated for it. This wasn't desirable, because the qstr would never be used. This clears out quite a bit of flash storage on the proxlight trinkey. --- py/genlast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/genlast.py b/py/genlast.py index ad44745d97..460271af81 100644 --- a/py/genlast.py +++ b/py/genlast.py @@ -12,7 +12,7 @@ import subprocess from makeqstrdefs import qstr_unescape, QSTRING_BLOCK_LIST re_line = re.compile(r"#[line]*\s(\d+)\s\"([^\"]+)\"", re.DOTALL) -re_qstr = re.compile(r"MP_QSTR_[_a-zA-Z0-9]+", re.DOTALL) +re_qstr = re.compile(r"\bMP_QSTR_[_a-zA-Z0-9]+", re.DOTALL) re_translate = re.compile(r"translate\(\"((?:(?=(\\?))\2.)*?)\"\)", re.DOTALL) From 2315b62bff5ada6dfdfa6a9662266ef2451a9294 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 11:21:22 -0600 Subject: [PATCH 02/32] Remove unused static qstrs These are turned into TRANSLATE() messages now, so the qstr version would not be used. --- py/qstrdefs.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 02b87f4ec3..70753866bd 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -49,7 +49,6 @@ Q({:#x}) Q({:#b}) Q( ) Q(\n) -Q(maximum recursion depth exceeded) Q() Q() Q() @@ -63,7 +62,3 @@ Q(utf-8) #if MICROPY_MODULE_FROZEN Q(.frozen) #endif - -#if MICROPY_ENABLE_PYSTACK -Q(pystack exhausted) -#endif From 284ac21f512ed06137662833c1c30e2f7e4631cb Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 14:34:44 -0600 Subject: [PATCH 03/32] merge a message --- shared-bindings/busio/I2C.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index 71ac0e3995..3dd645b256 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -345,7 +345,7 @@ STATIC mp_obj_t busio_i2c_writeto_then_readfrom(size_t n_args, const mp_obj_t *p const int32_t in_end = args[ARG_in_end].u_int; normalize_buffer_bounds(&in_start, in_end, &in_length); if (in_length == 0) { - mp_raise_ValueError_varg(translate("%q length must be >= 1"), MP_QSTR_out_buffer); + mp_raise_ValueError_varg(translate("%q length must be >= %d"), MP_QSTR_out_buffer, 1); } uint8_t status = common_hal_busio_i2c_write_read(self, args[ARG_address].u_int, From 6ac2022093bc627b7bb61c336aa5f683406841ea Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 14:36:35 -0600 Subject: [PATCH 04/32] merge a message --- shared-bindings/usb_hid/Device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/usb_hid/Device.c b/shared-bindings/usb_hid/Device.c index 97196144be..cb88766b3e 100644 --- a/shared-bindings/usb_hid/Device.c +++ b/shared-bindings/usb_hid/Device.c @@ -155,7 +155,7 @@ STATIC mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args } if (report_ids_array[0] == 0 && report_ids_count > 1) { - mp_raise_ValueError_varg(translate("%q with a report ID of 0 must be of length 1"), MP_QSTR_report_ids); + mp_raise_ValueError_varg(translate("%q length must be %d"), MP_QSTR_report_id_space_0, 1); } common_hal_usb_hid_device_construct( From f652a898e78d0a6f0fe7963c86891771d09652df Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 14:37:32 -0600 Subject: [PATCH 05/32] merge two messages --- py/argcheck.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/argcheck.c b/py/argcheck.c index c28c577088..9ec21d4898 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -239,7 +239,7 @@ mp_obj_t mp_arg_validate_type(mp_obj_t obj, const mp_obj_type_t *type, qstr arg_ mp_obj_t mp_arg_validate_type_string(mp_obj_t obj, qstr arg_name) { if (!mp_obj_is_str(obj)) { - mp_raise_TypeError_varg(translate("%q must be a string"), arg_name); + mp_raise_TypeError_varg(translate("%q must be of type %q"), arg_name, MP_QSTR_str); } return obj; } @@ -247,7 +247,7 @@ mp_obj_t mp_arg_validate_type_string(mp_obj_t obj, qstr arg_name) { mp_int_t mp_arg_validate_type_int(mp_obj_t obj, qstr arg_name) { mp_int_t an_int; if (!mp_obj_get_int_maybe(obj, &an_int)) { - mp_raise_TypeError_varg(translate("%q must be an int"), arg_name); + mp_raise_TypeError_varg(translate("%q must be of type %q"), arg_name, MP_QSTR_int); } return an_int; } From 7df21c9ecfd2335b004825b999752853cf2fb3f0 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 14:44:08 -0600 Subject: [PATCH 06/32] Combine a message --- py/runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/runtime.c b/py/runtime.c index e5b411b0d3..e3750b7448 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -310,7 +310,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) { } #else if (op == MP_UNARY_OP_INT) { - mp_raise_TypeError_varg(MP_ERROR_TEXT("can't convert %q to int"), mp_obj_get_type_qstr(arg)); + mp_raise_TypeError_varg(MP_ERROR_TEXT("can't convert %q to %q"), mp_obj_get_type_qstr(arg), MP_QSTR_int); } else { mp_raise_TypeError_varg(MP_ERROR_TEXT("unsupported type for %q: '%q'"), mp_unary_op_method_name[op], mp_obj_get_type_qstr(arg)); From ac999098ee4c9aee39f017bb50146bda419f3d96 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 14:49:01 -0600 Subject: [PATCH 07/32] merge a message --- shared-bindings/time/__init__.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 096c80d382..d02923f162 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -97,9 +97,7 @@ STATIC mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, s size_t len; mp_obj_t *items; mp_obj_get_array(args[0], &len, &items); - if (len != 9) { - mp_raise_TypeError(translate("time.struct_time() takes a 9-sequence")); - } + mp_arg_validate_length(len, 9, MP_QSTR_value); return namedtuple_make_new(type, len, 0, items); } From 8658e7a9546647521a281ac22e473bf688763d0e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 14:55:45 -0600 Subject: [PATCH 08/32] re-use length validator --- shared-bindings/microcontroller/Pin.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/shared-bindings/microcontroller/Pin.c b/shared-bindings/microcontroller/Pin.c index 42076aa90e..f1b9a90d45 100644 --- a/shared-bindings/microcontroller/Pin.c +++ b/shared-bindings/microcontroller/Pin.c @@ -156,9 +156,7 @@ void validate_no_duplicate_pins_2(mp_obj_t seq1, mp_obj_t seq2, qstr arg_name1, // Validate every element in the list to be a free pin. void validate_list_is_free_pins(qstr what, const mcu_pin_obj_t **pins_out, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out) { mp_int_t len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(seq)); - if (len > max_pins) { - mp_raise_ValueError_varg(translate("At most %d %q may be specified (not %d)"), max_pins, what, len); - } + mp_arg_validate_length_max(len, max_pins, what); *count_out = len; for (mp_int_t i = 0; i < len; i++) { pins_out[i] = validate_obj_is_free_pin(mp_obj_subscr(seq, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); From 7c9cd567a0780448b3b29e9666e3cd9dbc50161f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 14:58:59 -0600 Subject: [PATCH 09/32] If uart is disabled, no pins will work; show NotImplementedError instead --- shared-bindings/busio/UART.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c index eb1d1685a5..59e46cafc4 100644 --- a/shared-bindings/busio/UART.c +++ b/shared-bindings/busio/UART.c @@ -155,7 +155,7 @@ STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, si args[ARG_receiver_buffer_size].u_int, NULL, false); return (mp_obj_t)self; #else - mp_raise_ValueError(translate("Invalid pins")); + mp_raise_NotImplementedError(NULL); #endif // CIRCUITPY_BUSIO_UART } From beb053a94d742d8829e2b77ca8f9b06a7bf7a186 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 14:59:57 -0600 Subject: [PATCH 10/32] more thoroughly disable UART when --- ports/atmel-samd/common-hal/busio/UART.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/atmel-samd/common-hal/busio/UART.c b/ports/atmel-samd/common-hal/busio/UART.c index 3a9b628e0b..6027b6a5fa 100644 --- a/ports/atmel-samd/common-hal/busio/UART.c +++ b/ports/atmel-samd/common-hal/busio/UART.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#if CIRCUITPY_BUSIO_UART #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/busio/UART.h" @@ -485,3 +486,4 @@ bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { usart_async_get_status(usart_desc_p, &async_status); return !(async_status.flags & USART_ASYNC_STATUS_BUSY); } +#endif From db01dfea2046d29c66acaf709dfaf14129a5fc87 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 15:03:22 -0600 Subject: [PATCH 11/32] use a standard length validator --- shared-module/usb_hid/__init__.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/shared-module/usb_hid/__init__.c b/shared-module/usb_hid/__init__.c index 99be84542f..11b87a78f1 100644 --- a/shared-module/usb_hid/__init__.c +++ b/shared-module/usb_hid/__init__.c @@ -220,9 +220,7 @@ bool common_hal_usb_hid_enable(const mp_obj_t devices, uint8_t boot_device) { } const mp_int_t num_devices = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(devices)); - if (num_devices > MAX_HID_DEVICES) { - mp_raise_ValueError_varg(translate("No more than %d HID devices allowed"), MAX_HID_DEVICES); - } + mp_arg_validate_length_max(num_devices, MAX_HID_DEVICES, MP_QSTR_devices); num_hid_devices = num_devices; From 2b01c139f5df6f0c58c302143c7857aca968baf8 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 15:05:33 -0600 Subject: [PATCH 12/32] use a standard validator function --- shared-bindings/adafruit_pixelbuf/PixelBuf.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/shared-bindings/adafruit_pixelbuf/PixelBuf.c b/shared-bindings/adafruit_pixelbuf/PixelBuf.c index 6203f672ad..2252b7d59e 100644 --- a/shared-bindings/adafruit_pixelbuf/PixelBuf.c +++ b/shared-bindings/adafruit_pixelbuf/PixelBuf.c @@ -129,9 +129,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_a } static void parse_byteorder(mp_obj_t byteorder_obj, pixelbuf_byteorder_details_t *parsed) { - if (!mp_obj_is_str(byteorder_obj)) { - mp_raise_TypeError(translate("byteorder is not a string")); - } + mp_arg_validate_type_string(byteorder_obj, MP_QSTR_byteorder); size_t bo_len; const char *byteorder = mp_obj_str_get_data(byteorder_obj, &bo_len); From 0e19fbb60f41c3586725320aa93771ac6c4cac9c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 15:24:49 -0600 Subject: [PATCH 13/32] Use a function to raise ZeroDivisionError, consistent string --- locale/circuitpython.pot | 58 +++------------------------------------- py/modmath.c | 2 +- py/objcomplex.c | 2 +- py/objfloat.c | 2 +- py/objint_longlong.c | 2 +- py/objint_mpz.c | 2 +- py/runtime.c | 6 ++++- py/runtime.h | 1 + 8 files changed, 15 insertions(+), 60 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 3958d2869a..9928ca03e0 100755 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -118,7 +118,7 @@ msgstr "" msgid "%q is %q" msgstr "" -#: py/argcheck.c +#: py/argcheck.c shared-bindings/usb_hid/Device.c msgid "%q length must be %d" msgstr "" @@ -130,14 +130,10 @@ msgstr "" msgid "%q length must be <= %d" msgstr "" -#: py/argcheck.c +#: py/argcheck.c shared-bindings/busio/I2C.c msgid "%q length must be >= %d" msgstr "" -#: shared-bindings/busio/I2C.c -msgid "%q length must be >= 1" -msgstr "" - #: py/argcheck.c msgid "%q must be %d" msgstr "" @@ -163,14 +159,6 @@ msgstr "" msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" msgstr "" -#: py/argcheck.c -msgid "%q must be a string" -msgstr "" - -#: py/argcheck.c -msgid "%q must be an int" -msgstr "" - #: py/argcheck.c py/obj.c msgid "%q must be of type %q" msgstr "" @@ -201,10 +189,6 @@ msgstr "" msgid "%q pin invalid" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q with a report ID of 0 must be of length 1" -msgstr "" - #: py/bc.c py/objnamedtuple.c msgid "%q() takes %d positional arguments but %d were given" msgstr "" @@ -511,10 +495,6 @@ msgstr "" msgid "Array values should be single bytes." msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "At most %d %q may be specified (not %d)" -msgstr "" - #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -1260,10 +1240,6 @@ msgstr "" msgid "Invalid multicast MAC address" msgstr "" -#: shared-bindings/busio/UART.c -msgid "Invalid pins" -msgstr "" - #: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c msgid "Invalid size" msgstr "" @@ -1501,11 +1477,6 @@ msgstr "" msgid "No long integer support" msgstr "" -#: shared-module/usb_hid/__init__.c -#, c-format -msgid "No more than %d HID devices allowed" -msgstr "" - #: shared-bindings/wifi/Radio.c msgid "No network with that ssid" msgstr "" @@ -2545,10 +2516,6 @@ msgstr "" msgid "buffer too small for requested bytes" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -msgid "byteorder is not a string" -msgstr "" - #: py/objarray.c msgid "bytes length not a multiple of item size" msgstr "" @@ -2590,14 +2557,10 @@ msgstr "" msgid "can't cancel self" msgstr "" -#: py/obj.c py/objint.c shared-module/adafruit_pixelbuf/PixelBuf.c +#: py/obj.c py/objint.c py/runtime.c shared-module/adafruit_pixelbuf/PixelBuf.c msgid "can't convert %q to %q" msgstr "" -#: py/runtime.c -msgid "can't convert %q to int" -msgstr "" - #: py/obj.c #, c-format msgid "can't convert %s to complex" @@ -2781,10 +2744,6 @@ msgstr "" msgid "comparison of int and uint" msgstr "" -#: py/objcomplex.c -msgid "complex division by zero" -msgstr "" - #: py/objfloat.c py/parsenum.c msgid "complex values not supported" msgstr "" @@ -2887,12 +2846,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: py/objfloat.c py/objint_mpz.c -msgid "divide by zero" -msgstr "" - -#: py/modmath.c py/objint_longlong.c py/runtime.c -#: shared-bindings/math/__init__.c +#: py/runtime.c shared-bindings/math/__init__.c msgid "division by zero" msgstr "" @@ -4043,10 +3997,6 @@ msgstr "" msgid "syntax error in uctypes descriptor" msgstr "" -#: shared-bindings/time/__init__.c -msgid "time.struct_time() takes a 9-sequence" -msgstr "" - #: ports/atmel-samd/common-hal/watchdog/WatchDogTimer.c #: ports/espressif/common-hal/watchdog/WatchDogTimer.c #: ports/nrf/common-hal/watchdog/WatchDogTimer.c diff --git a/py/modmath.c b/py/modmath.c index 167d46d02b..bf27e68eaf 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -254,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, MP_ERROR_TEXT("division by zero")); + mp_raise_ZeroDivisionError(); } return mp_obj_new_float(l / MICROPY_FLOAT_C_FUN(log)(base)); } diff --git a/py/objcomplex.c b/py/objcomplex.c index f205249bb4..7f4fd621e6 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -217,7 +217,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_INPLACE_TRUE_DIVIDE: if (rhs_imag == 0) { if (rhs_real == 0) { - mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("complex division by zero")); + mp_raise_ZeroDivisionError(); } lhs_real /= rhs_real; lhs_imag /= rhs_real; diff --git a/py/objfloat.c b/py/objfloat.c index f8261df933..7aebcfdeb2 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -266,7 +266,7 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: if (rhs_val == 0) { zero_division_error: - mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero")); + mp_raise_ZeroDivisionError(); } // Python specs require that x == (x//y)*y + (x%y) so we must // call divmod to compute the correct floor division, which diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 67ec844f47..d318eab38e 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -236,7 +236,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, MP_ERROR_TEXT("division by zero")); + mp_raise_ZeroDivisionError(); } mp_obj_t mp_obj_new_int(mp_int_t value) { diff --git a/py/objint_mpz.c b/py/objint_mpz.c index fd74803fe7..e147e5f08a 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -244,7 +244,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_FLOOR_DIVIDE: { if (mpz_is_zero(zrhs)) { zero_division_error: - mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero")); + mp_raise_ZeroDivisionError(); } mpz_t rem; mpz_init_zero(&rem); diff --git a/py/runtime.c b/py/runtime.c index e3750b7448..6be5c22335 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -631,7 +631,7 @@ unsupported_op: #endif zero_division: - mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("division by zero")); + mp_raise_ZeroDivisionError(); } mp_obj_t mp_call_function_0(mp_obj_t fun) { @@ -1765,3 +1765,7 @@ NORETURN void mp_raise_recursion_depth(void) { mp_raise_RuntimeError(MP_ERROR_TEXT("maximum recursion depth exceeded")); } #endif + +NORETURN void mp_raise_ZeroDivisionError(void) { + mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("division by zero")); +} diff --git a/py/runtime.h b/py/runtime.h index 923071f7ca..951165e279 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -226,6 +226,7 @@ NORETURN void mp_raise_NotImplementedError(const compressed_string_t *msg); NORETURN void mp_raise_NotImplementedError_varg(const compressed_string_t *fmt, ...); NORETURN void mp_raise_OverflowError_varg(const compressed_string_t *fmt, ...); NORETURN void mp_raise_recursion_depth(void); +NORETURN void mp_raise_ZeroDivisionError(void); #endif #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG From f67bca94c4d190e95bd376c1ce883cf17f2437b5 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 15:26:46 -0600 Subject: [PATCH 14/32] On python3 log(0) raises math domain error, not zerodivisionerror --- shared-bindings/math/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/math/__init__.c b/shared-bindings/math/__init__.c index 58405564db..42a32749da 100644 --- a/shared-bindings/math/__init__.c +++ b/shared-bindings/math/__init__.c @@ -371,7 +371,7 @@ STATIC mp_obj_t mp_math_log(size_t n_args, const mp_obj_t *args) { #pragma GCC diagnostic ignored "-Wfloat-equal" } else if (base == (mp_float_t)1.0) { #pragma GCC diagnostic pop - mp_raise_msg(&mp_type_ZeroDivisionError, translate("division by zero")); + math_error(); } return mp_obj_new_float(l / MICROPY_FLOAT_C_FUN(log)(base)); } From 5fb191b51c84164788605a7657356eda18ec6baa Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 15:28:33 -0600 Subject: [PATCH 15/32] Use a standard validator --- py/parsenum.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/parsenum.c b/py/parsenum.c index adf2a4d84d..24d46705a7 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -55,9 +55,9 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m mp_obj_t ret_val; // check radix base - if ((base != 0 && base < 2) || base > 36) { + if (base != 0) { // this won't be reached if lex!=NULL - mp_raise_ValueError(MP_ERROR_TEXT("int() arg 2 must be >= 2 and <= 36")); + mp_arg_validate_int_range(base, 2, 36, MP_QSTR_base); } // skip leading space From d61fde349d42d54d10ccb542534ff002bf201abf Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 15:30:43 -0600 Subject: [PATCH 16/32] re-use an error message --- py/objint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objint.c b/py/objint.c index b44a2e3b4a..6dc675823f 100644 --- a/py/objint.c +++ b/py/objint.c @@ -396,7 +396,7 @@ 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, MP_ERROR_TEXT("long int not supported in this build")); + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow")); return mp_const_none; } From d39d146352186b61279a0795ca270fcde56a6877 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 15:36:23 -0600 Subject: [PATCH 17/32] Merge some messages --- locale/circuitpython.pot | 26 +++++--------------------- py/objrange.c | 2 +- py/objslice.c | 2 +- shared-bindings/random/__init__.c | 2 +- 4 files changed, 8 insertions(+), 24 deletions(-) mode change 100755 => 100644 locale/circuitpython.pot diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot old mode 100755 new mode 100644 index 9928ca03e0..e85b9f5d72 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -189,6 +189,10 @@ msgstr "" msgid "%q pin invalid" msgstr "" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "" + #: py/bc.c py/objnamedtuple.c msgid "%q() takes %d positional arguments but %d were given" msgstr "" @@ -2846,7 +2850,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: py/runtime.c shared-bindings/math/__init__.c +#: py/runtime.c msgid "division by zero" msgstr "" @@ -3218,10 +3222,6 @@ msgstr "" msgid "inputs are not iterable" msgstr "" -#: py/parsenum.c -msgid "int() arg 2 must be >= 2 and <= 36" -msgstr "" - #: extmod/ulab/code/numpy/approx.c msgid "interp is defined for 1D iterables of equal length" msgstr "" @@ -3359,10 +3359,6 @@ msgstr "" msgid "local variable referenced before assignment" msgstr "" -#: py/objint.c -msgid "long int not supported in this build" -msgstr "" - #: ports/espressif/common-hal/canio/CAN.c msgid "loopback + silent mode not supported by peripheral" msgstr "" @@ -3897,10 +3893,6 @@ msgstr "" msgid "slice step can't be zero" msgstr "" -#: py/objslice.c -msgid "slice step cannot be zero" -msgstr "" - #: py/nativeglue.c msgid "slice unsupported" msgstr "" @@ -3949,10 +3941,6 @@ msgstr "" msgid "start/end indices" msgstr "" -#: shared-bindings/random/__init__.c -msgid "step must be non-zero" -msgstr "" - #: shared-bindings/random/__init__.c msgid "stop not reachable from start" msgstr "" @@ -4278,10 +4266,6 @@ msgstr "" msgid "y value out of bounds" msgstr "" -#: py/objrange.c -msgid "zero step" -msgstr "" - #: extmod/ulab/code/scipy/signal/signal.c msgid "zi must be an ndarray" msgstr "" diff --git a/py/objrange.c b/py/objrange.c index b0c74815dc..78a5fcd0f8 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -110,7 +110,7 @@ STATIC mp_obj_t range_make_new(const mp_obj_type_t *type, size_t n_args, size_t if (n_args == 3) { o->step = mp_obj_get_int(args[2]); if (o->step == 0) { - mp_raise_ValueError(MP_ERROR_TEXT("zero step")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q step cannot be zero"), MP_QSTR_range); } } } diff --git a/py/objslice.c b/py/objslice.c index 3172f798c0..395af727e8 100644 --- a/py/objslice.c +++ b/py/objslice.c @@ -157,7 +157,7 @@ void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *r } else { step = mp_obj_get_int(self->step); if (step == 0) { - mp_raise_ValueError(MP_ERROR_TEXT("slice step cannot be zero")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q step cannot be zero"), MP_QSTR_slice); } } diff --git a/shared-bindings/random/__init__.c b/shared-bindings/random/__init__.c index 29c6a0e74b..fcf432931e 100644 --- a/shared-bindings/random/__init__.c +++ b/shared-bindings/random/__init__.c @@ -108,7 +108,7 @@ STATIC mp_obj_t random_randrange(size_t n_args, const mp_obj_t *args) { } else if (step < 0) { n = (stop - start + step + 1) / step; } else { - mp_raise_ValueError(translate("step must be non-zero")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q step cannot be zero"), MP_QSTR_randrange); } if (n <= 0) { mp_raise_ValueError(translate("invalid step")); From a94663b3c9359e076fd5a49a4f2097996d9351f4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 15:37:57 -0600 Subject: [PATCH 18/32] use a standard error message --- py/objstrunicode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 0f26da62cf..863bbd42d7 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -159,7 +159,7 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s if (mp_obj_is_small_int(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { - mp_raise_TypeError_varg(MP_ERROR_TEXT("string indices must be integers, not %q"), mp_obj_get_type_qstr(index)); + mp_raise_TypeError_varg(translate("%q must be of type %q"), MP_QSTR_index, MP_QSTR_int); } const byte *s, *top = self_data + self_len; if (i < 0) { From 4158ddfc17c825017d4e989d2cdf027f9563e3d6 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 15:40:59 -0600 Subject: [PATCH 19/32] compile out terse mismatch message when not used --- py/argcheck.c | 2 ++ py/runtime.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/py/argcheck.c b/py/argcheck.c index 9ec21d4898..01c712ac36 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -145,9 +145,11 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals); } +#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE NORETURN void mp_arg_error_terse_mismatch(void) { mp_raise_TypeError(MP_ERROR_TEXT("argument num/types mismatch")); } +#endif #if MICROPY_CPYTHON_COMPAT NORETURN void mp_arg_error_unimpl_kw(void) { diff --git a/py/runtime.h b/py/runtime.h index 951165e279..a5f66b1507 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -91,7 +91,9 @@ static inline void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_mi } void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); +#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE NORETURN void mp_arg_error_terse_mismatch(void); +#endif NORETURN void mp_arg_error_unimpl_kw(void); NORETURN void mp_arg_error_invalid(qstr arg_name); From c46e219795db804c04d80ec474b555510ab300b3 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 15:46:48 -0600 Subject: [PATCH 20/32] Having an input-only pin is rare, save a string on other ports --- ports/espressif/mpconfigport.h | 2 ++ py/circuitpy_mpconfig.h | 4 ++++ shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c | 4 ++++ shared-bindings/digitalio/DigitalInOut.c | 2 ++ shared-bindings/digitalio/DigitalInOut.h | 2 ++ 5 files changed, 14 insertions(+) diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index 632a7a13cd..1b154b4b99 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -99,4 +99,6 @@ #define CIRCUITPY_PORT_NUM_SUPERVISOR_ALLOCATIONS (1) #endif +#define CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY (1) + #endif // MICROPY_INCLUDED_ESPRESSIF_MPCONFIGPORT_H diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index d6d8419c8f..dc528d0787 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -582,6 +582,10 @@ void supervisor_run_background_tasks_if_tick(void); #define MICROPY_WRAP_MP_EXECUTE_BYTECODE PLACE_IN_ITCM #endif +#ifndef CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY +#define CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY (0) +#endif + #ifndef CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL #define CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL (0) #endif diff --git a/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c b/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c index afb11856e2..6626d27f77 100644 --- a/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +++ b/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c @@ -105,9 +105,13 @@ STATIC mp_obj_t adafruit_bus_device_spidevice_make_new(const mp_obj_type_t *type if (args[ARG_chip_select].u_obj != MP_OBJ_NULL) { digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(MP_OBJ_TO_PTR(args[ARG_chip_select].u_obj), true, DRIVE_MODE_PUSH_PULL); + #if CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY if (result == DIGITALINOUT_INPUT_ONLY) { mp_raise_NotImplementedError(translate("Pin is input only")); } + #else + (void)result; + #endif } return (mp_obj_t)self; diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index eb3c1ec69d..e6fe592a65 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -53,8 +53,10 @@ STATIC void check_result(digitalinout_result_t result) { return; case DIGITALINOUT_PIN_BUSY: mp_raise_ValueError_varg(translate("%q in use"), MP_QSTR_Pin); + #if CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY case DIGITALINOUT_INPUT_ONLY: mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_direction); + #endif #if CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL case DIGITALINOUT_INVALID_PULL: mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_pull); diff --git a/shared-bindings/digitalio/DigitalInOut.h b/shared-bindings/digitalio/DigitalInOut.h index 80c3970f0e..79a700c905 100644 --- a/shared-bindings/digitalio/DigitalInOut.h +++ b/shared-bindings/digitalio/DigitalInOut.h @@ -38,7 +38,9 @@ extern const mp_obj_type_t digitalio_digitalinout_type; typedef enum { DIGITALINOUT_OK, DIGITALINOUT_PIN_BUSY, + #if CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY DIGITALINOUT_INPUT_ONLY, + #endif #if CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL DIGITALINOUT_INVALID_PULL, #endif From 4671658c63bb39072d79d57c770321e03cc7fd63 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 16:32:34 -0600 Subject: [PATCH 21/32] Use ASCII apostrophe in french translation, it saves flash space .. it makes mchar_t, the type of storage needed for all the code points in all translation messages, be an 8-bit type instead of a 16-bit type --- locale/fr.po | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/locale/fr.po b/locale/fr.po index 9f6bfba96b..905116cb71 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -684,7 +684,7 @@ msgstr "Les blocs CBC doivent être des multiples de 16 octets" #: supervisor/shared/safe_mode.c msgid "CIRCUITPY drive could not be found or created." -msgstr "L’appareil CIRCUITPY ne peut pas être trouvé ou créé." +msgstr "L'appareil CIRCUITPY ne peut pas être trouvé ou créé." #: ports/espressif/common-hal/espidf/__init__.c ports/espressif/esp_error.c msgid "CRC or checksum was invalid" @@ -842,11 +842,11 @@ msgstr "Fichier .mpy corrompu" #: ports/espressif/common-hal/neopixel_write/__init__.c msgid "Could not retrieve clock" -msgstr "Impossible d’obtenir l’horloge" +msgstr "Impossible d'obtenir l'horloge" #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" -msgstr "Impossible de définir l’adresse" +msgstr "Impossible de définir l'adresse" #: shared-bindings/pwmio/PWMOut.c msgid "Could not start PWM" @@ -1006,7 +1006,7 @@ msgstr "Échec d'allocation du tampon %q" #: ports/espressif/common-hal/wifi/__init__.c msgid "Failed to allocate Wifi memory" -msgstr "Impossible d’allouer la mémoire pour Wifi" +msgstr "Impossible d'allouer la mémoire pour Wifi" #: ports/espressif/common-hal/wifi/ScannedNetworks.c msgid "Failed to allocate wifi scan memory" @@ -1833,7 +1833,7 @@ msgstr "Ainsi que tout autres modules présents sur le système de fichiers\n" #: shared-module/vectorio/Polygon.c msgid "Polygon needs at least 3 points" -msgstr "Polygon a besoin d’au moins 3 points" +msgstr "Polygon a besoin d'au moins 3 points" #: shared-bindings/_bleio/Adapter.c msgid "Prefix buffer must be on the heap" @@ -2552,7 +2552,7 @@ msgstr "matrice/octets requis à la droite" #: extmod/ulab/code/numpy/numerical.c msgid "attempt to get (arg)min/(arg)max of empty sequence" -msgstr "tentative d’obtenir (arg)min/(arg)max d'une séquence vide" +msgstr "tentative d'obtenir (arg)min/(arg)max d'une séquence vide" #: extmod/ulab/code/numpy/numerical.c msgid "attempt to get argmin/argmax of an empty sequence" @@ -2620,7 +2620,7 @@ msgstr "tampon est plus petit que la taille demandée" #: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c msgid "buffer size must be a multiple of element size" -msgstr "taille du tampon doit être un multiple de la taille de l’élément" +msgstr "taille du tampon doit être un multiple de la taille de l'élément" #: shared-module/struct/__init__.c msgid "buffer size must match format" @@ -3181,7 +3181,7 @@ msgstr "la fonction a reçu plusieurs valeurs pour l'argument '%q'" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "function has the same sign at the ends of interval" -msgstr "la fonction a le même signe aux extrémités de l’intervalle" +msgstr "la fonction a le même signe aux extrémités de l'intervalle" #: extmod/ulab/code/ndarray.c msgid "function is defined for ndarrays only" @@ -4186,11 +4186,11 @@ msgstr "le délai (timeout) doit être < 655.35 secondes" #: shared-module/sdcardio/SDCard.c msgid "timeout waiting for v1 card" -msgstr "Délai d’expiration dépassé en attendant une carte v1" +msgstr "Délai d'expiration dépassé en attendant une carte v1" #: shared-module/sdcardio/SDCard.c msgid "timeout waiting for v2 card" -msgstr "Délai d’expiration dépassé en attendant une carte v2" +msgstr "Délai d'expiration dépassé en attendant une carte v2" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "timer re-init" @@ -4390,7 +4390,7 @@ msgstr "width doit être plus que zero" #: ports/espressif/common-hal/wifi/Radio.c #: ports/raspberrypi/common-hal/wifi/Radio.c msgid "wifi is not enabled" -msgstr "wifi n’est pas activé" +msgstr "wifi n'est pas activé" #: ports/raspberrypi/common-hal/wifi/Monitor.c msgid "wifi.Monitor not available" From 9c11bb2ed9b20c8b1709b994336264b724ebd92a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 17:04:58 -0600 Subject: [PATCH 22/32] Check that translations fit in expected character type --- py/maketranslationdata.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/py/maketranslationdata.py b/py/maketranslationdata.py index c0ae85f4e0..19bbc443a3 100644 --- a/py/maketranslationdata.py +++ b/py/maketranslationdata.py @@ -146,7 +146,10 @@ def iter_substrings(s, minlen, maxlen): yield s[begin : begin + n] -def compute_huffman_coding(translations, f): +translation_requires_uint16 = {"cs", "el", "fr", "ja", "ko", "pl", "ru", "tr", "zh_Latn_pinyin"} + + +def compute_huffman_coding(translation_name, translations, f): texts = [t[1] for t in translations] words = [] @@ -163,6 +166,12 @@ def compute_huffman_coding(translations, f): bits_per_codepoint = 16 if max_ord > 255 else 8 values_type = "uint16_t" if max_ord > 255 else "uint8_t" + translation_name = translation_name.split("/")[-1].split(".")[0] + if max_ord > 255 and translation_name not in translation_requires_uint16: + raise ValueError( + f"Translation {translation_name} expected to fit in 8 bits but required 16 bits" + ) + while len(words) < max_words: # Until the dictionary is filled to capacity, use a heuristic to find # the best "word" (2- to 11-gram) to add to it. @@ -522,5 +531,7 @@ if __name__ == "__main__": i18ns = parse_input_headers(args.infiles) i18ns = sorted(i18ns) translations = translate(args.translation, i18ns) - encoding_table = compute_huffman_coding(translations, args.compression_filename) + encoding_table = compute_huffman_coding( + args.translation, translations, args.compression_filename + ) output_translation_data(encoding_table, translations, args.translation_filename) From 6be0a425c751574074ff92637303c1236a8754ab Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 17:05:09 -0600 Subject: [PATCH 23/32] Don't run maketranslationdata twice --- py/py.mk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/py/py.mk b/py/py.mk index 6827fbe786..0cbfd252f2 100644 --- a/py/py.mk +++ b/py/py.mk @@ -262,8 +262,15 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(PY_SRC)/makeqstrdata.py $(HEADER_BUILD)/ $(STEPECHO) "GEN $@" $(Q)$(PYTHON) $(PY_SRC)/makeqstrdata.py --output_type=data $(HEADER_BUILD)/qstrdefs.preprocessed.h > $@ -$(PY_BUILD)/translations-$(TRANSLATION).c $(HEADER_BUILD)/compression.generated.h: $(PY_SRC)/maketranslationdata.py $(HEADER_BUILD)/$(TRANSLATION).mo $(HEADER_BUILD)/qstrdefs.preprocessed.h +# Is generated as a side-effect of building compression.generated.h +# Specifying both in a single rule actually causes the rule to be run twice! +# This alternative makes it run just once. +$(PY_BUILD)/translations-$(TRANSLATION).c: $(HEADER_BUILD)/compression.generated.h + @true + +$(HEADER_BUILD)/compression.generated.h: $(PY_SRC)/maketranslationdata.py $(HEADER_BUILD)/$(TRANSLATION).mo $(HEADER_BUILD)/qstrdefs.preprocessed.h $(STEPECHO) "GEN $@" + $(Q)mkdir -p $(PY_BUILD) $(Q)$(PYTHON) $(PY_SRC)/maketranslationdata.py --compression_filename $(HEADER_BUILD)/compression.generated.h --translation $(HEADER_BUILD)/$(TRANSLATION).mo --translation_filename $(PY_BUILD)/translations-$(TRANSLATION).c $(HEADER_BUILD)/qstrdefs.preprocessed.h PY_CORE_O += $(PY_BUILD)/translations-$(TRANSLATION).o From 530e5a1df274cb352c147c8ce3e24b4bd4f2f475 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 17:08:53 -0600 Subject: [PATCH 24/32] Use standard validation function --- shared-bindings/busio/I2C.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index 3dd645b256..e589dea08b 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -344,9 +344,7 @@ STATIC mp_obj_t busio_i2c_writeto_then_readfrom(size_t n_args, const mp_obj_t *p int32_t in_start = args[ARG_in_start].u_int; const int32_t in_end = args[ARG_in_end].u_int; normalize_buffer_bounds(&in_start, in_end, &in_length); - if (in_length == 0) { - mp_raise_ValueError_varg(translate("%q length must be >= %d"), MP_QSTR_out_buffer, 1); - } + mp_arg_validate_length_min(in_length, 1, MP_QSTR_out_buffer); uint8_t status = common_hal_busio_i2c_write_read(self, args[ARG_address].u_int, ((uint8_t *)out_bufinfo.buf) + out_start, out_length,((uint8_t *)in_bufinfo.buf) + in_start, in_length); From 19a3893d40aa07232368f327584d7321446f66d0 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 17:48:04 -0600 Subject: [PATCH 25/32] update translations again --- locale/circuitpython.pot | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index e85b9f5d72..1875781e9d 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -130,7 +130,7 @@ msgstr "" msgid "%q length must be <= %d" msgstr "" -#: py/argcheck.c shared-bindings/busio/I2C.c +#: py/argcheck.c msgid "%q length must be >= %d" msgstr "" @@ -159,7 +159,7 @@ msgstr "" msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" msgstr "" -#: py/argcheck.c py/obj.c +#: py/argcheck.c py/obj.c py/objstrunicode.c msgid "%q must be of type %q" msgstr "" @@ -3949,10 +3949,6 @@ msgstr "" msgid "stream operation not supported" msgstr "" -#: py/objstrunicode.c -msgid "string indices must be integers, not %q" -msgstr "" - #: py/stream.c msgid "string not supported; use bytes or bytearray" msgstr "" From 0f6091cc73e8bc38855015518bb2643be64469e4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 18:54:53 -0600 Subject: [PATCH 26/32] update fil translation to fit in uint8_t --- locale/fil.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/locale/fil.po b/locale/fil.po index 2cf6e49da4..8d9a48bd69 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -282,7 +282,7 @@ msgstr "Inaasahan ng '%s' ang hangang r%d" #: py/emitinlinethumb.c #, c-format msgid "'%s' expects {r0, r1, ...}" -msgstr "Inaasahan ng '%s' ay {r0, r1, …}" +msgstr "Inaasahan ng '%s' ay {r0, r1, ...}" #: py/emitinlinextensa.c #, c-format @@ -2789,7 +2789,7 @@ msgstr "" #: shared-bindings/displayio/Palette.c msgid "color buffer must be a bytearray or array of type 'b' or 'B'" -msgstr "ang color buffer ay dapat bytearray o array na type ‘b’ or ‘B’" +msgstr "ang color buffer ay dapat bytearray o array na type 'b' or 'B'" #: shared-bindings/displayio/Palette.c msgid "color must be between 0x000000 and 0xffffff" @@ -3911,7 +3911,7 @@ msgstr "return annotation ay dapat na identifier" #: py/emitnative.c msgid "return expected '%q' but got '%q'" -msgstr "return umasa ng '%q' pero ang nakuha ay ‘%q’" +msgstr "return umasa ng '%q' pero ang nakuha ay '%q'" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format @@ -4621,7 +4621,7 @@ msgstr "" #~ "Mangyaring bisitahin ang learn.adafruit.com/category/circuitpython para " #~ "sa project guides.\n" #~ "\n" -#~ "Para makita ang listahan ng modules, `help(“modules”)`.\n" +#~ "Para makita ang listahan ng modules, `help(\"modules\")`.\n" #~ msgid "integer required" #~ msgstr "kailangan ng int" From ed33f65fd9c59c2948bdfc5eace43f9046daeae0 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 18:57:33 -0600 Subject: [PATCH 27/32] move define to proper place --- ports/espressif/mpconfigport.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index 1b154b4b99..c296be2024 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -33,6 +33,8 @@ #define MICROPY_USE_INTERNAL_PRINTF (0) #define MICROPY_PY_SYS_PLATFORM "Espressif" +#define CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY (1) + #include "py/circuitpy_mpconfig.h" #if CIRCUITPY_BLEIO @@ -99,6 +101,4 @@ #define CIRCUITPY_PORT_NUM_SUPERVISOR_ALLOCATIONS (1) #endif -#define CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY (1) - #endif // MICROPY_INCLUDED_ESPRESSIF_MPCONFIGPORT_H From 9916b39b656f3a74d522e799a406c05d9172462a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 8 Nov 2022 19:44:33 -0600 Subject: [PATCH 28/32] update nl translation to fit in uint8_t --- locale/nl.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locale/nl.po b/locale/nl.po index e002370151..acd7b53fd3 100644 --- a/locale/nl.po +++ b/locale/nl.po @@ -283,7 +283,7 @@ msgstr "'%s' verwacht op zijn meest r%d" #: py/emitinlinethumb.c #, c-format msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' verwacht {r0, r1, …}" +msgstr "'%s' verwacht {r0, r1, ...}" #: py/emitinlinextensa.c #, c-format From d16c9515b7d980ddca02835024762e4d604d5747 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 9 Nov 2022 06:58:09 -0600 Subject: [PATCH 29/32] Compact the characters of certain translations, so they fit in uint8_t This saves a few hundred bytes on the affected translations, such as `el` which shrunk from 186152 to 185588 bytes (564 bytes saved). --- py/maketranslationdata.py | 80 ++++++++++++++++++++++--- supervisor/shared/translate/translate.c | 3 + 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/py/maketranslationdata.py b/py/maketranslationdata.py index 19bbc443a3..98c3d77dbb 100644 --- a/py/maketranslationdata.py +++ b/py/maketranslationdata.py @@ -10,6 +10,7 @@ supervisor/shared/translate/translate.h from __future__ import print_function import bisect +from dataclasses import dataclass import re import sys @@ -146,7 +147,40 @@ def iter_substrings(s, minlen, maxlen): yield s[begin : begin + n] -translation_requires_uint16 = {"cs", "el", "fr", "ja", "ko", "pl", "ru", "tr", "zh_Latn_pinyin"} +translation_requires_uint16 = {"cs", "fr", "ja", "ko", "pl", "tr", "zh_Latn_pinyin"} + + +def compute_unicode_offset(texts): + all_ch = set(" ".join(texts)) + ch_160 = sorted(c for c in all_ch if 160 <= ord(c) < 255) + ch_256 = sorted(c for c in all_ch if 255 < ord(c)) + if not ch_256: + return 0, 0 + min_256 = ord(min(ch_256)) + span = ord(max(ch_256)) - ord(min(ch_256)) + 1 + + if ch_160: + max_160 = ord(max(ch_160)) + 1 + else: + max_160 = max(160, 255 - span) + + if max_160 + span > 256: + return 0, 0 + + offstart = max_160 + offset = min_256 - max_160 + return offstart, offset + + +@dataclass +class EncodingTable: + values: object + lengths: object + words: object + canonical: object + extractor: object + apply_offset: object + remove_offset: object def compute_huffman_coding(translation_name, translations, f): @@ -156,8 +190,26 @@ def compute_huffman_coding(translation_name, translations, f): start_unused = 0x80 end_unused = 0xFF max_ord = 0 + offstart, offset = compute_unicode_offset(texts) + + def apply_offset(c): + oc = ord(c) + if oc >= offstart: + oc += offset + return chr(oc) + + def remove_offset(c): + oc = ord(c) + if oc >= offstart: + oc = oc - offset + try: + return chr(oc) + except Exception as e: + raise ValueError(f"remove_offset {offstart=} {oc=}") from e + for text in texts: for c in text: + c = remove_offset(c) ord_c = ord(c) max_ord = max(ord_c, max_ord) if 0x80 <= ord_c < 0xFF: @@ -276,15 +328,17 @@ def compute_huffman_coding(translation_name, translations, f): length_count[length] += 1 if last_length: renumbered <<= length - last_length - canonical[atom] = "{0:0{width}b}".format(renumbered, width=length) # print(f"atom={repr(atom)} code={code}", file=sys.stderr) + canonical[atom] = "{0:0{width}b}".format(renumbered, width=length) if len(atom) > 1: o = words.index(atom) + 0x80 s = "".join(C_ESCAPES.get(ch1, ch1) for ch1 in atom) + f.write(f"// {o} {s} {counter[atom]} {canonical[atom]} {renumbered}\n") else: s = C_ESCAPES.get(atom, atom) + canonical[atom] = "{0:0{width}b}".format(renumbered, width=length) o = ord(atom) - f.write(f"// {o} {s} {counter[atom]} {canonical[atom]} {renumbered}\n") + f.write(f"// {o} {s} {counter[atom]} {canonical[atom]} {renumbered}\n") renumbered += 1 last_length = length lengths = bytearray() @@ -306,7 +360,11 @@ def compute_huffman_coding(translation_name, translations, f): f.write("typedef {} mchar_t;\n".format(values_type)) f.write("const uint8_t lengths[] = {{ {} }};\n".format(", ".join(map(str, lengths)))) - f.write("const mchar_t values[] = {{ {} }};\n".format(", ".join(str(ord(u)) for u in values))) + f.write( + "const mchar_t values[] = {{ {} }};\n".format( + ", ".join(str(ord(remove_offset(u))) for u in values) + ) + ) f.write( "#define compress_max_length_bits ({})\n".format( max_translation_encoded_length.bit_length() @@ -314,7 +372,7 @@ def compute_huffman_coding(translation_name, translations, f): ) f.write( "const mchar_t words[] = {{ {} }};\n".format( - ", ".join(str(ord(c)) for w in words for c in w) + ", ".join(str(ord(remove_offset(c))) for w in words for c in w) ) ) f.write("const uint8_t wlencount[] = {{ {} }};\n".format(", ".join(str(p) for p in wlencount))) @@ -322,12 +380,17 @@ def compute_huffman_coding(translation_name, translations, f): f.write("#define word_end {}\n".format(word_end)) f.write("#define minlen {}\n".format(minlen)) f.write("#define maxlen {}\n".format(maxlen)) + f.write("#define offstart {}\n".format(offstart)) + f.write("#define offset {}\n".format(offset)) - return (values, lengths, words, canonical, extractor) + return EncodingTable(values, lengths, words, canonical, extractor, apply_offset, remove_offset) def decompress(encoding_table, encoded, encoded_length_bits): - (values, lengths, words, _, _) = encoding_table + values = encoding_table.values + lengths = encoding_table.lengths + words = encoding_table.words + dec = [] this_byte = 0 this_bit = 7 @@ -385,7 +448,8 @@ def decompress(encoding_table, encoded, encoded_length_bits): def compress(encoding_table, decompressed, encoded_length_bits, len_translation_encoded): if not isinstance(decompressed, str): raise TypeError() - (_, _, _, canonical, extractor) = encoding_table + canonical = encoding_table.canonical + extractor = encoding_table.extractor enc = bytearray(len(decompressed) * 3) current_bit = 7 diff --git a/supervisor/shared/translate/translate.c b/supervisor/shared/translate/translate.c index ae6c7524e5..423c5444fd 100644 --- a/supervisor/shared/translate/translate.c +++ b/supervisor/shared/translate/translate.c @@ -57,6 +57,9 @@ STATIC void get_word(int n, const mchar_t **pos, const mchar_t **end) { } STATIC int put_utf8(char *buf, int u) { + if (u >= offstart) { + u += offset; + } if (u <= 0x7f) { *buf = u; return 1; From e5b83821f8b28153c1fdce34c8645d98ec1712f4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 9 Nov 2022 07:00:25 -0600 Subject: [PATCH 30/32] fr should fit in 8 bits --- py/maketranslationdata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/maketranslationdata.py b/py/maketranslationdata.py index 98c3d77dbb..938e8de667 100644 --- a/py/maketranslationdata.py +++ b/py/maketranslationdata.py @@ -147,7 +147,7 @@ def iter_substrings(s, minlen, maxlen): yield s[begin : begin + n] -translation_requires_uint16 = {"cs", "fr", "ja", "ko", "pl", "tr", "zh_Latn_pinyin"} +translation_requires_uint16 = {"cs", "ja", "ko", "pl", "tr", "zh_Latn_pinyin"} def compute_unicode_offset(texts): From fb66a6bfe57d5b55c25291ef021c4133a4880ae0 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 9 Nov 2022 07:57:36 -0600 Subject: [PATCH 31/32] Don't use "offset" as an identifier --- py/maketranslationdata.py | 4 ++-- supervisor/shared/translate/translate.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/py/maketranslationdata.py b/py/maketranslationdata.py index 938e8de667..fbf396c73f 100644 --- a/py/maketranslationdata.py +++ b/py/maketranslationdata.py @@ -380,8 +380,8 @@ def compute_huffman_coding(translation_name, translations, f): f.write("#define word_end {}\n".format(word_end)) f.write("#define minlen {}\n".format(minlen)) f.write("#define maxlen {}\n".format(maxlen)) - f.write("#define offstart {}\n".format(offstart)) - f.write("#define offset {}\n".format(offset)) + f.write("#define translation_offstart {}\n".format(offstart)) + f.write("#define translation_offset {}\n".format(offset)) return EncodingTable(values, lengths, words, canonical, extractor, apply_offset, remove_offset) diff --git a/supervisor/shared/translate/translate.c b/supervisor/shared/translate/translate.c index 423c5444fd..b07aa584ca 100644 --- a/supervisor/shared/translate/translate.c +++ b/supervisor/shared/translate/translate.c @@ -57,8 +57,8 @@ STATIC void get_word(int n, const mchar_t **pos, const mchar_t **end) { } STATIC int put_utf8(char *buf, int u) { - if (u >= offstart) { - u += offset; + if (u >= translation_offstart) { + u += translation_offset; } if (u <= 0x7f) { *buf = u; From d2e2a6107523951c9ab93a4ef812b7ffaeb06866 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 9 Nov 2022 08:28:56 -0600 Subject: [PATCH 32/32] Reworking how "run list" works saves a dozen bytes --- main.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/main.c b/main.c index 10fdc65224..d70e718b6d 100644 --- a/main.c +++ b/main.c @@ -218,12 +218,10 @@ void supervisor_execution_status(void) { } #endif -#define STRING_LIST(...) {__VA_ARGS__, ""} - // Look for the first file that exists in the list of filenames, using mp_import_stat(). // Return its index. If no file found, return -1. -STATIC const char *first_existing_file_in_list(const char *const *filenames) { - for (int i = 0; filenames[i] != (char *)""; i++) { +STATIC const char *first_existing_file_in_list(const char *const *filenames, size_t n_filenames) { + for (size_t i = 0; i < n_filenames; i++) { mp_import_stat_t stat = mp_import_stat(filenames[i]); if (stat == MP_IMPORT_STAT_FILE) { return filenames[i]; @@ -232,11 +230,11 @@ STATIC const char *first_existing_file_in_list(const char *const *filenames) { return NULL; } -STATIC bool maybe_run_list(const char *const *filenames) { +STATIC bool maybe_run_list(const char *const *filenames, size_t n_filenames) { _exec_result.return_code = 0; _exec_result.exception = MP_OBJ_NULL; _exec_result.exception_line = 0; - _current_executing_filename = first_existing_file_in_list(filenames); + _current_executing_filename = first_existing_file_in_list(filenames, n_filenames); if (_current_executing_filename == NULL) { return false; } @@ -391,12 +389,14 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) { filesystem_flush(); } if (safe_mode == NO_SAFE_MODE && !autoreload_pending()) { - static const char *const supported_filenames[] = STRING_LIST( - "code.txt", "code.py", "main.py", "main.txt"); + static const char *const supported_filenames[] = { + "code.txt", "code.py", "main.py", "main.txt" + }; #if CIRCUITPY_FULL_BUILD - static const char *const double_extension_filenames[] = STRING_LIST( + static const char *const double_extension_filenames[] = { "code.txt.py", "code.py.txt", "code.txt.txt","code.py.py", - "main.txt.py", "main.py.txt", "main.txt.txt","main.py.py"); + "main.txt.py", "main.py.txt", "main.txt.txt","main.py.py" + }; #endif supervisor_allocation *heap = allocate_remaining_memory(); @@ -410,14 +410,15 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) { // Check if a different run file has been allocated if (next_code_allocation) { - ((next_code_info_t *)next_code_allocation->ptr)->options &= ~SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET; - next_code_options = ((next_code_info_t *)next_code_allocation->ptr)->options; - if (((next_code_info_t *)next_code_allocation->ptr)->filename[0] != '\0') { - const char *next_list[] = {((next_code_info_t *)next_code_allocation->ptr)->filename, ""}; + next_code_info_t *info = ((next_code_info_t *)next_code_allocation->ptr); + info->options &= ~SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET; + next_code_options = info->options; + if (info->filename[0] != '\0') { // This is where the user's python code is actually executed: - found_main = maybe_run_list(next_list); + const char *const filenames[] = { info->filename }; + found_main = maybe_run_list(filenames, MP_ARRAY_SIZE(filenames)); if (!found_main) { - serial_write(((next_code_info_t *)next_code_allocation->ptr)->filename); + serial_write(info->filename); serial_write_compressed(translate(" not found.\n")); } } @@ -425,11 +426,11 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool *simulate_reset) { // Otherwise, default to the standard list of filenames if (!found_main) { // This is where the user's python code is actually executed: - found_main = maybe_run_list(supported_filenames); + found_main = maybe_run_list(supported_filenames, MP_ARRAY_SIZE(supported_filenames)); // If that didn't work, double check the extensions #if CIRCUITPY_FULL_BUILD if (!found_main) { - found_main = maybe_run_list(double_extension_filenames); + found_main = maybe_run_list(double_extension_filenames, MP_ARRAY_SIZE(double_extension_filenames)); if (found_main) { serial_write_compressed(translate("WARNING: Your code filename has two extensions\n")); } @@ -741,7 +742,7 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { && safe_mode == NO_SAFE_MODE && MP_STATE_VM(vfs_mount_table) != NULL; - static const char *const boot_py_filenames[] = STRING_LIST("boot.py", "boot.txt"); + static const char *const boot_py_filenames[] = {"boot.py", "boot.txt"}; // Do USB setup even if boot.py is not run. @@ -778,7 +779,7 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { port_boot_info(); #endif - bool found_boot = maybe_run_list(boot_py_filenames); + bool found_boot = maybe_run_list(boot_py_filenames, MP_ARRAY_SIZE(boot_py_filenames)); (void)found_boot;